diff --git a/.github/workflows/bsim-tests-publish.yaml b/.github/workflows/bsim-tests-publish.yaml index 132a891cc46..aad33a22339 100644 --- a/.github/workflows/bsim-tests-publish.yaml +++ b/.github/workflows/bsim-tests-publish.yaml @@ -13,7 +13,7 @@ jobs: steps: - name: Download artifacts - uses: dawidd6/action-download-artifact@v2 + uses: dawidd6/action-download-artifact@v3 with: run_id: ${{ github.event.workflow_run.id }} diff --git a/.github/workflows/bsim-tests.yaml b/.github/workflows/bsim-tests.yaml index 0574134f830..52d384e92fd 100644 --- a/.github/workflows/bsim-tests.yaml +++ b/.github/workflows/bsim-tests.yaml @@ -90,50 +90,50 @@ jobs: echo "ZEPHYR_SDK_INSTALL_DIR=/opt/toolchains/zephyr-sdk-$( cat SDK_VERSION )" >> $GITHUB_ENV - name: Check common triggering files - uses: tj-actions/changed-files@v41 + uses: tj-actions/changed-files@v44 id: check-common-files with: files: | .github/workflows/bsim-tests.yaml .github/workflows/bsim-tests-publish.yaml west.yml - boards/posix/** - soc/posix/** - arch/posix/** - include/zephyr/arch/posix/** - scripts/native_simulator/** + boards/posix/ + soc/posix/ + arch/posix/ + include/zephyr/arch/posix/ + scripts/native_simulator/ tests/bsim/* - name: Check if Bluethooth files changed - uses: tj-actions/changed-files@v41 + uses: tj-actions/changed-files@v44 id: check-bluetooth-files with: files: | - tests/bsim/bluetooth/** - samples/bluetooth/** - subsys/bluetooth/** + tests/bsim/bluetooth/ + samples/bluetooth/ + subsys/bluetooth/ - name: Check if Networking files changed - uses: tj-actions/changed-files@v41 + uses: tj-actions/changed-files@v44 id: check-networking-files with: files: | - tests/bsim/net/** - samples/net/sockets/echo_*/** - modules/openthread/** - subsys/net/l2/openthread/** + tests/bsim/net/ + samples/net/sockets/echo_*/ + modules/openthread/ + subsys/net/l2/openthread/ include/zephyr/net/openthread.h - drivers/ieee802154/** + drivers/ieee802154/ include/zephyr/net/ieee802154* - name: Check if UART files changed - uses: tj-actions/changed-files@v41 + uses: tj-actions/changed-files@v44 id: check-uart-files with: files: | - tests/bsim/drivers/uart/** + tests/bsim/drivers/uart/ drivers/serial/*nrfx* - tests/drivers/uart/** + tests/drivers/uart/ - name: Update BabbleSim to manifest revision if: > diff --git a/.github/workflows/bug_snapshot.yaml b/.github/workflows/bug_snapshot.yaml index 16b251b7f2f..b4f9022bf28 100644 --- a/.github/workflows/bug_snapshot.yaml +++ b/.github/workflows/bug_snapshot.yaml @@ -42,7 +42,7 @@ jobs: echo "BUGS_PICKLE_PATH=${BUGS_PICKLE_PATH}" >> ${GITHUB_ENV} - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@v2 + uses: aws-actions/configure-aws-credentials@v4 with: aws-access-key-id: ${{ vars.AWS_BUILDS_ZEPHYR_BUG_SNAPSHOT_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_BUILDS_ZEPHYR_BUG_SNAPSHOT_SECRET_ACCESS_KEY }} diff --git a/.github/workflows/codecov.yaml b/.github/workflows/codecov.yaml index 1c5ded582f0..19c50aba9b4 100644 --- a/.github/workflows/codecov.yaml +++ b/.github/workflows/codecov.yaml @@ -2,7 +2,7 @@ name: Code Coverage with codecov on: schedule: - - cron: '25 06,18 * * 1-5' + - cron: '25 06,18 * * *' concurrency: group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.head_ref || github.ref }} @@ -220,10 +220,10 @@ jobs: - name: Upload coverage to Codecov if: always() - uses: codecov/codecov-action@v3 + uses: codecov/codecov-action@v4 with: - directory: ./coverage/reports env_vars: OS,PYTHON fail_ci_if_error: false verbose: true - files: merged.xml + token: ${{ secrets.CODECOV_TOKEN }} + files: coverage/reports/merged.xml diff --git a/.github/workflows/compliance.yml b/.github/workflows/compliance.yml index 88c98e84710..09c0767cd19 100644 --- a/.github/workflows/compliance.yml +++ b/.github/workflows/compliance.yml @@ -17,6 +17,11 @@ jobs: ref: ${{ github.event.pull_request.head.sha }} fetch-depth: 0 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: 3.11 + - name: cache-pip uses: actions/cache@v4 with: diff --git a/.github/workflows/daily_test_version.yml b/.github/workflows/daily_test_version.yml index 31e9fcde9b8..1886b4a8c80 100644 --- a/.github/workflows/daily_test_version.yml +++ b/.github/workflows/daily_test_version.yml @@ -17,7 +17,7 @@ jobs: steps: - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@v2 + uses: aws-actions/configure-aws-credentials@v4 with: aws-access-key-id: ${{ vars.AWS_TESTING_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_TESTING_SECRET_ACCESS_KEY }} diff --git a/.github/workflows/devicetree_checks.yml b/.github/workflows/devicetree_checks.yml index 3b254354bc2..fd902ac4579 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', '3.11', '3.12'] + python-version: ['3.10', '3.11', '3.12'] os: [ubuntu-22.04, macos-11, windows-2022] exclude: - os: macos-11 diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index d1bcfe3e06f..e8d53405257 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -34,20 +34,20 @@ jobs: ref: ${{ github.event.pull_request.head.sha }} fetch-depth: 0 - name: Check if Documentation related files changed - uses: tj-actions/changed-files@v42 + uses: tj-actions/changed-files@v44 id: check-doc-files with: files: | - doc/** + doc/ **.rst - include/** + include/ kernel/include/kernel_arch_interface.h lib/libc/** subsys/testsuite/ztest/include/** - tests/** + tests/ **/Kconfig* west.yml - scripts/dts/** + scripts/dts/ doc/requirements.txt .github/workflows/doc-build.yml diff --git a/.github/workflows/doc-publish-pr.yml b/.github/workflows/doc-publish-pr.yml index de08d013bd1..e35c6d65120 100644 --- a/.github/workflows/doc-publish-pr.yml +++ b/.github/workflows/doc-publish-pr.yml @@ -21,7 +21,7 @@ jobs: steps: - name: Download artifacts - uses: dawidd6/action-download-artifact@v2 + uses: dawidd6/action-download-artifact@v3 with: workflow: doc-build.yml run_id: ${{ github.event.workflow_run.id }} @@ -51,7 +51,7 @@ jobs: fi - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@v2 + uses: aws-actions/configure-aws-credentials@v4 with: aws-access-key-id: ${{ vars.AWS_BUILDS_ZEPHYR_PR_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_BUILDS_ZEPHYR_PR_SECRET_ACCESS_KEY }} diff --git a/.github/workflows/doc-publish.yml b/.github/workflows/doc-publish.yml index c250e6514aa..869cfceaad2 100644 --- a/.github/workflows/doc-publish.yml +++ b/.github/workflows/doc-publish.yml @@ -24,7 +24,7 @@ jobs: steps: - name: Download artifacts - uses: dawidd6/action-download-artifact@v2 + uses: dawidd6/action-download-artifact@v3 with: workflow: doc-build.yml run_id: ${{ github.event.workflow_run.id }} @@ -37,7 +37,7 @@ jobs: fi - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@v2 + uses: aws-actions/configure-aws-credentials@v4 with: aws-access-key-id: ${{ vars.AWS_DOCS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_DOCS_SECRET_ACCESS_KEY }} diff --git a/.github/workflows/footprint-tracking.yml b/.github/workflows/footprint-tracking.yml index 5f355e944fb..ede9f52602e 100644 --- a/.github/workflows/footprint-tracking.yml +++ b/.github/workflows/footprint-tracking.yml @@ -74,7 +74,7 @@ jobs: west update 2>&1 1> west.update.log || west update 2>&1 1> west.update2.log - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@v2 + uses: aws-actions/configure-aws-credentials@v4 with: aws-access-key-id: ${{ vars.AWS_TESTING_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_TESTING_SECRET_ACCESS_KEY }} diff --git a/.github/workflows/issue_count.yml b/.github/workflows/issue_count.yml index f44ef5531d4..7d6ed6dfc3e 100644 --- a/.github/workflows/issue_count.yml +++ b/.github/workflows/issue_count.yml @@ -27,7 +27,7 @@ jobs: sudo apt-get update sudo apt-get install discount - - uses: brcrista/summarize-issues@v3 + - uses: brcrista/summarize-issues@v4 with: title: 'Issues Report for ${{ github.repository }}' configPath: 'issues-report-config.json' @@ -42,7 +42,7 @@ jobs: path: ${{ env.OUTPUT_FILE_NAME }} - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@v2 + uses: aws-actions/configure-aws-credentials@v4 with: aws-access-key-id: ${{ vars.AWS_TESTING_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_TESTING_SECRET_ACCESS_KEY }} diff --git a/.github/workflows/pylib_tests.yml b/.github/workflows/pylib_tests.yml index fd010bb207b..8827acebdb4 100644 --- a/.github/workflows/pylib_tests.yml +++ b/.github/workflows/pylib_tests.yml @@ -25,7 +25,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - python-version: [3.8, 3.9, '3.10', '3.11', '3.12'] + python-version: ['3.10', '3.11', '3.12'] os: [ubuntu-22.04] steps: - name: checkout diff --git a/.github/workflows/scripts_tests.yml b/.github/workflows/scripts_tests.yml index bf04640a30a..86db35ae02e 100644 --- a/.github/workflows/scripts_tests.yml +++ b/.github/workflows/scripts_tests.yml @@ -25,7 +25,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - python-version: [3.8, 3.9, '3.10', '3.11', '3.12'] + python-version: ['3.10', '3.11', '3.12'] os: [ubuntu-20.04] steps: - name: checkout diff --git a/.github/workflows/twister_tests.yml b/.github/workflows/twister_tests.yml index e7fe29f9e4a..fa6737badb8 100644 --- a/.github/workflows/twister_tests.yml +++ b/.github/workflows/twister_tests.yml @@ -32,7 +32,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - python-version: [3.8, 3.9, '3.10', '3.11', '3.12'] + python-version: ['3.10', '3.11', '3.12'] os: [ubuntu-22.04] steps: - name: checkout diff --git a/.github/workflows/twister_tests_blackbox.yml b/.github/workflows/twister_tests_blackbox.yml index ec380f0eecd..edec21e28d3 100644 --- a/.github/workflows/twister_tests_blackbox.yml +++ b/.github/workflows/twister_tests_blackbox.yml @@ -21,7 +21,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - python-version: [3.8, 3.9, '3.10', '3.11', '3.12'] + python-version: ['3.10', '3.11', '3.12'] os: [ubuntu-22.04] container: image: ghcr.io/zephyrproject-rtos/ci:v0.26.11 diff --git a/.github/workflows/west_cmds.yml b/.github/workflows/west_cmds.yml index 379086e3d14..c1e38695dc9 100644 --- a/.github/workflows/west_cmds.yml +++ b/.github/workflows/west_cmds.yml @@ -29,7 +29,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - python-version: [3.8, 3.9, '3.10', '3.11', '3.12'] + python-version: ['3.10', '3.11', '3.12'] os: [ubuntu-22.04, macos-11, windows-2022] exclude: - os: macos-11 diff --git a/CMakeLists.txt b/CMakeLists.txt index b4d12bb8c87..401060f989c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -200,7 +200,8 @@ elseif(CONFIG_SPEED_OPTIMIZATIONS) elseif(CONFIG_SIZE_OPTIMIZATIONS) set(OPTIMIZATION_FLAG ${OPTIMIZE_FOR_SIZE_FLAG}) # Default in kconfig else() - assert(0 "Unreachable code. Expected optimization level to have been chosen. See Kconfig.zephyr") + message(FATAL_ERROR + "Unreachable code. Expected optimization level to have been chosen. See Kconfig.zephyr") endif() if(NOT CONFIG_ARCH_IS_SET) @@ -218,6 +219,26 @@ if(CONFIG_LTO) add_link_options($) endif() +if(CONFIG_STD_C23) + set(CSTD c2x) +elseif(CONFIG_STD_C17) + set(CSTD c17) +elseif(CONFIG_STD_C11) + set(CSTD c11) +elseif(CONFIG_STD_C99) + set(CSTD c99) +elseif(CONFIG_STD_C90) + set(CSTD c90) +else() + message(FATAL_ERROR "Unreachable code. Expected C standard to have been chosen.") +endif() + +if(CONFIG_GNU_C_EXTENSIONS) + string(REPLACE "c" "gnu" CSTD "${CSTD}") +endif() + +list(APPEND CMAKE_C_COMPILE_FEATURES ${compile_features_${CSTD}}) + # @Intent: Obtain compiler specific flags related to C++ that are not influenced by kconfig zephyr_compile_options($<$:$>) @@ -247,7 +268,8 @@ if(CONFIG_CPP) set(STD_CPP_DIALECT_FLAGS $) list(APPEND CMAKE_CXX_COMPILE_FEATURES ${compile_features_cpp20}) else() - assert(0 "Unreachable code. Expected C++ standard to have been chosen. See Kconfig.zephyr.") + message(FATAL_ERROR + "Unreachable code. Expected C++ standard to have been chosen. See Kconfig.zephyr.") endif() set(CMAKE_CXX_COMPILE_FEATURES ${CMAKE_CXX_COMPILE_FEATURES} PARENT_SCOPE) @@ -601,6 +623,7 @@ get_property(LIBC_LINK_LIBRARIES TARGET zephyr_interface PROPERTY LIBC_LINK_LIBR zephyr_link_libraries(${LIBC_LINK_LIBRARIES}) set(syscall_list_h ${CMAKE_CURRENT_BINARY_DIR}/include/generated/syscall_list.h) +set(edk_syscall_list_h ${CMAKE_CURRENT_BINARY_DIR}/edk/include/generated/syscall_list.h) set(syscalls_json ${CMAKE_CURRENT_BINARY_DIR}/misc/generated/syscalls.json) set(struct_tags_json ${CMAKE_CURRENT_BINARY_DIR}/misc/generated/struct_tags.json) @@ -884,7 +907,7 @@ foreach(zephyr_lib ${ZEPHYR_LIBS_PROPERTY}) add_dependencies(${zephyr_lib} zephyr_generated_headers) endforeach() -if(CONFIG_LLEXT) +if(CONFIG_KERNEL_WHOLE_ARCHIVE) set(WHOLE_ARCHIVE_LIBS ${ZEPHYR_LIBS_PROPERTY} kernel) else() set(WHOLE_ARCHIVE_LIBS ${ZEPHYR_LIBS_PROPERTY}) @@ -954,14 +977,19 @@ if(CONFIG_USERSPACE) set(PROCESS_GPERF ${ZEPHYR_BASE}/scripts/build/process_gperf.py) endif() -get_property(CSTD GLOBAL PROPERTY CSTD) -set_ifndef(CSTD c99) +get_property(GLOBAL_CSTD GLOBAL PROPERTY CSTD) +if(DEFINED GLOBAL_CSTD) + message(DEPRECATION + "Global CSTD property is deprecated, see Kconfig.zephyr for C Standard options.") + set(CSTD ${GLOBAL_CSTD}) + list(APPEND CMAKE_C_COMPILE_FEATURES ${compile_features_${CSTD}}) +endif() # @Intent: Obtain compiler specific flag for specifying the c standard zephyr_compile_options( $<$:$${CSTD}> ) -set(CMAKE_C_COMPILE_FEATURES ${compile_features_${CSTD}} PARENT_SCOPE) +set(CMAKE_C_COMPILE_FEATURES ${CMAKE_C_COMPILE_FEATURES} PARENT_SCOPE) # @Intent: Configure linker scripts, i.e. generate linker scripts with variables substituted toolchain_ld_configure_files() @@ -1704,7 +1732,7 @@ endif() if(CONFIG_OUTPUT_DISASSEMBLY) if(CONFIG_OUTPUT_DISASSEMBLE_ALL) set(disassembly_type "$") - else() + elseif (CONFIG_OUTPUT_DISASSEMBLY_WITH_SOURCE) set(disassembly_type "$") endif() list(APPEND @@ -1769,6 +1797,17 @@ if(CONFIG_BUILD_OUTPUT_STRIPPED) ) endif() +if(CONFIG_BUILD_OUTPUT_COMPRESS_DEBUG_SECTIONS) + list(APPEND + post_build_commands + COMMAND $ + $ + $ + $${KERNEL_ELF_NAME} + $ +) +endif() + if(CONFIG_BUILD_OUTPUT_EXE) if (NOT CONFIG_NATIVE_LIBRARY) list(APPEND @@ -2023,6 +2062,51 @@ if((CMAKE_BUILD_TYPE IN_LIST build_types) AND (NOT NO_BUILD_TYPE_WARNING)) endif() endif() +# Extension Development Kit (EDK) generation. +set(llext_edk_file ${PROJECT_BINARY_DIR}/${CONFIG_LLEXT_EDK_NAME}.tar.xz) + +# TODO maybe generate flags for C CXX ASM +zephyr_get_compile_options_for_lang(C zephyr_flags) + +# Filter out non LLEXT and LLEXT_EDK flags - and add required ones +llext_filter_zephyr_flags(LLEXT_REMOVE_FLAGS ${zephyr_flags} llext_edk_cflags) +llext_filter_zephyr_flags(LLEXT_EDK_REMOVE_FLAGS ${llext_edk_cflags} llext_edk_cflags) + +list(APPEND llext_edk_cflags ${LLEXT_APPEND_FLAGS}) +list(APPEND llext_edk_cflags ${LLEXT_EDK_APPEND_FLAGS}) + +add_custom_command( + OUTPUT ${llext_edk_file} + # Regenerate syscalls in case CONFIG_LLEXT_EDK_USERSPACE_ONLY + COMMAND ${CMAKE_COMMAND} + -E make_directory edk/include/generated + COMMAND + ${PYTHON_EXECUTABLE} + ${ZEPHYR_BASE}/scripts/build/gen_syscalls.py + --json-file ${syscalls_json} # Read this file + --base-output edk/include/generated/syscalls # Write to this dir + --syscall-dispatch edk/include/generated/syscall_dispatch.c # Write this file + --syscall-list ${edk_syscall_list_h} + $<$:--userspace-only> + ${SYSCALL_LONG_REGISTERS_ARG} + ${SYSCALL_SPLIT_TIMEOUT_ARG} + COMMAND ${CMAKE_COMMAND} + -DPROJECT_BINARY_DIR=${PROJECT_BINARY_DIR} + -DAPPLICATION_SOURCE_DIR=${APPLICATION_SOURCE_DIR} + -DINTERFACE_INCLUDE_DIRECTORIES="$,:>" + -Dllext_edk_file=${llext_edk_file} + -DAUTOCONF_H=${AUTOCONF_H} + -Dllext_cflags="${llext_edk_cflags}" + -Dllext_edk_name=${CONFIG_LLEXT_EDK_NAME} + -DWEST_TOPDIR=${WEST_TOPDIR} + -DZEPHYR_BASE=${ZEPHYR_BASE} + -DCONFIG_LLEXT_EDK_USERSPACE_ONLY=${CONFIG_LLEXT_EDK_USERSPACE_ONLY} + -P ${ZEPHYR_BASE}/cmake/llext-edk.cmake + DEPENDS ${logical_target_for_zephyr_elf} + COMMAND_EXPAND_LISTS +) +add_custom_target(llext-edk DEPENDS ${llext_edk_file}) + # @Intent: Set compiler specific flags for standard C/C++ includes # Done at the very end, so any other system includes which may # be added by Zephyr components were first in list. diff --git a/Kconfig.zephyr b/Kconfig.zephyr index 5375245ced0..e44cd327cb5 100644 --- a/Kconfig.zephyr +++ b/Kconfig.zephyr @@ -316,6 +316,13 @@ config LINKER_USE_RELAX endmenu # "Linker Sections" +config LINKER_ITERABLE_SUBALIGN + int + default 8 if 64BIT + default 4 + help + Hidden option for the default subalignment of iterable sections. + config LINKER_DEVNULL_SUPPORT bool default y if CPU_CORTEX_M || (RISCV && !64BIT) @@ -338,6 +345,84 @@ endmenu menu "Compiler Options" +config REQUIRES_STD_C99 + bool + help + Hidden option to select compiler support C99 standard or higher. + +config REQUIRES_STD_C11 + bool + select REQUIRES_STD_C99 + help + Hidden option to select compiler support C11 standard or higher. + +config REQUIRES_STD_C17 + bool + select REQUIRES_STD_C11 + help + Hidden option to select compiler support C17 standard or higher. + +config REQUIRES_STD_C23 + bool + select REQUIRES_STD_C17 + help + Hidden option to select compiler support C23 standard or higher. + +choice STD_C + prompt "C Standard" + default STD_C23 if REQUIRES_STD_C23 + default STD_C17 if REQUIRES_STD_C17 + default STD_C11 if REQUIRES_STD_C11 + default STD_C99 + help + C Standards. + +config STD_C90 + bool "C90" + depends on !REQUIRES_STD_C99 + help + 1989 C standard as completed in 1989 and ratified by ISO/IEC + as ISO/IEC 9899:1990. This version is known as "ANSI C". + +config STD_C99 + bool "C99" + depends on !REQUIRES_STD_C11 + help + 1999 C standard. + +config STD_C11 + bool "C11" + depends on !REQUIRES_STD_C17 + help + 2011 C standard. + +config STD_C17 + bool "C17" + depends on !REQUIRES_STD_C23 + help + 2017 C standard, addresses defects in C11 without introducing + new language features. + +config STD_C23 + bool "C23" + help + 2023 C standard. + +endchoice + +config TOOLCHAIN_SUPPORTS_GNU_EXTENSIONS + bool + default y if "$(ZEPHYR_TOOLCHAIN_VARIANT)" = "zephyr" + help + Hidden option to signal that toolchain supports GNU Extensions. + +config GNU_C_EXTENSIONS + bool "GNU C Extensions" + depends on TOOLCHAIN_SUPPORTS_GNU_EXTENSIONS + help + Enable GNU C Extensions. GNU C provides several language features + not found in ISO standard C. + config CODING_GUIDELINE_CHECK bool "Enforce coding guideline rules" help @@ -520,17 +605,17 @@ choice config ASSERT_ON_ERRORS bool "Assert on all errors" help - Assert on errors covered with the CHECK macro. + Assert on errors covered with the CHECKIF() macro. config NO_RUNTIME_CHECKS bool "No runtime error checks" help - Do not do any runtime checks or asserts when using the CHECK macro. + Do not do any runtime checks or asserts when using the CHECKIF() macro. config RUNTIME_ERROR_CHECKS bool "Runtime error checks" help - Always perform runtime checks covered with the CHECK macro. This + Always perform runtime checks covered with the CHECKIF() macro. This option is the default and the only option used during testing. endchoice @@ -567,6 +652,17 @@ config OUTPUT_DISASSEMBLE_ALL The .lst file will contain complete disassembly of the firmware not just those expected to contain instructions including zeros +config OUTPUT_DISASSEMBLY_WITH_SOURCE + bool "Include source code in output disassembly file" + default y + depends on OUTPUT_DISASSEMBLY && !OUTPUT_DISASSEMBLE_ALL + help + The .lst file will also contain the source code. Having + control over this can be useful for reproducible builds + since it can be used to remove one of the elements of + the .lst file that can vary across platforms because + of reasons such as having ".." include paths. + config OUTPUT_PRINT_MEMORY_USAGE bool "Print memory usage to stdout" default y @@ -688,6 +784,11 @@ config BUILD_OUTPUT_STRIPPED Build a stripped binary zephyr/zephyr.strip in the build directory. The name of this file can be customized with CONFIG_KERNEL_BIN_NAME. +config BUILD_OUTPUT_COMPRESS_DEBUG_SECTIONS + bool "Compress debug sections in the ELF file" + help + Compress debug sections in the ELF file to reduce the file size. + config BUILD_OUTPUT_ADJUST_LMA string help diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index c70147b5195..c24eb2e290c 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -114,11 +114,7 @@ ACPI: status: maintained maintainers: - - jhedberg - najumon1980 - collaborators: - - finikorg - - tbursztyka files: - lib/acpi/ - include/zephyr/acpi/ @@ -135,7 +131,6 @@ ARC arch: collaborators: - abrodkin - evgeniy-paltsev - - SiyuanCheng-CN files: - arch/arc/ - include/zephyr/arch/arc/ @@ -191,14 +186,18 @@ ARM64 arch: - arch.arm64 ARM Platforms: - status: odd fixes + status: maintained + maintainers: + - ithinuel files: - boards/arm/mps*/ - boards/arm/v2m_*/ + - boards/arm/fvp_base*/ - soc/arm/mps*/ - soc/arm/musca/ - soc/arm/beetle/ - - soc/arm/fvp_aemv8r/aarch32/ + - soc/arm/designstart/ + - soc/arm/fvp_aemv8*/ - dts/arm/armv*.dtsi labels: - "platform: ARM" @@ -238,13 +237,10 @@ MIPS arch: - arch.mips Ambiq Platforms: - status: maintained - maintainers: - - fkokosinski + status: odd fixes collaborators: - - tgorochowik - - msobkowski - aaronyegx + - AlessandroLuo - RichardSWheatley files: - soc/ambiq/ @@ -414,6 +410,7 @@ Bluetooth Mesh: - Andrewpini - akredalen - HaavardRei + - omkar3141 files: - subsys/bluetooth/mesh/ - include/zephyr/bluetooth/mesh/ @@ -445,7 +442,14 @@ Bluetooth Audio: - include/zephyr/bluetooth/audio/ - tests/bluetooth/audio/ - tests/bsim/bluetooth/audio/ - - tests/bluetooth/shell/audio* + - tests/bluetooth/shell/audio.conf + - tests/bluetooth/tester/overlay-le-audio.conf + - doc/connectivity/bluetooth/api/audio/ + - samples/bluetooth/broadcast_audio*/ + - samples/bluetooth/hap*/ + - samples/bluetooth/public_broadcast*/ + - samples/bluetooth/tmap*/ + - samples/bluetooth/unicast_audio*/ labels: - "area: Bluetooth Audio" - "area: Bluetooth" @@ -772,6 +776,8 @@ Devicetree: - include/zephyr/devicetree/ - scripts/kconfig/kconfigfunctions.py - include/zephyr/devicetree.h + files-exclude: + - dts/common/nordic/ labels: - "area: Devicetree" tests: @@ -1224,6 +1230,7 @@ Release Notes: status: odd fixes collaborators: - decsny + - lmajewski files: - drivers/ethernet/ - include/zephyr/dt-bindings/ethernet/ @@ -1312,6 +1319,9 @@ Release Notes: status: maintained maintainers: - bjarki-trackunit + collaborators: + - tomi-font + - fabiobaltieri files: - doc/hardware/peripherals/gnss.rst - drivers/gnss/ @@ -1362,6 +1372,7 @@ Release Notes: - include/zephyr/dt-bindings/i2c/ - tests/boards/*/i2c/ - tests/drivers/*/i2c/ + - samples/drivers/i2c/ labels: - "area: I2C" tests: @@ -1478,6 +1489,8 @@ Release Notes: "Drivers: Reset": status: odd fixes + collaborators: + - decsny files: - drivers/reset/ - include/zephyr/drivers/reset.h @@ -1658,10 +1671,6 @@ Release Notes: status: maintained maintainers: - dcpleung - collaborators: - - jhedberg - - finikorg - - tbursztyka files: - drivers/pcie/ - include/zephyr/drivers/pcie/ @@ -1804,6 +1813,7 @@ Release Notes: - teburd - yperess - tristan-google + - ubieda files: - drivers/sensor/ - include/zephyr/drivers/sensor.h @@ -2397,6 +2407,8 @@ Mbed TLS: maintainers: - d3zd3z - ceolin + collaborators: + - ithinuel files: - tests/crypto/mbedtls/ - doc/services/crypto/ @@ -3022,11 +3034,11 @@ Shell: Shields: status: maintained maintainers: - - erwango + - kartben collaborators: - avisconti - jfischer-no - - kartben + - erwango files: - boards/shields/ - doc/hardware/porting/shields.rst @@ -3132,11 +3144,15 @@ Synopsys Platforms: collaborators: - abrodkin - evgeniy-paltsev - - IRISZZW files: - soc/snps/ - boards/snps/ + - boards/qemu/arc/ - samples/boards/arc_secure_services/ + - scripts/west_commands/runners/mdb.py + - scripts/west_commands/tests/test_mdb.py + - scripts/west_commands/runners/nsim.py + - cmake/emu/nsim.cmake labels: - "platform: Synopsys" @@ -3212,11 +3228,12 @@ SiLabs Platforms: Intel Platforms (X86): status: maintained maintainers: - - jhedberg + - edersondisouza collaborators: - - tbursztyka - - laurenmurphyx64 - najumon1980 + - teburd + - dcpleung + - ceolin files: - boards/intel/adl/ - boards/intel/ehl/ @@ -3225,17 +3242,18 @@ Intel Platforms (X86): - soc/intel/atom/ - soc/intel/lakemont/ - soc/intel/*_lake/ - - samples/boards/up_squared/ + - drivers/timer/Kconfig.x86 + - drivers/timer/hpet.c + - drivers/timer/apic* labels: - "platform: X86" Intel Platforms (Xtensa): status: maintained maintainers: - - nashif + - dcpleung collaborators: - andyross - - dcpleung - lyakh - lgirdwood - marc-hb @@ -3245,6 +3263,7 @@ Intel Platforms (Xtensa): - softwarecki - jxstelter - marcinszkudlinski + - nashif files: - boards/intel/adsp/ - soc/intel/intel_adsp/ @@ -3263,6 +3282,7 @@ Intel Platforms (ISH): collaborators: - teburd - likongintel + - nashif files: - boards/intel/ish/ - soc/intel/intel_ish/ @@ -3330,6 +3350,7 @@ NXP Platforms (MCU): - yvanderv - EmilioCBen - decsny + - butok files: - boards/nxp/mimxrt*/ - boards/nxp/frdm*/ @@ -3450,20 +3471,44 @@ nRF Platforms: status: maintained maintainers: - anangl + - masz-nordic + collaborators: + - jaz1-nordic + - kl-cruz + - magp-nordic + - nika-nordic files: - boards/nordic/ - - drivers/*/*nrfx*.c + - drivers/*/*nrf*.c + - drivers/*/*nordic*/ - soc/nordic/ - samples/boards/nrf/ - - dts/arm/nordic/ + - dts/*/nordic/ - dts/bindings/*/nordic,* - - tests/drivers/timer/nrf_rtc_timer/ + - tests/drivers/*/*nrf*/ + - snippets/nordic*/ labels: - "platform: nRF" +OpenTitan Platforms: + status: maintained + maintainers: + - snematbakhsh + files: + - boards/lowrisc/opentitan_earlgrey/ + - drivers/*/*opentitan* + - dts/bindings/*/*opentitan* + - dts/riscv/lowrisc/*opentitan* + - soc/lowrisc/opentitan/ + labels: + - "platform: OpenTitan" + description: >- + OpenTitan boards, SOCs, dts files and related drivers. + Renesas SmartBond Platforms: status: maintained maintainers: + - ioannis-karachalios - andrzej-kaczmarek - blauret files: @@ -3631,8 +3676,10 @@ TI K3 Platforms: - vaishnavachath collaborators: - gramsay0 + - dnltz files: - - boards/phytec/*am62*/ + - boards/phytec/phyboard_lyra/ + - boards/phytec/phyboard_electra/ - boards/ti/*am62*/ - drivers/*/*ti_k3* - dts/bindings/*/ti,k3* @@ -3676,8 +3723,6 @@ Infineon Platforms: - drivers/*/*xmc* - drivers/sensor/infineon/ - dts/arm/infineon/ - - dts/arm/cypress/ - - soc/cypress/ - dts/bindings/*/*infineon* - soc/infineon/ labels: @@ -3733,12 +3778,12 @@ Sysbuild: - "57300" files: - share/sysbuild/ - - samples/application_development/sysbuild/ + - samples/sysbuild/ - doc/build/sysbuild/ labels: - "area: Sysbuild" tests: - - sample.application_development.sysbuild + - sample.sysbuild Task Watchdog: status: maintained @@ -3796,7 +3841,8 @@ TF-M Integration: maintainers: - d3zd3z collaborators: - - SebastianBoe + - Vge0rge + - ithinuel files: - samples/tfm_integration/ - modules/trusted-firmware-m/ @@ -3984,14 +4030,107 @@ West: status: maintained maintainers: - najumon1980 - - jhedberg - collaborators: - - tbursztyka files: - modules/acpica/ labels: - "area: ACPI" +"West project: bsim": + status: maintained + maintainers: + - aescolar + files: [] + labels: + - "platform: nRF BSIM" + +"West project: babblesim_base": + status: maintained + maintainers: + - aescolar + files: [] + labels: + - "platform: nRF BSIM" + +"West project: babblesim_ext_2G4_libPhyComv1": + status: maintained + maintainers: + - aescolar + files: [] + labels: + - "platform: nRF BSIM" + +"West project: babblesim_ext_2G4_phy_v1": + status: maintained + maintainers: + - aescolar + files: [] + labels: + - "platform: nRF BSIM" + +"West project: babblesim_ext_2G4_channel_NtNcable": + status: maintained + maintainers: + - aescolar + files: [] + labels: + - "platform: nRF BSIM" + +"West project: babblesim_ext_2G4_channel_multiatt": + status: maintained + maintainers: + - aescolar + files: [] + labels: + - "platform: nRF BSIM" + +"West project: babblesim_ext_2G4_modem_magic": + status: maintained + maintainers: + - aescolar + files: [] + labels: + - "platform: nRF BSIM" + +"West project: babblesim_ext_2G4_modem_BLE_simple": + status: maintained + maintainers: + - aescolar + files: [] + labels: + - "platform: nRF BSIM" + +"West project: babblesim_ext_2G4_device_burst_interferer": + status: maintained + maintainers: + - aescolar + files: [] + labels: + - "platform: nRF BSIM" + +"West project: babblesim_ext_2G4_device_WLAN_actmod": + status: maintained + maintainers: + - aescolar + files: [] + labels: + - "platform: nRF BSIM" + +"West project: babblesim_ext_2G4_device_playback": + status: maintained + maintainers: + - aescolar + files: [] + labels: + - "platform: nRF BSIM" + +"West project: babblesim_ext_libCryptov1": + status: maintained + maintainers: + - aescolar + files: [] + labels: + - "platform: nRF BSIM" + "West project: canopennode": status: maintained maintainers: @@ -4032,7 +4171,7 @@ West: files: - modules/cmsis-dsp/ labels: - - "area: ARM" + - "area: CMSIS-DSP" "West project: cmsis-nn": status: maintained @@ -4043,7 +4182,7 @@ West: files: - modules/cmsis-nn/ labels: - - "area: ARM" + - "area: CMSIS-NN" "West project: edtt": status: maintained @@ -4075,13 +4214,10 @@ West: - "platform: Altera" "West project: hal_ambiq": - status: maintained - maintainers: - - fkokosinski + status: odd fixes collaborators: - - tgorochowik - - msobkowski - aaronyegx + - AlessandroLuo - RichardSWheatley files: - modules/hal_ambiq/ @@ -4231,6 +4367,10 @@ West: "West project: hal_renesas": status: maintained maintainers: + - KhiemNguyenT + - ioannis-karachalios + collaborators: + - blauret - andrzej-kaczmarek files: [] labels: @@ -4393,6 +4533,8 @@ West: maintainers: - d3zd3z - ceolin + collaborators: + - ithinuel files: - modules/mbedtls/ labels: @@ -4558,7 +4700,8 @@ West: maintainers: - d3zd3z collaborators: - - SebastianBoe + - Vge0rge + - ithinuel files: - modules/trusted-firmware-m/ labels: @@ -4569,7 +4712,8 @@ West: maintainers: - d3zd3z collaborators: - - SebastianBoe + - Vge0rge + - ithinuel files: [] labels: - "area: TF-M" @@ -4581,6 +4725,7 @@ West: - sgrrzhf collaborators: - carlocaione + - ithinuel files: - modules/trusted-firmware-a/ labels: @@ -4591,7 +4736,8 @@ West: maintainers: - d3zd3z collaborators: - - SebastianBoe + - Vge0rge + - ithinuel files: [] labels: - "area: TF-M" @@ -4657,15 +4803,14 @@ Xtensa arch: x86 arch: status: maintained maintainers: - - jhedberg + - edersondisouza collaborators: - - tbursztyka - andyross - - nashif - dcpleung - ceolin - laurenmurphyx64 - najumon1980 + - nashif files: - arch/x86/ - include/zephyr/arch/x86/ diff --git a/arch/Kconfig b/arch/Kconfig index a800d220b58..b9e40d8ec20 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -144,6 +144,12 @@ config ARCH_POSIX select BARRIER_OPERATIONS_BUILTIN # POSIX arch based targets get their memory cleared on entry by the host OS select SKIP_BSS_CLEAR + # Override the C standard used for compilation to C 2011 + # This is due to some tests using _Static_assert which is a 2011 feature, but + # otherwise relying on compilers supporting it also when set to C99. + # This was in general ok, but with some host compilers and C library versions + # it led to problems. So we override it to 2011 for the native targets. + select REQUIRES_STD_C11 help POSIX (native) architecture diff --git a/arch/arc/core/fault.c b/arch/arc/core/fault.c index f896361ac88..763ed7a2c73 100644 --- a/arch/arc/core/fault.c +++ b/arch/arc/core/fault.c @@ -53,9 +53,8 @@ static const struct z_exc_handle exceptions[] = { */ static bool z_check_thread_stack_fail(const uint32_t fault_addr, uint32_t sp) { - uint32_t guard_end, guard_start; - #if defined(CONFIG_MULTITHREADING) + uint32_t guard_end, guard_start; const struct k_thread *thread = _current; if (!thread) { @@ -90,7 +89,6 @@ static bool z_check_thread_stack_fail(const uint32_t fault_addr, uint32_t sp) guard_end = thread->stack_info.start; guard_start = guard_end - Z_ARC_STACK_GUARD_SIZE; } -#endif /* CONFIG_MULTITHREADING */ /* treat any MPU exceptions within the guard region as a stack * overflow.As some instrustions @@ -101,6 +99,7 @@ static bool z_check_thread_stack_fail(const uint32_t fault_addr, uint32_t sp) if (fault_addr < guard_end && fault_addr >= guard_start) { return true; } +#endif /* CONFIG_MULTITHREADING */ return false; } diff --git a/arch/arc/core/mpu/arc_core_mpu.c b/arch/arc/core/mpu/arc_core_mpu.c index 0ffcdc875b4..2d739d7a233 100644 --- a/arch/arc/core/mpu/arc_core_mpu.c +++ b/arch/arc/core/mpu/arc_core_mpu.c @@ -34,7 +34,7 @@ int arch_mem_domain_max_partitions_get(void) /* * Validate the given buffer is user accessible or not */ -int arch_buffer_validate(void *addr, size_t size, int write) +int arch_buffer_validate(const void *addr, size_t size, int write) { return arc_core_mpu_buffer_validate(addr, size, write); } diff --git a/arch/arc/core/mpu/arc_mpu_common_internal.h b/arch/arc/core/mpu/arc_mpu_common_internal.h index 736a9742af9..a9ff5518b2f 100644 --- a/arch/arc/core/mpu/arc_mpu_common_internal.h +++ b/arch/arc/core/mpu/arc_mpu_common_internal.h @@ -207,7 +207,7 @@ int arc_core_mpu_get_max_domain_partition_regions(void) /** * @brief validate the given buffer is user accessible or not */ -int arc_core_mpu_buffer_validate(void *addr, size_t size, int write) +int arc_core_mpu_buffer_validate(const void *addr, size_t size, int write) { /* * For ARC MPU, smaller region number takes priority. diff --git a/arch/arc/core/mpu/arc_mpu_v4_internal.h b/arch/arc/core/mpu/arc_mpu_v4_internal.h index e7e91fed93f..3bf6fca6c43 100644 --- a/arch/arc/core/mpu/arc_mpu_v4_internal.h +++ b/arch/arc/core/mpu/arc_mpu_v4_internal.h @@ -779,7 +779,7 @@ int arc_core_mpu_get_max_domain_partition_regions(void) /** * @brief validate the given buffer is user accessible or not */ -int arc_core_mpu_buffer_validate(void *addr, size_t size, int write) +int arc_core_mpu_buffer_validate(const void *addr, size_t size, int write) { int r_index; int key = arch_irq_lock(); diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 3f5f3075777..bf68ec6faae 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -34,6 +34,71 @@ config ARM_CUSTOM_INTERRUPT_CONTROLLER is assumed that the custom interrupt control interface implementation assumes responsibility for handling the NVIC. +config ROMSTART_RELOCATION_ROM + bool + default n + help + Relocates the rom_start region containing the boot-vector data and + irq vectors to the region specified by configurations: + ROMSTART_REGION_ADDRESS and ROMSTART_REGION_SIZE + + This is useful for the Linux Remoteproc framework that uses the elf-loader + such that it is able to load the correct boot-vector (contained in rom_start) + into the correct memory location independent of the chosen zephyr,flash + ROM region. + + Most SOCs include an alias for the boot-vector at address 0x00000000 + so a default which might be supported by the corresponding Linux rproc driver. + If it is not, additionnal options allows to specify the addresses. + + In general this option should be chosen if the zephyr,flash chosen node + is not placed into the boot-vector memory area. + + While this aims at generating a correct zephyr.elf file, it has the side + effect of enlarging the bin file. If the zephyr.bin file is used to boot the + secondary core, this option should be disabled. + + Example: + on IMX7D, the chosen zephyr,flash can be OCRAM/OCRAM_S/TCM/DDR memories + for code location. But the boot-vector must be placed into OCRAM_S for the + CORTEX-M to boot (alias 0, real 0x00180000/32K available). + +if ROMSTART_RELOCATION_ROM + + config ROMSTART_REGION_ADDRESS + hex + default 0x00000000 + help + Start address of the rom_start region. + This setting can be derived from a DT node reg property or specified directly. + + A default value of 0x00000000 might work in most cases as SOCs have an alias + to the right memory region of the boot-vector. + + Examples: + -IMX7D the boot-vector is OCRAM_S (0x00180000, aliased at 0x0). + -IMX6SX the boot-vector is TCML (0x007F8000, aliased at 0x0). + -IMX8MQ the boot-vector is TCML (0x007E0000, aliased at 0x0). + -IMX8MN the boot-vector is ITCM (0x007E0000, aliased at 0x0). + + Example of DT definition: + $(dt_nodelabel_reg_addr_hex,ocram_s_sys) + + config ROMSTART_REGION_SIZE + hex + default 1 + help + Size of the rom_start region in KB. + + Default is 1KB which is enough to store the boot and irq vectors. + + This setting can be derived from a DT node reg property or specified directly. + + Example for IMX7D that needs the boot-vector into OCRAM_S (0x00180000): + $(dt_nodelabel_reg_size_hex,ocram_s_sys,0,K) + +endif + config CODE_DATA_RELOCATION_SRAM bool "Relocate code/data sections to SRAM" depends on CPU_CORTEX_M diff --git a/arch/arm/core/cortex_m/CMakeLists.txt b/arch/arm/core/cortex_m/CMakeLists.txt index 225d7111bdc..b220e6c81e8 100644 --- a/arch/arm/core/cortex_m/CMakeLists.txt +++ b/arch/arm/core/cortex_m/CMakeLists.txt @@ -3,7 +3,7 @@ zephyr_library() zephyr_library_sources( - exc_exit.S + exc_exit.c fault.c fault_s.S fpu.c @@ -16,11 +16,11 @@ zephyr_library_sources( irq_manage.c prep_c.c thread.c - cpu_idle.S + cpu_idle.c ) 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_GEN_SW_ISR_TABLE isr_wrapper.c) zephyr_library_sources_ifdef(CONFIG_DEBUG_COREDUMP coredump.c) zephyr_library_sources_ifdef(CONFIG_THREAD_LOCAL_STORAGE __aeabi_read_tp.S) zephyr_library_sources_ifdef(CONFIG_SEMIHOST semihost.c) diff --git a/arch/arm/core/cortex_m/__aeabi_read_tp.S b/arch/arm/core/cortex_m/__aeabi_read_tp.S index 8aeba3e5d12..745fda73b9b 100644 --- a/arch/arm/core/cortex_m/__aeabi_read_tp.S +++ b/arch/arm/core/cortex_m/__aeabi_read_tp.S @@ -12,8 +12,14 @@ GTEXT(__aeabi_read_tp) GDATA(z_arm_tls_ptr) +/* Grab the TLS pointer and store in R0. + * According to the Run-Time ABI for the ArmĀ® Architecture section 5.3.5, this + * function may only clobber r0, ip, lr & CPSR. + * + * This can only be guaranteed by either implementing a naked C function with + * inline assembly, or plain assembly. + */ SECTION_FUNC(TEXT, __aeabi_read_tp) - /* Grab the TLS pointer and store in R0 */ ldr r0, =z_arm_tls_ptr ldr r0, [r0] bx lr diff --git a/arch/arm/core/cortex_m/cpu_idle.S b/arch/arm/core/cortex_m/cpu_idle.S deleted file mode 100644 index 8acae5ddb13..00000000000 --- a/arch/arm/core/cortex_m/cpu_idle.S +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright (c) 2013-2014 Wind River Systems, Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief ARM Cortex-M power management - * - */ - -#include -#include - -#if defined(CONFIG_ARM_ON_EXIT_CPU_IDLE) -#include -#endif - -_ASM_FILE_PROLOGUE - -GTEXT(z_arm_cpu_idle_init) -GTEXT(arch_cpu_idle) -GTEXT(arch_cpu_atomic_idle) - -#define _SCB_SCR 0xE000ED10 - -#define _SCB_SCR_SEVONPEND (1 << 4) -#define _SCB_SCR_SLEEPDEEP (1 << 2) -#define _SCB_SCR_SLEEPONEXIT (1 << 1) -#define _SCR_INIT_BITS _SCB_SCR_SEVONPEND - -.macro _sleep_if_allowed wait_instruction -#if defined(CONFIG_ARM_ON_ENTER_CPU_IDLE_HOOK) - push {r0, lr} - bl z_arm_on_enter_cpu_idle - /* Skip the wait instruction if on_enter_cpu_idle() returns false. */ - cmp r0, #0 - beq _skip_\@ -#endif /* CONFIG_ARM_ON_ENTER_CPU_IDLE_HOOK */ - - /* - * Wait for all memory transactions to complete before entering low - * power state. - */ - dsb - \wait_instruction - -#if defined(CONFIG_ARM_ON_EXIT_CPU_IDLE) - /* Inline the macro provided by SoC-specific code */ - SOC_ON_EXIT_CPU_IDLE -#endif /* CONFIG_ARM_ON_EXIT_CPU_IDLE */ - -#if defined(CONFIG_ARM_ON_ENTER_CPU_IDLE_HOOK) -_skip_\@: -#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) - pop {r0, r1} - mov lr, r1 -#else - pop {r0, lr} -#endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */ -#endif /* CONFIG_ARM_ON_ENTER_CPU_IDLE_HOOK */ -.endm - -/** - * - * @brief Initialization of CPU idle - * - * Only called by arch_kernel_init(). Sets SEVONPEND bit once for the system's - * duration. - * - * C function prototype: - * - * void z_arm_cpu_idle_init(void); - */ - -SECTION_FUNC(TEXT, z_arm_cpu_idle_init) - ldr r1, =_SCB_SCR - movs.n r2, #_SCR_INIT_BITS - str r2, [r1] - bx lr - -SECTION_FUNC(TEXT, arch_cpu_idle) -#if defined(CONFIG_TRACING) || \ - defined(CONFIG_ARM_ON_ENTER_CPU_IDLE_PREPARE_HOOK) - push {r0, lr} - -#ifdef CONFIG_TRACING - bl sys_trace_idle -#endif -#ifdef CONFIG_ARM_ON_ENTER_CPU_IDLE_PREPARE_HOOK - bl z_arm_on_enter_cpu_idle_prepare -#endif - -#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) - pop {r0, r1} - mov lr, r1 -#else - pop {r0, lr} -#endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */ -#endif - -#if defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) - /* - * PRIMASK is always cleared on ARMv7-M and ARMv8-M Mainline (not used - * for interrupt locking), and configuring BASEPRI to the lowest - * priority to ensure wake-up will cause interrupts to be serviced - * before entering low power state. - * - * Set PRIMASK before configuring BASEPRI to prevent interruption - * before wake-up. - */ - cpsid i - - /* - * Set wake-up interrupt priority to the lowest and synchronise to - * ensure that this is visible to the WFI instruction. - */ - eors.n r0, r0 - msr BASEPRI, r0 - isb -#else - /* - * For all the other ARM architectures that do not implement BASEPRI, - * PRIMASK is used as the interrupt locking mechanism, and it is not - * necessary to set PRIMASK here, as PRIMASK would have already been - * set by the caller as part of interrupt locking if necessary - * (i.e. if the caller sets _kernel.idle). - */ -#endif /* CONFIG_ARMV7_M_ARMV8_M_MAINLINE */ - - /* Enter low power state */ - _sleep_if_allowed wfi - - /* - * Clear PRIMASK and flush instruction buffer to immediately service - * the wake-up interrupt. - */ - cpsie i - isb - - bx lr - -SECTION_FUNC(TEXT, arch_cpu_atomic_idle) -#if defined(CONFIG_TRACING) || \ - defined(CONFIG_ARM_ON_ENTER_CPU_IDLE_PREPARE_HOOK) - push {r0, lr} - -#ifdef CONFIG_TRACING - bl sys_trace_idle -#endif -#ifdef CONFIG_ARM_ON_ENTER_CPU_IDLE_PREPARE_HOOK - bl z_arm_on_enter_cpu_idle_prepare -#endif - -#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) - pop {r0, r1} - mov lr, r1 -#else - pop {r0, lr} -#endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */ -#endif - /* - * Lock PRIMASK while sleeping: wfe will still get interrupted by - * incoming interrupts but the CPU will not service them right away. - */ - cpsid i - - /* - * No need to set SEVONPEND, it's set once in z_arm_cpu_idle_init() - * and never touched again. - */ - - /* r0: interrupt mask from caller */ - -#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) - /* No BASEPRI, call wfe directly - * (SEVONPEND is set in z_arm_cpu_idle_init()) - */ - _sleep_if_allowed wfe - - cmp r0, #0 - bne _irq_disabled - cpsie i -_irq_disabled: - -#elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) - /* r1: zero, for setting BASEPRI (needs a register) */ - eors.n r1, r1 - - /* unlock BASEPRI so wfe gets interrupted by incoming interrupts */ - msr BASEPRI, r1 - - _sleep_if_allowed wfe - - msr BASEPRI, r0 - cpsie i -#else -#error Unknown ARM architecture -#endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */ - bx lr diff --git a/arch/arm/core/cortex_m/cpu_idle.c b/arch/arm/core/cortex_m/cpu_idle.c new file mode 100644 index 00000000000..4df091fbbd6 --- /dev/null +++ b/arch/arm/core/cortex_m/cpu_idle.c @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2013-2014 Wind River Systems, Inc. + * Copyright (c) 2023 Arm Limited + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief ARM Cortex-M power management + */ +#include +#include + +#if defined(CONFIG_ARM_ON_EXIT_CPU_IDLE) +#include +#endif + +/** + * @brief Initialization of CPU idle + * + * Only called by arch_kernel_init(). Sets SEVONPEND bit once for the system's + * duration. + */ +void z_arm_cpu_idle_init(void) +{ + SCB->SCR = SCB_SCR_SEVONPEND_Msk; +} + +#if defined(CONFIG_ARM_ON_EXIT_CPU_IDLE) +#define ON_EXIT_IDLE_HOOK SOC_ON_EXIT_CPU_IDLE +#else +#define ON_EXIT_IDLE_HOOK do {} while (false) +#endif + +#if defined(CONFIG_ARM_ON_ENTER_CPU_IDLE_HOOK) +#define SLEEP_IF_ALLOWED(wait_instr) do { \ + /* Skip the wait instr if on_enter_cpu_idle returns false */ \ + if (z_arm_on_enter_cpu_idle()) { \ + /* Wait for all memory transaction to complete */ \ + /* before entering low power state. */ \ + __DSB(); \ + wait_instr(); \ + /* Inline the macro provided by SoC-specific code */ \ + ON_EXIT_IDLE_HOOK; \ + } \ +} while (false) +#else +#define SLEEP_IF_ALLOWED(wait_instr) do { \ + __DSB(); \ + wait_instr(); \ + ON_EXIT_IDLE_HOOK; \ +} while (false) +#endif + +void arch_cpu_idle(void) +{ +#if defined(CONFIG_TRACING) + sys_trace_idle(); +#endif + +#if CONFIG_ARM_ON_ENTER_CPU_IDLE_PREPARE_HOOK + z_arm_on_enter_cpu_idle_prepare(); +#endif + +#if defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) + /* + * PRIMASK is always cleared on ARMv7-M and ARMv8-M (not used + * for interrupt locking), and configuring BASEPRI to the lowest + * priority to ensure wake-up will cause interrupts to be serviced + * before entering low power state. + * + * Set PRIMASK before configuring BASEPRI to prevent interruption + * before wake-up. + */ + __disable_irq(); + + /* + * Set wake-up interrupt priority to the lowest and synchronize to + * ensure that this is visible to the WFI instruction. + */ + __set_BASEPRI(0); + __ISB(); +#else + /* + * For all the other ARM architectures that do not implement BASEPRI, + * PRIMASK is used as the interrupt locking mechanism, and it is not + * necessary to set PRIMASK here, as PRIMASK would have already been + * set by the caller as part of interrupt locking if necessary + * (i.e. if the caller sets _kernel.idle). + */ +#endif + + SLEEP_IF_ALLOWED(__WFI); + + __enable_irq(); + __ISB(); +} + +void arch_cpu_atomic_idle(unsigned int key) +{ +#if defined(CONFIG_TRACING) + sys_trace_idle(); +#endif + +#if CONFIG_ARM_ON_ENTER_CPU_IDLE_PREPARE_HOOK + z_arm_on_enter_cpu_idle_prepare(); +#endif + + /* + * Lock PRIMASK while sleeping: wfe will still get interrupted by + * incoming interrupts but the CPU will not service them right away. + */ + __disable_irq(); + + /* + * No need to set SEVONPEND, it's set once in z_arm_cpu_idle_init() + * and never touched again. + */ + +#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) + /* No BASEPRI, call wfe directly. (SEVONPEND is set in z_arm_cpu_idle_init()) */ +#elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) + /* unlock BASEPRI so wfe gets interrupted by incoming interrupts */ + __set_BASEPRI(0); + __ISB(); +#else +#error Unsupported architecture +#endif + + SLEEP_IF_ALLOWED(__WFE); + + arch_irq_unlock(key); +#if defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) + __enable_irq(); +#endif +} diff --git a/arch/arm/core/cortex_m/exc_exit.S b/arch/arm/core/cortex_m/exc_exit.S deleted file mode 100644 index 351d2d3e475..00000000000 --- a/arch/arm/core/cortex_m/exc_exit.S +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2013-2014 Wind River Systems, Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief ARM Cortex-M exception/interrupt exit API - * - * Provides functions for performing kernel handling when exiting exceptions or - * interrupts that are installed directly in the vector table (i.e. that are not - * wrapped around by _isr_wrapper()). - */ - -#include -#include -#include -#include - -_ASM_FILE_PROLOGUE - -GTEXT(z_arm_exc_exit) -GTEXT(z_arm_int_exit) -GDATA(_kernel) - -/** - * - * @brief Kernel housekeeping when exiting interrupt handler installed - * directly in vector table - * - * Kernel allows installing interrupt handlers (ISRs) directly into the vector - * table to get the lowest interrupt latency possible. This allows the ISR to - * be invoked directly without going through a software interrupt table. - * However, upon exiting the ISR, some kernel work must still be performed, - * namely possible context switching. While ISRs connected in the software - * interrupt table do this automatically via a wrapper, ISRs connected directly - * in the vector table must invoke z_arm_int_exit() as the *very last* action - * before returning. - * - * e.g. - * - * void myISR(void) - * { - * printk("in %s\n", __FUNCTION__); - * doStuff(); - * z_arm_int_exit(); - * } - * - */ - -SECTION_SUBSEC_FUNC(TEXT, _HandlerModeExit, z_arm_int_exit) - -/* z_arm_int_exit falls through to z_arm_exc_exit (they are aliases of each - * other) - */ - -/** - * - * @brief Kernel housekeeping when exiting exception handler installed - * directly in vector table - * - * See z_arm_int_exit(). - * - */ - -SECTION_SUBSEC_FUNC(TEXT, _HandlerModeExit, z_arm_exc_exit) - -#ifdef CONFIG_PREEMPT_ENABLED - ldr r3, =_kernel - - ldr r1, [r3, #_kernel_offset_to_current] - ldr r0, [r3, #_kernel_offset_to_ready_q_cache] - cmp r0, r1 - beq _EXIT_EXC - - /* context switch required, pend the PendSV exception */ - ldr r1, =_SCS_ICSR - ldr r2, =_SCS_ICSR_PENDSV - str r2, [r1] - -_ExcExitWithGdbStub: - -_EXIT_EXC: -#endif /* CONFIG_PREEMPT_ENABLED */ - -#ifdef CONFIG_STACK_SENTINEL - push {r0, lr} - bl z_check_stack_sentinel -#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) - pop {r0, r1} - mov lr, r1 -#else - pop {r0, lr} -#endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */ -#endif /* CONFIG_STACK_SENTINEL */ - - bx lr diff --git a/arch/arm/core/cortex_m/exc_exit.c b/arch/arm/core/cortex_m/exc_exit.c new file mode 100644 index 00000000000..450b3972361 --- /dev/null +++ b/arch/arm/core/cortex_m/exc_exit.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2013-2014 Wind River Systems, Inc. + * Copyright (c) 2023 Arm Limited + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief ARM Cortex-M exception/interrupt exit API + * + * Provides functions for performing kernel handling when exiting exceptions or + * interrupts that are installed directly in the vector table (i.e. that are not + * wrapped around by _isr_wrapper()). + */ + +#include +#include +#include + +/** + * + * @brief Kernel housekeeping when exiting interrupt handler installed + * directly in vector table + * + * Kernel allows installing interrupt handlers (ISRs) directly into the vector + * table to get the lowest interrupt latency possible. This allows the ISR to + * be invoked directly without going through a software interrupt table. + * However, upon exiting the ISR, some kernel work must still be performed, + * namely possible context switching. While ISRs connected in the software + * interrupt table do this automatically via a wrapper, ISRs connected directly + * in the vector table must invoke z_arm_int_exit() as the *very last* action + * before returning. + * + * e.g. + * + * void myISR(void) + * { + * printk("in %s\n", __FUNCTION__); + * doStuff(); + * z_arm_int_exit(); + * } + * + */ +FUNC_ALIAS(z_arm_exc_exit, z_arm_int_exit, void); + +/** + * + * @brief Kernel housekeeping when exiting exception handler installed + * directly in vector table + * + * See z_arm_int_exit(). + * + */ +Z_GENERIC_SECTION(.text._HandlerModeExit) void z_arm_exc_exit(void) +{ +#ifdef CONFIG_PREEMPT_ENABLED + /* If thread is preemptible */ + if (_kernel.cpus->current->base.prio >= 0) { + /* and cached thread is not current thread */ + if (_kernel.ready_q.cache != _kernel.cpus->current) { + /* trigger a context switch */ + SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk; + } + } +#endif /* CONFIG_PREEMPT_ENABLED */ + +#ifdef CONFIG_STACK_SENTINEL + z_check_stack_sentinel(); +#endif /* CONFIG_STACK_SENTINEL */ +} diff --git a/arch/arm/core/cortex_m/irq_relay.S b/arch/arm/core/cortex_m/irq_relay.S index 229282c7650..1b2aafe505a 100644 --- a/arch/arm/core/cortex_m/irq_relay.S +++ b/arch/arm/core/cortex_m/irq_relay.S @@ -31,7 +31,7 @@ GDATA(z_main_stack) SECTION_FUNC(TEXT, __vector_relay_handler) mrs r0, ipsr; - lsls r0, r0, $0x02; + lsls r0, r0, #0x02; ldr r1, =_vector_table_pointer; ldr r1, [r1]; diff --git a/arch/arm/core/cortex_m/isr_wrapper.S b/arch/arm/core/cortex_m/isr_wrapper.S deleted file mode 100644 index f81b577804f..00000000000 --- a/arch/arm/core/cortex_m/isr_wrapper.S +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright (c) 2013-2014 Wind River Systems, Inc. - * Copyright (c) 2020 Stephanos Ioannidis - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief ARM Cortex-M wrapper for ISRs with parameter - * - * Wrapper installed in vector table for handling dynamic interrupts that accept - * a parameter. - */ -/* - * Tell armclang that stack alignment are ensured. - */ -.eabi_attribute Tag_ABI_align_preserved, 1 - -#include -#include -#include -#include -#include - - -_ASM_FILE_PROLOGUE - -GDATA(_sw_isr_table) - -GTEXT(_isr_wrapper) -GTEXT(z_arm_int_exit) - -/** - * - * @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 (see documentation for - * z_arm_pendsv()) and pends the PendSV exception if so: the latter will - * perform the context switch itself. - * - */ -SECTION_FUNC(TEXT, _isr_wrapper) - - push {r0,lr} /* r0, lr are now the first items on the stack */ - -#ifdef CONFIG_TRACING_ISR - bl sys_trace_isr_enter -#endif - -#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. - */ - - /* - * Disable interrupts to prevent nesting while exiting idle state. This - * is only necessary for the Cortex-M because it is the only ARM - * architecture variant that automatically enables interrupts when - * entering an ISR. - */ - cpsid i /* PRIMASK = 1 */ - - /* is this a wakeup from idle ? */ - ldr r2, =_kernel - /* requested idle duration, in ticks */ - ldr r0, [r2, #_kernel_offset_to_idle] - cmp r0, #0 - -#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) - beq _idle_state_cleared - movs.n r1, #0 - /* clear kernel idle state */ - str r1, [r2, #_kernel_offset_to_idle] - bl z_pm_save_idle_exit -_idle_state_cleared: - -#elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) - ittt ne - movne r1, #0 - /* clear kernel idle state */ - strne r1, [r2, #_kernel_offset_to_idle] - blne z_pm_save_idle_exit -#else -#error Unknown ARM architecture -#endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */ - - cpsie i /* re-enable interrupts (PRIMASK = 0) */ - -#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 -#endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */ - - 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 */ - 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 - -#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) - pop {r0, r3} - mov lr, r3 -#elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) - pop {r0, lr} -#else -#error Unknown ARM architecture -#endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */ - - /* Use 'bx' instead of 'b' because 'bx' can jump further, and use - * 'bx' instead of 'blx' because exception return is done in - * z_arm_int_exit() */ - ldr r1, =z_arm_int_exit - bx r1 diff --git a/arch/arm/core/cortex_m/isr_wrapper.c b/arch/arm/core/cortex_m/isr_wrapper.c new file mode 100644 index 00000000000..6e6016508c6 --- /dev/null +++ b/arch/arm/core/cortex_m/isr_wrapper.c @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2013-2014 Wind River Systems, Inc. + * Copyright (c) 2020 Stephanos Ioannidis + * Copyright (c) 2023 Arm Limited + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief ARM Cortex-M wrapper for ISRs with parameter + * + * Wrapper installed in vector table for handling dynamic interrupts that accept + * a parameter. + */ +#include +#include +#include +#include + +/** + * + * @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 (see documentation for + * z_arm_pendsv()) and pends the PendSV exception if so: the latter will + * perform the context switch itself. + * + */ +void _isr_wrapper(void) +{ +#ifdef CONFIG_TRACING_ISR + 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. + */ + + /* + * Disable interrupts to prevent nesting while exiting idle state. This + * is only necessary for the Cortex-M because it is the only ARM + * architecture variant that automatically enables interrupts when + * entering an ISR. + */ + __disable_irq(); + + /* is this a wakeup from idle ? */ + /* requested idle duration, in ticks */ + if (_kernel.idle != 0) { + /* clear kernel idle state */ + _kernel.idle = 0; + z_pm_save_idle_exit(); + } + /* re-enable interrupts */ + __enable_irq(); +#endif /* CONFIG_PM */ + +#if defined(CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER) + int32_t irq_number = z_soc_irq_get_active(); +#else + /* _sw_isr_table does not map the expections, only the interrupts. */ + int32_t irq_number = __get_IPSR(); +#endif + irq_number -= 16; + + struct _isr_table_entry *entry = &_sw_isr_table[irq_number]; + (entry->isr)(entry->arg); + +#if defined(CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER) + z_soc_irq_eoi(irq_number); +#endif + +#ifdef CONFIG_TRACING_ISR + sys_trace_isr_exit(); +#endif /* CONFIG_TRACING_ISR */ + + z_arm_exc_exit(); +} diff --git a/arch/arm/core/cortex_m/pm_s2ram.S b/arch/arm/core/cortex_m/pm_s2ram.S index aa715c8bbb9..1e5bca04fe2 100644 --- a/arch/arm/core/cortex_m/pm_s2ram.S +++ b/arch/arm/core/cortex_m/pm_s2ram.S @@ -14,12 +14,11 @@ #include #include -#define MAGIC (0xDABBAD00) - _ASM_FILE_PROLOGUE +GTEXT(pm_s2ram_mark_set) +GTEXT(pm_s2ram_mark_check_and_clear) GDATA(_cpu_context) -GDATA(marker) SECTION_FUNC(TEXT, arch_pm_s2ram_suspend) /* @@ -64,11 +63,9 @@ SECTION_FUNC(TEXT, arch_pm_s2ram_suspend) str r2, [r1, #___cpu_context_t_control_OFFSET] /* - * Set the marker to MAGIC value + * Mark entering suspend to RAM. */ - ldr r1, =marker - ldr r2, =MAGIC - str r2, [r1] + bl pm_s2ram_mark_set /* * Call the system_off function passed as parameter. This should never @@ -82,35 +79,29 @@ SECTION_FUNC(TEXT, arch_pm_s2ram_suspend) */ /* - * Reset the marker + * Reset the marking of suspend to RAM, return is ignored. */ - ldr r1, =marker - mov r2, #0x0 - str r2, [r1] + push {r0} + bl pm_s2ram_mark_check_and_clear + pop {r0} pop {r4-r12, lr} bx lr + GTEXT(arch_pm_s2ram_resume) SECTION_FUNC(TEXT, arch_pm_s2ram_resume) /* - * Check if the marker is set + * Check if reset occurred after suspending to RAM. */ - ldr r0, =marker - ldr r0, [r0] - ldr r1, =MAGIC - cmp r0, r1 + push {lr} + bl pm_s2ram_mark_check_and_clear + cmp r0, #0x1 + pop {lr} beq resume bx lr resume: - /* - * Reset the marker - */ - ldr r0, =marker - mov r1, #0x0 - str r1, [r0] - /* * Restore the CPU context */ diff --git a/arch/arm/core/cortex_m/pm_s2ram.c b/arch/arm/core/cortex_m/pm_s2ram.c index 7b499278dd2..2657d48dc32 100644 --- a/arch/arm/core/cortex_m/pm_s2ram.c +++ b/arch/arm/core/cortex_m/pm_s2ram.c @@ -9,12 +9,33 @@ #include +#define MAGIC (0xDABBAD00) + /** * CPU context for S2RAM */ __noinit _cpu_context_t _cpu_context; +#ifndef CONFIG_PM_S2RAM_CUSTOM_MARKING /** * S2RAM Marker */ -__noinit uint32_t marker; +static __noinit uint32_t marker; + +void pm_s2ram_mark_set(void) +{ + marker = MAGIC; +} + +bool pm_s2ram_mark_check_and_clear(void) +{ + if (marker == MAGIC) { + marker = 0; + + return true; + } + + return false; +} + +#endif /* CONFIG_PM_S2RAM_CUSTOM_MARKING */ diff --git a/arch/arm/core/cortex_m/swap.c b/arch/arm/core/cortex_m/swap.c index 9a597ef219d..b60f6acd675 100644 --- a/arch/arm/core/cortex_m/swap.c +++ b/arch/arm/core/cortex_m/swap.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2018 Linaro, Limited + * Copyright (c) 2023 Arm Limited * * SPDX-License-Identifier: Apache-2.0 */ @@ -47,3 +48,59 @@ int arch_swap(unsigned int key) */ return _current->arch.swap_return_value; } + +uintptr_t z_arm_pendsv_c(uintptr_t exc_ret) +{ + /* Store LSB of LR (EXC_RETURN) to the thread's 'mode' word. */ + IF_ENABLED(CONFIG_ARM_STORE_EXC_RETURN, + (_kernel.cpus[0].current->arch.mode_exc_return = (uint8_t)exc_ret;)); + + /* Protect the kernel state while we play with the thread lists */ + uint32_t basepri = arch_irq_lock(); + + /* fetch the thread to run from the ready queue cache */ + struct k_thread *current = _kernel.cpus[0].current = _kernel.ready_q.cache; + + /* + * Clear PendSV so that if another interrupt comes in and + * decides, with the new kernel state based on the new thread + * being context-switched in, that it needs to reschedule, it + * will take, but that previously pended PendSVs do not take, + * since they were based on the previous kernel state and this + * has been handled. + */ + SCB->ICSR = SCB_ICSR_PENDSVCLR_Msk; + + /* For Cortex-M, store TLS pointer in a global variable, + * as it lacks the process ID or thread ID register + * to be used by toolchain to access thread data. + */ + IF_ENABLED(CONFIG_THREAD_LOCAL_STORAGE, + (extern uintptr_t z_arm_tls_ptr; z_arm_tls_ptr = current->tls)); + + IF_ENABLED(CONFIG_ARM_STORE_EXC_RETURN, + (exc_ret = (exc_ret & 0xFFFFFF00) | current->arch.mode_exc_return)); + + /* Restore previous interrupt disable state (irq_lock key) + * (We clear the arch.basepri field after restoring state) + */ + basepri = current->arch.basepri; + current->arch.basepri = 0; + + arch_irq_unlock(basepri); + +#if defined(CONFIG_MPU_STACK_GUARD) || defined(CONFIG_USERSPACE) + /* Re-program dynamic memory map */ + z_arm_configure_dynamic_mpu_regions(current); +#endif + + /* restore mode */ + IF_ENABLED(CONFIG_USERSPACE, ({ + CONTROL_Type ctrl = {.w = __get_CONTROL()}; + /* exit privileged state when returing to thread mode. */ + ctrl.b.nPRIV = 0; + __set_CONTROL(ctrl.w | current->arch.mode); + })); + + return exc_ret; +} diff --git a/arch/arm/core/cortex_m/swap_helper.S b/arch/arm/core/cortex_m/swap_helper.S index af1d0d791dd..c2cb3ef7f2f 100644 --- a/arch/arm/core/cortex_m/swap_helper.S +++ b/arch/arm/core/cortex_m/swap_helper.S @@ -27,6 +27,7 @@ _ASM_FILE_PROLOGUE GTEXT(z_arm_svc) GTEXT(z_arm_pendsv) GTEXT(z_do_kernel_oops) +GTEXT(z_arm_pendsv_c) #if defined(CONFIG_USERSPACE) GTEXT(z_arm_do_syscall) #endif @@ -94,7 +95,7 @@ SECTION_FUNC(TEXT, z_arm_pendsv) /* store r8-12 */ stmea r0!, {r3-r7} #elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) - stmia r0, {v1-v8, ip} + stmia r0, {r4-r11, ip} #ifdef CONFIG_FPU_SHARING /* Assess whether switched-out thread had been using the FP registers. */ tst lr, #_EXC_RETURN_FTYPE_Msk @@ -117,125 +118,20 @@ out_fp_endif: #error Unknown ARM architecture #endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */ - /* Protect the kernel state while we play with the thread lists */ -#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) - cpsid i -#elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) - movs.n r0, #_EXC_IRQ_DEFAULT_PRIO - msr BASEPRI_MAX, r0 - isb /* Make the effect of disabling interrupts be realized immediately */ -#else -#error Unknown ARM architecture -#endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */ - - /* - * Prepare to clear PendSV with interrupts unlocked, but - * don't clear it yet. PendSV must not be cleared until - * the new thread is context-switched in since all decisions - * to pend PendSV have been taken with the current kernel - * state and this is what we're handling currently. - */ - ldr v4, =_SCS_ICSR - ldr v3, =_SCS_ICSR_UNPENDSV - - /* _kernel is still in r1 */ - - /* fetch the thread to run from the ready queue cache */ - ldr r2, [r1, #_kernel_offset_to_ready_q_cache] - - str r2, [r1, #_kernel_offset_to_current] - - /* - * Clear PendSV so that if another interrupt comes in and - * decides, with the new kernel state based on the new thread - * being context-switched in, that it needs to reschedule, it - * will take, but that previously pended PendSVs do not take, - * since they were based on the previous kernel state and this - * has been handled. - */ - - /* _SCS_ICSR is still in v4 and _SCS_ICSR_UNPENDSV in v3 */ - str v3, [v4, #0] + mov r4, lr + mov r0, lr + bl z_arm_pendsv_c + mov lr, r4 -#if defined(CONFIG_THREAD_LOCAL_STORAGE) - /* Grab the TLS pointer */ - ldr r4, =_thread_offset_to_tls - adds r4, r2, r4 - ldr r0, [r4] - - /* For Cortex-M, store TLS pointer in a global variable, - * as it lacks the process ID or thread ID register - * to be used by toolchain to access thread data. - */ - ldr r4, =z_arm_tls_ptr - str r0, [r4] -#endif + ldr r1, =_kernel + ldr r2, [r1, #_kernel_offset_to_current] #if defined(CONFIG_ARM_STORE_EXC_RETURN) /* Restore EXC_RETURN value. */ - ldrsb lr, [r2, #_thread_offset_to_mode_exc_return] -#endif - - /* Restore previous interrupt disable state (irq_lock key) - * (We clear the arch.basepri field after restoring state) - */ -#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) && (_thread_offset_to_basepri > 124) - /* Doing it this way since the offset to thread->arch.basepri can in - * some configurations be larger than the maximum of 124 for ldr/str - * immediate offsets. - */ - ldr r4, =_thread_offset_to_basepri - adds r4, r2, r4 - - ldr r0, [r4] - movs.n r3, #0 - str r3, [r4] -#else - ldr r0, [r2, #_thread_offset_to_basepri] - movs r3, #0 - str r3, [r2, #_thread_offset_to_basepri] + mov lr, r0 #endif #if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) - /* BASEPRI not available, previous interrupt disable state - * maps to PRIMASK. - * - * Only enable interrupts if value is 0, meaning interrupts - * were enabled before irq_lock was called. - */ - cmp r0, #0 - bne _thread_irq_disabled - cpsie i -_thread_irq_disabled: - -#if defined(CONFIG_MPU_STACK_GUARD) || defined(CONFIG_USERSPACE) - /* Re-program dynamic memory map */ - push {r2,lr} - mov r0, r2 - bl z_arm_configure_dynamic_mpu_regions - pop {r2,r3} - mov lr, r3 -#endif - -#ifdef CONFIG_USERSPACE - /* restore mode */ - ldr r3, =_thread_offset_to_mode - adds r3, r2, r3 - ldr r0, [r3] - mrs r3, CONTROL - movs.n r1, #1 - bics r3, r1 - orrs r3, r0 - msr CONTROL, r3 - - /* ISB is not strictly necessary here (stack pointer is not being - * touched), but it's recommended to avoid executing pre-fetched - * instructions with the previous privilege. - */ - isb - -#endif - ldr r4, =_thread_offset_to_callee_saved adds r0, r2, r4 @@ -253,9 +149,6 @@ _thread_irq_disabled: subs r0, #36 ldmia r0!, {r4-r7} #elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) - /* restore BASEPRI for the incoming thread */ - msr BASEPRI, r0 - #ifdef CONFIG_FPU_SHARING /* Assess whether switched-in thread had been using the FP registers. */ tst lr, #_EXC_RETURN_FTYPE_Msk @@ -285,33 +178,9 @@ in_fp_endif: isb #endif -#if defined(CONFIG_MPU_STACK_GUARD) || defined(CONFIG_USERSPACE) - /* Re-program dynamic memory map */ - push {r2,lr} - mov r0, r2 /* _current thread */ - bl z_arm_configure_dynamic_mpu_regions - pop {r2,lr} -#endif - -#ifdef CONFIG_USERSPACE - /* restore mode */ - ldr r0, [r2, #_thread_offset_to_mode] - mrs r3, CONTROL - bic r3, #1 - orr r3, r0 - msr CONTROL, r3 - - /* ISB is not strictly necessary here (stack pointer is not being - * touched), but it's recommended to avoid executing pre-fetched - * instructions with the previous privilege. - */ - isb - -#endif - /* load callee-saved + psp from thread */ add r0, r2, #_thread_offset_to_callee_saved - ldmia r0, {v1-v8, ip} + ldmia r0, {r4-r11, ip} #else #error Unknown ARM architecture #endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */ @@ -429,7 +298,8 @@ _stack_frame_endif: #endif /* exception return is done in z_arm_int_exit() */ - b z_arm_int_exit + ldr r0, =z_arm_int_exit + bx r0 #endif _oops: diff --git a/arch/arm/core/cortex_m/thread.c b/arch/arm/core/cortex_m/thread.c index 980f35566c5..e9ab7292ab5 100644 --- a/arch/arm/core/cortex_m/thread.c +++ b/arch/arm/core/cortex_m/thread.c @@ -1,6 +1,7 @@ /* * Copyright (c) 2013-2014 Wind River Systems, Inc. * Copyright (c) 2021 Lexmark International, Inc. + * Copyright (c) 2023 Arm Limited * * SPDX-License-Identifier: Apache-2.0 */ @@ -554,39 +555,58 @@ void arch_switch_to_main_thread(struct k_thread *main_thread, char *stack_ptr, #if defined(CONFIG_CPU_CORTEX_M_HAS_SPLIM) __set_PSPLIM(main_thread->stack_info.start); #else -#error "Built-in PSP limit checks not supported by HW" +#error "Built-in PSP limit checks not supported by the hardware." #endif #endif /* CONFIG_BUILTIN_STACK_GUARD */ /* * Set PSP to the highest address of the main stack * before enabling interrupts and jumping to main. + * + * The compiler may store _main on the stack, but this + * location is relative to `PSP`. + * This assembly block ensures that _main is stored in + * a callee saved register before switching stack and continuing + * with the thread entry process. + * + * When calling arch_irq_unlock_outlined, LR is lost which is fine since + * we do not intend to return after calling z_thread_entry. */ __asm__ volatile ( - "mov r0, %0\n\t" /* Store _main in R0 */ - "msr PSP, %1\n\t" /* __set_PSP(stack_ptr) */ - - "movs r1, #0\n\t" -#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) - "cpsie i\n\t" /* __enable_irq() */ -#elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) - "cpsie if\n\t" /* __enable_irq(); __enable_fault_irq() */ - "msr BASEPRI, r1\n\t" /* __set_BASEPRI(0) */ -#else -#error Unknown ARM architecture -#endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */ - "isb\n\t" - "movs r2, #0\n\t" - "movs r3, #0\n\t" - "bl z_thread_entry\n\t" /* z_thread_entry(_main, 0, 0, 0); */ - : - : "r" (_main), "r" (stack_ptr) - : "r0" /* not to be overwritten by msr PSP, %1 */ - ); + "mov r4, %0\n" /* force _main to be stored in a register */ + "msr PSP, %1\n" /* __set_PSP(stack_ptr) */ + + "mov r0, #0\n" /* arch_irq_unlock(0) */ + "ldr r3, =arch_irq_unlock_outlined\n" + "blx r3\n" + + "mov r0, r4\n" /* z_thread_entry(_main, NULL, NULL, NULL) */ + "mov r1, #0\n" + "mov r2, #0\n" + "mov r3, #0\n" + "ldr r4, =z_thread_entry\n" + "bx r4\n" /* We donā€™t intend to return, so there is no need to link. */ + : "+r" (_main) + : "r" (stack_ptr) + : "r0", "r1", "r2", "r3", "r4"); CODE_UNREACHABLE; } +__used void arch_irq_unlock_outlined(unsigned int key) +{ +#if defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) + __enable_fault_irq(); /* alters FAULTMASK */ + __enable_irq(); /* alters PRIMASK */ +#endif + arch_irq_unlock(key); +} + +__used unsigned int arch_irq_lock_outlined(void) +{ + return arch_irq_lock(); +} + #if !defined(CONFIG_MULTITHREADING) FUNC_NORETURN void z_arm_switch_to_main_no_multithreading( @@ -608,42 +628,38 @@ FUNC_NORETURN void z_arm_switch_to_main_no_multithreading( * after stack pointer change. The function is not going * to return, so callee-saved registers do not need to be * stacked. + * + * The compiler may store _main on the stack, but this + * location is relative to `PSP`. + * This assembly block ensures that _main is stored in + * a callee saved register before switching stack and continuing + * with the thread entry process. */ - register void *p1_inreg __asm__("r0") = p1; - register void *p2_inreg __asm__("r1") = p2; - register void *p3_inreg __asm__("r2") = p3; __asm__ volatile ( #ifdef CONFIG_BUILTIN_STACK_GUARD - "msr PSPLIM, %[_psplim]\n\t" -#endif - "msr PSP, %[_psp]\n\t" /* __set_PSP(psp) */ -#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) - "cpsie i\n\t" /* enable_irq() */ -#elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) - "cpsie if\n\t" /* __enable_irq(); __enable_fault_irq() */ - "mov r3, #0\n\t" - "msr BASEPRI, r3\n\t" /* __set_BASEPRI(0) */ -#endif - "isb\n\t" - "blx %[_main_entry]\n\t" /* main_entry(p1, p2, p3) */ -#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) - "cpsid i\n\t" /* disable_irq() */ -#elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) - "msr BASEPRI, %[basepri]\n\t"/* __set_BASEPRI(_EXC_IRQ_DEFAULT_PRIO) */ - "isb\n\t" + "msr PSPLIM, %[_psplim]\n" /* __set_PSPLIM(_psplim) */ #endif + "msr PSP, %[_psp]\n" /* __set_PSP(psp) */ + "mov r0, #0\n" + "ldr r1, =arch_irq_unlock_outlined\n" + "blx r1\n" + + "mov r0, %[_p1]\n" + "mov r1, %[_p2]\n" + "mov r2, %[_p3]\n" + "blx %[_main_entry]\n" /* main_entry(p1, p2, p3) */ + + "ldr r0, =arch_irq_lock_outlined\n" + "blx r0\n" "loop: b loop\n\t" /* while (true); */ : - : "r" (p1_inreg), "r" (p2_inreg), "r" (p3_inreg), + : [_p1]"r" (p1), [_p2]"r" (p2), [_p3]"r" (p3), [_psp]"r" (psp), [_main_entry]"r" (main_entry) -#if defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) - , [basepri] "r" (_EXC_IRQ_DEFAULT_PRIO) -#endif #ifdef CONFIG_BUILTIN_STACK_GUARD , [_psplim]"r" (psplim) #endif - : + : "r0", "r1", "r2", "r3" ); CODE_UNREACHABLE; /* LCOV_EXCL_LINE */ diff --git a/arch/arm/core/fatal.c b/arch/arm/core/fatal.c index c5adebf8ee7..4364d48d45d 100644 --- a/arch/arm/core/fatal.c +++ b/arch/arm/core/fatal.c @@ -73,6 +73,16 @@ void z_arm_fatal_error(unsigned int reason, const z_arch_esf_t *esf) esf_dump(esf); } #endif /* CONFIG_EXCEPTION_DEBUG */ + + /* LOG the IRQn that was unhandled */ +#if defined(CONFIG_CPU_CORTEX_M) + if (reason == K_ERR_SPURIOUS_IRQ) { + uint32_t irqn = __get_IPSR() - 16; + + LOG_ERR("Unhandled IRQn: %d", irqn); + } +#endif + z_fatal_error(reason, esf); } diff --git a/arch/arm/core/irq_offload.c b/arch/arm/core/irq_offload.c index 4e183c02e57..5dc1feccf7a 100644 --- a/arch/arm/core/irq_offload.c +++ b/arch/arm/core/irq_offload.c @@ -10,6 +10,7 @@ #include #include +#include volatile irq_offload_routine_t offload_routine; static const void *offload_param; @@ -22,14 +23,11 @@ void z_irq_do_offload(void) void arch_irq_offload(irq_offload_routine_t routine, const void *parameter) { -#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) && defined(CONFIG_ASSERT) - /* ARMv6-M/ARMv8-M Baseline HardFault if you make a SVC call with - * interrupts locked. +#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) && !defined(CONFIG_ARMV8_M_BASELINE) \ + && defined(CONFIG_ASSERT) + /* ARMv6-M HardFault if you make a SVC call with interrupts locked. */ - unsigned int key; - - __asm__ volatile("mrs %0, PRIMASK;" : "=r" (key) : : "memory"); - __ASSERT(key == 0U, "irq_offload called with interrupts locked\n"); + __ASSERT(__get_PRIMASK() == 0U, "irq_offload called with interrupts locked\n"); #endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE && CONFIG_ASSERT */ k_sched_lock(); diff --git a/arch/arm/core/mpu/Kconfig b/arch/arm/core/mpu/Kconfig index dc540038e2b..c6d1bdc7da0 100644 --- a/arch/arm/core/mpu/Kconfig +++ b/arch/arm/core/mpu/Kconfig @@ -14,6 +14,8 @@ config ARM_MPU select MPU_REQUIRES_POWER_OF_TWO_ALIGNMENT if !(CPU_HAS_NXP_MPU || ARMV8_M_BASELINE || ARMV8_M_MAINLINE || AARCH32_ARMV8_R) select MPU_REQUIRES_NON_OVERLAPPING_REGIONS if CPU_HAS_ARM_MPU && (ARMV8_M_BASELINE || ARMV8_M_MAINLINE || AARCH32_ARMV8_R) select MPU_GAP_FILLING if AARCH32_ARMV8_R + select ARCH_MEM_DOMAIN_SUPPORTS_ISOLATED_STACKS + select MEM_DOMAIN_ISOLATED_STACKS help MCU implements Memory Protection Unit. diff --git a/arch/arm/core/mpu/arm_core_mpu.c b/arch/arm/core/mpu/arm_core_mpu.c index 2fb0f141125..dde98c0b07f 100644 --- a/arch/arm/core/mpu/arm_core_mpu.c +++ b/arch/arm/core/mpu/arm_core_mpu.c @@ -338,7 +338,7 @@ int arch_mem_domain_max_partitions_get(void) return ARM_CORE_MPU_MAX_DOMAIN_PARTITIONS_GET(available_regions); } -int arch_buffer_validate(void *addr, size_t size, int write) +int arch_buffer_validate(const void *addr, size_t size, int write) { return arm_core_mpu_buffer_validate(addr, size, write); } diff --git a/arch/arm/core/mpu/arm_core_mpu_dev.h b/arch/arm/core/mpu/arm_core_mpu_dev.h index fd56131d7dc..254d6d9dda3 100644 --- a/arch/arm/core/mpu/arm_core_mpu_dev.h +++ b/arch/arm/core/mpu/arm_core_mpu_dev.h @@ -261,7 +261,7 @@ int arm_core_mpu_get_max_available_dyn_regions(void); * spans multiple enabled MPU regions (even if these regions all * permit user access). */ -int arm_core_mpu_buffer_validate(void *addr, size_t size, int write); +int arm_core_mpu_buffer_validate(const void *addr, size_t size, int write); #endif /* CONFIG_ARM_MPU */ diff --git a/arch/arm/core/mpu/arm_mpu.c b/arch/arm/core/mpu/arm_mpu.c index cd4c8ccd7a0..52ad585b79c 100644 --- a/arch/arm/core/mpu/arm_mpu.c +++ b/arch/arm/core/mpu/arm_mpu.c @@ -341,7 +341,7 @@ int arm_core_mpu_get_max_available_dyn_regions(void) * * Presumes the background mapping is NOT user accessible. */ -int arm_core_mpu_buffer_validate(void *addr, size_t size, int write) +int arm_core_mpu_buffer_validate(const void *addr, size_t size, int write) { return mpu_buffer_validate(addr, size, write); } diff --git a/arch/arm/core/mpu/arm_mpu_v7_internal.h b/arch/arm/core/mpu/arm_mpu_v7_internal.h index 1fe3417901e..9641ab25000 100644 --- a/arch/arm/core/mpu/arm_mpu_v7_internal.h +++ b/arch/arm/core/mpu/arm_mpu_v7_internal.h @@ -169,7 +169,7 @@ static inline int is_user_accessible_region(uint32_t r_index, int write) * This internal function validates whether a given memory buffer * is user accessible or not. */ -static inline int mpu_buffer_validate(void *addr, size_t size, int write) +static inline int mpu_buffer_validate(const void *addr, size_t size, int write) { int32_t r_index; int rc = -EPERM; diff --git a/arch/arm/core/mpu/arm_mpu_v8_internal.h b/arch/arm/core/mpu/arm_mpu_v8_internal.h index 751786d5a4c..66a00a452a7 100644 --- a/arch/arm/core/mpu/arm_mpu_v8_internal.h +++ b/arch/arm/core/mpu/arm_mpu_v8_internal.h @@ -408,7 +408,7 @@ static inline int is_user_accessible_region(uint32_t rnr, int write) * This internal function validates whether a given memory buffer * is user accessible or not. */ -static inline int mpu_buffer_validate(void *addr, size_t size, int write) +static inline int mpu_buffer_validate(const void *addr, size_t size, int write) { int32_t rnr; int rc = -EPERM; @@ -455,7 +455,7 @@ static inline int mpu_buffer_validate(void *addr, size_t size, int write) * in case the fast address range check fails. * */ -static inline int mpu_buffer_validate(void *addr, size_t size, int write) +static inline int mpu_buffer_validate(const void *addr, size_t size, int write) { uint32_t _addr = (uint32_t)addr; uint32_t _size = (uint32_t)size; diff --git a/arch/arm/core/mpu/nxp_mpu.c b/arch/arm/core/mpu/nxp_mpu.c index 39d7cde6f8f..b0fe24c6bf6 100644 --- a/arch/arm/core/mpu/nxp_mpu.c +++ b/arch/arm/core/mpu/nxp_mpu.c @@ -602,7 +602,7 @@ static inline int is_user_accessible_region(uint32_t r_index, int write) /** * @brief validate the given buffer is user accessible or not */ -int arm_core_mpu_buffer_validate(void *addr, size_t size, int write) +int arm_core_mpu_buffer_validate(const void *addr, size_t size, int write) { uint8_t r_index; diff --git a/arch/arm64/core/fatal.c b/arch/arm64/core/fatal.c index 5d475e4c655..84ff767508e 100644 --- a/arch/arm64/core/fatal.c +++ b/arch/arm64/core/fatal.c @@ -313,11 +313,13 @@ void z_arm64_fatal_error(unsigned int reason, z_arch_esf_t *esf) far = read_far_el1(); elr = read_elr_el1(); break; +#if !defined(CONFIG_ARMV8_R) case MODE_EL3: esr = read_esr_el3(); far = read_far_el3(); elr = read_elr_el3(); break; +#endif /* CONFIG_ARMV8_R */ } #ifdef CONFIG_ARM64_STACK_PROTECTION diff --git a/arch/arm64/core/reset.S b/arch/arm64/core/reset.S index cfcffec4ce7..5e406bea132 100644 --- a/arch/arm64/core/reset.S +++ b/arch/arm64/core/reset.S @@ -43,6 +43,7 @@ SECTION_SUBSEC_FUNC(TEXT,_reset_section,__reset_prep_c) switch_el x0, 3f, 2f, 1f 3: +#if !defined(CONFIG_ARMV8_R) /* Reinitialize SCTLR from scratch in EL3 */ ldr w0, =(SCTLR_EL3_RES1 | SCTLR_I_BIT | SCTLR_SA_BIT) msr sctlr_el3, x0 @@ -55,6 +56,7 @@ SECTION_SUBSEC_FUNC(TEXT,_reset_section,__reset_prep_c) msr sp_el1, x24 b out +#endif /* CONFIG_ARMV8_R */ 2: /* Disable alignment fault checking */ mrs x0, sctlr_el2 @@ -216,7 +218,9 @@ stack_init_done: switch_el: switch_el x0, 3f, 2f, 1f + 3: +#if !defined(CONFIG_ARMV8_R) /* EL3 init */ bl z_arm64_el3_init @@ -224,6 +228,7 @@ switch_el: adr x0, switch_el bl z_arm64_el3_get_next_el eret +#endif /* CONFIG_ARMV8_R */ 2: /* EL2 init */ diff --git a/arch/arm64/core/reset.c b/arch/arm64/core/reset.c index f96783318f4..03cf389007d 100644 --- a/arch/arm64/core/reset.c +++ b/arch/arm64/core/reset.c @@ -41,6 +41,8 @@ void z_arm64_el_highest_init(void) barrier_isync_fence_full(); } + +#if !defined(CONFIG_ARMV8_R) enum el3_next_el { EL3_TO_EL2, EL3_TO_EL1_NO_EL2, @@ -113,6 +115,7 @@ void z_arm64_el3_init(void) z_arm64_el2_init(); } } +#endif /* CONFIG_ARMV8_R */ void z_arm64_el2_init(void) { @@ -195,6 +198,7 @@ void z_arm64_el1_init(void) barrier_isync_fence_full(); } +#if !defined(CONFIG_ARMV8_R) void z_arm64_el3_get_next_el(uint64_t switch_addr) { uint64_t spsr; @@ -214,3 +218,4 @@ void z_arm64_el3_get_next_el(uint64_t switch_addr) write_spsr_el3(spsr); } +#endif /* CONFIG_ARMV8_R */ diff --git a/arch/arm64/core/userspace.S b/arch/arm64/core/userspace.S index 618aa6b2c20..968d2a436bc 100644 --- a/arch/arm64/core/userspace.S +++ b/arch/arm64/core/userspace.S @@ -51,7 +51,7 @@ strlen_done: ret /* - * int arch_buffer_validate(void *addr, size_t size, int write) + * int arch_buffer_validate(const void *addr, size_t size, int write) */ GTEXT(arch_buffer_validate) diff --git a/arch/posix/CMakeLists.txt b/arch/posix/CMakeLists.txt index 478e29cac1e..8dfc696bc6d 100644 --- a/arch/posix/CMakeLists.txt +++ b/arch/posix/CMakeLists.txt @@ -99,11 +99,13 @@ elseif (CONFIG_NATIVE_LIBRARY) get_filename_component(COMPILER_OWN_INCLUDE_PATH "${_OUTPUT}" DIRECTORY) # Do not use the C library from this compiler/host, - # but still use the basic compiler headers + # but still use the basic compiler headers, + # remove all operating system specific predefined macros, # no_builtin to avoid the compiler using builtin replacements for std library functions zephyr_compile_options( -nostdinc -isystem ${COMPILER_OWN_INCLUDE_PATH} + "SHELL:-include ${ZEPHYR_BASE}/arch/posix/include/undef_system_defines.h" $ $ ) @@ -171,10 +173,12 @@ endif() if(CONFIG_ASAN_RECOVER) zephyr_compile_options(-fsanitize-recover=all) + target_compile_options(native_simulator INTERFACE "-fsanitize-recover=all") endif() if(CONFIG_ARCH_POSIX_LIBFUZZER) list(APPEND LLVM_SANITIZERS "fuzzer") + target_compile_options(native_simulator INTERFACE "-DNSI_NO_MAIN=1") if(NOT CONFIG_64BIT) # On i386, libfuzzer seems to dynamically relocate the binary, so # we need to emit PIC code. This limitation is undocumented and @@ -187,17 +191,12 @@ list(JOIN LLVM_SANITIZERS "," LLVM_SANITIZERS_ARG) if(NOT ${LLVM_SANITIZERS_ARG} STREQUAL "") set(LLVM_SANITIZERS_ARG "-fsanitize=${LLVM_SANITIZERS_ARG}") zephyr_compile_options("${LLVM_SANITIZERS_ARG}") - zephyr_link_libraries("${LLVM_SANITIZERS_ARG}") + if (CONFIG_NATIVE_APPLICATION) + zephyr_link_libraries("${LLVM_SANITIZERS_ARG}") + endif() target_link_options(native_simulator INTERFACE ${LLVM_SANITIZERS_ARG}) target_compile_options(native_simulator INTERFACE ${LLVM_SANITIZERS_ARG}) endif() -# Override the C standard used for compilation to C 2011 -# This is due to some tests using _Static_assert which is a 2011 feature, but -# otherwise relying on compilers supporting it also when set to C99. -# This was in general ok, but with some host compilers and C library versions -# it led to problems. So we override it to 2011 for the native targets. -set_property(GLOBAL PROPERTY CSTD c11) - add_subdirectory(core) diff --git a/arch/posix/Kconfig b/arch/posix/Kconfig index a31e1349b21..1ed79b38976 100644 --- a/arch/posix/Kconfig +++ b/arch/posix/Kconfig @@ -22,12 +22,12 @@ config ARCH_POSIX_RECOMMENDED_STACK_SIZE thread stack, the real stack is the native underlying pthread stack. Therefore the allocated stack can be limited to this size) -menuconfig ARCH_POSIX_LIBFUZZER +config ARCH_POSIX_LIBFUZZER bool "Build fuzz test target" help - Build the posix app as a LLVM libfuzzer target. Requires + Build as an LLVM libfuzzer target. Requires support from the toolchain (currently only clang works, and - only on native_posix/native/64), and should normally be used in + only on native_{posix,sim}[//64]), and should normally be used in concert with some of CONFIG_ASAN/UBSAN/MSAN for validation. The application needs to implement the LLVMFuzzerTestOneInput() entry point, which runs in the host @@ -35,28 +35,6 @@ menuconfig ARCH_POSIX_LIBFUZZER sample and https://llvm.org/docs/LibFuzzer.html for more information. -if ARCH_POSIX_LIBFUZZER - -config ARCH_POSIX_FUZZ_IRQ - int "OS interrupt via which to deliver fuzz cases" - default 3 - help - When using libfuzzer, new fuzz cases are delivered to Zephyr - via interrupts. The IRQ should be otherwise unused, but can - be any value desired by the app. - -config ARCH_POSIX_FUZZ_TICKS - int "Ticks to allow for fuzz case processing" - default 2 - help - Fuzz interrupts are delivered, from the perspective of the - OS, at a steady cadence in simulated time. In general most - apps won't require much time to reach an idle state - following a unit-test style case, so the default is short to - prevent interaction with regular timer workloads. - -endif # CONFIG_ARCH_POSIX_LIBFUZZER - config ARCH_POSIX_TRAP_ON_FATAL bool "Raise a SIGTRAP on fatal error" help diff --git a/arch/posix/include/undef_system_defines.h b/arch/posix/include/undef_system_defines.h new file mode 100644 index 00000000000..d7384e403a6 --- /dev/null +++ b/arch/posix/include/undef_system_defines.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2024 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * Undefine all system-specific macros defined internally, by the compiler. + * Run 'gcc -dM -E - < /dev/null | sort' to get full list of internally + * defined macros. + */ + +#undef __gnu_linux__ +#undef __linux +#undef __linux__ +#undef linux + +#undef __unix +#undef __unix__ +#undef unix diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 66c96cddda9..1c4d547b29c 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -38,6 +38,23 @@ config RISCV_ALWAYS_SWITCH_THROUGH_ECALL and most people should say n here to minimize context switching overhead. +config RISCV_ENABLE_FRAME_POINTER + bool + default y + depends on OVERRIDE_FRAME_POINTER_DEFAULT && !OMIT_FRAME_POINTER + help + Hidden option to simplify access to OVERRIDE_FRAME_POINTER_DEFAULT + and OMIT_FRAME_POINTER. It is automatically enabled when the frame + pointer unwinding is enabled. + +config RISCV_EXCEPTION_STACK_TRACE + bool + default y + depends on EXCEPTION_STACK_TRACE + imply THREAD_STACK_INFO + help + Internal config to enable runtime stack traces on fatal exceptions. + menu "RISCV Processor Options" config INCLUDE_RESET_VECTOR @@ -249,6 +266,8 @@ config RISCV_PMP select ARCH_MEM_DOMAIN_SYNCHRONOUS_API if USERSPACE select ARCH_MEM_DOMAIN_DATA if USERSPACE select THREAD_LOCAL_STORAGE if USERSPACE + select ARCH_MEM_DOMAIN_SUPPORTS_ISOLATED_STACKS + select MEM_DOMAIN_ISOLATED_STACKS help MCU implements Physical Memory Protection. diff --git a/arch/riscv/core/CMakeLists.txt b/arch/riscv/core/CMakeLists.txt index 1d8daac060c..7ffcffd65c8 100644 --- a/arch/riscv/core/CMakeLists.txt +++ b/arch/riscv/core/CMakeLists.txt @@ -25,4 +25,5 @@ zephyr_library_sources_ifdef(CONFIG_RISCV_PMP pmp.c pmp.S) zephyr_library_sources_ifdef(CONFIG_THREAD_LOCAL_STORAGE tls.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE userspace.S) zephyr_library_sources_ifdef(CONFIG_SEMIHOST semihost.c) +zephyr_library_sources_ifdef(CONFIG_RISCV_EXCEPTION_STACK_TRACE stacktrace.c) zephyr_linker_sources(ROM_START SORT_KEY 0x0vectors vector_table.ld) diff --git a/arch/riscv/core/coredump.c b/arch/riscv/core/coredump.c index c7a63dae6de..f232816433a 100644 --- a/arch/riscv/core/coredump.c +++ b/arch/riscv/core/coredump.c @@ -7,9 +7,35 @@ #include #include +#ifndef CONFIG_64BIT #define ARCH_HDR_VER 1 +#else +#define ARCH_HDR_VER 2 +#endif struct riscv_arch_block { +#ifdef CONFIG_64BIT + struct { + uint64_t ra; + uint64_t tp; + uint64_t t0; + uint64_t t1; + uint64_t t2; + uint64_t a0; + uint64_t a1; + uint64_t a2; + uint64_t a3; + uint64_t a4; + uint64_t a5; + uint64_t a6; + uint64_t a7; + uint64_t t3; + uint64_t t4; + uint64_t t5; + uint64_t t6; + uint64_t pc; + } r; +#else /* !CONFIG_64BIT */ struct { uint32_t ra; uint32_t tp; @@ -32,6 +58,7 @@ struct riscv_arch_block { #endif /* !CONFIG_RISCV_ISA_RV32E */ uint32_t pc; } r; +#endif /* CONFIG_64BIT */ } __packed; /* diff --git a/arch/riscv/core/fatal.c b/arch/riscv/core/fatal.c index d0f789a328d..8efffd37371 100644 --- a/arch/riscv/core/fatal.c +++ b/arch/riscv/core/fatal.c @@ -28,8 +28,38 @@ static const struct z_exc_handle exceptions[] = { #define NO_REG " " #endif +/* Stack trace function */ +void z_riscv_unwind_stack(const z_arch_esf_t *esf); + +uintptr_t z_riscv_get_sp_before_exc(const z_arch_esf_t *esf) +{ + /* + * Kernel stack pointer prior this exception i.e. before + * storing the exception stack frame. + */ + uintptr_t sp = (uintptr_t)esf + sizeof(z_arch_esf_t); + +#ifdef CONFIG_USERSPACE + if ((esf->mstatus & MSTATUS_MPP) == PRV_U) { + /* + * Exception happened in user space: + * consider the saved user stack instead. + */ + sp = esf->sp; + } +#endif + + return sp; +} + FUNC_NORETURN void z_riscv_fatal_error(unsigned int reason, const z_arch_esf_t *esf) +{ + z_riscv_fatal_error_csf(reason, esf, NULL); +} + +FUNC_NORETURN void z_riscv_fatal_error_csf(unsigned int reason, const z_arch_esf_t *esf, + const _callee_saved_t *csf) { #ifdef CONFIG_EXCEPTION_DEBUG if (esf != NULL) { @@ -47,14 +77,32 @@ FUNC_NORETURN void z_riscv_fatal_error(unsigned int reason, LOG_ERR(" a6: " PR_REG " t6: " PR_REG, esf->a6, esf->t6); LOG_ERR(" a7: " PR_REG, esf->a7); #endif /* CONFIG_RISCV_ISA_RV32E */ -#ifdef CONFIG_USERSPACE - LOG_ERR(" sp: " PR_REG, esf->sp); -#endif + LOG_ERR(" sp: " PR_REG, z_riscv_get_sp_before_exc(esf)); LOG_ERR(" ra: " PR_REG, esf->ra); LOG_ERR(" mepc: " PR_REG, esf->mepc); LOG_ERR("mstatus: " PR_REG, esf->mstatus); LOG_ERR(""); } + + if (csf != NULL) { +#if defined(CONFIG_RISCV_ISA_RV32E) + LOG_ERR(" s0: " PR_REG, csf->s0); + LOG_ERR(" s1: " PR_REG, csf->s1); +#else + LOG_ERR(" s0: " PR_REG " s6: " PR_REG, csf->s0, csf->s6); + LOG_ERR(" s1: " PR_REG " s7: " PR_REG, csf->s1, csf->s7); + LOG_ERR(" s2: " PR_REG " s8: " PR_REG, csf->s2, csf->s8); + LOG_ERR(" s3: " PR_REG " s9: " PR_REG, csf->s3, csf->s9); + LOG_ERR(" s4: " PR_REG " s10: " PR_REG, csf->s4, csf->s10); + LOG_ERR(" s5: " PR_REG " s11: " PR_REG, csf->s5, csf->s11); +#endif /* CONFIG_RISCV_ISA_RV32E */ + LOG_ERR(""); + } + + if (IS_ENABLED(CONFIG_RISCV_EXCEPTION_STACK_TRACE)) { + z_riscv_unwind_stack(esf); + } + #endif /* CONFIG_EXCEPTION_DEBUG */ z_fatal_error(reason, esf); CODE_UNREACHABLE; diff --git a/arch/riscv/core/irq_manage.c b/arch/riscv/core/irq_manage.c index bf0b6684a5d..b60deceefab 100644 --- a/arch/riscv/core/irq_manage.c +++ b/arch/riscv/core/irq_manage.c @@ -43,7 +43,7 @@ int arch_irq_connect_dynamic(unsigned int irq, unsigned int priority, void (*routine)(const void *parameter), const void *parameter, uint32_t flags) { - z_isr_install(irq, routine, parameter); + z_isr_install(irq + CONFIG_RISCV_RESERVED_IRQ_ISR_TABLES_OFFSET, routine, parameter); #if defined(CONFIG_RISCV_HAS_PLIC) || defined(CONFIG_RISCV_HAS_CLIC) z_riscv_irq_priority_set(irq, priority, flags); diff --git a/arch/riscv/core/isr.S b/arch/riscv/core/isr.S index 422c2ce23bf..e9a3d523127 100644 --- a/arch/riscv/core/isr.S +++ b/arch/riscv/core/isr.S @@ -41,6 +41,23 @@ RV_I( op a7, __z_arch_esf_t_a7_OFFSET(sp) );\ RV_E( op ra, __z_arch_esf_t_ra_OFFSET(sp) ) +#ifdef CONFIG_EXCEPTION_DEBUG +/* Convenience macro for storing callee saved register [s0 - s11] states. */ +#define STORE_CALLEE_SAVED() \ + RV_E( sr s0, ___callee_saved_t_s0_OFFSET(sp) );\ + RV_E( sr s1, ___callee_saved_t_s1_OFFSET(sp) );\ + RV_I( sr s2, ___callee_saved_t_s2_OFFSET(sp) );\ + RV_I( sr s3, ___callee_saved_t_s3_OFFSET(sp) );\ + RV_I( sr s4, ___callee_saved_t_s4_OFFSET(sp) );\ + RV_I( sr s5, ___callee_saved_t_s5_OFFSET(sp) );\ + RV_I( sr s6, ___callee_saved_t_s6_OFFSET(sp) );\ + RV_I( sr s7, ___callee_saved_t_s7_OFFSET(sp) );\ + RV_I( sr s8, ___callee_saved_t_s8_OFFSET(sp) );\ + RV_I( sr s9, ___callee_saved_t_s9_OFFSET(sp) );\ + RV_I( sr s10, ___callee_saved_t_s10_OFFSET(sp) );\ + RV_I( sr s11, ___callee_saved_t_s11_OFFSET(sp) ) +#endif /* CONFIG_EXCEPTION_DEBUG */ + .macro get_current_cpu dst #if defined(CONFIG_SMP) || defined(CONFIG_USERSPACE) csrr \dst, mscratch @@ -61,7 +78,12 @@ GTEXT(__soc_save_context) GTEXT(__soc_restore_context) #endif /* CONFIG_RISCV_SOC_CONTEXT_SAVE */ +#ifdef CONFIG_EXCEPTION_DEBUG +GTEXT(z_riscv_fatal_error_csf) +#else GTEXT(z_riscv_fatal_error) +#endif /* CONFIG_EXCEPTION_DEBUG */ + GTEXT(z_get_next_switch_handle) GTEXT(z_riscv_switch) GTEXT(z_riscv_thread_start) @@ -181,6 +203,8 @@ SECTION_FUNC(exception.entry, _isr_wrapper) bnez t1, no_fp /* determine if this is an Illegal Instruction exception */ csrr t2, mcause + li t1, CONFIG_RISCV_MCAUSE_EXCEPTION_MASK + and t2, t2, t1 li t1, 2 /* 2 = illegal instruction */ bne t1, t2, no_fp /* determine if we trapped on an FP instruction. */ @@ -386,7 +410,19 @@ do_fault: /* Handle RV_ECALL_RUNTIME_EXCEPT. Retrieve reason in a0, esf in A1. */ lr a0, __z_arch_esf_t_a0_OFFSET(sp) 1: mv a1, sp + +#ifdef CONFIG_EXCEPTION_DEBUG + /* Allocate space for caller-saved registers on current thread stack */ + addi sp, sp, -__callee_saved_t_SIZEOF + + /* Save callee-saved registers to be passed as 3rd arg */ + STORE_CALLEE_SAVED() ; + mv a2, sp + + tail z_riscv_fatal_error_csf +#else tail z_riscv_fatal_error +#endif #if defined(CONFIG_IRQ_OFFLOAD) do_irq_offload: diff --git a/arch/riscv/core/offsets/offsets.c b/arch/riscv/core/offsets/offsets.c index 96982341b1a..9bc9306c2e9 100644 --- a/arch/riscv/core/offsets/offsets.c +++ b/arch/riscv/core/offsets/offsets.c @@ -126,6 +126,10 @@ GEN_SOC_OFFSET_SYMS(); GEN_ABSOLUTE_SYM(__z_arch_esf_t_SIZEOF, sizeof(z_arch_esf_t)); +#ifdef CONFIG_EXCEPTION_DEBUG +GEN_ABSOLUTE_SYM(__callee_saved_t_SIZEOF, ROUND_UP(sizeof(_callee_saved_t), ARCH_STACK_PTR_ALIGN)); +#endif /* CONFIG_EXCEPTION_DEBUG */ + #ifdef CONFIG_USERSPACE GEN_OFFSET_SYM(_cpu_arch_t, user_exc_sp); GEN_OFFSET_SYM(_cpu_arch_t, user_exc_tmp0); diff --git a/arch/riscv/core/pmp.c b/arch/riscv/core/pmp.c index 3807b3b103b..50b5dd58f5d 100644 --- a/arch/riscv/core/pmp.c +++ b/arch/riscv/core/pmp.c @@ -667,7 +667,7 @@ int arch_mem_domain_thread_remove(struct k_thread *thread) ((inner_start) >= (outer_start) && (inner_size) <= (outer_size) && \ ((inner_start) - (outer_start)) <= ((outer_size) - (inner_size))) -int arch_buffer_validate(void *addr, size_t size, int write) +int arch_buffer_validate(const void *addr, size_t size, int write) { uintptr_t start = (uintptr_t)addr; int ret = -1; diff --git a/arch/riscv/core/stacktrace.c b/arch/riscv/core/stacktrace.c new file mode 100644 index 00000000000..a85dcfbd82d --- /dev/null +++ b/arch/riscv/core/stacktrace.c @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2024 Meta Platforms + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); + +uintptr_t z_riscv_get_sp_before_exc(const z_arch_esf_t *esf); + +#if __riscv_xlen == 32 + #define PR_REG "%08" PRIxPTR +#elif __riscv_xlen == 64 + #define PR_REG "%016" PRIxPTR +#endif + +#define MAX_STACK_FRAMES 8 + +struct stackframe { + uintptr_t fp; + uintptr_t ra; +}; + +static bool in_stack_bound(uintptr_t addr) +{ +#ifdef CONFIG_THREAD_STACK_INFO + uintptr_t start, end; + + if (_current == NULL || arch_is_in_isr()) { + /* We were servicing an interrupt */ + int cpu_id; + +#ifdef CONFIG_SMP + cpu_id = arch_curr_cpu()->id; +#else + cpu_id = 0; +#endif + + start = (uintptr_t)K_KERNEL_STACK_BUFFER(z_interrupt_stacks[cpu_id]); + end = start + CONFIG_ISR_STACK_SIZE; +#ifdef CONFIG_USERSPACE + /* TODO: handle user threads */ +#endif + } else { + start = _current->stack_info.start; + end = Z_STACK_PTR_ALIGN(_current->stack_info.start + _current->stack_info.size); + } + + return (addr >= start) && (addr < end); +#else + ARG_UNUSED(addr); + return true; +#endif /* CONFIG_THREAD_STACK_INFO */ +} + +static inline bool in_text_region(uintptr_t addr) +{ + extern uintptr_t __text_region_start, __text_region_end; + + return (addr >= (uintptr_t)&__text_region_start) && (addr < (uintptr_t)&__text_region_end); +} + +#ifdef CONFIG_RISCV_ENABLE_FRAME_POINTER +void z_riscv_unwind_stack(const z_arch_esf_t *esf) +{ + uintptr_t fp = esf->s0; + uintptr_t ra; + struct stackframe *frame; + + if (esf == NULL) { + return; + } + + LOG_ERR("call trace:"); + + for (int i = 0; (i < MAX_STACK_FRAMES) && (fp != 0U) && in_stack_bound(fp);) { + frame = (struct stackframe *)fp - 1; + ra = frame->ra; + if (in_text_region(ra)) { + LOG_ERR(" %2d: fp: " PR_REG " ra: " PR_REG, i, fp, ra); + /* + * Increment the iterator only if `ra` is within the text region to get the + * most out of it + */ + i++; + } + fp = frame->fp; + } + + LOG_ERR(""); +} +#else /* !CONFIG_RISCV_ENABLE_FRAME_POINTER */ +void z_riscv_unwind_stack(const z_arch_esf_t *esf) +{ + uintptr_t sp = z_riscv_get_sp_before_exc(esf); + uintptr_t ra; + uintptr_t *ksp = (uintptr_t *)sp; + + if (esf == NULL) { + return; + } + + LOG_ERR("call trace:"); + + for (int i = 0; + (i < MAX_STACK_FRAMES) && ((uintptr_t)ksp != 0U) && in_stack_bound((uintptr_t)ksp); + ksp++) { + ra = *ksp; + if (in_text_region(ra)) { + LOG_ERR(" %2d: sp: " PR_REG " ra: " PR_REG, i, (uintptr_t)ksp, ra); + /* + * Increment the iterator only if `ra` is within the text region to get the + * most out of it + */ + i++; + } + } + + LOG_ERR(""); +} +#endif /* CONFIG_RISCV_ENABLE_FRAME_POINTER */ diff --git a/arch/riscv/include/kernel_arch_func.h b/arch/riscv/include/kernel_arch_func.h index b639f09c6c6..bdfc0527b95 100644 --- a/arch/riscv/include/kernel_arch_func.h +++ b/arch/riscv/include/kernel_arch_func.h @@ -69,9 +69,13 @@ arch_switch(void *switch_to, void **switched_from) #endif } +/* Thin wrapper around z_riscv_fatal_error_csf */ FUNC_NORETURN void z_riscv_fatal_error(unsigned int reason, const z_arch_esf_t *esf); +FUNC_NORETURN void z_riscv_fatal_error_csf(unsigned int reason, const z_arch_esf_t *esf, + const _callee_saved_t *csf); + static inline bool arch_is_in_isr(void) { #ifdef CONFIG_SMP diff --git a/arch/x86/core/Kconfig.intel64 b/arch/x86/core/Kconfig.intel64 index 913bb0e794d..2e6e7ebd00a 100644 --- a/arch/x86/core/Kconfig.intel64 +++ b/arch/x86/core/Kconfig.intel64 @@ -88,7 +88,4 @@ config X86_USERSPACE supporting user-level threads that are protected from each other and from crashing the kernel. -config MP_MAX_NUM_CPUS - range 1 4 - endif # X86_64 diff --git a/arch/x86/core/early_serial.c b/arch/x86/core/early_serial.c index 3a0bc7465e1..53fb8af7e3a 100644 --- a/arch/x86/core/early_serial.c +++ b/arch/x86/core/early_serial.c @@ -25,8 +25,8 @@ * together. */ static mm_reg_t mmio; -#define IN(reg) (sys_read32(mmio + reg * 4) & 0xff) -#define OUT(reg, val) sys_write32((val) & 0xff, mmio + reg * 4) +#define IN(reg) (sys_read32(mmio + (reg) * 4) & 0xff) +#define OUT(reg, val) sys_write32((val) & 0xff, mmio + (reg) * 4) #elif defined(X86_SOC_EARLY_SERIAL_MMIO8_ADDR) /* Still other devices use a MMIO region containing packed byte * registers diff --git a/arch/x86/core/intel64/cpu.c b/arch/x86/core/intel64/cpu.c index d1aedcd4dec..8d68afa2a19 100644 --- a/arch/x86/core/intel64/cpu.c +++ b/arch/x86/core/intel64/cpu.c @@ -3,7 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include #include +#include #include #include #include @@ -12,125 +14,32 @@ #include #include #ifdef CONFIG_ACPI +#include #include #endif -BUILD_ASSERT(CONFIG_MP_MAX_NUM_CPUS <= 4, "Only supports max 4 CPUs"); - /* * Map of CPU logical IDs to CPU local APIC IDs. By default, * we assume this simple identity mapping, as found in QEMU. * The symbol is weak so that boards/SoC files can override. */ -__weak uint8_t x86_cpu_loapics[] = { 0, 1, 2, 3 }; - -extern char x86_ap_start[]; /* AP entry point in locore.S */ - -extern uint8_t z_x86_exception_stack[]; -extern uint8_t z_x86_exception_stack1[]; -extern uint8_t z_x86_exception_stack2[]; -extern uint8_t z_x86_exception_stack3[]; - -extern uint8_t z_x86_nmi_stack[]; -extern uint8_t z_x86_nmi_stack1[]; -extern uint8_t z_x86_nmi_stack2[]; -extern uint8_t z_x86_nmi_stack3[]; - -#ifdef CONFIG_X86_KPTI -extern uint8_t z_x86_trampoline_stack[]; -extern uint8_t z_x86_trampoline_stack1[]; -extern uint8_t z_x86_trampoline_stack2[]; -extern uint8_t z_x86_trampoline_stack3[]; -#endif /* CONFIG_X86_KPTI */ - -Z_GENERIC_SECTION(.tss) -struct x86_tss64 tss0 = { -#ifdef CONFIG_X86_KPTI - .ist2 = (uint64_t) z_x86_trampoline_stack + Z_X86_TRAMPOLINE_STACK_SIZE, -#endif - .ist6 = (uint64_t) z_x86_nmi_stack + CONFIG_X86_EXCEPTION_STACK_SIZE, - .ist7 = (uint64_t) z_x86_exception_stack + CONFIG_X86_EXCEPTION_STACK_SIZE, - .iomapb = 0xFFFF, - .cpu = &(_kernel.cpus[0]) -}; - -#if CONFIG_MP_MAX_NUM_CPUS > 1 -Z_GENERIC_SECTION(.tss) -struct x86_tss64 tss1 = { -#ifdef CONFIG_X86_KPTI - .ist2 = (uint64_t) z_x86_trampoline_stack1 + Z_X86_TRAMPOLINE_STACK_SIZE, -#endif - .ist6 = (uint64_t) z_x86_nmi_stack1 + CONFIG_X86_EXCEPTION_STACK_SIZE, - .ist7 = (uint64_t) z_x86_exception_stack1 + CONFIG_X86_EXCEPTION_STACK_SIZE, - .iomapb = 0xFFFF, - .cpu = &(_kernel.cpus[1]) -}; -#endif - -#if CONFIG_MP_MAX_NUM_CPUS > 2 -Z_GENERIC_SECTION(.tss) -struct x86_tss64 tss2 = { -#ifdef CONFIG_X86_KPTI - .ist2 = (uint64_t) z_x86_trampoline_stack2 + Z_X86_TRAMPOLINE_STACK_SIZE, -#endif - .ist6 = (uint64_t) z_x86_nmi_stack2 + CONFIG_X86_EXCEPTION_STACK_SIZE, - .ist7 = (uint64_t) z_x86_exception_stack2 + CONFIG_X86_EXCEPTION_STACK_SIZE, - .iomapb = 0xFFFF, - .cpu = &(_kernel.cpus[2]) -}; -#endif - -#if CONFIG_MP_MAX_NUM_CPUS > 3 -Z_GENERIC_SECTION(.tss) -struct x86_tss64 tss3 = { -#ifdef CONFIG_X86_KPTI - .ist2 = (uint64_t) z_x86_trampoline_stack3 + Z_X86_TRAMPOLINE_STACK_SIZE, -#endif - .ist6 = (uint64_t) z_x86_nmi_stack3 + CONFIG_X86_EXCEPTION_STACK_SIZE, - .ist7 = (uint64_t) z_x86_exception_stack3 + CONFIG_X86_EXCEPTION_STACK_SIZE, - .iomapb = 0xFFFF, - .cpu = &(_kernel.cpus[3]) -}; +#if defined(CONFIG_ACPI) +__weak uint8_t x86_cpu_loapics[CONFIG_MP_MAX_NUM_CPUS]; +#else +#define INIT_CPUID(n, _) n +__weak uint8_t x86_cpu_loapics[] = { + LISTIFY(CONFIG_MP_MAX_NUM_CPUS, INIT_CPUID, (,)),}; #endif +extern char x86_ap_start[]; /* AP entry point in locore.S */ +LISTIFY(CONFIG_MP_MAX_NUM_CPUS, ACPI_CPU_INIT, (;)); -/* We must put this in a dedicated section, or else it will land into .bss: - * in this case, though locore.S initalizes it relevantly, all will be - * lost when calling z_bss_zero() in z_x86_cpu_init prior to using it. - */ Z_GENERIC_SECTION(.boot_arg) x86_boot_arg_t x86_cpu_boot_arg; struct x86_cpuboot x86_cpuboot[] = { - { - .tr = X86_KERNEL_CPU0_TR, - .gs_base = &tss0, - .sp = (uint64_t) z_interrupt_stacks[0] + - K_KERNEL_STACK_LEN(CONFIG_ISR_STACK_SIZE), - .stack_size = - K_KERNEL_STACK_LEN(CONFIG_ISR_STACK_SIZE), - .fn = z_prep_c, - .arg = &x86_cpu_boot_arg, - }, -#if CONFIG_MP_MAX_NUM_CPUS > 1 - { - .tr = X86_KERNEL_CPU1_TR, - .gs_base = &tss1 - }, -#endif -#if CONFIG_MP_MAX_NUM_CPUS > 2 - { - .tr = X86_KERNEL_CPU2_TR, - .gs_base = &tss2 - }, -#endif -#if CONFIG_MP_MAX_NUM_CPUS > 3 - { - .tr = X86_KERNEL_CPU3_TR, - .gs_base = &tss3 - }, -#endif + LISTIFY(CONFIG_MP_MAX_NUM_CPUS, X86_CPU_BOOT_INIT, (,)), }; /* @@ -151,6 +60,12 @@ void arch_cpu_start(int cpu_num, k_thread_stack_t *stack, int sz, if (lapic != NULL) { /* We update the apic_id, __start will need it. */ x86_cpu_loapics[cpu_num] = lapic->Id; + } else { + /* TODO: kernel need to handle the error scenario if someone config + * CONFIG_MP_MAX_NUM_CPUS more than what platform supported. + */ + __ASSERT(false, "CPU reached more than maximum supported!"); + return; } })); @@ -160,6 +75,7 @@ void arch_cpu_start(int cpu_num, k_thread_stack_t *stack, int sz, x86_cpuboot[cpu_num].stack_size = sz; x86_cpuboot[cpu_num].fn = fn; x86_cpuboot[cpu_num].arg = arg; + x86_cpuboot[cpu_num].cpu_id = cpu_num; z_loapic_ipi(apic_id, LOAPIC_ICR_IPI_INIT, 0); k_busy_wait(10000); @@ -181,18 +97,19 @@ void arch_cpu_start(int cpu_num, k_thread_stack_t *stack, int sz, */ FUNC_NORETURN void z_x86_cpu_init(struct x86_cpuboot *cpuboot) { +#if defined(CONFIG_ACPI) + __ASSERT(z_x86_cpuid_get_current_physical_apic_id() == + x86_cpu_loapics[cpuboot->cpu_id], "APIC ID miss match!"); +#endif x86_sse_init(NULL); - /* The internal cpu_number is the index to x86_cpuboot[] */ - unsigned char cpu_num = (unsigned char)(cpuboot - x86_cpuboot); - - if (cpu_num == 0U) { + if (cpuboot->cpu_id == 0U) { /* Only need to do these once per boot */ z_bss_zero(); z_data_copy(); } - z_loapic_enable(cpu_num); + z_loapic_enable(cpuboot->cpu_id); #ifdef CONFIG_USERSPACE /* Set landing site for 'syscall' instruction */ diff --git a/arch/x86/core/intel64/fatal.c b/arch/x86/core/intel64/fatal.c index 5772234a0d9..9dd97614dc1 100644 --- a/arch/x86/core/intel64/fatal.c +++ b/arch/x86/core/intel64/fatal.c @@ -15,6 +15,8 @@ LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); */ __weak bool z_x86_do_kernel_nmi(const z_arch_esf_t *esf) { + ARG_UNUSED(esf); + return false; } diff --git a/arch/x86/core/intel64/locore.S b/arch/x86/core/intel64/locore.S index d68e80c423f..68f89c90398 100644 --- a/arch/x86/core/intel64/locore.S +++ b/arch/x86/core/intel64/locore.S @@ -80,6 +80,15 @@ movq %rax, %cr0 .endm +.macro DEFINE_TSS_STACK_ARRAY + .irp idx, DEFINE_STACK_ARRAY_IDX + .word __X86_TSS64_SIZEOF-1 + .word tss\idx + .word 0x8900 + .word 0, 0, 0, 0, 0 + .endr +.endm + /* The .locore section begins the page-aligned initialization region * of low memory. The first address is used as the architectural * entry point for auxiliary CPUs being brought up (in real mode!) @@ -113,17 +122,13 @@ __start: nop nop -#if CONFIG_MP_MAX_NUM_CPUS > 1 - .code16 .global x86_ap_start x86_ap_start: - /* * First, we move to 32-bit protected mode, and set up the * same flat environment that the BSP gets from the loader. */ - lgdt gdt48 lidt idt48 movl %cr0, %eax @@ -145,7 +150,7 @@ x86_ap_start: movl LOAPIC_BASE_ADDRESS+LOAPIC_ID, %eax shrl $24, %eax - andl $0x0F, %eax /* local APIC ID -> EAX */ + andl $0xFF, %eax /* local APIC ID -> EAX */ movl $x86_cpuboot, %ebp xorl %ebx, %ebx @@ -160,8 +165,6 @@ x86_ap_start: unknown_loapic_id: jmp unknown_loapic_id -#endif /* CONFIG_MP_MAX_NUM_CPUS > 1 */ - .code32 .globl __start32 __start32: @@ -1094,31 +1097,7 @@ gdt: /* Remaining entries are TSS for each enabled CPU */ - .word __X86_TSS64_SIZEOF-1 /* 0x40: 64-bit TSS (16-byte entry) */ - .word tss0 - .word 0x8900 - .word 0, 0, 0, 0, 0 - -#if CONFIG_MP_MAX_NUM_CPUS > 1 - .word __X86_TSS64_SIZEOF-1 /* 0x50: 64-bit TSS (16-byte entry) */ - .word tss1 - .word 0x8900 - .word 0, 0, 0, 0, 0 -#endif - -#if CONFIG_MP_MAX_NUM_CPUS > 2 - .word __X86_TSS64_SIZEOF-1 /* 0x60: 64-bit TSS (16-byte entry) */ - .word tss2 - .word 0x8900 - .word 0, 0, 0, 0, 0 -#endif - -#if CONFIG_MP_MAX_NUM_CPUS > 3 - .word __X86_TSS64_SIZEOF-1 /* 0x70: 64-bit TSS (16-byte entry) */ - .word tss3 - .word 0x8900 - .word 0, 0, 0, 0, 0 -#endif + DEFINE_TSS_STACK_ARRAY gdt_end: @@ -1129,80 +1108,3 @@ gdt48: /* LGDT descriptor for 32 bit mode */ gdt80: /* LGDT descriptor for long mode */ .word (gdt_end - gdt - 1) .quad gdt -.section .lodata,"ad" - -/* - * Known-good stack for handling CPU exceptions. - */ - -.global z_x86_exception_stack -.align 16 -z_x86_exception_stack: - .fill CONFIG_X86_EXCEPTION_STACK_SIZE, 1, 0xAA -.global z_x86_nmi_stack -.align 16 -z_x86_nmi_stack: - .fill CONFIG_X86_EXCEPTION_STACK_SIZE, 1, 0xAA - -#if CONFIG_MP_MAX_NUM_CPUS > 1 -.global z_x86_exception_stack1 -.align 16 -z_x86_exception_stack1: - .fill CONFIG_X86_EXCEPTION_STACK_SIZE, 1, 0xAA -.global z_x86_nmi_stack1 -.align 16 -z_x86_nmi_stack1: - .fill CONFIG_X86_EXCEPTION_STACK_SIZE, 1, 0xAA -#endif - -#if CONFIG_MP_MAX_NUM_CPUS > 2 -.global z_x86_exception_stack2 -.align 16 -z_x86_exception_stack2: - .fill CONFIG_X86_EXCEPTION_STACK_SIZE, 1, 0xAA -.global z_x86_nmi_stack2 -.align 16 -z_x86_nmi_stack2: - .fill CONFIG_X86_EXCEPTION_STACK_SIZE, 1, 0xAA -#endif - -#if CONFIG_MP_MAX_NUM_CPUS > 3 -.global z_x86_exception_stack3 -.align 16 -z_x86_exception_stack3: - .fill CONFIG_X86_EXCEPTION_STACK_SIZE, 1, 0xAA -.global z_x86_nmi_stack3 -.align 16 -z_x86_nmi_stack3: - .fill CONFIG_X86_EXCEPTION_STACK_SIZE, 1, 0xAA -#endif - -#ifdef CONFIG_X86_KPTI -.section .trampolines,"ad" - -.global z_x86_trampoline_stack -.align 16 -z_x86_trampoline_stack: - .fill Z_X86_TRAMPOLINE_STACK_SIZE, 1, 0xAA - -#if CONFIG_MP_MAX_NUM_CPUS > 1 -.global z_x86_trampoline_stack1 -.align 16 -z_x86_trampoline_stack1: - .fill Z_X86_TRAMPOLINE_STACK_SIZE, 1, 0xAA -#endif - -#if CONFIG_MP_MAX_NUM_CPUS > 2 -.global z_x86_trampoline_stack2 -.align 16 -z_x86_trampoline_stack2: - .fill Z_X86_TRAMPOLINE_STACK_SIZE, 1, 0xAA -#endif - -#if CONFIG_MP_MAX_NUM_CPUS > 3 -.global z_x86_trampoline_stack3 -.align 16 -z_x86_trampoline_stack3: - .fill Z_X86_TRAMPOLINE_STACK_SIZE, 1, 0xAA -#endif -#endif /* CONFIG_X86_KPTI */ diff --git a/arch/x86/core/intel64/thread.c b/arch/x86/core/intel64/thread.c index f26f25ab5f1..49cb58ec9c6 100644 --- a/arch/x86/core/intel64/thread.c +++ b/arch/x86/core/intel64/thread.c @@ -37,6 +37,8 @@ void arch_new_thread(struct k_thread *thread, k_thread_stack_t *stack, * which is only needed if the stack is not memory mapped. */ z_x86_set_stack_guard(stack); +#else + ARG_UNUSED(stack); #endif #ifdef CONFIG_USERSPACE switch_entry = z_x86_userspace_prepare_thread(thread); @@ -68,11 +70,16 @@ void arch_new_thread(struct k_thread *thread, k_thread_stack_t *stack, int arch_float_disable(struct k_thread *thread) { /* x86-64 always has FP/SSE enabled so cannot be disabled */ + ARG_UNUSED(thread); + return -ENOTSUP; } int arch_float_enable(struct k_thread *thread, unsigned int options) { /* x86-64 always has FP/SSE enabled so nothing to do here */ + ARG_UNUSED(thread); + ARG_UNUSED(options); + return 0; } diff --git a/arch/x86/core/prep_c.c b/arch/x86/core/prep_c.c index 17a4a7f7473..d9b62b0b711 100644 --- a/arch/x86/core/prep_c.c +++ b/arch/x86/core/prep_c.c @@ -65,7 +65,7 @@ FUNC_NORETURN void z_prep_c(void *arg) #endif #endif -#if CONFIG_X86_STACK_PROTECTION +#ifdef CONFIG_X86_STACK_PROTECTION unsigned int num_cpus = arch_num_cpus(); for (int i = 0; i < num_cpus; i++) { diff --git a/arch/x86/core/x86_mmu.c b/arch/x86/core/x86_mmu.c index 71aafe5cad9..7bfa2088a41 100644 --- a/arch/x86/core/x86_mmu.c +++ b/arch/x86/core/x86_mmu.c @@ -450,6 +450,8 @@ static inline void assert_addr_aligned(uintptr_t addr) #if __ASSERT_ON __ASSERT((addr & (CONFIG_MMU_PAGE_SIZE - 1)) == 0U, "unaligned address 0x%" PRIxPTR, addr); +#else + ARG_UNUSED(addr); #endif } @@ -481,6 +483,8 @@ static inline void assert_size_aligned(size_t size) #if __ASSERT_ON __ASSERT((size & (CONFIG_MMU_PAGE_SIZE - 1)) == 0U, "unaligned size %zu", size); +#else + ARG_UNUSED(size); #endif } @@ -828,6 +832,9 @@ static inline pentry_t pte_finalize_value(pentry_t val, bool user_table, get_entry_phys(val, level) != shared_phys_addr) { val = ~val; } +#else + ARG_UNUSED(user_table); + ARG_UNUSED(level); #endif return val; } @@ -841,7 +848,7 @@ static inline pentry_t pte_finalize_value(pentry_t val, bool user_table, __pinned_func static inline pentry_t atomic_pte_get(const pentry_t *target) { - return (pentry_t)atomic_ptr_get((atomic_ptr_t *)target); + return (pentry_t)atomic_ptr_get((const atomic_ptr_t *)target); } __pinned_func @@ -1162,8 +1169,8 @@ static int range_map(void *virt, uintptr_t phys, size_t size, { int ret = 0, ret2; - LOG_DBG("%s: %p -> %p (%zu) flags " PRI_ENTRY " mask " - PRI_ENTRY " opt 0x%x", __func__, (void *)phys, virt, size, + LOG_DBG("%s: 0x%" PRIxPTR " -> %p (%zu) flags " PRI_ENTRY " mask " + PRI_ENTRY " opt 0x%x", __func__, phys, virt, size, entry_flags, mask, options); #ifdef CONFIG_X86_64 @@ -1294,7 +1301,7 @@ void arch_mem_unmap(void *addr, size_t size) { int ret; - ret = range_map_unlocked((void *)addr, 0, size, 0, 0, + ret = range_map_unlocked(addr, 0, size, 0, 0, OPTION_FLUSH | OPTION_CLEAR); __ASSERT_NO_MSG(ret == 0); ARG_UNUSED(ret); @@ -1355,7 +1362,7 @@ void z_x86_mmu_init(void) #endif } -#if CONFIG_X86_STACK_PROTECTION +#ifdef CONFIG_X86_STACK_PROTECTION __pinned_func void z_x86_set_stack_guard(k_thread_stack_t *stack) { @@ -1380,7 +1387,7 @@ void z_x86_set_stack_guard(k_thread_stack_t *stack) __pinned_func static bool page_validate(pentry_t *ptables, uint8_t *addr, bool write) { - pentry_t *table = (pentry_t *)ptables; + pentry_t *table = ptables; for (int level = 0; level < NUM_LEVELS; level++) { pentry_t entry = get_entry(table, addr, level); @@ -1425,7 +1432,7 @@ static inline void bcb_fence(void) } __pinned_func -int arch_buffer_validate(void *addr, size_t size, int write) +int arch_buffer_validate(const void *addr, size_t size, int write) { pentry_t *ptables = z_x86_thread_page_tables_get(_current); uint8_t *virt; @@ -1433,8 +1440,8 @@ int arch_buffer_validate(void *addr, size_t size, int write) int ret = 0; /* 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); + (void)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) { @@ -1774,8 +1781,8 @@ static inline int apply_region(pentry_t *ptables, void *start, __pinned_func static void set_stack_perms(struct k_thread *thread, pentry_t *ptables) { - LOG_DBG("update stack for thread %p's ptables at %p: %p (size %zu)", - thread, ptables, (void *)thread->stack_info.start, + LOG_DBG("update stack for thread %p's ptables at %p: 0x%" PRIxPTR " (size %zu)", + thread, ptables, thread->stack_info.start, thread->stack_info.size); apply_region(ptables, (void *)thread->stack_info.start, thread->stack_info.size, @@ -1922,8 +1929,8 @@ int arch_mem_domain_thread_add(struct k_thread *thread) } thread->arch.ptables = z_mem_phys_addr(domain->arch.ptables); - LOG_DBG("set thread %p page tables to %p", thread, - (void *)thread->arch.ptables); + LOG_DBG("set thread %p page tables to 0x%" PRIxPTR, thread, + thread->arch.ptables); /* Check if we're doing a migration from a different memory domain * and have to remove permissions from its old domain. @@ -2001,9 +2008,7 @@ static void mark_addr_page_reserved(uintptr_t addr, size_t len) continue; } - struct z_page_frame *pf = z_phys_to_page_frame(pos); - - pf->flags |= Z_PAGE_FRAME_RESERVED; + z_page_frame_set(z_phys_to_page_frame(pos), Z_PAGE_FRAME_RESERVED); } } diff --git a/arch/x86/include/intel64/kernel_arch_data.h b/arch/x86/include/intel64/kernel_arch_data.h index 6cbf18a831d..af3b0d1c816 100644 --- a/arch/x86/include/intel64/kernel_arch_data.h +++ b/arch/x86/include/intel64/kernel_arch_data.h @@ -26,6 +26,7 @@ struct x86_cpuboot { size_t stack_size; /* size of stack */ arch_cpustart_t fn; /* kernel entry function */ void *arg; /* argument for above function */ + uint8_t cpu_id; /* CPU ID */ }; typedef struct x86_cpuboot x86_cpuboot_t; @@ -38,4 +39,44 @@ extern uint8_t x86_cpu_loapics[]; /* CPU logical ID -> local APIC ID */ #define Z_X86_TRAMPOLINE_STACK_SIZE 128 #endif +#ifdef CONFIG_X86_KPTI +#define TRAMPOLINE_STACK(n) \ + uint8_t z_x86_trampoline_stack##n[Z_X86_TRAMPOLINE_STACK_SIZE] \ + __attribute__ ((section(".trampolines"))); + +#define TRAMPOLINE_INIT(n) \ + .ist2 = (uint64_t)z_x86_trampoline_stack##n + Z_X86_TRAMPOLINE_STACK_SIZE, +#else +#define TRAMPOLINE_STACK(n) +#define TRAMPOLINE_INIT(n) +#endif /* CONFIG_X86_KPTI */ + +#define ACPI_CPU_INIT(n, _) \ + uint8_t z_x86_exception_stack##n[CONFIG_X86_EXCEPTION_STACK_SIZE] __aligned(16); \ + uint8_t z_x86_nmi_stack##n[CONFIG_X86_EXCEPTION_STACK_SIZE] __aligned(16); \ + TRAMPOLINE_STACK(n); \ + Z_GENERIC_SECTION(.tss) \ + struct x86_tss64 tss##n = { \ + TRAMPOLINE_INIT(n) \ + .ist6 = (uint64_t)z_x86_nmi_stack##n + CONFIG_X86_EXCEPTION_STACK_SIZE, \ + .ist7 = (uint64_t)z_x86_exception_stack##n + CONFIG_X86_EXCEPTION_STACK_SIZE, \ + .iomapb = 0xFFFF, .cpu = &(_kernel.cpus[n]) \ + } + +#define X86_CPU_BOOT_INIT(n, _) \ + { \ + .tr = (0x40 + (16 * n)), \ + .gs_base = &tss##n, \ + .sp = (uint64_t)z_interrupt_stacks[n] + \ + K_KERNEL_STACK_LEN(CONFIG_ISR_STACK_SIZE), \ + .stack_size = K_KERNEL_STACK_LEN(CONFIG_ISR_STACK_SIZE), \ + .fn = z_prep_c, \ + .arg = &x86_cpu_boot_arg, \ + } + +#define STACK_ARRAY_IDX(n, _) n + +#define DEFINE_STACK_ARRAY_IDX\ + LISTIFY(CONFIG_MP_MAX_NUM_CPUS, STACK_ARRAY_IDX, (,)) + #endif /* ZEPHYR_ARCH_X86_INCLUDE_INTEL64_KERNEL_ARCH_DATA_H_ */ diff --git a/arch/x86/include/x86_mmu.h b/arch/x86/include/x86_mmu.h index 0328e98d735..31c8526cb7a 100644 --- a/arch/x86/include/x86_mmu.h +++ b/arch/x86/include/x86_mmu.h @@ -217,6 +217,8 @@ static inline pentry_t *z_x86_thread_page_tables_get(struct k_thread *thread) */ return z_mem_virt_addr(thread->arch.ptables); } +#else + ARG_UNUSED(thread); #endif return z_x86_kernel_ptables; } diff --git a/arch/x86/zefi/printf.h b/arch/x86/zefi/printf.h index 2f234967028..a3960064029 100644 --- a/arch/x86/zefi/printf.h +++ b/arch/x86/zefi/printf.h @@ -45,14 +45,18 @@ static void prdec(struct _pfr *r, long v) char digs[11 * sizeof(long)/4]; int i = sizeof(digs) - 1; - digs[i--] = 0; + digs[i] = 0; + --i; while (v || i == 9) { - digs[i--] = '0' + (v % 10); + digs[i] = '0' + (v % 10); + --i; v /= 10; } - while (digs[++i] != '\0') { + ++i; + while (digs[i] != '\0') { pc(r, digs[i]); + ++i; } } @@ -101,8 +105,10 @@ static int vpf(struct _pfr *r, const char *f, va_list ap) case 's': { char *s = va_arg(ap, char *); - while (*s != '\0') - pc(r, *s++); + while (*s != '\0') { + pc(r, *s); + ++s; + } break; } case 'p': @@ -117,8 +123,9 @@ static int vpf(struct _pfr *r, const char *f, va_list ap) int d = (v >> (i*4)) & 0xf; sig += !!d; - if (sig || i == 0) + if (sig || i == 0) { pc(r, "0123456789abcdef"[d]); + } } break; } @@ -142,7 +149,7 @@ static int vpf(struct _pfr *r, const char *f, va_list ap) static inline int snprintf(char *buf, unsigned long len, const char *f, ...) { - int ret = 0; + int ret; struct _pfr r = { .buf = buf, .len = len }; CALL_VPF(&r); @@ -151,7 +158,7 @@ static inline int snprintf(char *buf, unsigned long len, const char *f, ...) static inline int sprintf(char *buf, const char *f, ...) { - int ret = 0; + int ret; struct _pfr r = { .buf = buf, .len = 0x7fffffff }; CALL_VPF(&r); @@ -160,7 +167,7 @@ static inline int sprintf(char *buf, const char *f, ...) static inline int printf(const char *f, ...) { - int ret = 0; + int ret; struct _pfr r = {0}; CALL_VPF(&r); diff --git a/arch/x86/zefi/zefi.c b/arch/x86/zefi/zefi.c index 0f81398f4a8..56d0701e79b 100644 --- a/arch/x86/zefi/zefi.c +++ b/arch/x86/zefi/zefi.c @@ -56,7 +56,8 @@ static void efi_putchar(int c) efi_putchar('\r'); } - efibuf[n++] = c; + efibuf[n] = c; + ++n; if (c == '\n' || n == PUTCHAR_BUFSZ) { efibuf[n] = 0U; @@ -134,6 +135,8 @@ static void disable_hpet(void) */ uintptr_t __abi efi_entry(void *img_handle, struct efi_system_table *sys_tab) { + (void)img_handle; + efi = sys_tab; z_putchar = efi_putchar; printf("*** Zephyr EFI Loader ***\n"); diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig index 8aa3d0fa96c..82a44f820c5 100644 --- a/arch/xtensa/Kconfig +++ b/arch/xtensa/Kconfig @@ -22,6 +22,16 @@ config XTENSA_RESET_VECTOR This is always needed for the simulator. Real boards may already implement this in boot ROM. +config XTENSA_GEN_HANDLERS + bool "Automatically generate interrupt handlers" + default n + help + When set, an "xtensa_handlers.h" file is generated + containing definitions for the interrupt entry code of the + target Xtensa core, based automatically on the details in + the core-isa.h file. This replaces the previous scheme + where a _soc_inthandlers.h file would be generated offline. + config XTENSA_USE_CORE_CRT1 bool "Use crt1.S from core" default y diff --git a/arch/xtensa/core/CMakeLists.txt b/arch/xtensa/core/CMakeLists.txt index fab15a803da..4c2ce8173ca 100644 --- a/arch/xtensa/core/CMakeLists.txt +++ b/arch/xtensa/core/CMakeLists.txt @@ -84,3 +84,30 @@ add_custom_target(zsr_h DEPENDS ${ZSR_H}) add_dependencies(zephyr_interface zsr_h) unset(MAY_NEED_SYSCALL_SCRATCH_REG) + +# Similar: auto-generate interrupt handlers +set(HANDLERS ${CMAKE_BINARY_DIR}/zephyr/include/generated/xtensa_handlers) + +add_custom_command( + OUTPUT ${HANDLERS}_tmp.c + COMMAND ${CMAKE_C_COMPILER} -E -U__XCC__ + -I${ZEPHYR_XTENSA_MODULE_DIR}/zephyr/soc/${CONFIG_SOC} + -o ${HANDLERS}_tmp.c + - < ${CMAKE_CURRENT_SOURCE_DIR}/xtensa_intgen.tmpl) + +add_custom_command( + OUTPUT ${HANDLERS}.h + DEPENDS ${HANDLERS}_tmp.c + COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/xtensa_intgen.py + ${HANDLERS}_tmp.c > ${HANDLERS}.h) + +add_custom_target(xtensa_handlers_h DEPENDS ${HANDLERS}.h) +add_dependencies(zephyr_interface xtensa_handlers_h) + +# Auto-generate interrupt vector entry +set(VECS_LD ${CMAKE_BINARY_DIR}/zephyr/include/generated/xtensa_vectors.ld) +add_custom_command(OUTPUT ${VECS_LD} DEPENDS ${CORE_ISA_DM} + COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/gen_vectors.py + ${CORE_ISA_DM} > ${VECS_LD}) +add_custom_target(xtensa_vectors_ld DEPENDS ${VECS_LD}) +add_dependencies(zephyr_interface xtensa_vectors_ld) diff --git a/arch/xtensa/core/elf.c b/arch/xtensa/core/elf.c index 46da8eb908a..e85fab84c69 100644 --- a/arch/xtensa/core/elf.c +++ b/arch/xtensa/core/elf.c @@ -37,7 +37,7 @@ void arch_elf_relocate_local(struct llext_loader *ldr, struct llext *ext, if (ELF_ST_TYPE(sym->st_info) == STT_SECTION) { elf_shdr_t *shdr = llext_peek(ldr, ldr->hdr.e_shoff + sym->st_shndx * ldr->hdr.e_shentsize); - sh_addr = shdr->sh_addr; + sh_addr = shdr->sh_addr ? : (uintptr_t)llext_peek(ldr, shdr->sh_offset); } else { sh_addr = ldr->sects[LLEXT_MEM_TEXT].sh_addr; } diff --git a/arch/xtensa/core/gen_vectors.py b/arch/xtensa/core/gen_vectors.py new file mode 100755 index 00000000000..e9e60e30fe5 --- /dev/null +++ b/arch/xtensa/core/gen_vectors.py @@ -0,0 +1,122 @@ +#!/usr/bin/env python3 +# Copyright 2023 The ChromiumOS Authors +# SPDX-License-Identifier: Apache-2.0 +import sys +import re + +# Xtensa Vector Table linker generator +# +# Takes a pre-processed (gcc -dM) core-isa.h file as its first +# argument, and emits a GNU linker section declartion which will +# correctly load the exception vectors and literals as long as their +# code is declared using standard conventions (see below). +# +# The section name will be ".z_xtensa_vectors", and a symbol +# "z_xtensa_vecbase" is emitted containing a valid value for the +# VECBASE SR at runtime. +# +# Obviously, this requires that XCHAL_HAVE_VECBASE=1. A similar trick +# could be played to load vectors at fixed addresses on hardware that +# lacks VECBASE, but the core-isa.h interface is inexplicably +# different. +# +# Because the "standard conventions" (which descend from somewhere in +# Cadence) are not documented anywhere and just end up cut and pasted +# between devices, here's an attempt at a specification: +# +# + The six register window exception vectors are defined with offsets +# internal to their assembly code. They are linked in a single +# section named ".WindowVectors.text". +# +# + The "kernel", "user" and "double exception" vectors are emitted in +# sections named ".KernelExceptionVector.text", +# "UserExceptionVector.text" and "DoubleExceptionVector.text" +# respectively. +# +# + XEA2 interrupt vectors are in sections named +# ".LevelInterruptVector.text", except (!) for ones which are +# given special names. The "debug" and "NMI" interrupts (if they +# exist) are technically implemented as standard interrupt vectors +# (of a platform-dependent level), but the code for them is emitted +# in ".DebugExceptionVector.text" and ".NMIExceptionVector.text", +# and not a section corresponding to their interrupt level. +# +# + Any unused bytes at the end of a vector are made available as +# storage for immediate values used by the following vector (Xtensa +# can only back-reference immediates for MOVI/L32R instructions) as +# a "Vector.literal" section. Note that there is no guarantee +# of how much space is available, it depends on the previous +# vector's code size. Zephyr code has historically not used this +# space, as support in existing linker scripts is inconsistent. But +# it's exposed here. + +coreisa = sys.argv[1] + +debug_level = 0 + +# Translation for the core-isa.h vs. linker section naming conventions +sect_names = { "DOUBLEEXC" : "DoubleException", + "KERNEL" : "KernelException", + "NMI" : "NMIException", + "USER" : "UserException" } + +offsets = {} + +with open(coreisa) as infile: + for line in infile.readlines(): + m = re.match(r"^#define\s+XCHAL_([^ ]+)_VECOFS\s*(.*)", line.rstrip()) + if m: + (sym, val) = (m.group(1), m.group(2)) + if sym == "WINDOW_OF4": + # This must be the start of the section + assert eval(val) == 0 + elif sym.startswith("WINDOW"): + # Ignore the other window exceptions, they're internally sorted + pass + elif sym == "RESET": + # Ignore, not actually part of the vector table + pass + elif sym == "DEBUG": + # This one is a recursive macro that doesn't expand, + # so handle manually + m = re.match(r"XCHAL_INTLEVEL(\d+)_VECOFS", val) + if not m: + print(f"no intlevel match for debug val {val}") + assert m + debug_level = eval(m.group(1)) + else: + if val == "XCHAL_NMI_VECOFS": + # This gets recursively defined in the other + # direction, so ignore the INTLEVEL + pass + else: + addr = eval(val) + m = re.match(r"^INTLEVEL(\d+)", sym) + if m: + offsets[f"Level{m.group(1)}Interrupt"] = addr + else: + offsets[sect_names[sym]] = addr + +if debug_level > 0: + old = f"Level{debug_level}Interrupt" + offsets[f"DebugException"] = offsets[old] + del offsets[old] + +sects = list(offsets) +sects.sort(key=lambda s: offsets[s]) + +print("/* Automatically Generated Code - Do Not Edit */") +print("/* See arch/xtensa/core/gen_vector.py */") +print("") + +# The 1k alignment is experimental, the docs on the Relocatable Vector +# Option doesn't specify an alignment at all, but writes to the +# bottom bits don't take... +print( " .z_xtensa_vectors : ALIGN(1024) {") +print( " z_xtensa_vecbase = .;") +print(f" KEEP(*(.WindowVectors.text));") +for s in sects: + print(f" KEEP(*(.{s}Vector.literal));") + print( " . = 0x%3.3x;" % (offsets[s])) + print(f" KEEP(*(.{s}Vector.text));") +print(" }") diff --git a/arch/xtensa/core/mpu.c b/arch/xtensa/core/mpu.c index 29e33629771..76036b32c70 100644 --- a/arch/xtensa/core/mpu.c +++ b/arch/xtensa/core/mpu.c @@ -969,7 +969,7 @@ int arch_mem_domain_thread_remove(struct k_thread *thread) return ret; } -int arch_buffer_validate(void *addr, size_t size, int write) +int arch_buffer_validate(const void *addr, size_t size, int write) { uintptr_t aligned_addr; size_t aligned_size, addr_offset; diff --git a/arch/xtensa/core/ptables.c b/arch/xtensa/core/ptables.c index e28fa1aa8f0..f44e17ad6a9 100644 --- a/arch/xtensa/core/ptables.c +++ b/arch/xtensa/core/ptables.c @@ -214,15 +214,18 @@ static inline uint32_t *alloc_l2_table(void) } static void map_memory_range(const uint32_t start, const uint32_t end, - const uint32_t attrs, bool shared) + const uint32_t attrs) { uint32_t page, *table; + bool shared = !!(attrs & XTENSA_MMU_MAP_SHARED); + uint32_t sw_attrs = (attrs & XTENSA_MMU_PTE_ATTR_ORIGINAL) == XTENSA_MMU_PTE_ATTR_ORIGINAL ? + attrs : 0; 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); + sw_attrs, attrs); uint32_t l2_pos = XTENSA_MMU_L2_POS(page); uint32_t l1_pos = XTENSA_MMU_L1_POS(page); @@ -236,7 +239,7 @@ static void map_memory_range(const uint32_t start, const uint32_t end, xtensa_kernel_ptables[l1_pos] = XTENSA_MMU_PTE((uint32_t)table, XTENSA_MMU_KERNEL_RING, - XTENSA_MMU_PAGE_TABLE_ATTR); + sw_attrs, XTENSA_MMU_PAGE_TABLE_ATTR); } table = (uint32_t *)(xtensa_kernel_ptables[l1_pos] & XTENSA_MMU_PTE_PPN_MASK); @@ -245,18 +248,18 @@ static void map_memory_range(const uint32_t start, const uint32_t end, } static void map_memory(const uint32_t start, const uint32_t end, - const uint32_t attrs, bool shared) + const uint32_t attrs) { - map_memory_range(start, end, attrs, shared); + map_memory_range(start, end, attrs); #ifdef CONFIG_XTENSA_MMU_DOUBLE_MAP if (sys_cache_is_ptr_uncached((void *)start)) { map_memory_range(POINTER_TO_UINT(sys_cache_cached_ptr_get((void *)start)), POINTER_TO_UINT(sys_cache_cached_ptr_get((void *)end)), - attrs | XTENSA_MMU_CACHED_WB, shared); + attrs | XTENSA_MMU_CACHED_WB); } else if (sys_cache_is_ptr_cached((void *)start)) { map_memory_range(POINTER_TO_UINT(sys_cache_uncached_ptr_get((void *)start)), - POINTER_TO_UINT(sys_cache_uncached_ptr_get((void *)end)), attrs, shared); + POINTER_TO_UINT(sys_cache_uncached_ptr_get((void *)end)), attrs); } #endif } @@ -270,24 +273,14 @@ static void xtensa_init_page_tables(void) 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); + map_memory(range->start, range->end, range->attrs | XTENSA_MMU_PTE_ATTR_ORIGINAL); } 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); + map_memory(range->start, range->end, range->attrs | XTENSA_MMU_PTE_ATTR_ORIGINAL); } /* Finally, the direct-mapped pages used in the page tables @@ -297,10 +290,10 @@ static void xtensa_init_page_tables(void) */ 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); + XTENSA_MMU_PAGE_TABLE_ATTR | XTENSA_MMU_PERM_W); 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); + XTENSA_MMU_PAGE_TABLE_ATTR | XTENSA_MMU_PERM_W); sys_cache_data_flush_all(); } @@ -337,15 +330,12 @@ void xtensa_mmu_init(void) __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; + z_page_frame_set(&z_page_frames[idx], Z_PAGE_FRAME_RESERVED); } } #endif /* CONFIG_ARCH_HAS_RESERVED_PAGE_FRAMES */ @@ -369,7 +359,7 @@ static bool l2_page_table_map(uint32_t *l1_table, void *vaddr, uintptr_t phys, 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); + 0, XTENSA_MMU_PAGE_TABLE_ATTR); sys_cache_data_flush_range((void *)&l1_table[l1_pos], sizeof(l1_table[0])); } @@ -377,7 +367,7 @@ static bool l2_page_table_map(uint32_t *l1_table, void *vaddr, uintptr_t phys, 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); + 0, flags); sys_cache_data_flush_range((void *)&table[l2_pos], sizeof(table[0])); xtensa_tlb_autorefill_invalidate(); @@ -725,7 +715,7 @@ static inline uint32_t *alloc_l1_table(void) return NULL; } -static uint32_t *dup_table(uint32_t *source_table) +static uint32_t *dup_table(void) { uint16_t i, j; uint32_t *dst_table = alloc_l1_table(); @@ -737,26 +727,38 @@ static uint32_t *dup_table(uint32_t *source_table) for (i = 0; i < XTENSA_L1_PAGE_TABLE_ENTRIES; i++) { uint32_t *l2_table, *src_l2_table; - if (is_pte_illegal(source_table[i])) { + if (is_pte_illegal(xtensa_kernel_ptables[i]) || + (i == XTENSA_MMU_L1_POS(XTENSA_MMU_PTEVADDR))) { dst_table[i] = XTENSA_MMU_PTE_ILLEGAL; continue; } - src_l2_table = (uint32_t *)(source_table[i] & XTENSA_MMU_PTE_PPN_MASK); + src_l2_table = (uint32_t *)(xtensa_kernel_ptables[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++) { + uint32_t original_attr = XTENSA_MMU_PTE_SW_GET(src_l2_table[j]); + l2_table[j] = src_l2_table[j]; + if (original_attr != 0x0) { + uint8_t ring; + + ring = XTENSA_MMU_PTE_RING_GET(l2_table[j]); + l2_table[j] = XTENSA_MMU_PTE_ATTR_SET(l2_table[j], original_attr); + l2_table[j] = XTENSA_MMU_PTE_RING_SET(l2_table[j], + ring == XTENSA_MMU_SHARED_RING ? + XTENSA_MMU_SHARED_RING : XTENSA_MMU_KERNEL_RING); + } } /* 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); + 0, XTENSA_MMU_PAGE_TABLE_ATTR); sys_cache_data_flush_range((void *)l2_table, XTENSA_L2_PAGE_TABLE_SIZE); } @@ -783,7 +785,19 @@ int arch_mem_domain_init(struct k_mem_domain *domain) __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 this is the default domain, we don't need + * to create a new set of page tables. We can just + * use the kernel page tables and save memory. + */ + + if (domain == &k_mem_domain_default) { + domain->arch.ptables = xtensa_kernel_ptables; + domain->arch.asid = asid_count; + goto end; + } + + + ptables = dup_table(); if (ptables == NULL) { ret = -ENOMEM; @@ -795,6 +809,7 @@ int arch_mem_domain_init(struct k_mem_domain *domain) sys_slist_append(&xtensa_domain_list, &domain->arch.node); +end: ret = 0; err: @@ -1043,7 +1058,7 @@ static bool page_validate(uint32_t *ptables, uint32_t page, uint8_t ring, bool w return true; } -int arch_buffer_validate(void *addr, size_t size, int write) +int arch_buffer_validate(const void *addr, size_t size, int write) { int ret = 0; uint8_t *virt; diff --git a/arch/xtensa/core/vector_handlers.c b/arch/xtensa/core/vector_handlers.c index b8dca1c1967..f0b0a9175ff 100644 --- a/arch/xtensa/core/vector_handlers.c +++ b/arch/xtensa/core/vector_handlers.c @@ -10,13 +10,18 @@ #include #include #include -#include <_soc_inthandlers.h> #include #include #include #include #include +#ifdef CONFIG_XTENSA_GEN_HANDLERS +#include +#else +#include <_soc_inthandlers.h> +#endif + #include LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); @@ -359,7 +364,7 @@ void *xtensa_excint1_c(int *interrupted_stack) * thread. */ __asm__ volatile("rsil %0, %1" - : "=r" (ignore) : "i"(XCHAL_NMILEVEL)); + : "=r" (ignore) : "i"(XCHAL_EXCM_LEVEL)); _current_cpu->nested = 1; } diff --git a/arch/xtensa/core/xtensa_intgen.py b/arch/xtensa/core/xtensa_intgen.py index 6a7935d409c..2770cb4662c 100755 --- a/arch/xtensa/core/xtensa_intgen.py +++ b/arch/xtensa/core/xtensa_intgen.py @@ -105,13 +105,11 @@ def emit_int_handler(ints): cprint("#endif") cprint("") -# Populate empty levels just for sanity. The second-to-last interrupt -# level (usually "debug") typically doesn't have any associated -# vectors, but we don't have any way to know that a-prioi. -max = 0 -for lvl in ints_by_lvl: - if lvl > max: - max = lvl +# Populate all theoretical levels just in case. Odd cores have been +# seen in the wild with "empty" interrupt levels that exist in the +# hardware but without any interrupts associated with them. The +# unused handlers will be ignored if uncalled. +max = 15 for lvl in range(0, max+1): if not lvl in ints_by_lvl: diff --git a/arch/xtensa/include/xtensa_asm2_s.h b/arch/xtensa/include/xtensa_asm2_s.h index 8ca152088a7..dddf7bb309c 100644 --- a/arch/xtensa/include/xtensa_asm2_s.h +++ b/arch/xtensa/include/xtensa_asm2_s.h @@ -609,11 +609,6 @@ _Level\LVL\()Vector: s32i a2, a1, ___xtensa_irq_bsa_t_a2_OFFSET s32i a3, a1, ___xtensa_irq_bsa_t_a3_OFFSET -#ifdef CONFIG_ADSP_IDLE_CLOCK_GATING - /* Needed when waking from low-power waiti state */ - isync -#endif - /* 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 diff --git a/arch/xtensa/include/xtensa_mmu_priv.h b/arch/xtensa/include/xtensa_mmu_priv.h index 631760f03cb..608cbac9c46 100644 --- a/arch/xtensa/include/xtensa_mmu_priv.h +++ b/arch/xtensa/include/xtensa_mmu_priv.h @@ -41,11 +41,6 @@ #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 @@ -55,10 +50,24 @@ /** Number of bits to shift for ring in PTE */ #define XTENSA_MMU_PTE_RING_SHIFT 4U +/** Number of bits to shift for SW reserved ared in PTE */ +#define XTENSA_MMU_PTE_SW_SHIFT 6U + +/** Mask for SW bits in PTE */ +#define XTENSA_MMU_PTE_SW_MASK 0x00000FC0U + +/** + * Internal bit just used to indicate that the attr field must + * be set in the SW bits too. It is used later when duplicating the + * kernel page tables. + */ +#define XTENSA_MMU_PTE_ATTR_ORIGINAL BIT(31) + /** Construct a page table entry (PTE) */ -#define XTENSA_MMU_PTE(paddr, ring, attr) \ +#define XTENSA_MMU_PTE(paddr, ring, sw, attr) \ (((paddr) & XTENSA_MMU_PTE_PPN_MASK) | \ (((ring) << XTENSA_MMU_PTE_RING_SHIFT) & XTENSA_MMU_PTE_RING_MASK) | \ + (((sw) << XTENSA_MMU_PTE_SW_SHIFT) & XTENSA_MMU_PTE_SW_MASK) | \ ((attr) & XTENSA_MMU_PTE_ATTR_MASK)) /** Get the attributes from a PTE */ @@ -67,7 +76,15 @@ /** Set the attributes in a PTE */ #define XTENSA_MMU_PTE_ATTR_SET(pte, attr) \ - (((pte) & ~XTENSA_MMU_PTE_ATTR_MASK) | (attr)) + (((pte) & ~XTENSA_MMU_PTE_ATTR_MASK) | (attr & XTENSA_MMU_PTE_ATTR_MASK)) + +/** Set the SW field in a PTE */ +#define XTENSA_MMU_PTE_SW_SET(pte, sw) \ + (((pte) & ~XTENSA_MMU_PTE_SW_MASK) | (sw << XTENSA_MMU_PTE_SW_SHIFT)) + +/** Get the SW field from a PTE */ +#define XTENSA_MMU_PTE_SW_GET(pte) \ + (((pte) & XTENSA_MMU_PTE_SW_MASK) >> XTENSA_MMU_PTE_SW_SHIFT) /** Set the ring in a PTE */ #define XTENSA_MMU_PTE_RING_SET(pte, ring) \ @@ -76,7 +93,7 @@ /** Get the ring from a PTE */ #define XTENSA_MMU_PTE_RING_GET(pte) \ - (((pte) & ~XTENSA_MMU_PTE_RING_MASK) >> XTENSA_MMU_PTE_RING_SHIFT) + (((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) \ diff --git a/boards/96boards/carbon/Kconfig.defconfig b/boards/96boards/carbon/Kconfig.defconfig index fe90a4fdd4c..cede46b95fe 100644 --- a/boards/96boards/carbon/Kconfig.defconfig +++ b/boards/96boards/carbon/Kconfig.defconfig @@ -20,37 +20,6 @@ endchoice endif # BT -if NETWORKING - -# Re-create the NET_L2_BT dependencies here -config BT - default y - -config BT_PERIPHERAL - default BT - -config BT_CENTRAL - default BT - -config BT_SMP - default BT - -config BT_L2CAP_DYNAMIC_CHANNEL - default BT - -# BT is the only onboard network iface, so use it for IP networking -# if it's enabled - -config NET_L2_BT - depends on NET_IPV6 - default BT - -config NET_L2_BT_ZEP1656 - depends on NET_IPV6 - default BT - -endif # NETWORKING - endif # BOARD_96B_CARBON_STM32F401XE if BOARD_96B_CARBON_NRF51822 diff --git a/boards/96boards/carbon/doc/stm32f401xe.rst b/boards/96boards/carbon/doc/stm32f401xe.rst index e025a12ff32..222c6056a38 100644 --- a/boards/96boards/carbon/doc/stm32f401xe.rst +++ b/boards/96boards/carbon/doc/stm32f401xe.rst @@ -338,16 +338,16 @@ in general, see :ref:`build_an_application`. #. Install the dfu-util flashing app, as described above. -#. Build and flash the ``samples/bluetooth/ipsp`` application for +#. Build and flash the ``samples/bluetooth/peripheral_hr`` application for 96b_carbon. See the instructions above for how to put your board into DFU mode if you haven't done this before: .. zephyr-app-commands:: - :zephyr-app: samples/bluetooth/ipsp + :zephyr-app: samples/bluetooth/peripheral_hr :board: 96b_carbon/stm32f401xe :goals: build flash -#. Refer to the instructions in :ref:`bluetooth-ipsp-sample` for how +#. Refer to the instructions in :ref:`peripheral_hr` for how to verify functionality. Congratulations! Your 96Boards Carbon now has Bluetooth diff --git a/boards/actinius/icarus/actinius_icarus_nrf9160_1_4_0.yaml b/boards/actinius/icarus/actinius_icarus_nrf9160_1_4_0.yaml index 1f3d3d9e0c0..119745e52ed 100644 --- a/boards/actinius/icarus/actinius_icarus_nrf9160_1_4_0.yaml +++ b/boards/actinius/icarus/actinius_icarus_nrf9160_1_4_0.yaml @@ -1,5 +1,5 @@ identifier: actinius_icarus@1.4.0/nrf9160 -name: Actinius Icarus +name: Actinius Icarus (rev. 1.4.0) type: mcu arch: arm toolchain: diff --git a/boards/actinius/icarus/actinius_icarus_nrf9160_2_0_0.yaml b/boards/actinius/icarus/actinius_icarus_nrf9160_2_0_0.yaml index d8bce888556..f017d9c6f3c 100644 --- a/boards/actinius/icarus/actinius_icarus_nrf9160_2_0_0.yaml +++ b/boards/actinius/icarus/actinius_icarus_nrf9160_2_0_0.yaml @@ -1,5 +1,5 @@ identifier: actinius_icarus@2.0.0/nrf9160 -name: Actinius Icarus +name: Actinius Icarus (rev. 2.0.0) type: mcu arch: arm toolchain: diff --git a/boards/actinius/icarus/actinius_icarus_nrf9160_ns_1_4_0.yaml b/boards/actinius/icarus/actinius_icarus_nrf9160_ns_1_4_0.yaml index 46005a7da10..07338249661 100644 --- a/boards/actinius/icarus/actinius_icarus_nrf9160_ns_1_4_0.yaml +++ b/boards/actinius/icarus/actinius_icarus_nrf9160_ns_1_4_0.yaml @@ -1,5 +1,5 @@ identifier: actinius_icarus@1.4.0/nrf9160/ns -name: Actinius Icarus Non-Secure +name: Actinius Icarus Non-Secure (rev. 1.4.0) type: mcu arch: arm toolchain: diff --git a/boards/actinius/icarus/actinius_icarus_nrf9160_ns_2_0_0.yaml b/boards/actinius/icarus/actinius_icarus_nrf9160_ns_2_0_0.yaml index e8d9256f3f0..a6a5ecc7738 100644 --- a/boards/actinius/icarus/actinius_icarus_nrf9160_ns_2_0_0.yaml +++ b/boards/actinius/icarus/actinius_icarus_nrf9160_ns_2_0_0.yaml @@ -1,5 +1,5 @@ identifier: actinius_icarus@2.0.0/nrf9160/ns -name: Actinius Icarus Non-Secure +name: Actinius Icarus Non-Secure (rev. 2.0.0) type: mcu arch: arm toolchain: diff --git a/boards/adafruit/itsybitsy/adafruit_itsybitsy_nrf52840.dts b/boards/adafruit/itsybitsy/adafruit_itsybitsy_nrf52840.dts index 56a31b13106..45827a7bcec 100644 --- a/boards/adafruit/itsybitsy/adafruit_itsybitsy_nrf52840.dts +++ b/boards/adafruit/itsybitsy/adafruit_itsybitsy_nrf52840.dts @@ -8,6 +8,7 @@ #include #include "adafruit_itsybitsy_nrf52840-pinctrl.dtsi" #include +#include / { model = "Adafruit ItsyBitsy nRF52840 Express"; @@ -107,6 +108,10 @@ compatible = "apa,apa102"; reg = <0>; spi-max-frequency = <5250000>; + chain-length = <1>; + color-mapping = ; }; }; diff --git a/boards/adafruit/trinket_m0/adafruit_trinket_m0.dts b/boards/adafruit/trinket_m0/adafruit_trinket_m0.dts index b94b0e1ed73..21fc54fb9e9 100644 --- a/boards/adafruit/trinket_m0/adafruit_trinket_m0.dts +++ b/boards/adafruit/trinket_m0/adafruit_trinket_m0.dts @@ -8,6 +8,7 @@ #include #include #include "adafruit_trinket_m0-pinctrl.dtsi" +#include / { model = "Adafruit Trinket M0"; @@ -87,6 +88,10 @@ compatible = "apa,apa102"; reg = <0>; spi-max-frequency = <24000000>; + chain-length = <1>; + color-mapping = ; }; }; diff --git a/boards/adi/eval_adin1110ebz/adi_eval_adin1110ebz.dts b/boards/adi/eval_adin1110ebz/adi_eval_adin1110ebz.dts index 00f00777a23..171e57963bc 100644 --- a/boards/adi/eval_adin1110ebz/adi_eval_adin1110ebz.dts +++ b/boards/adi/eval_adin1110ebz/adi_eval_adin1110ebz.dts @@ -34,19 +34,19 @@ leds { /* Respecting pcb silkscreen naming */ compatible = "gpio-leds"; green_led: led_uC0 { - gpios = <&gpioc 13 GPIO_ACTIVE_HIGH>; + gpios = <&gpioc 13 GPIO_ACTIVE_LOW>; label = "Status uC0"; }; red_led: led_uC1 { - gpios = <&gpioe 2 GPIO_ACTIVE_HIGH>; + gpios = <&gpioe 2 GPIO_ACTIVE_LOW>; label = "Status uC1 "; }; yellow_led: led_uC2 { - gpios = <&gpioe 6 GPIO_ACTIVE_HIGH>; + gpios = <&gpioe 6 GPIO_ACTIVE_LOW>; label = "Status uC2"; }; blue_led: led_uC3 { - gpios = <&gpiog 15 GPIO_ACTIVE_HIGH>; + gpios = <&gpiog 15 GPIO_ACTIVE_LOW>; label = "Status uC3"; }; }; diff --git a/boards/adi/eval_adin2111ebz/adi_eval_adin2111ebz.dts b/boards/adi/eval_adin2111ebz/adi_eval_adin2111ebz.dts index 5db24f04e80..83a3343ca35 100644 --- a/boards/adi/eval_adin2111ebz/adi_eval_adin2111ebz.dts +++ b/boards/adi/eval_adin2111ebz/adi_eval_adin2111ebz.dts @@ -24,23 +24,23 @@ leds { compatible = "gpio-leds"; blue_led: uC_led1 { - gpios = <&gpiob 6 GPIO_ACTIVE_HIGH>; + gpios = <&gpiob 6 GPIO_ACTIVE_LOW>; label = "Debug led uC1"; }; net_red_led: led_NET1 { - gpios = <&gpiob 10 GPIO_ACTIVE_HIGH>; + gpios = <&gpiob 10 GPIO_ACTIVE_LOW>; label = "NET led 1"; }; net_green_led: led_NET2 { - gpios = <&gpiob 11 GPIO_ACTIVE_HIGH>; + gpios = <&gpiob 11 GPIO_ACTIVE_LOW>; label = "NET led 2"; }; mod_red_led: led_MOD1 { - gpios = <&gpioe 2 GPIO_ACTIVE_HIGH>; + gpios = <&gpioe 2 GPIO_ACTIVE_LOW>; label = "Mod led 1"; }; mod_green_led: led_MOD2 { - gpios = <&gpioe 6 GPIO_ACTIVE_HIGH>; + gpios = <&gpioe 6 GPIO_ACTIVE_LOW>; label = "Mod led 2"; }; }; diff --git a/boards/adi/sdp_k1/adi_sdp_120pin_connector.dtsi b/boards/adi/sdp_k1/adi_sdp_120pin_connector.dtsi new file mode 100644 index 00000000000..a6696d780bf --- /dev/null +++ b/boards/adi/sdp_k1/adi_sdp_120pin_connector.dtsi @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2024 Analog Devices Inc. + * Copyright (c) 2024 Baylibre, SAS + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + sdp_k1_120_hdr: connector { + compatible = "adi,sdp-120"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map = + /* pin map */ /* sdp-120 */ + <32 0 &gpiof 7 0>, /* SPI_D2 */ + <33 0 &gpiod 13 0>, /* SPI_D3 */ + <34 0 &gpioc 11 0>, /* SERIAL_INT */ + <36 0 &gpioc 6 0>, /* SPI_SEL_B_N */ + <37 0 &gpioc 7 0>, /* SPI_SEL_C_N */ + <38 0 &gpiof 6 0>, /* SPI_SEL1/SPI_SS_N */ + + <42 0 &gpioj 0 0>, /* GPIO0 */ + <43 0 &gpioj 3 0>, /* GPIO2 */ + <44 0 &gpioj 5 0>, /* GPIO4 */ + <46 0 &gpioj 13 0>, /* GPIO6 */ + + /* TIMER A */ + <47 0 &gpiob 14 0>, /* TMR_A */ + + <58 0 &gpiod 6 0>, /* UART2_RX */ + <61 0 &gpiod 5 0>, /* UART2_TX */ + + /* TIMER D */ + <71 0 &gpioc 8 0>, /* TMR_D */ + + /* TIMER B */ + <72 0 &gpioe 6 0>, /* TMR_B */ + + <73 0 &gpioj 14 0>, /* GPIO7 */ + <75 0 &gpioj 12 0>, /* GPIO5 */ + <76 0 &gpioj 4 0>, /* GPIO3 */ + <77 0 &gpioj 1 0>, /* GPIO1 */ + + /* I2C3 */ + <78 0 &gpioh 7 0>, /* SCL_0 */ + <79 0 &gpioc 9 0>, /* SDA_0 */ + + /* SPI5 */ + <81 0 &gpioh 6 0>, /* SPI_CLK - spi5_sck_ph6 */ + <82 0 &gpiof 8 0>, /* SPI_MISO - spi5_miso_pf8 */ + <83 0 &gpiof 9 0>, /* SPI_MOSI - spi5_mosi_pf9 */ + <84 0 &gpiob 6 0>, /* SPI_SEL_A_N - could be PB6 or PB9 */ + + /* SPORT - no driver yet */ + <86 0 &gpiog 13 0>, /* SPORT_TSCLK */ + <87 0 &gpiog 14 0>, /* SPORT_DT0 */ + <88 0 &gpioa 8 0>, /* SPORT_TFS */ + <89 0 &gpioe 4 0>, /* SPORT_RFS */ + <90 0 &gpioe 5 0>, /* SPORT_DR0 */ + <91 0 &gpioe 2 0>; /* SPORT_RSCLK */ + }; + + pmod_spi { + compatible = "digilent,pmod"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map = <0 0 &sdp_k1_120_hdr SDP_120_SPI_SEL_A_N 0>, // IO1 + <1 0 &sdp_k1_120_hdr SDP_120_SPI_MISO 0>, // IO2 + <2 0 &sdp_k1_120_hdr SDP_120_SPI_MOSI 0>, // IO3 + <3 0 &sdp_k1_120_hdr SDP_120_SPI_CLK 0>, // IO4 + <4 0 &sdp_k1_120_hdr SDP_120_SERIAL_INT 0>, // IO5 + <5 0 &sdp_k1_120_hdr SDP_120_GPIO5 0>, // IO6 + <6 0 &sdp_k1_120_hdr SDP_120_GPIO6 0>, // IO7 + <7 0 &sdp_k1_120_hdr SDP_120_GPIO7 0>; // IO8 + status = "disabled"; + }; + + pmod_usart { + compatible = "digilent,pmod"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map = <0 0 &sdp_k1_120_hdr SDP_120_GPIO0 0>, // IO1 + <1 0 &sdp_k1_120_hdr SDP_120_UART_TX 0>, // IO2 + <2 0 &sdp_k1_120_hdr SDP_120_UART_RX 0>, // IO3 + <3 0 &sdp_k1_120_hdr SDP_120_GPIO3 0>, // IO4 + <4 0 &sdp_k1_120_hdr SDP_120_SERIAL_INT 0>, // IO5 + <5 0 &sdp_k1_120_hdr SDP_120_GPIO5 0>, // IO6 + <6 0 &sdp_k1_120_hdr SDP_120_GPIO6 0>, // IO7 + <7 0 &sdp_k1_120_hdr SDP_120_GPIO7 0>; // IO8 + status = "disabled"; + }; + +}; + +/* + * Note from sdp-k1 schematic for overlapping signals + * + * NOTE: SOME OF THE SPI & QUADSPI SIGNALS ON THE SDP + * CONNECTOR ON PAGE 9 ARE ROUTED TO MULTIPLE PINS ON THE + * STM32F469. TAKE CARE NOT TO ENABLE SPI AND QUADSPI ON + * THE SDP CONNECTOR SIMULTANEOUSLY. + */ + +sdp_spi: &spi5 { + pinctrl-0 = <&spi5_sck_ph6 &spi5_miso_pf8 &spi5_mosi_pf9>; + pinctrl-names = "default"; + cs-gpios = <&sdp_k1_120_hdr SDP_120_SPI_SEL_A_N (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + status = "okay"; +}; + +sdp_i2c: &i2c3 { }; + +sdp_serial: &usart2{ }; diff --git a/boards/adi/sdp_k1/adi_sdp_k1.dts b/boards/adi/sdp_k1/adi_sdp_k1.dts index 52c68f90c18..a1b663867a5 100644 --- a/boards/adi/sdp_k1/adi_sdp_k1.dts +++ b/boards/adi/sdp_k1/adi_sdp_k1.dts @@ -8,6 +8,7 @@ #include #include #include "arduino_r3_connector.dtsi" +#include "adi_sdp_120pin_connector.dtsi" / { model = "Analog Devices Inc. SDP-K1 board"; diff --git a/boards/ambiq/apollo3_evb/Kconfig.apollo3_evb b/boards/ambiq/apollo3_evb/Kconfig.apollo3_evb new file mode 100644 index 00000000000..f5ca25f15f4 --- /dev/null +++ b/boards/ambiq/apollo3_evb/Kconfig.apollo3_evb @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright (c) 2023 Ambiq Micro Inc. + +config BOARD_APOLLO3_EVB + select SOC_APOLLO3_BLUE diff --git a/boards/ambiq/apollo3_evb/apollo3_evb-pinctrl.dtsi b/boards/ambiq/apollo3_evb/apollo3_evb-pinctrl.dtsi new file mode 100644 index 00000000000..cfba01ba4de --- /dev/null +++ b/boards/ambiq/apollo3_evb/apollo3_evb-pinctrl.dtsi @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2023 Ambiq Micro Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&pinctrl { + uart0_default: uart0_default { + group1 { + pinmux = ; + }; + group2 { + pinmux = ; + input-enable; + }; + }; + i2c0_default: i2c0_default { + group1 { + pinmux = , ; + drive-open-drain; + drive-strength = "0.5"; + bias-pull-up; + }; + }; + i2c1_default: i2c1_default { + group1 { + pinmux = , ; + drive-open-drain; + drive-strength = "0.5"; + bias-pull-up; + }; + }; + i2c2_default: i2c2_default { + group1 { + pinmux = , ; + drive-open-drain; + drive-strength = "0.5"; + bias-pull-up; + }; + }; + i2c3_default: i2c3_default { + group1 { + pinmux = , ; + drive-open-drain; + drive-strength = "0.5"; + bias-pull-up; + }; + }; + i2c4_default: i2c4_default { + group1 { + pinmux = , ; + drive-open-drain; + drive-strength = "0.5"; + bias-pull-up; + }; + }; + i2c5_default: i2c5_default { + group1 { + pinmux = , ; + drive-open-drain; + drive-strength = "0.5"; + bias-pull-up; + }; + }; + + spi0_default: spi0_default { + group1 { + pinmux = , , ; + }; + group2 { + pinmux = ; + drive-push-pull; + ambiq,iom-nce-module = <0>; + ambiq,iom-num = <0>; + }; + }; + spi1_default: spi1_default { + group1 { + pinmux = , , ; + }; + group2 { + pinmux = ; + drive-push-pull; + ambiq,iom-nce-module = <1>; + ambiq,iom-num = <1>; + }; + }; + spi2_default: spi2_default { + group1 { + pinmux = , , ; + }; + group2 { + pinmux = ; + drive-push-pull; + ambiq,iom-nce-module = <3>; + ambiq,iom-num = <2>; + }; + }; + spi3_default: spi3_default { + group1 { + pinmux = , , ; + }; + group2 { + pinmux = ; + drive-push-pull; + ambiq,iom-nce-module = <0>; + ambiq,iom-num = <3>; + }; + }; + spi4_default: spi4_default { + group1 { + pinmux = , , ; + }; + group2 { + pinmux = ; + drive-push-pull; + ambiq,iom-nce-module = <1>; + ambiq,iom-num = <4>; + }; + }; + spi5_default: spi5_default { + group1 { + pinmux = , , ; + }; + group2 { + pinmux = ; + drive-push-pull; + ambiq,iom-nce-module = <0>; + ambiq,iom-num = <5>; + }; + }; + + mspi0_default: mspi0_default{ + group1 { + pinmux = , + , + , + , + ; + }; + group2 { + pinmux = ; + drive-push-pull; + drive-strength = "0.5"; + ambiq,iom-nce-module = <0>; + ambiq,iom-num = <6>; + }; + }; +}; diff --git a/boards/ambiq/apollo3_evb/apollo3_evb.dts b/boards/ambiq/apollo3_evb/apollo3_evb.dts new file mode 100644 index 00000000000..9f1cac0b309 --- /dev/null +++ b/boards/ambiq/apollo3_evb/apollo3_evb.dts @@ -0,0 +1,112 @@ +/dts-v1/; +#include + +#include "apollo3_evb-pinctrl.dtsi" + +/ { + model = "Ambiq Apollo3 Blue evaluation board"; + compatible = "ambiq,apollo3_evb"; + + chosen { + zephyr,itcm = &tcm; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + 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 10 GPIO_ACTIVE_LOW>; + label = "LED 0"; + }; + led1: led_1 { + gpios = <&gpio0_31 30 GPIO_ACTIVE_LOW>; + label = "LED 1"; + }; + led2: led_2 { + gpios = <&gpio0_31 15 GPIO_ACTIVE_LOW>; + label = "LED 2"; + }; + led3: led_3 { + gpios = <&gpio0_31 14 GPIO_ACTIVE_LOW>; + label = "LED 3"; + }; + led4: led_4 { + gpios = <&gpio0_31 17 GPIO_ACTIVE_LOW>; + label = "LED 4"; + }; + }; + + buttons { + compatible = "gpio-keys"; + button0: button_0 { + gpios = <&gpio0_31 16 GPIO_ACTIVE_LOW>; + label = "BTN0"; + }; + button1: button_1 { + gpios = <&gpio0_31 18 GPIO_ACTIVE_LOW>; + label = "BTN1"; + }; + button2: button_2 { + gpios = <&gpio0_31 19 GPIO_ACTIVE_LOW>; + label = "BTN2"; + }; + }; +}; + +&flash0 { + erase-block-size = <8192>; + write-block-size = <4>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* Set 16KB of storage at the end of the 976KB of flash */ + storage_partition: partition@f0000 { + label = "storage"; + reg = <0x000f0000 0x4000>; + }; + }; +}; + +&uart0 { + current-speed = <115200>; + pinctrl-0 = <&uart0_default>; + pinctrl-names = "default"; + status = "okay"; +}; + +&wdt0 { + status = "okay"; +}; + +&i2c3 { + compatible = "ambiq,i2c"; + pinctrl-0 = <&i2c3_default>; + pinctrl-names = "default"; + clock-frequency = ; + status = "okay"; +}; + +&gpio0_31 { + status = "okay"; +}; + +&gpio32_63 { + status = "okay"; +}; diff --git a/boards/ambiq/apollo3_evb/apollo3_evb.yaml b/boards/ambiq/apollo3_evb/apollo3_evb.yaml new file mode 100644 index 00000000000..f55c135f1d4 --- /dev/null +++ b/boards/ambiq/apollo3_evb/apollo3_evb.yaml @@ -0,0 +1,18 @@ +identifier: apollo3_evb +name: Apollo3 Blue EVB +type: mcu +arch: arm +ram: 384 +flash: 976 +toolchain: + - zephyr + - gnuarmemb +supported: + - uart + - watchdog + - gpio + - i2c +testing: + ignore_tags: + - net +vendor: ambiq diff --git a/boards/ambiq/apollo3_evb/apollo3_evb_defconfig b/boards/ambiq/apollo3_evb/apollo3_evb_defconfig new file mode 100644 index 00000000000..5f556803e52 --- /dev/null +++ b/boards/ambiq/apollo3_evb/apollo3_evb_defconfig @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright (c) 2023 Ambiq Micro Inc. + +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_UART_INTERRUPT_DRIVEN=y diff --git a/boards/ambiq/apollo3_evb/board.cmake b/boards/ambiq/apollo3_evb/board.cmake new file mode 100644 index 00000000000..1a5a2709639 --- /dev/null +++ b/boards/ambiq/apollo3_evb/board.cmake @@ -0,0 +1,6 @@ +# Copyright (c) 2023 Ambiq Micro Inc. +# SPDX-License-Identifier: Apache-2.0 + +board_runner_args(jlink "--device=AMA3B1KK-KBR" "--iface=swd" "--speed=1000") + +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/ambiq/apollo3_evb/board.yml b/boards/ambiq/apollo3_evb/board.yml new file mode 100644 index 00000000000..8c3925245c3 --- /dev/null +++ b/boards/ambiq/apollo3_evb/board.yml @@ -0,0 +1,5 @@ +board: + name: apollo3_evb + vendor: ambiq + socs: + - name: apollo3_blue diff --git a/boards/ambiq/apollo3_evb/doc/apollo3-blue-soc-eval-board.jpg b/boards/ambiq/apollo3_evb/doc/apollo3-blue-soc-eval-board.jpg new file mode 100644 index 00000000000..5e30793f396 Binary files /dev/null and b/boards/ambiq/apollo3_evb/doc/apollo3-blue-soc-eval-board.jpg differ diff --git a/boards/ambiq/apollo3_evb/doc/index.rst b/boards/ambiq/apollo3_evb/doc/index.rst new file mode 100644 index 00000000000..12990d0c9fe --- /dev/null +++ b/boards/ambiq/apollo3_evb/doc/index.rst @@ -0,0 +1,102 @@ +.. _apollo3_evb: + +Ambiq Apollo3 Blue EVB +###################### + +Apollo3 Blue EVB is a board by Ambiq featuring their ultra-low power Apollo3 Blue SoC. + +.. image:: ./apollo3-blue-soc-eval-board.jpg + :align: center + :alt: Apollo3 Blue EVB + +Hardware +******** + +- Apollo3 Blue SoC with up to 96 MHz operating frequency +- ARMĀ® CortexĀ® M4F core +- 16 kB 2-way Associative/Direct-Mapped Cache per core +- Up to 1 MB of flash memory for code/data +- Up to 384 KB of low leakage / low power RAM for code/data +- Integrated Bluetooth 5 Low-energy controller + +For more information about the Apollo3 Blue SoC and Apollo3 Blue EVB board: + +- `Apollo3 Blue Website`_ +- `Apollo3 Blue Datasheet`_ +- `Apollo3 Blue EVB Website`_ + +Supported Features +================== + +The Apollo3 Blue EVB board configuration supports the following hardware features: + ++-----------+------------+-------------------------------------+ +| Interface | Controller | Driver/Component | ++===========+============+=====================================+ +| MPU | on-chip | memory protection unit | ++-----------+------------+-------------------------------------+ +| NVIC | on-chip | nested vector interrupt controller | ++-----------+------------+-------------------------------------+ +| SYSTICK | on-chip | systick | ++-----------+------------+-------------------------------------+ +| STIMER | on-chip | stimer | ++-----------+------------+-------------------------------------+ +| GPIO | on-chip | gpio | ++-----------+------------+-------------------------------------+ +| UART | on-chip | serial | ++-----------+------------+-------------------------------------+ +| WDT | on-chip | watchdog | ++-----------+------------+-------------------------------------+ +| RADIO | on-chip | bluetooth | ++-----------+------------+-------------------------------------+ + +The default configuration can be found in the defconfig file: +``boards/arm/apollo3_evb/apollo3_evb_defconfig``. + +Programming and Debugging +========================= + +Flashing an application +----------------------- + +Connect your device to your host computer using the JLINK USB port. +The sample application :ref:`hello_world` is used for this example. +Build the Zephyr kernel and application, then flash it to the device: + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: apollo3_evb + :goals: flash + +.. note:: + `west flash` requires `SEGGER J-Link software`_ and `pylink`_ Python module + to be installed on you host computer. + +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 be able to see on the corresponding Serial Port +the following message: + +.. code-block:: console + + Hello World! apollo3_evb + +.. _Apollo3 Blue Website: + https://ambiq.com/apollo3-blue/ + +.. _Apollo3 Blue Datasheet: + https://contentportal.ambiq.com/documents/20123/388390/Apollo3-Blue-SoC-Datasheet.pdf + +.. _Apollo3 Blue EVB Website: + https://www.ambiq.top/en/apollo3-blue-soc-eval-board + +.. _SEGGER J-Link software: + https://www.segger.com/downloads/jlink + +.. _pylink: + https://github.com/Square/pylink diff --git a/boards/ambiq/apollo3p_evb/Kconfig.apollo3p_evb b/boards/ambiq/apollo3p_evb/Kconfig.apollo3p_evb new file mode 100644 index 00000000000..cda93708d30 --- /dev/null +++ b/boards/ambiq/apollo3p_evb/Kconfig.apollo3p_evb @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright (c) 2023 Ambiq Micro Inc. + +config BOARD_APOLLO3P_EVB + select SOC_APOLLO3P_BLUE diff --git a/boards/ambiq/apollo3p_evb/apollo3p_evb-pinctrl.dtsi b/boards/ambiq/apollo3p_evb/apollo3p_evb-pinctrl.dtsi new file mode 100644 index 00000000000..5619b134ee9 --- /dev/null +++ b/boards/ambiq/apollo3p_evb/apollo3p_evb-pinctrl.dtsi @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2023 Ambiq Micro Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&pinctrl { + uart0_default: uart0_default { + group1 { + pinmux = ; + }; + group2 { + pinmux = ; + input-enable; + }; + }; + i2c0_default: i2c0_default { + group1 { + pinmux = , ; + drive-open-drain; + drive-strength = "0.5"; + bias-pull-up; + }; + }; + i2c1_default: i2c1_default { + group1 { + pinmux = , ; + drive-open-drain; + drive-strength = "0.5"; + bias-pull-up; + }; + }; + i2c2_default: i2c2_default { + group1 { + pinmux = , ; + drive-open-drain; + drive-strength = "0.5"; + bias-pull-up; + }; + }; + i2c3_default: i2c3_default { + group1 { + pinmux = , ; + drive-open-drain; + drive-strength = "0.5"; + bias-pull-up; + }; + }; + i2c4_default: i2c4_default { + group1 { + pinmux = , ; + drive-open-drain; + drive-strength = "0.5"; + bias-pull-up; + }; + }; + i2c5_default: i2c5_default { + group1 { + pinmux = , ; + drive-open-drain; + drive-strength = "0.5"; + bias-pull-up; + }; + }; + + spi0_default: spi0_default { + group1 { + pinmux = , , ; + }; + group2 { + pinmux = ; + drive-push-pull; + ambiq,iom-mspi = <1>; + ambiq,iom-nce-module = <0>; + ambiq,iom-num = <0>; + }; + }; + spi1_default: spi1_default { + group1 { + pinmux = , , ; + }; + group2 { + pinmux = ; + drive-push-pull; + ambiq,iom-mspi = <1>; + ambiq,iom-nce-module = <1>; + ambiq,iom-num = <1>; + }; + }; + spi2_default: spi2_default { + group1 { + pinmux = , , ; + }; + group2 { + pinmux = ; + drive-push-pull; + ambiq,iom-mspi = <1>; + ambiq,iom-nce-module = <3>; + ambiq,iom-num = <2>; + }; + }; + spi3_default: spi3_default { + group1 { + pinmux = , , ; + }; + group2 { + pinmux = ; + drive-push-pull; + ambiq,iom-mspi = <1>; + ambiq,iom-nce-module = <0>; + ambiq,iom-num = <3>; + }; + }; + spi4_default: spi4_default { + group1 { + pinmux = , , ; + }; + group2 { + pinmux = ; + drive-push-pull; + ambiq,iom-mspi = <1>; + ambiq,iom-nce-module = <1>; + ambiq,iom-num = <4>; + }; + }; + spi5_default: spi5_default { + group1 { + pinmux = , , ; + }; + group2 { + pinmux = ; + drive-push-pull; + ambiq,iom-mspi = <1>; + ambiq,iom-nce-module = <0>; + ambiq,iom-num = <5>; + }; + }; + + mspi0_default: mspi0_default{ + group1 { + pinmux = , + , + , + , + ; + }; + group2 { + pinmux = ; + drive-push-pull; + drive-strength = "0.5"; + ambiq,iom-mspi = <0>; + ambiq,iom-nce-module = <0>; + ambiq,iom-num = <0>; + }; + }; + mspi1_default: mspi1_default{ + group1 { + pinmux = , + , + , + , + , + , + , + , + ; + }; + group2 { + pinmux = ; + drive-push-pull; + drive-strength = "0.5"; + ambiq,iom-mspi = <0>; + ambiq,iom-nce-module = <0>; + ambiq,iom-num = <1>; + }; + }; + mspi2_default: mspi2_default{ + group1 { + pinmux = , + , + , + , + ; + }; + group2 { + pinmux = ; + drive-push-pull; + drive-strength = "0.5"; + ambiq,iom-mspi = <0>; + ambiq,iom-nce-module = <0>; + ambiq,iom-num = <2>; + }; + }; +}; diff --git a/boards/ambiq/apollo3p_evb/apollo3p_evb.dts b/boards/ambiq/apollo3p_evb/apollo3p_evb.dts new file mode 100644 index 00000000000..02acc1bed57 --- /dev/null +++ b/boards/ambiq/apollo3p_evb/apollo3p_evb.dts @@ -0,0 +1,116 @@ +/dts-v1/; +#include + +#include "apollo3p_evb-pinctrl.dtsi" + +/ { + model = "Ambiq Apollo3 Blue Plus evaluation board"; + compatible = "ambiq,apollo3p_evb"; + + chosen { + zephyr,itcm = &tcm; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + 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 10 GPIO_ACTIVE_LOW>; + label = "LED 0"; + }; + led1: led_1 { + gpios = <&gpio0_31 30 GPIO_ACTIVE_LOW>; + label = "LED 1"; + }; + led2: led_2 { + gpios = <&gpio0_31 15 GPIO_ACTIVE_LOW>; + label = "LED 2"; + }; + led3: led_3 { + gpios = <&gpio0_31 14 GPIO_ACTIVE_LOW>; + label = "LED 3"; + }; + led4: led_4 { + gpios = <&gpio0_31 17 GPIO_ACTIVE_LOW>; + label = "LED 4"; + }; + }; + + buttons { + compatible = "gpio-keys"; + button0: button_0 { + gpios = <&gpio0_31 16 GPIO_ACTIVE_LOW>; + label = "BTN0"; + }; + button1: button_1 { + gpios = <&gpio0_31 18 GPIO_ACTIVE_LOW>; + label = "BTN1"; + }; + button2: button_2 { + gpios = <&gpio0_31 19 GPIO_ACTIVE_LOW>; + label = "BTN2"; + }; + }; +}; + +&flash0 { + erase-block-size = <8192>; + write-block-size = <4>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* Set 16KB of storage at the end of the 2000KB of flash */ + storage_partition: partition@1f0000 { + label = "storage"; + reg = <0x001f0000 0x4000>; + }; + }; +}; + +&uart0 { + current-speed = <115200>; + pinctrl-0 = <&uart0_default>; + pinctrl-names = "default"; + status = "okay"; +}; + +&wdt0 { + status = "okay"; +}; + +&i2c3 { + compatible = "ambiq,i2c"; + pinctrl-0 = <&i2c3_default>; + pinctrl-names = "default"; + clock-frequency = ; + status = "okay"; +}; + +&gpio0_31 { + status = "okay"; +}; + +&gpio32_63 { + status = "okay"; +}; + +&gpio64_95 { + status = "okay"; +}; diff --git a/boards/ambiq/apollo3p_evb/apollo3p_evb.yaml b/boards/ambiq/apollo3p_evb/apollo3p_evb.yaml new file mode 100644 index 00000000000..0ed3fe2929d --- /dev/null +++ b/boards/ambiq/apollo3p_evb/apollo3p_evb.yaml @@ -0,0 +1,18 @@ +identifier: apollo3p_evb +name: Apollo3 Blue Plus EVB +type: mcu +arch: arm +ram: 768 +flash: 2000 +toolchain: + - zephyr + - gnuarmemb +supported: + - uart + - watchdog + - gpio + - i2c +testing: + ignore_tags: + - net +vendor: ambiq diff --git a/boards/ambiq/apollo3p_evb/apollo3p_evb_defconfig b/boards/ambiq/apollo3p_evb/apollo3p_evb_defconfig new file mode 100644 index 00000000000..5f556803e52 --- /dev/null +++ b/boards/ambiq/apollo3p_evb/apollo3p_evb_defconfig @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright (c) 2023 Ambiq Micro Inc. + +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_UART_INTERRUPT_DRIVEN=y diff --git a/boards/ambiq/apollo3p_evb/board.cmake b/boards/ambiq/apollo3p_evb/board.cmake new file mode 100644 index 00000000000..d81e4cdc13d --- /dev/null +++ b/boards/ambiq/apollo3p_evb/board.cmake @@ -0,0 +1,6 @@ +# Copyright (c) 2023 Ambiq Micro Inc. +# SPDX-License-Identifier: Apache-2.0 + +board_runner_args(jlink "--device=AMA3B2KK-KBR" "--iface=swd" "--speed=1000") + +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/ambiq/apollo3p_evb/board.yml b/boards/ambiq/apollo3p_evb/board.yml new file mode 100644 index 00000000000..507a85548b0 --- /dev/null +++ b/boards/ambiq/apollo3p_evb/board.yml @@ -0,0 +1,5 @@ +board: + name: apollo3p_evb + vendor: ambiq + socs: + - name: apollo3p_blue diff --git a/boards/ambiq/apollo3p_evb/doc/apollo3-blue-plus-soc-eval-board.jpg b/boards/ambiq/apollo3p_evb/doc/apollo3-blue-plus-soc-eval-board.jpg new file mode 100644 index 00000000000..6aa0d0a7d53 Binary files /dev/null and b/boards/ambiq/apollo3p_evb/doc/apollo3-blue-plus-soc-eval-board.jpg differ diff --git a/boards/ambiq/apollo3p_evb/doc/index.rst b/boards/ambiq/apollo3p_evb/doc/index.rst new file mode 100644 index 00000000000..9d56556d69c --- /dev/null +++ b/boards/ambiq/apollo3p_evb/doc/index.rst @@ -0,0 +1,102 @@ +.. _apollo3p_evb: + +Ambiq Apollo3 Blue Plus EVB +########################### + +Apollo3 Blue Plus EVB is a board by Ambiq featuring their ultra-low power Apollo3 Blue Plus SoC. + +.. image:: ./apollo3-blue-plus-soc-eval-board.jpg + :align: center + :alt: Apollo3 Blue Plus EVB + +Hardware +******** + +- Apollo3 Blue Plus SoC with up to 96 MHz operating frequency +- ARMĀ® CortexĀ® M4F core +- 16 kB 2-way Associative/Direct-Mapped Cache per core +- Up to 2 MB of flash memory for code/data +- Up to 768 KB of low leakage / low power RAM for code/data +- Integrated Bluetooth 5 Low-energy controller + +For more information about the Apollo3 Blue Plus SoC and Apollo3 Blue Plus EVB board: + +- `Apollo3 Blue Plus Website`_ +- `Apollo3 Blue Plus Datasheet`_ +- `Apollo3 Blue Plus EVB Website`_ + +Supported Features +================== + +The Apollo3 Blue Plus EVB board configuration supports the following hardware features: + ++-----------+------------+-------------------------------------+ +| Interface | Controller | Driver/Component | ++===========+============+=====================================+ +| MPU | on-chip | memory protection unit | ++-----------+------------+-------------------------------------+ +| NVIC | on-chip | nested vector interrupt controller | ++-----------+------------+-------------------------------------+ +| SYSTICK | on-chip | systick | ++-----------+------------+-------------------------------------+ +| STIMER | on-chip | stimer | ++-----------+------------+-------------------------------------+ +| GPIO | on-chip | gpio | ++-----------+------------+-------------------------------------+ +| UART | on-chip | serial | ++-----------+------------+-------------------------------------+ +| WDT | on-chip | watchdog | ++-----------+------------+-------------------------------------+ +| RADIO | on-chip | bluetooth | ++-----------+------------+-------------------------------------+ + +The default configuration can be found in the defconfig file: +``boards/arm/apollo3p_evb/apollo3p_evb_defconfig``. + +Programming and Debugging +========================= + +Flashing an application +----------------------- + +Connect your device to your host computer using the JLINK USB port. +The sample application :ref:`hello_world` is used for this example. +Build the Zephyr kernel and application, then flash it to the device: + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: apollo3p_evb + :goals: flash + +.. note:: + `west flash` requires `SEGGER J-Link software`_ and `pylink`_ Python module + to be installed on you host computer. + +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 be able to see on the corresponding Serial Port +the following message: + +.. code-block:: console + + Hello World! apollo3p_evb + +.. _Apollo3 Blue Plus Website: + https://ambiq.com/apollo3-blue-plus/ + +.. _Apollo3 Blue Plus Datasheet: + https://contentportal.ambiq.com/documents/20123/388390/Apollo3-Blue-Plus-SoC-Datasheet.pdf + +.. _Apollo3 Blue Plus EVB Website: + https://www.ambiq.top/en/apollo3-blue-plus-soc-eval-board + +.. _SEGGER J-Link software: + https://www.segger.com/downloads/jlink + +.. _pylink: + https://github.com/Square/pylink diff --git a/boards/ambiq/apollo4p_evb/apollo4p_evb.yaml b/boards/ambiq/apollo4p_evb/apollo4p_evb.yaml index 1aa0fbf75d4..205da184346 100644 --- a/boards/ambiq/apollo4p_evb/apollo4p_evb.yaml +++ b/boards/ambiq/apollo4p_evb/apollo4p_evb.yaml @@ -14,6 +14,7 @@ supported: - gpio - spi - i2c + - hwinfo testing: ignore_tags: - net diff --git a/boards/arduino/giga_r1/arduino_giga_r1_stm32h747xx_m7.dts b/boards/arduino/giga_r1/arduino_giga_r1_stm32h747xx_m7.dts index 4459780243b..0ffb4f75380 100644 --- a/boards/arduino/giga_r1/arduino_giga_r1_stm32h747xx_m7.dts +++ b/boards/arduino/giga_r1/arduino_giga_r1_stm32h747xx_m7.dts @@ -141,8 +141,6 @@ 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>; }; &flash0 { diff --git a/boards/arduino/uno_r4/arduino_uno_r4_minima.dts b/boards/arduino/uno_r4/arduino_uno_r4_minima.dts index 6984b6c5354..d80ca6d4f1f 100644 --- a/boards/arduino/uno_r4/arduino_uno_r4_minima.dts +++ b/boards/arduino/uno_r4/arduino_uno_r4_minima.dts @@ -21,4 +21,33 @@ aliases { led0 = &led; }; + + 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 &ioport0 14 0>, /* A0 */ + <1 0 &ioport0 0 0>, /* A1 */ + <2 0 &ioport0 1 0>, /* A2 */ + <3 0 &ioport0 2 0>, /* A3 */ + <4 0 &ioport1 1 0>, /* A4 */ + <5 0 &ioport1 0 0>, /* A5 */ + <6 0 &ioport3 1 0>, /* D0 */ + <7 0 &ioport3 2 0>, /* D1 */ + <8 0 &ioport1 5 0>, /* D2 */ + <9 0 &ioport1 4 0>, /* D3 */ + <10 0 &ioport1 3 0>, /* D4 */ + <11 0 &ioport1 2 0>, /* D5 */ + <12 0 &ioport1 6 0>, /* D6 */ + <13 0 &ioport1 7 0>, /* D7 */ + <14 0 &ioport3 4 0>, /* D8 */ + <15 0 &ioport3 3 0>, /* D9 */ + <16 0 &ioport1 12 0>, /* D10 */ + <17 0 &ioport1 9 0>, /* D11 */ + <18 0 &ioport1 10 0>, /* D12 */ + <19 0 &ioport1 11 0>, /* D13 */ + <20 0 &ioport1 1 0>, /* D14 */ + <21 0 &ioport1 0 0>; /* D15 */ + }; }; diff --git a/boards/arduino/uno_r4/arduino_uno_r4_wifi.dts b/boards/arduino/uno_r4/arduino_uno_r4_wifi.dts index 2cba24cdf16..a3a2019990e 100644 --- a/boards/arduino/uno_r4/arduino_uno_r4_wifi.dts +++ b/boards/arduino/uno_r4/arduino_uno_r4_wifi.dts @@ -21,4 +21,33 @@ aliases { led0 = &led; }; + + 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 &ioport0 14 0>, /* A0 */ + <1 0 &ioport0 0 0>, /* A1 */ + <2 0 &ioport0 1 0>, /* A2 */ + <3 0 &ioport0 2 0>, /* A3 */ + <4 0 &ioport1 1 0>, /* A4 */ + <5 0 &ioport1 0 0>, /* A5 */ + <6 0 &ioport3 1 0>, /* D0 */ + <7 0 &ioport3 2 0>, /* D1 */ + <8 0 &ioport1 4 0>, /* D2 */ + <9 0 &ioport1 5 0>, /* D3 */ + <10 0 &ioport1 6 0>, /* D4 */ + <11 0 &ioport1 7 0>, /* D5 */ + <12 0 &ioport1 11 0>, /* D6 */ + <13 0 &ioport1 12 0>, /* D7 */ + <14 0 &ioport3 4 0>, /* D8 */ + <15 0 &ioport3 3 0>, /* D9 */ + <16 0 &ioport1 3 0>, /* D10 */ + <17 0 &ioport4 11 0>, /* D11 */ + <18 0 &ioport4 10 0>, /* D12 */ + <19 0 &ioport1 2 0>, /* D13 */ + <20 0 &ioport1 1 0>, /* D14 */ + <21 0 &ioport1 0 0>; /* D15 */ + }; }; diff --git a/boards/arm/fvp_baser_aemv8r/board.cmake b/boards/arm/fvp_baser_aemv8r/board.cmake index f7753bc5099..8f5b70f5f33 100644 --- a/boards/arm/fvp_baser_aemv8r/board.cmake +++ b/boards/arm/fvp_baser_aemv8r/board.cmake @@ -5,7 +5,8 @@ set(SUPPORTED_EMU_PLATFORMS armfvp) set(ARMFVP_BIN_NAME FVP_BaseR_AEMv8R) set(ARMFVP_MIN_VERSION 11.16.16) -if(CONFIG_BOARD_FVP_BASER_AEMV8R_FVP_AEMV8R_AARCH64) +if(CONFIG_BOARD_FVP_BASER_AEMV8R_FVP_AEMV8R_AARCH64 OR + CONFIG_BOARD_FVP_BASER_AEMV8R_FVP_AEMV8R_AARCH64_SMP) set(ARMFVP_FLAGS -C cluster0.has_aarch64=1 -C cluster0.VMSA_supported=0 @@ -38,7 +39,8 @@ if(CONFIG_BOARD_FVP_BASER_AEMV8R_FVP_AEMV8R_AARCH64) -C bp.vis.rate_limit-enable=0 -C cache_state_modelled=1 ) -elseif(CONFIG_BOARD_FVP_BASER_AEMV8R_FVP_AEMV8R_AARCH32) +elseif(CONFIG_BOARD_FVP_BASER_AEMV8R_FVP_AEMV8R_AARCH32 OR + CONFIG_BOARD_FVP_BASER_AEMV8R_FVP_AEMV8R_AARCH32_SMP) set(ARMFVP_FLAGS -C cluster0.has_aarch64=0 -C cluster0.VMSA_supported=0 diff --git a/boards/atmel/sam/sam_e70_xplained/sam_e70_xplained-common.dtsi b/boards/atmel/sam/sam_e70_xplained/sam_e70_xplained-common.dtsi index 93dc9b1f356..ded3866acfe 100644 --- a/boards/atmel/sam/sam_e70_xplained/sam_e70_xplained-common.dtsi +++ b/boards/atmel/sam/sam_e70_xplained/sam_e70_xplained-common.dtsi @@ -206,9 +206,6 @@ zephyr_udc0: &usbhs { pinctrl-0 = <&can0_default>; pinctrl-names = "default"; - bus-speed = <125000>; - bus-speed-data = <1000000>; - can-transceiver { max-bitrate = <5000000>; }; diff --git a/boards/atmel/sam/sam_v71_xult/sam_v71_xult-common.dtsi b/boards/atmel/sam/sam_v71_xult/sam_v71_xult-common.dtsi index 9864c7ae50a..f6981455b51 100644 --- a/boards/atmel/sam/sam_v71_xult/sam_v71_xult-common.dtsi +++ b/boards/atmel/sam/sam_v71_xult/sam_v71_xult-common.dtsi @@ -331,9 +331,6 @@ zephyr_udc0: &usbhs { pinctrl-0 = <&can1_default>; pinctrl-names = "default"; - bus-speed = <125000>; - bus-speed-data = <1000000>; - can-transceiver { max-bitrate = <5000000>; }; diff --git a/boards/atmel/sam0/samc21n_xpro/samc21n_xpro.dts b/boards/atmel/sam0/samc21n_xpro/samc21n_xpro.dts index 79ff5b90ecf..3827dc104d9 100644 --- a/boards/atmel/sam0/samc21n_xpro/samc21n_xpro.dts +++ b/boards/atmel/sam0/samc21n_xpro/samc21n_xpro.dts @@ -162,9 +162,6 @@ pinctrl-0 = <&can0_default>; pinctrl-names = "default"; - bus-speed = <125000>; - bus-speed-data = <1000000>; - can-transceiver { max-bitrate = <5000000>; }; @@ -174,9 +171,6 @@ pinctrl-0 = <&can1_default>; pinctrl-names = "default"; - bus-speed = <125000>; - bus-speed-data = <1000000>; - can-transceiver { max-bitrate = <5000000>; }; diff --git a/boards/bcdevices/plt_demo_v2/blueclover_plt_demo_v2_nrf52832.dts b/boards/bcdevices/plt_demo_v2/blueclover_plt_demo_v2_nrf52832.dts index 48bcacff102..245b2eb1aad 100644 --- a/boards/bcdevices/plt_demo_v2/blueclover_plt_demo_v2_nrf52832.dts +++ b/boards/bcdevices/plt_demo_v2/blueclover_plt_demo_v2_nrf52832.dts @@ -8,6 +8,7 @@ #include #include "blueclover_plt_demo_v2_nrf52832-pinctrl.dtsi" #include +#include / { model = "Blue Clover PLT Demo Board V2"; @@ -107,6 +108,10 @@ compatible = "apa,apa102"; reg = <0>; spi-max-frequency = <5250000>; + chain-length = <4>; + color-mapping = ; }; }; diff --git a/boards/croxel/croxel_cx1825/Kconfig b/boards/croxel/croxel_cx1825/Kconfig new file mode 100644 index 00000000000..81b03929adc --- /dev/null +++ b/boards/croxel/croxel_cx1825/Kconfig @@ -0,0 +1,16 @@ +# Copyright (c) 2024 Luis Ubieda +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_CROXEL_CX1825 + +config BOARD_ENABLE_DCDC + bool "DCDC mode" + select SOC_DCDC_NRF52X + default y + +config BOARD_ENABLE_DCDC_HV + bool "High Voltage DCDC converter" + select SOC_DCDC_NRF52X_HV + default y + +endif # BOARD_CROXEL_CX1825 diff --git a/boards/croxel/croxel_cx1825/Kconfig.croxel_cx1825 b/boards/croxel/croxel_cx1825/Kconfig.croxel_cx1825 new file mode 100644 index 00000000000..0900f35b4ab --- /dev/null +++ b/boards/croxel/croxel_cx1825/Kconfig.croxel_cx1825 @@ -0,0 +1,5 @@ +# Copyright (c) 2024 Luis Ubieda +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_CROXEL_CX1825 + select SOC_NRF52840_QIAA diff --git a/boards/croxel/croxel_cx1825/Kconfig.defconfig b/boards/croxel/croxel_cx1825/Kconfig.defconfig new file mode 100644 index 00000000000..c96e14fea06 --- /dev/null +++ b/boards/croxel/croxel_cx1825/Kconfig.defconfig @@ -0,0 +1,18 @@ +# Copyright (c) 2024 Luis Ubieda +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_CROXEL_CX1825 + +config BT_CTLR + default BT + +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_CROXEL_CX1825 diff --git a/boards/croxel/croxel_cx1825/board.cmake b/boards/croxel/croxel_cx1825/board.cmake new file mode 100644 index 00000000000..f95878945be --- /dev/null +++ b/boards/croxel/croxel_cx1825/board.cmake @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: Apache-2.0 + +board_runner_args(jlink "--device=nRF52840_xxAA" "--speed=4000") +board_runner_args(pyocd "--target=nrf52840" "--frequency=4000000") +include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) +include(${ZEPHYR_BASE}/boards/common/nrfutil.board.cmake) +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) +include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) +include(${ZEPHYR_BASE}/boards/common/openocd-nrf5.board.cmake) diff --git a/boards/croxel/croxel_cx1825/board.yml b/boards/croxel/croxel_cx1825/board.yml new file mode 100644 index 00000000000..eed390e4a2c --- /dev/null +++ b/boards/croxel/croxel_cx1825/board.yml @@ -0,0 +1,5 @@ +board: + name: croxel_cx1825 + vendor: croxel + socs: + - name: nrf52840 diff --git a/boards/croxel/croxel_cx1825/croxel_cx1825_nrf52840-pinctrl.dtsi b/boards/croxel/croxel_cx1825/croxel_cx1825_nrf52840-pinctrl.dtsi new file mode 100644 index 00000000000..218e6214eb9 --- /dev/null +++ b/boards/croxel/croxel_cx1825/croxel_cx1825_nrf52840-pinctrl.dtsi @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2024 Luis Ubieda + * SPDX-License-Identifier: Apache-2.0 + */ + +&pinctrl { + + i2c0_default: i2c0_default { + group1 { + psels = , + ; + }; + }; + + i2c0_sleep: i2c0_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; + + pwm0_default: pwm0_default { + group1 { + psels = ; + }; + }; + + pwm0_sleep: pwm0_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; diff --git a/boards/croxel/croxel_cx1825/croxel_cx1825_nrf52840.dts b/boards/croxel/croxel_cx1825/croxel_cx1825_nrf52840.dts new file mode 100644 index 00000000000..fac78f10b71 --- /dev/null +++ b/boards/croxel/croxel_cx1825/croxel_cx1825_nrf52840.dts @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2024 Luis Ubieda + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include "croxel_cx1825_nrf52840-pinctrl.dtsi" +#include + +/ { + model = "Croxel CX1825 NRF52840"; + compatible = "croxel,cx1825-nrf52840"; + + chosen { + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; + zephyr,console = &cdc_acm_0; + zephyr,shell-uart = &cdc_acm_0; + }; + + leds { + compatible = "gpio-leds"; + led0: led_0 { + gpios = <&gpio0 8 GPIO_ACTIVE_LOW>; + label = "Red LED"; + }; + led1: led_1 { + gpios = <&gpio0 12 GPIO_ACTIVE_LOW>; + label = "Green LED"; + }; + }; + + buttons { + compatible = "gpio-keys"; + button0: button_0 { + gpios = <&gpio0 16 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "Push button switch 0"; + zephyr,code = ; + }; + }; + + /* These aliases are provided for compatibility with samples */ + aliases { + led0 = &led0; + led1 = &led1; + sw0 = &button0; + bootloader-led0 = &led0; + mcuboot-button0 = &button0; + mcuboot-led0 = &led0; + watchdog0 = &wdt0; + }; +}; + +&adc { + status = "okay"; +}; + +&uicr { + gpio-as-nreset; +}; + +&gpiote { + status = "okay"; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&pwm0 { + status = "okay"; + pinctrl-0 = <&pwm0_default>; + pinctrl-1 = <&pwm0_sleep>; + pinctrl-names = "default", "sleep"; +}; + +arduino_i2c: &i2c0 { + compatible = "nordic,nrf-twi"; + status = "okay"; + pinctrl-0 = <&i2c0_default>; + pinctrl-1 = <&i2c0_sleep>; + pinctrl-names = "default", "sleep"; + + hts221: hts221@5f { + compatible = "st,hts221"; + status = "okay"; + reg = <0x5f>; + drdy-gpios = <&gpio1 2 GPIO_ACTIVE_HIGH>; + }; + + lps22hb: lps22hb-press@5c { + compatible = "st,lps22hb-press"; + status = "okay"; + reg = <0x5c>; + }; + + apds9960: apds9960@39 { + compatible = "avago,apds9960"; + status = "okay"; + reg = <0x39>; + int-gpios = <&gpio0 4 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + }; + + lis3dh: lis3dh@18 { + compatible = "st,lis3dh", "st,lis2dh"; + status = "okay"; + reg = <0x18>; + irq-gpios = <&gpio1 15 GPIO_ACTIVE_HIGH>; + }; +}; + +zephyr_udc0: &usbd { + compatible = "nordic,nrf-usbd"; + status = "okay"; + + cdc_acm_0: cdc_acm_0 { + compatible = "zephyr,cdc-acm-uart"; + }; +}; + +&flash0 { + + 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 0x00076000>; + }; + slot1_partition: partition@82000 { + label = "image-1"; + reg = <0x00082000 0x00076000>; + }; + + /* + * Storage partition will be used by FCB/LittleFS/NVS + * if enabled. + */ + storage_partition: partition@f8000 { + label = "storage"; + reg = <0x000f8000 0x00008000>; + }; + }; +}; diff --git a/boards/croxel/croxel_cx1825/croxel_cx1825_nrf52840.yaml b/boards/croxel/croxel_cx1825/croxel_cx1825_nrf52840.yaml new file mode 100644 index 00000000000..8fa7989a6eb --- /dev/null +++ b/boards/croxel/croxel_cx1825/croxel_cx1825_nrf52840.yaml @@ -0,0 +1,19 @@ +identifier: croxel_cx1825/nrf52840 +name: Croxel-CX1825-NRF52840 +type: mcu +arch: arm +ram: 256 +flash: 1024 +toolchain: + - zephyr + - gnuarmemb + - xtools +supported: + - arduino_gpio + - arduino_i2c + - ble + - counter + - gpio + - i2c + - watchdog +vendor: croxel diff --git a/boards/croxel/croxel_cx1825/croxel_cx1825_nrf52840_defconfig b/boards/croxel/croxel_cx1825/croxel_cx1825_nrf52840_defconfig new file mode 100644 index 00000000000..8694d118b00 --- /dev/null +++ b/boards/croxel/croxel_cx1825/croxel_cx1825_nrf52840_defconfig @@ -0,0 +1,22 @@ +# Copyright (c) 2024 Luis Ubieda +# SPDX-License-Identifier: Apache-2.0 + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable hardware stack protection +CONFIG_HW_STACK_PROTECTION=y + +# enable GPIO +CONFIG_GPIO=y + +# Assume we start console by default +CONFIG_USB_DEVICE_INITIALIZE_AT_BOOT=y + +# Console over USB CDC-ACM +CONFIG_USB_DEVICE_STACK=y +CONFIG_SERIAL=y +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y +CONFIG_UART_INTERRUPT_DRIVEN=y +CONFIG_UART_LINE_CTRL=y diff --git a/boards/croxel/croxel_cx1825/doc/img/cx1825_nrf52840.jpg b/boards/croxel/croxel_cx1825/doc/img/cx1825_nrf52840.jpg new file mode 100644 index 00000000000..64ce7b6369c Binary files /dev/null and b/boards/croxel/croxel_cx1825/doc/img/cx1825_nrf52840.jpg differ diff --git a/boards/croxel/croxel_cx1825/doc/index.rst b/boards/croxel/croxel_cx1825/doc/index.rst new file mode 100644 index 00000000000..f3e42b3657b --- /dev/null +++ b/boards/croxel/croxel_cx1825/doc/index.rst @@ -0,0 +1,130 @@ +.. _croxel_cx1825_nrf52840: + +CX1825 nRF52840 +############### + +Overview +******** + +Croxel's `CX1825 Bluetooth Prototyping board`_ provides support for the Nordic +Semiconductor nRF52840 ARM Cortex-M4F CPU 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)` +* RADIO (Bluetooth Low Energy and 802.15.4) +* :abbr:`RTC (nRF RTC System Clock)` +* Segger RTT (RTT Console) +* :abbr:`SPI (Serial Peripheral Interface)` +* :abbr:`USB (Universal Serial Bus)` +* :abbr:`WDT (Watchdog Timer)` + +.. figure:: img/cx1825_nrf52840.jpg + :align: center + :alt: CX1825 + + Croxel's CX1825 Bluetooth Prototyping board (Credit: Croxel) + +Hardware +******** + +- Ezurio's BL654 (nRF52840 ARM Cortex-M4F processor at 64MHz) +- 1 MB flash memory and 256 KB of SRAM +- Coin-cell retainer for Lithium coincell batteries +- 2 Discrete LEDs (Red and Green) +- User Button +- Reset Button +- Accelerometer (LIS3DH) +- Ambient & RGB Light and Proximity Sensor (APDS9960) +- Temperature and Humidity Sensor (HTS221) +- Barometric Pressure sensor (LPS22H) +- Hall Effect Switch (MLX90248) +- RGB LED with Charge-Pump driver (LPS5521) +- Digital Microphone +- Beeper +- QWIIC connector supporting expansion for I2C devices +- USB Connector for data and power +- 16-pin Expansion connector +- SWD Connector + +Supported Features +================== + +- Discrete LEDs (red and green) +- Buttons (User and Reset) +- Sensors (Accelerometer, Light, Temperature and Humidity, Pressure and Hall-Effect sensors) +- Beeper +- Radio (Bluetooth, IEEE 802.15.4) +- SOC peripherals (ADC, Clock, Flash, GPIO, I2C, MPU, NVIC, PWM, Radio, RTC, SPI, USB, WDT) + +Future Feature Support +====================== + +- RGB LED (Charge-Pump driver not implemented) +- Microphone + +Connections and IOs +=================== + +Croxel's CX1825 Bluetooth Prototyping board has detailed information +about the board (`schematic`_) + +LEDs +---- + +- LED1 (red) = P0.8 +- LED2 (green) = P0.12 + +Digital Inputs +-------------- + +- User Button = P1.16 +- Reset Button = P0.18 +- Hall-Effect Switch = P0.15 + +Programming and Debugging +************************* + +Applications for the ``croxel_cx1825/nrf52840`` board configuration +can be built and flashed in the usual way (see :ref:`build_an_application` +and :ref:`application_run` for more details). + +Flashing +======== + +Flashing Zephyr onto the ``croxel_cx1825_nrf52840`` board requires +an external programmer. The programmer is attached to the SWD header. + +Build the Zephyr kernel and the :zephyr:code-sample:`blinky` sample application. + + .. zephyr-app-commands:: + :zephyr-app: samples/basic/blinky + :board: croxel_cx1825/nrf52840 + :goals: build + :compact: + +Flash the image. + + .. zephyr-app-commands:: + :zephyr-app: samples/basic/blinky + :board: croxel_cx1825/nrf52840 + :goals: flash + :compact: + +You should see the red LED blink. + +References +********** + +.. target-notes:: + +.. _CX1825 Bluetooth Prototyping board: + https://croxel.com/ble + +.. _schematic: + https://croxeldata.s3.amazonaws.com/cx1825/CX1825-01_SCH_200424A.PDF diff --git a/boards/croxel/croxel_cx1825/pre_dt_board.cmake b/boards/croxel/croxel_cx1825/pre_dt_board.cmake new file mode 100644 index 00000000000..3369c21d3af --- /dev/null +++ b/boards/croxel/croxel_cx1825/pre_dt_board.cmake @@ -0,0 +1,7 @@ +# Copyright (c) 2022 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +# Suppress "unique_unit_address_if_enabled" to handle the following overlaps: +# - power@40000000 & clock@40000000 & bprot@40000000 +# - acl@4001e000 & flash-controller@4001e000 +list(APPEND EXTRA_DTC_FLAGS "-Wno-unique_unit_address_if_enabled") diff --git a/boards/croxel/index.rst b/boards/croxel/index.rst new file mode 100644 index 00000000000..0555c607d90 --- /dev/null +++ b/boards/croxel/index.rst @@ -0,0 +1,10 @@ +.. _boards-croxel: + +Croxel +###### + +.. toctree:: + :maxdepth: 1 + :glob: + + **/* diff --git a/boards/cypress/cy8ckit_062_ble/cy8ckit_062_ble_cy8c6347_m0.dts b/boards/cypress/cy8ckit_062_ble/cy8ckit_062_ble_cy8c6347_m0.dts index 8f5176e2623..0fae593a879 100644 --- a/boards/cypress/cy8ckit_062_ble/cy8ckit_062_ble_cy8c6347_m0.dts +++ b/boards/cypress/cy8ckit_062_ble/cy8ckit_062_ble_cy8c6347_m0.dts @@ -7,7 +7,7 @@ /dts-v1/; -#include +#include #include "cy8ckit_062_ble_common.dtsi" / { diff --git a/boards/cypress/cy8ckit_062_ble/cy8ckit_062_ble_cy8c6347_m0_0_0_0.yaml b/boards/cypress/cy8ckit_062_ble/cy8ckit_062_ble_cy8c6347_m0_0_0_0.yaml index 311c88f58ac..a8e935bd50a 100644 --- a/boards/cypress/cy8ckit_062_ble/cy8ckit_062_ble_cy8c6347_m0_0_0_0.yaml +++ b/boards/cypress/cy8ckit_062_ble/cy8ckit_062_ble_cy8c6347_m0_0_0_0.yaml @@ -6,7 +6,7 @@ # identifier: cy8ckit_062_ble@0.0.0/cy8c6347/m0 -name: Cypress PSoC6 BLE Pioneer Kit (M0) +name: Cypress PSoC6 BLE Pioneer Kit (M0, rev. 0.0.0) type: mcu arch: arm ram: 288 diff --git a/boards/cypress/cy8ckit_062_ble/cy8ckit_062_ble_cy8c6347_m0_1_0_0.yaml b/boards/cypress/cy8ckit_062_ble/cy8ckit_062_ble_cy8c6347_m0_1_0_0.yaml index c3bcfac49c5..27b02fa4bed 100644 --- a/boards/cypress/cy8ckit_062_ble/cy8ckit_062_ble_cy8c6347_m0_1_0_0.yaml +++ b/boards/cypress/cy8ckit_062_ble/cy8ckit_062_ble_cy8c6347_m0_1_0_0.yaml @@ -6,7 +6,7 @@ # identifier: cy8ckit_062_ble@1.0.0/cy8c6347/m0 -name: Cypress PSoC6 BLE Pioneer Kit (M0) +name: Cypress PSoC6 BLE Pioneer Kit (M0, rev. 1.0.0) type: mcu arch: arm ram: 288 diff --git a/boards/cypress/cy8ckit_062_ble/cy8ckit_062_ble_cy8c6347_m4.dts b/boards/cypress/cy8ckit_062_ble/cy8ckit_062_ble_cy8c6347_m4.dts index 82887420422..e232445e811 100644 --- a/boards/cypress/cy8ckit_062_ble/cy8ckit_062_ble_cy8c6347_m4.dts +++ b/boards/cypress/cy8ckit_062_ble/cy8ckit_062_ble_cy8c6347_m4.dts @@ -7,7 +7,7 @@ /dts-v1/; -#include +#include #include "cy8ckit_062_ble_common.dtsi" / { diff --git a/boards/cypress/cy8ckit_062_ble/cy8ckit_062_ble_cy8c6347_m4_0_0_0.yaml b/boards/cypress/cy8ckit_062_ble/cy8ckit_062_ble_cy8c6347_m4_0_0_0.yaml index ba22e8aa624..30708da7fa4 100644 --- a/boards/cypress/cy8ckit_062_ble/cy8ckit_062_ble_cy8c6347_m4_0_0_0.yaml +++ b/boards/cypress/cy8ckit_062_ble/cy8ckit_062_ble_cy8c6347_m4_0_0_0.yaml @@ -6,7 +6,7 @@ # identifier: cy8ckit_062_ble@0.0.0/cy8c6347/m4 -name: Cypress PSoC6 BLE Pioneer Kit (M4) +name: Cypress PSoC6 BLE Pioneer Kit (M4, rev. 0.0.0) type: mcu arch: arm ram: 288 diff --git a/boards/cypress/cy8ckit_062_ble/cy8ckit_062_ble_cy8c6347_m4_1_0_0.yaml b/boards/cypress/cy8ckit_062_ble/cy8ckit_062_ble_cy8c6347_m4_1_0_0.yaml index bd4a3affce9..c7572470978 100644 --- a/boards/cypress/cy8ckit_062_ble/cy8ckit_062_ble_cy8c6347_m4_1_0_0.yaml +++ b/boards/cypress/cy8ckit_062_ble/cy8ckit_062_ble_cy8c6347_m4_1_0_0.yaml @@ -6,7 +6,7 @@ # identifier: cy8ckit_062_ble@1.0.0/cy8c6347/m4 -name: Cypress PSoC6 BLE Pioneer Kit (M4) +name: Cypress PSoC6 BLE Pioneer Kit (M4, rev. 1.0.0) type: mcu arch: arm ram: 288 diff --git a/boards/cypress/cy8ckit_062_wifi_bt/cy8ckit_062_wifi_bt_cy8c6247_m0.dts b/boards/cypress/cy8ckit_062_wifi_bt/cy8ckit_062_wifi_bt_cy8c6247_m0.dts index fff6d89ea5d..18fe196201b 100644 --- a/boards/cypress/cy8ckit_062_wifi_bt/cy8ckit_062_wifi_bt_cy8c6247_m0.dts +++ b/boards/cypress/cy8ckit_062_wifi_bt/cy8ckit_062_wifi_bt_cy8c6247_m0.dts @@ -7,7 +7,7 @@ /dts-v1/; -#include +#include #include / { diff --git a/boards/cypress/cy8ckit_062_wifi_bt/cy8ckit_062_wifi_bt_cy8c6247_m4.dts b/boards/cypress/cy8ckit_062_wifi_bt/cy8ckit_062_wifi_bt_cy8c6247_m4.dts index e192f94580d..7cd87ba8634 100644 --- a/boards/cypress/cy8ckit_062_wifi_bt/cy8ckit_062_wifi_bt_cy8c6247_m4.dts +++ b/boards/cypress/cy8ckit_062_wifi_bt/cy8ckit_062_wifi_bt_cy8c6247_m4.dts @@ -6,7 +6,7 @@ /dts-v1/; -#include +#include / { model = "cy8ckit_062_wifi_bt_m4 with a Cypress PSoC6 SoC"; diff --git a/boards/cypress/cy8ckit_062s4/board.yml b/boards/cypress/cy8ckit_062s4/board.yml deleted file mode 100644 index adb45b87c07..00000000000 --- a/boards/cypress/cy8ckit_062s4/board.yml +++ /dev/null @@ -1,5 +0,0 @@ -board: - name: cy8ckit_062s4 - vendor: cypress - socs: - - name: cy8c6244lqi_s4d92 diff --git a/boards/cypress/cy8cproto_062_4343w/board.yml b/boards/cypress/cy8cproto_062_4343w/board.yml deleted file mode 100644 index 575dbf83414..00000000000 --- a/boards/cypress/cy8cproto_062_4343w/board.yml +++ /dev/null @@ -1,5 +0,0 @@ -board: - name: cy8cproto_062_4343w - vendor: cypress - socs: - - name: cy8c624abzi_s2d44 diff --git a/boards/cypress/cy8cproto_063_ble/board.yml b/boards/cypress/cy8cproto_063_ble/board.yml deleted file mode 100644 index b35cb08ec2f..00000000000 --- a/boards/cypress/cy8cproto_063_ble/board.yml +++ /dev/null @@ -1,5 +0,0 @@ -board: - name: cy8cproto_063_ble - vendor: cypress - socs: - - name: cyble_416045_02 diff --git a/boards/deprecated.cmake b/boards/deprecated.cmake index e3812e10261..89a8b463e69 100644 --- a/boards/deprecated.cmake +++ b/boards/deprecated.cmake @@ -39,7 +39,7 @@ set(adp_xc7k_ae350_DEPRECATED adp_xc7k ) set(am62x_m4_phyboard_lyra_DEPRECATED - phyboard_lyra_am62x/am6234/m4 + phyboard_lyra/am6234/m4 ) set(am62x_m4_sk_DEPRECATED sk_am62/am6234/m4 @@ -630,7 +630,7 @@ set(pan1783a_pa_evb_cpunet_DEPRECATED pan1783a_pa_evb/nrf5340/cpunet ) set(phycore_am62x_a53_DEPRECATED - phycore_am62x/am6234/a53 + phyboard_lyra/am6234/a53 ) set(pico_pi_m4_DEPRECATED pico_pi/mcimx7d/m4 diff --git a/boards/espressif/esp32_devkitc_wroom/esp32_devkitc_wroom_esp32_appcpu.dts b/boards/espressif/esp32_devkitc_wroom/esp32_devkitc_wroom_appcpu.dts similarity index 100% rename from boards/espressif/esp32_devkitc_wroom/esp32_devkitc_wroom_esp32_appcpu.dts rename to boards/espressif/esp32_devkitc_wroom/esp32_devkitc_wroom_appcpu.dts diff --git a/boards/espressif/esp32_devkitc_wroom/esp32_devkitc_wroom_esp32_appcpu.yaml b/boards/espressif/esp32_devkitc_wroom/esp32_devkitc_wroom_appcpu.yaml similarity index 100% rename from boards/espressif/esp32_devkitc_wroom/esp32_devkitc_wroom_esp32_appcpu.yaml rename to boards/espressif/esp32_devkitc_wroom/esp32_devkitc_wroom_appcpu.yaml diff --git a/boards/espressif/esp32_devkitc_wroom/esp32_devkitc_wroom_esp32_appcpu_defconfig b/boards/espressif/esp32_devkitc_wroom/esp32_devkitc_wroom_appcpu_defconfig similarity index 100% rename from boards/espressif/esp32_devkitc_wroom/esp32_devkitc_wroom_esp32_appcpu_defconfig rename to boards/espressif/esp32_devkitc_wroom/esp32_devkitc_wroom_appcpu_defconfig diff --git a/boards/espressif/esp32_devkitc_wroom/esp32_devkitc_wroom_esp32_procpu.dts b/boards/espressif/esp32_devkitc_wroom/esp32_devkitc_wroom_procpu.dts similarity index 100% rename from boards/espressif/esp32_devkitc_wroom/esp32_devkitc_wroom_esp32_procpu.dts rename to boards/espressif/esp32_devkitc_wroom/esp32_devkitc_wroom_procpu.dts diff --git a/boards/espressif/esp32_devkitc_wroom/esp32_devkitc_wroom_esp32_procpu.yaml b/boards/espressif/esp32_devkitc_wroom/esp32_devkitc_wroom_procpu.yaml similarity index 100% rename from boards/espressif/esp32_devkitc_wroom/esp32_devkitc_wroom_esp32_procpu.yaml rename to boards/espressif/esp32_devkitc_wroom/esp32_devkitc_wroom_procpu.yaml diff --git a/boards/espressif/esp32_devkitc_wroom/esp32_devkitc_wroom_esp32_procpu_defconfig b/boards/espressif/esp32_devkitc_wroom/esp32_devkitc_wroom_procpu_defconfig similarity index 100% rename from boards/espressif/esp32_devkitc_wroom/esp32_devkitc_wroom_esp32_procpu_defconfig rename to boards/espressif/esp32_devkitc_wroom/esp32_devkitc_wroom_procpu_defconfig diff --git a/boards/espressif/esp32_devkitc_wrover/esp32_devkitc_wrover_esp32_appcpu.dts b/boards/espressif/esp32_devkitc_wrover/esp32_devkitc_wrover_appcpu.dts similarity index 100% rename from boards/espressif/esp32_devkitc_wrover/esp32_devkitc_wrover_esp32_appcpu.dts rename to boards/espressif/esp32_devkitc_wrover/esp32_devkitc_wrover_appcpu.dts diff --git a/boards/espressif/esp32_devkitc_wrover/esp32_devkitc_wrover_appcpu.yaml b/boards/espressif/esp32_devkitc_wrover/esp32_devkitc_wrover_appcpu.yaml new file mode 100644 index 00000000000..04082823801 --- /dev/null +++ b/boards/espressif/esp32_devkitc_wrover/esp32_devkitc_wrover_appcpu.yaml @@ -0,0 +1,27 @@ +identifier: esp32_devkitc_wrover/esp32/appcpu +name: ESP32-DevkitC-WROVER-E 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/espressif/esp32_devkitc_wrover/esp32_devkitc_wrover_esp32_appcpu_defconfig b/boards/espressif/esp32_devkitc_wrover/esp32_devkitc_wrover_appcpu_defconfig similarity index 100% rename from boards/espressif/esp32_devkitc_wrover/esp32_devkitc_wrover_esp32_appcpu_defconfig rename to boards/espressif/esp32_devkitc_wrover/esp32_devkitc_wrover_appcpu_defconfig diff --git a/boards/espressif/esp32_devkitc_wrover/esp32_devkitc_wrover_esp32_appcpu.yaml b/boards/espressif/esp32_devkitc_wrover/esp32_devkitc_wrover_esp32_appcpu.yaml deleted file mode 100644 index 8c8e8ae1577..00000000000 --- a/boards/espressif/esp32_devkitc_wrover/esp32_devkitc_wrover_esp32_appcpu.yaml +++ /dev/null @@ -1,27 +0,0 @@ -identifier: esp32_devkitc_wrover/esp32/appcpu -name: ESP32-DevkitC-WROVER-E -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/espressif/esp32_devkitc_wrover/esp32_devkitc_wrover_esp32_procpu.yaml b/boards/espressif/esp32_devkitc_wrover/esp32_devkitc_wrover_esp32_procpu.yaml deleted file mode 100644 index bf130d7d3a8..00000000000 --- a/boards/espressif/esp32_devkitc_wrover/esp32_devkitc_wrover_esp32_procpu.yaml +++ /dev/null @@ -1,25 +0,0 @@ -identifier: esp32_devkitc_wrover/esp32/procpu -name: ESP32-DevkitC-WROVER-E -type: mcu -arch: xtensa -toolchain: - - zephyr -supported: - - adc - - dac - - gpio - - i2c - - watchdog - - uart - - nvs - - pwm - - dac - - spi - - counter - - entropy - - input -testing: - ignore_tags: - - net - - bluetooth -vendor: espressif diff --git a/boards/espressif/esp32_devkitc_wrover/esp32_devkitc_wrover_esp32_procpu.dts b/boards/espressif/esp32_devkitc_wrover/esp32_devkitc_wrover_procpu.dts similarity index 100% rename from boards/espressif/esp32_devkitc_wrover/esp32_devkitc_wrover_esp32_procpu.dts rename to boards/espressif/esp32_devkitc_wrover/esp32_devkitc_wrover_procpu.dts diff --git a/boards/espressif/esp32_devkitc_wrover/esp32_devkitc_wrover_procpu.yaml b/boards/espressif/esp32_devkitc_wrover/esp32_devkitc_wrover_procpu.yaml new file mode 100644 index 00000000000..a2089253a3c --- /dev/null +++ b/boards/espressif/esp32_devkitc_wrover/esp32_devkitc_wrover_procpu.yaml @@ -0,0 +1,25 @@ +identifier: esp32_devkitc_wrover/esp32/procpu +name: ESP32-DevkitC-WROVER-E PROCPU +type: mcu +arch: xtensa +toolchain: + - zephyr +supported: + - adc + - dac + - gpio + - i2c + - watchdog + - uart + - nvs + - pwm + - dac + - spi + - counter + - entropy + - input +testing: + ignore_tags: + - net + - bluetooth +vendor: espressif diff --git a/boards/espressif/esp32_devkitc_wrover/esp32_devkitc_wrover_esp32_procpu_defconfig b/boards/espressif/esp32_devkitc_wrover/esp32_devkitc_wrover_procpu_defconfig similarity index 100% rename from boards/espressif/esp32_devkitc_wrover/esp32_devkitc_wrover_esp32_procpu_defconfig rename to boards/espressif/esp32_devkitc_wrover/esp32_devkitc_wrover_procpu_defconfig diff --git a/boards/espressif/esp32_ethernet_kit/esp32_ethernet_kit_esp32_appcpu.dts b/boards/espressif/esp32_ethernet_kit/esp32_ethernet_kit_appcpu.dts similarity index 100% rename from boards/espressif/esp32_ethernet_kit/esp32_ethernet_kit_esp32_appcpu.dts rename to boards/espressif/esp32_ethernet_kit/esp32_ethernet_kit_appcpu.dts diff --git a/boards/espressif/esp32_ethernet_kit/esp32_ethernet_kit_appcpu.yaml b/boards/espressif/esp32_ethernet_kit/esp32_ethernet_kit_appcpu.yaml new file mode 100644 index 00000000000..7f2f067d72c --- /dev/null +++ b/boards/espressif/esp32_ethernet_kit/esp32_ethernet_kit_appcpu.yaml @@ -0,0 +1,27 @@ +identifier: esp32_ethernet_kit/esp32/appcpu +name: ESP32 ETHERNET KIT 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/espressif/esp32_ethernet_kit/esp32_ethernet_kit_esp32_appcpu_defconfig b/boards/espressif/esp32_ethernet_kit/esp32_ethernet_kit_appcpu_defconfig similarity index 100% rename from boards/espressif/esp32_ethernet_kit/esp32_ethernet_kit_esp32_appcpu_defconfig rename to boards/espressif/esp32_ethernet_kit/esp32_ethernet_kit_appcpu_defconfig diff --git a/boards/espressif/esp32_ethernet_kit/esp32_ethernet_kit_esp32_appcpu.yaml b/boards/espressif/esp32_ethernet_kit/esp32_ethernet_kit_esp32_appcpu.yaml deleted file mode 100644 index 1984dea8da3..00000000000 --- a/boards/espressif/esp32_ethernet_kit/esp32_ethernet_kit_esp32_appcpu.yaml +++ /dev/null @@ -1,27 +0,0 @@ -identifier: esp32_ethernet_kit/esp32/appcpu -name: ESP32 ETHERNET KIT -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/espressif/esp32_ethernet_kit/esp32_ethernet_kit_esp32_procpu.yaml b/boards/espressif/esp32_ethernet_kit/esp32_ethernet_kit_esp32_procpu.yaml deleted file mode 100644 index d7d4958d2e7..00000000000 --- a/boards/espressif/esp32_ethernet_kit/esp32_ethernet_kit_esp32_procpu.yaml +++ /dev/null @@ -1,17 +0,0 @@ -identifier: esp32_ethernet_kit/esp32/procpu -name: ESP32 ETHERNET KIT -type: mcu -arch: xtensa -toolchain: - - zephyr -supported: - - gpio - - watchdog - - uart - - nvs - - pwm -testing: - ignore_tags: - - net - - bluetooth -vendor: espressif diff --git a/boards/espressif/esp32_ethernet_kit/esp32_ethernet_kit_esp32_procpu.dts b/boards/espressif/esp32_ethernet_kit/esp32_ethernet_kit_procpu.dts similarity index 100% rename from boards/espressif/esp32_ethernet_kit/esp32_ethernet_kit_esp32_procpu.dts rename to boards/espressif/esp32_ethernet_kit/esp32_ethernet_kit_procpu.dts diff --git a/boards/espressif/esp32_ethernet_kit/esp32_ethernet_kit_procpu.yaml b/boards/espressif/esp32_ethernet_kit/esp32_ethernet_kit_procpu.yaml new file mode 100644 index 00000000000..ca098c1ef77 --- /dev/null +++ b/boards/espressif/esp32_ethernet_kit/esp32_ethernet_kit_procpu.yaml @@ -0,0 +1,17 @@ +identifier: esp32_ethernet_kit/esp32/procpu +name: ESP32 ETHERNET KIT PROCPU +type: mcu +arch: xtensa +toolchain: + - zephyr +supported: + - gpio + - watchdog + - uart + - nvs + - pwm +testing: + ignore_tags: + - net + - bluetooth +vendor: espressif diff --git a/boards/espressif/esp32_ethernet_kit/esp32_ethernet_kit_esp32_procpu_defconfig b/boards/espressif/esp32_ethernet_kit/esp32_ethernet_kit_procpu_defconfig similarity index 100% rename from boards/espressif/esp32_ethernet_kit/esp32_ethernet_kit_esp32_procpu_defconfig rename to boards/espressif/esp32_ethernet_kit/esp32_ethernet_kit_procpu_defconfig diff --git a/boards/espressif/esp32c3_devkitm/esp32c3_devkitm.dts b/boards/espressif/esp32c3_devkitm/esp32c3_devkitm.dts index e636089ba03..f1d9481a8b7 100644 --- a/boards/espressif/esp32c3_devkitm/esp32c3_devkitm.dts +++ b/boards/espressif/esp32c3_devkitm/esp32c3_devkitm.dts @@ -94,7 +94,6 @@ status = "disabled"; pinctrl-0 = <&twai_default>; pinctrl-names = "default"; - bus-speed = <125000>; }; &flash0 { diff --git a/boards/espressif/esp32s2_devkitc/esp32s2_devkitc.dts b/boards/espressif/esp32s2_devkitc/esp32s2_devkitc.dts index 25b1c599c57..f8282767d22 100644 --- a/boards/espressif/esp32s2_devkitc/esp32s2_devkitc.dts +++ b/boards/espressif/esp32s2_devkitc/esp32s2_devkitc.dts @@ -163,3 +163,7 @@ &wdt0 { status = "okay"; }; + +&dac { + status = "okay"; +}; diff --git a/boards/espressif/esp32s3_devkitc/esp32s3_devkitc_esp32s3_appcpu.dts b/boards/espressif/esp32s3_devkitc/esp32s3_devkitc_appcpu.dts similarity index 100% rename from boards/espressif/esp32s3_devkitc/esp32s3_devkitc_esp32s3_appcpu.dts rename to boards/espressif/esp32s3_devkitc/esp32s3_devkitc_appcpu.dts diff --git a/boards/espressif/esp32s3_devkitc/esp32s3_devkitc_esp32s3_appcpu.yaml b/boards/espressif/esp32s3_devkitc/esp32s3_devkitc_appcpu.yaml similarity index 100% rename from boards/espressif/esp32s3_devkitc/esp32s3_devkitc_esp32s3_appcpu.yaml rename to boards/espressif/esp32s3_devkitc/esp32s3_devkitc_appcpu.yaml diff --git a/boards/espressif/esp32s3_devkitc/esp32s3_devkitc_esp32s3_appcpu_defconfig b/boards/espressif/esp32s3_devkitc/esp32s3_devkitc_appcpu_defconfig similarity index 100% rename from boards/espressif/esp32s3_devkitc/esp32s3_devkitc_esp32s3_appcpu_defconfig rename to boards/espressif/esp32s3_devkitc/esp32s3_devkitc_appcpu_defconfig diff --git a/boards/espressif/esp32s3_devkitc/esp32s3_devkitc_esp32s3_procpu.dts b/boards/espressif/esp32s3_devkitc/esp32s3_devkitc_esp32s3_procpu.dts deleted file mode 100644 index 253731fc721..00000000000 --- a/boards/espressif/esp32s3_devkitc/esp32s3_devkitc_esp32s3_procpu.dts +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Copyright (c) 2024 Espressif Systems (Shanghai) Co., Ltd. - * - * SPDX-License-Identifier: Apache-2.0 - */ -/dts-v1/; - -#include "espressif/esp32s3/esp32s3_wroom_n8.dtsi" -#include "esp32s3_devkitc-pinctrl.dtsi" -#include -#include - -/ { - model = "Espressif ESP32S3-DevkitC PROCPU"; - compatible = "espressif,esp32s3"; - - aliases { - i2c-0 = &i2c0; - watchdog0 = &wdt0; - }; - - chosen { - zephyr,sram = &sram0; - zephyr,console = &uart0; - zephyr,shell-uart = &uart0; - zephyr,flash = &flash0; - zephyr,code-partition = &slot0_partition; - }; - - aliases { - uart-0 = &uart0; - sw0 = &button0; - }; - - buttons { - compatible = "gpio-keys"; - button0: button_0 { - gpios = <&gpio0 0 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; - label = "BOOT Button"; - zephyr,code = ; - }; - }; -}; - -&cpu0 { - clock-frequency = ; -}; - -&cpu1 { - clock-frequency = ; -}; - -&usb_serial { - status = "disabled"; -}; - -&uart0 { - status = "okay"; - current-speed = <115200>; - pinctrl-0 = <&uart0_default>; - pinctrl-names = "default"; -}; - -&gpio0 { - status = "okay"; -}; - -&gpio1 { - 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>; - pinctrl-names = "default"; -}; - -&i2c1 { - clock-frequency = ; - pinctrl-0 = <&i2c1_default>; - pinctrl-names = "default"; -}; - -&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"; - pinctrl-0 = <&spim3_default>; - pinctrl-names = "default"; -}; - -&twai { - pinctrl-0 = <&twai_default>; - pinctrl-names = "default"; - bus-speed = <125000>; -}; - -&timer0 { - status = "disabled"; -}; - -&timer1 { - status = "disabled"; -}; - -&timer2 { - status = "disabled"; -}; - -&timer3 { - status = "disabled"; -}; - -&wdt0 { - status = "okay"; -}; - -&trng0 { - status = "okay"; -}; - -&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/espressif/esp32s3_devkitc/esp32s3_devkitc_procpu.dts b/boards/espressif/esp32s3_devkitc/esp32s3_devkitc_procpu.dts new file mode 100644 index 00000000000..4538c41fa5f --- /dev/null +++ b/boards/espressif/esp32s3_devkitc/esp32s3_devkitc_procpu.dts @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2024 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ +/dts-v1/; + +#include "espressif/esp32s3/esp32s3_wroom_n8.dtsi" +#include "esp32s3_devkitc-pinctrl.dtsi" +#include +#include + +/ { + model = "Espressif ESP32S3-DevkitC PROCPU"; + compatible = "espressif,esp32s3"; + + aliases { + i2c-0 = &i2c0; + watchdog0 = &wdt0; + }; + + chosen { + zephyr,sram = &sram0; + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; + }; + + aliases { + uart-0 = &uart0; + sw0 = &button0; + }; + + buttons { + compatible = "gpio-keys"; + button0: button_0 { + gpios = <&gpio0 0 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "BOOT Button"; + zephyr,code = ; + }; + }; +}; + +&cpu0 { + clock-frequency = ; +}; + +&cpu1 { + clock-frequency = ; +}; + +&usb_serial { + status = "disabled"; +}; + +&uart0 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart0_default>; + pinctrl-names = "default"; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + 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>; + pinctrl-names = "default"; +}; + +&i2c1 { + clock-frequency = ; + pinctrl-0 = <&i2c1_default>; + pinctrl-names = "default"; +}; + +&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"; + pinctrl-0 = <&spim3_default>; + pinctrl-names = "default"; +}; + +&twai { + pinctrl-0 = <&twai_default>; + pinctrl-names = "default"; +}; + +&timer0 { + status = "disabled"; +}; + +&timer1 { + status = "disabled"; +}; + +&timer2 { + status = "disabled"; +}; + +&timer3 { + status = "disabled"; +}; + +&wdt0 { + status = "okay"; +}; + +&trng0 { + status = "okay"; +}; + +&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/espressif/esp32s3_devkitc/esp32s3_devkitc_esp32s3_procpu.yaml b/boards/espressif/esp32s3_devkitc/esp32s3_devkitc_procpu.yaml similarity index 100% rename from boards/espressif/esp32s3_devkitc/esp32s3_devkitc_esp32s3_procpu.yaml rename to boards/espressif/esp32s3_devkitc/esp32s3_devkitc_procpu.yaml diff --git a/boards/espressif/esp32s3_devkitc/esp32s3_devkitc_esp32s3_procpu_defconfig b/boards/espressif/esp32s3_devkitc/esp32s3_devkitc_procpu_defconfig similarity index 100% rename from boards/espressif/esp32s3_devkitc/esp32s3_devkitc_esp32s3_procpu_defconfig rename to boards/espressif/esp32s3_devkitc/esp32s3_devkitc_procpu_defconfig diff --git a/boards/espressif/esp32s3_devkitm/esp32s3_devkitm_esp32s3_appcpu.dts b/boards/espressif/esp32s3_devkitm/esp32s3_devkitm_appcpu.dts similarity index 100% rename from boards/espressif/esp32s3_devkitm/esp32s3_devkitm_esp32s3_appcpu.dts rename to boards/espressif/esp32s3_devkitm/esp32s3_devkitm_appcpu.dts diff --git a/boards/espressif/esp32s3_devkitm/esp32s3_devkitm_esp32s3_appcpu.yaml b/boards/espressif/esp32s3_devkitm/esp32s3_devkitm_appcpu.yaml similarity index 100% rename from boards/espressif/esp32s3_devkitm/esp32s3_devkitm_esp32s3_appcpu.yaml rename to boards/espressif/esp32s3_devkitm/esp32s3_devkitm_appcpu.yaml diff --git a/boards/espressif/esp32s3_devkitm/esp32s3_devkitm_esp32s3_appcpu_defconfig b/boards/espressif/esp32s3_devkitm/esp32s3_devkitm_appcpu_defconfig similarity index 100% rename from boards/espressif/esp32s3_devkitm/esp32s3_devkitm_esp32s3_appcpu_defconfig rename to boards/espressif/esp32s3_devkitm/esp32s3_devkitm_appcpu_defconfig diff --git a/boards/espressif/esp32s3_devkitm/esp32s3_devkitm_esp32s3_procpu.dts b/boards/espressif/esp32s3_devkitm/esp32s3_devkitm_esp32s3_procpu.dts deleted file mode 100644 index e0d4461a33b..00000000000 --- a/boards/espressif/esp32s3_devkitm/esp32s3_devkitm_esp32s3_procpu.dts +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd. - * - * SPDX-License-Identifier: Apache-2.0 - */ -/dts-v1/; - -#include -#include "esp32s3_devkitm-pinctrl.dtsi" -#include -#include - -/ { - model = "Espressif ESP32S3-DevkitM PROCPU"; - compatible = "espressif,esp32s3"; - - aliases { - i2c-0 = &i2c0; - watchdog0 = &wdt0; - }; - - chosen { - zephyr,sram = &sram0; - zephyr,console = &uart0; - zephyr,shell-uart = &uart0; - zephyr,flash = &flash0; - zephyr,code-partition = &slot0_partition; - }; - - aliases { - uart-0 = &uart0; - sw0 = &button0; - }; - - buttons { - compatible = "gpio-keys"; - button0: button_0 { - gpios = <&gpio0 0 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; - label = "BOOT Button"; - 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"; -}; - -&gpio0 { - status = "okay"; -}; - -&gpio1 { - 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>; - pinctrl-names = "default"; -}; - -&i2c1 { - clock-frequency = ; - pinctrl-0 = <&i2c1_default>; - pinctrl-names = "default"; -}; - -&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"; - pinctrl-0 = <&spim3_default>; - pinctrl-names = "default"; -}; - -&twai { - pinctrl-0 = <&twai_default>; - pinctrl-names = "default"; - bus-speed = <125000>; -}; - -&timer0 { - status = "disabled"; -}; - -&timer1 { - status = "disabled"; -}; - -&timer2 { - status = "disabled"; -}; - -&timer3 { - status = "disabled"; -}; - -&wdt0 { - status = "okay"; -}; - -&trng0 { - status = "okay"; -}; - -&usb_serial { - status = "disabled"; -}; - -&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/espressif/esp32s3_devkitm/esp32s3_devkitm_procpu.dts b/boards/espressif/esp32s3_devkitm/esp32s3_devkitm_procpu.dts new file mode 100644 index 00000000000..0cb8b962829 --- /dev/null +++ b/boards/espressif/esp32s3_devkitm/esp32s3_devkitm_procpu.dts @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ +/dts-v1/; + +#include +#include "esp32s3_devkitm-pinctrl.dtsi" +#include +#include + +/ { + model = "Espressif ESP32S3-DevkitM PROCPU"; + compatible = "espressif,esp32s3"; + + aliases { + i2c-0 = &i2c0; + watchdog0 = &wdt0; + }; + + chosen { + zephyr,sram = &sram0; + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; + }; + + aliases { + uart-0 = &uart0; + sw0 = &button0; + }; + + buttons { + compatible = "gpio-keys"; + button0: button_0 { + gpios = <&gpio0 0 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "BOOT Button"; + 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"; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + 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>; + pinctrl-names = "default"; +}; + +&i2c1 { + clock-frequency = ; + pinctrl-0 = <&i2c1_default>; + pinctrl-names = "default"; +}; + +&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"; + pinctrl-0 = <&spim3_default>; + pinctrl-names = "default"; +}; + +&twai { + pinctrl-0 = <&twai_default>; + pinctrl-names = "default"; +}; + +&timer0 { + status = "disabled"; +}; + +&timer1 { + status = "disabled"; +}; + +&timer2 { + status = "disabled"; +}; + +&timer3 { + status = "disabled"; +}; + +&wdt0 { + status = "okay"; +}; + +&trng0 { + status = "okay"; +}; + +&usb_serial { + status = "disabled"; +}; + +&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/espressif/esp32s3_devkitm/esp32s3_devkitm_esp32s3_procpu.yaml b/boards/espressif/esp32s3_devkitm/esp32s3_devkitm_procpu.yaml similarity index 100% rename from boards/espressif/esp32s3_devkitm/esp32s3_devkitm_esp32s3_procpu.yaml rename to boards/espressif/esp32s3_devkitm/esp32s3_devkitm_procpu.yaml diff --git a/boards/espressif/esp32s3_devkitm/esp32s3_devkitm_esp32s3_procpu_defconfig b/boards/espressif/esp32s3_devkitm/esp32s3_devkitm_procpu_defconfig similarity index 100% rename from boards/espressif/esp32s3_devkitm/esp32s3_devkitm_esp32s3_procpu_defconfig rename to boards/espressif/esp32s3_devkitm/esp32s3_devkitm_procpu_defconfig diff --git a/boards/espressif/esp_wrover_kit/esp_wrover_kit-pinctrl.dtsi b/boards/espressif/esp_wrover_kit/esp_wrover_kit-pinctrl.dtsi index 07ef6d2cda1..aee93f0eb67 100644 --- a/boards/espressif/esp_wrover_kit/esp_wrover_kit-pinctrl.dtsi +++ b/boards/espressif/esp_wrover_kit/esp_wrover_kit-pinctrl.dtsi @@ -64,4 +64,11 @@ }; }; + sdhc0_default: sdhc0_default { + group1 { + pinmux = ; + bias-pull-up; + output-high; + }; + }; }; diff --git a/boards/espressif/esp_wrover_kit/esp_wrover_kit_esp32_appcpu.dts b/boards/espressif/esp_wrover_kit/esp_wrover_kit_appcpu.dts similarity index 100% rename from boards/espressif/esp_wrover_kit/esp_wrover_kit_esp32_appcpu.dts rename to boards/espressif/esp_wrover_kit/esp_wrover_kit_appcpu.dts diff --git a/boards/espressif/esp_wrover_kit/esp_wrover_kit_appcpu.yaml b/boards/espressif/esp_wrover_kit/esp_wrover_kit_appcpu.yaml new file mode 100644 index 00000000000..57971b3571c --- /dev/null +++ b/boards/espressif/esp_wrover_kit/esp_wrover_kit_appcpu.yaml @@ -0,0 +1,27 @@ +identifier: esp_wrover_kit/esp32/appcpu +name: ESP WROVER KIT 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/espressif/esp_wrover_kit/esp_wrover_kit_esp32_appcpu_defconfig b/boards/espressif/esp_wrover_kit/esp_wrover_kit_appcpu_defconfig similarity index 100% rename from boards/espressif/esp_wrover_kit/esp_wrover_kit_esp32_appcpu_defconfig rename to boards/espressif/esp_wrover_kit/esp_wrover_kit_appcpu_defconfig diff --git a/boards/espressif/esp_wrover_kit/esp_wrover_kit_esp32_appcpu.yaml b/boards/espressif/esp_wrover_kit/esp_wrover_kit_esp32_appcpu.yaml deleted file mode 100644 index 64f7ef2124f..00000000000 --- a/boards/espressif/esp_wrover_kit/esp_wrover_kit_esp32_appcpu.yaml +++ /dev/null @@ -1,27 +0,0 @@ -identifier: esp_wrover_kit/esp32/appcpu -name: ESP WROVER KIT -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/espressif/esp_wrover_kit/esp_wrover_kit_esp32_procpu.dts b/boards/espressif/esp_wrover_kit/esp_wrover_kit_esp32_procpu.dts deleted file mode 100644 index 3709a13b475..00000000000 --- a/boards/espressif/esp_wrover_kit/esp_wrover_kit_esp32_procpu.dts +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright (c) 2021 Espressif Systems (Shanghai) Co., Ltd. - * - * SPDX-License-Identifier: Apache-2.0 - */ -/dts-v1/; - -#include -#include "esp_wrover_kit-pinctrl.dtsi" - -/ { - model = "Espressif ESP32-Wrover-Kit PROCPU"; - compatible = "espressif,esp32"; - - aliases { - led0 = &blue_led; - led1 = &green_led; - led2 = &red_led; - pwm-led0 = &pwm_led_red; - pwm-led1 = &pwm_led_green; - pwm-led2 = &pwm_led_blue; - red-pwm-led = &pwm_led_red; - green-pwm-led = &pwm_led_green; - blue-pwm-led = &pwm_led_blue; - uart-0 = &uart0; - i2c-0 = &i2c0; - watchdog0 = &wdt0; - }; - - chosen { - zephyr,sram = &sram0; - zephyr,console = &uart0; - zephyr,shell-uart = &uart0; - zephyr,flash = &flash0; - zephyr,code-partition = &slot0_partition; - zephyr,display = &ili9341; - }; - - leds { - compatible = "gpio-leds"; - - blue_led: led_0 { - gpios = <&gpio0 4 GPIO_ACTIVE_HIGH>; - label = "Blue - LED0"; - }; - - green_led: led_1 { - gpios = <&gpio0 2 GPIO_ACTIVE_HIGH>; - label = "Green - LED1"; - }; - - red_led: led_2 { - gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>; - label = "Red - LED2"; - }; - }; - - pwmleds { - compatible = "pwm-leds"; - pwm_led_red: pwm_led_0 { - label = "Red PWM LED"; - pwms = <&ledc0 0 PWM_HZ(100) PWM_POLARITY_NORMAL>; - }; - pwm_led_green: pwm_led_1 { - label = "Green PWM LED"; - pwms = <&ledc0 1 PWM_HZ(100) PWM_POLARITY_NORMAL>; - }; - pwm_led_blue: pwm_led_2 { - label = "Blue PWM LED"; - pwms = <&ledc0 2 PWM_HZ(100) PWM_POLARITY_NORMAL>; - }; - }; - - mipi_dbi { - compatible = "zephyr,mipi-dbi-spi"; - dc-gpios = <&gpio0 21 GPIO_ACTIVE_HIGH>; - reset-gpios = <&gpio0 18 GPIO_ACTIVE_LOW>; - spi-dev = <&spi3>; - write-only; - #address-cells = <1>; - #size-cells = <0>; - - ili9341: ili9341@0 { - compatible = "ilitek,ili9341"; - mipi-max-frequency = <25000000>; - reg = <0>; - pixel-format = <0>; - rotation = <0>; - width = <240>; - height = <320>; - }; - }; -}; - -&cpu0 { - clock-frequency = ; -}; - -&cpu1 { - clock-frequency = ; -}; - -&uart0 { - status = "okay"; - current-speed = <115200>; - pinctrl-0 = <&uart0_default>; - pinctrl-names = "default"; -}; - -&gpio0 { - status = "okay"; - - /* FIXME: should be part of the display node */ - lcd-backlight { - gpio-hog; - gpios = <5 GPIO_ACTIVE_HIGH>; - output-low; - }; -}; - -&gpio1 { - status = "okay"; -}; - -&i2c0 { - status = "okay"; - clock-frequency = ; - sda-gpios = <&gpio0 21 GPIO_OPEN_DRAIN>; - scl-gpios = <&gpio0 22 GPIO_OPEN_DRAIN>; - pinctrl-0 = <&i2c0_default>; - pinctrl-names = "default"; -}; - -&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"; - pinctrl-0 = <&spim3_default>; - pinctrl-names = "default"; -}; - -&ledc0 { - pinctrl-0 = <&ledc0_default>; - pinctrl-names = "default"; - status = "okay"; - #address-cells = <1>; - #size-cells = <0>; - channel0@0 { - reg = <0x0>; - timer = <0>; - }; - channel1@1 { - reg = <0x1>; - timer = <1>; - }; - channel2@2 { - reg = <0x2>; - timer = <2>; - }; -}; - -&timer0 { - status = "okay"; -}; - -&timer1 { - status = "okay"; -}; - -&timer2 { - status = "okay"; -}; - -&timer3 { - status = "okay"; -}; - -&trng0 { - status = "okay"; -}; - -&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/espressif/esp_wrover_kit/esp_wrover_kit_esp32_procpu.yaml b/boards/espressif/esp_wrover_kit/esp_wrover_kit_esp32_procpu.yaml deleted file mode 100644 index 80c6a5d3983..00000000000 --- a/boards/espressif/esp_wrover_kit/esp_wrover_kit_esp32_procpu.yaml +++ /dev/null @@ -1,23 +0,0 @@ -identifier: esp_wrover_kit/esp32/procpu -name: ESP WROVER KIT -type: mcu -arch: xtensa -toolchain: - - zephyr -supported: - - adc - - dac - - gpio - - i2c - - watchdog - - uart - - nvs - - pwm - - spi - - counter - - entropy -testing: - ignore_tags: - - net - - bluetooth -vendor: espressif diff --git a/boards/espressif/esp_wrover_kit/esp_wrover_kit_procpu.dts b/boards/espressif/esp_wrover_kit/esp_wrover_kit_procpu.dts new file mode 100644 index 00000000000..ac0bacd604c --- /dev/null +++ b/boards/espressif/esp_wrover_kit/esp_wrover_kit_procpu.dts @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2021 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ +/dts-v1/; + +#include +#include "esp_wrover_kit-pinctrl.dtsi" + +/ { + model = "Espressif ESP32-Wrover-Kit PROCPU"; + compatible = "espressif,esp32"; + + aliases { + led0 = &blue_led; + led1 = &green_led; + led2 = &red_led; + pwm-led0 = &pwm_led_red; + pwm-led1 = &pwm_led_green; + pwm-led2 = &pwm_led_blue; + red-pwm-led = &pwm_led_red; + green-pwm-led = &pwm_led_green; + blue-pwm-led = &pwm_led_blue; + uart-0 = &uart0; + i2c-0 = &i2c0; + watchdog0 = &wdt0; + sdhc0 = &sdhc1; + }; + + chosen { + zephyr,sram = &sram0; + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; + zephyr,display = &ili9341; + zephyr,sdhc = &sdhc1; + }; + + leds { + compatible = "gpio-leds"; + + blue_led: led_0 { + gpios = <&gpio0 4 GPIO_ACTIVE_HIGH>; + label = "Blue - LED0"; + }; + + green_led: led_1 { + gpios = <&gpio0 2 GPIO_ACTIVE_HIGH>; + label = "Green - LED1"; + }; + + red_led: led_2 { + gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>; + label = "Red - LED2"; + }; + }; + + pwmleds { + compatible = "pwm-leds"; + pwm_led_red: pwm_led_0 { + label = "Red PWM LED"; + pwms = <&ledc0 0 PWM_HZ(100) PWM_POLARITY_NORMAL>; + }; + pwm_led_green: pwm_led_1 { + label = "Green PWM LED"; + pwms = <&ledc0 1 PWM_HZ(100) PWM_POLARITY_NORMAL>; + }; + pwm_led_blue: pwm_led_2 { + label = "Blue PWM LED"; + pwms = <&ledc0 2 PWM_HZ(100) PWM_POLARITY_NORMAL>; + }; + }; + + mipi_dbi { + compatible = "zephyr,mipi-dbi-spi"; + dc-gpios = <&gpio0 21 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpio0 18 GPIO_ACTIVE_LOW>; + spi-dev = <&spi3>; + write-only; + #address-cells = <1>; + #size-cells = <0>; + + ili9341: ili9341@0 { + compatible = "ilitek,ili9341"; + mipi-max-frequency = <25000000>; + reg = <0>; + pixel-format = <0>; + rotation = <0>; + width = <240>; + height = <320>; + }; + }; +}; + +&cpu0 { + clock-frequency = ; +}; + +&cpu1 { + clock-frequency = ; +}; + +&uart0 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart0_default>; + pinctrl-names = "default"; +}; + +&gpio0 { + status = "okay"; + + /* FIXME: should be part of the display node */ + lcd-backlight { + gpio-hog; + gpios = <5 GPIO_ACTIVE_HIGH>; + output-low; + }; +}; + +&gpio1 { + status = "okay"; +}; + +&i2c0 { + status = "okay"; + clock-frequency = ; + sda-gpios = <&gpio0 21 GPIO_OPEN_DRAIN>; + scl-gpios = <&gpio0 22 GPIO_OPEN_DRAIN>; + pinctrl-0 = <&i2c0_default>; + pinctrl-names = "default"; +}; + +&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"; + pinctrl-0 = <&spim3_default>; + pinctrl-names = "default"; +}; + +&ledc0 { + pinctrl-0 = <&ledc0_default>; + pinctrl-names = "default"; + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + channel0@0 { + reg = <0x0>; + timer = <0>; + }; + channel1@1 { + reg = <0x1>; + timer = <1>; + }; + channel2@2 { + reg = <0x2>; + timer = <2>; + }; +}; + +&timer0 { + status = "okay"; +}; + +&timer1 { + status = "okay"; +}; + +&timer2 { + status = "okay"; +}; + +&timer3 { + status = "okay"; +}; + +&trng0 { + status = "okay"; +}; + +&sdhc { + sdhc1: sdhc@1 { + status = "okay"; + + pinctrl-0 = <&sdhc0_default>; + pinctrl-names = "default"; + power-delay-ms = <100>; + max-bus-freq = <52000000>; + bus-width = <4>; + + clk-pin = <14>; + cmd-pin = <15>; + d0-pin = <2>; + d1-pin = <4>; + d2-pin = <12>; + d3-pin = <13>; + + mmc { + compatible = "zephyr,sdmmc-disk"; + status = "okay"; + }; + }; +}; + +&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/espressif/esp_wrover_kit/esp_wrover_kit_procpu.yaml b/boards/espressif/esp_wrover_kit/esp_wrover_kit_procpu.yaml new file mode 100644 index 00000000000..d316dd1b8d0 --- /dev/null +++ b/boards/espressif/esp_wrover_kit/esp_wrover_kit_procpu.yaml @@ -0,0 +1,24 @@ +identifier: esp_wrover_kit/esp32/procpu +name: ESP WROVER KIT PROCPU +type: mcu +arch: xtensa +toolchain: + - zephyr +supported: + - adc + - dac + - gpio + - i2c + - watchdog + - uart + - nvs + - pwm + - sdhc + - spi + - counter + - entropy +testing: + ignore_tags: + - net + - bluetooth +vendor: espressif diff --git a/boards/espressif/esp_wrover_kit/esp_wrover_kit_esp32_procpu_defconfig b/boards/espressif/esp_wrover_kit/esp_wrover_kit_procpu_defconfig similarity index 100% rename from boards/espressif/esp_wrover_kit/esp_wrover_kit_esp32_procpu_defconfig rename to boards/espressif/esp_wrover_kit/esp_wrover_kit_procpu_defconfig diff --git a/boards/hardkernel/odroid_go/odroid_go_esp32_appcpu.dts b/boards/hardkernel/odroid_go/odroid_go_appcpu.dts similarity index 100% rename from boards/hardkernel/odroid_go/odroid_go_esp32_appcpu.dts rename to boards/hardkernel/odroid_go/odroid_go_appcpu.dts diff --git a/boards/hardkernel/odroid_go/odroid_go_appcpu.yaml b/boards/hardkernel/odroid_go/odroid_go_appcpu.yaml new file mode 100644 index 00000000000..946166f95b4 --- /dev/null +++ b/boards/hardkernel/odroid_go/odroid_go_appcpu.yaml @@ -0,0 +1,27 @@ +identifier: odroid_go/esp32/appcpu +name: ODROID-GO 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: hardkernel diff --git a/boards/hardkernel/odroid_go/odroid_go_esp32_appcpu_defconfig b/boards/hardkernel/odroid_go/odroid_go_appcpu_defconfig similarity index 100% rename from boards/hardkernel/odroid_go/odroid_go_esp32_appcpu_defconfig rename to boards/hardkernel/odroid_go/odroid_go_appcpu_defconfig diff --git a/boards/hardkernel/odroid_go/odroid_go_esp32_appcpu.yaml b/boards/hardkernel/odroid_go/odroid_go_esp32_appcpu.yaml deleted file mode 100644 index a5a1c003ef3..00000000000 --- a/boards/hardkernel/odroid_go/odroid_go_esp32_appcpu.yaml +++ /dev/null @@ -1,27 +0,0 @@ -identifier: odroid_go/esp32/appcpu -name: ODROID-GO -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: hardkernel diff --git a/boards/hardkernel/odroid_go/odroid_go_esp32_procpu.dts b/boards/hardkernel/odroid_go/odroid_go_esp32_procpu.dts deleted file mode 100644 index caf722d8cc9..00000000000 --- a/boards/hardkernel/odroid_go/odroid_go_esp32_procpu.dts +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Copyright (c) 2019 Yannis Damigos - * - * SPDX-License-Identifier: Apache-2.0 - */ -/dts-v1/; - -#include -#include "odroid_go-pinctrl.dtsi" -#include - -/ { - model = "ODROID-GO Game Kit PROCPU"; - compatible = "hardkernel,odroid_go", "espressif,esp32"; - - chosen { - zephyr,sram = &sram0; - zephyr,console = &uart0; - zephyr,shell-uart = &uart0; - zephyr,flash = &flash0; - zephyr,code-partition = &slot0_partition; - zephyr,display = &ili9341; - }; - - leds { - compatible = "gpio-leds"; - blue_led: led { - gpios = <&gpio0 2 GPIO_ACTIVE_HIGH>; - label = "Status Led"; - }; - }; - - gpio_keys { - compatible = "gpio-keys"; - menu_button: menu_button { - label = "Menu"; - gpios = <&gpio0 13 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; - zephyr,code = ; - }; - volume_button: volume_button { - label = "Volume"; - gpios = <&gpio0 0 GPIO_ACTIVE_LOW>; - zephyr,code = ; - }; - select_button: select_button { - label = "Select"; - gpios = <&gpio0 27 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; - zephyr,code = ; - }; - a_button: a_button { - label = "A"; - gpios = <&gpio1 0 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; - zephyr,code = ; - }; - b_button: b_button { - label = "B"; - gpios = <&gpio1 1 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; - zephyr,code = ; - }; - start_button: start_button { - label = "Start"; - gpios = <&gpio1 7 GPIO_ACTIVE_LOW>; - zephyr,code = ; - }; - }; - - lcd_backlight_en { - compatible = "regulator-fixed"; - regulator-name = "lcd_backlight_enable"; - enable-gpios = <&gpio0 14 GPIO_ACTIVE_HIGH>; - regulator-boot-on; - }; - - aliases { - uart-0 = &uart0; - led0 = &blue_led; - sw0 = &menu_button; - watchdog0 = &wdt0; - }; - - mipi_dbi { - compatible = "zephyr,mipi-dbi-spi"; - dc-gpios = <&gpio0 21 GPIO_ACTIVE_HIGH>; - spi-dev = <&spi3>; - write-only; - #address-cells = <1>; - #size-cells = <0>; - - ili9341: ili9341@0 { - compatible = "ilitek,ili9341"; - mipi-max-frequency = <25000000>; - pixel-format = <0>; - reg = <0>; - rotation = <270>; - width = <320>; - height = <240>; - }; - }; -}; - -&cpu0 { - clock-frequency = ; -}; - -&cpu1 { - clock-frequency = ; -}; - -&uart0 { - status = "okay"; - current-speed = <115200>; - pinctrl-0 = <&uart0_default>; - pinctrl-names = "default"; -}; - -&gpio0 { - status = "okay"; - - blue-led-disable { - gpio-hog; - gpios = <2 GPIO_ACTIVE_HIGH>; - output-low; - }; -}; - -&gpio1 { - status = "okay"; -}; - -&i2c0 { - status = "okay"; - clock-frequency = ; - sda-gpios = <&gpio0 4 GPIO_OPEN_DRAIN>; - scl-gpios = <&gpio0 15 GPIO_OPEN_DRAIN>; - pinctrl-0 = <&i2c0_default>; - pinctrl-names = "default"; -}; - -&spi3 { - #address-cells = <1>; - #size-cells = <0>; - status = "okay"; - pinctrl-0 = <&spim3_default>; - pinctrl-names = "default"; - - sdhc0: sdhc@1 { - compatible = "zephyr,sdhc-spi-slot"; - reg = <1>; - status = "okay"; - mmc { - compatible = "zephyr,sdmmc-disk"; - status = "okay"; - }; - spi-max-frequency = <20000000>; - }; -}; - -&timer0 { - status = "okay"; -}; - -&timer1 { - status = "okay"; -}; - -&timer2 { - status = "okay"; -}; - -&timer3 { - status = "okay"; -}; - -&trng0 { - status = "okay"; -}; - -&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/hardkernel/odroid_go/odroid_go_esp32_procpu.yaml b/boards/hardkernel/odroid_go/odroid_go_esp32_procpu.yaml deleted file mode 100644 index 59363bb4ee9..00000000000 --- a/boards/hardkernel/odroid_go/odroid_go_esp32_procpu.yaml +++ /dev/null @@ -1,18 +0,0 @@ -identifier: odroid_go/esp32/procpu -name: ODROID-GO -type: mcu -arch: xtensa -toolchain: - - zephyr -supported: - - gpio - - i2c - - spi - - watchdog - - uart - - nvs -testing: - ignore_tags: - - net - - bluetooth -vendor: hardkernel diff --git a/boards/hardkernel/odroid_go/odroid_go_procpu.dts b/boards/hardkernel/odroid_go/odroid_go_procpu.dts new file mode 100644 index 00000000000..c17c25823e2 --- /dev/null +++ b/boards/hardkernel/odroid_go/odroid_go_procpu.dts @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2019 Yannis Damigos + * + * SPDX-License-Identifier: Apache-2.0 + */ +/dts-v1/; + +#include +#include "odroid_go-pinctrl.dtsi" +#include + +/ { + model = "ODROID-GO Game Kit PROCPU"; + compatible = "hardkernel,odroid_go", "espressif,esp32"; + + chosen { + zephyr,sram = &sram0; + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; + zephyr,display = &ili9341; + }; + + leds { + compatible = "gpio-leds"; + blue_led: led { + gpios = <&gpio0 2 GPIO_ACTIVE_HIGH>; + label = "Status Led"; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + menu_button: menu_button { + label = "Menu"; + gpios = <&gpio0 13 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + zephyr,code = ; + }; + volume_button: volume_button { + label = "Volume"; + gpios = <&gpio0 0 GPIO_ACTIVE_LOW>; + zephyr,code = ; + }; + select_button: select_button { + label = "Select"; + gpios = <&gpio0 27 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + zephyr,code = ; + }; + a_button: a_button { + label = "A"; + gpios = <&gpio1 0 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + zephyr,code = ; + }; + b_button: b_button { + label = "B"; + gpios = <&gpio1 1 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + zephyr,code = ; + }; + start_button: start_button { + label = "Start"; + gpios = <&gpio1 7 GPIO_ACTIVE_LOW>; + zephyr,code = ; + }; + }; + + lcd_backlight_en { + compatible = "regulator-fixed"; + regulator-name = "lcd_backlight_enable"; + enable-gpios = <&gpio0 14 GPIO_ACTIVE_HIGH>; + regulator-boot-on; + }; + + aliases { + uart-0 = &uart0; + led0 = &blue_led; + sw0 = &menu_button; + watchdog0 = &wdt0; + sdhc0 = &sd0; + }; + + mipi_dbi { + compatible = "zephyr,mipi-dbi-spi"; + dc-gpios = <&gpio0 21 GPIO_ACTIVE_HIGH>; + spi-dev = <&spi3>; + write-only; + #address-cells = <1>; + #size-cells = <0>; + + ili9341: ili9341@0 { + compatible = "ilitek,ili9341"; + mipi-max-frequency = <25000000>; + pixel-format = <0>; + reg = <0>; + rotation = <270>; + width = <320>; + height = <240>; + }; + }; +}; + +&cpu0 { + clock-frequency = ; +}; + +&cpu1 { + clock-frequency = ; +}; + +&uart0 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart0_default>; + pinctrl-names = "default"; +}; + +&gpio0 { + status = "okay"; + + blue-led-disable { + gpio-hog; + gpios = <2 GPIO_ACTIVE_HIGH>; + output-low; + }; +}; + +&gpio1 { + status = "okay"; +}; + +&i2c0 { + status = "okay"; + clock-frequency = ; + sda-gpios = <&gpio0 4 GPIO_OPEN_DRAIN>; + scl-gpios = <&gpio0 15 GPIO_OPEN_DRAIN>; + pinctrl-0 = <&i2c0_default>; + pinctrl-names = "default"; +}; + +&spi3 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + pinctrl-0 = <&spim3_default>; + pinctrl-names = "default"; + + sd0: sd@1 { + compatible = "zephyr,sdhc-spi-slot"; + reg = <1>; + status = "okay"; + mmc { + compatible = "zephyr,sdmmc-disk"; + status = "okay"; + }; + spi-max-frequency = <20000000>; + }; +}; + +&timer0 { + status = "okay"; +}; + +&timer1 { + status = "okay"; +}; + +&timer2 { + status = "okay"; +}; + +&timer3 { + status = "okay"; +}; + +&trng0 { + status = "okay"; +}; + +&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/hardkernel/odroid_go/odroid_go_procpu.yaml b/boards/hardkernel/odroid_go/odroid_go_procpu.yaml new file mode 100644 index 00000000000..f2eafb52676 --- /dev/null +++ b/boards/hardkernel/odroid_go/odroid_go_procpu.yaml @@ -0,0 +1,18 @@ +identifier: odroid_go/esp32/procpu +name: ODROID-GO PROCPU +type: mcu +arch: xtensa +toolchain: + - zephyr +supported: + - gpio + - i2c + - spi + - watchdog + - uart + - nvs +testing: + ignore_tags: + - net + - bluetooth +vendor: hardkernel diff --git a/boards/hardkernel/odroid_go/odroid_go_esp32_procpu_defconfig b/boards/hardkernel/odroid_go/odroid_go_procpu_defconfig similarity index 100% rename from boards/hardkernel/odroid_go/odroid_go_esp32_procpu_defconfig rename to boards/hardkernel/odroid_go/odroid_go_procpu_defconfig diff --git a/boards/heltec/heltec_wifi_lora32_v2/heltec_wifi_lora32_v2_esp32_appcpu.dts b/boards/heltec/heltec_wifi_lora32_v2/heltec_wifi_lora32_v2_appcpu.dts similarity index 100% rename from boards/heltec/heltec_wifi_lora32_v2/heltec_wifi_lora32_v2_esp32_appcpu.dts rename to boards/heltec/heltec_wifi_lora32_v2/heltec_wifi_lora32_v2_appcpu.dts diff --git a/boards/heltec/heltec_wifi_lora32_v2/heltec_wifi_lora32_v2_appcpu.yaml b/boards/heltec/heltec_wifi_lora32_v2/heltec_wifi_lora32_v2_appcpu.yaml new file mode 100644 index 00000000000..d838e27766e --- /dev/null +++ b/boards/heltec/heltec_wifi_lora32_v2/heltec_wifi_lora32_v2_appcpu.yaml @@ -0,0 +1,27 @@ +identifier: heltec_wifi_lora32_v2/esp32/appcpu +name: HELTEC WiFi LoRa 32 (V2) Board 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/heltec/heltec_wifi_lora32_v2/heltec_wifi_lora32_v2_esp32_appcpu_defconfig b/boards/heltec/heltec_wifi_lora32_v2/heltec_wifi_lora32_v2_appcpu_defconfig similarity index 100% rename from boards/heltec/heltec_wifi_lora32_v2/heltec_wifi_lora32_v2_esp32_appcpu_defconfig rename to boards/heltec/heltec_wifi_lora32_v2/heltec_wifi_lora32_v2_appcpu_defconfig diff --git a/boards/heltec/heltec_wifi_lora32_v2/heltec_wifi_lora32_v2_esp32_appcpu.yaml b/boards/heltec/heltec_wifi_lora32_v2/heltec_wifi_lora32_v2_esp32_appcpu.yaml deleted file mode 100644 index 373c6b0eae9..00000000000 --- a/boards/heltec/heltec_wifi_lora32_v2/heltec_wifi_lora32_v2_esp32_appcpu.yaml +++ /dev/null @@ -1,27 +0,0 @@ -identifier: heltec_wifi_lora32_v2/esp32/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/heltec/heltec_wifi_lora32_v2/heltec_wifi_lora32_v2_esp32_procpu.yaml b/boards/heltec/heltec_wifi_lora32_v2/heltec_wifi_lora32_v2_esp32_procpu.yaml deleted file mode 100644 index f8571589d7a..00000000000 --- a/boards/heltec/heltec_wifi_lora32_v2/heltec_wifi_lora32_v2_esp32_procpu.yaml +++ /dev/null @@ -1,17 +0,0 @@ -identifier: heltec_wifi_lora32_v2/esp32/procpu -name: HELTEC WiFi LoRa 32 (V2) Board -type: mcu -arch: xtensa -toolchain: - - zephyr -supported: - - gpio - - i2c - - watchdog - - uart - - nvs -testing: - ignore_tags: - - net - - bluetooth -vendor: espressif diff --git a/boards/heltec/heltec_wifi_lora32_v2/heltec_wifi_lora32_v2_esp32_procpu.dts b/boards/heltec/heltec_wifi_lora32_v2/heltec_wifi_lora32_v2_procpu.dts similarity index 100% rename from boards/heltec/heltec_wifi_lora32_v2/heltec_wifi_lora32_v2_esp32_procpu.dts rename to boards/heltec/heltec_wifi_lora32_v2/heltec_wifi_lora32_v2_procpu.dts diff --git a/boards/heltec/heltec_wifi_lora32_v2/heltec_wifi_lora32_v2_procpu.yaml b/boards/heltec/heltec_wifi_lora32_v2/heltec_wifi_lora32_v2_procpu.yaml new file mode 100644 index 00000000000..d516f1e1c5c --- /dev/null +++ b/boards/heltec/heltec_wifi_lora32_v2/heltec_wifi_lora32_v2_procpu.yaml @@ -0,0 +1,17 @@ +identifier: heltec_wifi_lora32_v2/esp32/procpu +name: HELTEC WiFi LoRa 32 (V2) Board PROCPU +type: mcu +arch: xtensa +toolchain: + - zephyr +supported: + - gpio + - i2c + - watchdog + - uart + - nvs +testing: + ignore_tags: + - net + - bluetooth +vendor: espressif diff --git a/boards/heltec/heltec_wifi_lora32_v2/heltec_wifi_lora32_v2_esp32_procpu_defconfig b/boards/heltec/heltec_wifi_lora32_v2/heltec_wifi_lora32_v2_procpu_defconfig similarity index 100% rename from boards/heltec/heltec_wifi_lora32_v2/heltec_wifi_lora32_v2_esp32_procpu_defconfig rename to boards/heltec/heltec_wifi_lora32_v2/heltec_wifi_lora32_v2_procpu_defconfig diff --git a/boards/heltec/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3_esp32s3_appcpu.dts b/boards/heltec/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3_appcpu.dts similarity index 100% rename from boards/heltec/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3_esp32s3_appcpu.dts rename to boards/heltec/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3_appcpu.dts diff --git a/boards/heltec/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3_appcpu.yaml b/boards/heltec/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3_appcpu.yaml new file mode 100644 index 00000000000..d738477900d --- /dev/null +++ b/boards/heltec/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3_appcpu.yaml @@ -0,0 +1,27 @@ +identifier: heltec_wireless_stick_lite_v3/esp32s3/appcpu +name: Heltec Wireless Stick Lite (V3) 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: heltec diff --git a/boards/heltec/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3_esp32s3_appcpu_defconfig b/boards/heltec/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3_appcpu_defconfig similarity index 100% rename from boards/heltec/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3_esp32s3_appcpu_defconfig rename to boards/heltec/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3_appcpu_defconfig diff --git a/boards/heltec/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3_esp32s3_appcpu.yaml b/boards/heltec/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3_esp32s3_appcpu.yaml deleted file mode 100644 index a465da8f94d..00000000000 --- a/boards/heltec/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3_esp32s3_appcpu.yaml +++ /dev/null @@ -1,27 +0,0 @@ -identifier: heltec_wireless_stick_lite_v3/esp32s3/appcpu -name: ESP32-S3 DevKitM 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: heltec diff --git a/boards/heltec/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3_esp32s3_procpu.dts b/boards/heltec/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3_esp32s3_procpu.dts deleted file mode 100644 index 38d870a6fbb..00000000000 --- a/boards/heltec/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3_esp32s3_procpu.dts +++ /dev/null @@ -1,216 +0,0 @@ -/* - * 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 PROCPU"; - 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/heltec/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3_procpu.dts b/boards/heltec/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3_procpu.dts new file mode 100644 index 00000000000..255fc34c051 --- /dev/null +++ b/boards/heltec/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3_procpu.dts @@ -0,0 +1,215 @@ +/* + * 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 PROCPU"; + 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"; +}; + +&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/heltec/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3_esp32s3_procpu.yaml b/boards/heltec/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3_procpu.yaml similarity index 100% rename from boards/heltec/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3_esp32s3_procpu.yaml rename to boards/heltec/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3_procpu.yaml diff --git a/boards/heltec/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3_esp32s3_procpu_defconfig b/boards/heltec/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3_procpu_defconfig similarity index 100% rename from boards/heltec/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3_esp32s3_procpu_defconfig rename to boards/heltec/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3_procpu_defconfig diff --git a/boards/cypress/cy8ckit_062s4/Kconfig.cy8ckit_062s4 b/boards/infineon/cy8ckit_062s4/Kconfig.cy8ckit_062s4 similarity index 100% rename from boards/cypress/cy8ckit_062s4/Kconfig.cy8ckit_062s4 rename to boards/infineon/cy8ckit_062s4/Kconfig.cy8ckit_062s4 diff --git a/boards/cypress/cy8ckit_062s4/board.cmake b/boards/infineon/cy8ckit_062s4/board.cmake similarity index 100% rename from boards/cypress/cy8ckit_062s4/board.cmake rename to boards/infineon/cy8ckit_062s4/board.cmake diff --git a/boards/infineon/cy8ckit_062s4/board.yml b/boards/infineon/cy8ckit_062s4/board.yml new file mode 100644 index 00000000000..c460d9f0503 --- /dev/null +++ b/boards/infineon/cy8ckit_062s4/board.yml @@ -0,0 +1,5 @@ +board: + name: cy8ckit_062s4 + vendor: infineon + socs: + - name: cy8c6244lqi_s4d92 diff --git a/boards/cypress/cy8ckit_062s4/cy8ckit_062s4.dts b/boards/infineon/cy8ckit_062s4/cy8ckit_062s4.dts similarity index 93% rename from boards/cypress/cy8ckit_062s4/cy8ckit_062s4.dts rename to boards/infineon/cy8ckit_062s4/cy8ckit_062s4.dts index 6695a24a4b8..457878a62b7 100644 --- a/boards/cypress/cy8ckit_062s4/cy8ckit_062s4.dts +++ b/boards/infineon/cy8ckit_062s4/cy8ckit_062s4.dts @@ -4,7 +4,7 @@ */ /dts-v1/; -#include +#include / { model = "Infineon PSoC 62S4 Pioneer Kit"; diff --git a/boards/cypress/cy8ckit_062s4/cy8ckit_062s4.yaml b/boards/infineon/cy8ckit_062s4/cy8ckit_062s4.yaml similarity index 93% rename from boards/cypress/cy8ckit_062s4/cy8ckit_062s4.yaml rename to boards/infineon/cy8ckit_062s4/cy8ckit_062s4.yaml index aaa7d0c8305..4ab5c7580ec 100644 --- a/boards/cypress/cy8ckit_062s4/cy8ckit_062s4.yaml +++ b/boards/infineon/cy8ckit_062s4/cy8ckit_062s4.yaml @@ -12,4 +12,4 @@ toolchain: - gnuarmemb supported: - gpio -vendor: cypress +vendor: infineon diff --git a/boards/cypress/cy8ckit_062s4/cy8ckit_062s4_defconfig b/boards/infineon/cy8ckit_062s4/cy8ckit_062s4_defconfig similarity index 100% rename from boards/cypress/cy8ckit_062s4/cy8ckit_062s4_defconfig rename to boards/infineon/cy8ckit_062s4/cy8ckit_062s4_defconfig diff --git a/boards/cypress/cy8ckit_062s4/doc/img/cy8ckit_062s4.png b/boards/infineon/cy8ckit_062s4/doc/img/cy8ckit_062s4.png similarity index 100% rename from boards/cypress/cy8ckit_062s4/doc/img/cy8ckit_062s4.png rename to boards/infineon/cy8ckit_062s4/doc/img/cy8ckit_062s4.png diff --git a/boards/cypress/cy8ckit_062s4/doc/index.rst b/boards/infineon/cy8ckit_062s4/doc/index.rst similarity index 100% rename from boards/cypress/cy8ckit_062s4/doc/index.rst rename to boards/infineon/cy8ckit_062s4/doc/index.rst diff --git a/boards/cypress/cy8cproto_062_4343w/Kconfig.cy8cproto_062_4343w b/boards/infineon/cy8cproto_062_4343w/Kconfig.cy8cproto_062_4343w similarity index 100% rename from boards/cypress/cy8cproto_062_4343w/Kconfig.cy8cproto_062_4343w rename to boards/infineon/cy8cproto_062_4343w/Kconfig.cy8cproto_062_4343w diff --git a/boards/cypress/cy8cproto_062_4343w/Kconfig.defconfig b/boards/infineon/cy8cproto_062_4343w/Kconfig.defconfig similarity index 100% rename from boards/cypress/cy8cproto_062_4343w/Kconfig.defconfig rename to boards/infineon/cy8cproto_062_4343w/Kconfig.defconfig diff --git a/boards/cypress/cy8cproto_062_4343w/board.cmake b/boards/infineon/cy8cproto_062_4343w/board.cmake similarity index 100% rename from boards/cypress/cy8cproto_062_4343w/board.cmake rename to boards/infineon/cy8cproto_062_4343w/board.cmake diff --git a/boards/infineon/cy8cproto_062_4343w/board.yml b/boards/infineon/cy8cproto_062_4343w/board.yml new file mode 100644 index 00000000000..f89df6ee65e --- /dev/null +++ b/boards/infineon/cy8cproto_062_4343w/board.yml @@ -0,0 +1,5 @@ +board: + name: cy8cproto_062_4343w + vendor: infineon + socs: + - name: cy8c624abzi_s2d44 diff --git a/boards/cypress/cy8cproto_062_4343w/cy8cproto_062_4343w-common.dtsi b/boards/infineon/cy8cproto_062_4343w/cy8cproto_062_4343w-common.dtsi similarity index 100% rename from boards/cypress/cy8cproto_062_4343w/cy8cproto_062_4343w-common.dtsi rename to boards/infineon/cy8cproto_062_4343w/cy8cproto_062_4343w-common.dtsi diff --git a/boards/cypress/cy8cproto_062_4343w/cy8cproto_062_4343w-pinctrl.dtsi b/boards/infineon/cy8cproto_062_4343w/cy8cproto_062_4343w-pinctrl.dtsi similarity index 100% rename from boards/cypress/cy8cproto_062_4343w/cy8cproto_062_4343w-pinctrl.dtsi rename to boards/infineon/cy8cproto_062_4343w/cy8cproto_062_4343w-pinctrl.dtsi diff --git a/boards/cypress/cy8cproto_062_4343w/cy8cproto_062_4343w.dts b/boards/infineon/cy8cproto_062_4343w/cy8cproto_062_4343w.dts similarity index 94% rename from boards/cypress/cy8cproto_062_4343w/cy8cproto_062_4343w.dts rename to boards/infineon/cy8cproto_062_4343w/cy8cproto_062_4343w.dts index cc793184b14..7997344dd54 100644 --- a/boards/cypress/cy8cproto_062_4343w/cy8cproto_062_4343w.dts +++ b/boards/infineon/cy8cproto_062_4343w/cy8cproto_062_4343w.dts @@ -4,8 +4,8 @@ */ /dts-v1/; -#include -#include +#include +#include #include "cy8cproto_062_4343w-common.dtsi" #include "cy8cproto_062_4343w-pinctrl.dtsi" @@ -45,16 +45,19 @@ uart5: &scb5 { uart2: &scb2 { compatible = "infineon,cat1-uart"; status = "okay"; + /* The UART bus speed (current_speed) for zephyr_bt_uart should be the same * as the default baudrate defined in CYW43xx firmware (default 115200). */ - current-speed = <115200>; /* 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"; + /* HW Flow control must be enabled for HCI H4 */ + hw-flow-control; + bt-hci { status = "okay"; compatible = "infineon,cyw43xxx-bt-hci"; diff --git a/boards/cypress/cy8cproto_062_4343w/cy8cproto_062_4343w.yaml b/boards/infineon/cy8cproto_062_4343w/cy8cproto_062_4343w.yaml similarity index 87% rename from boards/cypress/cy8cproto_062_4343w/cy8cproto_062_4343w.yaml rename to boards/infineon/cy8cproto_062_4343w/cy8cproto_062_4343w.yaml index 8300a160c5a..113c686db03 100644 --- a/boards/cypress/cy8cproto_062_4343w/cy8cproto_062_4343w.yaml +++ b/boards/infineon/cy8cproto_062_4343w/cy8cproto_062_4343w.yaml @@ -22,4 +22,7 @@ supported: - gpio - uart - i2c -vendor: cypress + - thermistor + - uart + - timer +vendor: infineon diff --git a/boards/cypress/cy8cproto_062_4343w/cy8cproto_062_4343w_defconfig b/boards/infineon/cy8cproto_062_4343w/cy8cproto_062_4343w_defconfig similarity index 100% rename from boards/cypress/cy8cproto_062_4343w/cy8cproto_062_4343w_defconfig rename to boards/infineon/cy8cproto_062_4343w/cy8cproto_062_4343w_defconfig diff --git a/boards/cypress/cy8cproto_062_4343w/doc/img/board.jpg b/boards/infineon/cy8cproto_062_4343w/doc/img/board.jpg similarity index 100% rename from boards/cypress/cy8cproto_062_4343w/doc/img/board.jpg rename to boards/infineon/cy8cproto_062_4343w/doc/img/board.jpg diff --git a/boards/cypress/cy8cproto_062_4343w/doc/index.rst b/boards/infineon/cy8cproto_062_4343w/doc/index.rst similarity index 100% rename from boards/cypress/cy8cproto_062_4343w/doc/index.rst rename to boards/infineon/cy8cproto_062_4343w/doc/index.rst diff --git a/boards/cypress/cy8cproto_062_4343w/support/openocd.cfg b/boards/infineon/cy8cproto_062_4343w/support/openocd.cfg similarity index 100% rename from boards/cypress/cy8cproto_062_4343w/support/openocd.cfg rename to boards/infineon/cy8cproto_062_4343w/support/openocd.cfg diff --git a/boards/cypress/cy8cproto_063_ble/Kconfig.cy8cproto_063_ble b/boards/infineon/cy8cproto_063_ble/Kconfig.cy8cproto_063_ble similarity index 100% rename from boards/cypress/cy8cproto_063_ble/Kconfig.cy8cproto_063_ble rename to boards/infineon/cy8cproto_063_ble/Kconfig.cy8cproto_063_ble diff --git a/boards/cypress/cy8cproto_063_ble/Kconfig.defconfig b/boards/infineon/cy8cproto_063_ble/Kconfig.defconfig similarity index 100% rename from boards/cypress/cy8cproto_063_ble/Kconfig.defconfig rename to boards/infineon/cy8cproto_063_ble/Kconfig.defconfig diff --git a/boards/cypress/cy8cproto_063_ble/board.cmake b/boards/infineon/cy8cproto_063_ble/board.cmake similarity index 100% rename from boards/cypress/cy8cproto_063_ble/board.cmake rename to boards/infineon/cy8cproto_063_ble/board.cmake diff --git a/boards/infineon/cy8cproto_063_ble/board.yml b/boards/infineon/cy8cproto_063_ble/board.yml new file mode 100644 index 00000000000..6ef5bd8e9d7 --- /dev/null +++ b/boards/infineon/cy8cproto_063_ble/board.yml @@ -0,0 +1,5 @@ +board: + name: cy8cproto_063_ble + vendor: infineon + socs: + - name: cyble_416045_02 diff --git a/boards/cypress/cy8cproto_063_ble/cy8cproto_063_ble-pinctrl.dtsi b/boards/infineon/cy8cproto_063_ble/cy8cproto_063_ble-pinctrl.dtsi similarity index 100% rename from boards/cypress/cy8cproto_063_ble/cy8cproto_063_ble-pinctrl.dtsi rename to boards/infineon/cy8cproto_063_ble/cy8cproto_063_ble-pinctrl.dtsi diff --git a/boards/cypress/cy8cproto_063_ble/cy8cproto_063_ble.dts b/boards/infineon/cy8cproto_063_ble/cy8cproto_063_ble.dts similarity index 95% rename from boards/cypress/cy8cproto_063_ble/cy8cproto_063_ble.dts rename to boards/infineon/cy8cproto_063_ble/cy8cproto_063_ble.dts index e918f547bd2..0f96ff07a77 100644 --- a/boards/cypress/cy8cproto_063_ble/cy8cproto_063_ble.dts +++ b/boards/infineon/cy8cproto_063_ble/cy8cproto_063_ble.dts @@ -6,8 +6,8 @@ /dts-v1/; -#include -#include +#include +#include #include "cy8cproto_063_ble-pinctrl.dtsi" #include diff --git a/boards/cypress/cy8cproto_063_ble/cy8cproto_063_ble.yaml b/boards/infineon/cy8cproto_063_ble/cy8cproto_063_ble.yaml similarity index 92% rename from boards/cypress/cy8cproto_063_ble/cy8cproto_063_ble.yaml rename to boards/infineon/cy8cproto_063_ble/cy8cproto_063_ble.yaml index 1aaef3040d3..db4f1ec95b0 100644 --- a/boards/cypress/cy8cproto_063_ble/cy8cproto_063_ble.yaml +++ b/boards/infineon/cy8cproto_063_ble/cy8cproto_063_ble.yaml @@ -19,4 +19,5 @@ supported: - i2c - watchdog - spi -vendor: cypress + - timer +vendor: infineon diff --git a/boards/cypress/cy8cproto_063_ble/cy8cproto_063_ble_defconfig b/boards/infineon/cy8cproto_063_ble/cy8cproto_063_ble_defconfig similarity index 100% rename from boards/cypress/cy8cproto_063_ble/cy8cproto_063_ble_defconfig rename to boards/infineon/cy8cproto_063_ble/cy8cproto_063_ble_defconfig diff --git a/boards/cypress/cy8cproto_063_ble/doc/img/cy8cproto-063-ble.jpg b/boards/infineon/cy8cproto_063_ble/doc/img/cy8cproto-063-ble.jpg similarity index 100% rename from boards/cypress/cy8cproto_063_ble/doc/img/cy8cproto-063-ble.jpg rename to boards/infineon/cy8cproto_063_ble/doc/img/cy8cproto-063-ble.jpg diff --git a/boards/cypress/cy8cproto_063_ble/doc/index.rst b/boards/infineon/cy8cproto_063_ble/doc/index.rst similarity index 100% rename from boards/cypress/cy8cproto_063_ble/doc/index.rst rename to boards/infineon/cy8cproto_063_ble/doc/index.rst diff --git a/boards/cypress/cy8cproto_063_ble/support/openocd.cfg b/boards/infineon/cy8cproto_063_ble/support/openocd.cfg similarity index 100% rename from boards/cypress/cy8cproto_063_ble/support/openocd.cfg rename to boards/infineon/cy8cproto_063_ble/support/openocd.cfg diff --git a/boards/infineon/xmc45_relax_kit/xmc45_relax_kit-pinctrl.dtsi b/boards/infineon/xmc45_relax_kit/xmc45_relax_kit-pinctrl.dtsi index 936733ea02a..b8bb7b42a8c 100644 --- a/boards/infineon/xmc45_relax_kit/xmc45_relax_kit-pinctrl.dtsi +++ b/boards/infineon/xmc45_relax_kit/xmc45_relax_kit-pinctrl.dtsi @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include &uart_tx_p0_1_u1c1 { drive-strength = "strong-soft-edge"; diff --git a/boards/infineon/xmc45_relax_kit/xmc45_relax_kit.dts b/boards/infineon/xmc45_relax_kit/xmc45_relax_kit.dts index 6b1519a4553..feb0a8e5aba 100644 --- a/boards/infineon/xmc45_relax_kit/xmc45_relax_kit.dts +++ b/boards/infineon/xmc45_relax_kit/xmc45_relax_kit.dts @@ -8,8 +8,8 @@ /dts-v1/; -#include -#include +#include +#include #include #include "xmc45_relax_kit-pinctrl.dtsi" diff --git a/boards/infineon/xmc47_relax_kit/xmc47_relax_kit-pinctrl.dtsi b/boards/infineon/xmc47_relax_kit/xmc47_relax_kit-pinctrl.dtsi index e6688a7ebb2..75b35c388b7 100644 --- a/boards/infineon/xmc47_relax_kit/xmc47_relax_kit-pinctrl.dtsi +++ b/boards/infineon/xmc47_relax_kit/xmc47_relax_kit-pinctrl.dtsi @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include &uart_tx_p1_5_u0c0 { drive-strength = "strong-soft-edge"; diff --git a/boards/infineon/xmc47_relax_kit/xmc47_relax_kit.dts b/boards/infineon/xmc47_relax_kit/xmc47_relax_kit.dts index df37b32e3c7..ec8879bcb40 100644 --- a/boards/infineon/xmc47_relax_kit/xmc47_relax_kit.dts +++ b/boards/infineon/xmc47_relax_kit/xmc47_relax_kit.dts @@ -7,8 +7,8 @@ /dts-v1/; -#include -#include +#include +#include #include #include "xmc47_relax_kit-pinctrl.dtsi" #include "arduino_r3_connector.dtsi" @@ -207,7 +207,6 @@ &can_node1 { status = "okay"; - bus-speed = <125000>; input-src = "RXDC"; pinctrl-0 = <&can_tx_p1_12_node1 &can_rx_p1_13_node1>; pinctrl-names = "default"; diff --git a/boards/ite/it82xx2_evb/Kconfig.it82xx2_evb b/boards/ite/it82xx2_evb/Kconfig.it82xx2_evb index 94025707fa4..e2f8a89e09b 100644 --- a/boards/ite/it82xx2_evb/Kconfig.it82xx2_evb +++ b/boards/ite/it82xx2_evb/Kconfig.it82xx2_evb @@ -2,4 +2,4 @@ # SPDX-License-Identifier: Apache-2.0 config BOARD_IT82XX2_EVB - select SOC_IT82202_AX + select SOC_IT82202AX diff --git a/boards/ite/it82xx2_evb/it82xx2_evb.dts b/boards/ite/it82xx2_evb/it82xx2_evb.dts index 1d1bb23eeb6..bd623e969c5 100644 --- a/boards/ite/it82xx2_evb/it82xx2_evb.dts +++ b/boards/ite/it82xx2_evb/it82xx2_evb.dts @@ -203,6 +203,10 @@ pinctrl-names = "default"; }; +&sha0 { + status = "okay"; +}; + zephyr_udc0: &usb0 { status = "okay"; pinctrl-0 = <&usb0_dm_gph5_default diff --git a/boards/ite/it8xxx2_evb/Kconfig.it8xxx2_evb b/boards/ite/it8xxx2_evb/Kconfig.it8xxx2_evb index 8e9b476eb68..d5d55c35aa2 100644 --- a/boards/ite/it8xxx2_evb/Kconfig.it8xxx2_evb +++ b/boards/ite/it8xxx2_evb/Kconfig.it8xxx2_evb @@ -2,4 +2,4 @@ # SPDX-License-Identifier: Apache-2.0 config BOARD_IT8XXX2_EVB - select SOC_IT81302_BX + select SOC_IT81302BX diff --git a/boards/kincony/kincony_kc868_a32/kincony_kc868_a32_esp32_appcpu.dts b/boards/kincony/kincony_kc868_a32/kincony_kc868_a32_appcpu.dts similarity index 100% rename from boards/kincony/kincony_kc868_a32/kincony_kc868_a32_esp32_appcpu.dts rename to boards/kincony/kincony_kc868_a32/kincony_kc868_a32_appcpu.dts diff --git a/boards/kincony/kincony_kc868_a32/kincony_kc868_a32_appcpu.yaml b/boards/kincony/kincony_kc868_a32/kincony_kc868_a32_appcpu.yaml new file mode 100644 index 00000000000..8a80a51872e --- /dev/null +++ b/boards/kincony/kincony_kc868_a32/kincony_kc868_a32_appcpu.yaml @@ -0,0 +1,27 @@ +identifier: kincony_kc868_a32/esp32/appcpu +name: KINCONY-KC868-A32 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/kincony/kincony_kc868_a32/kincony_kc868_a32_esp32_appcpu_defconfig b/boards/kincony/kincony_kc868_a32/kincony_kc868_a32_appcpu_defconfig similarity index 100% rename from boards/kincony/kincony_kc868_a32/kincony_kc868_a32_esp32_appcpu_defconfig rename to boards/kincony/kincony_kc868_a32/kincony_kc868_a32_appcpu_defconfig diff --git a/boards/kincony/kincony_kc868_a32/kincony_kc868_a32_esp32_appcpu.yaml b/boards/kincony/kincony_kc868_a32/kincony_kc868_a32_esp32_appcpu.yaml deleted file mode 100644 index af75ec0edbc..00000000000 --- a/boards/kincony/kincony_kc868_a32/kincony_kc868_a32_esp32_appcpu.yaml +++ /dev/null @@ -1,27 +0,0 @@ -identifier: kincony_kc868_a32/esp32/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/kincony/kincony_kc868_a32/kincony_kc868_a32_esp32_procpu.yaml b/boards/kincony/kincony_kc868_a32/kincony_kc868_a32_esp32_procpu.yaml deleted file mode 100644 index 51ac12191f6..00000000000 --- a/boards/kincony/kincony_kc868_a32/kincony_kc868_a32_esp32_procpu.yaml +++ /dev/null @@ -1,19 +0,0 @@ -identifier: kincony_kc868_a32/esp32/procpu -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/kincony/kincony_kc868_a32/kincony_kc868_a32_esp32_procpu.dts b/boards/kincony/kincony_kc868_a32/kincony_kc868_a32_procpu.dts similarity index 100% rename from boards/kincony/kincony_kc868_a32/kincony_kc868_a32_esp32_procpu.dts rename to boards/kincony/kincony_kc868_a32/kincony_kc868_a32_procpu.dts diff --git a/boards/kincony/kincony_kc868_a32/kincony_kc868_a32_procpu.yaml b/boards/kincony/kincony_kc868_a32/kincony_kc868_a32_procpu.yaml new file mode 100644 index 00000000000..325c3794c29 --- /dev/null +++ b/boards/kincony/kincony_kc868_a32/kincony_kc868_a32_procpu.yaml @@ -0,0 +1,19 @@ +identifier: kincony_kc868_a32/esp32/procpu +name: KINCONY-KC868-A32 PROCPU +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/kincony/kincony_kc868_a32/kincony_kc868_a32_esp32_procpu_defconfig b/boards/kincony/kincony_kc868_a32/kincony_kc868_a32_procpu_defconfig similarity index 100% rename from boards/kincony/kincony_kc868_a32/kincony_kc868_a32_esp32_procpu_defconfig rename to boards/kincony/kincony_kc868_a32/kincony_kc868_a32_procpu_defconfig diff --git a/boards/luatos/esp32c3_luatos_core/esp32c3_luatos_core.dtsi b/boards/luatos/esp32c3_luatos_core/esp32c3_luatos_core.dtsi index 2972e4725f1..bf83c33898c 100644 --- a/boards/luatos/esp32c3_luatos_core/esp32c3_luatos_core.dtsi +++ b/boards/luatos/esp32c3_luatos_core/esp32c3_luatos_core.dtsi @@ -94,7 +94,6 @@ status = "disabled"; pinctrl-0 = <&twai_default>; pinctrl-names = "default"; - bus-speed = <125000>; }; &flash0 { diff --git a/boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core.dtsi b/boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core.dtsi index efaded4d02d..849dd35bd67 100644 --- a/boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core.dtsi +++ b/boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core.dtsi @@ -85,7 +85,6 @@ &twai { pinctrl-0 = <&twai_default>; pinctrl-names = "default"; - bus-speed = <125000>; }; &timer0 { diff --git a/boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_esp32s3_appcpu.dts b/boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_appcpu.dts similarity index 100% rename from boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_esp32s3_appcpu.dts rename to boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_appcpu.dts diff --git a/boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_appcpu.yaml b/boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_appcpu.yaml new file mode 100644 index 00000000000..ae7e008793e --- /dev/null +++ b/boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_appcpu.yaml @@ -0,0 +1,27 @@ +identifier: esp32s3_luatos_core/esp32s3/appcpu +name: ESP32-S3 LuatOS Core 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: luatos diff --git a/boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_esp32s3_appcpu_defconfig b/boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_appcpu_defconfig similarity index 100% rename from boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_esp32s3_appcpu_defconfig rename to boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_appcpu_defconfig diff --git a/boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_esp32s3_appcpu_usb.dts b/boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_appcpu_usb.dts similarity index 100% rename from boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_esp32s3_appcpu_usb.dts rename to boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_appcpu_usb.dts diff --git a/boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_appcpu_usb.yaml b/boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_appcpu_usb.yaml new file mode 100644 index 00000000000..3a80a65a46a --- /dev/null +++ b/boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_appcpu_usb.yaml @@ -0,0 +1,27 @@ +identifier: esp32s3_luatos_core/esp32s3/appcpu/usb +name: ESP32-S3 LuatOS Core APPCPU USB +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: luatos diff --git a/boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_esp32s3_appcpu_usb_defconfig b/boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_appcpu_usb_defconfig similarity index 100% rename from boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_esp32s3_appcpu_usb_defconfig rename to boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_appcpu_usb_defconfig diff --git a/boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_esp32s3_appcpu.yaml b/boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_esp32s3_appcpu.yaml deleted file mode 100644 index 05aac04c00f..00000000000 --- a/boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_esp32s3_appcpu.yaml +++ /dev/null @@ -1,27 +0,0 @@ -identifier: esp32s3_luatos_core/esp32s3/appcpu -name: ESP32-S3 LuatOS Core -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: luatos diff --git a/boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_esp32s3_appcpu_usb.yaml b/boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_esp32s3_appcpu_usb.yaml deleted file mode 100644 index cb2ac02717b..00000000000 --- a/boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_esp32s3_appcpu_usb.yaml +++ /dev/null @@ -1,27 +0,0 @@ -identifier: esp32s3_luatos_core/esp32s3/appcpu/usb -name: ESP32-S3 LuatOS Core USB -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: luatos diff --git a/boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_esp32s3_procpu.yaml b/boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_esp32s3_procpu.yaml deleted file mode 100644 index 2a1bb02cc2f..00000000000 --- a/boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_esp32s3_procpu.yaml +++ /dev/null @@ -1,22 +0,0 @@ -identifier: esp32s3_luatos_core/esp32s3/procpu -name: ESP32-S3 LuatOS Core -type: mcu -arch: xtensa -toolchain: - - zephyr -supported: - - gpio - - uart - - i2c - - spi - - can - - counter - - watchdog - - entropy - - pwm - - dma -testing: - ignore_tags: - - net - - bluetooth -vendor: luatos diff --git a/boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_esp32s3_procpu_usb.yaml b/boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_esp32s3_procpu_usb.yaml deleted file mode 100644 index f1cd4d19d5a..00000000000 --- a/boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_esp32s3_procpu_usb.yaml +++ /dev/null @@ -1,22 +0,0 @@ -identifier: esp32s3_luatos_core/esp32s3/procpu/usb -name: ESP32-S3 LuatOS Core USB -type: mcu -arch: xtensa -toolchain: - - zephyr -supported: - - gpio - - uart - - i2c - - spi - - can - - counter - - watchdog - - entropy - - pwm - - dma -testing: - ignore_tags: - - net - - bluetooth -vendor: luatos diff --git a/boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_esp32s3_procpu.dts b/boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_procpu.dts similarity index 100% rename from boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_esp32s3_procpu.dts rename to boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_procpu.dts diff --git a/boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_procpu.yaml b/boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_procpu.yaml new file mode 100644 index 00000000000..6d564843a1c --- /dev/null +++ b/boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_procpu.yaml @@ -0,0 +1,22 @@ +identifier: esp32s3_luatos_core/esp32s3/procpu +name: ESP32-S3 LuatOS Core PROCPU +type: mcu +arch: xtensa +toolchain: + - zephyr +supported: + - gpio + - uart + - i2c + - spi + - can + - counter + - watchdog + - entropy + - pwm + - dma +testing: + ignore_tags: + - net + - bluetooth +vendor: luatos diff --git a/boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_esp32s3_procpu_defconfig b/boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_procpu_defconfig similarity index 100% rename from boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_esp32s3_procpu_defconfig rename to boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_procpu_defconfig diff --git a/boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_esp32s3_procpu_usb.dts b/boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_procpu_usb.dts similarity index 100% rename from boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_esp32s3_procpu_usb.dts rename to boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_procpu_usb.dts diff --git a/boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_procpu_usb.yaml b/boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_procpu_usb.yaml new file mode 100644 index 00000000000..7e160d68117 --- /dev/null +++ b/boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_procpu_usb.yaml @@ -0,0 +1,22 @@ +identifier: esp32s3_luatos_core/esp32s3/procpu/usb +name: ESP32-S3 LuatOS Core PROCPU USB +type: mcu +arch: xtensa +toolchain: + - zephyr +supported: + - gpio + - uart + - i2c + - spi + - can + - counter + - watchdog + - entropy + - pwm + - dma +testing: + ignore_tags: + - net + - bluetooth +vendor: luatos diff --git a/boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_esp32s3_procpu_usb_defconfig b/boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_procpu_usb_defconfig similarity index 100% rename from boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_esp32s3_procpu_usb_defconfig rename to boards/luatos/esp32s3_luatos_core/esp32s3_luatos_core_procpu_usb_defconfig diff --git a/boards/m5stack/m5stack_atom_lite/m5stack_atom_lite_esp32_appcpu.dts b/boards/m5stack/m5stack_atom_lite/m5stack_atom_lite_appcpu.dts similarity index 100% rename from boards/m5stack/m5stack_atom_lite/m5stack_atom_lite_esp32_appcpu.dts rename to boards/m5stack/m5stack_atom_lite/m5stack_atom_lite_appcpu.dts diff --git a/boards/m5stack/m5stack_atom_lite/m5stack_atom_lite_esp32_appcpu.yaml b/boards/m5stack/m5stack_atom_lite/m5stack_atom_lite_appcpu.yaml similarity index 100% rename from boards/m5stack/m5stack_atom_lite/m5stack_atom_lite_esp32_appcpu.yaml rename to boards/m5stack/m5stack_atom_lite/m5stack_atom_lite_appcpu.yaml diff --git a/boards/m5stack/m5stack_atom_lite/m5stack_atom_lite_esp32_appcpu_defconfig b/boards/m5stack/m5stack_atom_lite/m5stack_atom_lite_appcpu_defconfig similarity index 100% rename from boards/m5stack/m5stack_atom_lite/m5stack_atom_lite_esp32_appcpu_defconfig rename to boards/m5stack/m5stack_atom_lite/m5stack_atom_lite_appcpu_defconfig diff --git a/boards/m5stack/m5stack_atom_lite/m5stack_atom_lite_esp32_procpu.dts b/boards/m5stack/m5stack_atom_lite/m5stack_atom_lite_procpu.dts similarity index 100% rename from boards/m5stack/m5stack_atom_lite/m5stack_atom_lite_esp32_procpu.dts rename to boards/m5stack/m5stack_atom_lite/m5stack_atom_lite_procpu.dts diff --git a/boards/m5stack/m5stack_atom_lite/m5stack_atom_lite_esp32_procpu.yaml b/boards/m5stack/m5stack_atom_lite/m5stack_atom_lite_procpu.yaml similarity index 100% rename from boards/m5stack/m5stack_atom_lite/m5stack_atom_lite_esp32_procpu.yaml rename to boards/m5stack/m5stack_atom_lite/m5stack_atom_lite_procpu.yaml diff --git a/boards/m5stack/m5stack_atom_lite/m5stack_atom_lite_esp32_procpu_defconfig b/boards/m5stack/m5stack_atom_lite/m5stack_atom_lite_procpu_defconfig similarity index 100% rename from boards/m5stack/m5stack_atom_lite/m5stack_atom_lite_esp32_procpu_defconfig rename to boards/m5stack/m5stack_atom_lite/m5stack_atom_lite_procpu_defconfig diff --git a/boards/m5stack/m5stack_atoms3/m5stack_atoms3_esp32s3_appcpu.dts b/boards/m5stack/m5stack_atoms3/m5stack_atoms3_appcpu.dts similarity index 100% rename from boards/m5stack/m5stack_atoms3/m5stack_atoms3_esp32s3_appcpu.dts rename to boards/m5stack/m5stack_atoms3/m5stack_atoms3_appcpu.dts diff --git a/boards/m5stack/m5stack_atoms3/m5stack_atoms3_appcpu.yaml b/boards/m5stack/m5stack_atoms3/m5stack_atoms3_appcpu.yaml new file mode 100644 index 00000000000..30c20695c27 --- /dev/null +++ b/boards/m5stack/m5stack_atoms3/m5stack_atoms3_appcpu.yaml @@ -0,0 +1,27 @@ +identifier: m5stack_atoms3/esp32s3/appcpu +name: M5Stack AtomS3 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: m5stack diff --git a/boards/m5stack/m5stack_atoms3/m5stack_atoms3_esp32s3_appcpu_defconfig b/boards/m5stack/m5stack_atoms3/m5stack_atoms3_appcpu_defconfig similarity index 100% rename from boards/m5stack/m5stack_atoms3/m5stack_atoms3_esp32s3_appcpu_defconfig rename to boards/m5stack/m5stack_atoms3/m5stack_atoms3_appcpu_defconfig diff --git a/boards/m5stack/m5stack_atoms3/m5stack_atoms3_esp32s3_appcpu.yaml b/boards/m5stack/m5stack_atoms3/m5stack_atoms3_esp32s3_appcpu.yaml deleted file mode 100644 index a8efc9aad00..00000000000 --- a/boards/m5stack/m5stack_atoms3/m5stack_atoms3_esp32s3_appcpu.yaml +++ /dev/null @@ -1,27 +0,0 @@ -identifier: m5stack_atoms3/esp32s3/appcpu -name: M5Stack AtomS3 -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: m5stack diff --git a/boards/m5stack/m5stack_atoms3/m5stack_atoms3_esp32s3_procpu.yaml b/boards/m5stack/m5stack_atoms3/m5stack_atoms3_esp32s3_procpu.yaml deleted file mode 100644 index 4be28b02f83..00000000000 --- a/boards/m5stack/m5stack_atoms3/m5stack_atoms3_esp32s3_procpu.yaml +++ /dev/null @@ -1,21 +0,0 @@ -identifier: m5stack_atoms3/esp32s3/procpu -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/m5stack/m5stack_atoms3/m5stack_atoms3_esp32s3_procpu.dts b/boards/m5stack/m5stack_atoms3/m5stack_atoms3_procpu.dts similarity index 100% rename from boards/m5stack/m5stack_atoms3/m5stack_atoms3_esp32s3_procpu.dts rename to boards/m5stack/m5stack_atoms3/m5stack_atoms3_procpu.dts diff --git a/boards/m5stack/m5stack_atoms3/m5stack_atoms3_procpu.yaml b/boards/m5stack/m5stack_atoms3/m5stack_atoms3_procpu.yaml new file mode 100644 index 00000000000..082aa4e5699 --- /dev/null +++ b/boards/m5stack/m5stack_atoms3/m5stack_atoms3_procpu.yaml @@ -0,0 +1,21 @@ +identifier: m5stack_atoms3/esp32s3/procpu +name: M5Stack AtomS3 PROCPU +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/m5stack/m5stack_atoms3/m5stack_atoms3_esp32s3_procpu_defconfig b/boards/m5stack/m5stack_atoms3/m5stack_atoms3_procpu_defconfig similarity index 100% rename from boards/m5stack/m5stack_atoms3/m5stack_atoms3_esp32s3_procpu_defconfig rename to boards/m5stack/m5stack_atoms3/m5stack_atoms3_procpu_defconfig diff --git a/boards/m5stack/m5stack_atoms3_lite/m5stack_atoms3_lite_esp32s3_appcpu.dts b/boards/m5stack/m5stack_atoms3_lite/m5stack_atoms3_lite_appcpu.dts similarity index 100% rename from boards/m5stack/m5stack_atoms3_lite/m5stack_atoms3_lite_esp32s3_appcpu.dts rename to boards/m5stack/m5stack_atoms3_lite/m5stack_atoms3_lite_appcpu.dts diff --git a/boards/m5stack/m5stack_atoms3_lite/m5stack_atoms3_lite_appcpu.yaml b/boards/m5stack/m5stack_atoms3_lite/m5stack_atoms3_lite_appcpu.yaml new file mode 100644 index 00000000000..004ed974675 --- /dev/null +++ b/boards/m5stack/m5stack_atoms3_lite/m5stack_atoms3_lite_appcpu.yaml @@ -0,0 +1,27 @@ +identifier: m5stack_atoms3_lite/esp32s3/appcpu +name: M5Stack AtomS3-Lite 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: m5stack diff --git a/boards/m5stack/m5stack_atoms3_lite/m5stack_atoms3_lite_esp32s3_appcpu_defconfig b/boards/m5stack/m5stack_atoms3_lite/m5stack_atoms3_lite_appcpu_defconfig similarity index 100% rename from boards/m5stack/m5stack_atoms3_lite/m5stack_atoms3_lite_esp32s3_appcpu_defconfig rename to boards/m5stack/m5stack_atoms3_lite/m5stack_atoms3_lite_appcpu_defconfig diff --git a/boards/m5stack/m5stack_atoms3_lite/m5stack_atoms3_lite_esp32s3_appcpu.yaml b/boards/m5stack/m5stack_atoms3_lite/m5stack_atoms3_lite_esp32s3_appcpu.yaml deleted file mode 100644 index 0a641e9ef12..00000000000 --- a/boards/m5stack/m5stack_atoms3_lite/m5stack_atoms3_lite_esp32s3_appcpu.yaml +++ /dev/null @@ -1,27 +0,0 @@ -identifier: m5stack_atoms3_lite/esp32s3/appcpu -name: M5Stack AtomS3-Lite -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: m5stack diff --git a/boards/m5stack/m5stack_atoms3_lite/m5stack_atoms3_lite_esp32s3_procpu.yaml b/boards/m5stack/m5stack_atoms3_lite/m5stack_atoms3_lite_esp32s3_procpu.yaml deleted file mode 100644 index 3012207d36d..00000000000 --- a/boards/m5stack/m5stack_atoms3_lite/m5stack_atoms3_lite_esp32s3_procpu.yaml +++ /dev/null @@ -1,23 +0,0 @@ -identifier: m5stack_atoms3_lite/esp32s3/procpu -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/m5stack/m5stack_atoms3_lite/m5stack_atoms3_lite_esp32s3_procpu.dts b/boards/m5stack/m5stack_atoms3_lite/m5stack_atoms3_lite_procpu.dts similarity index 100% rename from boards/m5stack/m5stack_atoms3_lite/m5stack_atoms3_lite_esp32s3_procpu.dts rename to boards/m5stack/m5stack_atoms3_lite/m5stack_atoms3_lite_procpu.dts diff --git a/boards/m5stack/m5stack_atoms3_lite/m5stack_atoms3_lite_procpu.yaml b/boards/m5stack/m5stack_atoms3_lite/m5stack_atoms3_lite_procpu.yaml new file mode 100644 index 00000000000..996732bc3dd --- /dev/null +++ b/boards/m5stack/m5stack_atoms3_lite/m5stack_atoms3_lite_procpu.yaml @@ -0,0 +1,23 @@ +identifier: m5stack_atoms3_lite/esp32s3/procpu +name: M5Stack AtomS3-Lite PROCPU +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/m5stack/m5stack_atoms3_lite/m5stack_atoms3_lite_esp32s3_procpu_defconfig b/boards/m5stack/m5stack_atoms3_lite/m5stack_atoms3_lite_procpu_defconfig similarity index 100% rename from boards/m5stack/m5stack_atoms3_lite/m5stack_atoms3_lite_esp32s3_procpu_defconfig rename to boards/m5stack/m5stack_atoms3_lite/m5stack_atoms3_lite_procpu_defconfig diff --git a/boards/m5stack/m5stack_core2/doc/index.rst b/boards/m5stack/m5stack_core2/doc/index.rst index 96669efcb1b..3e492af3532 100644 --- a/boards/m5stack/m5stack_core2/doc/index.rst +++ b/boards/m5stack/m5stack_core2/doc/index.rst @@ -219,6 +219,6 @@ Related Documents - `M5Stack-Core2 schematic `_ (PDF) - `ESP32-PICO-D4 Datasheet `_ (PDF) -- `M5StickC PLUS docs `_ +- `M5Stack-Core2 docs `_ - `ESP32 Datasheet `_ (PDF) - `ESP32 Hardware Reference `_ diff --git a/boards/m5stack/m5stack_core2/m5stack_core2_esp32_appcpu.dts b/boards/m5stack/m5stack_core2/m5stack_core2_appcpu.dts similarity index 100% rename from boards/m5stack/m5stack_core2/m5stack_core2_esp32_appcpu.dts rename to boards/m5stack/m5stack_core2/m5stack_core2_appcpu.dts diff --git a/boards/m5stack/m5stack_core2/m5stack_core2_appcpu.yaml b/boards/m5stack/m5stack_core2/m5stack_core2_appcpu.yaml new file mode 100644 index 00000000000..a49668e9547 --- /dev/null +++ b/boards/m5stack/m5stack_core2/m5stack_core2_appcpu.yaml @@ -0,0 +1,27 @@ +identifier: m5stack_core2/esp32/appcpu +name: M5Stack Core2 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: m5stack diff --git a/boards/m5stack/m5stack_core2/m5stack_core2_esp32_appcpu_defconfig b/boards/m5stack/m5stack_core2/m5stack_core2_appcpu_defconfig similarity index 100% rename from boards/m5stack/m5stack_core2/m5stack_core2_esp32_appcpu_defconfig rename to boards/m5stack/m5stack_core2/m5stack_core2_appcpu_defconfig diff --git a/boards/m5stack/m5stack_core2/m5stack_core2_esp32_appcpu.yaml b/boards/m5stack/m5stack_core2/m5stack_core2_esp32_appcpu.yaml deleted file mode 100644 index 8e5a51d07c7..00000000000 --- a/boards/m5stack/m5stack_core2/m5stack_core2_esp32_appcpu.yaml +++ /dev/null @@ -1,27 +0,0 @@ -identifier: m5stack_core2/esp32/appcpu -name: M5Stack Core2 -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: m5stack diff --git a/boards/m5stack/m5stack_core2/m5stack_core2_esp32_procpu.dts b/boards/m5stack/m5stack_core2/m5stack_core2_esp32_procpu.dts deleted file mode 100644 index 3ccb638c974..00000000000 --- a/boards/m5stack/m5stack_core2/m5stack_core2_esp32_procpu.dts +++ /dev/null @@ -1,292 +0,0 @@ -/* - * Copyright (c) 2023 Martin Kiepfer - * - * SPDX-License-Identifier: Apache-2.0 - */ -/dts-v1/; - -#include -#include "m5stack_core2-pinctrl.dtsi" -#include "grove_connectors.dtsi" -#include "m5stack_mbus_connectors.dtsi" -#include -#include - -/ { - model = "M5Stack Core2 PROCPU"; - compatible = "m5stack,core2"; - - aliases { - pwr-led = &pwr_led; - uart-0 = &uart0; - i2c-0 = &i2c0; - watchdog0 = &wdt0; - rtc = &pfc8563_rtc; - led0 = &led_pwr; - }; - - chosen { - zephyr,sram = &sram0; - zephyr,console = &uart0; - zephyr,shell-uart = &uart0; - zephyr,flash = &flash0; - zephyr,display = &ili9342c; - zephyr,code-partition = &slot0_partition; - zephyr,rtc = &pfc8563_rtc; - }; - - leds { - compatible = "gpio-leds"; - led_pwr: led_pwr { - gpios = <&axp192_gpio 1 (GPIO_OPEN_DRAIN | GPIO_ACTIVE_LOW)>; - label = "Power LED"; - }; - }; - - lvgl_pointer { - compatible = "zephyr,lvgl-pointer-input"; - input = <&ft5336_touch>; - swap-xy; - }; - - mipi_dbi { - compatible = "zephyr,mipi-dbi-spi"; - dc-gpios = <&gpio0 15 GPIO_ACTIVE_HIGH>; - reset-gpios = <&axp192_gpio 4 (GPIO_OPEN_DRAIN | GPIO_ACTIVE_LOW)>; - spi-dev = <&spi3>; - write-only; - #address-cells = <1>; - #size-cells = <0>; - - ili9342c: ili9342c@0 { - compatible = "ilitek,ili9342c"; - mipi-max-frequency = <30000000>; - reg = <0>; - vin-supply = <&lcd_bg>; - pixel-format = ; - display-inversion; - width = <320>; - height = <240>; - rotation = <0>; - }; - }; -}; - -&cpu0 { - clock-frequency = ; -}; - -&cpu1 { - clock-frequency = ; -}; - -&psram0 { - reg = <0x3f800000 DT_SIZE_M(8)>; - status = "disabled"; -}; - -&uart0 { - status = "okay"; - current-speed = <115200>; - pinctrl-0 = <&uart0_tx_gpio1 &uart0_rx_gpio3>; - pinctrl-names = "default"; -}; - -&uart1 { - status = "disabled"; - current-speed = <115200>; - pinctrl-0 = <&uart1_rx_gpio33 &uart1_tx_gpio32>; - pinctrl-names = "default"; -}; - -&gpio0 { - status = "okay"; -}; - -&gpio1 { - status = "okay"; -}; - -&i2c0 { - status = "okay"; - clock-frequency = ; - sda-gpios = <&gpio0 21 GPIO_OPEN_DRAIN>; - scl-gpios = <&gpio0 22 GPIO_OPEN_DRAIN>; - pinctrl-0 = <&i2c0_default>; - scl-timeout-us = <0>; - pinctrl-names = "default"; - - pfc8563_rtc: pfc8563@51 { - compatible = "nxp,pcf8563"; - reg = <0x51>; - status = "okay"; - }; - - axp192_pmic: axp192@34 { - compatible = "x-powers,axp192"; - reg = <0x34>; - status = "okay"; - - axp192_regulator: axp192_regulator { - compatible = "x-powers,axp192-regulator"; - status = "okay"; - - vdd_mcu: DCDC1 { - regulator-init-microvolt = <3350000>; - regulator-min-microvolt = <3200000>; - regulator-max-microvolt = <3400000>; - regulator-initial-mode = ; - regulator-boot-on; - regulator-always-on; - }; - - lcd_bg: DCDC3 { - regulator-init-microvolt = <2800000>; - regulator-min-microvolt = <2500000>; - regulator-max-microvolt = <3300000>; - regulator-boot-on; - }; - - v_peri: LDO2 { - regulator-init-microvolt = <3300000>; - regulator-min-microvolt = <3200000>; - regulator-max-microvolt = <3300000>; - regulator-boot-on; - }; - - vib_motor: LDO3 { - regulator-init-microvolt = <2800000>; - }; - }; - - axp192_gpio: axp192_gpio { - compatible = "x-powers,axp192-gpio"; - gpio-controller; - #gpio-cells = <2>; - ngpios = <6>; - status = "okay"; - - pwr_led: axp192_gpio1 { - gpio-hog; - gpios = <1 (GPIO_OPEN_DRAIN | GPIO_ACTIVE_LOW)>; - output-high; - line-name = "pwr-led"; - }; - - bus_pwr_en: axp192_gpio0 { - gpio-hog; - gpios = <0 0>; - output-high; - line-name = "bus_pwr_en"; - }; - }; - }; - - bus_5v: bus_5v { - compatible = "regulator-fixed"; - regulator-name = "bus_5v"; - enable-gpios = <&axp192_gpio 5 GPIO_ACTIVE_HIGH>; - }; - - ft5336_touch: ft5336@38 { - compatible = "focaltech,ft5336"; - reg = <0x38>; - int-gpios = <&gpio1 7 0>; - }; -}; - -&i2c1 { - status = "disabled"; - clock-frequency = ; - sda-gpios = <&gpio1 0 GPIO_OPEN_DRAIN>; - scl-gpios = <&gpio1 1 GPIO_OPEN_DRAIN>; - pinctrl-0 = <&i2c1_default>; - pinctrl-names = "default"; -}; - -&spi3 { - #address-cells = <1>; - #size-cells = <0>; - status = "okay"; - pinctrl-0 = <&spim3_default>; - pinctrl-names = "default"; - dma-enabled; - clock-frequency = <20000000>; - cs-gpios = <&gpio0 5 GPIO_ACTIVE_LOW>, - <&gpio0 4 GPIO_ACTIVE_LOW>; - - sdhc0: sdhc@1 { - compatible = "zephyr,sdhc-spi-slot"; - reg = <1>; - status = "okay"; - spi-max-frequency = <20000000>; - mmc { - compatible = "zephyr,sdmmc-disk"; - status = "okay"; - }; - - }; -}; - - -&timer0 { - status = "okay"; -}; - -&timer1 { - status = "okay"; -}; - -&timer2 { - status = "okay"; -}; - -&timer3 { - status = "okay"; -}; - -&trng0 { - status = "okay"; -}; - -&flash0 { - status = "okay"; - reg = <0 DT_SIZE_M(16)>; - - 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>; - }; - - /* 14MB storage */ - storage_partition: partition@250000 { - label = "storage"; - reg = <0x00250000 0x00db0000>; - }; - }; -}; diff --git a/boards/m5stack/m5stack_core2/m5stack_core2_esp32_procpu.yaml b/boards/m5stack/m5stack_core2/m5stack_core2_esp32_procpu.yaml deleted file mode 100644 index b5f7a37910d..00000000000 --- a/boards/m5stack/m5stack_core2/m5stack_core2_esp32_procpu.yaml +++ /dev/null @@ -1,20 +0,0 @@ -identifier: m5stack_core2/esp32/procpu -name: M5Stack Core2 -type: mcu -arch: xtensa -toolchain: - - zephyr -supported: - - gpio - - i2c - - spi - - watchdog - - regulator - - uart - - pinmux - - nvs -testing: - ignore_tags: - - net - - bluetooth -vendor: m5stack diff --git a/boards/m5stack/m5stack_core2/m5stack_core2_procpu.dts b/boards/m5stack/m5stack_core2/m5stack_core2_procpu.dts new file mode 100644 index 00000000000..7cd5bc187c9 --- /dev/null +++ b/boards/m5stack/m5stack_core2/m5stack_core2_procpu.dts @@ -0,0 +1,293 @@ +/* + * Copyright (c) 2023 Martin Kiepfer + * + * SPDX-License-Identifier: Apache-2.0 + */ +/dts-v1/; + +#include +#include "m5stack_core2-pinctrl.dtsi" +#include "grove_connectors.dtsi" +#include "m5stack_mbus_connectors.dtsi" +#include +#include + +/ { + model = "M5Stack Core2 PROCPU"; + compatible = "m5stack,core2"; + + aliases { + pwr-led = &pwr_led; + uart-0 = &uart0; + i2c-0 = &i2c0; + watchdog0 = &wdt0; + rtc = &pfc8563_rtc; + led0 = &led_pwr; + sdhc0 = &sd0; + }; + + chosen { + zephyr,sram = &sram0; + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,flash = &flash0; + zephyr,display = &ili9342c; + zephyr,code-partition = &slot0_partition; + zephyr,rtc = &pfc8563_rtc; + }; + + leds { + compatible = "gpio-leds"; + led_pwr: led_pwr { + gpios = <&axp192_gpio 1 (GPIO_OPEN_DRAIN | GPIO_ACTIVE_LOW)>; + label = "Power LED"; + }; + }; + + lvgl_pointer { + compatible = "zephyr,lvgl-pointer-input"; + input = <&ft5336_touch>; + swap-xy; + }; + + mipi_dbi { + compatible = "zephyr,mipi-dbi-spi"; + dc-gpios = <&gpio0 15 GPIO_ACTIVE_HIGH>; + reset-gpios = <&axp192_gpio 4 (GPIO_OPEN_DRAIN | GPIO_ACTIVE_LOW)>; + spi-dev = <&spi3>; + write-only; + #address-cells = <1>; + #size-cells = <0>; + + ili9342c: ili9342c@0 { + compatible = "ilitek,ili9342c"; + mipi-max-frequency = <30000000>; + reg = <0>; + vin-supply = <&lcd_bg>; + pixel-format = ; + display-inversion; + width = <320>; + height = <240>; + rotation = <0>; + }; + }; +}; + +&cpu0 { + clock-frequency = ; +}; + +&cpu1 { + clock-frequency = ; +}; + +&psram0 { + reg = <0x3f800000 DT_SIZE_M(8)>; + status = "disabled"; +}; + +&uart0 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart0_tx_gpio1 &uart0_rx_gpio3>; + pinctrl-names = "default"; +}; + +&uart1 { + status = "disabled"; + current-speed = <115200>; + pinctrl-0 = <&uart1_rx_gpio33 &uart1_tx_gpio32>; + pinctrl-names = "default"; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&i2c0 { + status = "okay"; + clock-frequency = ; + sda-gpios = <&gpio0 21 GPIO_OPEN_DRAIN>; + scl-gpios = <&gpio0 22 GPIO_OPEN_DRAIN>; + pinctrl-0 = <&i2c0_default>; + scl-timeout-us = <0>; + pinctrl-names = "default"; + + pfc8563_rtc: pfc8563@51 { + compatible = "nxp,pcf8563"; + reg = <0x51>; + status = "okay"; + }; + + axp192_pmic: axp192@34 { + compatible = "x-powers,axp192"; + reg = <0x34>; + status = "okay"; + + axp192_regulator: axp192_regulator { + compatible = "x-powers,axp192-regulator"; + status = "okay"; + + vdd_mcu: DCDC1 { + regulator-init-microvolt = <3350000>; + regulator-min-microvolt = <3200000>; + regulator-max-microvolt = <3400000>; + regulator-initial-mode = ; + regulator-boot-on; + regulator-always-on; + }; + + lcd_bg: DCDC3 { + regulator-init-microvolt = <2800000>; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + }; + + v_peri: LDO2 { + regulator-init-microvolt = <3300000>; + regulator-min-microvolt = <3200000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + }; + + vib_motor: LDO3 { + regulator-init-microvolt = <2800000>; + }; + }; + + axp192_gpio: axp192_gpio { + compatible = "x-powers,axp192-gpio"; + gpio-controller; + #gpio-cells = <2>; + ngpios = <6>; + status = "okay"; + + pwr_led: axp192_gpio1 { + gpio-hog; + gpios = <1 (GPIO_OPEN_DRAIN | GPIO_ACTIVE_LOW)>; + output-high; + line-name = "pwr-led"; + }; + + bus_pwr_en: axp192_gpio0 { + gpio-hog; + gpios = <0 0>; + output-high; + line-name = "bus_pwr_en"; + }; + }; + }; + + bus_5v: bus_5v { + compatible = "regulator-fixed"; + regulator-name = "bus_5v"; + enable-gpios = <&axp192_gpio 5 GPIO_ACTIVE_HIGH>; + }; + + ft5336_touch: ft5336@38 { + compatible = "focaltech,ft5336"; + reg = <0x38>; + int-gpios = <&gpio1 7 0>; + }; +}; + +&i2c1 { + status = "disabled"; + clock-frequency = ; + sda-gpios = <&gpio1 0 GPIO_OPEN_DRAIN>; + scl-gpios = <&gpio1 1 GPIO_OPEN_DRAIN>; + pinctrl-0 = <&i2c1_default>; + pinctrl-names = "default"; +}; + +&spi3 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + pinctrl-0 = <&spim3_default>; + pinctrl-names = "default"; + dma-enabled; + clock-frequency = <20000000>; + cs-gpios = <&gpio0 5 GPIO_ACTIVE_LOW>, + <&gpio0 4 GPIO_ACTIVE_LOW>; + + sd0: sd@1 { + compatible = "zephyr,sdhc-spi-slot"; + reg = <1>; + status = "okay"; + spi-max-frequency = <20000000>; + mmc { + compatible = "zephyr,sdmmc-disk"; + status = "okay"; + }; + + }; +}; + + +&timer0 { + status = "okay"; +}; + +&timer1 { + status = "okay"; +}; + +&timer2 { + status = "okay"; +}; + +&timer3 { + status = "okay"; +}; + +&trng0 { + status = "okay"; +}; + +&flash0 { + status = "okay"; + reg = <0 DT_SIZE_M(16)>; + + 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>; + }; + + /* 14MB storage */ + storage_partition: partition@250000 { + label = "storage"; + reg = <0x00250000 0x00db0000>; + }; + }; +}; diff --git a/boards/m5stack/m5stack_core2/m5stack_core2_procpu.yaml b/boards/m5stack/m5stack_core2/m5stack_core2_procpu.yaml new file mode 100644 index 00000000000..5a95351e16d --- /dev/null +++ b/boards/m5stack/m5stack_core2/m5stack_core2_procpu.yaml @@ -0,0 +1,20 @@ +identifier: m5stack_core2/esp32/procpu +name: M5Stack Core2 PROCPU +type: mcu +arch: xtensa +toolchain: + - zephyr +supported: + - gpio + - i2c + - spi + - watchdog + - regulator + - uart + - pinmux + - nvs +testing: + ignore_tags: + - net + - bluetooth +vendor: m5stack diff --git a/boards/m5stack/m5stack_core2/m5stack_core2_esp32_procpu_defconfig b/boards/m5stack/m5stack_core2/m5stack_core2_procpu_defconfig similarity index 100% rename from boards/m5stack/m5stack_core2/m5stack_core2_esp32_procpu_defconfig rename to boards/m5stack/m5stack_core2/m5stack_core2_procpu_defconfig diff --git a/boards/m5stack/m5stack_stamps3/m5stack_stamps3_esp32s3_appcpu.dts b/boards/m5stack/m5stack_stamps3/m5stack_stamps3_appcpu.dts similarity index 100% rename from boards/m5stack/m5stack_stamps3/m5stack_stamps3_esp32s3_appcpu.dts rename to boards/m5stack/m5stack_stamps3/m5stack_stamps3_appcpu.dts diff --git a/boards/m5stack/m5stack_stamps3/m5stack_stamps3_appcpu.yaml b/boards/m5stack/m5stack_stamps3/m5stack_stamps3_appcpu.yaml new file mode 100644 index 00000000000..9443a7e09c6 --- /dev/null +++ b/boards/m5stack/m5stack_stamps3/m5stack_stamps3_appcpu.yaml @@ -0,0 +1,27 @@ +identifier: m5stack_stamps3/esp32s3/appcpu +name: M5Stack StampS3 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: m5stack diff --git a/boards/m5stack/m5stack_stamps3/m5stack_stamps3_esp32s3_appcpu_defconfig b/boards/m5stack/m5stack_stamps3/m5stack_stamps3_appcpu_defconfig similarity index 100% rename from boards/m5stack/m5stack_stamps3/m5stack_stamps3_esp32s3_appcpu_defconfig rename to boards/m5stack/m5stack_stamps3/m5stack_stamps3_appcpu_defconfig diff --git a/boards/m5stack/m5stack_stamps3/m5stack_stamps3_esp32s3_appcpu.yaml b/boards/m5stack/m5stack_stamps3/m5stack_stamps3_esp32s3_appcpu.yaml deleted file mode 100644 index eb4fcfcd028..00000000000 --- a/boards/m5stack/m5stack_stamps3/m5stack_stamps3_esp32s3_appcpu.yaml +++ /dev/null @@ -1,27 +0,0 @@ -identifier: m5stack_stamps3/esp32s3/appcpu -name: M5Stack StampS3 -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: m5stack diff --git a/boards/m5stack/m5stack_stamps3/m5stack_stamps3_esp32s3_procpu.yaml b/boards/m5stack/m5stack_stamps3/m5stack_stamps3_esp32s3_procpu.yaml deleted file mode 100644 index 99e14f59b19..00000000000 --- a/boards/m5stack/m5stack_stamps3/m5stack_stamps3_esp32s3_procpu.yaml +++ /dev/null @@ -1,20 +0,0 @@ -identifier: m5stack_stamps3/esp32s3/procpu -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/m5stack/m5stack_stamps3/m5stack_stamps3_esp32s3_procpu.dts b/boards/m5stack/m5stack_stamps3/m5stack_stamps3_procpu.dts similarity index 100% rename from boards/m5stack/m5stack_stamps3/m5stack_stamps3_esp32s3_procpu.dts rename to boards/m5stack/m5stack_stamps3/m5stack_stamps3_procpu.dts diff --git a/boards/m5stack/m5stack_stamps3/m5stack_stamps3_procpu.yaml b/boards/m5stack/m5stack_stamps3/m5stack_stamps3_procpu.yaml new file mode 100644 index 00000000000..746a5d2916e --- /dev/null +++ b/boards/m5stack/m5stack_stamps3/m5stack_stamps3_procpu.yaml @@ -0,0 +1,20 @@ +identifier: m5stack_stamps3/esp32s3/procpu +name: M5Stack StampS3 PROCPU +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/m5stack/m5stack_stamps3/m5stack_stamps3_esp32s3_procpu_defconfig b/boards/m5stack/m5stack_stamps3/m5stack_stamps3_procpu_defconfig similarity index 100% rename from boards/m5stack/m5stack_stamps3/m5stack_stamps3_esp32s3_procpu_defconfig rename to boards/m5stack/m5stack_stamps3/m5stack_stamps3_procpu_defconfig diff --git a/boards/m5stack/m5stickc_plus/Kconfig.defconfig b/boards/m5stack/m5stickc_plus/Kconfig.defconfig index 638a054bec1..aea1b614a01 100644 --- a/boards/m5stack/m5stickc_plus/Kconfig.defconfig +++ b/boards/m5stack/m5stickc_plus/Kconfig.defconfig @@ -16,6 +16,21 @@ choice BT_HCI_BUS_TYPE default BT_ESP32 if BT endchoice +config GPIO_HOGS_INIT_PRIORITY + default 70 + +config MFD_INIT_PRIORITY + default 70 + +config REGULATOR_AXP192_INIT_PRIORITY + default 71 + +config GPIO_AXP192_INIT_PRIORITY + default 72 + +config REGULATOR_FIXED_INIT_PRIORITY + default 75 + endif # BOARD_M5STICKC_PLUS_ESP32_PROCPU if BOARD_M5STICKC_PLUS_ESP32_APPCPU diff --git a/boards/m5stack/m5stickc_plus/m5stickc_plus-pinctrl.dtsi b/boards/m5stack/m5stickc_plus/m5stickc_plus-pinctrl.dtsi index d711fc9880b..d41decd3e96 100644 --- a/boards/m5stack/m5stickc_plus/m5stickc_plus-pinctrl.dtsi +++ b/boards/m5stack/m5stickc_plus/m5stickc_plus-pinctrl.dtsi @@ -37,35 +37,25 @@ pinmux = ; }; - spim3_miso_gpio25: spim3_miso_gpio25 { - pinmux = ; + spim3_default: spim3_default { + group1 { + pinmux = , + , + ; + }; + group2 { + pinmux = ; + output-low; + }; + }; + + i2c0_default: i2c0_default { + group1 { + pinmux = , + ; + bias-pull-up; + drive-open-drain; + output-high; + }; }; - - spim3_mosi_gpio15: spim3_mosi_gpio15 { - pinmux = ; - output-low; - }; - - spim3_sclk_gpio13: spim3_sclk_gpio13 { - pinmux = ; - }; - - spim3_csel_gpio5: spim3_csel_gpio5 { - pinmux = ; - }; - - i2c0_sda_gpio21: i2c0_sda_gpio21 { - pinmux = ; - bias-pull-up; - drive-open-drain; - output-high; - }; - - i2c0_scl_gpio22: i2c0_scl_gpio22 { - pinmux = ; - bias-pull-up; - drive-open-drain; - output-high; - }; - }; diff --git a/boards/m5stack/m5stickc_plus/m5stickc_plus_esp32_appcpu.dts b/boards/m5stack/m5stickc_plus/m5stickc_plus_appcpu.dts similarity index 100% rename from boards/m5stack/m5stickc_plus/m5stickc_plus_esp32_appcpu.dts rename to boards/m5stack/m5stickc_plus/m5stickc_plus_appcpu.dts diff --git a/boards/m5stack/m5stickc_plus/m5stickc_plus_appcpu.yaml b/boards/m5stack/m5stickc_plus/m5stickc_plus_appcpu.yaml new file mode 100644 index 00000000000..ac942189097 --- /dev/null +++ b/boards/m5stack/m5stickc_plus/m5stickc_plus_appcpu.yaml @@ -0,0 +1,27 @@ +identifier: m5stickc_plus/esp32/appcpu +name: M5StickC PLUS 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: m5stack diff --git a/boards/m5stack/m5stickc_plus/m5stickc_plus_esp32_appcpu_defconfig b/boards/m5stack/m5stickc_plus/m5stickc_plus_appcpu_defconfig similarity index 100% rename from boards/m5stack/m5stickc_plus/m5stickc_plus_esp32_appcpu_defconfig rename to boards/m5stack/m5stickc_plus/m5stickc_plus_appcpu_defconfig diff --git a/boards/m5stack/m5stickc_plus/m5stickc_plus_esp32_appcpu.yaml b/boards/m5stack/m5stickc_plus/m5stickc_plus_esp32_appcpu.yaml deleted file mode 100644 index e436849ced4..00000000000 --- a/boards/m5stack/m5stickc_plus/m5stickc_plus_esp32_appcpu.yaml +++ /dev/null @@ -1,27 +0,0 @@ -identifier: m5stickc_plus/esp32/appcpu -name: M5StickC PLUS -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: m5stack diff --git a/boards/m5stack/m5stickc_plus/m5stickc_plus_esp32_procpu.dts b/boards/m5stack/m5stickc_plus/m5stickc_plus_esp32_procpu.dts deleted file mode 100644 index 2f0f6975bba..00000000000 --- a/boards/m5stack/m5stickc_plus/m5stickc_plus_esp32_procpu.dts +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright (c) 2022 AVSystem Sławomir Wolf Sp.j. (AVSystem) - * - * SPDX-License-Identifier: Apache-2.0 - */ -/dts-v1/; - -#include -#include "m5stickc_plus-pinctrl.dtsi" -#include - -/ { - model = "M5StickC Plus PROCPU"; - compatible = "m5stack,m5stickc-plus"; - - aliases { - led0 = &red_led; - sw0 = &user_button_0; - sw1 = &user_button_1; - uart-0 = &uart0; - i2c-0 = &i2c0; - 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"; - - red_led: led_0 { - gpios = <&gpio0 10 GPIO_ACTIVE_HIGH>; - label = "Red - LED0"; - }; - }; - - gpio_keys { - compatible = "gpio-keys"; - - user_button_0: button_0 { - label = "User button 0"; - gpios = <&gpio1 5 GPIO_ACTIVE_LOW>; - zephyr,code = ; - }; - user_button_1: button_1 { - label = "User button 1"; - gpios = <&gpio1 7 GPIO_ACTIVE_LOW>; - zephyr,code = ; - }; - }; -}; - -&cpu0 { - clock-frequency = ; -}; - -&cpu1 { - clock-frequency = ; -}; - -&uart0 { - status = "okay"; - current-speed = <115200>; - pinctrl-0 = <&uart0_tx_gpio1 &uart0_rx_gpio3>; - pinctrl-names = "default"; -}; - -&gpio0 { - status = "okay"; -}; - -&gpio1 { - status = "okay"; -}; - -/* IMU MPU-6886, RTC BM8563, PMU AXP192 */ -&i2c0 { - status = "okay"; - clock-frequency = ; - sda-gpios = <&gpio0 21 GPIO_OPEN_DRAIN>; - scl-gpios = <&gpio0 22 GPIO_OPEN_DRAIN>; - pinctrl-0 = <&i2c0_sda_gpio21 &i2c0_scl_gpio22>; - pinctrl-names = "default"; -}; - -&spi2 { - #address-cells = <1>; - #size-cells = <0>; - status = "okay"; - pinctrl-0 = <&spim2_miso_gpio12 &spim2_mosi_gpio11 - &spim2_sclk_gpio14 &spim2_csel_gpio16>; - pinctrl-names = "default"; -}; - -/* LCD TFT 1.14", 135x240 px, ST7789v2 */ -&spi3 { - #address-cells = <1>; - #size-cells = <0>; - status = "okay"; - pinctrl-0 = <&spim3_miso_gpio25 &spim3_mosi_gpio15 - &spim3_sclk_gpio13 &spim3_csel_gpio5>; - pinctrl-names = "default"; -}; - -&timer0 { - status = "okay"; -}; - -&timer1 { - status = "okay"; -}; - -&timer2 { - status = "okay"; -}; - -&timer3 { - status = "okay"; -}; - -&trng0 { - status = "okay"; -}; - -&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/m5stack/m5stickc_plus/m5stickc_plus_esp32_procpu.yaml b/boards/m5stack/m5stickc_plus/m5stickc_plus_esp32_procpu.yaml deleted file mode 100644 index 24499601d4a..00000000000 --- a/boards/m5stack/m5stickc_plus/m5stickc_plus_esp32_procpu.yaml +++ /dev/null @@ -1,19 +0,0 @@ -identifier: m5stickc_plus/esp32/procpu -name: M5StickC PLUS -type: mcu -arch: xtensa -toolchain: - - zephyr -supported: - - gpio - - i2c - - spi - - watchdog - - uart - - pinmux - - nvs -testing: - ignore_tags: - - net - - bluetooth -vendor: m5stack diff --git a/boards/m5stack/m5stickc_plus/m5stickc_plus_esp32_procpu_defconfig b/boards/m5stack/m5stickc_plus/m5stickc_plus_esp32_procpu_defconfig deleted file mode 100644 index ee9920cda68..00000000000 --- a/boards/m5stack/m5stickc_plus/m5stickc_plus_esp32_procpu_defconfig +++ /dev/null @@ -1,10 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -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/m5stack/m5stickc_plus/m5stickc_plus_procpu.dts b/boards/m5stack/m5stickc_plus/m5stickc_plus_procpu.dts new file mode 100644 index 00000000000..c1418ed51c3 --- /dev/null +++ b/boards/m5stack/m5stickc_plus/m5stickc_plus_procpu.dts @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2022 AVSystem Sławomir Wolf Sp.j. (AVSystem) + * + * SPDX-License-Identifier: Apache-2.0 + */ +/dts-v1/; + +#include +#include "m5stickc_plus-pinctrl.dtsi" +#include +#include + +/ { + model = "M5StickC Plus PROCPU"; + compatible = "m5stack,m5stickc-plus"; + + aliases { + led0 = &red_led; + sw0 = &user_button_0; + sw1 = &user_button_1; + uart-0 = &uart0; + i2c-0 = &i2c0; + watchdog0 = &wdt0; + accel0 = &mpu6886; + rtc = &bm8563; + }; + + chosen { + zephyr,sram = &sram0; + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; + zephyr,rtc = &bm8563; + zephyr,display = &st7789v; + }; + + leds { + compatible = "gpio-leds"; + + red_led: led_0 { + gpios = <&gpio0 10 GPIO_ACTIVE_HIGH>; + label = "Red - LED0"; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + + user_button_0: button_0 { + label = "User button 0"; + gpios = <&gpio1 5 GPIO_ACTIVE_LOW>; + zephyr,code = ; + }; + user_button_1: button_1 { + label = "User button 1"; + gpios = <&gpio1 7 GPIO_ACTIVE_LOW>; + zephyr,code = ; + }; + }; +}; + +&cpu0 { + clock-frequency = ; +}; + +&cpu1 { + clock-frequency = ; +}; + +&uart0 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart0_tx_gpio1 &uart0_rx_gpio3>; + pinctrl-names = "default"; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +/* IMU MPU-6886, RTC BM8563, PMU AXP192 */ +&i2c0 { + status = "okay"; + clock-frequency = ; + sda-gpios = <&gpio0 21 GPIO_OPEN_DRAIN>; + scl-gpios = <&gpio0 22 GPIO_OPEN_DRAIN>; + pinctrl-0 = <&i2c0_default>; + scl-timeout-us = <0>; + pinctrl-names = "default"; + + axp192_pmic: axp192@34 { + compatible = "x-powers,axp192"; + reg = <0x34>; + status = "okay"; + + axp192_regulator: axp192_regulator { + compatible = "x-powers,axp192-regulator"; + status = "okay"; + + vdd_mcu: DCDC1 { + regulator-init-microvolt = <3350000>; + regulator-min-microvolt = <3200000>; + regulator-max-microvolt = <3400000>; + regulator-initial-mode = ; + regulator-boot-on; + regulator-always-on; + }; + + lcd_bl: LDO2 { + regulator-init-microvolt = <2800000>; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3000000>; + regulator-boot-on; + }; + + lcd_logic: LDO3 { + regulator-init-microvolt = <3000000>; + }; + }; + axp192_gpio: axp192_gpio { + compatible = "x-powers,axp192-gpio"; + gpio-controller; + #gpio-cells = <2>; + ngpios = <6>; + status = "okay"; + }; + }; + + mpu6886: mpu6886@68 { + status = "okay"; + compatible = "invensense,mpu6050"; + reg = <0x68>; + }; + + bm8563: bm8563@51 { + compatible = "nxp,pcf8563"; + reg = <0x51>; + status = "okay"; + }; +}; + +&spi2 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + pinctrl-0 = <&spim2_miso_gpio12 &spim2_mosi_gpio11 + &spim2_sclk_gpio14 &spim2_csel_gpio16>; + pinctrl-names = "default"; +}; + +/* LCD TFT 1.14", 135x240 px, ST7789v2 */ +&spi3 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + pinctrl-0 = <&spim3_default>; + pinctrl-names = "default"; + st7789v: st7789v@0 { + compatible = "sitronix,st7789v"; + reg = <0>; + spi-max-frequency = <20000000>; + cmd-data-gpios = <&gpio0 23 GPIO_ACTIVE_LOW>; + reset-gpios = <&gpio0 18 GPIO_ACTIVE_LOW>; + + width = <135>; + height = <240>; + x-offset = <53>; + y-offset = <40>; + + vcom = <0x28>; + gctrl = <0x35>; + vrhs = <0x10>; + vdvs = <0x20>; + mdac = <0x00>; + gamma = <0x01>; + colmod = <0x55>; + lcm = <0x2c>; + 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 F0]; + rgb-param = [40 02 14]; + }; +}; + +&timer0 { + status = "okay"; +}; + +&timer1 { + status = "okay"; +}; + +&timer2 { + status = "okay"; +}; + +&timer3 { + status = "okay"; +}; + +&trng0 { + status = "okay"; +}; + +&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/m5stack/m5stickc_plus/m5stickc_plus_procpu.yaml b/boards/m5stack/m5stickc_plus/m5stickc_plus_procpu.yaml new file mode 100644 index 00000000000..69741a72d8f --- /dev/null +++ b/boards/m5stack/m5stickc_plus/m5stickc_plus_procpu.yaml @@ -0,0 +1,21 @@ +identifier: m5stickc_plus/esp32/procpu +name: M5StickC PLUS PROCPU +type: mcu +arch: xtensa +toolchain: + - zephyr +supported: + - gpio + - i2c + - spi + - watchdog + - uart + - pinmux + - nvs + - regulator + - display +testing: + ignore_tags: + - net + - bluetooth +vendor: m5stack diff --git a/boards/m5stack/m5stickc_plus/m5stickc_plus_procpu_defconfig b/boards/m5stack/m5stickc_plus/m5stickc_plus_procpu_defconfig new file mode 100644 index 00000000000..6b210f481bc --- /dev/null +++ b/boards/m5stack/m5stickc_plus/m5stickc_plus_procpu_defconfig @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_MAIN_STACK_SIZE=2048 + +CONFIG_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_UART_CONSOLE=y + +CONFIG_REGULATOR=y + +CONFIG_GPIO=y +CONFIG_I2C=y diff --git a/boards/m5stack/stamp_c3/stamp_c3.dts b/boards/m5stack/stamp_c3/stamp_c3.dts index 56353da3d81..812c2aeaa86 100644 --- a/boards/m5stack/stamp_c3/stamp_c3.dts +++ b/boards/m5stack/stamp_c3/stamp_c3.dts @@ -93,7 +93,6 @@ status = "disabled"; pinctrl-0 = <&twai_default>; pinctrl-names = "default"; - bus-speed = <125000>; }; &flash0 { diff --git a/boards/madmachine/mm_swiftio/mm_swiftio.dts b/boards/madmachine/mm_swiftio/mm_swiftio.dts index b9994d1e8c1..e4212cd8294 100644 --- a/boards/madmachine/mm_swiftio/mm_swiftio.dts +++ b/boards/madmachine/mm_swiftio/mm_swiftio.dts @@ -192,7 +192,7 @@ &csi { status = "okay"; - sensor = <&ov7725>; + source = <&ov7725>; pinctrl-0 = <&pinmux_csi>; pinctrl-names = "default"; diff --git a/boards/microchip/mpfs_icicle/board.yml b/boards/microchip/mpfs_icicle/board.yml index a4976aa909b..f97e2409c14 100644 --- a/boards/microchip/mpfs_icicle/board.yml +++ b/boards/microchip/mpfs_icicle/board.yml @@ -3,3 +3,5 @@ board: vendor: microchip socs: - name: polarfire + variants: + - name: 'smp' diff --git a/boards/microchip/mpfs_icicle/doc/index.rst b/boards/microchip/mpfs_icicle/doc/index.rst index 7a599081793..203745dc4ee 100644 --- a/boards/microchip/mpfs_icicle/doc/index.rst +++ b/boards/microchip/mpfs_icicle/doc/index.rst @@ -23,6 +23,11 @@ Applications for the ``mpfs_icicle`` board configuration can be built as usual :board: mpfs_icicle :goals: build +To build the default SMP capable variant + +.. zephyr-app-commands:: + :board: mpfs_icicle/polarfire/smp + :goals: build Flashing ======== diff --git a/boards/microchip/mpfs_icicle/mpfs_icicle_smp.dts b/boards/microchip/mpfs_icicle/mpfs_icicle_smp.dts new file mode 100644 index 00000000000..6d122ed5d97 --- /dev/null +++ b/boards/microchip/mpfs_icicle/mpfs_icicle_smp.dts @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2020-2021 Microchip Technology Inc + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include +#include + +/ { + model = "Microchip PolarFire-SoC Icicle Kit"; + compatible = "microchip,mpfs-icicle-kit", "microchip,mpfs"; + + cpus { + cpu@0 { + status = "disabled"; + }; + }; + + aliases { + led0 = &led0; + sw0 = &sw0; + i2c0 = &i2c0; + i2c1 = &i2c1; + }; + + chosen { + zephyr,console = &uart1; + zephyr,shell-uart = &uart1; + zephyr,sram = &sram1; + }; + + leds { + compatible = "gpio-leds"; + + led0: led0 { + gpios = <&gpio2 16 GPIO_ACTIVE_LOW>; + label = "LED_0"; + }; + }; + + keys { + compatible = "gpio-keys"; + sw0: sw0 { + gpios = <&gpio2 30 GPIO_ACTIVE_LOW>; + label = "SW_0"; + zephyr,code = ; + }; + }; +}; + +&uart1 { + status = "okay"; + current-speed = <115200>; + clock-frequency = <150000000>; +}; + +&qspi0 { + status = "okay"; + qspi_flash: spi-nor-flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <5000000>; + size = ; + jedec-id = [20 ba 19]; + }; +}; + +&spi1 { + status = "okay"; +}; + +&syscontroller_qspi { + status = "okay"; + sys_ctrl_flash: spi-nor-flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <5000000>; + }; +}; + +&gpio2 { + status = "okay"; +}; + +&i2c0 { + status = "okay"; +}; + +&i2c1 { + status = "okay"; +}; diff --git a/boards/microchip/mpfs_icicle/mpfs_icicle_smp.yaml b/boards/microchip/mpfs_icicle/mpfs_icicle_smp.yaml new file mode 100644 index 00000000000..2f7983ca092 --- /dev/null +++ b/boards/microchip/mpfs_icicle/mpfs_icicle_smp.yaml @@ -0,0 +1,12 @@ +identifier: mpfs_icicle/polarfire/smp +name: Microchip PolarFire ICICLE kit (SMP) +type: mcu +arch: riscv +toolchain: + - zephyr +ram: 3840 +testing: + ignore_tags: + - net + - bluetooth +vendor: microchip diff --git a/boards/microchip/mpfs_icicle/mpfs_icicle_smp_defconfig b/boards/microchip/mpfs_icicle/mpfs_icicle_smp_defconfig new file mode 100644 index 00000000000..529171d1c46 --- /dev/null +++ b/boards/microchip/mpfs_icicle/mpfs_icicle_smp_defconfig @@ -0,0 +1,14 @@ +CONFIG_MPFS_HAL=n +CONFIG_BASE64=y +CONFIG_INCLUDE_RESET_VECTOR=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_GPIO=y +CONFIG_I2C=y +CONFIG_SMP=y +CONFIG_RV_BOOT_HART=1 +CONFIG_MP_MAX_NUM_CPUS=4 diff --git a/boards/native/doc/bsim_boards_design.rst b/boards/native/doc/bsim_boards_design.rst index 6165f76a438..7fef9d1b522 100644 --- a/boards/native/doc/bsim_boards_design.rst +++ b/boards/native/doc/bsim_boards_design.rst @@ -7,6 +7,7 @@ Bsim boards * :ref:`Simulated nRF52833 (nrf52_bsim)` * :ref:`Simulated nRF5340 (nrf5340bsim)` +* :ref:`Simulated nRF54L15 (nrf54l15bsim)` .. contents:: Table of contents :depth: 2 @@ -20,8 +21,8 @@ These boards are postfixed with `_bsim` as they use BabbleSim_ 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, +Particular details on the :ref:`nRF52`, :ref:`nRF5340` and +:ref:`nRF54l15` simulation boards, including how to use them, can be found in their respective documentation. .. _BabbleSim: diff --git a/boards/native/native_posix/Kconfig.defconfig b/boards/native/native_posix/Kconfig.defconfig index 5fc24d50c62..9132dd9c14d 100644 --- a/boards/native/native_posix/Kconfig.defconfig +++ b/boards/native/native_posix/Kconfig.defconfig @@ -27,16 +27,6 @@ choice BT_HCI_BUS_TYPE depends on BT_HCI endchoice -if LOG - -# For native_posix we can log synchronously without any problem -# Doing so will be nicer for debugging -choice LOG_MODE - default LOG_MODE_IMMEDIATE -endchoice - -endif # LOG - if CONSOLE config POSIX_ARCH_CONSOLE @@ -47,18 +37,6 @@ config UART_CONSOLE endif # CONSOLE -config FLASH_SIMULATOR - default y - depends on FLASH - -config USB_NATIVE_POSIX - default y - depends on USB_DEVICE_DRIVER - -config EEPROM_SIMULATOR - default y - depends on EEPROM - if I2C config EMUL diff --git a/boards/native/native_posix/main.c b/boards/native/native_posix/main.c index 5e603ac6efd..f68f4dbf0e3 100644 --- a/boards/native/native_posix/main.c +++ b/boards/native/native_posix/main.c @@ -118,40 +118,4 @@ int main(int argc, char *argv[]) return 1; /* LCOV_EXCL_LINE */ } -#else /* CONFIG_ARCH_POSIX_LIBFUZZER */ - -const uint8_t *posix_fuzz_buf; -size_t posix_fuzz_sz; - -/** - * Entry point for fuzzing (when enabled). Works by placing the data - * into two known symbols, triggering an app-visible interrupt, and - * then letting the OS run for a fixed amount of time (intended to be - * "long enough" to handle the event and reach a quiescent state - * again) - */ -int LLVMFuzzerTestOneInput(const uint8_t *data, size_t sz) -{ - static bool posix_initialized; - - if (!posix_initialized) { - posix_init(0, NULL); - posix_initialized = true; - } - - /* Provide the fuzz data to Zephyr as an interrupt, with - * "DMA-like" data placed into posix_fuzz_buf/sz - */ - posix_fuzz_buf = data; - posix_fuzz_sz = sz; - hw_irq_ctrl_set_irq(CONFIG_ARCH_POSIX_FUZZ_IRQ); - - /* Give the OS time to process whatever happened in that - * interrupt and reach an idle state. - */ - posix_exec_for(k_ticks_to_us_ceil64(CONFIG_ARCH_POSIX_FUZZ_TICKS)); - - return 0; -} - #endif diff --git a/boards/native/native_sim/Kconfig.defconfig b/boards/native/native_sim/Kconfig.defconfig index 64657779d7a..e154d43a525 100644 --- a/boards/native/native_sim/Kconfig.defconfig +++ b/boards/native/native_sim/Kconfig.defconfig @@ -27,16 +27,6 @@ choice BT_HCI_BUS_TYPE depends on BT_HCI endchoice -if LOG - -# For native_sim we can log synchronously without any problem -# Doing so will be nicer for debugging -choice LOG_MODE - default LOG_MODE_IMMEDIATE -endchoice - -endif # LOG - if CONSOLE config POSIX_ARCH_CONSOLE @@ -47,18 +37,6 @@ config UART_CONSOLE endif # CONSOLE -config FLASH_SIMULATOR - default y - depends on FLASH - -config USB_NATIVE_POSIX - default y - depends on USB_DEVICE_DRIVER - -config EEPROM_SIMULATOR - default y - depends on EEPROM - if I2C config EMUL diff --git a/boards/native/native_sim/native_sim.dts b/boards/native/native_sim/native_sim.dts index aa4f2eab0c8..87d6297f749 100644 --- a/boards/native/native_sim/native_sim.dts +++ b/boards/native/native_sim/native_sim.dts @@ -161,10 +161,9 @@ compatible = "zephyr,native-posix-counter"; }; - gpio0: gpio@800 { + gpio0: gpio_emul { status = "okay"; compatible = "zephyr,gpio-emul"; - reg = <0x800 0x4>; rising-edge; falling-edge; high-level; @@ -190,7 +189,6 @@ can_loopback0: can_loopback0 { status = "okay"; compatible = "zephyr,can-loopback"; - bus-speed = <125000>; }; can0: can { @@ -200,7 +198,6 @@ * name, e.g.: sudo ip link property add dev vcan0 altname zcan0 */ host-interface = "zcan0"; - bus-speed = <125000>; }; rtc: rtc { diff --git a/boards/native/nrf_bsim/CMakeLists.txt b/boards/native/nrf_bsim/CMakeLists.txt index a4329cd8880..d55a52e1a53 100644 --- a/boards/native/nrf_bsim/CMakeLists.txt +++ b/boards/native/nrf_bsim/CMakeLists.txt @@ -6,6 +6,10 @@ find_package(BabbleSim) zephyr_library() +if (CONFIG_BOARD_NRF54L15BSIM_NRF54L15_CPUFLPR) + message(FATAL_ERROR "Targeting the nrf54l15bsim/nrf54l15/cpuflpr core is not yet supported") +endif() + # Due to the BLE controller assumption about enum size zephyr_compile_options( -fshort-enums diff --git a/boards/native/nrf_bsim/Kconfig b/boards/native/nrf_bsim/Kconfig index caed5baf8b6..0273667c415 100644 --- a/boards/native/nrf_bsim/Kconfig +++ b/boards/native/nrf_bsim/Kconfig @@ -34,6 +34,17 @@ config BOARD_NRF5340BSIM_NRF5340_CPUAPP 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_NRF54L15BSIM_NRF54L15_CPUAPP + bool + select SOC_SERIES_BSIM_NRF54LX + select SOC_COMPATIBLE_NRF54L15 + select SOC_COMPATIBLE_NRF54L15_CPUAPP + select CLOCK_CONTROL + help + Simulated NRF54L15 Application core + Will produce a console Linux process which can be executed natively. + It needs the BabbleSim simulator both in compile time and to execute + if SOC_SERIES_BSIM_NRFXX @@ -76,6 +87,13 @@ config SOC_SERIES_BSIM_NRF53X help Any NRF53 simulated SOC with BabbleSim, based on the POSIX arch +config SOC_SERIES_BSIM_NRF54LX + bool + select SOC_SERIES_BSIM_NRFXX + select SOC_COMPATIBLE_NRF54LX + help + Any NRF54L 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 diff --git a/boards/native/nrf_bsim/Kconfig.defconfig b/boards/native/nrf_bsim/Kconfig.defconfig index 639c5d47428..81f90836b54 100644 --- a/boards/native/nrf_bsim/Kconfig.defconfig +++ b/boards/native/nrf_bsim/Kconfig.defconfig @@ -30,10 +30,12 @@ config NATIVE_SIMULATOR_PRIMARY_MCU_INDEX default 0 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 BT_CTLR @@ -70,16 +72,6 @@ endif # BOARD_NRF5340BSIM_NRF5340_CPUAPP config NRF_802154_ENCRYPTION default n -if LOG - -# For this board we can log synchronously without any problem -# Doing so will be nicer for debugging -choice LOG_MODE - default LOG_MODE_IMMEDIATE -endchoice - -endif # LOG - if CONSOLE config POSIX_ARCH_CONSOLE diff --git a/boards/native/nrf_bsim/Kconfig.nrf54l15bsim b/boards/native/nrf_bsim/Kconfig.nrf54l15bsim new file mode 100644 index 00000000000..d3ef1f5ffa2 --- /dev/null +++ b/boards/native/nrf_bsim/Kconfig.nrf54l15bsim @@ -0,0 +1,5 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_NRF54L15BSIM + select SOC_POSIX diff --git a/boards/native/nrf_bsim/board.yml b/boards/native/nrf_bsim/board.yml index 874c661c380..ba14ed8aef6 100644 --- a/boards/native/nrf_bsim/board.yml +++ b/boards/native/nrf_bsim/board.yml @@ -6,6 +6,10 @@ boards: - name: nrf5340bsim vendor: zephyr socs: - # Note this is referring to the real SOC yaml, but we only use its name and cpu-cluster definition - # In practice this board uses the same native SOC (SOC_POSIX) as the nrf52_bsim - name: nrf5340 +- name: nrf54l15bsim + vendor: zephyr + socs: + - name: nrf54l15 +# Note the 53 and 54 are referring to the real SOC yamls, but we only use their name and cpu-cluster +# definitions. In practice these board uses the same native SOC (SOC_POSIX) as the nrf52_bsim diff --git a/boards/native/nrf_bsim/board_soc.h b/boards/native/nrf_bsim/board_soc.h index d75a187aa61..e0b1cb60a59 100644 --- a/boards/native/nrf_bsim/board_soc.h +++ b/boards/native/nrf_bsim/board_soc.h @@ -31,12 +31,15 @@ #include "cmsis.h" #include "soc_nrf_common.h" +/* For offloading interrupts we can use any free interrupt */ #if defined(CONFIG_BOARD_NRF52_BSIM) #define OFFLOAD_SW_IRQ SWI0_EGU0_IRQn #elif defined(CONFIG_BOARD_NRF5340BSIM_NRF5340_CPUAPP) #define OFFLOAD_SW_IRQ EGU0_IRQn #elif defined(CONFIG_BOARD_NRF5340BSIM_NRF5340_CPUNET) #define OFFLOAD_SW_IRQ SWI0_IRQn +#elif defined(CONFIG_BOARD_NRF54L15BSIM) +#define OFFLOAD_SW_IRQ SWI00_IRQn #endif #define FLASH_PAGE_ERASE_MAX_TIME_US 89700UL diff --git a/boards/native/nrf_bsim/common/bstests_entry.c b/boards/native/nrf_bsim/common/bstests_entry.c index c1f08deb9cd..7b22a50ebf5 100644 --- a/boards/native/nrf_bsim/common/bstests_entry.c +++ b/boards/native/nrf_bsim/common/bstests_entry.c @@ -74,7 +74,7 @@ static struct bst_test_instance *bst_test_find(struct bst_test_list *tests, return NULL; } -void bst_install_tests(void) +__noubsan void bst_install_tests(void) { int idx = 0; @@ -224,6 +224,13 @@ void bst_main(void) */ uint8_t bst_delete(void) { + static bool already_deleted; + + if (already_deleted) { + return bst_result; + } + already_deleted = true; + if (current_test && current_test->test_delete_f) { current_test->test_delete_f(); } diff --git a/boards/native/nrf_bsim/doc/nrf54l15bsim.rst b/boards/native/nrf_bsim/doc/nrf54l15bsim.rst new file mode 100644 index 00000000000..702ff50f851 --- /dev/null +++ b/boards/native/nrf_bsim/doc/nrf54l15bsim.rst @@ -0,0 +1,89 @@ +.. _nrf54l15bsim: + +NRF54L15 simulated boards (BabbleSim) +##################################### + +.. contents:: + :depth: 1 + :backlinks: entry + :local: + + +Overview +******** + +To allow simulating nRF54L15 SOCs a Zephyr target boards is provided: the +``nrf54l15bsim/nrf54l15/cpuapp``. + +This uses `BabbleSim`_ to simulate the radio activity, and the +:ref:`POSIX architecture` and the `native simulator`_ to +run applications natively on the development system. This has the benefit of +providing native code execution performance and easy debugging using +native tools, but inherits :ref:`its limitations `. + +Just like for the nrf54l15pdk target, +the nrf54l15bsim/nrf54l15/cpuapp build target provides support for the application core, +on the simulated nRF54L15 SOC. + +.. note:: + + This simulated target does **not** yet support targeting the cpuflpr core. + +.. warning:: + + This target is experimental, and does not yet include models of the RADIO peripheral, + so the BLE and 802.15.4 stacks cannot be run on it yet. + +This boards include models of some of the nRF54L15 SOC peripherals: + +* DPPI (Distributed Programmable Peripheral Interconnect) +* EGU (Event Generator Unit) +* FICR (Factory Information Configuration Registers) +* GRTC (Global Real-time Counter) +* PPIB (PPI Bridge) +* RRAMC (Resistive RAM Controller) +* RTC (Real Time Counter) +* TEMP (Temperature sensor) +* TIMER +* UICR (User Information Configuration Registers) + +and will use the same drivers as the nrf54l15pdk targets for these. +For more information on what is modeled to which level of detail, +check the `HW models implementation status`_. + +Note that unlike a real nrf54l15 device, the nrf54l15bsim boards have unlimited RAM, and code does +not occupy their RRAM. + +.. _BabbleSim: + https://BabbleSim.github.io + +.. _native simulator: + https://github.com/BabbleSim/native_simulator/blob/main/docs/README.md + +.. _HW models implementation status: + https://github.com/BabbleSim/ext_nRF_hw_models/blob/main/docs/README_impl_status.md + + +Building for, and using this board +********************************** + +You can follow the instructions from the :ref:`nrf52_bsim board `. +Simply change the board/target appropriately when building. + + +TrustZone, TF-M and other security considerations +************************************************* + +ARM's TrustZone is not modeled in this board. This means that: + +* There is no differentiation between secure and non secure execution states or bus accesses. +* All RAM, flash and peripherals are in principle accessible from all SW. Peripherals with their + own interconnect master ports can, in principle, access any other peripheral or RAM area. +* There is no nrf54l15bsim/nrf54l15/cpuapp/ns board/build target, or possibility of mixing secure + and non-secure images. +* Currently there is no model of the SPU, and therefore neither RRAM, RAM areas or peripherals + can be labeled as restricted for secure or non secure access. +* TF-M cannot be used. + +Note that the CRACEN peripheral is not modeled. The mbedTLS library can still be used +but with a SW crypto backend. diff --git a/boards/native/nrf_bsim/nrf54l15bsim_nrf54l15_cpuapp.dts b/boards/native/nrf_bsim/nrf54l15bsim_nrf54l15_cpuapp.dts new file mode 100644 index 00000000000..ff4aef337f2 --- /dev/null +++ b/boards/native/nrf_bsim/nrf54l15bsim_nrf54l15_cpuapp.dts @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include + +/ { + model = "Nordic NRF54L15 BSIM NRF54L15 Application"; + compatible = "bsim,nrf54l15-bsim-nrf54l15-cpuapp", "bsim,nrf54"; + + chosen { + zephyr,entropy = &rng; + zephyr,flash-controller = &rram_controller; + zephyr,flash = &cpuapp_rram; + }; + + /delete-node/ cpus; + /delete-node/ clocks; + /delete-node/ sw-pwm; + + soc { + /delete-node/ memory@20000000; + /delete-node/ memory@2002f000; + peripheral@50000000 { + /delete-node/ spi@4a000; + /delete-node/ uart@4a000; + /delete-node/ vpr@4c000; + /delete-node/ mailbox@0; + /delete-node/ interrupt-controller@f0000000; + /delete-node/ gpio@50400; + /delete-node/ radio@8a000; + /delete-node/ i2c@c6000; + /delete-node/ spi@c6000; + /delete-node/ uart@c6000; + /delete-node/ i2c@c7000; + /delete-node/ spi@c7000; + /delete-node/ uart@c7000; + /delete-node/ i2c@c8000; + /delete-node/ spi@c8000; + /delete-node/ uart@c8000; + /delete-node/ pwm@d2000; + /delete-node/ pwm@d3000; + /delete-node/ pwm@d4000; + /delete-node/ adc@d5000; + /delete-node/ nfct@d6000; + /delete-node/ gpio@d8200; + /delete-node/ gpiote@da000; + /delete-node/ i2s@dd000; + /delete-node/ qdec@e0000; + /delete-node/ qdec@e1000; + /delete-node/ i2c@104000; + /delete-node/ spi@104000; + /delete-node/ uart@104000; + /delete-node/ watchdog@108000; + /delete-node/ watchdog@109000; + /delete-node/ gpio@10a000; + /delete-node/ gpiote@10c000; + /delete-node/ clock@10e000; + }; + /delete-node/ spu@50003000; + /delete-node/ gpiote@5000d000; + /delete-node/ crypto@50844000; + }; + + rng: rng { + status = "okay"; + compatible = "zephyr,native-posix-rng"; + }; +}; + +&grtc { + owned-channels = <0 1 2 3 4 5 6 7 8 9 10 11>; + /* Channels 7-11 reserved for Zero Latency IRQs, 3-4 for FLPR */ + child-owned-channels = <3 4 7 8 9 10 11>; + status = "okay"; +}; + +&cpuapp_rram { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + storage_partition: partition@0 { + label = "storage"; + reg = <0x0 DT_SIZE_K(500)>; + }; + }; +}; + +&temp { + status = "okay"; +}; diff --git a/boards/native/nrf_bsim/nrf54l15bsim_nrf54l15_cpuapp.yaml b/boards/native/nrf_bsim/nrf54l15bsim_nrf54l15_cpuapp.yaml new file mode 100644 index 00000000000..cbdd257334f --- /dev/null +++ b/boards/native/nrf_bsim/nrf54l15bsim_nrf54l15_cpuapp.yaml @@ -0,0 +1,17 @@ +identifier: nrf54l15bsim/nrf54l15/cpuapp +name: NRF54L15 BabbleSim - Application Core target +type: native +arch: posix +simulation: native +env: + - BSIM_OUT_PATH +toolchain: + - zephyr +supported: + - counter +testing: + ignore_tags: + - gpio + - modem + - uart + - bsim_skip_CI diff --git a/boards/native/nrf_bsim/nrf54l15bsim_nrf54l15_cpuapp_defconfig b/boards/native/nrf_bsim/nrf54l15bsim_nrf54l15_cpuapp_defconfig new file mode 100644 index 00000000000..0fde4e01b58 --- /dev/null +++ b/boards/native/nrf_bsim/nrf54l15bsim_nrf54l15_cpuapp_defconfig @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright (c) 2023 Nordic Semiconductor ASA + +CONFIG_CONSOLE=y +CONFIG_NO_OPTIMIZATIONS=y + +# Start SYSCOUNTER on driver init +CONFIG_NRF_GRTC_START_SYSCOUNTER=y diff --git a/boards/nordic/nrf5340_audio_dk/nrf5340_audio_dk_nrf5340_cpuapp.yaml b/boards/nordic/nrf5340_audio_dk/nrf5340_audio_dk_nrf5340_cpuapp.yaml index 9c131a6c9d4..a4433e7e030 100644 --- a/boards/nordic/nrf5340_audio_dk/nrf5340_audio_dk_nrf5340_cpuapp.yaml +++ b/boards/nordic/nrf5340_audio_dk/nrf5340_audio_dk_nrf5340_cpuapp.yaml @@ -9,6 +9,10 @@ toolchain: ram: 448 flash: 1024 supported: + - arduino_adc + - arduino_i2c + - arduino_serial + - arduino_spi - gpio - i2s - spi diff --git a/boards/nordic/nrf5340_audio_dk/nrf5340_audio_dk_nrf5340_cpuapp_common.dtsi b/boards/nordic/nrf5340_audio_dk/nrf5340_audio_dk_nrf5340_cpuapp_common.dtsi index 132687888b2..8504e23ed7e 100644 --- a/boards/nordic/nrf5340_audio_dk/nrf5340_audio_dk_nrf5340_cpuapp_common.dtsi +++ b/boards/nordic/nrf5340_audio_dk/nrf5340_audio_dk_nrf5340_cpuapp_common.dtsi @@ -25,33 +25,15 @@ }; }; - 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 9 0>, /* D0 */ - <7 0 &gpio1 8 0>, /* D1 */ - <8 0 &gpio0 31 0>, /* D2 */ - <9 0 &gpio1 0 0>, /* D3 */ - <10 0 &gpio1 1 0>, /* D4 */ - <11 0 &gpio1 14 0>, /* D5 */ - <12 0 &gpio1 7 0>, /* D6 */ - <13 0 &gpio1 11 0>, /* D7 */ - <14 0 &gpio1 10 0>, /* D8 */ - <15 0 &gpio1 13 0>, /* D9 */ - <16 0 &gpio1 12 0>, /* D10 */ - <17 0 &gpio0 9 0>, /* D11 */ - <18 0 &gpio0 10 0>, /* D12 */ - <19 0 &gpio0 8 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 1>, /* A0 = P0.4 = AIN1 */ + <1 &adc 2>, /* A1 = P0.5 = AIN2 */ + <2 &adc 4>, /* A2 = P0.6 = AIN4 */ + <3 &adc 5>, /* A3 = P0.7 = AIN5 */ + <4 &adc 6>, /* A4 = P0.25 = AIN6 */ + <5 &adc 7>; /* A5 = P0.26 = AIN7 */ }; pmic { @@ -149,7 +131,7 @@ arduino_serial: &uart1 { pinctrl-names = "default", "sleep"; }; -&i2c1 { +arduino_i2c: &i2c1 { compatible = "nordic,nrf-twim"; status = "okay"; pinctrl-0 = <&i2c1_default>; @@ -201,16 +183,17 @@ arduino_serial: &uart1 { }; }; -&spi4 { +arduino_spi: &spi4 { compatible = "nordic,nrf-spim"; status = "okay"; - cs-gpios = <&gpio0 11 GPIO_ACTIVE_LOW>, <&gpio0 17 GPIO_ACTIVE_LOW>; + cs-gpios = <&arduino_header 16 GPIO_ACTIVE_LOW>, + <&gpio0 11 GPIO_ACTIVE_LOW>, <&gpio0 17 GPIO_ACTIVE_LOW>; pinctrl-0 = <&spi4_default>; pinctrl-1 = <&spi4_sleep>; pinctrl-names = "default", "sleep"; - sdhc0: sdhc@0 { + sdhc0: sdhc@1 { compatible = "zephyr,sdhc-spi-slot"; - reg = <0>; + reg = <1>; status = "okay"; sdmmc { compatible = "zephyr,sdmmc-disk"; @@ -220,9 +203,9 @@ arduino_serial: &uart1 { spi-max-frequency = <8000000>; }; - cs47l63: cs47l63@1 { + cs47l63: cs47l63@2 { compatible = "cirrus,cs47l63"; - reg = <1>; + reg = <2>; spi-max-frequency = <8000000>; irq-gpios = <&gpio0 19 GPIO_ACTIVE_LOW>; reset-gpios = <&gpio0 18 GPIO_ACTIVE_LOW>; diff --git a/boards/nordic/nrf5340_audio_dk/nrf5340_audio_dk_nrf5340_cpunet.dts b/boards/nordic/nrf5340_audio_dk/nrf5340_audio_dk_nrf5340_cpunet.dts index 22a05cac020..beb151d451f 100644 --- a/boards/nordic/nrf5340_audio_dk/nrf5340_audio_dk_nrf5340_cpunet.dts +++ b/boards/nordic/nrf5340_audio_dk/nrf5340_audio_dk_nrf5340_cpunet.dts @@ -25,35 +25,6 @@ watchdog0 = &wdt0; }; - 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 9 0>, /* D0 */ - <7 0 &gpio1 8 0>, /* D1 */ - <8 0 &gpio0 31 0>, /* D2 */ - <9 0 &gpio1 0 0>, /* D3 */ - <10 0 &gpio1 1 0>, /* D4 */ - <11 0 &gpio1 14 0>, /* D5 */ - <12 0 &gpio1 7 0>, /* D6 */ - <13 0 &gpio1 11 0>, /* D7 */ - <14 0 &gpio1 10 0>, /* D8 */ - <15 0 &gpio1 13 0>, /* D9 */ - <16 0 &gpio1 12 0>, /* D10 */ - <17 0 &gpio0 9 0>, /* D11 */ - <18 0 &gpio0 10 0>, /* D12 */ - <19 0 &gpio0 8 0>, /* D13 */ - <20 0 &gpio1 2 0>, /* D14 */ - <21 0 &gpio1 3 0>; /* D15 */ - }; - }; arduino_spi: &spi0 { diff --git a/boards/nordic/nrf5340_audio_dk/nrf5340_audio_dk_nrf5340_shared.dtsi b/boards/nordic/nrf5340_audio_dk/nrf5340_audio_dk_nrf5340_shared.dtsi index cbf7f62a88f..5d13b9288a6 100644 --- a/boards/nordic/nrf5340_audio_dk/nrf5340_audio_dk_nrf5340_shared.dtsi +++ b/boards/nordic/nrf5340_audio_dk/nrf5340_audio_dk_nrf5340_shared.dtsi @@ -70,6 +70,35 @@ }; }; + 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 9 0>, /* D0 */ + <7 0 &gpio1 8 0>, /* D1 */ + <8 0 &gpio0 31 0>, /* D2 */ + <9 0 &gpio1 0 0>, /* D3 */ + <10 0 &gpio1 1 0>, /* D4 */ + <11 0 &gpio1 14 0>, /* D5 */ + <12 0 &gpio1 7 0>, /* D6 */ + <13 0 &gpio1 11 0>, /* D7 */ + <14 0 &gpio1 10 0>, /* D8 */ + <15 0 &gpio1 13 0>, /* D9 */ + <16 0 &gpio1 12 0>, /* D10 */ + <17 0 &gpio0 9 0>, /* D11 */ + <18 0 &gpio0 10 0>, /* D12 */ + <19 0 &gpio0 8 0>, /* D13 */ + <20 0 &gpio1 2 0>, /* D14 */ + <21 0 &gpio1 3 0>; /* D15 */ + }; + aliases { led0 = &rgb1_red; led1 = &rgb1_green; diff --git a/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20-pinctrl.dtsi b/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20-pinctrl.dtsi index 8bc02597c6d..888d9a94748 100644 --- a/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20-pinctrl.dtsi +++ b/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20-pinctrl.dtsi @@ -51,25 +51,25 @@ }; }; - /omit-if-no-ref/ pwm120_default: pwm120_default { + /omit-if-no-ref/ exmif_default: exmif_default { group1 { - psels = ; + psels = , + , + ; + nordic,drive-mode = ; }; }; - /omit-if-no-ref/ pwm120_sleep: pwm120_sleep { + /omit-if-no-ref/ pwm130_default: pwm130_default { group1 { - psels = ; - low-power-enable; + psels = ; }; }; - /omit-if-no-ref/ exmif_default: exmif_default { + /omit-if-no-ref/ pwm130_sleep: pwm130_sleep { group1 { - psels = , - , - ; - nordic,drive-mode = ; + psels = ; + low-power-enable; }; }; }; diff --git a/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpuapp.dts b/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpuapp.dts index 736588e22b1..63025205b50 100644 --- a/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpuapp.dts +++ b/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpuapp.dts @@ -24,7 +24,9 @@ zephyr,flash = &mram1x; zephyr,sram = &cpuapp_data; zephyr,shell-uart = &uart136; + zephyr,ieee802154 = &cpuapp_ieee802154; zephyr,bt-hci-ipc = &ipc0; + nordic,802154-spinel-ipc = &ipc0; zephyr,entropy = &prng; }; @@ -39,6 +41,7 @@ sw1 = &button1; sw2 = &button2; sw3 = &button3; + ipc-to-cpusys = &cpuapp_cpusys_ipc; watchdog0 = &wdt010; }; @@ -94,17 +97,17 @@ }; }; + prng: prng { + compatible = "nordic,entropy-prng"; + status = "okay"; + }; + pwmleds { compatible = "pwm-leds"; pwm_led0: pwm_led_0 { - pwms = <&pwm120 0 PWM_MSEC(20) PWM_POLARITY_INVERTED>; + pwms = <&pwm130 0 PWM_MSEC(20) PWM_POLARITY_INVERTED>; }; }; - - prng: prng { - compatible = "nordic,entropy-prng"; - status = "okay"; - }; }; &cpuapp_ram0x_region { @@ -131,6 +134,10 @@ status = "okay"; }; +&cpusys_vevif { + status = "okay"; +}; + &cpusec_cpuapp_ipc { mbox-names = "tx", "rx"; tx-region = <&cpuapp_cpusec_ipc_shm>; @@ -147,6 +154,7 @@ ipc0: &cpuapp_cpurad_ipc { }; &cpuapp_cpusys_ipc { + status = "okay"; mbox-names = "rx", "tx"; tx-region = <&cpuapp_cpusys_ipc_shm>; rx-region = <&cpusys_cpuapp_ipc_shm>; @@ -212,13 +220,6 @@ ipc0: &cpuapp_cpurad_ipc { hw-flow-control; }; -&pwm120 { - status = "okay"; - pinctrl-0 = <&pwm120_default>; - pinctrl-1 = <&pwm120_sleep>; - pinctrl-names = "default", "sleep"; -}; - &gpio6 { status = "okay"; }; @@ -247,3 +248,18 @@ ipc0: &cpuapp_cpurad_ipc { t-exit-dpd = <30000>; }; }; + +&cpuapp_ieee802154 { + status = "okay"; +}; + +zephyr_udc0: &usbhs { + status = "okay"; +}; + +&pwm130 { + status = "okay"; + pinctrl-0 = <&pwm130_default>; + pinctrl-1 = <&pwm130_sleep>; + pinctrl-names = "default", "sleep"; +}; diff --git a/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpuapp.yaml b/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpuapp.yaml index 2f83ef80de6..713f7c3c273 100644 --- a/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpuapp.yaml +++ b/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpuapp.yaml @@ -17,3 +17,4 @@ supported: - pwm - spi - watchdog + - usb_device diff --git a/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpurad.dts b/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpurad.dts index 32cda09ff37..fb05ad589f6 100644 --- a/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpurad.dts +++ b/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpurad.dts @@ -25,16 +25,17 @@ zephyr,flash = &mram1x; zephyr,sram = &cpurad_ram0; zephyr,shell-uart = &uart135; + zephyr,ieee802154 = &cpurad_ieee802154; zephyr,bt-hci-ipc = &ipc0; + nordic,802154-spinel-ipc = &ipc0; zephyr,entropy = &prng; }; - prng: prng { compatible = "nordic,entropy-prng"; status = "okay"; }; - aliases { + ipc-to-cpusys = &cpurad_cpusys_ipc; resetinfo = &cpurad_resetinfo; }; }; @@ -59,6 +60,10 @@ status = "okay"; }; +&cpusys_vevif { + status = "okay"; +}; + &cpusec_cpurad_ipc { mbox-names = "tx", "rx"; tx-region = <&cpurad_cpusec_ipc_shm>; @@ -75,6 +80,7 @@ ipc0: &cpuapp_cpurad_ipc { }; &cpurad_cpusys_ipc { + status = "okay"; mbox-names = "rx", "tx"; tx-region = <&cpurad_cpusys_ipc_shm>; rx-region = <&cpusys_cpurad_ipc_shm>; @@ -108,3 +114,7 @@ ipc0: &cpuapp_cpurad_ipc { pinctrl-1 = <&uart136_sleep>; pinctrl-names = "default", "sleep"; }; + +&cpurad_ieee802154 { + status = "okay"; +}; diff --git a/boards/nordic/nrf54l15pdk/Kconfig.nrf54l15pdk b/boards/nordic/nrf54l15pdk/Kconfig.nrf54l15pdk index 36ee21a55b6..09afebc2e09 100644 --- a/boards/nordic/nrf54l15pdk/Kconfig.nrf54l15pdk +++ b/boards/nordic/nrf54l15pdk/Kconfig.nrf54l15pdk @@ -3,3 +3,5 @@ config BOARD_NRF54L15PDK select SOC_NRF54L15_ENGA_CPUAPP if BOARD_NRF54L15PDK_NRF54L15_CPUAPP || BOARD_NRF54L15PDK_NRF54L15_CPUAPP_NS + select SOC_NRF54L15_ENGA_CPUFLPR if BOARD_NRF54L15PDK_NRF54L15_CPUFLPR || \ + BOARD_NRF54L15PDK_NRF54L15_CPUFLPR_XIP diff --git a/boards/nordic/nrf54l15pdk/board.cmake b/boards/nordic/nrf54l15pdk/board.cmake index 5a1e4b3221d..1427b6e9154 100644 --- a/boards/nordic/nrf54l15pdk/board.cmake +++ b/boards/nordic/nrf54l15pdk/board.cmake @@ -1,7 +1,11 @@ # Copyright (c) 2024 Nordic Semiconductor ASA # SPDX-License-Identifier: Apache-2.0 -board_runner_args(jlink "--device=cortex-m33" "--speed=4000") +if (CONFIG_SOC_NRF54L15_ENGA_CPUAPP) + board_runner_args(jlink "--device=cortex-m33" "--speed=4000") +elseif (CONFIG_SOC_NRF54L15_ENGA_CPUFLPR) + board_runner_args(jlink "--speed=4000") +endif() if(BOARD_NRF54L15PDK_NRF54L15_CPUAPP_NS) set(TFM_PUBLIC_KEY_FORMAT "full") diff --git a/boards/nordic/nrf54l15pdk/board.yml b/boards/nordic/nrf54l15pdk/board.yml index 69b51223209..5df0270abe3 100644 --- a/boards/nordic/nrf54l15pdk/board.yml +++ b/boards/nordic/nrf54l15pdk/board.yml @@ -4,11 +4,13 @@ board: socs: - name: nrf54l15 variants: + - name: xip + cpucluster: cpuflpr - name: ns cpucluster: cpuapp revision: format: major.minor.patch - default: "0.2.1" + default: "0.3.0" revisions: - name: "0.2.1" - name: "0.3.0" diff --git a/boards/nordic/nrf54l15pdk/nrf54l15_cpuapp_common.dtsi b/boards/nordic/nrf54l15pdk/nrf54l15_cpuapp_common.dtsi new file mode 100644 index 00000000000..2fa2ec36428 --- /dev/null +++ b/boards/nordic/nrf54l15pdk/nrf54l15_cpuapp_common.dtsi @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* This file is common to the secure and non-secure domain */ + +#include +#include "nrf54l15pdk_nrf54l15-common.dtsi" + +/ { + chosen { + zephyr,console = &uart20; + zephyr,shell-uart = &uart20; + zephyr,uart-mcumgr = &uart20; + zephyr,flash-controller = &rram_controller; + zephyr,flash = &cpuapp_rram; + zephyr,ieee802154 = &ieee802154; + }; + + aliases { + spi-flash0 = &mx25r64; + }; +}; + +&cpuapp_sram { + status = "okay"; +}; + +&lfxo { + load-capacitors = "internal"; + load-capacitance-femtofarad = <15500>; +}; + +&hfxo { + load-capacitors = "internal"; + load-capacitance-femtofarad = <15000>; +}; + +&grtc { + owned-channels = <0 1 2 3 4 5 6 7 8 9 10 11>; + /* Channels 7-11 reserved for Zero Latency IRQs, 3-4 for FLPR */ + child-owned-channels = <3 4 7 8 9 10 11>; + status = "okay"; +}; + +&cpuapp_rram { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x0 DT_SIZE_K(64)>; + }; + slot0_partition: partition@10000 { + label = "image-0"; + reg = <0x10000 DT_SIZE_K(324)>; + }; + slot0_ns_partition: partition@61000 { + label = "image-0-nonsecure"; + reg = <0x61000 DT_SIZE_K(324)>; + }; + slot1_partition: partition@b2000 { + label = "image-1"; + reg = <0xb2000 DT_SIZE_K(324)>; + }; + slot1_ns_partition: partition@103000 { + label = "image-1-nonsecure"; + reg = <0x103000 DT_SIZE_K(324)>; + }; + /* 32k from 0x154000 to 0x15bfff reserved for TF-M partitions */ + storage_partition: partition@15c000 { + label = "storage"; + reg = <0x15c000 DT_SIZE_K(36)>; + }; + }; +}; + +&uart20 { + status = "okay"; + hw-flow-control; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&gpio2 { + status = "okay"; +}; + +&gpiote20 { + status = "okay"; +}; + +&gpiote30 { + status = "okay"; +}; + +&radio { + status = "okay"; +}; + +&ieee802154 { + status = "okay"; +}; + +&temp { + status = "okay"; +}; + +&clock { + status = "okay"; +}; + +&spi00 { + status = "okay"; + cs-gpios = <&gpio2 5 GPIO_ACTIVE_LOW>; + pinctrl-0 = <&spi00_default>; + pinctrl-1 = <&spi00_sleep>; + pinctrl-names = "default", "sleep"; + + mx25r64: mx25r6435f@0 { + compatible = "jedec,spi-nor"; + status = "disabled"; + reg = <0>; + spi-max-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 48 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>; + }; +}; + +&adc { + status = "okay"; +}; diff --git a/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15-common.dtsi b/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15-common.dtsi new file mode 100644 index 00000000000..8baba7eef4a --- /dev/null +++ b/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15-common.dtsi @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "nrf54l15pdk_nrf54l15-pinctrl.dtsi" + +/ { + leds { + compatible = "gpio-leds"; + led0: led_0 { + gpios = <&gpio2 9 GPIO_ACTIVE_HIGH>; + label = "Green LED 0"; + }; + led1: led_1 { + gpios = <&gpio1 10 GPIO_ACTIVE_HIGH>; + label = "Green LED 1"; + }; + led2: led_2 { + gpios = <&gpio2 7 GPIO_ACTIVE_HIGH>; + label = "Green LED 2"; + }; + led3: led_3 { + gpios = <&gpio1 14 GPIO_ACTIVE_HIGH>; + label = "Green LED 3"; + }; + }; + + pwmleds { + compatible = "pwm-leds"; + pwm_led1: pwm_led_1 { + pwms = <&pwm20 0 PWM_MSEC(20) PWM_POLARITY_INVERTED>; + }; + }; + + buttons { + compatible = "gpio-keys"; + button0: button_0 { + gpios = <&gpio1 13 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "Push button 0"; + zephyr,code = ; + }; + button1: button_1 { + gpios = <&gpio1 9 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "Push button 1"; + zephyr,code = ; + }; + button2: button_2 { + gpios = <&gpio1 8 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "Push button 2"; + zephyr,code = ; + }; + button3: button_3 { + gpios = <&gpio0 4 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "Push button 3"; + zephyr,code = ; + }; + }; + + aliases { + led0 = &led0; + led1 = &led1; + led2 = &led2; + led3 = &led3; + pwm-led0 = &pwm_led1; + sw0 = &button0; + sw1 = &button1; + sw2 = &button2; + sw3 = &button3; + watchdog0 = &wdt31; + }; +}; + +&uart20 { + 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"; +}; + +&pwm20 { + status = "okay"; + pinctrl-0 = <&pwm20_default>; + pinctrl-1 = <&pwm20_sleep>; + pinctrl-names = "default", "sleep"; +}; diff --git a/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15-pinctrl.dtsi b/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15-pinctrl.dtsi new file mode 100644 index 00000000000..a0790f2ac48 --- /dev/null +++ b/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15-pinctrl.dtsi @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor + * SPDX-License-Identifier: Apache-2.0 + */ + +&pinctrl { + /omit-if-no-ref/ uart20_default: uart20_default { + group1 { + psels = , + ; + }; + group2 { + psels = , + ; + bias-pull-up; + }; + }; + + /omit-if-no-ref/ uart20_sleep: uart20_sleep { + group1 { + psels = , + , + , + ; + low-power-enable; + }; + }; + + /omit-if-no-ref/ uart30_default: uart30_default { + group1 { + psels = , + ; + }; + group2 { + psels = , + ; + bias-pull-up; + }; + }; + + /omit-if-no-ref/ uart30_sleep: uart30_sleep { + group1 { + psels = , + , + , + ; + low-power-enable; + }; + }; + + /omit-if-no-ref/ spi00_default: spi00_default { + group1 { + psels = , + , + ; + }; + }; + + /omit-if-no-ref/ spi00_sleep: spi00_sleep { + group1 { + psels = , + , + ; + low-power-enable; + }; + }; + + /omit-if-no-ref/ pwm20_default: pwm20_default { + group1 { + psels = ; + }; + }; + + /omit-if-no-ref/ pwm20_sleep: pwm20_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; diff --git a/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_common_0_2_1.dtsi b/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_common_0_2_1.dtsi new file mode 100644 index 00000000000..2467b810bb8 --- /dev/null +++ b/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_common_0_2_1.dtsi @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&led0 { + gpios = <&gpio0 4 GPIO_ACTIVE_HIGH>; +}; + +&led1 { + gpios = <&gpio1 8 GPIO_ACTIVE_HIGH>; +}; + +&led2 { + gpios = <&gpio1 13 GPIO_ACTIVE_HIGH>; +}; + +&led3 { + gpios = <&gpio1 14 GPIO_ACTIVE_HIGH>; +}; + +&button0 { + gpios = <&gpio1 9 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; +}; + +&button1 { + gpios = <&gpio1 10 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; +}; + +&button2 { + gpios = <&gpio2 9 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; +}; + +&button3 { + gpios = <&gpio2 10 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; +}; + +&pinctrl { + /omit-if-no-ref/ pwm20_default: pwm20_default { + group1 { + psels = ; + }; + }; + + /omit-if-no-ref/ pwm20_sleep: pwm20_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; diff --git a/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuapp-pinctrl.dtsi b/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuapp-pinctrl.dtsi deleted file mode 100644 index 89ad7599870..00000000000 --- a/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuapp-pinctrl.dtsi +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2024 Nordic Semiconductor - * SPDX-License-Identifier: Apache-2.0 - */ - -&pinctrl { - uart20_default: uart20_default { - group1 { - psels = , - ; - }; - group2 { - psels = , - ; - bias-pull-up; - }; - }; - - uart20_sleep: uart20_sleep { - group1 { - psels = , - , - , - ; - low-power-enable; - }; - }; - - uart30_default: uart30_default { - group1 { - psels = , - ; - }; - group2 { - psels = , - ; - bias-pull-up; - }; - }; - - uart30_sleep: uart30_sleep { - group1 { - psels = , - , - , - ; - low-power-enable; - }; - }; - - spi0_default: spi0_default { - group1 { - psels = , - , - ; - }; - }; - - spi0_sleep: spi0_sleep { - group1 { - psels = , - , - ; - low-power-enable; - }; - }; - - /omit-if-no-ref/ pwm20_default: pwm20_default { - group1 { - psels = ; - }; - }; - - /omit-if-no-ref/ pwm20_sleep: pwm20_sleep { - group1 { - psels = ; - low-power-enable; - }; - }; -}; diff --git a/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuapp.dts b/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuapp.dts index 395f92d638c..831479ea950 100644 --- a/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuapp.dts +++ b/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuapp.dts @@ -5,218 +5,15 @@ */ /dts-v1/; -#include -#include "nrf54l15pdk_nrf54l15_cpuapp-pinctrl.dtsi" -#include + +#include "nrf54l15_cpuapp_common.dtsi" / { - model = "Nordic nRF54L15 PDK nRF54L15 Application MCU"; compatible = "nordic,nrf54l15pdk_nrf54l15-cpuapp"; + model = "Nordic nRF54L15 PDK nRF54L15 Application MCU"; chosen { - zephyr,console = &uart20; - zephyr,shell-uart = &uart20; - zephyr,uart-mcumgr = &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"; - }; - }; - - pwmleds { - compatible = "pwm-leds"; - pwm_led1: pwm_led_1 { - pwms = <&pwm20 0 PWM_MSEC(20) PWM_POLARITY_INVERTED>; - }; - }; - - 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; - pwm-led0 = &pwm_led1; - watchdog0 = &wdt30; - sw0 = &button0; - sw1 = &button1; - sw2 = &button2; - sw3 = &button3; - spi-flash0 = &mx25r64; - }; -}; - -&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"; - hw-flow-control; -}; - -&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"; -}; - -&ieee802154 { - status = "okay"; -}; - -&temp { - status = "okay"; -}; - -&rram0 { - partitions { - compatible = "fixed-partitions"; - #address-cells = <1>; - #size-cells = <1>; - boot_partition: partition@0 { - label = "mcuboot"; - reg = <0x0 DT_SIZE_K(64)>; - }; - slot0_partition: partition@10000 { - label = "image-0"; - reg = <0x10000 DT_SIZE_K(348)>; - }; - slot0_ns_partition: partition@67000 { - label = "image-0-nonsecure"; - reg = <0x67000 DT_SIZE_K(348)>; - }; - slot1_partition: partition@be000 { - label = "image-1"; - reg = <0xbe000 DT_SIZE_K(348)>; - }; - slot1_ns_partition: partition@115000 { - label = "image-1-nonsecure"; - reg = <0x115000 DT_SIZE_K(348)>; - }; - /* 32k from 0x16c000 to 0x173fff reserved for TF-M partitions */ - storage_partition: partition@174000 { - label = "storage"; - reg = <0x174000 DT_SIZE_K(36)>; - }; - }; -}; - -&clock { - status = "okay"; -}; - -&spi00 { - status = "okay"; - cs-gpios = <&gpio2 5 GPIO_ACTIVE_LOW>; - pinctrl-0 = <&spi0_default>; - pinctrl-1 = <&spi0_sleep>; - pinctrl-names = "default", "sleep"; - - mx25r64: mx25r6435f@0 { - compatible = "jedec,spi-nor"; - reg = <0>; - status = "disabled"; - spi-max-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 48 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>; + zephyr,sram = &cpuapp_sram; }; }; - -&adc { - status = "okay"; -}; - -&pwm20 { - status = "okay"; - pinctrl-0 = <&pwm20_default>; - pinctrl-1 = <&pwm20_sleep>; - pinctrl-names = "default", "sleep"; -}; diff --git a/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuapp.yaml b/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuapp.yaml index 2858ddd35c5..fd563bc6c1e 100644 --- a/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuapp.yaml +++ b/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuapp.yaml @@ -9,8 +9,8 @@ toolchain: - gnuarmemb - xtools - zephyr -ram: 256 -flash: 1536 +ram: 188 +flash: 324 supported: - adc - counter diff --git a/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuapp_0_2_1.overlay b/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuapp_0_2_1.overlay new file mode 100644 index 00000000000..1ca5cadaff9 --- /dev/null +++ b/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuapp_0_2_1.overlay @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "nrf54l15pdk_nrf54l15_common_0_2_1.dtsi" diff --git a/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuapp_0_3_0.overlay b/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuapp_0_3_0.overlay deleted file mode 100644 index 99ba6ff3062..00000000000 --- a/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuapp_0_3_0.overlay +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2024 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - - -&led0 { - gpios = <&gpio2 9 GPIO_ACTIVE_HIGH>; -}; - -&led1 { - gpios = <&gpio1 10 GPIO_ACTIVE_HIGH>; -}; - -&led2 { - gpios = <&gpio2 7 GPIO_ACTIVE_HIGH>; -}; - -&led3 { - gpios = <&gpio1 14 GPIO_ACTIVE_HIGH>; -}; - -&button0 { - gpios = <&gpio1 13 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; -}; - -&button1 { - gpios = <&gpio1 9 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; -}; - -&button2 { - gpios = <&gpio1 8 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; -}; - -&button3 { - gpios = <&gpio0 4 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; -}; - -&pinctrl { - /omit-if-no-ref/ pwm20_default: pwm20_default { - group1 { - psels = ; - }; - }; - - /omit-if-no-ref/ pwm20_sleep: pwm20_sleep { - group1 { - psels = ; - low-power-enable; - }; - }; -}; diff --git a/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuapp_0_3_0.yaml b/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuapp_0_3_0.yaml deleted file mode 100644 index a19bc8fdc8b..00000000000 --- a/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuapp_0_3_0.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright (c) 2024 Nordic Semiconductor ASA -# SPDX-License-Identifier: Apache-2.0 - -identifier: nrf54l15pdk@0.3.0/nrf54l15/cpuapp -name: nRF54l15-PDK-nRF54l15-Application -type: mcu -arch: arm -toolchain: - - gnuarmemb - - xtools - - zephyr -ram: 256 -flash: 1536 -supported: - - counter - - gpio - - i2c - - spi - - watchdog - - i2s diff --git a/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuapp_defconfig b/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuapp_defconfig index bb9fd0de14b..25559850091 100644 --- a/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuapp_defconfig +++ b/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuapp_defconfig @@ -8,6 +8,9 @@ CONFIG_SERIAL=y CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y +# Enable GPIO +CONFIG_GPIO=y + # Enable MPU CONFIG_ARM_MPU=y @@ -22,13 +25,6 @@ CONFIG_NULL_POINTER_EXCEPTION_DETECTION_NONE=y 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 diff --git a/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuapp_ns-pinctrl.dtsi b/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuapp_ns-pinctrl.dtsi deleted file mode 100644 index b4b924e90ef..00000000000 --- a/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuapp_ns-pinctrl.dtsi +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2024 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause - */ - -&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/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuapp_ns.dts b/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuapp_ns.dts index 49fd1ac0ece..6e05c69c5f9 100644 --- a/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuapp_ns.dts +++ b/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuapp_ns.dts @@ -1,90 +1,25 @@ /* * Copyright (c) 2024 Nordic Semiconductor ASA * - * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + * SPDX-License-Identifier: Apache-2.0 */ /dts-v1/; -#include -#include "nrf54l15pdk_nrf54l15_cpuapp_ns-pinctrl.dtsi" -/ { - chosen { - zephyr,console = &uart20; - /* TODO: NCSDK-24862: We don't support configuring RRAM and SRAM - * regions in the DTS file yet. The partition manager configures - * these regions now. - */ - zephyr,shell-uart = &uart20; - zephyr,flash = &rram0; - zephyr,sram = &sram0; - zephyr,ieee802154 = &ieee802154; - }; +#define USE_NON_SECURE_ADDRESS_MAP 1 - 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"; - }; - }; +#include "nrf54l15_cpuapp_common.dtsi" - 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 = ; - }; - }; +/ { + compatible = "nordic,nrf54l15pdk_nrf54l15-cpuapp"; + model = "Nordic nRF54L15 PDK nRF54L15 Application MCU"; - aliases { - led0 = &led0; - led1 = &led1; - led2 = &led2; - led3 = &led3; - sw0 = &button0; - sw1 = &button1; - sw2 = &button2; - sw3 = &button3; + chosen { + zephyr,code-partition = &slot0_partition; + zephyr,sram = &cpuapp_sram; }; }; -&uart20 { - status = "okay"; - current-speed = <115200>; - pinctrl-0 = <&uart20_default>; - pinctrl-1 = <&uart20_sleep>; - pinctrl-names = "default", "sleep"; -}; - &uart30 { /* Disable so that TF-M can use this UART */ status = "disabled"; @@ -94,39 +29,3 @@ 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"; -}; - -&ieee802154 { - status = "okay"; -}; - -&temp { - status = "okay"; -}; - -&clock { - status = "okay"; -}; diff --git a/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuflpr.dts b/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuflpr.dts new file mode 100644 index 00000000000..e7ce7b43f7a --- /dev/null +++ b/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuflpr.dts @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include "nrf54l15pdk_nrf54l15-common.dtsi" + +/ { + model = "Nordic nRF54L15 PDK nRF54L15 FLPR MCU"; + compatible = "nordic,nrf54l15pdk_nrf54l15-cpuflpr"; + + chosen { + zephyr,console = &uart30; + zephyr,shell-uart = &uart30; + zephyr,code-partition = &cpuflpr_code_partition; + zephyr,flash = &cpuflpr_rram; + zephyr,sram = &cpuflpr_sram; + }; +}; + +&cpuflpr_sram { + status = "okay"; + /* size must be increased due to booting from SRAM */ + reg = <0x20028000 DT_SIZE_K(96)>; + ranges = <0x0 0x20028000 0x18000>; +}; + +&cpuflpr_rram { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + cpuflpr_code_partition: partition@0 { + label = "image-0"; + reg = <0x0 DT_SIZE_K(96)>; + }; + }; +}; + +&grtc { + owned-channels = <3 4>; + status = "okay"; +}; + +&uart30 { + status = "okay"; + hw-flow-control; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&gpio2 { + status = "okay"; +}; + +&gpiote20 { + status = "okay"; +}; + +&gpiote30 { + status = "okay"; +}; diff --git a/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuflpr.yaml b/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuflpr.yaml new file mode 100644 index 00000000000..f05b6b74a8b --- /dev/null +++ b/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuflpr.yaml @@ -0,0 +1,17 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +identifier: nrf54l15pdk/nrf54l15/cpuflpr +name: nRF54L15-PDK-nRF54L15-Fast-Lightweight-Peripheral-Processor +type: mcu +arch: riscv +toolchain: + - zephyr +ram: 96 +flash: 96 +supported: + - counter + - gpio + - i2c + - spi + - watchdog diff --git a/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuflpr_0_2_1.overlay b/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuflpr_0_2_1.overlay new file mode 100644 index 00000000000..1ca5cadaff9 --- /dev/null +++ b/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuflpr_0_2_1.overlay @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "nrf54l15pdk_nrf54l15_common_0_2_1.dtsi" diff --git a/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuflpr_defconfig b/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuflpr_defconfig new file mode 100644 index 00000000000..256ac9103b4 --- /dev/null +++ b/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuflpr_defconfig @@ -0,0 +1,17 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +# Enable UART driver +CONFIG_SERIAL=y + +# Enable console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# Enable GPIO +CONFIG_GPIO=y + +CONFIG_USE_DT_CODE_PARTITION=y + +# Execute from SRAM +CONFIG_XIP=n diff --git a/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuflpr_xip.dts b/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuflpr_xip.dts new file mode 100644 index 00000000000..cab0eab896e --- /dev/null +++ b/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuflpr_xip.dts @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "nrf54l15pdk_nrf54l15_cpuflpr.dts" + +&cpuflpr_sram { + reg = <0x2002f000 DT_SIZE_K(68)>; + ranges = <0x0 0x2002f000 0x11000>; +}; diff --git a/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuflpr_xip.yaml b/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuflpr_xip.yaml new file mode 100644 index 00000000000..0b9d635fb8d --- /dev/null +++ b/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuflpr_xip.yaml @@ -0,0 +1,17 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +identifier: nrf54l15pdk/nrf54l15/cpuflpr/xip +name: nRF54L15-PDK-nRF54L15-Fast-Lightweight-Peripheral-Processor (RRAM XIP) +type: mcu +arch: riscv +toolchain: + - zephyr +ram: 68 +flash: 96 +supported: + - counter + - gpio + - i2c + - spi + - watchdog diff --git a/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuflpr_xip_0_2_1.overlay b/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuflpr_xip_0_2_1.overlay new file mode 100644 index 00000000000..1ca5cadaff9 --- /dev/null +++ b/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuflpr_xip_0_2_1.overlay @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "nrf54l15pdk_nrf54l15_common_0_2_1.dtsi" diff --git a/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuflpr_xip_defconfig b/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuflpr_xip_defconfig new file mode 100644 index 00000000000..0a436a648b4 --- /dev/null +++ b/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuflpr_xip_defconfig @@ -0,0 +1,15 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +# Enable UART driver +CONFIG_SERIAL=y + +# Enable console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# Enable GPIO +CONFIG_GPIO=y + +# Execute from RRAM +CONFIG_XIP=y diff --git a/boards/nordic/nrf9160dk/nrf9160dk_nrf52840_0_7_0.yaml b/boards/nordic/nrf9160dk/nrf9160dk_nrf52840_0_7_0.yaml index 20b76523286..7613fabaed5 100644 --- a/boards/nordic/nrf9160dk/nrf9160dk_nrf52840_0_7_0.yaml +++ b/boards/nordic/nrf9160dk/nrf9160dk_nrf52840_0_7_0.yaml @@ -1,5 +1,5 @@ identifier: nrf9160dk@0.7.0/nrf52840 -name: nRF9160-DK-NRF52840 +name: nRF9160-DK-NRF52840 (rev. 0.7.0) type: mcu arch: arm ram: 64 diff --git a/boards/nordic/nrf9160dk/nrf9160dk_nrf9160_0_7_0.yaml b/boards/nordic/nrf9160dk/nrf9160dk_nrf9160_0_7_0.yaml index d66078fde8b..52a05c85455 100644 --- a/boards/nordic/nrf9160dk/nrf9160dk_nrf9160_0_7_0.yaml +++ b/boards/nordic/nrf9160dk/nrf9160dk_nrf9160_0_7_0.yaml @@ -1,5 +1,5 @@ identifier: nrf9160dk@0.7.0/nrf9160 -name: nRF9160-DK-NRF9160 +name: nRF9160-DK-NRF9160 (rev. 0.7.0) type: mcu arch: arm toolchain: diff --git a/boards/nordic/nrf9160dk/nrf9160dk_nrf9160_ns_0_7_0.yaml b/boards/nordic/nrf9160dk/nrf9160dk_nrf9160_ns_0_7_0.yaml index 1957bc3ad25..0faa84b38c9 100644 --- a/boards/nordic/nrf9160dk/nrf9160dk_nrf9160_ns_0_7_0.yaml +++ b/boards/nordic/nrf9160dk/nrf9160dk_nrf9160_ns_0_7_0.yaml @@ -1,5 +1,5 @@ identifier: nrf9160dk@0.7.0/nrf9160/ns -name: nRF9160-DK-NRF9160-Non-Secure +name: nRF9160-DK-NRF9160-Non-Secure (rev. 0.7.0) type: mcu arch: arm toolchain: diff --git a/boards/nordic/nrf9161dk/nrf9161dk_nrf9161_0_7_0.yaml b/boards/nordic/nrf9161dk/nrf9161dk_nrf9161_0_7_0.yaml index 47842c49d46..9d9f07dc48b 100644 --- a/boards/nordic/nrf9161dk/nrf9161dk_nrf9161_0_7_0.yaml +++ b/boards/nordic/nrf9161dk/nrf9161dk_nrf9161_0_7_0.yaml @@ -1,5 +1,5 @@ identifier: nrf9161dk@0.7.0/nrf9161 -name: nRF9161-DK-NRF9161 +name: nRF9161-DK-NRF9161 (rev. 0.7.0) type: mcu arch: arm toolchain: diff --git a/boards/nordic/nrf9161dk/nrf9161dk_nrf9161_ns_0_7_0.yaml b/boards/nordic/nrf9161dk/nrf9161dk_nrf9161_ns_0_7_0.yaml index fd95098a773..c8224cafae4 100644 --- a/boards/nordic/nrf9161dk/nrf9161dk_nrf9161_ns_0_7_0.yaml +++ b/boards/nordic/nrf9161dk/nrf9161dk_nrf9161_ns_0_7_0.yaml @@ -1,5 +1,5 @@ identifier: nrf9161dk@0.7.0/nrf9161/ns -name: nRF9161-DK-NRF9161-Non-Secure +name: nRF9161-DK-NRF9161-Non-Secure (rev. 0.7.0) type: mcu arch: arm toolchain: diff --git a/boards/nuvoton/npcx4m8f_evb/npcx4m8f_evb.dts b/boards/nuvoton/npcx4m8f_evb/npcx4m8f_evb.dts index a34002e8bc8..b90d94b0c9e 100644 --- a/boards/nuvoton/npcx4m8f_evb/npcx4m8f_evb.dts +++ b/boards/nuvoton/npcx4m8f_evb/npcx4m8f_evb.dts @@ -118,3 +118,18 @@ compatible = "zephyr,kscan-input"; }; }; + +&i3c0 { + pinctrl-0 = <&i3c1_sda_scl_gpe3_e4>; + pinctrl-names = "default"; +}; + +&i3c1 { + pinctrl-0 = <&i3c2_sda_scl_gp50_56>; + pinctrl-names = "default"; +}; + +&i3c2 { + pinctrl-0 = <&i3c3_sda_scl_gpf4_f5>; + pinctrl-names = "default"; +}; diff --git a/boards/nuvoton/numaker_pfm_m467/numaker_pfm_m467.dts b/boards/nuvoton/numaker_pfm_m467/numaker_pfm_m467.dts index 28db9b9265a..69b0aa3fafc 100644 --- a/boards/nuvoton/numaker_pfm_m467/numaker_pfm_m467.dts +++ b/boards/nuvoton/numaker_pfm_m467/numaker_pfm_m467.dts @@ -111,8 +111,6 @@ }; &canfd0 { - bus-speed = <125000>; - bus-speed-data = <1000000>; pinctrl-0 = <&canfd0_default>; pinctrl-names = "default"; status = "okay"; diff --git a/boards/nxp/frdm_k22f/frdm_k22f.dts b/boards/nxp/frdm_k22f/frdm_k22f.dts index e11db24edfc..587aaa65ee1 100644 --- a/boards/nxp/frdm_k22f/frdm_k22f.dts +++ b/boards/nxp/frdm_k22f/frdm_k22f.dts @@ -154,6 +154,7 @@ arduino_spi: &spi0 { #pwm-cells = <3>; pinctrl-0 = <&ftm0_default>; pinctrl-names = "default"; + clock-source = "fixed"; }; &uart1 { diff --git a/boards/nxp/frdm_k64f/doc/index.rst b/boards/nxp/frdm_k64f/doc/index.rst index f144fa0ce97..1c240ef400f 100644 --- a/boards/nxp/frdm_k64f/doc/index.rst +++ b/boards/nxp/frdm_k64f/doc/index.rst @@ -391,13 +391,3 @@ 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/nxp/frdm_k64f/dts/nxp,enet-experimental.overlay b/boards/nxp/frdm_k64f/dts/nxp,enet-experimental.overlay deleted file mode 100644 index 9dfc07e9b08..00000000000 --- a/boards/nxp/frdm_k64f/dts/nxp,enet-experimental.overlay +++ /dev/null @@ -1,108 +0,0 @@ -/* - * 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/nxp/frdm_k64f/frdm_k64f-pinctrl.dtsi b/boards/nxp/frdm_k64f/frdm_k64f-pinctrl.dtsi index 70af2305ce8..403f66b3503 100644 --- a/boards/nxp/frdm_k64f/frdm_k64f-pinctrl.dtsi +++ b/boards/nxp/frdm_k64f/frdm_k64f-pinctrl.dtsi @@ -26,7 +26,21 @@ }; }; - enet_default: 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"; @@ -35,14 +49,17 @@ slew-rate = "fast"; }; group1 { - pinmux = , - , - , - , - , - , - , - ; + pinmux = ; + drive-strength = "low"; + slew-rate = "fast"; + }; + }; + + pinmux_ptp: pinmux_ptp { + group0 { + pinmux = , + , + ; drive-strength = "low"; slew-rate = "fast"; }; diff --git a/boards/nxp/frdm_k64f/frdm_k64f.dts b/boards/nxp/frdm_k64f/frdm_k64f.dts index a5affc02797..4c42385a794 100644 --- a/boards/nxp/frdm_k64f/frdm_k64f.dts +++ b/boards/nxp/frdm_k64f/frdm_k64f.dts @@ -174,6 +174,7 @@ arduino_spi: &spi0 { #pwm-cells = <3>; pinctrl-0 = <&ftm0_default>; pinctrl-names = "default"; + clock-source = "fixed"; }; &ftm3 { @@ -182,6 +183,7 @@ arduino_spi: &spi0 { #pwm-cells = <3>; pinctrl-0 = <&ftm3_default>; pinctrl-names = "default"; + clock-source = "fixed"; }; &uart0 { @@ -252,23 +254,38 @@ zephyr_udc0: &usbotg { }; }; -&enet { +&enet_mac { status = "okay"; - pinctrl-0 = <&enet_default>; + pinctrl-0 = <&pinmux_enet>; pinctrl-names = "default"; - ptp { - /* Be aware that PTC16 and PTC17 are also used for uart3 */ - status = "disabled"; - pinctrl-0 = <&ptp_default>; - pinctrl-names = "default"; + phy-handle = <&phy>; + zephyr,random-mac-address; + 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,interface-type = "rmii-25MHz"; }; }; +&enet_ptp_clock { + status = "okay"; + pinctrl-0 = <&pinmux_ptp>; + pinctrl-names = "default"; +}; + &flexcan0 { status = "okay"; pinctrl-0 = <&flexcan0_default>; pinctrl-names = "default"; - bus-speed = <125000>; }; &edma0 { diff --git a/boards/nxp/frdm_k82f/frdm_k82f.dts b/boards/nxp/frdm_k82f/frdm_k82f.dts index 53eed0cd28b..44b88975f4d 100644 --- a/boards/nxp/frdm_k82f/frdm_k82f.dts +++ b/boards/nxp/frdm_k82f/frdm_k82f.dts @@ -209,6 +209,7 @@ #pwm-cells = <3>; pinctrl-0 = <&ftm3_default>; pinctrl-names = "default"; + clock-source = "fixed"; }; &spi1 { diff --git a/boards/nxp/frdm_ke15z/Kconfig.frdm_ke15z b/boards/nxp/frdm_ke15z/Kconfig.frdm_ke15z new file mode 100644 index 00000000000..32c3589c591 --- /dev/null +++ b/boards/nxp/frdm_ke15z/Kconfig.frdm_ke15z @@ -0,0 +1,6 @@ +# Copyright 2024 NXP +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_FRDM_KE15Z + select SOC_MKE15Z7 + select SOC_PART_NUMBER_MKE15Z256VLL7 diff --git a/boards/nxp/frdm_ke15z/board.cmake b/boards/nxp/frdm_ke15z/board.cmake new file mode 100644 index 00000000000..d14370f54fa --- /dev/null +++ b/boards/nxp/frdm_ke15z/board.cmake @@ -0,0 +1,11 @@ +# +# Copyright 2024 NXP +# +# SPDX-License-Identifier: Apache-2.0 +# + +board_runner_args(linkserver "--device=MKE15Z256xxx7:FRDM-KE15Z") +board_runner_args(jlink "--device=MKE15Z256xxx7" "--reset-after-load") + +include(${ZEPHYR_BASE}/boards/common/linkserver.board.cmake) +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/nxp/frdm_ke15z/board.yml b/boards/nxp/frdm_ke15z/board.yml new file mode 100644 index 00000000000..c637334b8b8 --- /dev/null +++ b/boards/nxp/frdm_ke15z/board.yml @@ -0,0 +1,5 @@ +board: + name: frdm_ke15z + vendor: nxp + socs: + - name: mke15z7 diff --git a/boards/nxp/frdm_ke15z/doc/frdm_ke15z.webp b/boards/nxp/frdm_ke15z/doc/frdm_ke15z.webp new file mode 100644 index 00000000000..f45a78b66e2 Binary files /dev/null and b/boards/nxp/frdm_ke15z/doc/frdm_ke15z.webp differ diff --git a/boards/nxp/frdm_ke15z/doc/index.rst b/boards/nxp/frdm_ke15z/doc/index.rst new file mode 100644 index 00000000000..fd1dec9bc67 --- /dev/null +++ b/boards/nxp/frdm_ke15z/doc/index.rst @@ -0,0 +1,187 @@ +.. _frdm_ke15z: + +NXP FRDM-KE15Z +############## + +Overview +******** + +The FRDM-KE15Z is a development board for NXP Kinetis KE1xZ 32-bit +MCU-based platforms. The FRDM-KE15Z contains a robust TSI module +with up to 50 channels which makes this board highly flexible +for touch keys. Offers options for serial +communication, flash programming, and run-control debugging. + +.. figure:: frdm_ke15z.webp + :align: center + :alt: FRDM-KE15Z + +Hardware +******** + +- MKE15Z256VLL7 MCU (up to 72 MHz, 256 KB flash memory, 32 KB RAM) +- OpenSDA Debug Circuit with a virtual serial port +- Touch electrodes in the self-capacitive mode +- Compatible with FRDM-TOUCH, FRDM-MC-LVBLDC, and ArduinoĀ® boards +- User Components such as Reset; RGB LED and two user buttons +- 6-axis FXOS8700CQ digital accelerometer and magnetometer + +For more information about the KE1xZ SoC and the FRDM-KE15Z board, see +these NXP reference documents: + +- `KE1XZ SOC Website`_ +- `FRDM-KE15Z Datasheet`_ +- `FRDM-KE15Z Reference Manual`_ +- `FRDM-KE15Z Website`_ +- `FRDM-KE15Z User Guide`_ +- `FRDM-KE15Z Schematics`_ + +Supported Features +================== + +The frdm_ke15z board configuration supports the following hardware +features: + ++-----------+------------+-------------------------------------+ +| Interface | Controller | Driver/Component | ++===========+============+=====================================+ +| NVIC | on-chip | nested vector interrupt controller | ++-----------+------------+-------------------------------------+ +| SYSTICK | on-chip | systick | ++-----------+------------+-------------------------------------+ +| GPIO | on-chip | gpio | ++-----------+------------+-------------------------------------+ +| UART | on-chip | uart polling; | +| | | uart interrupt | ++-----------+------------+-------------------------------------+ + +The default configuration can be found in the defconfig file: +:zephyr_file:`boards/nxp/frdm_ke15z/frdm_ke15z_defconfig`. + +Other hardware features are not currently supported by the port. + +System Clock +============ + +The KE15 SoC is configured to run at 48 MHz using the FIRC. + +Serial Port +=========== + +The KE15 SoC has three UARTs. UART1 is configured for the console. + +Programming and Debugging +************************* + +Build and flash applications as usual (see :ref:`build_an_application` and +:ref:`application_run` for more details). + +Configuring a Debug Probe +========================= + +A debug probe is used for both flashing and debugging the board. This board is +configured by default to use Linkserver. + +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: 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 for this board, ``west flash`` and ``west debug`` will +call the linkserver runner. + +Option 2: :ref:`opensda-jlink-onboard-debug-probe` +-------------------------------------------------- + +Install the :ref:`jlink-debug-host-tools` and make sure they are in your search +path. + +Follow the instructions in :ref:`opensda-jlink-onboard-debug-probe` to program +the `OpenSDA J-Link Firmware for FRDM-KE15Z`_. +Use the ``-r jlink`` option with west to use the jlink runner. + +.. code-block:: console + + west flash -r jlink + +Configuring a Console +===================== + +Regardless of your choice in debug probe, we will use the OpenSDA +microcontroller as a usb-to-serial adapter for the serial console. + +Connect a USB cable from your PC to J5. + +Use the following settings with your serial terminal of choice (minicom, putty, +etc.): + +- Speed: 115200 +- Data: 8 bits +- Parity: None +- Stop bits: 1 + +Flashing +======== + +Here is an example for the :ref:`hello_world` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: frdm_ke15z + :goals: flash + +Open a serial terminal, reset the board (press the SW1 button), and you should +see the following message in the terminal: + +.. code-block:: console + + *** Booting Zephyr OS build v3.6.0-3478-gb923667860b1 *** + Hello World! frdm_ke15z/mke15z7 + +Debugging +========= + +Here is an example for the :ref:`hello_world` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: frdm_ke15z + :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 v3.6.0-xxx-gxxxxxxxxxxxx ***** + Hello World! frdm_ke15z + +.. _KE1XZ SoC Website: + https://www.nxp.com/products/processors-and-microcontrollers/arm-microcontrollers/general-purpose-mcus/ke-series-arm-cortex-m4-m0-plus/ke1xz-arm-cortex-m0-plus-5v-main-stream-mcu-with-nxp-touch-and-can-control:KE1xZ + +.. _FRDM-KE15Z Datasheet: + https://www.nxp.com/docs/en/data-sheet/KE1xZP100M72SF0.pdf + +.. _FRDM-KE15Z Reference Manual: + https://www.nxp.com/webapp/Download?colCode=KE1XZP100M72SF0RM + +.. _FRDM-KE15Z Website: + https://www.nxp.com/design/design-center/development-boards-and-designs/general-purpose-mcus/freedom-development-platform-for-kinetis-ke1xmcus:FRDM-KE15Z + +.. _FRDM-KE15Z User Guide: + https://www.nxp.com/document/guide/get-started-with-the-frdm-ke15z:NGS-FRDM-KE15Z + +.. _FRDM-KE15Z Schematics: + https://www.nxp.com/webapp/Download?colCode=FRDM-KE15Z-SCH-DESIGNFILES + +.. _DAPLink Bootloader Update: + https://os.mbed.com/blog/entry/DAPLink-bootloader-update/ + +.. _OpenSDA J-Link Firmware for FRDM-KE15Z: + https://www.segger.com/downloads/jlink/OpenSDA_FRDM-KE15Z diff --git a/boards/nxp/frdm_ke15z/frdm_ke15z-pinctrl.dtsi b/boards/nxp/frdm_ke15z/frdm_ke15z-pinctrl.dtsi new file mode 100644 index 00000000000..b004d91e60c --- /dev/null +++ b/boards/nxp/frdm_ke15z/frdm_ke15z-pinctrl.dtsi @@ -0,0 +1,17 @@ +/* + * Copyright 2024 NXP + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&pinctrl { + lpuart1_default: lpuart1_default { + group0 { + pinmux = , + ; + drive-strength = "low"; + slew-rate = "slow"; + }; + }; +}; diff --git a/boards/nxp/frdm_ke15z/frdm_ke15z.dts b/boards/nxp/frdm_ke15z/frdm_ke15z.dts new file mode 100644 index 00000000000..0a1c341b000 --- /dev/null +++ b/boards/nxp/frdm_ke15z/frdm_ke15z.dts @@ -0,0 +1,76 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include "frdm_ke15z-pinctrl.dtsi" +#include + +/ { + model = "NXP Freedom KE15Z board"; + compatible = "nxp,ke15z", "nxp,mke15z7"; + + aliases { + led0 = &green_led; + led1 = &blue_led; + led2 = &red_led; + sw0 = &user_button_0; + sw1 = &user_button_1; + }; + + chosen { + zephyr,sram = &sram_u; + zephyr,flash = &flash0; + zephyr,console = &lpuart1; + zephyr,shell-uart = &lpuart1; + }; + + leds { + compatible = "gpio-leds"; + red_led: led_0 { + gpios = <&gpiod 0 GPIO_ACTIVE_LOW>; + label = "RED LED"; + }; + green_led: led_1 { + gpios = <&gpiod 16 GPIO_ACTIVE_LOW>; + label = "GREEN LED"; + }; + blue_led: led_2 { + gpios = <&gpiod 15 GPIO_ACTIVE_LOW>; + label = "BLUE LED"; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + user_button_0: button_0 { + label = "User SW3"; + gpios = <&gpiod 3 GPIO_ACTIVE_LOW>; + zephyr,code = ; + }; + user_button_1: button_1 { + label = "User SW2"; + gpios = <&gpiob 11 GPIO_ACTIVE_LOW>; + zephyr,code = ; + }; + }; +}; + +&lpuart1 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&lpuart1_default>; + pinctrl-names = "default"; +}; + +&gpiob { + status = "okay"; +}; + +&gpiod { + status = "okay"; +}; diff --git a/boards/nxp/frdm_ke15z/frdm_ke15z.yaml b/boards/nxp/frdm_ke15z/frdm_ke15z.yaml new file mode 100644 index 00000000000..9a2a7ac4b27 --- /dev/null +++ b/boards/nxp/frdm_ke15z/frdm_ke15z.yaml @@ -0,0 +1,13 @@ +identifier: frdm_ke15z +name: NXP FRDM-KE15Z +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +flash: 256 +ram: 24 +supported: + - gpio + - uart diff --git a/boards/nxp/frdm_ke15z/frdm_ke15z_defconfig b/boards/nxp/frdm_ke15z/frdm_ke15z_defconfig new file mode 100644 index 00000000000..69a85bdc43d --- /dev/null +++ b/boards/nxp/frdm_ke15z/frdm_ke15z_defconfig @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SERIAL=y +CONFIG_UART_INTERRUPT_DRIVEN=y + +# Enable console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# GPIO Controller +CONFIG_GPIO=y + +# Clock Control +CONFIG_CLOCK_CONTROL=y + +# Enable pin controller +CONFIG_PINCTRL=y diff --git a/boards/nxp/frdm_mcxn947/Kconfig.defconfig b/boards/nxp/frdm_mcxn947/Kconfig.defconfig index 72cc76170b9..461a4ed6286 100644 --- a/boards/nxp/frdm_mcxn947/Kconfig.defconfig +++ b/boards/nxp/frdm_mcxn947/Kconfig.defconfig @@ -6,4 +6,12 @@ if BOARD_FRDM_MCXN947 config NET_L2_ETHERNET default y if NETWORKING +if SD_STACK + +# SD stack requires larger main stack size +config MAIN_STACK_SIZE + default 1536 + +endif + endif diff --git a/boards/nxp/frdm_mcxn947/board.c b/boards/nxp/frdm_mcxn947/board.c index 484858f02dd..e6568204ce9 100644 --- a/boards/nxp/frdm_mcxn947/board.c +++ b/boards/nxp/frdm_mcxn947/board.c @@ -4,9 +4,19 @@ */ #include #include +#include #include #include #include +#if CONFIG_USB_DC_NXP_EHCI +#include "usb_phy.h" +#include "usb.h" + +/* USB PHY condfiguration */ +#define BOARD_USB_PHY_D_CAL (0x04U) +#define BOARD_USB_PHY_TXCAL45DP (0x07U) +#define BOARD_USB_PHY_TXCAL45DM (0x07U) +#endif /* Board xtal frequency in Hz */ #define BOARD_XTAL0_CLK_HZ 24000000U @@ -94,6 +104,8 @@ static int frdm_mcxn947_init(void) /* Set AHBCLKDIV divider to value 1 */ CLOCK_SetClkDiv(kCLOCK_DivAhbClk, 1U); + CLOCK_SetupExtClocking(BOARD_XTAL0_CLK_HZ); + #if DT_NODE_HAS_STATUS(DT_NODELABEL(flexcomm1), okay) CLOCK_SetClkDiv(kCLOCK_DivFlexcom1Clk, 1u); CLOCK_AttachClk(kFRO12M_to_FLEXCOMM1); @@ -166,6 +178,96 @@ static int frdm_mcxn947_init(void) CLOCK_SetClkDiv(kCLOCK_DivWdt0Clk, 1u); #endif +#if DT_NODE_HAS_STATUS(DT_NODELABEL(ctimer0), okay) + CLOCK_SetClkDiv(kCLOCK_DivCtimer0Clk, 1U); + CLOCK_AttachClk(kPLL0_to_CTIMER0); +#endif + +#if DT_NODE_HAS_STATUS(DT_NODELABEL(ctimer1), okay) + CLOCK_SetClkDiv(kCLOCK_DivCtimer1Clk, 1U); + CLOCK_AttachClk(kPLL0_to_CTIMER1); +#endif + +#if DT_NODE_HAS_STATUS(DT_NODELABEL(ctimer2), okay) + CLOCK_SetClkDiv(kCLOCK_DivCtimer2Clk, 1U); + CLOCK_AttachClk(kPLL0_to_CTIMER2); +#endif + +#if DT_NODE_HAS_STATUS(DT_NODELABEL(ctimer3), okay) + CLOCK_SetClkDiv(kCLOCK_DivCtimer3Clk, 1U); + CLOCK_AttachClk(kPLL0_to_CTIMER3); +#endif + +#if DT_NODE_HAS_STATUS(DT_NODELABEL(ctimer4), okay) + CLOCK_SetClkDiv(kCLOCK_DivCtimer4Clk, 1U); + CLOCK_AttachClk(kPLL0_to_CTIMER4); +#endif + +#if DT_NODE_HAS_STATUS(DT_NODELABEL(usdhc0), okay) + CLOCK_SetClkDiv(kCLOCK_DivUSdhcClk, 1u); + CLOCK_AttachClk(kFRO_HF_to_USDHC); +#endif + +#if CONFIG_FLASH_MCUX_FLEXSPI_NOR + /* We downclock the FlexSPI to 50MHz, it will be set to the + * optimum speed supported by the Flash device during FLEXSPI + * Init + */ + flexspi_clock_set_freq(MCUX_FLEXSPI_CLK, MHZ(50)); +#endif + +#if DT_NODE_HAS_STATUS(DT_NODELABEL(vref), okay) + CLOCK_EnableClock(kCLOCK_Vref); + SPC_EnableActiveModeAnalogModules(SPC0, kSPC_controlVref); +#endif + +#if DT_NODE_HAS_STATUS(DT_NODELABEL(lpadc0), okay) + CLOCK_SetClkDiv(kCLOCK_DivAdc0Clk, 1U); + CLOCK_AttachClk(kFRO_HF_to_ADC0); +#endif + +#if DT_NODE_HAS_STATUS(DT_NODELABEL(usb1), okay) && CONFIG_USB_DC_NXP_EHCI + usb_phy_config_struct_t usbPhyConfig = { + BOARD_USB_PHY_D_CAL, BOARD_USB_PHY_TXCAL45DP, BOARD_USB_PHY_TXCAL45DM, + }; + + SPC0->ACTIVE_VDELAY = 0x0500; + /* Change the power DCDC to 1.8v (By default, DCDC is 1.8V), CORELDO to 1.1v (By default, + * CORELDO is 1.0V) + */ + SPC0->ACTIVE_CFG &= ~SPC_ACTIVE_CFG_CORELDO_VDD_DS_MASK; + SPC0->ACTIVE_CFG |= SPC_ACTIVE_CFG_DCDC_VDD_LVL(0x3) | SPC_ACTIVE_CFG_CORELDO_VDD_LVL(0x3) | + SPC_ACTIVE_CFG_SYSLDO_VDD_DS_MASK | SPC_ACTIVE_CFG_DCDC_VDD_DS(0x2u); + /* Wait until it is done */ + while (SPC0->SC & SPC_SC_BUSY_MASK) { + }; + if (0u == (SCG0->LDOCSR & SCG_LDOCSR_LDOEN_MASK)) { + SCG0->TRIM_LOCK = 0x5a5a0001U; + SCG0->LDOCSR |= SCG_LDOCSR_LDOEN_MASK; + /* wait LDO ready */ + while (0U == (SCG0->LDOCSR & SCG_LDOCSR_VOUT_OK_MASK)) { + }; + } + SYSCON->AHBCLKCTRLSET[2] |= SYSCON_AHBCLKCTRL2_USB_HS_MASK | + SYSCON_AHBCLKCTRL2_USB_HS_PHY_MASK; + SCG0->SOSCCFG &= ~(SCG_SOSCCFG_RANGE_MASK | SCG_SOSCCFG_EREFS_MASK); + /* xtal = 20 ~ 30MHz */ + SCG0->SOSCCFG = (1U << SCG_SOSCCFG_RANGE_SHIFT) | (1U << SCG_SOSCCFG_EREFS_SHIFT); + SCG0->SOSCCSR |= SCG_SOSCCSR_SOSCEN_MASK; + while (1) { + if (SCG0->SOSCCSR & SCG_SOSCCSR_SOSCVLD_MASK) { + break; + } + } + SYSCON->CLOCK_CTRL |= SYSCON_CLOCK_CTRL_CLKIN_ENA_MASK | + SYSCON_CLOCK_CTRL_CLKIN_ENA_FM_USBH_LPT_MASK; + CLOCK_EnableClock(kCLOCK_UsbHs); + CLOCK_EnableClock(kCLOCK_UsbHsPhy); + CLOCK_EnableUsbhsPhyPllClock(kCLOCK_Usbphy480M, BOARD_XTAL0_CLK_HZ); + CLOCK_EnableUsbhsClock(); + USB_EhciPhyInit(kUSB_ControllerEhci0, BOARD_XTAL0_CLK_HZ, &usbPhyConfig); +#endif + /* Set SystemCoreClock variable. */ SystemCoreClock = CLOCK_INIT_CORE_CLOCK; diff --git a/boards/nxp/frdm_mcxn947/board.cmake b/boards/nxp/frdm_mcxn947/board.cmake index 86cdff853d9..fa5862e5e00 100644 --- a/boards/nxp/frdm_mcxn947/board.cmake +++ b/boards/nxp/frdm_mcxn947/board.cmake @@ -23,6 +23,9 @@ else() message(FATAL_ERROR "Support for cpu1 not available yet") endif() +# Pyocd support added with the NXP.MCXN947_DFP.17.0.0.pack CMSIS Pack +board_runner_args(pyocd "--target=mcxn947") 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/nxp/frdm_mcxn947/doc/index.rst b/boards/nxp/frdm_mcxn947/doc/index.rst index 79f97f274dc..a7724ad69ce 100644 --- a/boards/nxp/frdm_mcxn947/doc/index.rst +++ b/boards/nxp/frdm_mcxn947/doc/index.rst @@ -78,6 +78,18 @@ The FRDM-MCXN947 board configuration supports the following hardware features: +-----------+------------+-------------------------------------+ | WATCHDOG | on-chip | watchdog | +-----------+------------+-------------------------------------+ +| PWM | on-chip | pwm | ++-----------+------------+-------------------------------------+ +| CTIMER | on-chip | counter | ++-----------+------------+-------------------------------------+ +| USDHC | on-chip | sdhc | ++-----------+------------+-------------------------------------+ +| VREF | on-chip | REGULATOR | ++-----------+------------+-------------------------------------+ +| ADC | on-chip | adc | ++-----------+------------+-------------------------------------+ +| USBHS | on-chip | USB device | ++-----------+------------+-------------------------------------+ Targets available ================== diff --git a/boards/nxp/frdm_mcxn947/frdm_mcxn947-pinctrl.dtsi b/boards/nxp/frdm_mcxn947/frdm_mcxn947-pinctrl.dtsi index 13bd6950920..8bdc9e1c91f 100644 --- a/boards/nxp/frdm_mcxn947/frdm_mcxn947-pinctrl.dtsi +++ b/boards/nxp/frdm_mcxn947/frdm_mcxn947-pinctrl.dtsi @@ -101,4 +101,60 @@ input-enable; }; }; + + pinmux_flexpwm1_pwm0: pinmux_flexpwm1_pwm0 { + group0 { + pinmux = , + ; + slew-rate = "fast"; + drive-strength = "low"; + }; + }; + + pinmux_flexpwm1_pwm1: pinmux_flexpwm1_pwm1 { + group0 { + pinmux = , + ; + slew-rate = "fast"; + drive-strength = "low"; + }; + }; + + pinmux_flexpwm1_pwm2: pinmux_flexpwm1_pwm2 { + group0 { + pinmux = , + ; + slew-rate = "fast"; + drive-strength = "low"; + }; + }; + + pinmux_usdhc0: pinmux_usdhc0 { + group0 { + pinmux = , + , + , + , + ; + slew-rate = "fast"; + drive-strength = "low"; + bias-pull-up; + input-enable; + }; + group1 { + pinmux = ; + slew-rate = "fast"; + drive-strength = "low"; + input-enable; + }; + }; + pinmux_lpadc0: pinmux_lpadc0 { + group0 { + pinmux = , + , + ; + slew-rate = "fast"; + drive-strength = "low"; + }; + }; }; diff --git a/boards/nxp/frdm_mcxn947/frdm_mcxn947.dtsi b/boards/nxp/frdm_mcxn947/frdm_mcxn947.dtsi index 22323d6422c..37e15451bc9 100644 --- a/boards/nxp/frdm_mcxn947/frdm_mcxn947.dtsi +++ b/boards/nxp/frdm_mcxn947/frdm_mcxn947.dtsi @@ -6,6 +6,7 @@ #include "frdm_mcxn947-pinctrl.dtsi" #include +#include / { aliases{ @@ -14,6 +15,7 @@ led2 = &blue_led; sw0 = &user_button_2; sw1 = &user_button_3; + sdhc0 = &usdhc0; }; leds { @@ -40,11 +42,13 @@ user_button_2: button_0 { label = "User SW2"; gpios = <&gpio0 23 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + zephyr,code = ; status = "disabled"; }; user_button_3: button_1 { label = "User SW3"; gpios = <&gpio0 6 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + zephyr,code = ; status = "disabled"; }; }; @@ -92,18 +96,18 @@ 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(960)>; + reg = <0x00010000 DT_SIZE_K(992)>; }; slot1_partition: partition@100000 { label = "image-1"; - reg = <0x00100000 DT_SIZE_K(960)>; - }; - scratch_partition: partition@1f0000 { - label = "image-scratch"; - reg = <0x001f0000 DT_SIZE_K(64)>; + reg = <0x00108000 DT_SIZE_K(984)>; }; + /* storage_partition is placed in WINBOND flash memory*/ }; }; @@ -168,3 +172,22 @@ status = "okay"; }; }; + +&flexpwm1_pwm0 { + pinctrl-0 = <&pinmux_flexpwm1_pwm0>; + pinctrl-names = "default"; +}; + +&usdhc0 { + pinctrl-0 = <&pinmux_usdhc0>; + pinctrl-1 = <&pinmux_usdhc0>; + pinctrl-2 = <&pinmux_usdhc0>; + cd-gpios = <&gpio2 1 GPIO_ACTIVE_LOW>; + pinctrl-names = "default", "slow", "med"; + no-1-8-v; +}; + +&lpadc0 { + pinctrl-0 = <&pinmux_lpadc0>; + pinctrl-names = "default"; +}; diff --git a/boards/nxp/frdm_mcxn947/frdm_mcxn947_mcxn947_cpu0.dts b/boards/nxp/frdm_mcxn947/frdm_mcxn947_mcxn947_cpu0.dts index cbc18e92f0c..e3d80335db2 100644 --- a/boards/nxp/frdm_mcxn947/frdm_mcxn947_mcxn947_cpu0.dts +++ b/boards/nxp/frdm_mcxn947/frdm_mcxn947_mcxn947_cpu0.dts @@ -28,6 +28,7 @@ aliases{ watchdog0 = &wwdt0; + pwm-0 = &flexpwm1_pwm0; }; }; @@ -57,6 +58,10 @@ status = "okay"; }; +&gpio2 { + status = "okay"; +}; + &green_led { status = "okay"; }; @@ -132,3 +137,31 @@ &wwdt0 { status = "okay"; }; + +&flexpwm1_pwm0 { + status = "okay"; +}; + +&ctimer0 { + status = "okay"; +}; + +&usdhc0 { + status = "okay"; + sdmmc { + compatible = "zephyr,sdmmc-disk"; + status = "okay"; + }; +}; + +&vref { + status = "okay"; +}; + +&lpadc0 { + status = "okay"; +}; + +zephyr_udc0: &usb1 { + status = "okay"; +}; diff --git a/boards/nxp/frdm_mcxn947/frdm_mcxn947_mcxn947_cpu0.yaml b/boards/nxp/frdm_mcxn947/frdm_mcxn947_mcxn947_cpu0.yaml index 1a4725a33ed..ef6ea7114dc 100644 --- a/boards/nxp/frdm_mcxn947/frdm_mcxn947_mcxn947_cpu0.yaml +++ b/boards/nxp/frdm_mcxn947/frdm_mcxn947_mcxn947_cpu0.yaml @@ -21,4 +21,10 @@ supported: - dac - i2c - watchdog + - pwm + - counter + - sdhc + - regulator + - adc + - usb_device vendor: nxp diff --git a/boards/nxp/frdm_rw612/CMakeLists.txt b/boards/nxp/frdm_rw612/CMakeLists.txt new file mode 100644 index 00000000000..a2a0b122735 --- /dev/null +++ b/boards/nxp/frdm_rw612/CMakeLists.txt @@ -0,0 +1,15 @@ +# +# Copyright 2022-2023 NXP +# +# SPDX-License-Identifier: Apache-2.0 +# + +if(CONFIG_NXP_RW6XX_BOOT_HEADER) + zephyr_compile_definitions(BOARD_FLASH_SIZE=CONFIG_FLASH_SIZE*1024) + zephyr_library() + # This FCB is specific to the flash on this board, it won't work + # for boards with different flash chips. If you flash this FCB + # onto a board with a different flash chip you may break it. + # See MCUXpresso config tools for making a correct one. + zephyr_library_sources(W25Q512JVFIQ_FCB.c) +endif() diff --git a/boards/nxp/frdm_rw612/Kconfig.frdm_rw612 b/boards/nxp/frdm_rw612/Kconfig.frdm_rw612 new file mode 100644 index 00000000000..53ccaf667f3 --- /dev/null +++ b/boards/nxp/frdm_rw612/Kconfig.frdm_rw612 @@ -0,0 +1,5 @@ +# Copyright 2024 NXP +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_FRDM_RW612 + select SOC_PART_NUMBER_RW612ETA2I diff --git a/boards/nxp/frdm_rw612/W25Q512JVFIQ_FCB.c b/boards/nxp/frdm_rw612/W25Q512JVFIQ_FCB.c new file mode 100644 index 00000000000..cecf36ad9a2 --- /dev/null +++ b/boards/nxp/frdm_rw612/W25Q512JVFIQ_FCB.c @@ -0,0 +1,106 @@ +/* + * Copyright 2021-2024 NXP + * All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +__attribute__((section(".flash_conf"), used)) const fc_flexspi_nor_config_t +flexspi_config = { + .memConfig = { + .tag = FC_BLOCK_TAG, + .version = FC_BLOCK_VERSION, + .readSampleClkSrc = 1, + .csHoldTime = 3, + .csSetupTime = 3, + .deviceModeCfgEnable = 1, + .deviceModeSeq = {.seqNum = 1, .seqId = 2}, + .deviceModeArg = 0x02, + .configCmdEnable = 0, + .deviceType = 0x1, + .sflashPadType = kSerialFlash_4Pads, + .serialClkFreq = 5, + .sflashA1Size = 0x4000000U, + .sflashA2Size = 0, + .sflashB1Size = 0, + .sflashB2Size = 0, + .lookupTable = { + + [0] = FC_FLEXSPI_LUT_SEQ( + FC_CMD_SDR, FC_FLEXSPI_1PAD, 0xEC, + FC_RADDR_SDR, FC_FLEXSPI_4PAD, + 0x20), + [1] = FC_FLEXSPI_LUT_SEQ( + FC_MODE8_SDR, FC_FLEXSPI_4PAD, 0xF0, + FC_DUMMY_SDR, FC_FLEXSPI_4PAD, + 0x04), + [2] = FC_FLEXSPI_LUT_SEQ( + FC_READ_SDR, FC_FLEXSPI_4PAD, 0x04, + FC_STOP_EXE, FC_FLEXSPI_1PAD, 0x00), + + + [4 * 1 + 0] = FC_FLEXSPI_LUT_SEQ( + FC_CMD_SDR, FC_FLEXSPI_1PAD, 0x05, + FC_READ_SDR, FC_FLEXSPI_1PAD, 0x04), + + + [4 * 2 + 0] = + FC_FLEXSPI_LUT_SEQ(FC_CMD_SDR, + FC_FLEXSPI_1PAD, + 0x31, FC_WRITE_SDR, + FC_FLEXSPI_1PAD, + 0x01), + + + [4 * 3 + 0] = + FC_FLEXSPI_LUT_SEQ(FC_CMD_SDR, + FC_FLEXSPI_1PAD, + 0x06, FC_STOP_EXE, FC_FLEXSPI_1PAD, + 0x00), + + + [4 * 5 + 0] = + FC_FLEXSPI_LUT_SEQ(FC_CMD_SDR, + FC_FLEXSPI_1PAD, + 0x21, FC_RADDR_SDR, + FC_FLEXSPI_1PAD, + 0x20), + + + [4 * 8 + 0] = + FC_FLEXSPI_LUT_SEQ(FC_CMD_SDR, + FC_FLEXSPI_1PAD, + 0xDC, FC_RADDR_SDR, + FC_FLEXSPI_1PAD, + 0x20), + + + [4 * 9 + 0] = + FC_FLEXSPI_LUT_SEQ(FC_CMD_SDR, + FC_FLEXSPI_1PAD, + 0x34, FC_RADDR_SDR, + FC_FLEXSPI_1PAD, + 0x20), + [4 * 9 + 1] = + FC_FLEXSPI_LUT_SEQ(FC_WRITE_SDR, + FC_FLEXSPI_4PAD, + 0x00, + FC_STOP_EXE, FC_FLEXSPI_1PAD, + 0x00), + + + [4 * 11 + 0] = FC_FLEXSPI_LUT_SEQ(FC_CMD_SDR, + FC_FLEXSPI_1PAD, + 0xC7, FC_STOP_EXE, + FC_FLEXSPI_1PAD, + 0x00), + }, + }, + .pageSize = 0x100, + .sectorSize = 0x1000, + .ipcmdSerialClkFreq = 0, + .blockSize = 0x10000, + .fcb_fill[0] = 0xFFFFFFFF, +}; diff --git a/boards/nxp/frdm_rw612/board.cmake b/boards/nxp/frdm_rw612/board.cmake new file mode 100644 index 00000000000..c7b1d7d51d4 --- /dev/null +++ b/boards/nxp/frdm_rw612/board.cmake @@ -0,0 +1,9 @@ +# Copyright 2022-2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +board_runner_args(jlink "--device=RW612" "--reset-after-load") + +board_runner_args(linkserver "--device=RW612:RDRW612") + +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) +include(${ZEPHYR_BASE}/boards/common/linkserver.board.cmake) diff --git a/boards/nxp/frdm_rw612/board.yml b/boards/nxp/frdm_rw612/board.yml new file mode 100644 index 00000000000..e52333358c4 --- /dev/null +++ b/boards/nxp/frdm_rw612/board.yml @@ -0,0 +1,5 @@ +board: + name: frdm_rw612 + vendor: nxp + socs: + - name: rw612 diff --git a/boards/nxp/frdm_rw612/doc/index.rst b/boards/nxp/frdm_rw612/doc/index.rst new file mode 100644 index 00000000000..caefff181f0 --- /dev/null +++ b/boards/nxp/frdm_rw612/doc/index.rst @@ -0,0 +1,116 @@ +.. _frdm_rw612: + +NXP FRDM_RW612 +############## + +Overview +******** + +The RW612 is a highly integrated, low-power tri-radio wireless MCU with an +integrated 260 MHz ARM Cortex-M33 MCU and Wi-Fi 6 + Bluetooth Low Energy (LE) 5.3 / 802.15.4 +radios designed for a broad array of applications, including connected smart home devices, +gaming controllers, enterprise and industrial automation, smart accessories and smart energy. + +The RW612 MCU subsystem includes 1.2 MB of on-chip SRAM and a high-bandwidth Quad SPI interface +with an on-the-fly decryption engine for securely accessing off-chip XIP flash. + +The advanced design of the RW612 delivers tight integration, low power and highly secure +operation in a space- and cost-efficient wireless MCU requiring only a single 3.3ā€ÆV power supply. + +Hardware +******** + +- 260 MHz ARM Cortex-M33, tri-radio cores for Wifi 6 + BLE 5.3 + 802.15.4 +- 1.2 MB on-chip SRAM + +Supported Features +================== + ++-----------+------------+-----------------------------------+ +| Interface | Controller | Driver/Component | ++===========+============+===================================+ +| NVIC | on-chip | nested vector interrupt controller| ++-----------+------------+-----------------------------------+ +| SYSTICK | on-chip | systick | ++-----------+------------+-----------------------------------+ +| MCI_IOMUX | on-chip | pinmux | ++-----------+------------+-----------------------------------+ +| GPIO | on-chip | gpio | ++-----------+------------+-----------------------------------+ +| USART | on-chip | serial | ++-----------+------------+-----------------------------------+ + + +The default configuration can be found in the defconfig file: + + :zephyr_file:`boards/nxp/frdm_rw612/frdm_rw612_defconfig` + +Other hardware features are not currently supported + +Programming and Debugging +************************* + +Build and flash applications as usual (see :ref:`build_an_application` and +:ref:`application_run` for more details). + +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 JLink Firmware. + +Configuring a Console +===================== + +Connect a USB cable from your PC to J10, and use the serial terminal of your choice +(minicom, putty, etc.) with the following settings: + +- Speed: 115200 +- Data: 8 bits +- Parity: None +- Stop bits: 1 + +Flashing +======== + +Here is an example for the :ref:`hello_world` application. This example uses the +:ref:`jlink-debug-host-tools` as default. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: frdm_rw612 + :goals: flash + +Open a serial terminal, reset the board (press the RESET button), and you should +see the following message in the terminal: + +.. code-block:: console + + ***** Booting Zephyr OS v3.6.0 ***** + Hello World! frdm_rw612 + +Debugging +========= + +Here is an example for the :ref:`hello_world` application. This example uses the +:ref:`jlink-debug-host-tools` as default. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: frdm_rw612 + :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 zephyr-v3.6.0 ***** + Hello World! frdm_rw612 + + +Resources +========= + +.. _RW612 Website: + https://www.nxp.com/products/wireless-connectivity/wi-fi-plus-bluetooth-plus-802-15-4/wireless-mcu-with-integrated-tri-radiobr1x1-wi-fi-6-plus-bluetooth-low-energy-5-3-802-15-4:RW612 diff --git a/boards/nxp/frdm_rw612/frdm_rw612-pinctrl.dtsi b/boards/nxp/frdm_rw612/frdm_rw612-pinctrl.dtsi new file mode 100644 index 00000000000..c9b0bcb8984 --- /dev/null +++ b/boards/nxp/frdm_rw612/frdm_rw612-pinctrl.dtsi @@ -0,0 +1,16 @@ +/* + * Copyright 2022-2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&pinctrl { + pinmux_flexcomm3_usart: pinmux_flexcomm3_usart { + group0 { + pinmux = ; + slew-rate = "normal"; + }; + }; +}; diff --git a/boards/nxp/frdm_rw612/frdm_rw612.dts b/boards/nxp/frdm_rw612/frdm_rw612.dts new file mode 100644 index 00000000000..ad7237fb658 --- /dev/null +++ b/boards/nxp/frdm_rw612/frdm_rw612.dts @@ -0,0 +1,57 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include "frdm_rw612-pinctrl.dtsi" + +/ { + model = "nxp,frdm_rw612"; + + aliases { + led0 = &green_led; + }; + + chosen { + zephyr,sram = &sram_data; + zephyr,flash = &w25q512jvfiq; + zephyr,console = &flexcomm3; + }; + + leds { + compatible = "gpio-leds"; + green_led: led_1 { + gpios = <&hsgpio0 12 0>; + }; + }; +}; + +&flexcomm3 { + compatible = "nxp,lpc-usart"; + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&pinmux_flexcomm3_usart>; + pinctrl-names = "default"; +}; + +&hsgpio0 { + status = "okay"; +}; + +&flexspi { + status = "okay"; + /* Winbond external flash */ + w25q512jvfiq: w25q512jvfiq@0 { + compatible = "nxp,imx-flexspi-nor"; + reg = <0>; + size = <(DT_SIZE_M(512) / 8)>; + status = "okay"; + erase-block-size = <4096>; + write-block-size = <1>; + spi-max-frequency = <133000000>; + }; +}; diff --git a/boards/nxp/frdm_rw612/frdm_rw612.yaml b/boards/nxp/frdm_rw612/frdm_rw612.yaml new file mode 100644 index 00000000000..cbb95c51716 --- /dev/null +++ b/boards/nxp/frdm_rw612/frdm_rw612.yaml @@ -0,0 +1,18 @@ +# +# Copyright 2022-2024 NXP +# +# SPDX-License-Identifier: Apache-2.0 +# + +identifier: frdm_rw612 +name: NXP FRDM_RW612 +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +ram: 960 +flash: 65536 +supported: + - gpio diff --git a/boards/nxp/frdm_rw612/frdm_rw612_defconfig b/boards/nxp/frdm_rw612/frdm_rw612_defconfig new file mode 100644 index 00000000000..b987fa24dc0 --- /dev/null +++ b/boards/nxp/frdm_rw612/frdm_rw612_defconfig @@ -0,0 +1,15 @@ +# +# Copyright 2022 NXP +# +# SPDX-License-Identifier: Apache-2.0 +# + +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_PINCTRL=y +CONFIG_UART_INTERRUPT_DRIVEN=y +CONFIG_GPIO=y +CONFIG_ARM_MPU=y +CONFIG_HW_STACK_PROTECTION=y +CONFIG_TRUSTED_EXECUTION_SECURE=y diff --git a/boards/nxp/frdm_rw612/pre_dt_board.cmake b/boards/nxp/frdm_rw612/pre_dt_board.cmake new file mode 100644 index 00000000000..2c56668e435 --- /dev/null +++ b/boards/nxp/frdm_rw612/pre_dt_board.cmake @@ -0,0 +1,7 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +# Suppress "simple_bus_reg" on RW6XX boards as all GPIO ports use the same register. +list(APPEND EXTRA_DTC_FLAGS "-Wno-simple_bus_reg") +# Suppress "spi_bus_bridge" as flexcomm node can be used as a SPI device. +list(APPEND EXTRA_DTC_FLAGS "-Wno-spi_bus_bridge") diff --git a/boards/nxp/hexiwear/hexiwear_mk64f12.dts b/boards/nxp/hexiwear/hexiwear_mk64f12.dts index bbd3b43051e..d530b6e9036 100644 --- a/boards/nxp/hexiwear/hexiwear_mk64f12.dts +++ b/boards/nxp/hexiwear/hexiwear_mk64f12.dts @@ -106,6 +106,7 @@ #pwm-cells = <3>; pinctrl-0 = <&ftm3_default>; pinctrl-names = "default"; + clock-source = "fixed"; }; &i2c0 { @@ -186,24 +187,20 @@ 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 */ - - 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/nxp/imx8ulp_evk/imx8ulp_evk_mimx8ud7_adsp.dts b/boards/nxp/imx8ulp_evk/imx8ulp_evk_mimx8ud7_adsp.dts index c9cb331a7ba..5beebf74c91 100644 --- a/boards/nxp/imx8ulp_evk/imx8ulp_evk_mimx8ud7_adsp.dts +++ b/boards/nxp/imx8ulp_evk/imx8ulp_evk_mimx8ud7_adsp.dts @@ -15,5 +15,18 @@ chosen { zephyr,sram = &sram0; + zephyr,console = &lpuart7; + zephyr,shell-uart = &lpuart7; }; }; + +&lpuart7 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&lpuart7_default>; + pinctrl-names = "default"; +}; + +&sai5 { + rx-dataline = <3>; +}; diff --git a/boards/nxp/imx8ulp_evk/imx8ulp_evk_mimx8ud7_adsp_defconfig b/boards/nxp/imx8ulp_evk/imx8ulp_evk_mimx8ud7_adsp_defconfig index 5c0df6aa56f..1d13336fc23 100644 --- a/boards/nxp/imx8ulp_evk/imx8ulp_evk_mimx8ud7_adsp_defconfig +++ b/boards/nxp/imx8ulp_evk/imx8ulp_evk_mimx8ud7_adsp_defconfig @@ -7,3 +7,8 @@ CONFIG_DYNAMIC_INTERRUPTS=y CONFIG_LOG=y CONFIG_CLOCK_CONTROL=y + +# serial-related configurations +CONFIG_SERIAL=y +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y diff --git a/boards/nxp/imx93_evk/imx93_evk_mimx9352_a55.dts b/boards/nxp/imx93_evk/imx93_evk_mimx9352_a55.dts index 6cd176d0ce3..cd025a547e7 100644 --- a/boards/nxp/imx93_evk/imx93_evk_mimx9352_a55.dts +++ b/boards/nxp/imx93_evk/imx93_evk_mimx9352_a55.dts @@ -83,18 +83,45 @@ }; -&lpi2c1{ +&lpi2c1 { status = "disabled"; clock-frequency = ; pinctrl-0 = <&i2c1_default>; pinctrl-names = "default"; }; -&lpi2c2{ +&lpi2c2 { status = "disabled"; clock-frequency = ; pinctrl-0 = <&i2c2_default>; pinctrl-names = "default"; + + mfd0:adp5585@34 { + compatible = "adi,adp5585"; + reg = <0x34>; + status = "disabled"; + + gpio_exp0: adp5585_gpio { + compatible = "adi,adp5585-gpio"; + gpio-controller; + #gpio-cells = <2>; + ngpios = <13>; + gpio-reserved-ranges = <5 3>; + /* + * This device has non-contiguous gpio range: + * GPIO Pin R0~R4 are gpio0~4 + * GPIO Pin C0~C4 are gpio8~12 + */ + + gpiohog_exp_sel: exp-sel-hog { + gpio-hog; + gpios = <4 GPIO_ACTIVE_HIGH>; + line-name = "exp_sel"; + output-low; + }; + status = "disabled"; + }; + }; }; &lpspi3 { diff --git a/boards/nxp/lpcxpresso55s06/lpcxpresso55s06_common.dtsi b/boards/nxp/lpcxpresso55s06/lpcxpresso55s06_common.dtsi index aa2373b829c..42849ac568b 100644 --- a/boards/nxp/lpcxpresso55s06/lpcxpresso55s06_common.dtsi +++ b/boards/nxp/lpcxpresso55s06/lpcxpresso55s06_common.dtsi @@ -151,8 +151,6 @@ &can0 { status = "okay"; - bus-speed = <125000>; - bus-speed-data = <1000000>; pinctrl-0 = <&pinmux_can0>; pinctrl-names = "default"; diff --git a/boards/nxp/lpcxpresso55s16/lpcxpresso55s16_common.dtsi b/boards/nxp/lpcxpresso55s16/lpcxpresso55s16_common.dtsi index 1b68d976f3e..d081a79b969 100644 --- a/boards/nxp/lpcxpresso55s16/lpcxpresso55s16_common.dtsi +++ b/boards/nxp/lpcxpresso55s16/lpcxpresso55s16_common.dtsi @@ -147,8 +147,6 @@ &can0 { status = "okay"; - bus-speed = <125000>; - bus-speed-data = <1000000>; pinctrl-0 = <&pinmux_can0>; pinctrl-names = "default"; diff --git a/boards/nxp/lpcxpresso55s36/lpcxpresso55s36.dts b/boards/nxp/lpcxpresso55s36/lpcxpresso55s36.dts index be2b16c27f7..42b48e8c203 100644 --- a/boards/nxp/lpcxpresso55s36/lpcxpresso55s36.dts +++ b/boards/nxp/lpcxpresso55s36/lpcxpresso55s36.dts @@ -126,8 +126,6 @@ }; &can0 { - bus-speed = <125000>; - bus-speed-data = <1000000>; pinctrl-0 = <&pinmux_mcan_can0>; pinctrl-names = "default"; status = "okay"; diff --git a/boards/nxp/ls1046ardb/ls1046ardb_ls1046a_smp_4cores_defconfig b/boards/nxp/ls1046ardb/ls1046ardb_ls1046a_smp_4cores_defconfig index 8ae910c3a70..08e3206a3b8 100644 --- a/boards/nxp/ls1046ardb/ls1046ardb_ls1046a_smp_4cores_defconfig +++ b/boards/nxp/ls1046ardb/ls1046ardb_ls1046a_smp_4cores_defconfig @@ -9,6 +9,17 @@ CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=25000000 # Zephyr Kernel Configuration CONFIG_XIP=n CONFIG_AARCH64_IMAGE_HEADER=y +CONFIG_MAX_THREAD_BYTES=5 +CONFIG_MAX_XLAT_TABLES=10 + +# SMP support +CONFIG_SMP=y +CONFIG_MP_MAX_NUM_CPUS=4 +CONFIG_CACHE_MANAGEMENT=y +CONFIG_ARMV8_A_NS=y + +# PSCI is supported +CONFIG_PM_CPU_OPS=y # Serial Drivers CONFIG_SERIAL=y @@ -17,6 +28,3 @@ CONFIG_UART_INTERRUPT_DRIVEN=y # Enable Console CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y - -# SMP support -CONFIG_MP_MAX_NUM_CPUS=4 diff --git a/boards/nxp/mimxrt1010_evk/board.cmake b/boards/nxp/mimxrt1010_evk/board.cmake index d482b24e322..ec24e040231 100644 --- a/boards/nxp/mimxrt1010_evk/board.cmake +++ b/boards/nxp/mimxrt1010_evk/board.cmake @@ -6,5 +6,8 @@ board_runner_args(pyocd "--target=mimxrt1010") board_runner_args(jlink "--device=MIMXRT1011") +board_runner_args(linkserver "--device=MIMXRT1011xxxxx:EVK-MIMXRT1010") + +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/nxp/mimxrt1010_evk/doc/index.rst b/boards/nxp/mimxrt1010_evk/doc/index.rst index f830b49aab5..438b038baea 100644 --- a/boards/nxp/mimxrt1010_evk/doc/index.rst +++ b/boards/nxp/mimxrt1010_evk/doc/index.rst @@ -181,6 +181,24 @@ Attach a J-Link 10-pin connector to J55. Check that jumpers J61 and J62 are **off** (they are on by default when boards ship from the factory) to ensure SWD signals are disconnected from the OpenSDA microcontroller. +Using LinkServer +---------------- + +Install the :ref:`linkserver-debug-host-tools` and make sure they are in your +search path. To use LinkServer the on board CMSIS-DAP firmware need updated with +LPCScrypt installed with LinkServer. + +To enter board debuger FW update mode, connect J22 first, and power cycle board. +For more details please refer to `Debug_Probe_Firmware_Programming.pdf`, which is +installed with LinkServer. + +.. code-block:: console + + :Ubuntu/Mac: scripts/program_CMSIS + :Windows: scripts/program_CMSIS.cmd + +You may also se the ``-r linkserver`` option with West to use the LinkServer. + Configuring a Console ===================== diff --git a/boards/nxp/mimxrt1010_evk/init.c b/boards/nxp/mimxrt1010_evk/init.c index 1fd4b67e457..3e2b49b112e 100644 --- a/boards/nxp/mimxrt1010_evk/init.c +++ b/boards/nxp/mimxrt1010_evk/init.c @@ -7,7 +7,7 @@ void SystemInitHook(void) { -#if DT_SAME_NODE(DT_NODELABEL(flexspi), DT_PARENT(DT_CHOSEN(flash))) +#if DT_SAME_NODE(DT_NODELABEL(flexspi), DT_PARENT(DT_CHOSEN(zephyr_flash))) /* AT25SF128A SPI Flash on the RT1010-EVK requires special alignment * considerations, so set the READADDROPT bit in the FlexSPI so it * will fetch more data than each AHB burst requires to meet alignment diff --git a/boards/nxp/mimxrt1020_evk/doc/index.rst b/boards/nxp/mimxrt1020_evk/doc/index.rst index 0043cf5a8a3..4b409031729 100644 --- a/boards/nxp/mimxrt1020_evk/doc/index.rst +++ b/boards/nxp/mimxrt1020_evk/doc/index.rst @@ -106,8 +106,6 @@ already supported, which can also be re-used on this mimxrt1020_evk board: | UART | on-chip | serial port-polling; | | | | serial port-interrupt | +-----------+------------+-------------------------------------+ -| ENET | on-chip | ethernet | -+-----------+------------+-------------------------------------+ | USB | on-chip | USB device | +-----------+------------+-------------------------------------+ | ADC | on-chip | adc | diff --git a/boards/nxp/mimxrt1020_evk/mimxrt1020_evk.dts b/boards/nxp/mimxrt1020_evk/mimxrt1020_evk.dts index e873a0f2167..efa02f80add 100644 --- a/boards/nxp/mimxrt1020_evk/mimxrt1020_evk.dts +++ b/boards/nxp/mimxrt1020_evk/mimxrt1020_evk.dts @@ -160,19 +160,6 @@ arduino_serial: &lpuart2 { pinctrl-names = "default"; }; -&enet { - status = "okay"; - pinctrl-0 = <&pinmux_enet>; - pinctrl-names = "default"; - int-gpios = <&gpio1 4 GPIO_ACTIVE_HIGH>; - reset-gpios = <&gpio1 22 GPIO_ACTIVE_HIGH>; - ptp { - status = "okay"; - pinctrl-0 = <&pinmux_ptp>; - pinctrl-names = "default"; - }; -}; - zephyr_udc0: &usb1 { status = "okay"; }; diff --git a/boards/nxp/mimxrt1024_evk/doc/index.rst b/boards/nxp/mimxrt1024_evk/doc/index.rst index 3838189d20d..88eeb46c946 100644 --- a/boards/nxp/mimxrt1024_evk/doc/index.rst +++ b/boards/nxp/mimxrt1024_evk/doc/index.rst @@ -299,13 +299,3 @@ 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/nxp/mimxrt1024_evk/dts/nxp,enet-experimental.overlay b/boards/nxp/mimxrt1024_evk/dts/nxp,enet-experimental.overlay deleted file mode 100644 index 2229b2a9b70..00000000000 --- a/boards/nxp/mimxrt1024_evk/dts/nxp,enet-experimental.overlay +++ /dev/null @@ -1,135 +0,0 @@ -/* - * 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/nxp/mimxrt1024_evk/mimxrt1024_evk-pinctrl.dtsi b/boards/nxp/mimxrt1024_evk/mimxrt1024_evk-pinctrl.dtsi index 1090e394381..5f4b0d31b57 100644 --- a/boards/nxp/mimxrt1024_evk/mimxrt1024_evk-pinctrl.dtsi +++ b/boards/nxp/mimxrt1024_evk/mimxrt1024_evk-pinctrl.dtsi @@ -20,7 +20,6 @@ }; }; - /* Note: USER_LED conflicts with ENET_RST */ pinmux_enet: pinmux_enet { group0 { pinmux = <&iomuxc_gpio_ad_b0_08_enet_ref_clk>; @@ -31,21 +30,29 @@ input-enable; }; group1 { - pinmux = <&iomuxc_gpio_ad_b0_04_gpio1_io04>; + 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 = "100-mhz"; + nxp,speed = "200-mhz"; }; group2 { - 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>, - <&iomuxc_gpio_emc_40_enet_mdio>, + 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; @@ -53,7 +60,7 @@ slew-rate = "fast"; nxp,speed = "200-mhz"; }; - group3 { + group1 { pinmux = <&iomuxc_gpio_ad_b1_06_gpio1_io22>; drive-strength = "r0-5"; bias-pull-up; @@ -61,14 +68,20 @@ slew-rate = "slow"; nxp,speed = "100-mhz"; }; - group4 { - pinmux = <&iomuxc_gpio_ad_b0_10_enet_rx_data0>; - drive-strength = "r0-6"; - slew-rate = "slow"; + 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 */ + }; + pinmux_flexcan1: pinmux_flexcan1 { group0 { pinmux = <&iomuxc_gpio_sd_b1_00_flexcan1_tx>, @@ -173,10 +186,6 @@ }; }; - /* intentionally left empty */ - pinmux_ptp: pinmux_ptp { - }; - pinmux_sai3: pinmux_sai3 { group0 { pinmux = <&iomuxc_gpio_sd_b1_06_sai3_tx_bclk>, diff --git a/boards/nxp/mimxrt1024_evk/mimxrt1024_evk.dts b/boards/nxp/mimxrt1024_evk/mimxrt1024_evk.dts index 4872416bbc1..c2c90d85996 100644 --- a/boards/nxp/mimxrt1024_evk/mimxrt1024_evk.dts +++ b/boards/nxp/mimxrt1024_evk/mimxrt1024_evk.dts @@ -123,19 +123,35 @@ arduino_serial: &lpuart2 { }; }; -&enet { +&enet_mac { status = "okay"; pinctrl-0 = <&pinmux_enet>; pinctrl-names = "default"; - int-gpios = <&gpio1 22 GPIO_ACTIVE_HIGH>; - reset-gpios = <&gpio1 4 GPIO_ACTIVE_HIGH>; - ptp { + phy-handle = <&phy>; + zephyr,random-mac-address; + 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"; - pinctrl-0 = <&pinmux_ptp>; - pinctrl-names = "default"; + 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"; +}; + &lpuart1 { status = "okay"; current-speed = <115200>; @@ -152,7 +168,6 @@ arduino_serial: &lpuart2 { &flexcan1 { status = "okay"; - bus-speed = <125000>; pinctrl-0 = <&pinmux_flexcan1>; pinctrl-names = "default"; diff --git a/boards/nxp/mimxrt1050_evk/Kconfig.defconfig b/boards/nxp/mimxrt1050_evk/Kconfig.defconfig index bfb4a84e341..1db4e04d777 100644 --- a/boards/nxp/mimxrt1050_evk/Kconfig.defconfig +++ b/boards/nxp/mimxrt1050_evk/Kconfig.defconfig @@ -37,12 +37,33 @@ endif # NETWORKING if LVGL +# LVGL should allocate buffers equal to size of display config LV_Z_VDB_SIZE - default 16 + default 100 + +# Enable double buffering +config LV_Z_DOUBLE_VDB + default y + +# Force full refresh. This prevents memory copy associated with partial +# display refreshes, which is not necessary for the eLCDIF driver +config LV_Z_FULL_REFRESH + default y config LV_DPI_DEF default 128 +config LV_Z_BITS_PER_PIXEL + default 16 + +# Force display buffers to be aligned to cache line size (32 bytes) +config LV_Z_VDB_ALIGN + default 32 + +# Use offloaded render thread +config LV_Z_FLUSH_THREAD + default y + choice LV_COLOR_DEPTH default LV_COLOR_DEPTH_16 endchoice diff --git a/boards/nxp/mimxrt1050_evk/doc/index.rst b/boards/nxp/mimxrt1050_evk/doc/index.rst index 1b578ba824e..c5351b9b636 100644 --- a/boards/nxp/mimxrt1050_evk/doc/index.rst +++ b/boards/nxp/mimxrt1050_evk/doc/index.rst @@ -357,9 +357,10 @@ External JLink :ref:`jlink-external-debug-probe` Install the :ref:`jlink-debug-host-tools` and make sure they are in your search path. -Attach a J-Link 20-pin connector to J21. Check that jumpers J32 and J33 are -**off** (they are on by default when boards ship from the factory) to ensure -SWD signals are disconnected from the OpenSDA microcontroller. +Attach a J-Link 20-pin connector to J21. Check that jumpers J32 and J33 with +schematic rev A0/A1 or J47 and J48 with schematic rev B1 are **off** (they are +on by default when boards ship from the factory) to ensure SWD signals are +disconnected from the OpenSDA microcontroller. Configuring a Console ===================== @@ -486,13 +487,3 @@ 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/nxp/mimxrt1050_evk/dts/nxp,enet-experimental.overlay b/boards/nxp/mimxrt1050_evk/dts/nxp,enet-experimental.overlay deleted file mode 100644 index 7fe69f0d52e..00000000000 --- a/boards/nxp/mimxrt1050_evk/dts/nxp,enet-experimental.overlay +++ /dev/null @@ -1,122 +0,0 @@ -/* - * 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/nxp/mimxrt1050_evk/mimxrt1050_evk-pinctrl.dtsi b/boards/nxp/mimxrt1050_evk/mimxrt1050_evk-pinctrl.dtsi index 1b73a7453a9..7648bf72f65 100644 --- a/boards/nxp/mimxrt1050_evk/mimxrt1050_evk-pinctrl.dtsi +++ b/boards/nxp/mimxrt1050_evk/mimxrt1050_evk-pinctrl.dtsi @@ -50,7 +50,6 @@ }; }; - /* Note: USER_LED conflicts with ENET_RST */ pinmux_enet: pinmux_enet { group0 { pinmux = <&iomuxc_gpio_b1_10_enet_ref_clk>; @@ -61,24 +60,13 @@ input-enable; }; group1 { - pinmux = <&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 = "100-mhz"; - }; - group2 { 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>, - <&iomuxc_gpio_emc_40_enet_mdc>, - <&iomuxc_gpio_emc_41_enet_mdio>; + <&iomuxc_gpio_b1_11_enet_rx_er>; drive-strength = "r0-5"; bias-pull-up; bias-pull-up-value = "100k"; @@ -87,6 +75,30 @@ }; }; + 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"; + }; + }; + /* conflicts with SAI1 */ pinmux_flexcan1: pinmux_flexcan1 { group0 { @@ -310,16 +322,6 @@ }; }; - 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"; - }; - }; - pinmux_sai1: pinmux_sai1 { group0 { pinmux = <&iomuxc_gpio_ad_b1_09_sai1_mclk>, diff --git a/boards/nxp/mimxrt1050_evk/mimxrt1050_evk.dts b/boards/nxp/mimxrt1050_evk/mimxrt1050_evk.dts index e636fc207d5..4bd6b5bb441 100644 --- a/boards/nxp/mimxrt1050_evk/mimxrt1050_evk.dts +++ b/boards/nxp/mimxrt1050_evk/mimxrt1050_evk.dts @@ -193,19 +193,35 @@ arduino_serial: &lpuart3 { pinctrl-names = "default"; }; -&enet { +&enet_mac { status = "okay"; pinctrl-0 = <&pinmux_enet>; pinctrl-names = "default"; - int-gpios = <&gpio1 10 GPIO_ACTIVE_HIGH>; - reset-gpios = <&gpio1 9 GPIO_ACTIVE_HIGH>; - ptp { - pinctrl-0 = <&pinmux_ptp>; - pinctrl-names = "default"; + phy-handle = <&phy>; + zephyr,random-mac-address; + 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 = <&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"; +}; + zephyr_udc0: &usb1 { status = "okay"; }; @@ -233,6 +249,10 @@ zephyr_udc0: &usb1 { status = "okay"; }; +&pxp { + status = "okay"; +}; + /* GPT and Systick are enabled. If power management is enabled, the GPT * timer will be used instead of systick, as allows the core clock to * be gated. diff --git a/boards/nxp/mimxrt1060_evk/doc/index.rst b/boards/nxp/mimxrt1060_evk/doc/index.rst index b67ec5e417c..e33336ea986 100644 --- a/boards/nxp/mimxrt1060_evk/doc/index.rst +++ b/boards/nxp/mimxrt1060_evk/doc/index.rst @@ -474,13 +474,3 @@ 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/nxp/mimxrt1060_evk/dts/nxp,enet-experimental.overlay b/boards/nxp/mimxrt1060_evk/dts/nxp,enet-experimental.overlay deleted file mode 100644 index 7fe69f0d52e..00000000000 --- a/boards/nxp/mimxrt1060_evk/dts/nxp,enet-experimental.overlay +++ /dev/null @@ -1,122 +0,0 @@ -/* - * 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/nxp/mimxrt1060_evk/mimxrt1060_evk-pinctrl.dtsi b/boards/nxp/mimxrt1060_evk/mimxrt1060_evk-pinctrl.dtsi index f41f92ba1ee..3b8bae22183 100644 --- a/boards/nxp/mimxrt1060_evk/mimxrt1060_evk-pinctrl.dtsi +++ b/boards/nxp/mimxrt1060_evk/mimxrt1060_evk-pinctrl.dtsi @@ -50,7 +50,6 @@ }; }; - /* Note: USER_LED conflicts with ENET_RST */ pinmux_enet: pinmux_enet { group0 { pinmux = <&iomuxc_gpio_b1_10_enet_ref_clk>; @@ -61,24 +60,27 @@ input-enable; }; group1 { - pinmux = <&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 = "100-mhz"; - }; - group2 { 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>, - <&iomuxc_gpio_emc_40_enet_mdc>, - <&iomuxc_gpio_emc_41_enet_mdio>; + <&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"; @@ -87,6 +89,17 @@ }; }; + 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"; + }; + }; + + pinmux_flexcan3: pinmux_flexcan3 { group0 { pinmux = <&iomuxc_gpio_ad_b0_14_flexcan3_tx>, @@ -306,16 +319,6 @@ }; }; - 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"; - }; - }; - pinmux_sai1: pinmux_sai1 { group0 { pinmux = <&iomuxc_gpio_ad_b1_09_sai1_mclk>, diff --git a/boards/nxp/mimxrt1060_evk/mimxrt1060_evk.dts b/boards/nxp/mimxrt1060_evk/mimxrt1060_evk.dts index 7438f4b38b0..08eb8541432 100644 --- a/boards/nxp/mimxrt1060_evk/mimxrt1060_evk.dts +++ b/boards/nxp/mimxrt1060_evk/mimxrt1060_evk.dts @@ -164,19 +164,35 @@ arduino_i2c: &lpi2c1 { pinctrl-names = "default", "sleep"; }; -&enet { +&enet_mac { status = "okay"; pinctrl-0 = <&pinmux_enet>; pinctrl-names = "default"; - int-gpios = <&gpio1 10 GPIO_ACTIVE_HIGH>; - reset-gpios = <&gpio1 9 GPIO_ACTIVE_HIGH>; - ptp { - pinctrl-0 = <&pinmux_ptp>; - pinctrl-names = "default"; + phy-handle = <&phy>; + zephyr,random-mac-address; + 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 = <&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"; +}; + &adc1 { status = "okay"; pinctrl-0 = <&pinmux_adc1>; @@ -226,8 +242,6 @@ zephyr_udc0: &usb1 { &flexcan3 { status = "okay"; - bus-speed = <125000>; - bus-speed-data = <1000000>; pinctrl-0 = <&pinmux_flexcan3>; pinctrl-names = "default"; diff --git a/boards/nxp/mimxrt1060_evk/mimxrt1060_evk_mimxrt1062_hyperflash.yaml b/boards/nxp/mimxrt1060_evk/mimxrt1060_evk_mimxrt1062_hyperflash.yaml index 93a7915e6fd..8dbd8533c1c 100644 --- a/boards/nxp/mimxrt1060_evk/mimxrt1060_evk_mimxrt1062_hyperflash.yaml +++ b/boards/nxp/mimxrt1060_evk/mimxrt1060_evk_mimxrt1062_hyperflash.yaml @@ -25,6 +25,7 @@ supported: - gpio - i2c - netif:eth + - pwm - sdhc - spi - usb_device diff --git a/boards/nxp/mimxrt1060_evk/mimxrt1060_evk_mimxrt1062_qspi.yaml b/boards/nxp/mimxrt1060_evk/mimxrt1060_evk_mimxrt1062_qspi.yaml index 82e15486159..1cd757e66d5 100644 --- a/boards/nxp/mimxrt1060_evk/mimxrt1060_evk_mimxrt1062_qspi.yaml +++ b/boards/nxp/mimxrt1060_evk/mimxrt1060_evk_mimxrt1062_qspi.yaml @@ -19,17 +19,17 @@ supported: - arduino_i2c - arduino_serial - arduino_spi + - adc + - can - counter - display - dma - gpio - i2c - netif:eth + - pwm - sdhc - spi - usb_device - - dma - - can - watchdog - - adc vendor: nxp diff --git a/boards/nxp/mimxrt1062_fmurt6/mimxrt1062_fmurt6.dts b/boards/nxp/mimxrt1062_fmurt6/mimxrt1062_fmurt6.dts index ff6f1bf6827..85a53c07f29 100644 --- a/boards/nxp/mimxrt1062_fmurt6/mimxrt1062_fmurt6.dts +++ b/boards/nxp/mimxrt1062_fmurt6/mimxrt1062_fmurt6.dts @@ -109,7 +109,6 @@ status = "okay"; pinctrl-0 = <&pinmux_flexcan1>; pinctrl-names = "default"; - bus-speed = <125000>; can-transceiver { max-bitrate = <5000000>; }; @@ -119,7 +118,6 @@ status = "disabled"; pinctrl-0 = <&pinmux_flexcan2>; pinctrl-names = "default"; - bus-speed = <125000>; can-transceiver { max-bitrate = <5000000>; }; @@ -129,8 +127,6 @@ status = "disabled"; pinctrl-0 = <&pinmux_flexcan3>; pinctrl-names = "default"; - bus-speed = <125000>; - bus-speed-data = <1000000>; can-transceiver { max-bitrate = <5000000>; }; @@ -386,11 +382,23 @@ nxp,prescaler = <64>; }; -&enet2 { +&enet2_mac { + pinctrl-0 = <&pinmux_enet>; + pinctrl-names = "default"; + zephyr,random-mac-address; + phy-connection-type = "rmii"; + phy-handle = <&phy>; +}; + +&enet2_mdio { status = "okay"; pinctrl-0 = <&pinmux_enet>; pinctrl-names = "default"; - phy-addr = <0>; + phy: phy@0 { + compatible = "ethernet-phy"; + reg = <0>; + status = "okay"; + }; }; zephyr_udc0: &usb1 { diff --git a/boards/nxp/mimxrt1064_evk/dts/nxp,enet-experimental.overlay b/boards/nxp/mimxrt1064_evk/dts/nxp,enet-experimental.overlay deleted file mode 100644 index 7fe69f0d52e..00000000000 --- a/boards/nxp/mimxrt1064_evk/dts/nxp,enet-experimental.overlay +++ /dev/null @@ -1,122 +0,0 @@ -/* - * 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/nxp/mimxrt1064_evk/mimxrt1064_evk-pinctrl.dtsi b/boards/nxp/mimxrt1064_evk/mimxrt1064_evk-pinctrl.dtsi index d8be3020998..ce4b393e4e3 100644 --- a/boards/nxp/mimxrt1064_evk/mimxrt1064_evk-pinctrl.dtsi +++ b/boards/nxp/mimxrt1064_evk/mimxrt1064_evk-pinctrl.dtsi @@ -50,7 +50,6 @@ }; }; - /* Note: USER_LED conflicts with ENET_RST */ pinmux_enet: pinmux_enet { group0 { pinmux = <&iomuxc_gpio_b1_10_enet_ref_clk>; @@ -61,24 +60,13 @@ input-enable; }; group1 { - pinmux = <&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 = "100-mhz"; - }; - group2 { 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>, - <&iomuxc_gpio_emc_40_enet_mdc>, - <&iomuxc_gpio_emc_41_enet_mdio>; + <&iomuxc_gpio_b1_11_enet_rx_er>; drive-strength = "r0-5"; bias-pull-up; bias-pull-up-value = "100k"; @@ -87,6 +75,30 @@ }; }; + 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"; + }; + }; + /* conflicts with SAI1 */ pinmux_flexcan1: pinmux_flexcan1 { group0 { @@ -291,16 +303,6 @@ }; }; - 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"; - }; - }; - pinmux_sai1: pinmux_sai1 { group0 { pinmux = <&iomuxc_gpio_ad_b1_09_sai1_mclk>, diff --git a/boards/nxp/mimxrt1064_evk/mimxrt1064_evk.dts b/boards/nxp/mimxrt1064_evk/mimxrt1064_evk.dts index f6b6d5c74b2..7351659dd87 100644 --- a/boards/nxp/mimxrt1064_evk/mimxrt1064_evk.dts +++ b/boards/nxp/mimxrt1064_evk/mimxrt1064_evk.dts @@ -236,26 +236,43 @@ arduino_serial: &lpuart3 { pinctrl-names = "default", "sleep"; }; -&enet { +&enet_mac { status = "okay"; pinctrl-0 = <&pinmux_enet>; pinctrl-names = "default"; - int-gpios = <&gpio1 10 GPIO_ACTIVE_HIGH>; - reset-gpios = <&gpio1 9 GPIO_ACTIVE_HIGH>; - ptp { - pinctrl-0 = <&pinmux_ptp>; - pinctrl-names = "default"; + phy-handle = <&phy>; + zephyr,random-mac-address; + 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 = <&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"; +}; + + zephyr_udc0: &usb1 { status = "okay"; }; &csi { status = "okay"; - sensor = <&mt9m114>; + source = <&mt9m114>; pinctrl-0 = <&pinmux_csi>; pinctrl-names = "default"; @@ -293,7 +310,6 @@ zephyr_udc0: &usb1 { &flexcan2 { status = "okay"; - bus-speed = <125000>; pinctrl-0 = <&pinmux_flexcan2>; pinctrl-names = "default"; diff --git a/boards/nxp/mimxrt1160_evk/board.cmake b/boards/nxp/mimxrt1160_evk/board.cmake index e9c7d7ea8c7..08c159f552a 100644 --- a/boards/nxp/mimxrt1160_evk/board.cmake +++ b/boards/nxp/mimxrt1160_evk/board.cmake @@ -7,6 +7,7 @@ if(CONFIG_SOC_MIMXRT1166_CM7 OR CONFIG_SECOND_CORE_MCUX) board_runner_args(pyocd "--target=mimxrt1160_cm7") board_runner_args(jlink "--device=MIMXRT1166xxx6_M7" "--reset-after-load") +board_runner_args(linkserver "--device=MIMXRT1166xxxxx:MIMXRT1160-EVK") elseif(CONFIG_SOC_MIMXRT1166_CM4) board_runner_args(pyocd "--target=mimxrt1160_cm4") # Note: Please use JLINK above V7.50 (Only support run cm4 image when debugging due to default boot core on board is cm7 core) @@ -14,4 +15,5 @@ board_runner_args(jlink "--device=MIMXRT1166xxx6_M4") endif() 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/nxp/mimxrt1160_evk/doc/index.rst b/boards/nxp/mimxrt1160_evk/doc/index.rst index ca680d0a103..deaac1c22ec 100644 --- a/boards/nxp/mimxrt1160_evk/doc/index.rst +++ b/boards/nxp/mimxrt1160_evk/doc/index.rst @@ -267,10 +267,8 @@ 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. -.. _Using J-Link RT1160: - Using J-Link ---------------------------------- +------------ Install the :ref:`jlink-debug-host-tools` and make sure they are in your search path. @@ -279,6 +277,17 @@ There are two options: the onboard debug circuit can be updated with Segger J-Link firmware, or :ref:`jlink-external-debug-probe` can be attached to the EVK. See `Using J-Link with MIMXRT1160-EVK or MIMXRT1170-EVK`_ for more details. +Using LinkServer +---------------- + +Install the :ref:`linkserver-debug-host-tools` and make sure they are in your +search path. LinkServer works with the CMSIS-DAP firmware include in LinkServer +install. Please follow the ``LPCScrypt\docs\Debug_Probe_Firmware_Programming.pdf`` +for more details. + +Linkserver is the default runner. You may also se the ``-r linkserver`` option +with West to use the LinkServer runner. + Configuring a Console ===================== @@ -356,13 +365,3 @@ 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/nxp/mimxrt1160_evk/dts/nxp,enet-experimental.overlay b/boards/nxp/mimxrt1160_evk/dts/nxp,enet-experimental.overlay deleted file mode 100644 index 58b8a801622..00000000000 --- a/boards/nxp/mimxrt1160_evk/dts/nxp,enet-experimental.overlay +++ /dev/null @@ -1,123 +0,0 @@ -/* - * 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/nxp/mimxrt1160_evk/mimxrt1160_evk-pinctrl.dtsi b/boards/nxp/mimxrt1160_evk/mimxrt1160_evk-pinctrl.dtsi index 1f17d8d62de..e9428ef79e6 100644 --- a/boards/nxp/mimxrt1160_evk/mimxrt1160_evk-pinctrl.dtsi +++ b/boards/nxp/mimxrt1160_evk/mimxrt1160_evk-pinctrl.dtsi @@ -56,9 +56,7 @@ slew-rate = "fast"; }; group3 { - pinmux = <&iomuxc_gpio_ad_32_enet_mdc>, - <&iomuxc_gpio_ad_33_enet_mdio>, - <&iomuxc_gpio_disp_b2_02_enet_tdata00>, + 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"; @@ -72,6 +70,18 @@ }; }; + 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 { + }; + pinmux_flexcan3: pinmux_flexcan3 { group0 { pinmux = <&iomuxc_lpsr_gpio_lpsr_01_can3_rx>, @@ -219,10 +229,6 @@ }; }; - /* intentionally left empty */ - pinmux_ptp: pinmux_ptp { - }; - pinmux_sai1: pinmux_sai1 { group0 { pinmux = <&iomuxc_gpio_ad_17_sai1_mclk>, diff --git a/boards/nxp/mimxrt1160_evk/mimxrt1160_evk.dtsi b/boards/nxp/mimxrt1160_evk/mimxrt1160_evk.dtsi index 93e1c3452fa..62d3bd59998 100644 --- a/boards/nxp/mimxrt1160_evk/mimxrt1160_evk.dtsi +++ b/boards/nxp/mimxrt1160_evk/mimxrt1160_evk.dtsi @@ -133,15 +133,35 @@ pinctrl-names = "default"; }; -&enet { +&enet_mac { + status = "okay"; pinctrl-0 = <&pinmux_enet>; pinctrl-names = "default"; - ptp { - pinctrl-0 = <&pinmux_ptp>; - pinctrl-names = "default"; + phy-handle = <&phy>; + phy-connection-type = "rmii"; + zephyr,random-mac-address; +}; + +&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"; +}; + &csi { pinctrl-0 = <&pinmux_csi>; pinctrl-names = "default"; diff --git a/boards/nxp/mimxrt1160_evk/mimxrt1160_evk_mimxrt1166_cm7.dts b/boards/nxp/mimxrt1160_evk/mimxrt1160_evk_mimxrt1166_cm7.dts index 010d8e98af9..2f4e842873f 100644 --- a/boards/nxp/mimxrt1160_evk/mimxrt1160_evk_mimxrt1166_cm7.dts +++ b/boards/nxp/mimxrt1160_evk/mimxrt1160_evk_mimxrt1166_cm7.dts @@ -45,8 +45,6 @@ &flexcan3 { status = "okay"; - bus-speed = <125000>; - bus-speed-data = <1000000>; can-transceiver { max-bitrate = <5000000>; }; @@ -84,15 +82,6 @@ status = "okay"; }; -&enet { - status = "okay"; - int-gpios = <&gpio9 11 GPIO_ACTIVE_HIGH>; - reset-gpios = <&gpio12 12 GPIO_ACTIVE_HIGH>; - ptp { - status = "okay"; - }; -}; - zephyr_udc0: &usb1 { status = "okay"; }; diff --git a/boards/nxp/mimxrt1170_evk/CMakeLists.txt b/boards/nxp/mimxrt1170_evk/CMakeLists.txt index c564e77e492..e87e07401d0 100644 --- a/boards/nxp/mimxrt1170_evk/CMakeLists.txt +++ b/boards/nxp/mimxrt1170_evk/CMakeLists.txt @@ -28,16 +28,16 @@ if(CONFIG_NXP_IMXRT_BOOT_HEADER) zephyr_library_sources(${RT1170_BOARD_DIR}/xip/${RT1170_BOARD_NAME}_flexspi_nor_config.c) zephyr_library_include_directories(${RT1170_BOARD_DIR}/xip) endif() - if(CONFIG_DEVICE_CONFIGURATION_DATA) - # Include device configuration data block for RT1170 EVK from NXP's HAL. + if(CONFIG_EXTERNAL_MEM_CONFIG_DATA) + # Include external memory configuration data block for RT1170 EVK from NXP's HAL. # This configuration block may need modification if another SDRAM chip # is used on your custom board. - zephyr_compile_definitions(XIP_BOOT_HEADER_DCD_ENABLE=1) - zephyr_library_sources(${RT1170_BOARD_DIR}/dcd.c) + zephyr_compile_definitions(XIP_BOOT_HEADER_XMCD_ENABLE=1) + zephyr_library_sources(${RT1170_BOARD_DIR}/xmcd/xmcd.c) else() if(CONFIG_SRAM_BASE_ADDRESS EQUAL 0x80000000) - message(WARNING "You are using SDRAM as RAM but no device " - "configuration data (DCD) is included. This configuration may not boot") + message(WARNING "You are using SDRAM as RAM but no external memory" + "configuration data (XMCD) is included. This configuration may not boot") endif() endif() endif() diff --git a/boards/nxp/mimxrt1170_evk/Kconfig.defconfig b/boards/nxp/mimxrt1170_evk/Kconfig.defconfig index 395d8351794..a54b1b8a145 100644 --- a/boards/nxp/mimxrt1170_evk/Kconfig.defconfig +++ b/boards/nxp/mimxrt1170_evk/Kconfig.defconfig @@ -5,8 +5,8 @@ if BOARD_MIMXRT1170_EVK -# Only use DCD when booting primary core (M7) -config DEVICE_CONFIGURATION_DATA +# Use External Memory Configuration Data (XMCD) by default when booting primary core (M7) +config EXTERNAL_MEM_CONFIG_DATA default y if CPU_CORTEX_M7 config NXP_IMX_EXTERNAL_SDRAM diff --git a/boards/nxp/mimxrt1170_evk/doc/index.rst b/boards/nxp/mimxrt1170_evk/doc/index.rst index 13b8d795c16..d6a80009e7c 100644 --- a/boards/nxp/mimxrt1170_evk/doc/index.rst +++ b/boards/nxp/mimxrt1170_evk/doc/index.rst @@ -444,13 +444,3 @@ 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/nxp/mimxrt1170_evk/dts/nxp,enet-experimental.overlay b/boards/nxp/mimxrt1170_evk/dts/nxp,enet-experimental.overlay deleted file mode 100644 index 58b8a801622..00000000000 --- a/boards/nxp/mimxrt1170_evk/dts/nxp,enet-experimental.overlay +++ /dev/null @@ -1,123 +0,0 @@ -/* - * 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/nxp/mimxrt1170_evk/mimxrt1170_evk-pinctrl.dtsi b/boards/nxp/mimxrt1170_evk/mimxrt1170_evk-pinctrl.dtsi index 35e7c521532..43b1642da96 100644 --- a/boards/nxp/mimxrt1170_evk/mimxrt1170_evk-pinctrl.dtsi +++ b/boards/nxp/mimxrt1170_evk/mimxrt1170_evk-pinctrl.dtsi @@ -23,7 +23,10 @@ bias-pull-up; slew-rate = "fast"; }; - group2 { + }; + + pinmux_lpi2c6: pinmux_lpi2c6 { + group0 { pinmux = <&iomuxc_lpsr_gpio_lpsr_07_lpi2c6_scl>, <&iomuxc_lpsr_gpio_lpsr_06_lpi2c6_sda>; drive-strength = "high"; @@ -56,9 +59,7 @@ slew-rate = "fast"; }; group3 { - pinmux = <&iomuxc_gpio_ad_32_enet_mdc>, - <&iomuxc_gpio_ad_33_enet_mdio>, - <&iomuxc_gpio_disp_b2_02_enet_tdata00>, + 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"; @@ -72,6 +73,18 @@ }; }; + 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 { + }; + pinmux_flexcan3: pinmux_flexcan3 { group0 { pinmux = <&iomuxc_lpsr_gpio_lpsr_01_can3_rx>, @@ -219,10 +232,6 @@ }; }; - /* intentionally left empty */ - pinmux_ptp: pinmux_ptp { - }; - pinmux_sai1: pinmux_sai1 { group0 { pinmux = <&iomuxc_gpio_ad_17_sai1_mclk>, diff --git a/boards/nxp/mimxrt1170_evk/mimxrt1170_evk.dtsi b/boards/nxp/mimxrt1170_evk/mimxrt1170_evk.dtsi index 9e59e733ebc..e70890f911d 100644 --- a/boards/nxp/mimxrt1170_evk/mimxrt1170_evk.dtsi +++ b/boards/nxp/mimxrt1170_evk/mimxrt1170_evk.dtsi @@ -96,20 +96,45 @@ pinctrl-names = "default"; }; -&enet { +&enet_mac { + status = "okay"; pinctrl-0 = <&pinmux_enet>; pinctrl-names = "default"; - ptp { - pinctrl-0 = <&pinmux_ptp>; - pinctrl-names = "default"; + phy-handle = <&phy>; + phy-connection-type = "rmii"; + zephyr,random-mac-address; +}; + +&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"; +}; + &csi { pinctrl-0 = <&pinmux_csi>; pinctrl-names = "default"; }; +&lpi2c6 { + pinctrl-0 = <&pinmux_lpi2c6>; + pinctrl-names = "default"; +}; + &flexcan3 { pinctrl-0 = <&pinmux_flexcan3>; pinctrl-names = "default"; diff --git a/boards/nxp/mimxrt1170_evk/mimxrt1170_evk_mimxrt1176_cm7.dts b/boards/nxp/mimxrt1170_evk/mimxrt1170_evk_mimxrt1176_cm7.dts index 4040cd63676..95eff6eb715 100644 --- a/boards/nxp/mimxrt1170_evk/mimxrt1170_evk_mimxrt1176_cm7.dts +++ b/boards/nxp/mimxrt1170_evk/mimxrt1170_evk_mimxrt1176_cm7.dts @@ -74,8 +74,6 @@ zephyr_mipi_dsi: &mipi_dsi { &flexcan3 { status = "okay"; - bus-speed = <125000>; - bus-speed-data = <1000000>; can-transceiver { max-bitrate = <5000000>; }; @@ -128,14 +126,6 @@ nxp_mipi_i2c: &lpi2c5 { status = "okay"; }; -&enet { - status = "okay"; - int-gpios = <&gpio9 11 GPIO_ACTIVE_HIGH>; - reset-gpios = <&gpio12 12 GPIO_ACTIVE_HIGH>; - ptp { - status = "okay"; - }; -}; &sai1 { status = "okay"; diff --git a/boards/nxp/mimxrt1170_evk/mimxrt1170_evk_mimxrt1176_cm7_B.overlay b/boards/nxp/mimxrt1170_evk/mimxrt1170_evk_mimxrt1176_cm7_B.overlay index 4073b78a83e..a43339de27b 100644 --- a/boards/nxp/mimxrt1170_evk/mimxrt1170_evk_mimxrt1176_cm7_B.overlay +++ b/boards/nxp/mimxrt1170_evk/mimxrt1170_evk_mimxrt1176_cm7_B.overlay @@ -70,7 +70,12 @@ /delete-node/ fxos8700@1f; }; -/* Disable ethernet, as PHY is not supported */ -&enet { - status = "disabled"; +&enet_mdio { + /delete-node/ phy@0; + + phy: phy@0 { + compatible = "ethernet-phy"; + reg = <0>; + status = "okay"; + }; }; diff --git a/boards/nxp/mr_canhubk3/mr_canhubk3.dts b/boards/nxp/mr_canhubk3/mr_canhubk3.dts index 65f6c86d569..ba74e255f62 100644 --- a/boards/nxp/mr_canhubk3/mr_canhubk3.dts +++ b/boards/nxp/mr_canhubk3/mr_canhubk3.dts @@ -358,8 +358,6 @@ pinctrl-0 = <&flexcan0_default>; pinctrl-names = "default"; phys = <&can_phy0>; - bus-speed = <125000>; - bus-speed-data = <1000000>; status = "okay"; }; @@ -367,40 +365,30 @@ pinctrl-0 = <&flexcan1_default>; pinctrl-names = "default"; phys = <&can_phy1>; - bus-speed = <125000>; - bus-speed-data = <1000000>; }; &flexcan2 { pinctrl-0 = <&flexcan2_default>; pinctrl-names = "default"; phys = <&can_phy2>; - bus-speed = <125000>; - bus-speed-data = <1000000>; }; &flexcan3 { pinctrl-0 = <&flexcan3_default>; pinctrl-names = "default"; phys = <&can_phy3>; - bus-speed = <125000>; - bus-speed-data = <1000000>; }; &flexcan4 { pinctrl-0 = <&flexcan4_default>; pinctrl-names = "default"; phys = <&can_phy4>; - bus-speed = <125000>; - bus-speed-data = <1000000>; }; &flexcan5 { pinctrl-0 = <&flexcan5_default>; pinctrl-names = "default"; phys = <&can_phy5>; - bus-speed = <125000>; - bus-speed-data = <1000000>; }; &lpi2c0 { diff --git a/boards/nxp/rd_rw612_bga/Kconfig.defconfig b/boards/nxp/rd_rw612_bga/Kconfig.defconfig index 713d8594e88..376f96da2b3 100644 --- a/boards/nxp/rd_rw612_bga/Kconfig.defconfig +++ b/boards/nxp/rd_rw612_bga/Kconfig.defconfig @@ -30,4 +30,8 @@ config LV_Z_FLUSH_THREAD endif # LVGL +# Enable interrupt support when using FT5336 driver +config INPUT_FT5336_INTERRUPT + default y if INPUT + endif # BOARD_RD_RW612_BGA diff --git a/boards/nxp/rd_rw612_bga/Kconfig.rd_rw612_bga b/boards/nxp/rd_rw612_bga/Kconfig.rd_rw612_bga index 80151467e90..17a3090d41a 100644 --- a/boards/nxp/rd_rw612_bga/Kconfig.rd_rw612_bga +++ b/boards/nxp/rd_rw612_bga/Kconfig.rd_rw612_bga @@ -2,4 +2,4 @@ # SPDX-License-Identifier: Apache-2.0 config BOARD_RD_RW612_BGA - select SOC_PART_NUMBER_RW612ETA1I + select SOC_PART_NUMBER_RW612ETA2I diff --git a/boards/nxp/rd_rw612_bga/doc/index.rst b/boards/nxp/rd_rw612_bga/doc/index.rst index c31df4ab448..42783abb9bb 100644 --- a/boards/nxp/rd_rw612_bga/doc/index.rst +++ b/boards/nxp/rd_rw612_bga/doc/index.rst @@ -45,7 +45,7 @@ Supported Features +-----------+------------+-----------------------------------+ | I2C | on-chip | i2c | +-----------+------------+-----------------------------------+ -| FLEXSPI | on-chip | flash | +| FLEXSPI | on-chip | flash/memc | +-----------+------------+-----------------------------------+ | TRNG | on-chip | entropy | +-----------+------------+-----------------------------------+ @@ -61,7 +61,11 @@ Supported Features +-----------+------------+-----------------------------------+ | MRT | on-chip | counter | +-----------+------------+-----------------------------------+ - +| OS_TIMER | on-chip | os timer | ++-----------+------------+-----------------------------------+ +| PM | on-chip | power management; uses SoC Power | +| | | Modes 1 and 2 | ++-----------+------------+-----------------------------------+ The default configuration can be found in the defconfig file: diff --git a/boards/nxp/rd_rw612_bga/dts/goworld_16880_lcm.overlay b/boards/nxp/rd_rw612_bga/dts/goworld_16880_lcm.overlay new file mode 100644 index 00000000000..8b9dbe92491 --- /dev/null +++ b/boards/nxp/rd_rw612_bga/dts/goworld_16880_lcm.overlay @@ -0,0 +1,91 @@ +#include + +/ { + chosen { + zephyr,display = &st7796s_lcdic; + }; + + lvgl_pointer { + compatible = "zephyr,lvgl-pointer-input"; + input = <&ft7401>; + swap-xy; + invert-y; + }; +}; + +&lcdic { + status = "okay"; + nxp,swap-bytes; + /* + * Settings to connect this display: + * Populate the following resistors: + * - R125, R123, R12, R124, R15, R243, R239, R236, R233, R286, R246 + * Remove the following resistors: + * - R9, R11, R20, R19, R242, R241, R237, R235, R245 + * Remove JP30 to disconnect Flexcomm SPI CS + * Display can be connected to Arduino header (J5/J6) + * Pin # | Signal | Header + * ------------------------------- + * 1 | VDD | J5.8 (+3.3V) + * 2 | RST | J6.8 (LCD_SPI_RESETN) + * 3 | SDO | J5.5 (SPI_MISO) + * 4 | CS | J5.3 (LCD_SPI_SS) + * 5 | SCLK | J5.6 (LCD_SPI_SCK) + * 6 | GND | J5.7 (GND) + * 7 | MOSI | J5.4 (LCD_SPI_SDIO) + * 8 | CD | J5.1 (LCD_SPI_DC) + * 9 | TE | J5.2 (LCD_SPI_TE, not enabled) + * + * Pins 10 and 11 correspond to the backlight anode and cathode, + * and must be driven by an external circuit + */ + st7796s_lcdic: st7796s@0 { + compatible = "sitronix,st7796s"; + status = "okay"; + reg = <0>; + mipi-max-frequency = <23000000>; + duplex = ; + height = <320>; + width = <480>; + invert-mode = "1-dot"; + frmctl1 = [80 10]; + bpc = [1F 50 00 20]; + dfc = [8A 07 3B]; + pwr1 = [80 64]; + pwr2 = <0x13>; + pwr3 = <0xA7>; + vcmpctl = <0x09>; + doca = [40 8A 00 00 29 19 A5 38]; + pgc = [F0 06 0B 07 06 05 2E 33 47 3A 17 16 2E 31]; + ngc = [F0 09 0D 09 08 23 2E 33 46 38 13 13 2C 32]; + madctl = <0x28>; + }; +}; + +&flexcomm2 { + status = "okay"; + ft7401: ft7401@38 { + /* + * Settings to connect this touch controller: + * Populate JP3 and JP50 to connect I2C + * Controller can be connected to Arduino Header (J8/J5) + * Pin #1 | Signal | Header + * ------------------------------- + * 1 | VDD | J8.2 (+3.3V) + * 2 | IOVDD | J8.4 (+3.3V) + * 3 | SCL | J5.10 (SCL) + * 4 | SDA | J5.9 (SDA) + * 5 | INT | J6.3 (D2) + * 6 | RST | J6.4 (D3) + * 7 | GND | J8.6 (GND) + * 8 | GND | J8.7 (GND) + * + * Note- the actual controller present on this IC is a FT7401, + * but the FT5336 driver in Zephyr supports this IC. + */ + compatible = "focaltech,ft5336"; + reg = <0x38>; + reset-gpios = <&hsgpio0 15 GPIO_ACTIVE_LOW>; + int-gpios = <&hsgpio0 11 GPIO_ACTIVE_HIGH>; + }; +}; diff --git a/boards/nxp/rd_rw612_bga/rd_rw612_bga-pinctrl.dtsi b/boards/nxp/rd_rw612_bga/rd_rw612_bga-pinctrl.dtsi index 04140e2a68c..db565403583 100644 --- a/boards/nxp/rd_rw612_bga/rd_rw612_bga-pinctrl.dtsi +++ b/boards/nxp/rd_rw612_bga/rd_rw612_bga-pinctrl.dtsi @@ -70,5 +70,21 @@ slew-rate = "ultra"; bias-pull-down; }; + + group2 { + pinmux = ; + slew-rate = "normal"; + }; + + group3 { + pinmux = ; + slew-rate = "normal"; + bias-pull-down; + }; }; }; diff --git a/boards/nxp/rd_rw612_bga/rd_rw612_bga.dts b/boards/nxp/rd_rw612_bga/rd_rw612_bga.dts index 23321fd1cdd..4a3f9588494 100644 --- a/boards/nxp/rd_rw612_bga/rd_rw612_bga.dts +++ b/boards/nxp/rd_rw612_bga/rd_rw612_bga.dts @@ -11,4 +11,5 @@ / { model = "nxp,rd_rw612_bga"; + compatible = "nxp,rd_rw612_bga"; }; diff --git a/boards/nxp/rd_rw612_bga/rd_rw612_bga.dtsi b/boards/nxp/rd_rw612_bga/rd_rw612_bga.dtsi index a9f52c885e3..3310e806608 100644 --- a/boards/nxp/rd_rw612_bga/rd_rw612_bga.dtsi +++ b/boards/nxp/rd_rw612_bga/rd_rw612_bga.dtsi @@ -116,6 +116,7 @@ arduino_i2c: &flexcomm2 { ahb-cacheable; ahb-read-addr-opt; rx-clock-source = <1>; + rx-clock-source-b = <3>; pinctrl-0 = <&pinmux_flexspi>; pinctrl-names = "default"; status = "okay"; @@ -156,6 +157,25 @@ arduino_i2c: &flexcomm2 { }; }; }; + is66wvq8m4: is66wvq8m4@2 { + compatible = "nxp,imx-flexspi-is66wvq8m4"; + /* IS66WVQ8M4 is 4MB, 32MBit pSRAM */ + size = ; + reg = <2>; + spi-max-frequency = <256000000>; + /* PSRAM cannot be enabled while board is in default XIP + * configuration, as it will conflict with flash chip. + */ + status = "disabled"; + cs-interval-unit = <1>; + cs-interval = <5>; + cs-hold-time = <2>; + cs-setup-time = <3>; + data-valid-time = <1>; + column-space = <14>; + ahb-write-wait-unit = <2>; + ahb-write-wait-interval = <0>; + }; }; &dmic0 { @@ -226,3 +246,21 @@ zephyr_udc0: &usb_otg { , ; }; + +&adc0 { + status = "okay"; +}; + +&dac0 { + status = "okay"; +}; + +/* OS Timer is the wakeup source for PM mode 2 */ +&os_timer { + status = "okay"; + wakeup-source; +}; + +&systick { + status = "disabled"; +}; diff --git a/boards/nxp/rd_rw612_bga/rd_rw612_bga.yaml b/boards/nxp/rd_rw612_bga/rd_rw612_bga.yaml index db7445f1c95..919f10479ee 100644 --- a/boards/nxp/rd_rw612_bga/rd_rw612_bga.yaml +++ b/boards/nxp/rd_rw612_bga/rd_rw612_bga.yaml @@ -25,3 +25,5 @@ supported: - watchdog - counter - hwinfo + - adc + - dac diff --git a/boards/nxp/rddrone_fmuk66/rddrone_fmuk66-pinctrl.dtsi b/boards/nxp/rddrone_fmuk66/rddrone_fmuk66-pinctrl.dtsi index 5d560f26154..a9bfe8d6d9f 100644 --- a/boards/nxp/rddrone_fmuk66/rddrone_fmuk66-pinctrl.dtsi +++ b/boards/nxp/rddrone_fmuk66/rddrone_fmuk66-pinctrl.dtsi @@ -10,7 +10,7 @@ #include &pinctrl { - enet_default: enet_default { + mdio_default: mdio_default { group0 { pinmux = ; drive-strength = "low"; @@ -19,14 +19,21 @@ slew-rate = "fast"; }; group1 { + pinmux = ; + drive-strength = "low"; + slew-rate = "fast"; + }; + }; + + enet_default: enet_default { + group0 { pinmux = , , , , , , - , - ; + ; drive-strength = "low"; slew-rate = "fast"; }; diff --git a/boards/nxp/rddrone_fmuk66/rddrone_fmuk66.dts b/boards/nxp/rddrone_fmuk66/rddrone_fmuk66.dts index 90c7493c82f..8d2b01c44ba 100644 --- a/boards/nxp/rddrone_fmuk66/rddrone_fmuk66.dts +++ b/boards/nxp/rddrone_fmuk66/rddrone_fmuk66.dts @@ -145,6 +145,7 @@ #pwm-cells = <3>; pinctrl-0 = <&ftm0_default>; pinctrl-names = "default"; + clock-source = "fixed"; }; @@ -155,6 +156,7 @@ #pwm-cells = <3>; pinctrl-0 = <&ftm3_default>; pinctrl-names = "default"; + clock-source = "fixed"; }; /* LPUART connected to debug header */ @@ -237,43 +239,48 @@ 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 0x000E9000>; }; - slot1_partition: partition@80000 { + slot1_partition: partition@F9000 { label = "image-1"; - reg = <0x00080000 0x00060000>; + reg = <0x000F9000 0x000E8000>; }; - scratch_partition: partition@e0000 { - label = "image-scratch"; - reg = <0x000e0000 0x00020000>; + storage_partition: partition@1e1000 { + label = "storage"; + reg = <0x001e1000 0x0001f000>; }; }; }; -&enet { +&enet_mac { status = "okay"; pinctrl-0 = <&enet_default>; pinctrl-names = "default"; + phy-connection-type = "rmii"; + phy-handle = <&phy>; + zephyr,random-mac-address; +}; + +&enet_mdio { + status = "okay"; + pinctrl-0 = <&mdio_default>; + pinctrl-names = "default"; + phy: phy@0 { + compatible = "ethernet-phy"; + reg = <0>; + status = "okay"; + }; }; &flexcan0 { status = "okay"; pinctrl-0 = <&flexcan0_default>; pinctrl-names = "default"; - bus-speed = <125000>; phys = <&transceiver0>; }; @@ -281,7 +288,6 @@ zephyr_udc0: &usbotg { status = "okay"; pinctrl-0 = <&flexcan1_default>; pinctrl-names = "default"; - bus-speed = <125000>; phys = <&transceiver1>; }; diff --git a/boards/nxp/s32z2xxdc2/s32z2xxdc2_s32z270.dtsi b/boards/nxp/s32z2xxdc2/s32z2xxdc2_s32z270.dtsi index 297b4926d11..1270676c77a 100644 --- a/boards/nxp/s32z2xxdc2/s32z2xxdc2_s32z270.dtsi +++ b/boards/nxp/s32z2xxdc2/s32z2xxdc2_s32z270.dtsi @@ -34,14 +34,10 @@ &can0 { pinctrl-0 = <&can0_default>; pinctrl-names = "default"; - bus-speed = <125000>; - bus-speed-data = <1000000>; status = "okay"; }; &can1 { pinctrl-0 = <&can1_default>; pinctrl-names = "default"; - bus-speed = <125000>; - bus-speed-data = <1000000>; }; diff --git a/boards/nxp/twr_ke18f/twr_ke18f.dts b/boards/nxp/twr_ke18f/twr_ke18f.dts index a926827d0e6..e0f3e1d242c 100644 --- a/boards/nxp/twr_ke18f/twr_ke18f.dts +++ b/boards/nxp/twr_ke18f/twr_ke18f.dts @@ -226,6 +226,7 @@ #pwm-cells = <3>; pinctrl-0 = <&ftm0_default>; pinctrl-names = "default"; + clock-source = "fixed"; }; &ftm3 { @@ -234,6 +235,7 @@ #pwm-cells = <3>; pinctrl-0 = <&ftm3_default>; pinctrl-names = "default"; + clock-source = "fixed"; }; &lpi2c0 { @@ -291,7 +293,6 @@ &flexcan0 { status = "okay"; - bus-speed = <125000>; pinctrl-0 = <&flexcan0_default>; pinctrl-names = "default"; @@ -339,21 +340,20 @@ label = "mcuboot"; reg = <0x00000000 0xc000>; }; + /* 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 = <0x0000c000 0x32000>; + reg = <0x0000c000 0x37000>; }; - slot1_partition: partition@3e000 { + slot1_partition: partition@43000 { label = "image-1"; - reg = <0x0003e000 0x32000>; - }; - scratch_partition: partition@70000 { - label = "image-scratch"; - reg = <0x00070000 0xa000>; + reg = <0x00043000 0x36000>; }; - storage_partition: partition@7a000 { + storage_partition: partition@79000 { label = "storage"; - reg = <0x0007a000 0x00006000>; + reg = <0x00079000 0x00007000>; }; }; }; diff --git a/boards/nxp/twr_kv58f220m/twr_kv58f220m.dts b/boards/nxp/twr_kv58f220m/twr_kv58f220m.dts index 72fdec68c83..f79c840942c 100644 --- a/boards/nxp/twr_kv58f220m/twr_kv58f220m.dts +++ b/boards/nxp/twr_kv58f220m/twr_kv58f220m.dts @@ -118,21 +118,20 @@ label = "mcuboot"; reg = <0x00000000 0x10000>; }; - storage_partition: partition@10000 { - label = "storage"; - reg = <0x00010000 0x10000>; - }; - slot0_partition: partition@20000 { + /* 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 = <0x00020000 0x60000>; + reg = <0x00010000 0x68000>; }; - slot1_partition: partition@80000 { + slot1_partition: partition@78000 { label = "image-1"; - reg = <0x00080000 0x60000>; + reg = <0x00078000 0x66000>; }; - scratch_partition: partition@e0000 { + storage_partition: partition@de000 { label = "image-scratch"; - reg = <0x000e0000 0x20000>; + reg = <0x000de000 0x22000>; }; }; }; diff --git a/boards/nxp/ucans32k1sic/ucans32k1sic.dts b/boards/nxp/ucans32k1sic/ucans32k1sic.dts index 9f6b37248c7..77b95236343 100644 --- a/boards/nxp/ucans32k1sic/ucans32k1sic.dts +++ b/boards/nxp/ucans32k1sic/ucans32k1sic.dts @@ -149,7 +149,8 @@ compatible = "nxp,kinetis-ftm-pwm"; pinctrl-0 = <&ftm0_default>; pinctrl-names = "default"; - prescaler = <128>; + clock-source = "system"; + prescaler = <4>; #pwm-cells = <3>; status = "okay"; }; @@ -158,6 +159,8 @@ compatible = "nxp,kinetis-ftm-pwm"; pinctrl-0 = <&ftm1_default>; pinctrl-names = "default"; + clock-source = "system"; + prescaler = <4>; #pwm-cells = <3>; status = "okay"; }; @@ -166,6 +169,8 @@ compatible = "nxp,kinetis-ftm-pwm"; pinctrl-0 = <&ftm2_default>; pinctrl-names = "default"; + clock-source = "system"; + prescaler = <4>; #pwm-cells = <3>; status = "okay"; }; @@ -174,8 +179,6 @@ pinctrl-0 = <&flexcan0_default>; pinctrl-names = "default"; phys = <&can_phy0>; - bus-speed = <125000>; - bus-speed-data = <1000000>; status = "okay"; }; @@ -183,7 +186,5 @@ pinctrl-0 = <&flexcan1_default>; pinctrl-names = "default"; phys = <&can_phy1>; - bus-speed = <125000>; - bus-speed-data = <1000000>; status = "okay"; }; diff --git a/boards/nxp/vmu_rt1170/vmu_rt1170-pinctrl.dtsi b/boards/nxp/vmu_rt1170/vmu_rt1170-pinctrl.dtsi index ac50cfa8b76..e7ab7ce896b 100644 --- a/boards/nxp/vmu_rt1170/vmu_rt1170-pinctrl.dtsi +++ b/boards/nxp/vmu_rt1170/vmu_rt1170-pinctrl.dtsi @@ -344,20 +344,9 @@ <&iomuxc_gpio_sd_b1_02_usdhc1_data0>, <&iomuxc_gpio_sd_b1_03_usdhc1_data1>, <&iomuxc_gpio_sd_b1_04_usdhc1_data2>, - <&iomuxc_gpio_sd_b1_05_usdhc1_data3>; + <&iomuxc_gpio_sd_b1_05_usdhc1_data3>, + <&iomuxc_gpio_sd_b1_01_usdhc1_clk>; bias-pull-up; - drive-strength = "high"; - slew-rate = "fast"; - input-enable; - }; - group1 { - pinmux = <&iomuxc_gpio_sd_b1_01_usdhc1_clk>; - drive-strength = "high"; - slew-rate = "fast"; - }; - group2 { - pinmux = <&iomuxc_gpio_ad_32_usdhc1_cd_b>; - bias-pull-down; input-enable; }; }; diff --git a/boards/nxp/vmu_rt1170/vmu_rt1170_mimxrt1176_cm7.dts b/boards/nxp/vmu_rt1170/vmu_rt1170_mimxrt1176_cm7.dts index 564164c5ae4..c2ea2f47496 100644 --- a/boards/nxp/vmu_rt1170/vmu_rt1170_mimxrt1176_cm7.dts +++ b/boards/nxp/vmu_rt1170/vmu_rt1170_mimxrt1176_cm7.dts @@ -175,8 +175,6 @@ status = "okay"; pinctrl-0 = <&pinmux_flexcan1>; pinctrl-names = "default"; - bus-speed = <125000>; - bus-speed-data = <1000000>; can-transceiver { max-bitrate = <5000000>; }; @@ -186,8 +184,6 @@ status = "okay"; pinctrl-0 = <&pinmux_flexcan2>; pinctrl-names = "default"; - bus-speed = <125000>; - bus-speed-data = <1000000>; can-transceiver { max-bitrate = <5000000>; }; @@ -197,8 +193,6 @@ status = "okay"; pinctrl-0 = <&pinmux_flexcan3>; pinctrl-names = "default"; - bus-speed = <125000>; - bus-speed-data = <1000000>; can-transceiver { max-bitrate = <5000000>; }; @@ -402,6 +396,7 @@ status = "okay"; no-1-8-v; pwr-gpios = <&gpio1 1 GPIO_ACTIVE_HIGH>; + cd-gpios = <&gpio3 31 (GPIO_ACTIVE_LOW | GPIO_PULL_DOWN)>; sdmmc { compatible = "zephyr,sdmmc-disk"; status = "okay"; diff --git a/boards/olimex/lora_stm32wl_devkit/olimex_lora_stm32wl_devkit_D.yaml b/boards/olimex/lora_stm32wl_devkit/olimex_lora_stm32wl_devkit_D.yaml index 29559d1e262..ead08879d1b 100644 --- a/boards/olimex/lora_stm32wl_devkit/olimex_lora_stm32wl_devkit_D.yaml +++ b/boards/olimex/lora_stm32wl_devkit/olimex_lora_stm32wl_devkit_D.yaml @@ -1,5 +1,5 @@ identifier: olimex_lora_stm32wl_devkit@D -name: Olimex LoRa STM32WL DevKit +name: Olimex LoRa STM32WL DevKit (rev. D) type: mcu arch: arm toolchain: diff --git a/boards/olimex/olimex_esp32_evb/olimex_esp32_evb_esp32_appcpu.dts b/boards/olimex/olimex_esp32_evb/olimex_esp32_evb_appcpu.dts similarity index 100% rename from boards/olimex/olimex_esp32_evb/olimex_esp32_evb_esp32_appcpu.dts rename to boards/olimex/olimex_esp32_evb/olimex_esp32_evb_appcpu.dts diff --git a/boards/olimex/olimex_esp32_evb/olimex_esp32_evb_appcpu.yaml b/boards/olimex/olimex_esp32_evb/olimex_esp32_evb_appcpu.yaml new file mode 100644 index 00000000000..fa3b6417b90 --- /dev/null +++ b/boards/olimex/olimex_esp32_evb/olimex_esp32_evb_appcpu.yaml @@ -0,0 +1,27 @@ +identifier: olimex_esp32_evb/esp32/appcpu +name: Olimex ESP32-EVB 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/olimex/olimex_esp32_evb/olimex_esp32_evb_esp32_appcpu_defconfig b/boards/olimex/olimex_esp32_evb/olimex_esp32_evb_appcpu_defconfig similarity index 100% rename from boards/olimex/olimex_esp32_evb/olimex_esp32_evb_esp32_appcpu_defconfig rename to boards/olimex/olimex_esp32_evb/olimex_esp32_evb_appcpu_defconfig diff --git a/boards/olimex/olimex_esp32_evb/olimex_esp32_evb_esp32_appcpu.yaml b/boards/olimex/olimex_esp32_evb/olimex_esp32_evb_esp32_appcpu.yaml deleted file mode 100644 index 9e81868de21..00000000000 --- a/boards/olimex/olimex_esp32_evb/olimex_esp32_evb_esp32_appcpu.yaml +++ /dev/null @@ -1,27 +0,0 @@ -identifier: olimex_esp32_evb/esp32/appcpu -name: Olimex ESP32-EVB -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/olimex/olimex_esp32_evb/olimex_esp32_evb_esp32_procpu.dts b/boards/olimex/olimex_esp32_evb/olimex_esp32_evb_esp32_procpu.dts deleted file mode 100644 index 11747f1a7b6..00000000000 --- a/boards/olimex/olimex_esp32_evb/olimex_esp32_evb_esp32_procpu.dts +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright (c) 2022 Henrik Brix Andersen - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/dts-v1/; - -#include -#include "olimex_esp32_evb-pinctrl.dtsi" -#include - -/ { - model = "Olimex ESP32-EVB"; - compatible = "olimex,esp32-evb", "espressif,esp32-wroom-32e", "espressif,esp32"; - - chosen { - zephyr,console = &uart0; - zephyr,shell-uart = &uart0; - zephyr,sram = &sram0; - zephyr,flash = &flash0; - zephyr,code-partition = &slot0_partition; - }; - - aliases { - sw0 = &button1; - watchdog0 = &wdt0; - }; - - gpio_keys { - compatible = "gpio-keys"; - button1: button1 { - gpios = <&gpio 34 GPIO_ACTIVE_LOW>; - label = "BUT1"; - zephyr,code = ; - }; - }; - - relay1: relay1 { - compatible = "regulator-fixed"; - enable-gpios = <&gpio 32 GPIO_ACTIVE_HIGH>; - regulator-name = "REL1"; - startup-delay-us = <10000>; - off-on-delay-us = <5000>; - }; - - relay2: relay2 { - compatible = "regulator-fixed"; - enable-gpios = <&gpio 33 GPIO_ACTIVE_HIGH>; - regulator-name = "REL2"; - startup-delay-us = <10000>; - off-on-delay-us = <5000>; - }; -}; - -&cpu0 { - clock-frequency = ; -}; - -&cpu1 { - clock-frequency = ; -}; - -uext_serial: &uart1 {}; -uext_i2c: &i2c0 {}; -uext_spi: &spi2 {}; - -&uart0 { - status = "okay"; - current-speed = <115200>; - pinctrl-0 = <&uart0_default>; - pinctrl-names = "default"; -}; - -&uart1 { - status = "okay"; - current-speed = <115200>; - pinctrl-0 = <&uart1_default>; - pinctrl-names = "default"; -}; - -&i2c0 { - status = "okay"; - clock-frequency = ; - sda-gpios = <&gpio0 16 GPIO_OPEN_DRAIN>; - scl-gpios = <&gpio0 13 GPIO_OPEN_DRAIN>; - pinctrl-0 = <&i2c0_default>; - pinctrl-names = "default"; -}; - -&spi2 { - status = "okay"; - pinctrl-0 = <&spim2_default>; - pinctrl-names = "default"; - #address-cells = <1>; - #size-cells = <0>; -}; - -&twai { - status = "okay"; - pinctrl-0 = <&twai_default>; - pinctrl-names = "default"; - bus-speed = <125000>; - - can-transceiver { - max-bitrate = <1000000>; - }; -}; - -&gpio0 { - status = "okay"; -}; - -&gpio1 { - status = "okay"; -}; - -&timer0 { - status = "okay"; -}; - -&timer1 { - status = "okay"; -}; - -&timer2 { - status = "okay"; -}; - -&timer3 { - status = "okay"; -}; - -&trng0 { - status = "okay"; -}; - -&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 DT_SIZE_K(60)>; - read-only; - }; - - /* Reserve 1024kB for the application in slot 0 */ - slot0_partition: partition@10000 { - label = "image-0"; - reg = <0x00010000 DT_SIZE_K(1024)>; - }; - - /* Reserve 1024kB for the application in slot 1 */ - slot1_partition: partition@110000 { - label = "image-1"; - reg = <0x00110000 DT_SIZE_K(1024)>; - }; - - /* Reserve 256kB for the scratch partition */ - scratch_partition: partition@210000 { - label = "image-scratch"; - reg = <0x00210000 DT_SIZE_K(256)>; - }; - - storage_partition: partition@250000 { - label = "storage"; - reg = <0x00250000 DT_SIZE_K(24)>; - }; - }; -}; diff --git a/boards/olimex/olimex_esp32_evb/olimex_esp32_evb_esp32_procpu.yaml b/boards/olimex/olimex_esp32_evb/olimex_esp32_evb_esp32_procpu.yaml deleted file mode 100644 index f4929c52b42..00000000000 --- a/boards/olimex/olimex_esp32_evb/olimex_esp32_evb_esp32_procpu.yaml +++ /dev/null @@ -1,20 +0,0 @@ -identifier: olimex_esp32_evb/esp32/procpu -name: Olimex ESP32-EVB -type: mcu -arch: xtensa -toolchain: - - zephyr -supported: - - can - - counter - - gpio - - hwinfo - - i2c - - spi - - uart - - watchdog -testing: - ignore_tags: - - net - - bluetooth -vendor: olimex diff --git a/boards/olimex/olimex_esp32_evb/olimex_esp32_evb_procpu.dts b/boards/olimex/olimex_esp32_evb/olimex_esp32_evb_procpu.dts new file mode 100644 index 00000000000..63070f08e1c --- /dev/null +++ b/boards/olimex/olimex_esp32_evb/olimex_esp32_evb_procpu.dts @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2022 Henrik Brix Andersen + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include "olimex_esp32_evb-pinctrl.dtsi" +#include + +/ { + model = "Olimex ESP32-EVB"; + compatible = "olimex,esp32-evb", "espressif,esp32-wroom-32e", "espressif,esp32"; + + chosen { + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; + }; + + aliases { + sw0 = &button1; + watchdog0 = &wdt0; + }; + + gpio_keys { + compatible = "gpio-keys"; + button1: button1 { + gpios = <&gpio 34 GPIO_ACTIVE_LOW>; + label = "BUT1"; + zephyr,code = ; + }; + }; + + relay1: relay1 { + compatible = "regulator-fixed"; + enable-gpios = <&gpio 32 GPIO_ACTIVE_HIGH>; + regulator-name = "REL1"; + startup-delay-us = <10000>; + off-on-delay-us = <5000>; + }; + + relay2: relay2 { + compatible = "regulator-fixed"; + enable-gpios = <&gpio 33 GPIO_ACTIVE_HIGH>; + regulator-name = "REL2"; + startup-delay-us = <10000>; + off-on-delay-us = <5000>; + }; +}; + +&cpu0 { + clock-frequency = ; +}; + +&cpu1 { + clock-frequency = ; +}; + +uext_serial: &uart1 {}; +uext_i2c: &i2c0 {}; +uext_spi: &spi2 {}; + +&uart0 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart0_default>; + pinctrl-names = "default"; +}; + +&uart1 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart1_default>; + pinctrl-names = "default"; +}; + +&i2c0 { + status = "okay"; + clock-frequency = ; + sda-gpios = <&gpio0 16 GPIO_OPEN_DRAIN>; + scl-gpios = <&gpio0 13 GPIO_OPEN_DRAIN>; + pinctrl-0 = <&i2c0_default>; + pinctrl-names = "default"; +}; + +&spi2 { + status = "okay"; + pinctrl-0 = <&spim2_default>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; +}; + +&twai { + status = "okay"; + pinctrl-0 = <&twai_default>; + pinctrl-names = "default"; + + can-transceiver { + max-bitrate = <1000000>; + }; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&timer0 { + status = "okay"; +}; + +&timer1 { + status = "okay"; +}; + +&timer2 { + status = "okay"; +}; + +&timer3 { + status = "okay"; +}; + +&trng0 { + status = "okay"; +}; + +&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 DT_SIZE_K(60)>; + read-only; + }; + + /* Reserve 1024kB for the application in slot 0 */ + slot0_partition: partition@10000 { + label = "image-0"; + reg = <0x00010000 DT_SIZE_K(1024)>; + }; + + /* Reserve 1024kB for the application in slot 1 */ + slot1_partition: partition@110000 { + label = "image-1"; + reg = <0x00110000 DT_SIZE_K(1024)>; + }; + + /* Reserve 256kB for the scratch partition */ + scratch_partition: partition@210000 { + label = "image-scratch"; + reg = <0x00210000 DT_SIZE_K(256)>; + }; + + storage_partition: partition@250000 { + label = "storage"; + reg = <0x00250000 DT_SIZE_K(24)>; + }; + }; +}; diff --git a/boards/olimex/olimex_esp32_evb/olimex_esp32_evb_procpu.yaml b/boards/olimex/olimex_esp32_evb/olimex_esp32_evb_procpu.yaml new file mode 100644 index 00000000000..c897a546214 --- /dev/null +++ b/boards/olimex/olimex_esp32_evb/olimex_esp32_evb_procpu.yaml @@ -0,0 +1,20 @@ +identifier: olimex_esp32_evb/esp32/procpu +name: Olimex ESP32-EVB PROCPU +type: mcu +arch: xtensa +toolchain: + - zephyr +supported: + - can + - counter + - gpio + - hwinfo + - i2c + - spi + - uart + - watchdog +testing: + ignore_tags: + - net + - bluetooth +vendor: olimex diff --git a/boards/olimex/olimex_esp32_evb/olimex_esp32_evb_esp32_procpu_defconfig b/boards/olimex/olimex_esp32_evb/olimex_esp32_evb_procpu_defconfig similarity index 100% rename from boards/olimex/olimex_esp32_evb/olimex_esp32_evb_esp32_procpu_defconfig rename to boards/olimex/olimex_esp32_evb/olimex_esp32_evb_procpu_defconfig diff --git a/boards/olimex/olimexino_stm32/olimexino_stm32.dts b/boards/olimex/olimexino_stm32/olimexino_stm32.dts index 931012548fd..8c3a3b1491a 100644 --- a/boards/olimex/olimexino_stm32/olimexino_stm32.dts +++ b/boards/olimex/olimexino_stm32/olimexino_stm32.dts @@ -166,7 +166,6 @@ zephyr_udc0: &usb { &can1 { pinctrl-0 = <&can_rx_remap1_pb8 &can_tx_remap1_pb9>; pinctrl-names = "default"; - bus-speed = <125000>; phys = <&transceiver0>; status = "okay"; }; diff --git a/boards/olimex/olimexino_stm32/olimexino_stm32.yaml b/boards/olimex/olimexino_stm32/olimexino_stm32.yaml index b4cf8b26bfb..266ff002184 100644 --- a/boards/olimex/olimexino_stm32/olimexino_stm32.yaml +++ b/boards/olimex/olimexino_stm32/olimexino_stm32.yaml @@ -11,7 +11,6 @@ supported: - gpio - i2c - pwm - - sdhc - spi - usb_device - watchdog diff --git a/boards/olimex/stm32_p405/olimex_stm32_p405.dts b/boards/olimex/stm32_p405/olimex_stm32_p405.dts index 866a8318f3e..776bf4a3827 100644 --- a/boards/olimex/stm32_p405/olimex_stm32_p405.dts +++ b/boards/olimex/stm32_p405/olimex_stm32_p405.dts @@ -87,7 +87,6 @@ &can1 { pinctrl-0 = <&can1_rx_pb8 &can1_tx_pb9>; pinctrl-names = "default"; - bus-speed = <125000>; status = "okay"; can-transceiver { diff --git a/boards/others/black_f407ve/black_f407ve.dts b/boards/others/black_f407ve/black_f407ve.dts index 6a76109ce84..539f9838fbf 100644 --- a/boards/others/black_f407ve/black_f407ve.dts +++ b/boards/others/black_f407ve/black_f407ve.dts @@ -126,14 +126,12 @@ zephyr_udc0: &usbotg_fs { &can1 { pinctrl-0 = <&can1_rx_pd0 &can1_tx_pd1>; pinctrl-names = "default"; - bus-speed = <125000>; status = "disabled"; }; &can2 { pinctrl-0 = <&can2_rx_pb12 &can2_tx_pb13>; pinctrl-names = "default"; - bus-speed = <125000>; status = "okay"; }; diff --git a/boards/others/black_f407zg_pro/black_f407zg_pro.dts b/boards/others/black_f407zg_pro/black_f407zg_pro.dts index 45a311c5030..2d96ce6a4fb 100644 --- a/boards/others/black_f407zg_pro/black_f407zg_pro.dts +++ b/boards/others/black_f407zg_pro/black_f407zg_pro.dts @@ -125,14 +125,12 @@ zephyr_udc0: &usbotg_fs { &can1 { pinctrl-0 = <&can1_rx_pd0 &can1_tx_pd1>; pinctrl-names = "default"; - bus-speed = <125000>; status = "disabled"; }; &can2 { pinctrl-0 = <&can2_rx_pb12 &can2_tx_pb13>; pinctrl-names = "default"; - bus-speed = <125000>; status = "okay"; }; diff --git a/boards/others/stm32_min_dev/stm32_min_dev_black.yaml b/boards/others/stm32_min_dev/stm32_min_dev_black.yaml index 0740dc17faf..543b58db837 100644 --- a/boards/others/stm32_min_dev/stm32_min_dev_black.yaml +++ b/boards/others/stm32_min_dev/stm32_min_dev_black.yaml @@ -1,5 +1,5 @@ identifier: stm32_min_dev@black -name: STM32 Minimum Development Board +name: STM32 Minimum Development Board (black) type: mcu arch: arm toolchain: diff --git a/boards/others/stm32_min_dev/stm32_min_dev_blue.yaml b/boards/others/stm32_min_dev/stm32_min_dev_blue.yaml index 8249d6f9719..3a7f4ad7308 100644 --- a/boards/others/stm32_min_dev/stm32_min_dev_blue.yaml +++ b/boards/others/stm32_min_dev/stm32_min_dev_blue.yaml @@ -1,5 +1,5 @@ identifier: stm32_min_dev@blue -name: STM32 Minimum Development Board +name: STM32 Minimum Development Board (blue) type: mcu arch: arm toolchain: diff --git a/boards/phytec/index.rst b/boards/phytec/index.rst index 0bde22965df..bb484358db1 100644 --- a/boards/phytec/index.rst +++ b/boards/phytec/index.rst @@ -1,7 +1,7 @@ .. _boards-phytec: -PHYTEC Messtechnik GmbH -####################### +PHYTEC +###### .. toctree:: :maxdepth: 1 diff --git a/boards/phytec/phyboard_electra/Kconfig.phyboard_electra b/boards/phytec/phyboard_electra/Kconfig.phyboard_electra new file mode 100644 index 00000000000..7529f968722 --- /dev/null +++ b/boards/phytec/phyboard_electra/Kconfig.phyboard_electra @@ -0,0 +1,8 @@ +# PHYTEC phyBOARD-Electra AM64x +# +# Copyright (c) 2024 PHYTEC Messtechnik GmbH +# +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_PHYBOARD_ELECTRA + select SOC_AM6442_M4 if BOARD_PHYBOARD_ELECTRA_AM6442_M4 diff --git a/boards/phytec/phyboard_electra/board.yml b/boards/phytec/phyboard_electra/board.yml new file mode 100644 index 00000000000..d5c24f15cbd --- /dev/null +++ b/boards/phytec/phyboard_electra/board.yml @@ -0,0 +1,5 @@ +board: + name: phyboard_electra + vendor: phytec + socs: + - name: am6442 diff --git a/boards/phytec/phyboard_electra/doc/img/phyCORE-AM64x_Electra_frontside.webp b/boards/phytec/phyboard_electra/doc/img/phyCORE-AM64x_Electra_frontside.webp new file mode 100644 index 00000000000..d4a48609847 Binary files /dev/null and b/boards/phytec/phyboard_electra/doc/img/phyCORE-AM64x_Electra_frontside.webp differ diff --git a/boards/phytec/phyboard_electra/doc/index.rst b/boards/phytec/phyboard_electra/doc/index.rst new file mode 100644 index 00000000000..4fe9c5afd55 --- /dev/null +++ b/boards/phytec/phyboard_electra/doc/index.rst @@ -0,0 +1,143 @@ +.. _phyboard_electra_am64xx_m4: + +phyBOARD-Electra AM64x M4F Core +############################### + +Overview +******** + +The AM64x phyBOARD-Electra board configuration is used by Zephyr applications +that run on the TI AM64x platform. The board configuration provides support +for the ARM Cortex-M4F MCU core and the following features: + +- Nested Vector Interrupt Controller (NVIC) +- System Tick System Clock (SYSTICK) + +The board configuration also enables support for the semihosting debugging console. + +See the `PHYTEC AM64x Product Page`_ for details. + +.. figure:: img/phyCORE-AM64x_Electra_frontside.webp + :align: center + :alt: phyBOARD-Electra AM64x + + PHYTEC phyBOARD-Electra with the phyCORE-AM64x SoM + +Hardware +******** +The AM64x phyBOARD-Electra kit features the AM64x SoC, which is composed of a +dual Cortex-A53 cluster and two dual Cortex-R5F cores in the MAIN domain as +well as a single Cortex-M4 core in the MCU domain. Zephyr is ported to run on +the M4F core and the following listed hardware specifications are used: + +- Low-power ARM Cortex-M4F +- Memory + + - 256KB of SRAM + - 2GB of DDR4 + +- Debug + + - XDS110 based JTAG + +Supported Features +================== + +The phyboard_electra/am6442/m4 configuration supports the following hardware 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. + +Devices +======== +System Clock +------------ + +This board configuration uses a system clock frequency of 400 MHz. + +DDR RAM +------- + +The board has 2GB of DDR RAM available. This board configuration +allocates Zephyr 4kB of RAM (only for resource table: 0xa4100000 to 0xa4100400). + +Serial Port +----------- + +This board configuration uses a single serial communication channel with the +MCU domain UART (MCU_UART0). + +GPIO +---- + +The phyCORE-AM64x has a heartbeat LED connected to gpio6. It's configured +to build and run the `basic/blinky` sample. + +SD Card +******* + +Download PHYTEC's official `WIC`_ as well as `BMAP`_ and flash the WIC file with +an etching software onto an SD-card. This will boot Linux on the A53 application +cores of the SoM. These cores will then load the zephyr binary on the M4 core +using remoteproc. + +The default configuration can be found in +:zephyr_file:`boards/phytec/phyboard_electra/phyboard_electra_am6442_m4_defconfig` + +Flashing +******** + +The Linux running on the A53 uses the remoteproc framework to manage the M4F co-processor. +Therefore, the testing requires the binary to be copied to the SD card to allow the A53 cores to +load it while booting using remoteproc. + +To test the M4F core, we build the :ref:`hello_world` sample with the following command. + +.. zephyr-app-commands:: + :board: phyboard_electra/am6442/m4 + :zephyr-app: samples/hello_world + :goals: build + +This builds the program and the binary is present in the `build/zephyr` directory as `zephyr.elf`. + +We now copy this binary onto the SD card in the `/lib/firmware` directory and name it as `am64-mcu-m4f0_0-fw`. + +.. code-block:: console + + # Mount the SD card at sdcard for example + sudo mount /dev/sdX sdcard + # copy the elf to the /lib/firmware directory + sudo cp --remove-destination zephyr.elf sdcard/lib/firmware/am64-mcu-m4f0_0-fw + +The SD card can now be used for booting. The binary will now be loaded onto the M4F core on boot. + +To allow the board to boot using the SD card, set the boot pins to the SD Card boot mode. Refer to `phyBOARD SD Card Booting Essentials`_. + +The board should boot into Linux and the binary will run and print Hello world to the MCU_UART0 +port. + + +.. _PHYTEC AM64x Product Page: + https://www.phytec.com/product/phycore-am64x/ + +.. _WIC: + https://download.phytec.de/Software/Linux/BSP-Yocto-AM64x/BSP-Yocto-Ampliphy-AM64x-PD23.2.1/images/ampliphy/phyboard-electra-am64xx-2/phytec-headless-image-phyboard-electra-am64xx-2.wic.xz + +.. _BMAP: + https://download.phytec.de/Software/Linux/BSP-Yocto-AM64x/BSP-Yocto-Ampliphy-AM64x-PD23.2.1/images/ampliphy/phyboard-electra-am64xx-2/phytec-headless-image-phyboard-electra-am64xx-2.wic.bmap + +.. _phyBOARD SD Card Booting Essentials: + https://docs.phytec.com/projects/yocto-phycore-am64x/en/bsp-yocto-ampliphy-am64x-pd23.2.1/bootingessentials/sdcard.html diff --git a/boards/phytec/phyboard_electra/phyboard_electra_am6442_m4.dts b/boards/phytec/phyboard_electra/phyboard_electra_am6442_m4.dts new file mode 100644 index 00000000000..d19c5a62c92 --- /dev/null +++ b/boards/phytec/phyboard_electra/phyboard_electra_am6442_m4.dts @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2024 PHYTEC Messtechnik GmbH + * Author: Daniel Schultz + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include + +/ { + model = "PHYTEC phyBOARD-Electra AM64x M4"; + compatible = "phytec,phyboard-electra-am64xx-m4", "ti,am6442"; + + chosen { + zephyr,sram = &sram0; + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,sram1 = &ddr0; + }; + + aliases { + led0 = &heartbeat_led; + }; + + cpus { + cpu@0 { + status = "okay"; + clock-frequency = ; + }; + }; + + ddr0:memory@a4100000 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0xa4100000 DT_SIZE_K(4)>; + zephyr,memory-region = "DDR"; + }; + + leds: leds { + compatible = "gpio-leds"; + heartbeat_led: led_0 { + gpios = <&gpio0 6 GPIO_ACTIVE_HIGH>; + label = "Heartbeat LED"; + }; + }; +}; + +&pinctrl { + mcu_uart0_rx_default: mcu_uart0_rx_default { + pinmux = ; + }; + mcu_uart0_tx_default: mcu_uart0_tx_default { + pinmux = ; + }; + mcu_gpio0_led_default: mcu_gpio0_led_default { + pinmux = ; + }; +}; + +&uart0 { + current-speed = <115200>; + pinctrl-0 = <&mcu_uart0_rx_default &mcu_uart0_tx_default>; + pinctrl-names = "default"; + status = "okay"; +}; + +&gpio0 { + pinctrl-0 = <&mcu_gpio0_led_default>; + pinctrl-names = "default"; + status = "okay"; +}; diff --git a/boards/phytec/phyboard_electra/phyboard_electra_am6442_m4.yaml b/boards/phytec/phyboard_electra/phyboard_electra_am6442_m4.yaml new file mode 100644 index 00000000000..efea3bdff35 --- /dev/null +++ b/boards/phytec/phyboard_electra/phyboard_electra_am6442_m4.yaml @@ -0,0 +1,8 @@ +identifier: phyboard_electra/am6442/m4 +name: PHYTEC phyBOARD-Electra AM64x M4 +type: mcu +arch: arm +toolchain: + - zephyr +ram: 192 +vendor: phytec diff --git a/boards/phytec/phyboard_electra/phyboard_electra_am6442_m4_defconfig b/boards/phytec/phyboard_electra/phyboard_electra_am6442_m4_defconfig new file mode 100644 index 00000000000..1e4d69df6a0 --- /dev/null +++ b/boards/phytec/phyboard_electra/phyboard_electra_am6442_m4_defconfig @@ -0,0 +1,25 @@ +# PHYTEC AM64x M4 phyBOARD-Electra +# +# Copyright (C) 2024 PHYTEC Messtechnik GmbH +# Author: Daniel Schultz +# +# SPDX-License-Identifier: Apache-2.0 + +# Platform Configuration +CONFIG_CORTEX_M_SYSTICK=y + +# Zephyr Kernel Configuration +CONFIG_XIP=n + +# Enable Pinctrl +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/phytec/phyboard_lyra/Kconfig.phyboard_lyra b/boards/phytec/phyboard_lyra/Kconfig.phyboard_lyra new file mode 100644 index 00000000000..93076900cf3 --- /dev/null +++ b/boards/phytec/phyboard_lyra/Kconfig.phyboard_lyra @@ -0,0 +1,12 @@ +# PHYTEC phyBOARD-Lyra AM62x M4/A53 +# +# Copyright (c) 2023 Texas Instruments Incorporated +# Copyright (c) 2023 L Lakshmanan +# +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_PHYBOARD_LYRA + select SOC_AM6234_A53 if BOARD_PHYBOARD_LYRA_AM6234_A53 + select SOC_AM6234_M4 if BOARD_PHYBOARD_LYRA_AM6234_M4 + help + PHYTEC phyBOARD-Lyra AM62x M4/A53 diff --git a/boards/phytec/phyboard_lyra/board.yml b/boards/phytec/phyboard_lyra/board.yml new file mode 100644 index 00000000000..2b98d77f510 --- /dev/null +++ b/boards/phytec/phyboard_lyra/board.yml @@ -0,0 +1,5 @@ +board: + name: phyboard_lyra + vendor: phytec + socs: + - name: am6234 diff --git a/boards/phytec/phyboard_lyra_am62x/doc/img/phyCORE-AM62x_Lyra_frontside.webp b/boards/phytec/phyboard_lyra/doc/img/phyCORE-AM62x_Lyra_frontside.webp similarity index 100% rename from boards/phytec/phyboard_lyra_am62x/doc/img/phyCORE-AM62x_Lyra_frontside.webp rename to boards/phytec/phyboard_lyra/doc/img/phyCORE-AM62x_Lyra_frontside.webp diff --git a/boards/phytec/phyboard_lyra/doc/phyboard_lyra_am62xx_a53.rst b/boards/phytec/phyboard_lyra/doc/phyboard_lyra_am62xx_a53.rst new file mode 100644 index 00000000000..410debfd9b7 --- /dev/null +++ b/boards/phytec/phyboard_lyra/doc/phyboard_lyra_am62xx_a53.rst @@ -0,0 +1,114 @@ +.. _phyboard_lyra_am62xx_a53: + +phyBOARD-Lyra AM62x A53 Core +############################ + +Overview +******** + +PHYTEC phyBOARD-Lyra AM62x board is based on TI Sitara applications +processor, composed of a quad CortexĀ®-A53 cluster and a single CortexĀ®-M4 core. +Zephyr OS is ported to run on the CortexĀ®-A53 core. + +- Board features: + + - RAM: 2GB DDR4 + - Storage: + + - 16GB eMMC + - 64MB OSPI NOR + - 4KB EEPROM + - Ethernet + +See the `PHYTEC AM62x Product Page`_ for details. + +.. figure:: img/phyCORE-AM62x_Lyra_frontside.webp + :align: center + :alt: phyBOARD-Lyra AM62x + + PHYTEC phyBOARD-Lyra with the phyCORE-AM62x SoM + +Supported Features +================== + +The Zephyr phyboard_lyra/am6234/a53 board configuration supports the following hardware +features: + ++-----------+------------+-------------------------------------+ +| Interface | Controller | Driver/Component | ++===========+============+=====================================+ +| GIC-v3 | on-chip | interrupt controller | ++-----------+------------+-------------------------------------+ +| ARM TIMER | on-chip | system clock | ++-----------+------------+-------------------------------------+ +| PINCTRL | on-chip | pinctrl | ++-----------+------------+-------------------------------------+ +| UART | on-chip | serial port | ++-----------+------------+-------------------------------------+ + +Devices +======== +System Clock +------------ + +This board configuration uses a system clock frequency of 200 MHz. + +DDR RAM +------- + +The board has 2GB of DDR RAM available. This board configuration +allocates Zephyr 1MB of RAM (0x82000000 to 0x82100000). + +Serial Port +----------- + +This board configuration uses a single serial communication channel with the +CPU's UART0. + +SD Card +******* + +Download PHYTEC's official `WIC`_ and `bmap`_ files and flash the WIC file with +bmap-tools on a SD-card. + +.. code-block:: console + + bmaptool copy phytec-qt5demo-image-phyboard-lyra-am62xx-3.wic.xz /dev/sdX + +Building +******** + +You can build an application in the usual way. Refer to +:ref:`build_an_application` for more details. Here is an example for +:ref:`hello_world`. + +.. zephyr-app-commands:: + :board: phyboard_lyra/am6234/a53 + :zephyr-app: samples/hello_world + :goals: build + +Programming +*********** + +Copy 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. + +Use U-Boot to load and kick zephyr.bin: + +.. code-block:: console + + fatload mmc 1:1 0x82000000 zephyr.bin; dcache flush; icache flush; dcache off; icache off; go 0x82000000 + + +.. + References + +.. _PHYTEC AM62x Product Page: + https://www.phytec.com/product/phycore-am62x/ + +.. _WIC: + https://download.phytec.de/Software/Linux/BSP-Yocto-AM62x/BSP-Yocto-Ampliphy-AM62x-PD23.2.1/images/ampliphy-xwayland/phyboard-lyra-am62xx-3/phytec-qt5demo-image-phyboard-lyra-am62xx-3.wic.xz + +.. _Bmap: + https://download.phytec.de/Software/Linux/BSP-Yocto-AM62x/BSP-Yocto-Ampliphy-AM62x-PD23.2.1/images/ampliphy-xwayland/phyboard-lyra-am62xx-3/phytec-qt5demo-image-phyboard-lyra-am62xx-3.wic.bmap diff --git a/boards/phytec/phyboard_lyra/doc/phyboard_lyra_am62xx_m4.rst b/boards/phytec/phyboard_lyra/doc/phyboard_lyra_am62xx_m4.rst new file mode 100644 index 00000000000..a8765c0fcc3 --- /dev/null +++ b/boards/phytec/phyboard_lyra/doc/phyboard_lyra_am62xx_m4.rst @@ -0,0 +1,145 @@ +.. _phyboard_lyra_am62xx_m4: + +phyBOARD-Lyra AM62x M4F Core +############################ + +Overview +******** + +The phyBOARD-Lyra AM62x board configuration is used by Zephyr applications +that run on the TI AM62x platform. The board configuration provides support +for the ARM Cortex-M4F MCU core and the following features: + +- Nested Vector Interrupt Controller (NVIC) +- System Tick System Clock (SYSTICK) + +The board configuration also enables support for the semihosting debugging console. + +See the `PHYTEC AM62x Product Page`_ for details. + +.. figure:: img/phyCORE-AM62x_Lyra_frontside.webp + :align: center + :alt: phyBOARD-Lyra AM62x + + PHYTEC phyBOARD-Lyra with the phyCORE-AM62x SoM + +Hardware +******** +The phyBOARD-Lyra AM62x kit features the AM62x SoC, which is composed of a +quad Cortex-A53 cluster and a single Cortex-M4 core in the MCU domain. Zephyr +is ported to run on the M4F core and the following listed hardware +specifications are used: + +- Low-power ARM Cortex-M4F +- Memory + + - 256KB of SRAM + - 2GB of DDR4 + +- Debug + + - XDS110 based JTAG + +Supported Features +================== + +The phyboard_lyra/am6234/m4 configuration supports the following hardware features: + ++-----------+------------+-------------------------------------+ +| Interface | Controller | Driver/Component | ++===========+============+=====================================+ +| NVIC | on-chip | nested vector interrupt controller | ++-----------+------------+-------------------------------------+ +| SYSTICK | on-chip | systick | ++-----------+------------+-------------------------------------+ +| PINCTRL | on-chip | pinctrl | ++-----------+------------+-------------------------------------+ +| UART | on-chip | serial | ++-----------+------------+-------------------------------------+ + +Other hardware features are not currently supported by the port. + +Devices +======== +System Clock +------------ + +This board configuration uses a system clock frequency of 400 MHz. + +DDR RAM +------- + +The board has 2GB of DDR RAM available. This board configuration +allocates Zephyr 4kB of RAM (only for resource table: 0x9CC00000 to 0x9CC00400). + +Serial Port +----------- + +This board configuration uses a single serial communication channel with the +MCU domain UART (MCU_UART0). + +SD Card +******* + +Download PHYTEC's official `WIC`_ as well as `BMAP`_ and flash the WIC file with +an etching software onto an SD-card. This will boot Linux on the A53 application +cores of the SoM. These cores will then load the zephyr binary on the M4 core +using remoteproc. + +The default configuration can be found in +:zephyr_file:`boards/phytec/phyboard_lyra/phyboard_lyra_am6234_m4_defconfig` + +Flashing +******** + +The Linux running on the A53 uses the remoteproc framework to manage the M4F co-processor. +Therefore, the testing requires the binary to be copied to the SD card to allow the A53 cores to +load it while booting using remoteproc. + +To test the M4F core, we build the `hello_world` sample with the following command. + +.. code-block:: console + + # From the root of the Zephyr repository + west build -p -b phyboard_lyra/am6234/m4 samples/hello_world + +This builds the program and the binary is present in the `build/zephyr` directory as `zephyr.elf`. + +We now copy this binary onto the SD card in the `/lib/firmware` directory and name it as `am62-mcu-m4f0_0-fw`. + +.. code-block:: console + + # Mount the SD card at sdcard for example + sudo mount /dev/sdX sdcard + # copy the elf to the /lib/firmware directory + sudo cp --remove-destination zephyr.elf sdcard/lib/firmware/am62-mcu-m4f0_0-fw + +The SD card can now be used for booting. The binary will now be loaded onto the M4F core on boot. + +To allow the board to boot using the SD card, set the boot pins to the SD Card boot mode. Refer to `phyBOARD SD Card Booting Essentials`_. + +After changing the boot mode, stop in U-Boot to enable the M4F co-processor. + +.. code-block:: console + + setenv overlays k3-am62-phyboard-lyra-rpmsg.dtbo + # Save the overlays variable permanently + saveenv + boot + +The board should boot into Linux and the binary will run and print Hello world to the MCU_UART0 +port. + + + +.. _PHYTEC AM62x Product Page: + https://www.phytec.com/product/phycore-am62x/ + +.. _WIC: + https://download.phytec.de/Software/Linux/BSP-Yocto-AM62x/BSP-Yocto-Ampliphy-AM62x-PD23.2.1/images/ampliphy-xwayland/phyboard-lyra-am62xx-3/phytec-qt5demo-image-phyboard-lyra-am62xx-3.wic.xz + +.. _BMAP: + https://download.phytec.de/Software/Linux/BSP-Yocto-AM62x/BSP-Yocto-Ampliphy-AM62x-PD23.2.1/images/ampliphy-xwayland/phyboard-lyra-am62xx-3/phytec-qt5demo-image-phyboard-lyra-am62xx-3.wic.bmap + +.. _phyBOARD SD Card Booting Essentials: + https://docs.phytec.com/projects/yocto-phycore-am62x/en/bsp-yocto-ampliphy-am62x-pd23.2.1/bootingessentials/sdcard.html diff --git a/boards/phytec/phyboard_lyra/phyboard_lyra_am6234_a53.dts b/boards/phytec/phyboard_lyra/phyboard_lyra_am6234_a53.dts new file mode 100644 index 00000000000..adf350b56f9 --- /dev/null +++ b/boards/phytec/phyboard_lyra/phyboard_lyra_am6234_a53.dts @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2023 Enphase Energy + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include + +/ { + model = "PHYTEC phyBOARD-Lyra AM62x A53"; + compatible = "phytec,phyboard-lyra-am62xx-a53", "ti,am625"; + + chosen { + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,sram = &ddr0; + }; + + cpus { + cpu@0 { + status = "okay"; + }; + cpu@1 { + status = "disabled"; + }; + cpu@2 { + status = "disabled"; + }; + cpu@3 { + status = "disabled"; + }; + }; + + ddr0: memory@82000000 { + /* Note: This board actually has 2GB DRAM available */ + reg = <0x82000000 DT_SIZE_M(1)>; + }; +}; + +&pinctrl { + uart0_rx_default: uart0_rx_default { + pinmux = ; + }; + uart0_tx_default: uart0_tx_default { + pinmux = ; + }; +}; + +&uart0 { + current-speed = <115200>; + pinctrl-0 = <&uart0_rx_default &uart0_tx_default>; + pinctrl-names = "default"; + status = "okay"; +}; diff --git a/boards/phytec/phyboard_lyra/phyboard_lyra_am6234_a53.yaml b/boards/phytec/phyboard_lyra/phyboard_lyra_am6234_a53.yaml new file mode 100644 index 00000000000..5f45c978c2a --- /dev/null +++ b/boards/phytec/phyboard_lyra/phyboard_lyra_am6234_a53.yaml @@ -0,0 +1,13 @@ +identifier: phyboard_lyra/am6234/a53 +name: PHYTEC phyBOARD-Lyra AM62x A53 +type: mcu +arch: arm64 +toolchain: + - zephyr + - cross-compile +ram: 1024 +testing: + ignore_tags: + - net + - bluetooth +vendor: phytec diff --git a/boards/phytec/phycore_am62x/phycore_am62x_am6234_a53_defconfig b/boards/phytec/phyboard_lyra/phyboard_lyra_am6234_a53_defconfig similarity index 100% rename from boards/phytec/phycore_am62x/phycore_am62x_am6234_a53_defconfig rename to boards/phytec/phyboard_lyra/phyboard_lyra_am6234_a53_defconfig diff --git a/boards/phytec/phyboard_lyra/phyboard_lyra_am6234_m4.dts b/boards/phytec/phyboard_lyra/phyboard_lyra_am6234_m4.dts new file mode 100644 index 00000000000..8112aeba419 --- /dev/null +++ b/boards/phytec/phyboard_lyra/phyboard_lyra_am6234_m4.dts @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2023 PHYTEC Messtechnik GmbH + * Author: Daniel Schultz + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include + +/ { + model = "PHYTEC phyBOARD-Lyra AM62x M4"; + compatible = "phytec,phyboard-lyra-am62xx-m4", "ti,am625"; + + chosen { + zephyr,sram = &sram0; + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,sram1 = &ddr0; + }; + + aliases { + led0 = &heartbeat_led; + }; + + cpus { + cpu@0 { + status = "okay"; + clock-frequency = <400000000>; + }; + }; + + ddr0:memory@9CC00000{ + compatible = "zephyr,memory-region", "mmio-sram"; + 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 { + mcu_uart0_rx_default: mcu_uart0_rx_default { + pinmux = ; + }; + mcu_uart0_tx_default: mcu_uart0_tx_default { + pinmux = ; + }; + mcu_gpio0_led_default: mcu_gpio0_led_default { + pinmux = ; + }; +}; + +&uart0 { + current-speed = <115200>; + pinctrl-0 = <&mcu_uart0_rx_default &mcu_uart0_tx_default>; + pinctrl-names = "default"; + status = "okay"; +}; + +&gpio0 { + pinctrl-0 = <&mcu_gpio0_led_default>; + pinctrl-names = "default"; + status = "okay"; +}; diff --git a/boards/phytec/phyboard_lyra/phyboard_lyra_am6234_m4.yaml b/boards/phytec/phyboard_lyra/phyboard_lyra_am6234_m4.yaml new file mode 100644 index 00000000000..0ef24d8f720 --- /dev/null +++ b/boards/phytec/phyboard_lyra/phyboard_lyra_am6234_m4.yaml @@ -0,0 +1,8 @@ +identifier: phyboard_lyra/am6234/m4 +name: PHYTEC phyBOARD-Lyra AM62x M4 +type: mcu +arch: arm +toolchain: + - zephyr +ram: 192 +vendor: phytec diff --git a/boards/phytec/phyboard_lyra/phyboard_lyra_am6234_m4_defconfig b/boards/phytec/phyboard_lyra/phyboard_lyra_am6234_m4_defconfig new file mode 100644 index 00000000000..a54f04a25e1 --- /dev/null +++ b/boards/phytec/phyboard_lyra/phyboard_lyra_am6234_m4_defconfig @@ -0,0 +1,25 @@ +# PHYTEC phyBOARD-Lyra AM62x M4 +# +# Copyright (C) 2023 PHYTEC Messtechnik GmbH +# Author: Daniel Schultz +# +# SPDX-License-Identifier: Apache-2.0 + +# Platform Configuration +CONFIG_CORTEX_M_SYSTICK=y + +# Zephyr Kernel Configuration +CONFIG_XIP=n + +# Enable Pinctrl +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/phytec/phyboard_lyra_am62x/Kconfig.phyboard_lyra_am62x b/boards/phytec/phyboard_lyra_am62x/Kconfig.phyboard_lyra_am62x deleted file mode 100644 index 1b9c5eb8161..00000000000 --- a/boards/phytec/phyboard_lyra_am62x/Kconfig.phyboard_lyra_am62x +++ /dev/null @@ -1,11 +0,0 @@ -# Texas Instruments Sitara AM62x-SK-M4 EVM -# -# Copyright (c) 2023 Texas Instruments Incorporated -# Copyright (c) 2023 L Lakshmanan -# -# SPDX-License-Identifier: Apache-2.0 - -config BOARD_PHYBOARD_LYRA_AM62X - select SOC_AM6234_M4 if BOARD_PHYBOARD_LYRA_AM62X_AM6234_M4 - help - PHYTEC AM62x M4 phyBOARD-Lyra diff --git a/boards/phytec/phyboard_lyra_am62x/board.yml b/boards/phytec/phyboard_lyra_am62x/board.yml deleted file mode 100644 index d91be2b4786..00000000000 --- a/boards/phytec/phyboard_lyra_am62x/board.yml +++ /dev/null @@ -1,5 +0,0 @@ -board: - name: phyboard_lyra_am62x - vendor: phytec - socs: - - name: am6234 diff --git a/boards/phytec/phyboard_lyra_am62x/doc/index.rst b/boards/phytec/phyboard_lyra_am62x/doc/index.rst deleted file mode 100644 index f18636318fd..00000000000 --- a/boards/phytec/phyboard_lyra_am62x/doc/index.rst +++ /dev/null @@ -1,145 +0,0 @@ -.. _am62x_m4_phyboard_lyra: - -AM62x phyBOARD-Lyra M4F Core -############################ - -Overview -******** - -The AM62x phyBOARD-Lyra board configuration is used by Zephyr applications -that run on the TI AM62x platform. The board configuration provides support -for the ARM Cortex-M4F MCU core and the following features: - -- Nested Vector Interrupt Controller (NVIC) -- System Tick System Clock (SYSTICK) - -The board configuration also enables support for the semihosting debugging console. - -See the `PHYTEC AM62x Product Page`_ for details. - -.. figure:: img/phyCORE-AM62x_Lyra_frontside.webp - :align: center - :alt: AM62x phyBOARD-Lyra - - PHYTEC phyBOARD-Lyra with the phyCORE-AM62x SoM - -Hardware -******** -The AM62x phyBOARD-Lyra kit features the AM62x SoC, which is composed of a -quad Cortex-A53 cluster and a single Cortex-M4 core in the MCU domain. Zephyr -is ported to run on the M4F core and the following listed hardware -specifications are used: - -- Low-power ARM Cortex-M4F -- Memory - - - 256KB of SRAM - - 2GB of DDR4 - -- Debug - - - XDS110 based JTAG - -Supported Features -================== - -The am62x_m4_phyboard_lyra configuration supports the following hardware features: - -+-----------+------------+-------------------------------------+ -| Interface | Controller | Driver/Component | -+===========+============+=====================================+ -| NVIC | on-chip | nested vector interrupt controller | -+-----------+------------+-------------------------------------+ -| SYSTICK | on-chip | systick | -+-----------+------------+-------------------------------------+ -| PINCTRL | on-chip | pinctrl | -+-----------+------------+-------------------------------------+ -| UART | on-chip | serial | -+-----------+------------+-------------------------------------+ - -Other hardware features are not currently supported by the port. - -Devices -======== -System Clock ------------- - -This board configuration uses a system clock frequency of 400 MHz. - -DDR RAM -------- - -The board has 2GB of DDR RAM available. This board configuration -allocates Zephyr 4kB of RAM (only for resource table: 0x9CC00000 to 0x9CC00400). - -Serial Port ------------ - -This board configuration uses a single serial communication channel with the -MCU domain UART (MCU_UART0). - -SD Card -******* - -Download PHYTEC's official `WIC`_ as well as `BMAP`_ and flash the WIC file with -an etching software onto an SD-card. This will boot Linux on the A53 application -cores of the SoM. These cores will then load the zephyr binary on the M4 core -using remoteproc. - -The default configuration can be found in -:zephyr_file:`boards/phytec/phyboard_lyra_am62x/phyboard_lyra_am62x_am6234_m4_defconfig` - -Flashing -******** - -The Linux running on the A53 uses the remoteproc framework to manage the M4F co-processor. -Therefore, the testing requires the binary to be copied to the SD card to allow the A53 cores to -load it while booting using remoteproc. - -To test the M4F core, we build the `hello_world` sample with the following command. - -.. code-block:: console - - # From the root of the Zephyr repository - west build -p -b phyboard_lyra_am62x/am6234/m4 samples/hello_world - -This builds the program and the binary is present in the `build/zephyr` directory as `zephyr.elf`. - -We now copy this binary onto the SD card in the `/lib/firmware` directory and name it as `am62-mcu-m4f0_0-fw`. - -.. code-block:: console - - # Mount the SD card at sdcard for example - sudo mount /dev/sdX sdcard - # copy the elf to the /lib/firmware directory - sudo cp --remove-destination zephyr.elf sdcard/lib/firmware/am62-mcu-m4f0_0-fw - -The SD card can now be used for booting. The binary will now be loaded onto the M4F core on boot. - -To allow the board to boot using the SD card, set the boot pins to the SD Card boot mode. Refer to `phyBOARD SD Card Booting Essentials`_. - -After changing the boot mode, stop in U-Boot to enable the M4F co-processor. - -.. code-block:: console - - setenv overlays k3-am62-phyboard-lyra-rpmsg.dtbo - # Save the overlays variable permanently - saveenv - boot - -The board should boot into Linux and the binary will run and print Hello world to the MCU_UART0 -port. - - - -.. _PHYTEC AM62x Product Page: - https://www.phytec.com/product/phycore-am62x/ - -.. _WIC: - https://download.phytec.de/Software/Linux/BSP-Yocto-AM62x/BSP-Yocto-AM62x-PD23.1.0/images/yogurt/phyboard-lyra-am62xx-2/phytec-qt5demo-image-phyboard-lyra-am62xx-2.wic.xz - -.. _BMAP: - https://download.phytec.de/Software/Linux/BSP-Yocto-AM62x/BSP-Yocto-AM62x-PD23.1.0/images/yogurt/phyboard-lyra-am62xx-2/phytec-qt5demo-image-phyboard-lyra-am62xx-2.wic.bmap - -.. _phyBOARD SD Card Booting Essentials: - https://docs.phytec.com/latest/phycore-am62x/bootingessentials/sdcard.html diff --git a/boards/phytec/phyboard_lyra_am62x/phyboard_lyra_am62x_am6234_m4.dts b/boards/phytec/phyboard_lyra_am62x/phyboard_lyra_am62x_am6234_m4.dts deleted file mode 100644 index ba370240340..00000000000 --- a/boards/phytec/phyboard_lyra_am62x/phyboard_lyra_am62x_am6234_m4.dts +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2023 PHYTEC Messtechnik GmbH - * Author: Daniel Schultz - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/dts-v1/; - -#include - -/ { - model = "PHYTEC AM62x M4 phyBOARD-Lyra"; - compatible = "phytec,am62x-m4-phyboard-lyra", "ti,am625"; - - chosen { - zephyr,sram = &sram0; - zephyr,console = &uart0; - zephyr,shell-uart = &uart0; - zephyr,sram1 = &ddr0; - }; - - aliases { - led0 = &heartbeat_led; - }; - - cpus { - cpu@0 { - status = "okay"; - clock-frequency = <400000000>; - }; - }; - - ddr0:memory@9CC00000{ - compatible = "zephyr,memory-region", "mmio-sram"; - 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 { - mcu_uart0_rx_default: mcu_uart0_rx_default { - pinmux = ; - }; - mcu_uart0_tx_default: mcu_uart0_tx_default { - pinmux = ; - }; - mcu_gpio0_led_default: mcu_gpio0_led_default { - pinmux = ; - }; -}; - -&uart0 { - current-speed = <115200>; - pinctrl-0 = <&mcu_uart0_rx_default &mcu_uart0_tx_default>; - pinctrl-names = "default"; - status = "okay"; -}; - -&gpio0 { - pinctrl-0 = <&mcu_gpio0_led_default>; - pinctrl-names = "default"; - status = "okay"; -}; diff --git a/boards/phytec/phyboard_lyra_am62x/phyboard_lyra_am62x_am6234_m4.yaml b/boards/phytec/phyboard_lyra_am62x/phyboard_lyra_am62x_am6234_m4.yaml deleted file mode 100644 index df0e8ec65bd..00000000000 --- a/boards/phytec/phyboard_lyra_am62x/phyboard_lyra_am62x_am6234_m4.yaml +++ /dev/null @@ -1,8 +0,0 @@ -identifier: phyboard_lyra_am62x/am6234/m4 -name: PHYTEC AM62x M4 phyBOARD-Lyra -type: mcu -arch: arm -toolchain: - - zephyr -ram: 192 -vendor: phytec diff --git a/boards/phytec/phyboard_lyra_am62x/phyboard_lyra_am62x_am6234_m4_defconfig b/boards/phytec/phyboard_lyra_am62x/phyboard_lyra_am62x_am6234_m4_defconfig deleted file mode 100644 index 7e20705fa3f..00000000000 --- a/boards/phytec/phyboard_lyra_am62x/phyboard_lyra_am62x_am6234_m4_defconfig +++ /dev/null @@ -1,25 +0,0 @@ -# PHYTEC AM62x M4 phyBOARD-Lyra -# -# Copyright (C) 2023 PHYTEC Messtechnik GmbH -# Author: Daniel Schultz -# -# SPDX-License-Identifier: Apache-2.0 - -# Platform Configuration -CONFIG_CORTEX_M_SYSTICK=y - -# Zephyr Kernel Configuration -CONFIG_XIP=n - -# Enable Pinctrl -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/phytec/phycore_am62x/Kconfig.phycore_am62x b/boards/phytec/phycore_am62x/Kconfig.phycore_am62x deleted file mode 100644 index 8c66cb29198..00000000000 --- a/boards/phytec/phycore_am62x/Kconfig.phycore_am62x +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright (c) 2023 Enphase Energy -# SPDX-License-Identifier: Apache-2.0 - -config BOARD_PHYCORE_AM62X - select SOC_AM6234_A53 if BOARD_PHYCORE_AM62X_AM6234_A53 diff --git a/boards/phytec/phycore_am62x/board.yml b/boards/phytec/phycore_am62x/board.yml deleted file mode 100644 index ae8e3412ff4..00000000000 --- a/boards/phytec/phycore_am62x/board.yml +++ /dev/null @@ -1,5 +0,0 @@ -board: - name: phycore_am62x - vendor: phytec - socs: - - name: am6234 diff --git a/boards/phytec/phycore_am62x/doc/index.rst b/boards/phytec/phycore_am62x/doc/index.rst deleted file mode 100644 index fd711350fe3..00000000000 --- a/boards/phytec/phycore_am62x/doc/index.rst +++ /dev/null @@ -1,109 +0,0 @@ -.. _phycore_am62x_a53: - -PHYTEC phyCORE-AM62x (Cortex-A53) -################################# - -Overview -******** - -PHYTEC phyCORE-AM62x board is based on TI Sitara applications -processor, composed of a quad CortexĀ®-A53 cluster and a single CortexĀ®-M4 core. -Zephyr OS is ported to run on the CortexĀ®-A53 core. - -- Board features: - - - RAM: 2GB DDR4 - - Storage: - - - 16GB eMMC - - 64MB OSPI NOR - - 4KB EEPROM - - Ethernet - -More information about the board can be found at the -`PHYTEC website`_. - -Supported Features -================== - -The Zephyr phycore_am62x_a53 board configuration supports the following hardware -features: - -+-----------+------------+-------------------------------------+ -| Interface | Controller | Driver/Component | -+===========+============+=====================================+ -| GIC-v3 | on-chip | interrupt controller | -+-----------+------------+-------------------------------------+ -| ARM TIMER | on-chip | system clock | -+-----------+------------+-------------------------------------+ -| PINCTRL | on-chip | pinctrl | -+-----------+------------+-------------------------------------+ -| UART | on-chip | serial port | -+-----------+------------+-------------------------------------+ - -Devices -======== -System Clock ------------- - -This board configuration uses a system clock frequency of 200 MHz. - -DDR RAM -------- - -The board has 2GB of DDR RAM available. This board configuration -allocates Zephyr 1MB of RAM (0x82000000 to 0x82100000). - -Serial Port ------------ - -This board configuration uses a single serial communication channel with the -CPU's UART0. - -SD Card -******* - -Download PHYTEC's official `WIC`_ and `bmap`_ files and flash the WIC file with -bmap-tools on a SD-card. - -.. code-block:: console - - bmaptool copy phytec-qt5demo-image-phyboard-lyra-am62xx-2.wic.xz /dev/sdX - -Building -******** - -You can build an application in the usual way. Refer to -:ref:`build_an_application` for more details. Here is an example for -:ref:`hello_world`. - -.. zephyr-app-commands:: - :board: phycore_am62x/am6234/a53 - :zephyr-app: samples/hello_world - :goals: build - -Programming -*********** - -Copy 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. - -Use U-Boot to load and kick zephyr.bin: - -.. code-block:: console - - fatload mmc 1:1 0x82000000 zephyr.bin; dcache flush; icache flush; dcache off; icache off; go 0x82000000 - - -.. - References - -.. _PHYTEC website: - https://www.phytec.com/product/phycore-am62x/ - -.. _WIC: - https://download.phytec.de/Software/Linux/BSP-Yocto-AM62x/BSP-Yocto-AM62x-PD23.1.0/images/yogurt/phyboard-lyra-am62xx-2/phytec-qt5demo-image-phyboard-lyra-am62xx-2.wic.xz - -.. _Bmap: - https://download.phytec.de/Software/Linux/BSP-Yocto-AM62x/BSP-Yocto-AM62x-PD23.1.0/images/yogurt/phyboard-lyra-am62xx-2/phytec-qt5demo-image-phyboard-lyra-am62xx-2.wic.bmap diff --git a/boards/phytec/phycore_am62x/phycore_am62x_am6234_a53.dts b/boards/phytec/phycore_am62x/phycore_am62x_am6234_a53.dts deleted file mode 100644 index 7ab205e9d86..00000000000 --- a/boards/phytec/phycore_am62x/phycore_am62x_am6234_a53.dts +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2023 Enphase Energy - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/dts-v1/; - -#include - -/ { - model = "PHYTEC phyCORE-AM62x A53"; - compatible = "ti,am6234"; - - chosen { - zephyr,console = &uart0; - zephyr,shell-uart = &uart0; - zephyr,sram = &ddr0; - }; - - cpus { - cpu@0 { - status = "okay"; - }; - cpu@1 { - status = "disabled"; - }; - cpu@2 { - status = "disabled"; - }; - cpu@3 { - status = "disabled"; - }; - }; - - ddr0: memory@82000000 { - /* Note: This board actually has 2GB DRAM available */ - reg = <0x82000000 DT_SIZE_M(1)>; - }; -}; - -&pinctrl { - uart0_rx_default: uart0_rx_default { - pinmux = ; - }; - uart0_tx_default: uart0_tx_default { - pinmux = ; - }; -}; - -&uart0 { - current-speed = <115200>; - pinctrl-0 = <&uart0_rx_default &uart0_tx_default>; - pinctrl-names = "default"; - status = "okay"; -}; diff --git a/boards/phytec/phycore_am62x/phycore_am62x_am6234_a53.yaml b/boards/phytec/phycore_am62x/phycore_am62x_am6234_a53.yaml deleted file mode 100644 index b12e8863b50..00000000000 --- a/boards/phytec/phycore_am62x/phycore_am62x_am6234_a53.yaml +++ /dev/null @@ -1,13 +0,0 @@ -identifier: phycore_am62x/am6234/a53 -name: PHYTEC phyCORE-AM62x A53 -type: mcu -arch: arm64 -toolchain: - - zephyr - - cross-compile -ram: 1024 -testing: - ignore_tags: - - net - - bluetooth -vendor: ti diff --git a/boards/phytec/reel_board/reel_board_nrf52840_2.yaml b/boards/phytec/reel_board/reel_board_nrf52840_2.yaml index dc6361d4f50..7112c3fde8e 100644 --- a/boards/phytec/reel_board/reel_board_nrf52840_2.yaml +++ b/boards/phytec/reel_board/reel_board_nrf52840_2.yaml @@ -1,5 +1,5 @@ identifier: reel_board@2 -name: reel-board +name: reel-board (rev. 2) type: mcu arch: arm ram: 512 diff --git a/boards/pjrc/teensy4/teensy40.dts b/boards/pjrc/teensy4/teensy40.dts index 0c8d07db2ec..63775c3d1c6 100644 --- a/boards/pjrc/teensy4/teensy40.dts +++ b/boards/pjrc/teensy4/teensy40.dts @@ -66,29 +66,34 @@ zephyr_udc0: &usb1 { current-speed = < 115200 >; }; -&flexcan1 { - status = "okay"; - bus-speed = < 125000 >; -}; - &edma0 { status = "okay"; }; /* Pinmux settings */ -&enet { +&enet_mac { pinctrl-0 = <&pinmux_enet>; pinctrl-names = "default"; + zephyr,random-mac-address; + phy-connection-type = "rmii"; + phy-handle = <&phy>; }; -&flexcan1 { - pinctrl-0 = <&pinmux_flexcan1>; +&enet_mdio { + status = "okay"; + pinctrl-0 = <&pinmux_enet>; pinctrl-names = "default"; + phy: phy@0 { + compatible = "ethernet-phy"; + reg = <0>; + status = "okay"; + }; }; &flexcan1 { pinctrl-0 = <&pinmux_flexcan1>; pinctrl-names = "default"; + status = "okay"; }; &flexcan2 { diff --git a/boards/qemu/malta/doc/index.rst b/boards/qemu/malta/doc/index.rst index 178d787f951..014d2ae9c78 100644 --- a/boards/qemu/malta/doc/index.rst +++ b/boards/qemu/malta/doc/index.rst @@ -95,7 +95,7 @@ Use this configuration to run :zephyr:code-sample:`synchronization` sample in bi .. zephyr-app-commands:: :zephyr-app: samples/synchronization :host-os: unix - :board: qemu_malta//be + :board: qemu_malta/qemu_malta/be :goals: run diff --git a/boards/qemu/malta/qemu_malta_qemu_malta_be.yaml b/boards/qemu/malta/qemu_malta_qemu_malta_be.yaml index 98aa9884dbf..3bdbe8fa5c8 100644 --- a/boards/qemu/malta/qemu_malta_qemu_malta_be.yaml +++ b/boards/qemu/malta/qemu_malta_qemu_malta_be.yaml @@ -1,4 +1,4 @@ -identifier: qemu_malta//be +identifier: qemu_malta/qemu_malta/be name: QEMU emulation for MIPS (big endian) type: qemu simulation: qemu diff --git a/boards/qemu/riscv32/qemu_riscv32.dts b/boards/qemu/riscv32/qemu_riscv32.dts index 6c820813021..2c38ca1da1d 100644 --- a/boards/qemu/riscv32/qemu_riscv32.dts +++ b/boards/qemu/riscv32/qemu_riscv32.dts @@ -2,7 +2,7 @@ /dts-v1/; -#include +#include / { chosen { diff --git a/boards/qemu/riscv32/qemu_riscv32_qemu_virt_riscv32_smp.dts b/boards/qemu/riscv32/qemu_riscv32_qemu_virt_riscv32_smp.dts index 6c820813021..2c38ca1da1d 100644 --- a/boards/qemu/riscv32/qemu_riscv32_qemu_virt_riscv32_smp.dts +++ b/boards/qemu/riscv32/qemu_riscv32_qemu_virt_riscv32_smp.dts @@ -2,7 +2,7 @@ /dts-v1/; -#include +#include / { chosen { diff --git a/boards/qemu/riscv32e/qemu_riscv32e.dts b/boards/qemu/riscv32e/qemu_riscv32e.dts index 7596ee0d6eb..403d75cb742 100644 --- a/boards/qemu/riscv32e/qemu_riscv32e.dts +++ b/boards/qemu/riscv32e/qemu_riscv32e.dts @@ -7,7 +7,7 @@ /dts-v1/; -#include +#include / { chosen { diff --git a/boards/qemu/riscv64/qemu_riscv64.dts b/boards/qemu/riscv64/qemu_riscv64.dts index fb96f6d3d38..673d4668019 100644 --- a/boards/qemu/riscv64/qemu_riscv64.dts +++ b/boards/qemu/riscv64/qemu_riscv64.dts @@ -3,7 +3,7 @@ /dts-v1/; -#include +#include / { chosen { diff --git a/boards/qemu/riscv64/qemu_riscv64_qemu_virt_riscv64_smp.dts b/boards/qemu/riscv64/qemu_riscv64_qemu_virt_riscv64_smp.dts index fb96f6d3d38..673d4668019 100644 --- a/boards/qemu/riscv64/qemu_riscv64_qemu_virt_riscv64_smp.dts +++ b/boards/qemu/riscv64/qemu_riscv64_qemu_virt_riscv64_smp.dts @@ -3,7 +3,7 @@ /dts-v1/; -#include +#include / { chosen { diff --git a/boards/qemu/x86/board.cmake b/boards/qemu/x86/board.cmake index 2738f43bdde..660a07fae31 100644 --- a/boards/qemu/x86/board.cmake +++ b/boards/qemu/x86/board.cmake @@ -71,7 +71,7 @@ set(QEMU_FLAGS_${ARCH} ) if(NOT CONFIG_ACPI) - list(APPEND QEMU_FLAGS_${ARCH} -no-acpi) + list(APPEND QEMU_FLAGS_${ARCH} -machine acpi=off) endif() # TODO: Support debug diff --git a/boards/qemu/x86/qemu_x86.dts b/boards/qemu/x86/qemu_x86.dts index fbe6042c178..023c551eb47 100644 --- a/boards/qemu/x86/qemu_x86.dts +++ b/boards/qemu/x86/qemu_x86.dts @@ -61,7 +61,6 @@ device-id = <0x8406>; interrupts = <11 IRQ_TYPE_LOWEST_LEVEL_LOW 3>; interrupt-parent = <&intc>; - bus-speed = <125000>; can-transceiver { max-bitrate = <1000000>; diff --git a/boards/rak/rak4631/Kconfig b/boards/rak/rak4631/Kconfig new file mode 100644 index 00000000000..b313c721fb6 --- /dev/null +++ b/boards/rak/rak4631/Kconfig @@ -0,0 +1,18 @@ +# RAKWIRELESS RAK4631 Board configuration + +# Copyright (c) 2024 Kelly Helmut Lord +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_RAK4631 + +config BOARD_ENABLE_DCDC + bool "DCDC mode" + select SOC_DCDC_NRF52X + default y + +config BOARD_ENABLE_DCDC_HV + bool "High Voltage DCDC converter" + select SOC_DCDC_NRF52X_HV + default y + +endif # BOARD_RAK4631 diff --git a/boards/raspberrypi/rpi_5/Kconfig.rpi_5 b/boards/raspberrypi/rpi_5/Kconfig.rpi_5 new file mode 100644 index 00000000000..8f06aba9474 --- /dev/null +++ b/boards/raspberrypi/rpi_5/Kconfig.rpi_5 @@ -0,0 +1,5 @@ +# Copyright 2024 Junho Lee +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_RPI_5 + select SOC_BCM2712 diff --git a/boards/raspberrypi/rpi_5/board.yml b/boards/raspberrypi/rpi_5/board.yml new file mode 100644 index 00000000000..d604b7f4e51 --- /dev/null +++ b/boards/raspberrypi/rpi_5/board.yml @@ -0,0 +1,5 @@ +board: + name: rpi_5 + vendor: raspberrypi + socs: + - name: bcm2712 diff --git a/boards/raspberrypi/rpi_5/doc/index.rst b/boards/raspberrypi/rpi_5/doc/index.rst new file mode 100644 index 00000000000..c22c695a405 --- /dev/null +++ b/boards/raspberrypi/rpi_5/doc/index.rst @@ -0,0 +1,161 @@ +.. rpi_5: + +Raspberry Pi 5 (Cortex-A76) +########################### + +Overview +******** + +`Raspberry Pi 5 product-brief`_ + +Hardware +******** + +- Broadcom BCM2712 2.4GHz quad-core 64-bit Arm Cortex-A76 CPU, with cryptography extensions, 512KB per-core L2 caches and a 2MB shared L3 cache +- VideoCore VII GPU, supporting OpenGL ES 3.1, Vulkan 1.2 +- Dual 4Kp60 HDMIĀ® display output with HDR support +- 4Kp60 HEVC decoder +- LPDDR4X-4267 SDRAM (4GB and 8GB SKUs available at launch) +- Dual-band 802.11ac Wi-FiĀ® +- Bluetooth 5.0 / Bluetooth Low Energy (BLE) +- microSD card slot, with support for high-speed SDR104 mode +- 2 x USB 3.0 ports, supporting simultaneous 5Gbps operation +- 2 x USB 2.0 ports +- Gigabit Ethernet, with PoE+ support (requires separate PoE+ HAT) +- 2 x 4-lane MIPI camera/display transceivers +- PCIe 2.0 x1 interface for fast peripherals (requires separate M.2 HAT or other adapter) +- 5V/5A DC power via USB-C, with Power Delivery support +- Raspberry Pi standard 40-pin header +- Real-time clock (RTC), powered from external battery +- Power button + +Supported Features +================== + +The Raspberry Pi 5 board configuration supports the following hardware features: + +.. 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,brcmstb-gpio` + * - UART + - :kconfig:option:`CONFIG_SERIAL` + - :dtcompatible:`arm,pl011` + +Not all hardware features are supported yet. See `Raspberry Pi hardware`_ for the complete list of hardware features. + +The default configuration can be found in +:zephyr_file:`boards/raspberrypi/rpi_5/rpi_5_defconfig`. + +Programming and Debugging +************************* + +Blinky +====== + +In brief, + 1. Format your Micro SD card with MBR and FAT32. + 2. Save three files below in the root directory. + * config.txt + * zephyr.bin + * `bcm2712-rpi-5.dtb`_ + 3. Insert the Micro SD card and power on the Raspberry Pi 5. + +then, You will see the Raspberry Pi 5 running the `zephyr.bin`. + +config.txt +---------- + +.. code-block:: text + + kernel=zephyr.bin + arm_64bit=1 + + +zephyr.bin +---------- + +Build an app `samples/basic/blinky` + +.. zephyr-app-commands:: + :zephyr-app: samples/basic/blinky + :board: rpi_5 + :goals: build + +Copy `zephyr.bin` from `build/zephyr` directory to the root directory of the Micro SD card. + +Insert the Micro SD card and power on the Raspberry Pi 5. And then, the STAT LED will start to blink. + + +Serial Communication +==================== + +wiring +------ + +You will need the following items: + * `Raspberry Pi Debug Probe`_ + * JST cable: 3-pin JST connector to 3-pin JST connector cable + * USB cable: USB A male - Micro USB B male + +Use the JST cable to connect the Raspberry Pi Debug Probe UART port to the Raspberry Pi 5 UART port between the HDMI ports. + +Then connect the Raspberry Pi Debug Probe to your computer with a USB cable. + + +config.txt +---------- + +.. code-block:: text + + kernel=zephyr.bin + arm_64bit=1 + enable_uart=1 + uart_2ndstage=1 + + +zephyr.bin +---------- + +Build an app `samples/hello_world` + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: rpi_5 + :goals: build + +Copy `zephyr.bin` from `build/zephyr` directory to the root directory of the Micro SD card. + +Insert the Micro SD card into your Raspberry Pi 5. + + +serial terminal emulator +------------------------ + +When you power on the Raspberry Pi 5, you will see the following output in the serial console: + +.. code-block:: text + + *** Booting Zephyr OS build XXXXXXXXXXXX *** + Hello World! rpi_5/bcm2712 + + +.. _Raspberry Pi 5 product-brief: + https://datasheets.raspberrypi.com/rpi5/raspberry-pi-5-product-brief.pdf + +.. _Raspberry Pi hardware: + https://www.raspberrypi.com/documentation/computers/raspberry-pi.html + +.. _bcm2712-rpi-5.dtb: + https://github.com/raspberrypi/firmware/raw/master/boot/bcm2712-rpi-5-b.dtb + +.. _Raspberry Pi Debug Probe: + https://www.raspberrypi.com/products/debug-probe/ diff --git a/boards/raspberrypi/rpi_5/rpi_5.dts b/boards/raspberrypi/rpi_5/rpi_5.dts new file mode 100644 index 00000000000..6fca0efd3d0 --- /dev/null +++ b/boards/raspberrypi/rpi_5/rpi_5.dts @@ -0,0 +1,45 @@ +/* + * Copyright 2024 Junho Lee + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include + +/ { + compatible = "raspberrypi,5-model-b", "brcm,bcm2712"; + model = "Raspberry Pi 5"; + #address-cells = <2>; + #size-cells = <1>; + + aliases { + led0 = &led_act; + }; + + chosen { + zephyr,sram = &sram0; + zephyr,console = &uart10; + zephyr,shell-uart = &uart10; + }; + + leds { + compatible = "gpio-leds"; + + led_act: led-act { + gpios = <&gio_aon 9 GPIO_ACTIVE_LOW>; + label = "ACT"; + }; + }; +}; + +&gio_aon { + status = "okay"; +}; + +&uart10 { + status = "okay"; + current-speed = <115200>; +}; diff --git a/boards/raspberrypi/rpi_5/rpi_5.yaml b/boards/raspberrypi/rpi_5/rpi_5.yaml new file mode 100644 index 00000000000..e293d78e9cd --- /dev/null +++ b/boards/raspberrypi/rpi_5/rpi_5.yaml @@ -0,0 +1,7 @@ +identifier: rpi_5 +name: Raspberry Pi 5 +type: mcu +arch: arm64 +toolchain: + - zephyr + - cross-compile diff --git a/boards/raspberrypi/rpi_5/rpi_5_defconfig b/boards/raspberrypi/rpi_5/rpi_5_defconfig new file mode 100644 index 00000000000..bc0375e8120 --- /dev/null +++ b/boards/raspberrypi/rpi_5/rpi_5_defconfig @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_ARM64_VA_BITS_40=y +CONFIG_ARM64_PA_BITS_40=y +CONFIG_TIMER_READS_ITS_FREQUENCY_AT_RUNTIME=y + +# Enable serial console. +CONFIG_SERIAL=y +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y diff --git a/boards/renesas/da1469x_dk_pro/Kconfig.defconfig b/boards/renesas/da1469x_dk_pro/Kconfig.defconfig index 9c447539c3b..c20c21658d0 100644 --- a/boards/renesas/da1469x_dk_pro/Kconfig.defconfig +++ b/boards/renesas/da1469x_dk_pro/Kconfig.defconfig @@ -34,4 +34,32 @@ config LV_Z_POINTER_INPUT_MSGQ_COUNT endif # INPUT +#if PM || PM_DEVICE || PM_DEVICE_RUNTIME + +# Increase stack size to avoid raising usage-fault +# exceptions due to stack overflow. +config IDLE_STACK_SIZE + default 2048 + +# Make sure the serial device has higher +# initialization priority. +config SERIAL_INIT_PRIORITY + default KERNEL_INIT_PRIORITY_DEFAULT + +#endif # PM || PM_DEVICE + +if BT + +choice BT_HCI_BUS_TYPE + default BT_DA1469X +endchoice + +config BT_WAIT_NOP + default y + +config TEST_RANDOM_GENERATOR + default y + +endif # BT + endif # BOARD_DA1469X_DK_PRO diff --git a/boards/renesas/da1469x_dk_pro/da1469x_dk_pro-pinctrl.dtsi b/boards/renesas/da1469x_dk_pro/da1469x_dk_pro-pinctrl.dtsi index 39daff3ff16..0a90af9a63c 100644 --- a/boards/renesas/da1469x_dk_pro/da1469x_dk_pro-pinctrl.dtsi +++ b/boards/renesas/da1469x_dk_pro/da1469x_dk_pro-pinctrl.dtsi @@ -47,14 +47,29 @@ }; }; + /omit-if-no-ref/ display_controller_sleep: display_controller_sleep { + group1 { + pinmux = , + , + , + , + , + , + , + , + , + ; + }; + }; + spi_controller: spi_controller { group1 { - pinmux = , - ; + pinmux = , + ; output-enable; }; group2 { - pinmux = ; + pinmux = ; input-enable; }; }; diff --git a/boards/renesas/da1469x_dk_pro/da1469x_dk_pro.dts b/boards/renesas/da1469x_dk_pro/da1469x_dk_pro.dts index f83098f6f19..f4a3d1d674e 100644 --- a/boards/renesas/da1469x_dk_pro/da1469x_dk_pro.dts +++ b/boards/renesas/da1469x_dk_pro/da1469x_dk_pro.dts @@ -119,6 +119,7 @@ status = "okay"; pinctrl-0 = <&uart_default>; pinctrl-names = "default"; + rx-wake-gpios = <&gpio0 8 GPIO_ACTIVE_LOW>; }; zephyr_udc0: &usbd { diff --git a/boards/renesas/da1469x_dk_pro/da1469x_dk_pro.yaml b/boards/renesas/da1469x_dk_pro/da1469x_dk_pro.yaml index eb29fd6c559..942bfe3e07e 100644 --- a/boards/renesas/da1469x_dk_pro/da1469x_dk_pro.yaml +++ b/boards/renesas/da1469x_dk_pro/da1469x_dk_pro.yaml @@ -21,4 +21,5 @@ supported: - dma - mipi_dbi - display + - memc vendor: renesas diff --git a/boards/renesas/da1469x_dk_pro/dts/da1469x_dk_pro_lcdc.overlay b/boards/renesas/da1469x_dk_pro/dts/da1469x_dk_pro_lcdc.overlay index c147201adc4..197882b5536 100644 --- a/boards/renesas/da1469x_dk_pro/dts/da1469x_dk_pro_lcdc.overlay +++ b/boards/renesas/da1469x_dk_pro/dts/da1469x_dk_pro_lcdc.overlay @@ -31,6 +31,14 @@ bias-pull-up; }; }; + + i2c2_sleep: i2c2_sleep { + group1 { + pinmux = , + ; + bias-pull-down; + }; + }; }; &i2c2 { @@ -47,7 +55,8 @@ &lcdc { status = "okay"; pinctrl-0 = <&display_controller_default>; - pinctrl-names = "default"; + pinctrl-1 = <&display_controller_sleep>; + pinctrl-names = "default", "sleep"; width = <480>; height = <272>; disp-gpios = <&gpio0 25 GPIO_ACTIVE_HIGH>; diff --git a/boards/renesas/da1469x_dk_pro/dts/da1469x_dk_pro_psram.overlay b/boards/renesas/da1469x_dk_pro/dts/da1469x_dk_pro_psram.overlay new file mode 100644 index 00000000000..5707f111d97 --- /dev/null +++ b/boards/renesas/da1469x_dk_pro/dts/da1469x_dk_pro_psram.overlay @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2024 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + + / { + aliases { + sram-ext = &memc; + }; +}; + +/* QSPIC settings for the APS6404L-3SQR QSPI PSRAM memory in QPI mode. */ +&memc { + status = "okay"; + is-ram; + dev-size = ; + dev-type = <0x5D>; + dev-id = <0x0D>; + dev-density = <0xE040>; + reset-delay-us = <50>; + read-cs-idle-min-ns = <18>; + tcem-max-us = <2>; + enter-qpi-mode; + enter-qpi-cmd = <0x35>; + extra-byte-enable; + extra-byte = <0x0>; + dummy-bytes-count = "dummy-bytes-count2"; + read-cmd = <0xEB>; + write-cmd = <0x38>; + rx-inst-mode = "quad-spi"; + rx-addr-mode = "quad-spi"; + rx-data-mode = "quad-spi"; + rx-dummy-mode = "quad-spi"; + rx-extra-mode = "quad-spi"; + tx-inst-mode = "quad-spi"; + tx-addr-mode = "quad-spi"; + tx-data-mode = "quad-spi"; +}; diff --git a/boards/renesas/rcar_h3ulcb/doc/rcar_h3ulcb_a57.rst b/boards/renesas/rcar_h3ulcb/doc/rcar_h3ulcb_a57.rst index d7a261dbb5c..aefe429f5c8 100644 --- a/boards/renesas/rcar_h3ulcb/doc/rcar_h3ulcb_a57.rst +++ b/boards/renesas/rcar_h3ulcb/doc/rcar_h3ulcb_a57.rst @@ -58,6 +58,8 @@ hardware features: +-----------+------------------------------+--------------------------------+ | UART | uart | serial port-polling | +-----------+------------------------------+--------------------------------+ +| MMC | renesas_rcar_mmc | DMA and SCC | ++-----------+------------------------------+--------------------------------+ Other hardware features have not been enabled yet for this board. diff --git a/boards/renesas/rcar_h3ulcb/rcar_h3ulcb_r8a77951_a57-pinctrl.dtsi b/boards/renesas/rcar_h3ulcb/rcar_h3ulcb_r8a77951_a57-pinctrl.dtsi index 088f930051d..6dc65b03313 100644 --- a/boards/renesas/rcar_h3ulcb/rcar_h3ulcb_r8a77951_a57-pinctrl.dtsi +++ b/boards/renesas/rcar_h3ulcb/rcar_h3ulcb_r8a77951_a57-pinctrl.dtsi @@ -14,4 +14,48 @@ scif2_data_a_rx_default: scif2_data_a_rx_default { pin = ; }; + + emmc2_clk: emmc2_clk { + pin = ; + }; + + emmc2_cmd: emmc2_cmd { + pin = ; + }; + + emmc2_data0: emmc2_data0 { + pin = ; + }; + + emmc2_data1: emmc2_data1 { + pin = ; + }; + + emmc2_data2: emmc2_data2 { + pin = ; + }; + + emmc2_data3: emmc2_data3 { + pin = ; + }; + + emmc2_data4: emmc2_data4 { + pin = ; + }; + + emmc2_data5: emmc2_data5 { + pin = ; + }; + + emmc2_data6: emmc2_data6 { + pin = ; + }; + + emmc2_data7: emmc2_data7 { + pin = ; + }; + + emmc2_ds: emmc2_ds { + pin = ; + }; }; diff --git a/boards/renesas/rcar_h3ulcb/rcar_h3ulcb_r8a77951_a57.dts b/boards/renesas/rcar_h3ulcb/rcar_h3ulcb_r8a77951_a57.dts index 5a2bef11c82..599a0f25314 100644 --- a/boards/renesas/rcar_h3ulcb/rcar_h3ulcb_r8a77951_a57.dts +++ b/boards/renesas/rcar_h3ulcb/rcar_h3ulcb_r8a77951_a57.dts @@ -23,6 +23,11 @@ device_type = "mmio-sram"; reg = <0x0 0x48000000 0x0 DT_SIZE_M(512)>; }; + + /* These aliases are provided for compatibility with samples */ + aliases { + sdhc0 = &emmc2; + }; }; &scif2 { @@ -30,3 +35,21 @@ pinctrl-names = "default"; status = "okay"; }; + +&emmc2 { + pinctrl-0 = <&emmc2_clk &emmc2_cmd &emmc2_ds + &emmc2_data0 &emmc2_data1 &emmc2_data2 &emmc2_data3 + &emmc2_data4 &emmc2_data5 &emmc2_data6 &emmc2_data7>; + pinctrl-1 = <&emmc2_clk &emmc2_cmd &emmc2_ds + &emmc2_data0 &emmc2_data1 &emmc2_data2 &emmc2_data3 + &emmc2_data4 &emmc2_data5 &emmc2_data6 &emmc2_data7>; + pinctrl-names = "default", "uhs"; + disk { + compatible = "zephyr,mmc-disk"; + status = "disabled"; + }; + bus-width = <8>; + mmc-hs200-1_8v; + mmc-hs400-1_8v; + non-removable; +}; diff --git a/boards/renesas/rcar_h3ulcb/rcar_h3ulcb_r8a77951_r7.dts b/boards/renesas/rcar_h3ulcb/rcar_h3ulcb_r8a77951_r7.dts index a5a23e779d8..cadd4dc9799 100644 --- a/boards/renesas/rcar_h3ulcb/rcar_h3ulcb_r8a77951_r7.dts +++ b/boards/renesas/rcar_h3ulcb/rcar_h3ulcb_r8a77951_r7.dts @@ -63,7 +63,6 @@ pinctrl-0 = <&can0_data_a_tx_default &can0_data_a_rx_default>; pinctrl-names = "default"; status = "okay"; - bus-speed = <125000>; can-transceiver { max-bitrate = <5000000>; diff --git a/boards/renesas/rcar_salvator_x/rcar_salvator_x_r8a77951_r7.dts b/boards/renesas/rcar_salvator_x/rcar_salvator_x_r8a77951_r7.dts index ce5c046f54a..d0db253f127 100644 --- a/boards/renesas/rcar_salvator_x/rcar_salvator_x_r8a77951_r7.dts +++ b/boards/renesas/rcar_salvator_x/rcar_salvator_x_r8a77951_r7.dts @@ -75,7 +75,6 @@ pinctrl-0 = <&can0_data_a_tx_default &can0_data_a_rx_default>; pinctrl-names = "default"; status = "okay"; - bus-speed = <125000>; }; &scif1 { diff --git a/boards/renesas/rcar_salvator_xs/doc/index.rst b/boards/renesas/rcar_salvator_xs/doc/index.rst index a9900158169..464b4e659d7 100644 --- a/boards/renesas/rcar_salvator_xs/doc/index.rst +++ b/boards/renesas/rcar_salvator_xs/doc/index.rst @@ -43,6 +43,8 @@ hardware features: +-----------+------------------------------+--------------------------------+ | UART | uart | serial port-polling | +-----------+------------------------------+--------------------------------+ +| MMC | renesas_rcar_mmc | DMA and SCC | ++-----------+------------------------------+--------------------------------+ Other hardware features have not been enabled yet for this board. diff --git a/boards/renesas/rcar_salvator_xs/rcar_salvator_xs-pinctrl.dtsi b/boards/renesas/rcar_salvator_xs/rcar_salvator_xs-pinctrl.dtsi index 69529f233ac..b563a720079 100644 --- a/boards/renesas/rcar_salvator_xs/rcar_salvator_xs-pinctrl.dtsi +++ b/boards/renesas/rcar_salvator_xs/rcar_salvator_xs-pinctrl.dtsi @@ -14,4 +14,48 @@ scif2_data_a_rx_default: scif2_data_a_rx_default { pin = ; }; + + emmc2_clk: emmc2_clk { + pin = ; + }; + + emmc2_cmd: emmc2_cmd { + pin = ; + }; + + emmc2_data0: emmc2_data0 { + pin = ; + }; + + emmc2_data1: emmc2_data1 { + pin = ; + }; + + emmc2_data2: emmc2_data2 { + pin = ; + }; + + emmc2_data3: emmc2_data3 { + pin = ; + }; + + emmc2_data4: emmc2_data4 { + pin = ; + }; + + emmc2_data5: emmc2_data5 { + pin = ; + }; + + emmc2_data6: emmc2_data6 { + pin = ; + }; + + emmc2_data7: emmc2_data7 { + pin = ; + }; + + emmc2_ds: emmc2_ds { + pin = ; + }; }; diff --git a/boards/renesas/rcar_salvator_xs/rcar_salvator_xs.dts b/boards/renesas/rcar_salvator_xs/rcar_salvator_xs.dts index 9c6bfc9a6eb..bc926dfddd4 100644 --- a/boards/renesas/rcar_salvator_xs/rcar_salvator_xs.dts +++ b/boards/renesas/rcar_salvator_xs/rcar_salvator_xs.dts @@ -19,6 +19,11 @@ zephyr,shell-uart = &scif2; }; + /* These aliases are provided for compatibility with samples */ + aliases { + sdhc0 = &emmc2; + }; + ram: memory@48000000 { device_type = "mmio-sram"; reg = <0x0 0x48000000 0x0 DT_SIZE_M(512)>; @@ -30,3 +35,21 @@ pinctrl-names = "default"; status = "okay"; }; + +&emmc2 { + pinctrl-0 = <&emmc2_clk &emmc2_cmd &emmc2_ds + &emmc2_data0 &emmc2_data1 &emmc2_data2 &emmc2_data3 + &emmc2_data4 &emmc2_data5 &emmc2_data6 &emmc2_data7>; + pinctrl-1 = <&emmc2_clk &emmc2_cmd &emmc2_ds + &emmc2_data0 &emmc2_data1 &emmc2_data2 &emmc2_data3 + &emmc2_data4 &emmc2_data5 &emmc2_data6 &emmc2_data7>; + pinctrl-names = "default", "uhs"; + disk { + compatible = "zephyr,mmc-disk"; + status = "disabled"; + }; + bus-width = <8>; + mmc-hs200-1_8v; + mmc-hs400-1_8v; + non-removable; +}; diff --git a/boards/renesas/rcar_spider_s4/Kconfig.defconfig b/boards/renesas/rcar_spider_s4/Kconfig.defconfig new file mode 100644 index 00000000000..8f042de539a --- /dev/null +++ b/boards/renesas/rcar_spider_s4/Kconfig.defconfig @@ -0,0 +1,5 @@ +# Copyright (c) 2024 EPAM Systems +# SPDX-License-Identifier: Apache-2.0 + +config BUILD_OUTPUT_BIN + default y if BOARD_RCAR_SPIDER_S4_R8A779F0_A55 diff --git a/boards/renesas/rcar_spider_s4/Kconfig.rcar_spider_s4 b/boards/renesas/rcar_spider_s4/Kconfig.rcar_spider_s4 index 7f6bacf4894..23f158b3b44 100644 --- a/boards/renesas/rcar_spider_s4/Kconfig.rcar_spider_s4 +++ b/boards/renesas/rcar_spider_s4/Kconfig.rcar_spider_s4 @@ -2,4 +2,5 @@ # SPDX-License-Identifier: Apache-2.0 config BOARD_RCAR_SPIDER_S4 - select SOC_R8A779F0 + select SOC_R8A779F0_R52 if BOARD_RCAR_SPIDER_S4_R8A779F0_R52 + select SOC_R8A779F0_A55 if BOARD_RCAR_SPIDER_S4_R8A779F0_A55 diff --git a/boards/renesas/rcar_spider_s4/board.cmake b/boards/renesas/rcar_spider_s4/board.cmake index b106c562c54..01310776d4c 100644 --- a/boards/renesas/rcar_spider_s4/board.cmake +++ b/boards/renesas/rcar_spider_s4/board.cmake @@ -1,3 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -board_runner_args(openocd "--use-elf") -include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) +if(CONFIG_BOARD_RCAR_SPIDER_S4_R8A779F0_R52) + board_runner_args(openocd "--use-elf") + include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) +endif() diff --git a/boards/renesas/rcar_spider_s4/doc/rcar_spider.rst b/boards/renesas/rcar_spider_s4/doc/rcar_spider.rst deleted file mode 100644 index 933c7054130..00000000000 --- a/boards/renesas/rcar_spider_s4/doc/rcar_spider.rst +++ /dev/null @@ -1,200 +0,0 @@ -.. _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_s4`` 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_s4 - :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_s4 - -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_s4 - :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_s4 - -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/renesas/rcar_spider_s4/doc/rcar_spider_a55.rst b/boards/renesas/rcar_spider_s4/doc/rcar_spider_a55.rst new file mode 100644 index 00000000000..2f45cf1521e --- /dev/null +++ b/boards/renesas/rcar_spider_s4/doc/rcar_spider_a55.rst @@ -0,0 +1,83 @@ +.. _rcar_spider_a55: + +R-CAR Spider S4 (ARM64) +####################### + +Overview +******** +R-Car S4 enables to launch 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. + +Hardware +******** +The R-Car S4 includes: + +* eight 1.2GHz Arm Cortex-A55 cores, 2 cores x 4 clusters; +* 1.0 GHz Arm Cortex-R52 core (hardware Lock step is supported); +* two 400MHz G4MH cores (hardware Lock step is supported); +* memory controller for LPDDR4X-3200 with 32bit bus (16bit x 1ch + 16bit x 1ch) with ECC; +* SD card host interface / eMMC; +* UFS 3.0 x 1 channel; +* PCI Express Gen4.0 interface (Dual lane x 2ch); +* ICUMX; +* ICUMH; +* SHIP-S x 3 channels; +* AES Accerator x 8 channels; +* CAN FD interface x 16 channels; +* R-Switch2 (Ether); +* 100base EtherAVB x 1 channel; +* Gbit-EtherTSN x 3 channels; +* 1 unit FlexRay (A,B 2ch) interface. + +Supported Features +================== +The Renesas ``rcar_spider_s4/r8a779f0/a55`` board configuration supports the following +hardware features: + ++-----------+------------------------------+--------------------------------+ +| Interface | Driver/components | Support level | ++===========+==============================+================================+ +| PINCTRL | pinctrl | | ++-----------+------------------------------+--------------------------------+ +| CLOCK | clock_control | | ++-----------+------------------------------+--------------------------------+ +| UART | serial | interrupt-driven/polling | ++-----------+------------------------------+--------------------------------+ + +Other hardware features have not been enabled yet for this board. + +Programming and Debugging +************************* + +The onboard flash is not supported by Zephyr at this time. However, it is possible to +load the Zephyr binary using U-Boot commands. + +One of the ways to load Zephyr is shown below. + +.. code-block:: console + + tftp 0x48000000 + booti 0x48000000 + +Here is an example for the :ref:`hello_world` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: rcar_spider_s4/r8a779f0/a55 + :goals: build + +References +********** + +- `Renesas R-Car Development Support website`_ +- `eLinux Spider page`_ + +.. _Renesas R-Car Development Support website: + https://www.renesas.com/us/en/support/partners/r-car-consortium/r-car-development-support + +.. _eLinux Spider page: + https://elinux.org/R-Car/Boards/Spider diff --git a/boards/renesas/rcar_spider_s4/doc/rcar_spider_r52.rst b/boards/renesas/rcar_spider_s4/doc/rcar_spider_r52.rst new file mode 100644 index 00000000000..d7fec18e036 --- /dev/null +++ b/boards/renesas/rcar_spider_s4/doc/rcar_spider_r52.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_s4/r8a779f0/r52`` 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_s4/r8a779f0/r52 + :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_s4 + +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_s4/r8a779f0/r52 + :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_s4 + +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/renesas/rcar_spider_s4/rcar_spider_s4.dts b/boards/renesas/rcar_spider_s4/rcar_spider_s4.dts deleted file mode 100644 index 367c867682d..00000000000 --- a/boards/renesas/rcar_spider_s4/rcar_spider_s4.dts +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2023 IoT.bzh - * - * SPDX-License-Identifier: Apache-2.0 - * - */ - -/dts-v1/; -#include -#include "rcar_spider_s4-pinctrl.dtsi" -#include - -/ { - model = "Renesas Spider board"; - compatible = "renesas,spider-s4"; - - 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/renesas/rcar_spider_s4/rcar_spider_s4.yaml b/boards/renesas/rcar_spider_s4/rcar_spider_s4.yaml deleted file mode 100644 index 92b98f20d30..00000000000 --- a/boards/renesas/rcar_spider_s4/rcar_spider_s4.yaml +++ /dev/null @@ -1,11 +0,0 @@ -identifier: rcar_spider_s4 -name: Cortex r52 for Renesas Spider -type: mcu -arch: arm -toolchain: - - zephyr - - gnuarmemb -supported: - - gpio - - clock_control - - uart diff --git a/boards/renesas/rcar_spider_s4/rcar_spider_s4_r8a779f0_a55-pinctrl.dtsi b/boards/renesas/rcar_spider_s4/rcar_spider_s4_r8a779f0_a55-pinctrl.dtsi new file mode 100644 index 00000000000..50739a237be --- /dev/null +++ b/boards/renesas/rcar_spider_s4/rcar_spider_s4_r8a779f0_a55-pinctrl.dtsi @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2023 EPAM Systems + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&pfc { + hscif0_data_tx_default: hscif0_data_tx_default { + pin = ; + }; + + hscif0_data_rx_default: hscif0_data_rx_default { + pin = ; + }; +}; diff --git a/boards/renesas/rcar_spider_s4/rcar_spider_s4_r8a779f0_a55.dts b/boards/renesas/rcar_spider_s4/rcar_spider_s4_r8a779f0_a55.dts new file mode 100644 index 00000000000..2075b90495c --- /dev/null +++ b/boards/renesas/rcar_spider_s4/rcar_spider_s4_r8a779f0_a55.dts @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2023-2024 EPAM Systems + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +/dts-v1/; +#include +#include +#include "rcar_spider_s4_r8a779f0_a55-pinctrl.dtsi" + +/ { + model = "Renesas Spider CA55"; + chosen { + zephyr,sram = &ram; + zephyr,console = &hscif0; + zephyr,shell-uart = &hscif0; + }; + + ram: memory@48000000 { + device_type = "mmio-sram"; + reg = <0x0 0x48000000 0x0 DT_SIZE_M(512)>; + }; +}; + +&hscif0 { + pinctrl-0 = <&hscif0_data_tx_default &hscif0_data_rx_default>; + pinctrl-names = "default"; + current-speed = <1843200>; + status = "okay"; +}; diff --git a/boards/renesas/rcar_spider_s4/rcar_spider_s4_r8a779f0_a55.yaml b/boards/renesas/rcar_spider_s4/rcar_spider_s4_r8a779f0_a55.yaml new file mode 100644 index 00000000000..abeafc4bd44 --- /dev/null +++ b/boards/renesas/rcar_spider_s4/rcar_spider_s4_r8a779f0_a55.yaml @@ -0,0 +1,12 @@ +identifier: rcar_spider_s4/r8a779f0/a55 +name: Cortex A55 for Renesas Spider +type: mcu +arch: arm64 +toolchain: + - zephyr + - cross-compile +supported: + - pinctrl + - gpio + - clock_control + - uart diff --git a/boards/renesas/rcar_spider_s4/rcar_spider_s4_r8a779f0_a55_defconfig b/boards/renesas/rcar_spider_s4/rcar_spider_s4_r8a779f0_a55_defconfig new file mode 100644 index 00000000000..dbf526298c0 --- /dev/null +++ b/boards/renesas/rcar_spider_s4/rcar_spider_s4_r8a779f0_a55_defconfig @@ -0,0 +1,19 @@ +# Cache management +CONFIG_CACHE_MANAGEMENT=y + +# Enable UART driver +CONFIG_SERIAL=y + +# Enable console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y +CONFIG_UART_INTERRUPT_DRIVEN=y + +# Enable clock control +CONFIG_CLOCK_CONTROL=y +CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=16666666 + +CONFIG_AARCH64_IMAGE_HEADER=y +CONFIG_XIP=n +CONFIG_MAX_XLAT_TABLES=24 +CONFIG_ARMV8_A_NS=y diff --git a/boards/renesas/rcar_spider_s4/rcar_spider_s4-pinctrl.dtsi b/boards/renesas/rcar_spider_s4/rcar_spider_s4_r8a779f0_r52-pinctrl.dtsi similarity index 100% rename from boards/renesas/rcar_spider_s4/rcar_spider_s4-pinctrl.dtsi rename to boards/renesas/rcar_spider_s4/rcar_spider_s4_r8a779f0_r52-pinctrl.dtsi diff --git a/boards/renesas/rcar_spider_s4/rcar_spider_s4_r8a779f0_r52.dts b/boards/renesas/rcar_spider_s4/rcar_spider_s4_r8a779f0_r52.dts new file mode 100644 index 00000000000..a8679700ea3 --- /dev/null +++ b/boards/renesas/rcar_spider_s4/rcar_spider_s4_r8a779f0_r52.dts @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2023 IoT.bzh + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +/dts-v1/; +#include +#include "rcar_spider_s4_r8a779f0_r52-pinctrl.dtsi" +#include + +/ { + model = "Renesas Spider board"; + compatible = "renesas,spider-s4-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/renesas/rcar_spider_s4/rcar_spider_s4_r8a779f0_r52.yaml b/boards/renesas/rcar_spider_s4/rcar_spider_s4_r8a779f0_r52.yaml new file mode 100644 index 00000000000..f8ac538889c --- /dev/null +++ b/boards/renesas/rcar_spider_s4/rcar_spider_s4_r8a779f0_r52.yaml @@ -0,0 +1,11 @@ +identifier: rcar_spider_s4/r8a779f0/r52 +name: Cortex r52 for Renesas Spider +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb +supported: + - gpio + - clock_control + - uart diff --git a/boards/renesas/rcar_spider_s4/rcar_spider_s4_defconfig b/boards/renesas/rcar_spider_s4/rcar_spider_s4_r8a779f0_r52_defconfig similarity index 100% rename from boards/renesas/rcar_spider_s4/rcar_spider_s4_defconfig rename to boards/renesas/rcar_spider_s4/rcar_spider_s4_r8a779f0_r52_defconfig diff --git a/boards/seagate/legend/legend_stm32f070xb_25hdd.yaml b/boards/seagate/legend/legend_stm32f070xb_25hdd.yaml index a9eb85aee47..e94bd6e2faa 100644 --- a/boards/seagate/legend/legend_stm32f070xb_25hdd.yaml +++ b/boards/seagate/legend/legend_stm32f070xb_25hdd.yaml @@ -1,5 +1,5 @@ identifier: legend@25hdd -name: Legend +name: Legend (25hdd) type: mcu arch: arm ram: 16 diff --git a/boards/seagate/legend/legend_stm32f070xb_25ssd.yaml b/boards/seagate/legend/legend_stm32f070xb_25ssd.yaml index db494bd878c..b1aa3766f77 100644 --- a/boards/seagate/legend/legend_stm32f070xb_25ssd.yaml +++ b/boards/seagate/legend/legend_stm32f070xb_25ssd.yaml @@ -1,5 +1,5 @@ identifier: legend@25ssd -name: Legend +name: Legend (25sdd) type: mcu arch: arm ram: 16 diff --git a/boards/seagate/legend/legend_stm32f070xb_35.yaml b/boards/seagate/legend/legend_stm32f070xb_35.yaml index 37ed59788d9..851fb36a8b4 100644 --- a/boards/seagate/legend/legend_stm32f070xb_35.yaml +++ b/boards/seagate/legend/legend_stm32f070xb_35.yaml @@ -1,5 +1,5 @@ identifier: legend@35 -name: Legend +name: Legend (35) type: mcu arch: arm ram: 16 diff --git a/boards/seco/stm32f3_seco_d23/stm32f3_seco_d23.dts b/boards/seco/stm32f3_seco_d23/stm32f3_seco_d23.dts index 79577593ddb..bfd1fc3c30b 100644 --- a/boards/seco/stm32f3_seco_d23/stm32f3_seco_d23.dts +++ b/boards/seco/stm32f3_seco_d23/stm32f3_seco_d23.dts @@ -177,7 +177,6 @@ zephyr_udc0: &usb { &can1 { pinctrl-0 = <&can_rx_pb8 &can_tx_pb9>; pinctrl-names = "default"; - bus-speed = <125000>; phys = <&transceiver0>; status = "okay"; }; diff --git a/boards/seeed/seeeduino_xiao/seeed_xiao_connector.dtsi b/boards/seeed/seeeduino_xiao/seeed_xiao_connector.dtsi index e4709327113..b149504e0a2 100644 --- a/boards/seeed/seeeduino_xiao/seeed_xiao_connector.dtsi +++ b/boards/seeed/seeeduino_xiao/seeed_xiao_connector.dtsi @@ -30,3 +30,4 @@ xiao_spi: &sercom0 {}; xiao_i2c: &sercom2 {}; xiao_serial: &sercom4 {}; xiao_dac: &dac0 {}; +xiao_adc: &adc {}; diff --git a/boards/seeed/xiao_ble/seeed_xiao_connector.dtsi b/boards/seeed/xiao_ble/seeed_xiao_connector.dtsi index 4f0c1ad983f..e4c7077c922 100644 --- a/boards/seeed/xiao_ble/seeed_xiao_connector.dtsi +++ b/boards/seeed/xiao_ble/seeed_xiao_connector.dtsi @@ -30,3 +30,4 @@ xiao_spi: &spi2 {}; xiao_i2c: &i2c1 {}; xiao_serial: &uart0 {}; +xiao_adc: &adc {}; diff --git a/boards/seeed/xiao_esp32c3/seeed_xiao_connector.dtsi b/boards/seeed/xiao_esp32c3/seeed_xiao_connector.dtsi index 08bd5d76d9f..23eab39a85c 100644 --- a/boards/seeed/xiao_esp32c3/seeed_xiao_connector.dtsi +++ b/boards/seeed/xiao_esp32c3/seeed_xiao_connector.dtsi @@ -27,3 +27,4 @@ xiao_spi: &spi2 {}; xiao_i2c: &i2c0 {}; xiao_serial: &uart0 {}; +xiao_adc: &adc0 {}; diff --git a/boards/seeed/xiao_esp32c3/xiao_esp32c3.dts b/boards/seeed/xiao_esp32c3/xiao_esp32c3.dts index 5cea1004af6..8475709095b 100644 --- a/boards/seeed/xiao_esp32c3/xiao_esp32c3.dts +++ b/boards/seeed/xiao_esp32c3/xiao_esp32c3.dts @@ -83,7 +83,6 @@ status = "okay"; pinctrl-0 = <&twai_default>; pinctrl-names = "default"; - bus-speed = <125000>; }; &wifi { diff --git a/boards/seeed/xiao_esp32s3/seeed_xiao_connector.dtsi b/boards/seeed/xiao_esp32s3/seeed_xiao_connector.dtsi index 73fe66d28dc..cc2f2f34f14 100644 --- a/boards/seeed/xiao_esp32s3/seeed_xiao_connector.dtsi +++ b/boards/seeed/xiao_esp32s3/seeed_xiao_connector.dtsi @@ -27,3 +27,4 @@ xiao_spi: &spi2 {}; xiao_i2c: &i2c0 {}; xiao_serial: &uart0 {}; +xiao_adc: &adc0 {}; diff --git a/boards/seeed/xiao_esp32s3/xiao_esp32s3_esp32s3_appcpu.dts b/boards/seeed/xiao_esp32s3/xiao_esp32s3_appcpu.dts similarity index 100% rename from boards/seeed/xiao_esp32s3/xiao_esp32s3_esp32s3_appcpu.dts rename to boards/seeed/xiao_esp32s3/xiao_esp32s3_appcpu.dts diff --git a/boards/seeed/xiao_esp32s3/xiao_esp32s3_appcpu.yaml b/boards/seeed/xiao_esp32s3/xiao_esp32s3_appcpu.yaml new file mode 100644 index 00000000000..53055263f34 --- /dev/null +++ b/boards/seeed/xiao_esp32s3/xiao_esp32s3_appcpu.yaml @@ -0,0 +1,27 @@ +identifier: xiao_esp32s3/esp32s3/appcpu +name: XIAO ESP32S3 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: seeed diff --git a/boards/seeed/xiao_esp32s3/xiao_esp32s3_esp32s3_appcpu_defconfig b/boards/seeed/xiao_esp32s3/xiao_esp32s3_appcpu_defconfig similarity index 100% rename from boards/seeed/xiao_esp32s3/xiao_esp32s3_esp32s3_appcpu_defconfig rename to boards/seeed/xiao_esp32s3/xiao_esp32s3_appcpu_defconfig diff --git a/boards/seeed/xiao_esp32s3/xiao_esp32s3_esp32s3_appcpu.yaml b/boards/seeed/xiao_esp32s3/xiao_esp32s3_esp32s3_appcpu.yaml deleted file mode 100644 index 5d66048e038..00000000000 --- a/boards/seeed/xiao_esp32s3/xiao_esp32s3_esp32s3_appcpu.yaml +++ /dev/null @@ -1,27 +0,0 @@ -identifier: xiao_esp32s3/esp32s3/appcpu -name: XIAO ESP32S3 -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: seeed diff --git a/boards/seeed/xiao_esp32s3/xiao_esp32s3_esp32s3_procpu.dts b/boards/seeed/xiao_esp32s3/xiao_esp32s3_esp32s3_procpu.dts deleted file mode 100644 index 99d7f0deb75..00000000000 --- a/boards/seeed/xiao_esp32s3/xiao_esp32s3_esp32s3_procpu.dts +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (c) 2023 Seeed Studio inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/dts-v1/; - -#include -#include "xiao_esp32s3-pinctrl.dtsi" -#include "seeed_xiao_connector.dtsi" - -/ { - model = "Seeed Xiao ESP32S3 PROCPU"; - compatible = "seeed,xiao-esp32s3"; - - chosen { - zephyr,sram = &sram0; - zephyr,console = &usb_serial; - zephyr,shell-uart = &usb_serial; - zephyr,flash = &flash0; - zephyr,code-partition = &slot0_partition; - }; - - aliases { - i2c-0 = &i2c0; - watchdog0 = &wdt0; - led0 = &led0; - }; - - leds { - compatible = "gpio-leds"; - led0: led_0 { - gpios = <&gpio0 21 GPIO_ACTIVE_LOW>; - label = "BUILTIN LED"; - }; - }; - -}; - -&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"; -}; - -&trng0 { - status = "okay"; -}; - -&spi2 { - #address-cells = <1>; - #size-cells = <0>; - status = "okay"; - pinctrl-0 = <&spim2_default>; - pinctrl-names = "default"; -}; - -&gpio0 { - status = "okay"; -}; - -&gpio1 { - status = "okay"; -}; - -&wdt0 { - status = "okay"; -}; - -&twai { - pinctrl-0 = <&twai_default>; - pinctrl-names = "default"; - bus-speed = <125000>; -}; - -&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/seeed/xiao_esp32s3/xiao_esp32s3_esp32s3_procpu.yaml b/boards/seeed/xiao_esp32s3/xiao_esp32s3_esp32s3_procpu.yaml deleted file mode 100644 index 8a1ace79ba6..00000000000 --- a/boards/seeed/xiao_esp32s3/xiao_esp32s3_esp32s3_procpu.yaml +++ /dev/null @@ -1,22 +0,0 @@ -identifier: xiao_esp32s3/esp32s3/procpu -name: XIAO ESP32S3 -type: mcu -arch: xtensa -toolchain: - - zephyr -supported: - - gpio - - uart - - i2c - - spi - - can - - counter - - watchdog - - entropy - - pwm - - dma -testing: - ignore_tags: - - net - - bluetooth -vendor: seeed diff --git a/boards/seeed/xiao_esp32s3/xiao_esp32s3_procpu.dts b/boards/seeed/xiao_esp32s3/xiao_esp32s3_procpu.dts new file mode 100644 index 00000000000..ae232f4d228 --- /dev/null +++ b/boards/seeed/xiao_esp32s3/xiao_esp32s3_procpu.dts @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2023 Seeed Studio inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include "xiao_esp32s3-pinctrl.dtsi" +#include "seeed_xiao_connector.dtsi" + +/ { + model = "Seeed Xiao ESP32S3 PROCPU"; + compatible = "seeed,xiao-esp32s3"; + + chosen { + zephyr,sram = &sram0; + zephyr,console = &usb_serial; + zephyr,shell-uart = &usb_serial; + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; + }; + + aliases { + i2c-0 = &i2c0; + watchdog0 = &wdt0; + led0 = &led0; + }; + + leds { + compatible = "gpio-leds"; + led0: led_0 { + gpios = <&gpio0 21 GPIO_ACTIVE_LOW>; + label = "BUILTIN LED"; + }; + }; + +}; + +&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"; +}; + +&trng0 { + status = "okay"; +}; + +&spi2 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + pinctrl-0 = <&spim2_default>; + pinctrl-names = "default"; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&wdt0 { + status = "okay"; +}; + +&twai { + pinctrl-0 = <&twai_default>; + pinctrl-names = "default"; +}; + +&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/seeed/xiao_esp32s3/xiao_esp32s3_procpu.yaml b/boards/seeed/xiao_esp32s3/xiao_esp32s3_procpu.yaml new file mode 100644 index 00000000000..d438611cb33 --- /dev/null +++ b/boards/seeed/xiao_esp32s3/xiao_esp32s3_procpu.yaml @@ -0,0 +1,22 @@ +identifier: xiao_esp32s3/esp32s3/procpu +name: XIAO ESP32S3 PROCPU +type: mcu +arch: xtensa +toolchain: + - zephyr +supported: + - gpio + - uart + - i2c + - spi + - can + - counter + - watchdog + - entropy + - pwm + - dma +testing: + ignore_tags: + - net + - bluetooth +vendor: seeed diff --git a/boards/seeed/xiao_esp32s3/xiao_esp32s3_esp32s3_procpu_defconfig b/boards/seeed/xiao_esp32s3/xiao_esp32s3_procpu_defconfig similarity index 100% rename from boards/seeed/xiao_esp32s3/xiao_esp32s3_esp32s3_procpu_defconfig rename to boards/seeed/xiao_esp32s3/xiao_esp32s3_procpu_defconfig diff --git a/boards/segger/ip_k66f/doc/index.rst b/boards/segger/ip_k66f/doc/index.rst index 5b4cd7195f0..1d081835cc8 100644 --- a/boards/segger/ip_k66f/doc/index.rst +++ b/boards/segger/ip_k66f/doc/index.rst @@ -62,8 +62,8 @@ The ip_k66f board configuration supports the following hardware features: The default configuration can be found in :zephyr_file:`boards/segger/ip_k66f/ip_k66f_defconfig` -Micrel/Microchip KSZ8794CNX Ethernet Switch is not currently -supported. +Micrel/Microchip KSZ8794CNX Ethernet Switch is supported +(see :zephyr:code-sample:`dsa` sample). Connections and IOs =================== diff --git a/boards/segger/ip_k66f/ip_k66f.dts b/boards/segger/ip_k66f/ip_k66f.dts index 018861f0729..b01ae35f463 100644 --- a/boards/segger/ip_k66f/ip_k66f.dts +++ b/boards/segger/ip_k66f/ip_k66f.dts @@ -103,14 +103,24 @@ }; }; -&enet { +&enet_mac { status = "okay"; pinctrl-0 = <&enet_default>; pinctrl-names = "default"; + zephyr,random-mac-address; + phy-connection-type = "rmii"; + phy-handle = <&phy>; +}; - fixed-link { - speed = <100>; - full-duplex; +&enet_mdio { + status = "okay"; + pinctrl-0 = <&enet_default>; + pinctrl-names = "default"; + phy: phy@0 { + compatible = "ethernet-phy"; + reg = <0>; + status = "okay"; + fixed-link = "100BASE-T Full-Duplex"; }; }; @@ -131,7 +141,7 @@ spi-cpol; spi-cpha; - dsa-master-port = <&enet>; + dsa-master-port = <&enet_mac>; dsa-slave-ports = <3>; lan3: lan_3 { diff --git a/boards/shields/esp_8266/boards/frdm_k64f.overlay b/boards/shields/esp_8266/boards/frdm_k64f.overlay index ea5fa47e8aa..cb0bdc2ad71 100644 --- a/boards/shields/esp_8266/boards/frdm_k64f.overlay +++ b/boards/shields/esp_8266/boards/frdm_k64f.overlay @@ -4,9 +4,15 @@ * SPDX-License-Identifier: Apache-2.0 */ -&enet { - /* ENET MUST be disabled because share - * pins with UART-3 - */ +/* ENET MUST be disabled because share +* pins with UART-3 +*/ +&enet_mac { + status = "disabled"; +}; +&enet_mdio { + status = "disabled"; +}; +&enet_ptp_clock { status = "disabled"; }; diff --git a/boards/shields/mcp2515/adafruit_can_picowbell.overlay b/boards/shields/mcp2515/adafruit_can_picowbell.overlay index 8a9d719e641..9e86a3236d3 100644 --- a/boards/shields/mcp2515/adafruit_can_picowbell.overlay +++ b/boards/shields/mcp2515/adafruit_can_picowbell.overlay @@ -15,7 +15,6 @@ status = "okay"; reg = <0x0>; osc-freq = <16000000>; - bus-speed = <125000>; can-transceiver { max-bitrate = <1000000>; diff --git a/boards/shields/mcp2515/dfrobot_can_bus_v2_0.overlay b/boards/shields/mcp2515/dfrobot_can_bus_v2_0.overlay index e520218830e..290522d8c92 100644 --- a/boards/shields/mcp2515/dfrobot_can_bus_v2_0.overlay +++ b/boards/shields/mcp2515/dfrobot_can_bus_v2_0.overlay @@ -15,7 +15,6 @@ status = "okay"; reg = <0x0>; osc-freq = <16000000>; - bus-speed = <125000>; can-transceiver { min-bitrate = <60000>; diff --git a/boards/shields/mcp2515/keyestudio_can_bus_ks0411.overlay b/boards/shields/mcp2515/keyestudio_can_bus_ks0411.overlay index e4136cf577b..d1f988f281e 100644 --- a/boards/shields/mcp2515/keyestudio_can_bus_ks0411.overlay +++ b/boards/shields/mcp2515/keyestudio_can_bus_ks0411.overlay @@ -15,7 +15,6 @@ status = "okay"; reg = <0x0>; osc-freq = <16000000>; - bus-speed = <125000>; can-transceiver { max-bitrate = <1000000>; diff --git a/boards/shields/mikroe_mcp2518fd_click/mikroe_mcp2518fd_click.overlay b/boards/shields/mikroe_mcp2518fd_click/mikroe_mcp2518fd_click.overlay index 43094d1d72a..522017c81ea 100644 --- a/boards/shields/mikroe_mcp2518fd_click/mikroe_mcp2518fd_click.overlay +++ b/boards/shields/mikroe_mcp2518fd_click/mikroe_mcp2518fd_click.overlay @@ -10,8 +10,6 @@ reg = <0x0>; osc-freq = <40000000>; - bus-speed = <125000>; - bus-speed-data = <1000000>; }; }; diff --git a/boards/shields/mikroe_weather_click/Kconfig.shield b/boards/shields/mikroe_weather_click/Kconfig.shield new file mode 100644 index 00000000000..9c73ce779a2 --- /dev/null +++ b/boards/shields/mikroe_weather_click/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2024 Common Ground Electronics +# SPDX-License-Identifier: Apache-2.0 + +config SHIELD_MIKROE_WEATHER_CLICK + def_bool $(shields_list_contains,mikroe_weather_click) diff --git a/boards/shields/mikroe_weather_click/doc/index.rst b/boards/shields/mikroe_weather_click/doc/index.rst new file mode 100644 index 00000000000..a11f55e6027 --- /dev/null +++ b/boards/shields/mikroe_weather_click/doc/index.rst @@ -0,0 +1,59 @@ +.. _mikroe_weather_click_shield: + +MikroElektronika Weather Click +############################## + +Overview +******** + +The MikroElektronika `Weather Click`_ features the `BME280`_ integrated +environmental sensor in a `mikroBUS`_ |trade| form factor. The sensor can +measure relative humidity, barometric pressure, and ambient temperature. + +.. figure:: weather-click.webp + :align: center + :alt: MikroElektronika Weather Click + + MikroElektronika Weather Click (Credit: MikroElektronika) + +Requirements +************ + +This shield can only be used with a board that provides a mikroBUS |trade| +socket and defines a ``mikrobus_i2c`` node label for the mikroBUS |trade| I2C +interface (see :ref:`shields` for more details). + +For more information about the BME280 and the Weather Click, see the following +documentation: + +- `Weather Click`_ +- `Weather Click Schematic`_ +- `BME280`_ +- `BME280 Datasheet`_ + +Programming +*********** + +Set ``-DSHIELD=mikroe_weather_click`` when you invoke ``west build``. For +example: + +.. zephyr-app-commands:: + :zephyr-app: samples/sensor/bme280 + :board: lpcxpresso55s16 + :shield: mikroe_weather_click + :goals: build + +.. _Weather Click: + https://www.mikroe.com/weather-click + +.. _Weather Click Schematic: + https://download.mikroe.com/documents/add-on-boards/click/weather/weather-click-schematic-v101.pdf + +.. _BME280: + https://www.bosch-sensortec.com/products/environmental-sensors/humidity-sensors-bme280/ + +.. _BME280 Datasheet: + https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bme280-ds002.pdf + +.. _mikroBUS: + https://www.mikroe.com/mikrobus diff --git a/boards/shields/mikroe_weather_click/doc/weather-click.webp b/boards/shields/mikroe_weather_click/doc/weather-click.webp new file mode 100644 index 00000000000..30c5229bf69 Binary files /dev/null and b/boards/shields/mikroe_weather_click/doc/weather-click.webp differ diff --git a/boards/shields/mikroe_weather_click/mikroe_weather_click.overlay b/boards/shields/mikroe_weather_click/mikroe_weather_click.overlay new file mode 100644 index 00000000000..f6a37f2903e --- /dev/null +++ b/boards/shields/mikroe_weather_click/mikroe_weather_click.overlay @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2024 Common Ground Electronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&mikrobus_i2c { + status = "okay"; + + bme280_mikroe_weather_click: bme280@76 { + compatible = "bosch,bme280"; + reg = <0x76>; + }; +}; diff --git a/boards/shields/rk055hdmipi4ma0/boards/mimxrt595_evk_mimxrt595s_cm33.overlay b/boards/shields/rk055hdmipi4ma0/boards/mimxrt595_evk_mimxrt595s_cm33.overlay index 04aba30fec0..bdc2bba1f40 100644 --- a/boards/shields/rk055hdmipi4ma0/boards/mimxrt595_evk_mimxrt595s_cm33.overlay +++ b/boards/shields/rk055hdmipi4ma0/boards/mimxrt595_evk_mimxrt595s_cm33.overlay @@ -13,7 +13,7 @@ }; /* GT911 IRQ GPIO is active low on this board, and needs probing mode */ -&touch_controller_rk055hdmipi4ma0 { +>911_rk055hdmipi4ma0 { irq-gpios = <&nxp_mipi_connector 29 GPIO_ACTIVE_LOW>; alt-addr = <0x14>; }; diff --git a/boards/shields/seeed_xiao_round_display/Kconfig.defconfig b/boards/shields/seeed_xiao_round_display/Kconfig.defconfig new file mode 100644 index 00000000000..81cbf380745 --- /dev/null +++ b/boards/shields/seeed_xiao_round_display/Kconfig.defconfig @@ -0,0 +1,23 @@ +# Copyright (c) 2024 Nicolas Goualard +# SPDX-License-Identifier: Apache-2.0 + +if SHIELD_SEEED_XIAO_ROUND_DISPLAY + +if DISPLAY + +if LVGL + +config INPUT + default y + +choice LV_COLOR_DEPTH + default LV_COLOR_DEPTH_16 +endchoice + +config LV_COLOR_16_SWAP + default y + +endif # LVGL +endif # DISPLAY + +endif # SHIELD_XIAO_ROUND_DISPLAY diff --git a/boards/shields/seeed_xiao_round_display/Kconfig.shield b/boards/shields/seeed_xiao_round_display/Kconfig.shield new file mode 100644 index 00000000000..0d0ed03c59b --- /dev/null +++ b/boards/shields/seeed_xiao_round_display/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2024 Nicolas Goualard +# SPDX-License-Identifier: Apache-2.0 + +config SHIELD_SEEED_XIAO_ROUND_DISPLAY + def_bool $(shields_list_contains,seeed_xiao_round_display) diff --git a/boards/shields/seeed_xiao_round_display/doc/img/seeed_xiao_round_display.webp b/boards/shields/seeed_xiao_round_display/doc/img/seeed_xiao_round_display.webp new file mode 100644 index 00000000000..7da04f4e91b Binary files /dev/null and b/boards/shields/seeed_xiao_round_display/doc/img/seeed_xiao_round_display.webp differ diff --git a/boards/shields/seeed_xiao_round_display/doc/index.rst b/boards/shields/seeed_xiao_round_display/doc/index.rst new file mode 100644 index 00000000000..de079248746 --- /dev/null +++ b/boards/shields/seeed_xiao_round_display/doc/index.rst @@ -0,0 +1,40 @@ +.. _seeed_xiao_round_display: + +Seeed Studio XIAO Round Display +############################### + +Overview +******** + +Seeed Studio Round Display for XIAO is an expansion board compatible with all +XIAO development boards. It features a fully covered touch screen on one side, +designed as a 39mm disc. It contains onboard RTC, charge chip, TF card slot +within its compact size, perfect for interactive displays in smart home, +wearables and more. + +More information can be found on `the Getting Started page`_ + +.. figure:: img/seeed_xiao_round_display.webp + :align: center + :alt: Seeed Studio XIAO Round Display + + Seeed Studio XIAO Round Display (Credit: Seeed Studio) + +Programming +*********** + +Set ``-DSHIELD=seeed_xiao_round_display`` when you invoke ``west build``. + +LVGL Basic Sample +================= + +For example: + +.. zephyr-app-commands:: + :zephyr-app: samples/subsys/display/lvgl + :board: xiao_ble/nrf52840 + :shield: seeed_xiao_round_display + :goals: build + +.. _the Getting Started page: + https://wiki.seeedstudio.com/get_start_round_display/ diff --git a/boards/shields/seeed_xiao_round_display/seeed_xiao_round_display.overlay b/boards/shields/seeed_xiao_round_display/seeed_xiao_round_display.overlay new file mode 100644 index 00000000000..dab060bb604 --- /dev/null +++ b/boards/shields/seeed_xiao_round_display/seeed_xiao_round_display.overlay @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2024, Nicolas Goualard + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + chosen { + zephyr,display = &gc9a01_xiao_round_display; + }; + + vbatt { + compatible = "voltage-divider"; + io-channels = <&xiao_adc 0>; + output-ohms = <470000>; + full-ohms = <940000>; + }; + + lvgl_pointer { + compatible = "zephyr,lvgl-pointer-input"; + input = <&chsc6x_xiao_round_display>; + }; + + aliases { + rtc = &pcf8563_xiao_round_display; + }; +}; + +&xiao_adc { + status = "okay"; +}; + +/* + * xiao_serial uses pins D6 and D7 of the Xiao, which are used respectively to + * control the screen backlight and as touch controller interrupt. + */ +&xiao_serial { + status = "disabled"; +}; + +&xiao_i2c { + clock-frequency = < I2C_BITRATE_FAST >; + + pcf8563_xiao_round_display: pcf8563@51 { + status = "okay"; + compatible = "nxp,pcf8563"; + reg = <0x51>; + }; + + chsc6x_xiao_round_display: chsc6x@2e { + status = "okay"; + compatible = "chipsemi,chsc6x"; + reg = <0x2e>; + irq-gpios = <&xiao_d 7 GPIO_ACTIVE_LOW>; + }; +}; + +&xiao_spi { + status = "okay"; + cs-gpios = <&xiao_d 1 GPIO_ACTIVE_LOW>, <&xiao_d 2 GPIO_ACTIVE_LOW>; + + gc9a01_xiao_round_display: gc9a01@0 { + status = "okay"; + compatible = "galaxycore,gc9x01x"; + reg = <0>; + spi-max-frequency = ; + cmd-data-gpios = <&xiao_d 3 GPIO_ACTIVE_HIGH>; + pixel-format = ; + width = <240>; + height = <240>; + display-inversion; + }; + + sdhc_xiao_round_display: sdhc@1 { + compatible = "zephyr,sdhc-spi-slot"; + reg = <1>; + status = "okay"; + mmc { + compatible = "zephyr,sdmmc-disk"; + status = "okay"; + }; + spi-max-frequency = ; + }; +}; diff --git a/boards/shields/st7735r/st7735r_ada_160x128.overlay b/boards/shields/st7735r/st7735r_ada_160x128.overlay index 42d7cd89060..d769b9a1a4d 100644 --- a/boards/shields/st7735r/st7735r_ada_160x128.overlay +++ b/boards/shields/st7735r/st7735r_ada_160x128.overlay @@ -4,38 +4,48 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include + / { chosen { zephyr,display = &st7735r_st7735r_ada_160x128; }; + + mipi_dbi_st7735r_ada_160x128 { + compatible = "zephyr,mipi-dbi-spi"; + spi-dev = <&arduino_spi>; + dc-gpios = <&arduino_header 15 GPIO_ACTIVE_HIGH>; /* D9 */ + reset-gpios = <&arduino_header 14 GPIO_ACTIVE_LOW>; /* D8 */ + #address-cells = <1>; + #size-cells = <0>; + + st7735r_st7735r_ada_160x128: st7735r@0 { + compatible = "sitronix,st7735r"; + mipi-max-frequency = <20000000>; + mipi-mode = ; + reg = <0>; + width = <160>; + height = <128>; + x-offset = <0>; + y-offset = <0>; + madctl = <0x60>; + colmod = <0x55>; + vmctr1 = <0x0e>; + pwctr1 = [a2 02 84]; + pwctr2 = [c5]; + pwctr3 = [0a 00]; + pwctr4 = [8a 2a]; + pwctr5 = [8a ee]; + frmctr1 = [01 2c 2d]; + frmctr2 = [01 2c 2d]; + frmctr3 = [01 2c 2d 01 2c 2d]; + gamctrp1 = [02 1c 07 12 37 32 29 2d 29 25 2b 39 00 01 03 10]; + gamctrn1 = [03 1d 07 06 2e 2c 29 2d 2e 2e 37 3f 00 00 02 10]; + }; + }; }; &arduino_spi { status = "okay"; cs-gpios = <&arduino_header 16 GPIO_ACTIVE_LOW>; /* D10 */ - - st7735r_st7735r_ada_160x128: st7735r@0 { - compatible = "sitronix,st7735r"; - spi-max-frequency = <20000000>; - reg = <0>; - cmd-data-gpios = <&arduino_header 15 GPIO_ACTIVE_LOW>; /* D9 */ - reset-gpios = <&arduino_header 14 GPIO_ACTIVE_LOW>; /* D8 */ - width = <160>; - height = <128>; - x-offset = <0>; - y-offset = <0>; - madctl = <0x60>; - colmod = <0x55>; - vmctr1 = <0x0e>; - pwctr1 = [a2 02 84]; - pwctr2 = [c5]; - pwctr3 = [0a 00]; - pwctr4 = [8a 2a]; - pwctr5 = [8a ee]; - frmctr1 = [01 2c 2d]; - frmctr2 = [01 2c 2d]; - frmctr3 = [01 2c 2d 01 2c 2d]; - gamctrp1 = [02 1c 07 12 37 32 29 2d 29 25 2b 39 00 01 03 10]; - gamctrn1 = [03 1d 07 06 2e 2c 29 2d 2e 2e 37 3f 00 00 02 10]; - }; }; diff --git a/boards/shields/tcan4550evm/tcan4550evm.overlay b/boards/shields/tcan4550evm/tcan4550evm.overlay index d25d8ff0e62..7aeb3022a9a 100644 --- a/boards/shields/tcan4550evm/tcan4550evm.overlay +++ b/boards/shields/tcan4550evm/tcan4550evm.overlay @@ -28,8 +28,6 @@ reset-gpios = <&arduino_header 14 GPIO_ACTIVE_HIGH>; /* D8 */ int-gpios = <&arduino_header 15 GPIO_ACTIVE_LOW>; /* D9 */ bosch,mram-cfg = <0x0 15 15 7 7 0 10 10>; - bus-speed = <125000>; - bus-speed-data = <1000000>; status = "okay"; can-transceiver { diff --git a/boards/shields/x_nucleo_idb05a1/Kconfig.defconfig b/boards/shields/x_nucleo_idb05a1/Kconfig.defconfig index 430b8a860f7..a5fe2515b50 100644 --- a/boards/shields/x_nucleo_idb05a1/Kconfig.defconfig +++ b/boards/shields/x_nucleo_idb05a1/Kconfig.defconfig @@ -17,7 +17,7 @@ config BT_BLUENRG_ACI # Disable Flow control config BT_HCI_ACL_FLOW_CONTROL default n -config BT_HCI_VS_EXT +config BT_HCI_VS default n endif # BT diff --git a/boards/silabs/efm32gg_sltb009a/efm32gg_sltb009a-pinctrl.dtsi b/boards/silabs/efm32gg_sltb009a/efm32gg_sltb009a-pinctrl.dtsi index 71d20205691..c071820bfc0 100644 --- a/boards/silabs/efm32gg_sltb009a/efm32gg_sltb009a-pinctrl.dtsi +++ b/boards/silabs/efm32gg_sltb009a/efm32gg_sltb009a-pinctrl.dtsi @@ -16,4 +16,22 @@ ; }; }; + + i2c0_default: i2c0_default { + group1 { + psels = , + , + , + ; + }; + }; + + i2c1_default: i2c1_default { + group1 { + psels = , + , + , + ; + }; + }; }; diff --git a/boards/silabs/efm32gg_sltb009a/efm32gg_sltb009a.dts b/boards/silabs/efm32gg_sltb009a/efm32gg_sltb009a.dts index 5dcae30fbee..eac47f56123 100644 --- a/boards/silabs/efm32gg_sltb009a/efm32gg_sltb009a.dts +++ b/boards/silabs/efm32gg_sltb009a/efm32gg_sltb009a.dts @@ -78,14 +78,14 @@ }; &i2c0 { - location-sda = ; - location-scl = ; + pinctrl-0 = <&i2c0_default>; + pinctrl-names = "default"; status = "okay"; }; &i2c1 { - location-sda = ; - location-scl = ; + pinctrl-0 = <&i2c1_default>; + pinctrl-names = "default"; status = "okay"; }; diff --git a/boards/silabs/efm32gg_slwstk6121a/efm32gg_slwstk6121a-pinctrl.dtsi b/boards/silabs/efm32gg_slwstk6121a/efm32gg_slwstk6121a-pinctrl.dtsi index ade31fddfd8..441cfc770cc 100644 --- a/boards/silabs/efm32gg_slwstk6121a/efm32gg_slwstk6121a-pinctrl.dtsi +++ b/boards/silabs/efm32gg_slwstk6121a/efm32gg_slwstk6121a-pinctrl.dtsi @@ -16,4 +16,22 @@ ; }; }; + + i2c0_default: i2c0_default { + group1 { + psels = , + , + , + ; + }; + }; + + i2c1_default: i2c1_default { + group1 { + psels = , + , + , + ; + }; + }; }; diff --git a/boards/silabs/efm32gg_slwstk6121a/efm32gg_slwstk6121a.dts b/boards/silabs/efm32gg_slwstk6121a/efm32gg_slwstk6121a.dts index 10912535b2d..a82fa896722 100644 --- a/boards/silabs/efm32gg_slwstk6121a/efm32gg_slwstk6121a.dts +++ b/boards/silabs/efm32gg_slwstk6121a/efm32gg_slwstk6121a.dts @@ -72,15 +72,15 @@ * to work properly. */ &i2c0 { - location-sda = ; - location-scl = ; + pinctrl-0 = <&i2c0_default>; + pinctrl-names = "default"; status = "okay"; }; /* Connected to Si7021 sensor on WSTK */ &i2c1 { - location-sda = ; - location-scl = ; + pinctrl-0 = <&i2c1_default>; + pinctrl-names = "default"; status = "okay"; }; diff --git a/boards/silabs/efm32gg_stk3701a/efm32gg_stk3701a-pinctrl.dtsi b/boards/silabs/efm32gg_stk3701a/efm32gg_stk3701a-pinctrl.dtsi index 8bb7025f4b2..4540922dd2f 100644 --- a/boards/silabs/efm32gg_stk3701a/efm32gg_stk3701a-pinctrl.dtsi +++ b/boards/silabs/efm32gg_stk3701a/efm32gg_stk3701a-pinctrl.dtsi @@ -25,4 +25,22 @@ ; }; }; + + i2c0_default: i2c0_default { + group1 { + psels = , + , + , + ; + }; + }; + + i2c1_default: i2c1_default { + group1 { + psels = , + , + , + ; + }; + }; }; diff --git a/boards/silabs/efm32gg_stk3701a/efm32gg_stk3701a.dts b/boards/silabs/efm32gg_stk3701a/efm32gg_stk3701a.dts index 1c457890f91..39589b61855 100644 --- a/boards/silabs/efm32gg_stk3701a/efm32gg_stk3701a.dts +++ b/boards/silabs/efm32gg_stk3701a/efm32gg_stk3701a.dts @@ -81,14 +81,14 @@ }; &i2c0 { - location-sda = ; - location-scl = ; + pinctrl-0 = <&i2c0_default>; + pinctrl-names = "default"; status = "okay"; }; &i2c1 { - location-sda = ; - location-scl = ; + pinctrl-0 = <&i2c1_default>; + pinctrl-names = "default"; status = "okay"; }; diff --git a/boards/silabs/efm32pg_stk3401a/efm32pg_stk3401a-pinctrl.dtsi b/boards/silabs/efm32pg_stk3401a/efm32pg_stk3401a-pinctrl.dtsi index 24b51c33612..418fe654bce 100644 --- a/boards/silabs/efm32pg_stk3401a/efm32pg_stk3401a-pinctrl.dtsi +++ b/boards/silabs/efm32pg_stk3401a/efm32pg_stk3401a-pinctrl.dtsi @@ -16,4 +16,13 @@ ; }; }; + + i2c0_default: i2c0_default { + group1 { + psels = , + , + , + ; + }; + }; }; diff --git a/boards/silabs/efm32pg_stk3401a/efm32pg_stk3401a_common.dtsi b/boards/silabs/efm32pg_stk3401a/efm32pg_stk3401a_common.dtsi index 6611bee4956..97427b85817 100644 --- a/boards/silabs/efm32pg_stk3401a/efm32pg_stk3401a_common.dtsi +++ b/boards/silabs/efm32pg_stk3401a/efm32pg_stk3401a_common.dtsi @@ -74,8 +74,8 @@ }; &i2c0 { - location-sda = ; - location-scl = ; + pinctrl-0 = <&i2c0_default>; + pinctrl-names = "default"; status = "okay"; }; diff --git a/boards/silabs/efm32pg_stk3402a/efm32pg_stk3402a-pinctrl.dtsi b/boards/silabs/efm32pg_stk3402a/efm32pg_stk3402a-pinctrl.dtsi index 4fac2b1a8df..b1d39788ba7 100644 --- a/boards/silabs/efm32pg_stk3402a/efm32pg_stk3402a-pinctrl.dtsi +++ b/boards/silabs/efm32pg_stk3402a/efm32pg_stk3402a-pinctrl.dtsi @@ -16,4 +16,13 @@ ; }; }; + + i2c0_default: i2c0_default { + group1 { + psels = , + , + , + ; + }; + }; }; diff --git a/boards/silabs/efm32pg_stk3402a/efm32pg_stk3402a_common.dtsi b/boards/silabs/efm32pg_stk3402a/efm32pg_stk3402a_common.dtsi index 0a2ad797644..05729334fcd 100644 --- a/boards/silabs/efm32pg_stk3402a/efm32pg_stk3402a_common.dtsi +++ b/boards/silabs/efm32pg_stk3402a/efm32pg_stk3402a_common.dtsi @@ -85,8 +85,8 @@ }; &i2c0 { - location-sda = ; - location-scl = ; + pinctrl-0 = <&i2c0_default>; + pinctrl-names = "default"; status = "okay"; }; diff --git a/boards/silabs/efr32_radio/efr32_radio_efr32mg12p432f1024gl125.dts b/boards/silabs/efr32_radio/efr32_radio_efr32mg12p432f1024gl125.dts index 6f1cba19b5c..64b9dce560d 100644 --- a/boards/silabs/efr32_radio/efr32_radio_efr32mg12p432f1024gl125.dts +++ b/boards/silabs/efr32_radio/efr32_radio_efr32mg12p432f1024gl125.dts @@ -6,7 +6,6 @@ /dts-v1/; #include -#include #include "efr32_radio.dtsi" / { @@ -62,9 +61,25 @@ }; }; -&usart0 { - current-speed = <115200>; - pinctrl-0 = <&usart0_default>; +&pinctrl { + i2c0_default: i2c0_default { + group1 { + psels = , + , + , + ; + }; + }; +}; + +&i2c0 { + pinctrl-0 = <&i2c0_default>; pinctrl-names = "default"; status = "okay"; + + si7021: si7021@40 { + compatible = "silabs,si7006"; + reg = <0x40>; + status = "okay"; + }; }; diff --git a/boards/silabs/efr32_radio/efr32_radio_efr32mg12p433f1024gm68.dts b/boards/silabs/efr32_radio/efr32_radio_efr32mg12p433f1024gm68.dts index ed7e2f992a1..effd66a8515 100644 --- a/boards/silabs/efr32_radio/efr32_radio_efr32mg12p433f1024gm68.dts +++ b/boards/silabs/efr32_radio/efr32_radio_efr32mg12p433f1024gm68.dts @@ -6,7 +6,6 @@ /dts-v1/; #include -#include #include "efr32_radio.dtsi" / { @@ -61,10 +60,3 @@ }; }; - -&usart0 { - current-speed = <115200>; - pinctrl-0 = <&usart0_default>; - pinctrl-names = "default"; - status = "okay"; -}; diff --git a/boards/silabs/efr32_thunderboard/thunderboard.dtsi b/boards/silabs/efr32_thunderboard/thunderboard.dtsi index be2401138ad..71979837476 100644 --- a/boards/silabs/efr32_thunderboard/thunderboard.dtsi +++ b/boards/silabs/efr32_thunderboard/thunderboard.dtsi @@ -142,9 +142,20 @@ status = "okay"; }; +&pinctrl { + i2c0_default: i2c0_default { + group1 { + psels = , + , + , + ; + }; + }; +}; + &i2c0 { - location-sda = ; - location-scl = ; + pinctrl-0 = <&i2c0_default>; + pinctrl-names = "default"; status = "okay"; si7210@30 { diff --git a/boards/silabs/efr32mg_sltb004a/efr32mg_sltb004a.dts b/boards/silabs/efr32mg_sltb004a/efr32mg_sltb004a.dts index 6bdc5be574f..3819bd6ca94 100644 --- a/boards/silabs/efr32mg_sltb004a/efr32mg_sltb004a.dts +++ b/boards/silabs/efr32mg_sltb004a/efr32mg_sltb004a.dts @@ -116,16 +116,36 @@ status = "okay"; }; +&pinctrl { + i2c0_default: i2c0_default { + group1 { + psels = , + , + , + ; + }; + }; + + i2c1_default: i2c1_default { + group1 { + psels = , + , + , + ; + }; + }; +}; + &i2c0 { - location-sda = ; - location-scl = ; + pinctrl-0 = <&i2c0_default>; + pinctrl-names = "default"; status = "okay"; }; &i2c1 { /* This set selects for CCS811_I2C supporting CCS811 */ - location-sda = ; - location-scl = ; + pinctrl-0 = <&i2c1_default>; + pinctrl-names = "default"; status = "okay"; ccs811: ccs811@5a { diff --git a/boards/silabs/efr32xg24_dk2601b/efr32xg24_dk2601b.dts b/boards/silabs/efr32xg24_dk2601b/efr32xg24_dk2601b.dts index 2bc6f6253ae..ffa883da6f9 100644 --- a/boards/silabs/efr32xg24_dk2601b/efr32xg24_dk2601b.dts +++ b/boards/silabs/efr32xg24_dk2601b/efr32xg24_dk2601b.dts @@ -27,6 +27,7 @@ led2 = &blue_led; sw0 = &button0; sw1 = &button1; + watchdog0 = &wdog0; }; leds { @@ -79,8 +80,8 @@ }; &i2c0 { - location-sda = ; - location-scl = ; + pinctrl-0 = <&i2c0_default>; + pinctrl-names = "default"; status = "okay"; veml6035: veml6035@29 { @@ -172,3 +173,7 @@ &adc0 { status = "okay"; }; + +&stimer0 { + status = "okay"; +}; diff --git a/boards/silabs/efr32xg24_dk2601b/efr32xg24_dk2601b.yaml b/boards/silabs/efr32xg24_dk2601b/efr32xg24_dk2601b.yaml index 2b803cca1ab..522d945ce5a 100644 --- a/boards/silabs/efr32xg24_dk2601b/efr32xg24_dk2601b.yaml +++ b/boards/silabs/efr32xg24_dk2601b/efr32xg24_dk2601b.yaml @@ -8,8 +8,10 @@ toolchain: - zephyr - gnuarmemb supported: + - counter - gpio - uart + - watchdog testing: ignore_tags: - net diff --git a/boards/sipeed/longan_nano/longan_nano-common.dtsi b/boards/sipeed/longan_nano/longan_nano-common.dtsi index 6d272ddd53d..c5e9202e94f 100644 --- a/boards/sipeed/longan_nano/longan_nano-common.dtsi +++ b/boards/sipeed/longan_nano/longan_nano-common.dtsi @@ -5,6 +5,7 @@ */ #include +#include / { chosen { @@ -65,6 +66,50 @@ sw0 = &button_boot0; watchdog0 = &fwdgt; }; + + mipi_dbi { + compatible = "zephyr,mipi-dbi-spi"; + reset-gpios = <&gpiob 1 GPIO_ACTIVE_LOW>; + dc-gpios = <&gpiob 0 GPIO_ACTIVE_HIGH>; + spi-dev = <&spi0>; + write-only; + #address-cells = <1>; + #size-cells = <0>; + + /* longan nano has LCD with st7735s controller. + * It can use with st7735r driver. + */ + lcd0: lcd@0 { + compatible = "sitronix,st7735r"; + reg = <0>; + status = "okay"; + width = <160>; + height = <80>; + inversion-on; + rgb-is-inverted; + x-offset = <1>; + y-offset = <26>; + pwctr1 = [62 02 04]; + pwctr2 = [C0]; + pwctr3 = [0D 00]; + pwctr4 = [8D 6A]; + pwctr5 = [8D EE]; + invctr = <3>; + frmctr1 = [05 3A 3A]; + frmctr2 = [05 3A 3A]; + frmctr3 = [05 3A 3A 05 3A 3A]; + vmctr1 = <14>; + gamctrp1 = [10 0E 02 03 0E 07 02 07 0A 12 27 37 00 0D 0E 10]; + gamctrn1 = [10 0E 03 03 0F 06 02 08 0A 13 26 36 00 0D 0E 10]; + colmod = <5>; + madctl = <120>; + caset = [00 01 00 a0]; + raset = [00 1a 00 69]; + + mipi-mode = ; + mipi-max-frequency = <4000000>; + }; + }; }; &gpioa { @@ -109,41 +154,6 @@ pinctrl-names = "default"; cs-gpios = <&gpiob 2 GPIO_ACTIVE_LOW>; - - /* longan nano has LCD with st7735s controller. - * It can use with st7735r driver. - */ - lcd0: lcd@0 { - compatible = "sitronix,st7735r"; - reg = <0>; - status = "okay"; - reset-gpios = <&gpiob 1 GPIO_ACTIVE_LOW>; - cmd-data-gpios = <&gpiob 0 GPIO_ACTIVE_LOW>; - width = <160>; - height = <80>; - inversion-on; - rgb-is-inverted; - x-offset = <1>; - y-offset = <26>; - pwctr1 = [62 02 04]; - pwctr2 = [C0]; - pwctr3 = [0D 00]; - pwctr4 = [8D 6A]; - pwctr5 = [8D EE]; - invctr = <3>; - frmctr1 = [05 3A 3A]; - frmctr2 = [05 3A 3A]; - frmctr3 = [05 3A 3A 05 3A 3A]; - vmctr1 = <14>; - gamctrp1 = [10 0E 02 03 0E 07 02 07 0A 12 27 37 00 0D 0E 10]; - gamctrn1 = [10 0E 03 03 0F 06 02 08 0A 13 26 36 00 0D 0E 10]; - colmod = <5>; - madctl = <120>; - caset = [00 01 00 a0]; - raset = [00 1a 00 69]; - - spi-max-frequency = <4000000>; - }; }; &spi1 { diff --git a/boards/snps/em_starterkit/em_starterkit_emsk_em11d_defconfig b/boards/snps/em_starterkit/em_starterkit_emsk_em11d_defconfig new file mode 100644 index 00000000000..38979ec4912 --- /dev/null +++ b/boards/snps/em_starterkit/em_starterkit_emsk_em11d_defconfig @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright (c) 2017 Synopsys + +CONFIG_SYS_CLOCK_TICKS_PER_SEC=100 +CONFIG_XIP=n +CONFIG_BUILD_NO_GAP_FILL=y +CONFIG_BUILD_OUTPUT_BIN=n +CONFIG_ARCV2_INTERRUPT_UNIT=y +CONFIG_ARCV2_TIMER=y +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_UART_INTERRUPT_DRIVEN=y +CONFIG_GPIO=y diff --git a/boards/snps/em_starterkit/em_starterkit_emsk_em7d_2_2.yaml b/boards/snps/em_starterkit/em_starterkit_emsk_em7d_2_2.yaml index 49833304424..29f4404ca95 100644 --- a/boards/snps/em_starterkit/em_starterkit_emsk_em7d_2_2.yaml +++ b/boards/snps/em_starterkit/em_starterkit_emsk_em7d_2_2.yaml @@ -1,5 +1,5 @@ identifier: em_starterkit@2.2/emsk_em7d -name: EM Starterkit EM7D +name: EM Starterkit EM7D (rev. 2.2) type: mcu arch: arc toolchain: diff --git a/boards/snps/hsdk/hsdk_arc_hsdk_2cores_defconfig b/boards/snps/hsdk/hsdk_arc_hsdk_2cores_defconfig index 711d759a8fd..bc0a91f60be 100644 --- a/boards/snps/hsdk/hsdk_arc_hsdk_2cores_defconfig +++ b/boards/snps/hsdk/hsdk_arc_hsdk_2cores_defconfig @@ -9,7 +9,6 @@ CONFIG_ARCV2_TIMER=y CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y CONFIG_SERIAL=y -CONFIG_UART_INTERRUPT_DRIVEN=y -CONFIG_ARC_MPU_ENABLE=y CONFIG_GPIO=y +CONFIG_SMP=y CONFIG_MP_MAX_NUM_CPUS=2 diff --git a/boards/snps/nsim/nsim_nsim_hs_mpuv6_defconfig b/boards/snps/nsim/nsim_nsim_hs_mpuv6_defconfig new file mode 100644 index 00000000000..583bc01b85b --- /dev/null +++ b/boards/snps/nsim/nsim_nsim_hs_mpuv6_defconfig @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SYS_CLOCK_TICKS_PER_SEC=100 +CONFIG_XIP=n +CONFIG_BUILD_OUTPUT_BIN=n +CONFIG_ARCV2_INTERRUPT_UNIT=y +CONFIG_ARCV2_TIMER=y +CONFIG_ARC_MPU_ENABLE=y +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y +CONFIG_SERIAL=y diff --git a/boards/snps/nsim/support/mdb_hs_mpuv6.args b/boards/snps/nsim/support/mdb_hs_mpuv6.args index a47fdf2718b..5f7a5a98e69 100644 --- a/boards/snps/nsim/support/mdb_hs_mpuv6.args +++ b/boards/snps/nsim/support/mdb_hs_mpuv6.args @@ -36,7 +36,7 @@ -dcache_mem_cycles=2 -icache=65536,64,4,a -icache_feature=2 - -dccm_size=0x40000 + -dccm_size=0x100000 -dccm_base=0x80000000 -dccm_mem_cycles=2 -iccm0_size=0x40000 diff --git a/boards/st/b_l4s5i_iot01a/Kconfig.defconfig b/boards/st/b_l4s5i_iot01a/Kconfig.defconfig index 36b722dbf38..0000fc670f3 100644 --- a/boards/st/b_l4s5i_iot01a/Kconfig.defconfig +++ b/boards/st/b_l4s5i_iot01a/Kconfig.defconfig @@ -36,7 +36,7 @@ config BT_BLUENRG_ACI # Disable Flow control config BT_HCI_ACL_FLOW_CONTROL default n -config BT_HCI_VS_EXT +config BT_HCI_VS default n endif # BT diff --git a/boards/st/b_u585i_iot02a/b_u585i_iot02a-common.dtsi b/boards/st/b_u585i_iot02a/b_u585i_iot02a-common.dtsi index 7912aa33deb..97fe4e0be57 100644 --- a/boards/st/b_u585i_iot02a/b_u585i_iot02a-common.dtsi +++ b/boards/st/b_u585i_iot02a/b_u585i_iot02a-common.dtsi @@ -1,5 +1,6 @@ /* * Copyright (c) 2021 Linaro Limited + * Copyright (c) 2024 STMicroelectronics * * SPDX-License-Identifier: Apache-2.0 */ @@ -246,6 +247,12 @@ zephyr_udc0: &usbotg_fs { status = "okay"; }; +&rtc { + clocks = <&rcc STM32_CLOCK_BUS_APB3 0x00200000>, + <&rcc STM32_SRC_LSE RTC_SEL(1)>; + status = "okay"; +}; + &iwdg { status = "okay"; }; diff --git a/boards/st/b_u585i_iot02a/b_u585i_iot02a.yaml b/boards/st/b_u585i_iot02a/b_u585i_iot02a.yaml index 27ba601cae5..ef3e9b0a210 100644 --- a/boards/st/b_u585i_iot02a/b_u585i_iot02a.yaml +++ b/boards/st/b_u585i_iot02a/b_u585i_iot02a.yaml @@ -23,4 +23,5 @@ supported: - pwm - counter - i2c + - rtc vendor: st diff --git a/boards/st/b_u585i_iot02a/board.cmake b/boards/st/b_u585i_iot02a/board.cmake index e09257e941e..73320d749c6 100644 --- a/boards/st/b_u585i_iot02a/board.cmake +++ b/boards/st/b_u585i_iot02a/board.cmake @@ -19,7 +19,10 @@ 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") +board_runner_args(jlink "--device=STM32U585AI" "--reset-after-load") + include(${ZEPHYR_BASE}/boards/common/stm32cubeprogrammer.board.cmake) # FIXME: openocd runner requires use of STMicro openocd fork. # Check board documentation for more details. include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/st/b_u585i_iot02a/doc/index.rst b/boards/st/b_u585i_iot02a/doc/index.rst index 166d2ac3907..0631b5b1ada 100644 --- a/boards/st/b_u585i_iot02a/doc/index.rst +++ b/boards/st/b_u585i_iot02a/doc/index.rst @@ -197,6 +197,8 @@ The Zephyr b_u585i_iot02a board configuration supports the following hardware fe +-----------+------------+-------------------------------------+ | RADIO | STM32WB5MMG| Bluetooth Low Energy (BLE) | +-----------+------------+-------------------------------------+ +| RTC | on-chip | rtc | ++-----------+------------+-------------------------------------+ The default configuration can be found in the defconfig file: :zephyr_file:`boards/st/b_u585i_iot02a/b_u585i_iot02a_defconfig` diff --git a/boards/st/disco_l475_iot1/Kconfig.defconfig b/boards/st/disco_l475_iot1/Kconfig.defconfig index 5679d2caff8..b99f7c57511 100644 --- a/boards/st/disco_l475_iot1/Kconfig.defconfig +++ b/boards/st/disco_l475_iot1/Kconfig.defconfig @@ -36,7 +36,7 @@ config BT_BLUENRG_ACI # Disable Flow control config BT_HCI_ACL_FLOW_CONTROL default n -config BT_HCI_VS_EXT +config BT_HCI_VS default n endif # BT diff --git a/boards/st/disco_l475_iot1/disco_l475_iot1.yaml b/boards/st/disco_l475_iot1/disco_l475_iot1.yaml index ca90da9607a..6600d0724a8 100644 --- a/boards/st/disco_l475_iot1/disco_l475_iot1.yaml +++ b/boards/st/disco_l475_iot1/disco_l475_iot1.yaml @@ -25,6 +25,7 @@ supported: - dac - qspi - dma + - rtc ram: 96 flash: 1024 vendor: st diff --git a/boards/st/disco_l475_iot1/doc/index.rst b/boards/st/disco_l475_iot1/doc/index.rst index dc49d4fcb2d..63ccdd9582e 100644 --- a/boards/st/disco_l475_iot1/doc/index.rst +++ b/boards/st/disco_l475_iot1/doc/index.rst @@ -131,6 +131,8 @@ The Zephyr Disco L475 IoT board configuration supports the following hardware fe +-----------+------------+-------------------------------------+ | die-temp | on-chip | die temperature sensor | +-----------+------------+-------------------------------------+ +| RTC | on-chip | rtc | ++-----------+------------+-------------------------------------+ Other hardware features are not yet supported on this Zephyr port. diff --git a/boards/st/nucleo_c031c6/doc/index.rst b/boards/st/nucleo_c031c6/doc/index.rst index 8ed5a7edfea..8f44ab9d307 100644 --- a/boards/st/nucleo_c031c6/doc/index.rst +++ b/boards/st/nucleo_c031c6/doc/index.rst @@ -90,6 +90,8 @@ The Zephyr nucleo_c031c6 board configuration supports the following hardware fea +-----------+------------+-------------------------------------+ | DMA | on-chip | Direct Memory Access | +-----------+------------+-------------------------------------+ +| RTC | on-chip | rtc | ++-----------+------------+-------------------------------------+ Other hardware features are not yet supported in this Zephyr port. diff --git a/boards/st/nucleo_c031c6/nucleo_c031c6.yaml b/boards/st/nucleo_c031c6/nucleo_c031c6.yaml index c4766287cc5..7f311f93c48 100644 --- a/boards/st/nucleo_c031c6/nucleo_c031c6.yaml +++ b/boards/st/nucleo_c031c6/nucleo_c031c6.yaml @@ -14,6 +14,7 @@ supported: - adc - i2c - dma + - rtc ram: 12 flash: 32 vendor: st diff --git a/boards/st/nucleo_f030r8/nucleo_f030r8_2.yaml b/boards/st/nucleo_f030r8/nucleo_f030r8_2.yaml index 194e1b45199..0cdc0e8ee9d 100644 --- a/boards/st/nucleo_f030r8/nucleo_f030r8_2.yaml +++ b/boards/st/nucleo_f030r8/nucleo_f030r8_2.yaml @@ -1,5 +1,5 @@ identifier: nucleo_f030r8@2 -name: ST Nucleo F030R8 +name: ST Nucleo F030R8 (rev. 2) type: mcu arch: arm toolchain: diff --git a/boards/st/nucleo_f070rb/doc/index.rst b/boards/st/nucleo_f070rb/doc/index.rst index 5e6544e9cfb..e8d9f40a77b 100644 --- a/boards/st/nucleo_f070rb/doc/index.rst +++ b/boards/st/nucleo_f070rb/doc/index.rst @@ -94,6 +94,8 @@ The Zephyr nucleo_f070rb board configuration supports the following hardware fea +-----------+------------+-------------------------------------+ | SPI | on-chip | SPI controller | +-----------+------------+-------------------------------------+ +| RTC | on-chip | rtc | ++-----------+------------+-------------------------------------+ Other hardware features are not yet supported in this Zephyr port. diff --git a/boards/st/nucleo_f070rb/nucleo_f070rb.dts b/boards/st/nucleo_f070rb/nucleo_f070rb.dts index 7cd2e3bd7b6..c504dad4de5 100644 --- a/boards/st/nucleo_f070rb/nucleo_f070rb.dts +++ b/boards/st/nucleo_f070rb/nucleo_f070rb.dts @@ -1,5 +1,6 @@ /* * Copyright (c) 2018 qianfan Zhao + * Copyright (c) 2024 STMicroelectronics * * SPDX-License-Identifier: Apache-2.0 */ @@ -48,6 +49,10 @@ }; }; +&clk_lse { + status = "okay"; +}; + &clk_hse { hse-bypass; clock-frequency = ; /* STLink 8MHz clock */ @@ -121,6 +126,12 @@ status = "okay"; }; +&rtc { + clocks = <&rcc STM32_CLOCK_BUS_APB1 0x10000000>, + <&rcc STM32_SRC_LSE RTC_SEL(1)>; + status = "okay"; +}; + &die_temp { status = "okay"; }; diff --git a/boards/st/nucleo_f070rb/nucleo_f070rb.yaml b/boards/st/nucleo_f070rb/nucleo_f070rb.yaml index 60af06296a9..5ed0d28dd3d 100644 --- a/boards/st/nucleo_f070rb/nucleo_f070rb.yaml +++ b/boards/st/nucleo_f070rb/nucleo_f070rb.yaml @@ -18,6 +18,7 @@ supported: - i2c - spi - watchdog + - rtc testing: ignore_tags: - net diff --git a/boards/st/nucleo_f091rc/doc/index.rst b/boards/st/nucleo_f091rc/doc/index.rst index eee47f79254..a83b00bd82a 100644 --- a/boards/st/nucleo_f091rc/doc/index.rst +++ b/boards/st/nucleo_f091rc/doc/index.rst @@ -108,6 +108,8 @@ The Zephyr nucleo_f091rc board configuration supports the following hardware fea +-----------+------------+-------------------------------------+ | die-temp | on-chip | die temperature sensor | +-----------+------------+-------------------------------------+ +| RTC | on-chip | rtc | ++-----------+------------+-------------------------------------+ Other hardware features are not yet supported in this Zephyr port. diff --git a/boards/st/nucleo_f091rc/nucleo_f091rc.dts b/boards/st/nucleo_f091rc/nucleo_f091rc.dts index b7a94b29e9e..b2443590918 100644 --- a/boards/st/nucleo_f091rc/nucleo_f091rc.dts +++ b/boards/st/nucleo_f091rc/nucleo_f091rc.dts @@ -116,7 +116,6 @@ &can1 { pinctrl-0 = <&can_rx_pa11 &can_tx_pa12>; pinctrl-names = "default"; - bus-speed = <125000>; status = "okay"; }; diff --git a/boards/st/nucleo_f091rc/nucleo_f091rc.yaml b/boards/st/nucleo_f091rc/nucleo_f091rc.yaml index c19aa47d955..d0ac388b263 100644 --- a/boards/st/nucleo_f091rc/nucleo_f091rc.yaml +++ b/boards/st/nucleo_f091rc/nucleo_f091rc.yaml @@ -23,6 +23,7 @@ supported: - dma - pwm - can + - rtc testing: ignore_tags: - net diff --git a/boards/st/nucleo_f103rb/doc/index.rst b/boards/st/nucleo_f103rb/doc/index.rst index 0ff1a60ef85..e2313c5e932 100644 --- a/boards/st/nucleo_f103rb/doc/index.rst +++ b/boards/st/nucleo_f103rb/doc/index.rst @@ -99,8 +99,6 @@ The Zephyr nucleo_f103rb board configuration supports the following hardware fea +-----------+------------+-------------------------------------+ | COUNTER | on-chip | rtc | +-----------+------------+-------------------------------------+ -| RTC | on-chip | rtc | -+-----------+------------+-------------------------------------+ Other hardware features are not yet supported in this Zephyr port. diff --git a/boards/st/nucleo_f207zg/doc/index.rst b/boards/st/nucleo_f207zg/doc/index.rst index a801f0bc1e9..032cf2ab859 100644 --- a/boards/st/nucleo_f207zg/doc/index.rst +++ b/boards/st/nucleo_f207zg/doc/index.rst @@ -108,6 +108,8 @@ The Zephyr nucleo_207zg board configuration supports the following hardware feat +-------------+------------+-------------------------------------+ | die-temp | on-chip | die temperature sensor | +-------------+------------+-------------------------------------+ +| RTC | on-chip | rtc | ++-------------+------------+-------------------------------------+ Other hardware features are not yet supported on this Zephyr port. diff --git a/boards/st/nucleo_f207zg/nucleo_f207zg.yaml b/boards/st/nucleo_f207zg/nucleo_f207zg.yaml index f89510912be..aeb13880f84 100644 --- a/boards/st/nucleo_f207zg/nucleo_f207zg.yaml +++ b/boards/st/nucleo_f207zg/nucleo_f207zg.yaml @@ -24,4 +24,5 @@ supported: - pwm - rng - dma + - rtc vendor: st diff --git a/boards/st/nucleo_f303re/nucleo_f303re.dts b/boards/st/nucleo_f303re/nucleo_f303re.dts index 7259a9f34af..af1bea6d92a 100644 --- a/boards/st/nucleo_f303re/nucleo_f303re.dts +++ b/boards/st/nucleo_f303re/nucleo_f303re.dts @@ -94,7 +94,6 @@ &can1 { pinctrl-0 = <&can_rx_pb8 &can_tx_pb9>; pinctrl-names = "default"; - bus-speed = <125000>; status = "okay"; }; diff --git a/boards/st/nucleo_f401re/doc/index.rst b/boards/st/nucleo_f401re/doc/index.rst index bd806a6378a..4b848eb1017 100644 --- a/boards/st/nucleo_f401re/doc/index.rst +++ b/boards/st/nucleo_f401re/doc/index.rst @@ -87,6 +87,8 @@ The Zephyr nucleo_401re board configuration supports the following hardware feat +-----------+------------+-------------------------------------+ | die-temp | on-chip | die temperature sensor | +-----------+------------+-------------------------------------+ +| RTC | on-chip | rtc | ++-----------+------------+-------------------------------------+ Other hardware features are not yet supported on Zephyr porting. diff --git a/boards/st/nucleo_f401re/nucleo_f401re.yaml b/boards/st/nucleo_f401re/nucleo_f401re.yaml index ea1d89798c0..457c4295196 100644 --- a/boards/st/nucleo_f401re/nucleo_f401re.yaml +++ b/boards/st/nucleo_f401re/nucleo_f401re.yaml @@ -17,6 +17,7 @@ supported: - spi - adc - watchdog + - rtc ram: 96 flash: 512 vendor: st diff --git a/boards/st/nucleo_f429zi/doc/index.rst b/boards/st/nucleo_f429zi/doc/index.rst index 9e795649a4e..c15e524238b 100644 --- a/boards/st/nucleo_f429zi/doc/index.rst +++ b/boards/st/nucleo_f429zi/doc/index.rst @@ -111,6 +111,8 @@ The Zephyr nucleo_f429zi board configuration supports the following hardware fea +-----------+------------+-------------------------------------+ | die-temp | on-chip | die temperature sensor | +-----------+------------+-------------------------------------+ +| RTC | on-chip | rtc | ++-----------+------------+-------------------------------------+ Other hardware features are not yet supported on this Zephyr port. diff --git a/boards/st/nucleo_f429zi/nucleo_f429zi.yaml b/boards/st/nucleo_f429zi/nucleo_f429zi.yaml index 762ede6fb2c..f8c167bc5ef 100644 --- a/boards/st/nucleo_f429zi/nucleo_f429zi.yaml +++ b/boards/st/nucleo_f429zi/nucleo_f429zi.yaml @@ -24,4 +24,5 @@ supported: - dac - dma - nvs + - rtc vendor: st diff --git a/boards/st/nucleo_f446re/nucleo_f446re.dts b/boards/st/nucleo_f446re/nucleo_f446re.dts index 6afc2996acc..3674692ec97 100644 --- a/boards/st/nucleo_f446re/nucleo_f446re.dts +++ b/boards/st/nucleo_f446re/nucleo_f446re.dts @@ -147,14 +147,12 @@ /* CAUTION: PB8 and PB9 may conflict with same pins of I2C1 */ pinctrl-0 = <&can1_rx_pb8 &can1_tx_pb9>; pinctrl-names = "default"; - bus-speed = <125000>; status = "okay"; }; &can2 { pinctrl-0 = <&can2_rx_pb12 &can2_tx_pb13>; pinctrl-names = "default"; - bus-speed = <125000>; status = "okay"; }; diff --git a/boards/st/nucleo_f446ze/nucleo_f446ze.dts b/boards/st/nucleo_f446ze/nucleo_f446ze.dts index d6c7dd4be45..5eaad0ca83d 100644 --- a/boards/st/nucleo_f446ze/nucleo_f446ze.dts +++ b/boards/st/nucleo_f446ze/nucleo_f446ze.dts @@ -180,7 +180,6 @@ zephyr_udc0: &usbotg_fs { &can1 { pinctrl-0 = <&can1_rx_pd0 &can1_tx_pd1>; pinctrl-names = "default"; - bus-speed = <125000>; status = "okay"; }; diff --git a/boards/st/nucleo_f722ze/doc/index.rst b/boards/st/nucleo_f722ze/doc/index.rst index f0c40595f3a..83b54130405 100644 --- a/boards/st/nucleo_f722ze/doc/index.rst +++ b/boards/st/nucleo_f722ze/doc/index.rst @@ -115,6 +115,8 @@ Supported Features +---------------+------------+-------------------------------+ | WWDG | on-chip | watchdog | +---------------+------------+-------------------------------+ +| RTC | on-chip | rtc | ++---------------+------------+-------------------------------+ Connections and IOs =================== diff --git a/boards/st/nucleo_f722ze/nucleo_f722ze.dts b/boards/st/nucleo_f722ze/nucleo_f722ze.dts index 8a128e61e6e..988a1204a9f 100644 --- a/boards/st/nucleo_f722ze/nucleo_f722ze.dts +++ b/boards/st/nucleo_f722ze/nucleo_f722ze.dts @@ -1,5 +1,6 @@ /* * Copyright (c) 2023 Evan Perry Grove + * Copyright (c) 2024 STMicroelectronics * * SPDX-License-Identifier: Apache-2.0 */ @@ -69,6 +70,10 @@ status = "disabled"; }; +&clk_lsi { + status = "okay"; +}; + &pll { div-m = <4>; mul-n = <216>; @@ -118,7 +123,6 @@ &can1 { pinctrl-0 = <&can1_rx_pd0 &can1_tx_pd1>; pinctrl-names = "default"; - bus-speed = <125000>; status = "okay"; }; diff --git a/boards/st/nucleo_f722ze/nucleo_f722ze.yaml b/boards/st/nucleo_f722ze/nucleo_f722ze.yaml index 94cdcb73914..4286f55eca9 100644 --- a/boards/st/nucleo_f722ze/nucleo_f722ze.yaml +++ b/boards/st/nucleo_f722ze/nucleo_f722ze.yaml @@ -20,6 +20,7 @@ supported: - quadspi - spi - usb_device + - rtc ram: 256 flash: 512 vendor: st diff --git a/boards/st/nucleo_f746zg/board.cmake b/boards/st/nucleo_f746zg/board.cmake index 8bbeabfe486..718b783f69d 100644 --- a/boards/st/nucleo_f746zg/board.cmake +++ b/boards/st/nucleo_f746zg/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=STM32F746ZG" "--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/st/nucleo_f746zg/doc/index.rst b/boards/st/nucleo_f746zg/doc/index.rst index cc1ca6d95ed..f0641545170 100644 --- a/boards/st/nucleo_f746zg/doc/index.rst +++ b/boards/st/nucleo_f746zg/doc/index.rst @@ -122,6 +122,8 @@ features: +-------------+------------+-------------------------------------+ | Backup SRAM | on-chip | Backup SRAM | +-------------+------------+-------------------------------------+ +| RTC | on-chip | rtc | ++-------------+------------+-------------------------------------+ Other hardware features are not yet supported on this Zephyr port. @@ -189,6 +191,17 @@ Nucleo F746ZG board includes an ST-LINK/V2-1 embedded debug tool interface. Flashing an application to Nucleo F746ZG ---------------------------------------- +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 + Here is an example for the :ref:`hello_world` application. Run a serial host program to connect with your Nucleo board. @@ -233,3 +246,6 @@ You can debug an application in the usual way. Here is an example for the .. _STM32F746 reference manual: https://www.st.com/resource/en/reference_manual/dm00124865.pdf + +.. _STM32CubeProgrammer: + https://www.st.com/en/development-tools/stm32cubeprog.html diff --git a/boards/st/nucleo_f746zg/nucleo_f746zg.dts b/boards/st/nucleo_f746zg/nucleo_f746zg.dts index db57eb734dc..90c4b4409a0 100644 --- a/boards/st/nucleo_f746zg/nucleo_f746zg.dts +++ b/boards/st/nucleo_f746zg/nucleo_f746zg.dts @@ -166,7 +166,6 @@ zephyr_udc0: &usbotg_fs { &can1 { pinctrl-0 = <&can1_rx_pd0 &can1_tx_pd1>; pinctrl-names = "default"; - bus-speed = <125000>; status = "okay"; }; diff --git a/boards/st/nucleo_f746zg/nucleo_f746zg.yaml b/boards/st/nucleo_f746zg/nucleo_f746zg.yaml index 015b1e3e642..ce8b0322fcd 100644 --- a/boards/st/nucleo_f746zg/nucleo_f746zg.yaml +++ b/boards/st/nucleo_f746zg/nucleo_f746zg.yaml @@ -26,4 +26,5 @@ supported: - dac - dma - backup_sram + - rtc vendor: st diff --git a/boards/st/nucleo_f767zi/doc/index.rst b/boards/st/nucleo_f767zi/doc/index.rst index 8500f7fd3f1..5dec0099d90 100644 --- a/boards/st/nucleo_f767zi/doc/index.rst +++ b/boards/st/nucleo_f767zi/doc/index.rst @@ -122,6 +122,8 @@ features: +-----------+------------+-------------------------------------+ | DAC | on-chip | DAC Controller | +-----------+------------+-------------------------------------+ +| RTC | on-chip | rtc | ++-----------+------------+-------------------------------------+ (*) nucleo_f767zi with soc cut-A (Device marking A) has some ethernet diff --git a/boards/st/nucleo_f767zi/nucleo_f767zi.dts b/boards/st/nucleo_f767zi/nucleo_f767zi.dts index 8ae863248f2..4125f4e6bde 100644 --- a/boards/st/nucleo_f767zi/nucleo_f767zi.dts +++ b/boards/st/nucleo_f767zi/nucleo_f767zi.dts @@ -165,7 +165,6 @@ zephyr_udc0: &usbotg_fs { &can1 { pinctrl-0 = <&can1_rx_pd0 &can1_tx_pd1>; pinctrl-names = "default"; - bus-speed = <125000>; status = "okay"; }; diff --git a/boards/st/nucleo_f767zi/nucleo_f767zi.yaml b/boards/st/nucleo_f767zi/nucleo_f767zi.yaml index e3be20e3780..1ca2d19993f 100644 --- a/boards/st/nucleo_f767zi/nucleo_f767zi.yaml +++ b/boards/st/nucleo_f767zi/nucleo_f767zi.yaml @@ -25,4 +25,5 @@ supported: - counter - can - dac + - rtc vendor: st diff --git a/boards/st/nucleo_g071rb/doc/index.rst b/boards/st/nucleo_g071rb/doc/index.rst index 9cc78b0f4c8..094666250f3 100644 --- a/boards/st/nucleo_g071rb/doc/index.rst +++ b/boards/st/nucleo_g071rb/doc/index.rst @@ -112,6 +112,8 @@ The Zephyr nucleo_g071rb board configuration supports the following hardware fea +-----------+------------+-------------------------------------+ | die-temp | on-chip | die temperature sensor | +-----------+------------+-------------------------------------+ +| RTC | on-chip | rtc | ++-----------+------------+-------------------------------------+ Other hardware features are not yet supported in this Zephyr port. diff --git a/boards/st/nucleo_g071rb/nucleo_g071rb.yaml b/boards/st/nucleo_g071rb/nucleo_g071rb.yaml index 755196fec16..8caf70832cd 100644 --- a/boards/st/nucleo_g071rb/nucleo_g071rb.yaml +++ b/boards/st/nucleo_g071rb/nucleo_g071rb.yaml @@ -25,4 +25,5 @@ supported: - dma - lptim - nvs + - rtc vendor: st diff --git a/boards/st/nucleo_g0b1re/nucleo_g0b1re.dts b/boards/st/nucleo_g0b1re/nucleo_g0b1re.dts index ec79bd3575d..d86d7c6ae8e 100644 --- a/boards/st/nucleo_g0b1re/nucleo_g0b1re.dts +++ b/boards/st/nucleo_g0b1re/nucleo_g0b1re.dts @@ -183,8 +183,6 @@ zephyr_udc0: &usb { <&rcc STM32_SRC_PLL_Q FDCAN_SEL(1)>; pinctrl-0 = <&fdcan1_rx_pa11 &fdcan1_tx_pa12>; pinctrl-names = "default"; - bus-speed = <125000>; - bus-speed-data = <1000000>; status = "okay"; }; @@ -193,8 +191,6 @@ zephyr_udc0: &usb { <&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"; }; diff --git a/boards/st/nucleo_g431rb/nucleo_g431rb.dts b/boards/st/nucleo_g431rb/nucleo_g431rb.dts index 9303087c1dc..8984d9d029d 100644 --- a/boards/st/nucleo_g431rb/nucleo_g431rb.dts +++ b/boards/st/nucleo_g431rb/nucleo_g431rb.dts @@ -20,6 +20,7 @@ zephyr,shell-uart = &lpuart1; zephyr,sram = &sram0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; }; leds: leds { @@ -49,6 +50,7 @@ aliases { led0 = &green_led; + mcuboot-led0 = &green_led; pwm-led0 = &green_pwm_led; sw0 = &user_button; watchdog0 = &iwdg; @@ -167,6 +169,18 @@ stm32_lp_tick_source: &lptim1 { #address-cells = <1>; #size-cells = <1>; + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 DT_SIZE_K(34)>; + }; + slot0_partition: partition@8800 { + label = "image-0"; + reg = <0x00008800 DT_SIZE_K(48)>; + }; + slot1_partition: partition@14800 { + label = "image-1"; + reg = <0x00014800 DT_SIZE_K(42)>; + }; /* Set 4Kb of storage at the end of the 128Kb of flash */ storage_partition: partition@1f000 { label = "storage"; diff --git a/boards/st/nucleo_g474re/doc/index.rst b/boards/st/nucleo_g474re/doc/index.rst index 9d23c072b75..d826ce37188 100644 --- a/boards/st/nucleo_g474re/doc/index.rst +++ b/boards/st/nucleo_g474re/doc/index.rst @@ -129,6 +129,8 @@ The Zephyr nucleo_g474re board configuration supports the following hardware fea +-----------+------------+-------------------------------------+ | FDCAN1 | on-chip | CAN controller | +-----------+------------+-------------------------------------+ +| RTC | on-chip | rtc | ++-----------+------------+-------------------------------------+ Other hardware features are not yet supported on this Zephyr port. diff --git a/boards/st/nucleo_g474re/nucleo_g474re.dts b/boards/st/nucleo_g474re/nucleo_g474re.dts index 8a87f6e0d01..a91ec3ccb60 100644 --- a/boards/st/nucleo_g474re/nucleo_g474re.dts +++ b/boards/st/nucleo_g474re/nucleo_g474re.dts @@ -20,6 +20,7 @@ zephyr,sram = &sram0; zephyr,flash = &flash0; zephyr,canbus = &fdcan1; + zephyr,code-partition = &slot0_partition; }; leds: leds { @@ -49,6 +50,7 @@ aliases { led0 = &green_led; + mcuboot-led0 = &green_led; pwm-led0 = &green_pwm_led; sw0 = &user_button; watchdog0 = &iwdg; @@ -170,6 +172,18 @@ stm32_lp_tick_source: &lptim1 { #address-cells = <1>; #size-cells = <1>; + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 DT_SIZE_K(34)>; + }; + slot0_partition: partition@8800 { + label = "image-0"; + reg = <0x00008800 DT_SIZE_K(240)>; + }; + slot1_partition: partition@44800 { + label = "image-1"; + reg = <0x00044800 DT_SIZE_K(234)>; + }; /* Set 4Kb of storage at the end of the 512Kb of flash */ storage_partition: partition@7f000 { label = "storage"; @@ -209,8 +223,6 @@ stm32_lp_tick_source: &lptim1 { <&rcc STM32_SRC_HSE FDCAN_SEL(0)>; pinctrl-0 = <&fdcan1_rx_pa11 &fdcan1_tx_pa12>; pinctrl-names = "default"; - bus-speed = <125000>; - bus-speed-data = <1000000>; status = "okay"; }; diff --git a/boards/st/nucleo_g474re/nucleo_g474re.yaml b/boards/st/nucleo_g474re/nucleo_g474re.yaml index d473be929bf..26c4254294f 100644 --- a/boards/st/nucleo_g474re/nucleo_g474re.yaml +++ b/boards/st/nucleo_g474re/nucleo_g474re.yaml @@ -24,4 +24,5 @@ supported: - dac - dma - can + - rtc vendor: st diff --git a/boards/st/nucleo_h563zi/nucleo_h563zi.dts b/boards/st/nucleo_h563zi/nucleo_h563zi.dts index 347a9fa9548..915a0ddee60 100644 --- a/boards/st/nucleo_h563zi/nucleo_h563zi.dts +++ b/boards/st/nucleo_h563zi/nucleo_h563zi.dts @@ -40,14 +40,24 @@ &mac { status = "okay"; - pinctrl-0 = <ð_mdc_pc1 - ð_rxd0_pc4 + pinctrl-0 = <ð_rxd0_pc4 ð_rxd1_pc5 ð_ref_clk_pa1 - ð_mdio_pa2 ð_crs_dv_pa7 ð_tx_en_pg11 ð_txd0_pg13 ð_txd1_pb15>; pinctrl-names = "default"; }; + +&mdio { + status = "okay"; + pinctrl-0 = <ð_mdio_pa2 ð_mdc_pc1>; + pinctrl-names = "default"; + + ethernet-phy@0 { + compatible = "ethernet-phy"; + reg = <0x00>; + status = "okay"; + }; +}; diff --git a/boards/st/nucleo_h723zg/doc/index.rst b/boards/st/nucleo_h723zg/doc/index.rst index 0c24a479920..93574531dae 100644 --- a/boards/st/nucleo_h723zg/doc/index.rst +++ b/boards/st/nucleo_h723zg/doc/index.rst @@ -115,6 +115,8 @@ features: +-------------+------------+-------------------------------------+ | Backup SRAM | on-chip | Backup SRAM | +-------------+------------+-------------------------------------+ +| RTC | on-chip | rtc | ++-------------+------------+-------------------------------------+ Other hardware features are not yet supported on this Zephyr port. diff --git a/boards/st/nucleo_h723zg/nucleo_h723zg.dts b/boards/st/nucleo_h723zg/nucleo_h723zg.dts index cb3064b6ef2..8fdd4be9442 100644 --- a/boards/st/nucleo_h723zg/nucleo_h723zg.dts +++ b/boards/st/nucleo_h723zg/nucleo_h723zg.dts @@ -160,9 +160,7 @@ &mac { status = "okay"; pinctrl-0 = <ð_ref_clk_pa1 - ð_mdio_pa2 ð_crs_dv_pa7 - ð_mdc_pc1 ð_rxd0_pc4 ð_rxd1_pc5 ð_tx_en_pg11 @@ -171,6 +169,18 @@ pinctrl-names = "default"; }; +&mdio { + status = "okay"; + pinctrl-0 = <ð_mdio_pa2 ð_mdc_pc1>; + pinctrl-names = "default"; + + phy: ethernet-phy@0 { + compatible = "ethernet-phy"; + reg = <0>; + status = "okay"; + }; +}; + zephyr_udc0: &usbotg_hs { pinctrl-0 = <&usb_otg_hs_dm_pa11 &usb_otg_hs_dp_pa12>; pinctrl-names = "default"; diff --git a/boards/st/nucleo_h723zg/nucleo_h723zg.yaml b/boards/st/nucleo_h723zg/nucleo_h723zg.yaml index 622c268ecea..698fb32a091 100644 --- a/boards/st/nucleo_h723zg/nucleo_h723zg.yaml +++ b/boards/st/nucleo_h723zg/nucleo_h723zg.yaml @@ -21,4 +21,5 @@ supported: - netif:eth - backup_sram - usb_device + - rtc vendor: st diff --git a/boards/st/nucleo_h743zi/doc/index.rst b/boards/st/nucleo_h743zi/doc/index.rst index d5d1ee596b6..66e75e574bb 100644 --- a/boards/st/nucleo_h743zi/doc/index.rst +++ b/boards/st/nucleo_h743zi/doc/index.rst @@ -129,6 +129,8 @@ features: +-------------+------------+-------------------------------------+ | die-temp | on-chip | die temperature sensor | +-------------+------------+-------------------------------------+ +| RTC | on-chip | rtc | ++-------------+------------+-------------------------------------+ Other hardware features are not yet supported on this Zephyr port. diff --git a/boards/st/nucleo_h743zi/nucleo_h743zi.dts b/boards/st/nucleo_h743zi/nucleo_h743zi.dts index ad88d87f059..f410d6f956e 100644 --- a/boards/st/nucleo_h743zi/nucleo_h743zi.dts +++ b/boards/st/nucleo_h743zi/nucleo_h743zi.dts @@ -172,8 +172,6 @@ zephyr_udc0: &usbotg_fs { 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"; }; @@ -187,11 +185,9 @@ zephyr_udc0: &usbotg_fs { */ &mac { status = "okay"; - pinctrl-0 = <ð_mdc_pc1 - ð_rxd0_pc4 + pinctrl-0 = <ð_rxd0_pc4 ð_rxd1_pc5 ð_ref_clk_pa1 - ð_mdio_pa2 ð_crs_dv_pa7 ð_tx_en_pg11 ð_txd0_pg13 @@ -199,6 +195,18 @@ zephyr_udc0: &usbotg_fs { pinctrl-names = "default"; }; +&mdio { + status = "okay"; + pinctrl-0 = <ð_mdio_pa2 ð_mdc_pc1>; + pinctrl-names = "default"; + + ethernet-phy@0 { + compatible = "ethernet-phy"; + reg = <0x00>; + status = "okay"; + }; +}; + &spi1 { status = "okay"; pinctrl-0 = <&spi1_sck_pa5 &spi1_miso_pa6 &spi1_mosi_pb5>; diff --git a/boards/st/nucleo_h743zi/nucleo_h743zi.yaml b/boards/st/nucleo_h743zi/nucleo_h743zi.yaml index e67e8d0e54e..b283964820a 100644 --- a/boards/st/nucleo_h743zi/nucleo_h743zi.yaml +++ b/boards/st/nucleo_h743zi/nucleo_h743zi.yaml @@ -25,4 +25,5 @@ supported: - can - dac - dma + - rtc vendor: st diff --git a/boards/st/nucleo_h745zi_q/nucleo_h745zi_q_stm32h745xx_m7.dts b/boards/st/nucleo_h745zi_q/nucleo_h745zi_q_stm32h745xx_m7.dts index cf22a60ad2a..d3ed100f74a 100644 --- a/boards/st/nucleo_h745zi_q/nucleo_h745zi_q_stm32h745xx_m7.dts +++ b/boards/st/nucleo_h745zi_q/nucleo_h745zi_q_stm32h745xx_m7.dts @@ -107,9 +107,7 @@ &mac { status = "okay"; pinctrl-0 = <ð_ref_clk_pa1 - ð_mdio_pa2 ð_crs_dv_pa7 - ð_mdc_pc1 ð_rxd0_pc4 ð_rxd1_pc5 ð_tx_en_pg11 @@ -118,6 +116,18 @@ pinctrl-names = "default"; }; +&mdio { + status = "okay"; + pinctrl-0 = <ð_mdio_pa2 ð_mdc_pc1>; + pinctrl-names = "default"; + + ethernet-phy@0 { + compatible = "ethernet-phy"; + reg = <0x00>; + status = "okay"; + }; +}; + &rng { status = "okay"; }; diff --git a/boards/st/nucleo_h753zi/nucleo_h753zi.dts b/boards/st/nucleo_h753zi/nucleo_h753zi.dts index 701cf4276f3..e3b52c2b50c 100644 --- a/boards/st/nucleo_h753zi/nucleo_h753zi.dts +++ b/boards/st/nucleo_h753zi/nucleo_h753zi.dts @@ -149,8 +149,6 @@ zephyr_udc0: &usbotg_fs { &fdcan1 { pinctrl-0 = <&fdcan1_rx_pd0 &fdcan1_tx_pd1>; pinctrl-names = "default"; - bus-speed = <125000>; - bus-speed-data = <1000000>; status = "okay"; }; @@ -164,11 +162,9 @@ zephyr_udc0: &usbotg_fs { */ &mac { status = "okay"; - pinctrl-0 = <ð_mdc_pc1 - ð_rxd0_pc4 + pinctrl-0 = <ð_rxd0_pc4 ð_rxd1_pc5 ð_ref_clk_pa1 - ð_mdio_pa2 ð_crs_dv_pa7 ð_tx_en_pg11 ð_txd0_pg13 @@ -176,6 +172,18 @@ zephyr_udc0: &usbotg_fs { pinctrl-names = "default"; }; +&mdio { + status = "okay"; + pinctrl-0 = <ð_mdio_pa2 ð_mdc_pc1>; + pinctrl-names = "default"; + + ethernet-phy@0 { + compatible = "ethernet-phy"; + reg = <0x00>; + status = "okay"; + }; +}; + &spi1 { status = "okay"; pinctrl-0 = <&spi1_sck_pa5 &spi1_miso_pa6 &spi1_mosi_pb5>; diff --git a/boards/st/nucleo_l073rz/doc/index.rst b/boards/st/nucleo_l073rz/doc/index.rst index 4c4ca788ddd..991a3710d08 100644 --- a/boards/st/nucleo_l073rz/doc/index.rst +++ b/boards/st/nucleo_l073rz/doc/index.rst @@ -104,6 +104,8 @@ The Zephyr nucleo_l073rz board configuration supports the following hardware fea +-----------+------------+-------------------------------------+ | die-temp | on-chip | die temperature sensor | +-----------+------------+-------------------------------------+ +| RTC | on-chip | rtc | ++-----------+------------+-------------------------------------+ Other hardware features are not yet supported in this Zephyr port. diff --git a/boards/st/nucleo_l073rz/nucleo_l073rz.dts b/boards/st/nucleo_l073rz/nucleo_l073rz.dts index 93571670b7d..eefd8d428e7 100644 --- a/boards/st/nucleo_l073rz/nucleo_l073rz.dts +++ b/boards/st/nucleo_l073rz/nucleo_l073rz.dts @@ -1,5 +1,6 @@ /* * Copyright (c) 2018 Ilya Tagunov + * Copyright (c) 2024 STMicroelectronics * * SPDX-License-Identifier: Apache-2.0 */ @@ -165,6 +166,12 @@ stm32_lp_tick_source: &lptim1 { }; }; +&rtc { + clocks = <&rcc STM32_CLOCK_BUS_APB1 0x10000000>, + <&rcc STM32_SRC_LSI RTC_SEL(2)>; + status = "okay"; +}; + &rng { status = "okay"; }; diff --git a/boards/st/nucleo_l073rz/nucleo_l073rz.yaml b/boards/st/nucleo_l073rz/nucleo_l073rz.yaml index f97973c4854..2a2ffde92bd 100644 --- a/boards/st/nucleo_l073rz/nucleo_l073rz.yaml +++ b/boards/st/nucleo_l073rz/nucleo_l073rz.yaml @@ -22,4 +22,5 @@ supported: - counter - rng - eeprom + - rtc vendor: st diff --git a/boards/st/nucleo_l152re/doc/index.rst b/boards/st/nucleo_l152re/doc/index.rst index 9d8e31a6a6e..e0e92e5c168 100644 --- a/boards/st/nucleo_l152re/doc/index.rst +++ b/boards/st/nucleo_l152re/doc/index.rst @@ -100,6 +100,8 @@ The Zephyr nucleo_l152re board configuration supports the following hardware fea +-----------+------------+-------------------------------------+ | die-temp | on-chip | die temperature sensor | +-----------+------------+-------------------------------------+ +| RTC | on-chip | rtc | ++-----------+------------+-------------------------------------+ Other hardware features are not yet supported in this Zephyr port. diff --git a/boards/st/nucleo_l152re/nucleo_l152re.yaml b/boards/st/nucleo_l152re/nucleo_l152re.yaml index cc550b993c9..2713e735fa5 100644 --- a/boards/st/nucleo_l152re/nucleo_l152re.yaml +++ b/boards/st/nucleo_l152re/nucleo_l152re.yaml @@ -23,4 +23,5 @@ supported: - pwm - dma - nvs + - rtc vendor: st diff --git a/boards/st/nucleo_l432kc/nucleo_l432kc.dts b/boards/st/nucleo_l432kc/nucleo_l432kc.dts index 370cfe3a0d8..f6a3d568913 100644 --- a/boards/st/nucleo_l432kc/nucleo_l432kc.dts +++ b/boards/st/nucleo_l432kc/nucleo_l432kc.dts @@ -99,7 +99,6 @@ &can1 { pinctrl-0 = <&can1_rx_pa11 &can1_tx_pa12>; pinctrl-names = "default"; - bus-speed = <125000>; status = "okay"; }; diff --git a/boards/st/nucleo_l433rc_p/nucleo_l433rc_p.dts b/boards/st/nucleo_l433rc_p/nucleo_l433rc_p.dts index 3c58b14302d..4e483b55f00 100644 --- a/boards/st/nucleo_l433rc_p/nucleo_l433rc_p.dts +++ b/boards/st/nucleo_l433rc_p/nucleo_l433rc_p.dts @@ -118,7 +118,6 @@ &can1 { pinctrl-0 = <&can1_rx_pa11 &can1_tx_pa12>; pinctrl-names = "default"; - bus-speed = <125000>; status = "okay"; }; diff --git a/boards/st/nucleo_l452re/nucleo_l452re_common.dtsi b/boards/st/nucleo_l452re/nucleo_l452re_common.dtsi index 3da0ae94b99..8f0d76d9a86 100644 --- a/boards/st/nucleo_l452re/nucleo_l452re_common.dtsi +++ b/boards/st/nucleo_l452re/nucleo_l452re_common.dtsi @@ -102,7 +102,6 @@ &can1 { pinctrl-0 = <&can1_rx_pa11 &can1_tx_pa12>; pinctrl-names = "default"; - bus-speed = <125000>; status = "okay"; }; diff --git a/boards/st/nucleo_l4r5zi/doc/index.rst b/boards/st/nucleo_l4r5zi/doc/index.rst index f449c985a83..5fd6156e1ba 100644 --- a/boards/st/nucleo_l4r5zi/doc/index.rst +++ b/boards/st/nucleo_l4r5zi/doc/index.rst @@ -141,6 +141,8 @@ hardware features: +-----------+------------+-------------------------------------+ | ADC | on-chip | adc | +-----------+------------+-------------------------------------+ +| RTC | on-chip | rtc | ++-----------+------------+-------------------------------------+ Other hardware features are not yet supported on this Zephyr port. diff --git a/boards/st/nucleo_l4r5zi/nucleo_l4r5zi.yaml b/boards/st/nucleo_l4r5zi/nucleo_l4r5zi.yaml index ee4115fc1e6..5be0e1f69be 100644 --- a/boards/st/nucleo_l4r5zi/nucleo_l4r5zi.yaml +++ b/boards/st/nucleo_l4r5zi/nucleo_l4r5zi.yaml @@ -18,6 +18,7 @@ supported: - nvs - counter - adc + - rtc ram: 640 flash: 2048 vendor: st diff --git a/boards/st/nucleo_u575zi_q/doc/index.rst b/boards/st/nucleo_u575zi_q/doc/index.rst index 5786fa21b07..d69bbe3f28d 100644 --- a/boards/st/nucleo_u575zi_q/doc/index.rst +++ b/boards/st/nucleo_u575zi_q/doc/index.rst @@ -167,10 +167,14 @@ The Zephyr nucleo_u575zi_q board configuration supports the following hardware f +-----------+------------+-------------------------------------+ | WATCHDOG | on-chip | independent watchdog | +-----------+------------+-------------------------------------+ +| USB FS | on-chip | USB Full Speed device | ++-----------+------------+-------------------------------------+ | BKP SRAM | on-chip | Backup SRAM | +-----------+------------+-------------------------------------+ | RNG | on-chip | True Random number generator | +-----------+------------+-------------------------------------+ +| RTC | on-chip | rtc | ++-----------+------------+-------------------------------------+ Other hardware features are not yet supported on this Zephyr port. diff --git a/boards/st/nucleo_u575zi_q/nucleo_u575zi_q-common.dtsi b/boards/st/nucleo_u575zi_q/nucleo_u575zi_q-common.dtsi index 92e438d03a8..bd8dc8453e0 100644 --- a/boards/st/nucleo_u575zi_q/nucleo_u575zi_q-common.dtsi +++ b/boards/st/nucleo_u575zi_q/nucleo_u575zi_q-common.dtsi @@ -1,5 +1,6 @@ /* * Copyright (c) 2021 Linaro Limited + * Copyright (c) 2024 STMicroelectronics * * SPDX-License-Identifier: Apache-2.0 */ @@ -171,13 +172,23 @@ status = "okay"; }; +zephyr_udc0: &usbotg_fs { + pinctrl-0 = <&usb_otg_fs_dm_pa11 &usb_otg_fs_dp_pa12>; + pinctrl-names = "default"; + status = "okay"; +}; + &fdcan1 { clocks = <&rcc STM32_CLOCK_BUS_APB1_2 0x00000200>, <&rcc STM32_SRC_PLL1_Q FDCAN1_SEL(1)>; pinctrl-0 = <&fdcan1_rx_pd0 &fdcan1_tx_pd1>; pinctrl-names = "default"; - bus-speed = <125000>; - bus-speed-data = <1000000>; + status = "okay"; +}; + +&rtc { + clocks = <&rcc STM32_CLOCK_BUS_APB3 0x00200000>, + <&rcc STM32_SRC_LSE RTC_SEL(1)>; status = "okay"; }; diff --git a/boards/st/nucleo_u575zi_q/nucleo_u575zi_q.yaml b/boards/st/nucleo_u575zi_q/nucleo_u575zi_q.yaml index 0c65b8361ff..a8a38453cb6 100644 --- a/boards/st/nucleo_u575zi_q/nucleo_u575zi_q.yaml +++ b/boards/st/nucleo_u575zi_q/nucleo_u575zi_q.yaml @@ -20,6 +20,7 @@ supported: - watchdog - backup_sram - dma + - rtc ram: 786 flash: 2048 vendor: st diff --git a/boards/st/nucleo_u5a5zj_q/doc/index.rst b/boards/st/nucleo_u5a5zj_q/doc/index.rst index 521997ca266..9245300e816 100644 --- a/boards/st/nucleo_u5a5zj_q/doc/index.rst +++ b/boards/st/nucleo_u5a5zj_q/doc/index.rst @@ -205,6 +205,8 @@ The Zephyr nucleo_u5a5zj_q board configuration supports the following hardware f +-----------+------------+-------------------------------------+ | RNG | on-chip | True Random number generator | +-----------+------------+-------------------------------------+ +| RTC | on-chip | rtc | ++-----------+------------+-------------------------------------+ Other hardware features are not yet supported on this Zephyr port. diff --git a/boards/st/nucleo_u5a5zj_q/nucleo_u5a5zj_q-common.dtsi b/boards/st/nucleo_u5a5zj_q/nucleo_u5a5zj_q-common.dtsi index d0ba893c873..a08d7b47ce2 100644 --- a/boards/st/nucleo_u5a5zj_q/nucleo_u5a5zj_q-common.dtsi +++ b/boards/st/nucleo_u5a5zj_q/nucleo_u5a5zj_q-common.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 STMicroelectronics + * Copyright (c) 2023-2024 STMicroelectronics * * SPDX-License-Identifier: Apache-2.0 */ @@ -175,8 +175,12 @@ <&rcc STM32_SRC_PLL1_Q FDCAN1_SEL(1)>; pinctrl-0 = <&fdcan1_rx_pd0 &fdcan1_tx_pd1>; pinctrl-names = "default"; - bus-speed = <125000>; - bus-speed-data = <1000000>; + status = "okay"; +}; + +&rtc { + clocks = <&rcc STM32_CLOCK_BUS_APB3 0x00200000>, + <&rcc STM32_SRC_LSE RTC_SEL(1)>; status = "okay"; }; diff --git a/boards/st/nucleo_u5a5zj_q/nucleo_u5a5zj_q.yaml b/boards/st/nucleo_u5a5zj_q/nucleo_u5a5zj_q.yaml index 4d74f6a13b8..cd937080414 100644 --- a/boards/st/nucleo_u5a5zj_q/nucleo_u5a5zj_q.yaml +++ b/boards/st/nucleo_u5a5zj_q/nucleo_u5a5zj_q.yaml @@ -20,5 +20,6 @@ supported: - watchdog - backup_sram - dma + - rtc ram: 2450 flash: 4096 diff --git a/boards/st/nucleo_wb55rg/doc/nucleo_wb55rg.rst b/boards/st/nucleo_wb55rg/doc/nucleo_wb55rg.rst index 04bdc9d45ec..6be25936050 100644 --- a/boards/st/nucleo_wb55rg/doc/nucleo_wb55rg.rst +++ b/boards/st/nucleo_wb55rg/doc/nucleo_wb55rg.rst @@ -173,6 +173,8 @@ The Zephyr nucleo_wb55rg board configuration supports the following hardware fea +-----------+------------+-------------------------------------+ | die-temp | on-chip | die temperature sensor | +-----------+------------+-------------------------------------+ +| RTC | on-chip | rtc | ++-----------+------------+-------------------------------------+ Other hardware features are not yet supported on this Zephyr port. diff --git a/boards/st/nucleo_wb55rg/nucleo_wb55rg.yaml b/boards/st/nucleo_wb55rg/nucleo_wb55rg.yaml index f455356048c..a2b42575b1b 100644 --- a/boards/st/nucleo_wb55rg/nucleo_wb55rg.yaml +++ b/boards/st/nucleo_wb55rg/nucleo_wb55rg.yaml @@ -22,4 +22,5 @@ supported: - arduino_spi - usb_device - nvs + - rtc vendor: st diff --git a/boards/st/nucleo_wba55cg/doc/nucleo_wba55cg.rst b/boards/st/nucleo_wba55cg/doc/nucleo_wba55cg.rst index 2423d6bc36a..70b08b6b056 100644 --- a/boards/st/nucleo_wba55cg/doc/nucleo_wba55cg.rst +++ b/boards/st/nucleo_wba55cg/doc/nucleo_wba55cg.rst @@ -177,6 +177,8 @@ The Zephyr nucleo_wba55cg board configuration supports the following hardware fe +-----------+------------+-------------------------------------+ | RADIO | on-chip | Bluetooth Low Energy | +-----------+------------+-------------------------------------+ +| RTC | on-chip | rtc | ++-----------+------------+-------------------------------------+ Other hardware features are not yet supported on this Zephyr port. diff --git a/boards/st/nucleo_wba55cg/nucleo_wba55cg.dts b/boards/st/nucleo_wba55cg/nucleo_wba55cg.dts index 88dd4083209..f3ba9c494e2 100644 --- a/boards/st/nucleo_wba55cg/nucleo_wba55cg.dts +++ b/boards/st/nucleo_wba55cg/nucleo_wba55cg.dts @@ -19,6 +19,7 @@ #size-cells = <1>; chosen { + zephyr,bt-c2h-uart = &usart1; zephyr,console = &usart1; zephyr,shell-uart = &usart1; zephyr,sram = &sram0; @@ -28,24 +29,48 @@ leds: leds { compatible = "gpio-leds"; - blue_led_1: led_1 { + blue_led_1: led_0 { gpios = <&gpiob 4 GPIO_ACTIVE_LOW>; label = "User LD1"; }; + green_led_2: led_1 { + gpios = <&gpioa 9 GPIO_ACTIVE_LOW>; + label = "User LD2"; + }; + red_led_3: led_2 { + gpios = <&gpiob 8 GPIO_ACTIVE_LOW>; + label = "User LD3"; + }; }; gpio_keys { compatible = "gpio-keys"; - user_button: button { - label = "User"; - gpios = <&gpioc 13 GPIO_ACTIVE_LOW>; + user_button_1: button_0 { + label = "User B1"; + gpios = <&gpioc 13 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; zephyr,code = ; }; + user_button_2: button_1 { + label = "User B2"; + gpios = <&gpiob 6 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + zephyr,code = ; + }; + user_button_3: button_2 { + label = "User B3"; + gpios = <&gpiob 7 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + zephyr,code = ; + }; }; aliases { led0 = &blue_led_1; - sw0 = &user_button; + led1 = &green_led_2; + led2 = &red_led_3; + sw0 = &user_button_1; + sw1 = &user_button_2; + sw2 = &user_button_3; + mcuboot-led0 = &blue_led_1; + mcuboot-button0 = &user_button_1; }; }; diff --git a/boards/st/nucleo_wba55cg/nucleo_wba55cg.yaml b/boards/st/nucleo_wba55cg/nucleo_wba55cg.yaml index 0f435e29c75..947549a697c 100644 --- a/boards/st/nucleo_wba55cg/nucleo_wba55cg.yaml +++ b/boards/st/nucleo_wba55cg/nucleo_wba55cg.yaml @@ -16,6 +16,7 @@ supported: - arduino_i2c - arduino_spi - counter + - rtc ram: 128 flash: 1024 vendor: st diff --git a/boards/st/nucleo_wl55jc/doc/nucleo_wl55jc.rst b/boards/st/nucleo_wl55jc/doc/nucleo_wl55jc.rst index df32bbc07c0..50f7c63d9e0 100644 --- a/boards/st/nucleo_wl55jc/doc/nucleo_wl55jc.rst +++ b/boards/st/nucleo_wl55jc/doc/nucleo_wl55jc.rst @@ -208,6 +208,8 @@ features: +-----------+------------+-------------------------------------+ | die-temp | on-chip | die temperature sensor | +-----------+------------+-------------------------------------+ +| RTC | on-chip | rtc | ++-----------+------------+-------------------------------------+ Other hardware features are not yet supported on this Zephyr port. diff --git a/boards/st/nucleo_wl55jc/nucleo_wl55jc.dts b/boards/st/nucleo_wl55jc/nucleo_wl55jc.dts index e83f45452dd..6e37b1c1485 100644 --- a/boards/st/nucleo_wl55jc/nucleo_wl55jc.dts +++ b/boards/st/nucleo_wl55jc/nucleo_wl55jc.dts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 STMicroelectronics + * Copyright (c) 2020-2024 STMicroelectronics * * SPDX-License-Identifier: Apache-2.0 */ @@ -85,6 +85,10 @@ stm32_lp_tick_source: &lptim1 { status = "okay"; }; +&clk_lse { + status = "okay"; +}; + &pll { div-m = <1>; mul-n = <6>; @@ -216,6 +220,12 @@ stm32_lp_tick_source: &lptim1 { }; }; +&rtc { + clocks = <&rcc STM32_CLOCK_BUS_APB1 0x00000400>, + <&rcc STM32_SRC_LSE RTC_SEL(1)>; + status = "okay"; +}; + &vref { status = "okay"; }; diff --git a/boards/st/nucleo_wl55jc/nucleo_wl55jc.yaml b/boards/st/nucleo_wl55jc/nucleo_wl55jc.yaml index b741d372805..4eb53ef3324 100644 --- a/boards/st/nucleo_wl55jc/nucleo_wl55jc.yaml +++ b/boards/st/nucleo_wl55jc/nucleo_wl55jc.yaml @@ -23,4 +23,5 @@ supported: - watchdog - nvs - lora + - rtc vendor: st diff --git a/boards/st/sensortile_box/Kconfig.defconfig b/boards/st/sensortile_box/Kconfig.defconfig index 29aa7598ef8..8e3f0bb1670 100644 --- a/boards/st/sensortile_box/Kconfig.defconfig +++ b/boards/st/sensortile_box/Kconfig.defconfig @@ -19,7 +19,7 @@ config BT_BLUENRG_ACI # Disable Flow control config BT_HCI_ACL_FLOW_CONTROL default n -config BT_HCI_VS_EXT +config BT_HCI_VS default n endif # BT diff --git a/boards/st/sensortile_box_pro/board.c b/boards/st/sensortile_box_pro/board.c index b66edf23be4..c19d0abe3da 100644 --- a/boards/st/sensortile_box_pro/board.c +++ b/boards/st/sensortile_box_pro/board.c @@ -20,11 +20,10 @@ 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; + if (!device_is_ready(dev)) { + return -ENODEV; } - - return 0; + return usb_enable(NULL); } /* needs to be done at Application */ diff --git a/boards/st/steval_stwinbx1/CMakeLists.txt b/boards/st/steval_stwinbx1/CMakeLists.txt new file mode 100644 index 00000000000..f2a184ea87f --- /dev/null +++ b/boards/st/steval_stwinbx1/CMakeLists.txt @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library_sources(board.c) diff --git a/boards/st/steval_stwinbx1/Kconfig.defconfig b/boards/st/steval_stwinbx1/Kconfig.defconfig new file mode 100644 index 00000000000..be9fa9523a5 --- /dev/null +++ b/boards/st/steval_stwinbx1/Kconfig.defconfig @@ -0,0 +1,21 @@ +# STEVAL_STWINBX1 Development kit board configuration + +# Copyright (c) 2024 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_STEVAL_STWINBX1 + +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_STEVAL_STWINBX1 diff --git a/boards/st/steval_stwinbx1/Kconfig.steval_stwinbx1 b/boards/st/steval_stwinbx1/Kconfig.steval_stwinbx1 new file mode 100644 index 00000000000..aae01c61ac7 --- /dev/null +++ b/boards/st/steval_stwinbx1/Kconfig.steval_stwinbx1 @@ -0,0 +1,5 @@ +# Copyright (c) 2024 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_STEVAL_STWINBX1 + select SOC_STM32U585XX diff --git a/boards/st/steval_stwinbx1/board.c b/boards/st/steval_stwinbx1/board.c new file mode 100644 index 00000000000..1d98da4aba0 --- /dev/null +++ b/boards/st/steval_stwinbx1/board.c @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_CONSOLE) && defined(CONFIG_UART_CONSOLE) +#if DT_NODE_HAS_COMPAT(DT_CHOSEN(zephyr_console), zephyr_cdc_acm_uart) +/* + * Enable console on USB CDC_ACM + */ +static int steval_stwinbx1_usb_console_init(void) +{ + const struct device *const dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_console)); + + if (!device_is_ready(dev)) { + return -ENODEV; + } + return (usb_enable(NULL)); +} + +/* needs to be done at Application */ +SYS_INIT(steval_stwinbx1_usb_console_init, APPLICATION, + CONFIG_KERNEL_INIT_PRIORITY_DEVICE); +#endif /* DT_NODE_HAS_COMPAT(DT_CHOSEN(zephyr_console), zephyr_cdc_acm_uart) */ +#endif /* defined(CONFIG_CONSOLE) && defined (CONFIG_UART_CONSOLE) */ diff --git a/boards/st/steval_stwinbx1/board.cmake b/boards/st/steval_stwinbx1/board.cmake new file mode 100644 index 00000000000..7b41b6115ca --- /dev/null +++ b/boards/st/steval_stwinbx1/board.cmake @@ -0,0 +1,18 @@ +# Copyright (c) 2024 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +# By default stm32cubeprogrammer configured to use DFU upload method. +# Comment below line and uncomment the second line to use SWD upoad method. +board_runner_args(stm32cubeprogrammer "--port=usb1") +# board_runner_args(stm32cubeprogrammer "--port=swd" "--reset-mode=hw") + +# Even if flash and start work, dfu-util return error 74. It can be ignored. +board_runner_args(dfu-util "--pid=0483:df11" "--alt=0" "--dfuse") + +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/dfu-util.board.cmake) +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) diff --git a/boards/st/steval_stwinbx1/board.yml b/boards/st/steval_stwinbx1/board.yml new file mode 100644 index 00000000000..64319223253 --- /dev/null +++ b/boards/st/steval_stwinbx1/board.yml @@ -0,0 +1,5 @@ +board: + name: steval_stwinbx1 + vendor: st + socs: + - name: stm32u585xx diff --git a/boards/st/steval_stwinbx1/doc/img/steval_stwinbx1.jpg b/boards/st/steval_stwinbx1/doc/img/steval_stwinbx1.jpg new file mode 100644 index 00000000000..ed0b01c8158 Binary files /dev/null and b/boards/st/steval_stwinbx1/doc/img/steval_stwinbx1.jpg differ diff --git a/boards/st/steval_stwinbx1/doc/index.rst b/boards/st/steval_stwinbx1/doc/index.rst new file mode 100644 index 00000000000..367de5d4373 --- /dev/null +++ b/boards/st/steval_stwinbx1/doc/index.rst @@ -0,0 +1,442 @@ +.. _steval_stwinbx1_board: + +STEVAL STWINBX1 Development kit +############################### + +Overview +******** + +The STWIN.box (STEVAL-STWINBX1) is a development kit that features an Arm|reg| Cortex|reg|-M33 based STM32U585AI MCU +and is a reference design that simplifies prototyping and testing of advanced industrial sensing applications in +IoT contexts such as condition monitoring and predictive maintenance. + +The STEVAL-STWINBX1 kit consists of an STWIN.box core system, a 480mAh LiPo battery, an adapter for the ST-LINK debugger, +a plastic case, an adapter board for DIL 24 sensors and a flexible cable. + +.. image:: img/steval_stwinbx1.jpg + :align: center + :alt: STEVAL-STWINBX1 Development kit + +More information about the board can be found at the `STEVAL-STWINBX1 Development kit website`_. + + +Supported Features +****************** + +The STEVAL-STWINBX1 provides motion, environmental, and audio +sensor data through either the built-in RS485 transceiver, BLE, Wi-Fi, and +NFC or USB protocols to a host application running on a smartphone/PC to implement applications such as: + +- Multisensing wireless platform for vibration monitoring and ultrasound detection +- Baby crying detection with Cloud AI learning +- Barometer / environmental monitoring +- Vehicle / goods tracking +- Vibration monitoring +- Compass and inclinometer +- Sensor data logger + +(see `Sensing`_ 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`_ + +Connectivity +************ + + - **BlueNRG-M2SA** Bluetooth|reg| low energy v5.2 wireless technology module + (`BlueNRG-M2 datasheet`_) + - **MXCHIP EMW3080** (802.11 b/g/n compliant Wi-Fi module) + - **ST25DV64K** dynamic NFC/RFID tag IC with 64-Kbit EEPROM + (`st25dv64k datasheet`_) + - USB Type-C|trade| connector (power supply and data) + - STDC14 programming connector for **STLINK-V3MINI** + (`stlink-v3mini`_) + - microSD card socket + +Sensing +******* + + - **ILPS22QS** MEMS pressure sensor + (`ilps22qs datasheet`_) + - **STTS22H** Digital temperature sensor + (`stts22hh datasheet`_) + - **TSV912** wide-bandwidth (8 MHz) rail-to-rail I/O op-amp + (`tsv912 datasheet`_) + - **ISM330DHCX** iNEMO IMU, 3D accelerometer and 3D gyroscope with Machine Learning Core and Finite State Machine + (`ism330dhcx datasheet`_) + - **IIS3DWB** wide bandwidth accelerometer + (`iis3dwb datasheet`_) + - **IIS2DLPC** high-performance ultra-low-power 3-axis accelerometer for industrial applications + (`iis2dlpc datasheet`_) + - **IIS2MDC** 3-axis magnetometer + (`iis2mdc datasheet`_) + - **IIS2ICLX** high-accuracy, high-resolution, low-power, 2-axis digital inclinometer with Machine Learning Core + (`iis2iclx datasheet`_) + - **IMP23ABSU** analog MEMS microphone + (`imp23absu datasheet`_) + - **IMP34DT05** digital MEMS microphone + (`imp34dt05 datasheet`_) + +Connections and IOs +******************* + +- 2x user LEDs + + - **led0** (Green) + - **led1** (Orange) + +- 4x buttons/switch + + - **User** / **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) + - **RESET** button, used to reset the board + - **PWR** button, used to Power on/off the board + + +For more details please refer to `STEVAL-STWINBX1 board User Manual`_. + +System Clock +------------ + +STEVAL-STWINBX1 System Clock could be driven by an internal or external oscillator, +as well as the main PLL clock. By default the System clock is driven by the PLL clock at 160MHz, +driven by 16MHz high speed external oscillator. +The internal AHB/APB1/APB2/APB3 AMBA buses are all clocked at 160MHz. + +Serial Port +----------- + +The USART2 is connected to JTAG/SWD connector +and may be used as console. + +USB interface +------------- + +STEVAL-STWINBX1 can be connected as a USB device to a PC host through its USB-C connector. +The final application may use it to declare STEVAL-STWINBX1 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 USART2 which is available on SWD connector (CN4). In this case a JTAG adapter + can be used to connect STEVAL-STWINBX1 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/st/steval_stwinbx1/steval_stwinbx1.dts`) + + - comment out the USB configuration macros + (:file:`boards/st/steval_stwinbx1/steval_stwinbx1_defconfig`) + +.. code-block:: dts + :caption: boards/st/steval_stwinbx1/steval_stwinbx1.dts + + / { + chosen { + zephyr,console = &usart2; + zephyr,shell-uart = &usart2; + //zephyr,console = &cdc_acm_uart0; + //zephyr,shell-uart = &cdc_acm_uart0; + }; + }; + +.. code-block:: Kconfig + :caption: boards/st/steval_stwinbx1/steval_stwinbx1_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=0x5740 + #CONFIG_USB_DEVICE_PRODUCT="Zephyr CDC STEval-STWinbx1" + #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/st/steval_stwinbx1/steval_stwinbx1.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 USER (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 + + The STEVAL-STWINBX1 does not include a on-board debug probe. + It requires to connect additional hardware, like a ST-LINK/V3 + embedded debug tool, to the board STDC14 connector (CN4) labeled ``MCU-/SWD``. + + +Install dfu-util +---------------- + +.. note:: + Required only to use dfu-util runner. + +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`_ + +Install STM32CubeProgrammer +--------------------------- + +.. note:: + Required to program over DFU (default) or SWD. + +It is recommended to use the latest version of `STM32CubeProgrammer`_ + + +Flash an Application to STEVAL-STWINBX1 +------------------------------------------ + +There are two ways to enter DFU mode: + +1. USB-C cable not connected + + While pressing the USER button, connect the USB-C cable to the USB OTG STEVAL-STWINBX1 + port and to your computer. + +2. USB-C cable connected + + While pressing the USER button, press the RESET button and release it. + +With both methods, 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=0200, devnum=58, cfg=1, intf=0, path="3-1", alt=2, name="@OTP Memory /0x0BFA0000/01*512 e", serial="207136863530" + Found DFU: [0483:df11] ver=0200, devnum=58, cfg=1, intf=0, path="3-1", alt=1, name="@Option Bytes /0x40022040/01*64 e", serial="207136863530" + Found DFU: [0483:df11] ver=0200, devnum=58, cfg=1, intf=0, path="3-1", alt=0, name="@Internal Flash /0x08000000/256*08Kg", serial="207136863530" + +You should see the following confirmation on your Linux host: + +.. code-block:: console + + $ dmesg + usb 3-1: new full-speed USB device number 16 using xhci_hcd + usb 3-1: New USB device found, idVendor=0483, idProduct=df11, bcdDevice= 2.00 + usb 3-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3 + usb 3-1: Product: DFU in FS Mode + usb 3-1: Manufacturer: STMicroelectronics + usb 3-1: SerialNumber: 207136863530 + +.. 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. + + +.. _STEVAL-STWINBX1 Development kit website: + https://www.st.com/en/evaluation-tools/steval-stwinbx1.html + +.. _STEVAL-STWINBX1 board User Manual: + https://www.st.com/resource/en/user_manual/um2965-getting-started-with-the-stevalstwinbx1-sensortile-wireless-industrial-node-development-kit-stmicroelectronics.pdf + +.. _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 + +.. _STM32CubeProgrammer: + https://www.st.com/en/development-tools/stm32cubeprog.html + +.. _DFU-UTIL website: + http://dfu-util.sourceforge.net/ + +.. _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 + +.. _BlueNRG-M2 datasheet: + https://www.st.com/en/product/BlueNRG-M2 + +.. _st25dv64k datasheet: + https://www.st.com/en/nfc/st25dv64k.html + +.. _stlink-v3mini: + https://www.st.com/en/development-tools/stlink-v3mini.html + +.. _ilps22qs datasheet: + https://www.st.com/en/mems-and-sensors/ilps22qs.html + +.. _stts22hh datasheet: + https://www.st.com/en/mems-and-sensors/stts22h.html + +.. _tsv912 datasheet: + https://www.st.com/en/automotive-analog-and-power/tsv912.html + +.. _ism330dhcx datasheet: + https://www.st.com/en/mems-and-sensors/ism330dhcx.html + +.. _iis3dwb datasheet: + https://www.st.com/en/mems-and-sensors/iis3dwb.html + +.. _iis2dlpc datasheet: + https://www.st.com/en/mems-and-sensors/iis2dlpc.html + +.. _iis2mdc datasheet: + https://www.st.com/en/mems-and-sensors/iis2mdc.html + +.. _iis2iclx datasheet: + https://www.st.com/en/mems-and-sensors/iis2iclx.html + +.. _imp23absu datasheet: + https://www.st.com/en/mems-and-sensors/imp23absu.html + +.. _imp34dt05 datasheet: + https://www.st.com/en/mems-and-sensors/imp34dt05.html diff --git a/boards/st/steval_stwinbx1/steval_stwinbx1.dts b/boards/st/steval_stwinbx1/steval_stwinbx1.dts new file mode 100644 index 00000000000..d84b9fae9cd --- /dev/null +++ b/boards/st/steval_stwinbx1/steval_stwinbx1.dts @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + #include + #include + #include + +/ { + model = "STMicroelectronics STEVAL-STWINBX1 Development kit"; + compatible = "st,steval_stwinbx1"; + + chosen { + /* + * By default, Zephyr console and shell are assigned to + * USB CDC/ACM. To enable console and shell over UART, + * uncomment the 2 following lines and set the correct + * config in steval_stwinbx1_defconfig. + */ + /* zephyr,console = &usart2; */ + /* zephyr,shell-uart = &usart2; */ + /* + * To enable console and shell over UART, + * comment the 2 following lines + */ + 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: led_1 { + gpios = <&gpioh 12 GPIO_ACTIVE_HIGH>; + label = "LED_1"; + }; + orange_led: led_2 { + gpios = <&gpioh 10 GPIO_ACTIVE_HIGH>; + label = "LED_2"; + }; + }; + + pwmleds { + compatible = "pwm-leds"; + + green_pwm_led: green_pwm_led { + pwms = <&pwm5 3 PWM_MSEC(20) PWM_POLARITY_NORMAL>; + label = "LED_1 - PWM5"; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + user_button: button { + label = "User"; + gpios = <&gpioe 0 GPIO_ACTIVE_HIGH>; + zephyr,code = ; + }; + }; + + aliases { + led0 = &green_led; + led1 = &orange_led; + pwm-led0 = &green_pwm_led; + sw0 = &user_button; + mcuboot-led0 = &green_led; + mcuboot-button0 = &user_button; + watchdog0 = &iwdg; + die-temp0 = &die_temp; + volt-sensor0 = &vref1; + volt-sensor1 = &vbat4; + }; +}; + +&clk_hsi48 { + status = "okay"; +}; + +&clk_hse { + clock-frequency = ; + status = "okay"; +}; + +&clk_lse { + status = "okay"; +}; + +&clk_msis { + status = "okay"; + msi-range = <4>; + msi-pll-mode; +}; + +&pll1 { + div-m = <1>; + mul-n = <10>; + div-q = <2>; + div-r = <1>; + clocks = <&clk_hse>; + status = "okay"; +}; + +&pll2 { + div-m = <2>; + mul-n = <48>; + div-p = <2>; + div-q = <7>; + div-r = <25>; + clocks = <&clk_hse>; + status = "okay"; +}; + +&pll3 { + div-m = <2>; + mul-n = <48>; + div-p = <2>; + div-q = <25>; + div-r = <2>; + clocks = <&clk_hse>; + status = "okay"; +}; + +&rcc { + clocks = <&pll1>; + clock-frequency = ; + ahb-prescaler = <1>; + apb1-prescaler = <1>; + apb2-prescaler = <1>; + apb3-prescaler = <1>; +}; + +&gpioe { + status = "okay"; + + /* Enable 2.7V Analog LDO */ + ldo-enable-gpios { + gpio-hog; + gpios = <15 GPIO_ACTIVE_HIGH>; + output-high; + }; +}; + +stm32_lp_tick_source: &lptim1 { + clocks = <&rcc STM32_CLOCK_BUS_APB3 0x00000800>, + <&rcc STM32_SRC_LSE LPTIM1_SEL(3)>; + status = "okay"; +}; + +&usart2 { + pinctrl-0 = <&usart2_tx_pd5 &usart2_rx_pd6>; + pinctrl-names = "default"; + current-speed = <115200>; + status = "okay"; +}; + +&i2c2 { + pinctrl-0 = <&i2c2_scl_ph4 &i2c2_sda_pf0>; + pinctrl-names = "default"; + status = "okay"; + clock-frequency = ; + + stts22h@3f { + compatible = "st,stts22h"; + reg = <0x3f>; + int-gpios = <&gpiof 5 GPIO_ACTIVE_HIGH>; + status = "okay"; + }; +}; + +&timers5 { + st,prescaler = <10000>; + status = "okay"; + + pwm5: pwm { + status = "okay"; + pinctrl-0 = <&tim5_ch3_ph12>; + pinctrl-names = "default"; + }; +}; + + +&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_in1_pc0>; + pinctrl-names = "default"; + st,adc-clock-source = ; + st,adc-prescaler = <4>; + vref-mv = <2750>; + status = "okay"; +}; + +&adc4 { + pinctrl-0 = <&adc4_in3_pc2>; + pinctrl-names = "default"; + st,adc-clock-source = ; + st,adc-prescaler = <4>; + vref-mv = <2750>; + status = "okay"; +}; + +&die_temp { + 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>; + pinctrl-names = "default"; + cd-gpios = <&gpiog 1 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 steval_stwinbx1 + * 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/st/steval_stwinbx1/steval_stwinbx1.yaml b/boards/st/steval_stwinbx1/steval_stwinbx1.yaml new file mode 100644 index 00000000000..a12712dda8a --- /dev/null +++ b/boards/st/steval_stwinbx1/steval_stwinbx1.yaml @@ -0,0 +1,15 @@ +identifier: steval_stwinbx1 +name: STEVAL STWINBX1 Development kit +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb +ram: 786 +flash: 2048 +supported: + - counter + - gpio + - pwm + - watchdog +vendor: st diff --git a/boards/st/steval_stwinbx1/steval_stwinbx1_defconfig b/boards/st/steval_stwinbx1/steval_stwinbx1_defconfig new file mode 100644 index 00000000000..c432b5184df --- /dev/null +++ b/boards/st/steval_stwinbx1/steval_stwinbx1_defconfig @@ -0,0 +1,32 @@ +# SPDX-License-Identifier: Apache-2.0 + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable hardware stack protection +CONFIG_HW_STACK_PROTECTION=y + +# enable GPIO +CONFIG_GPIO=y +CONFIG_GPIO_HOGS=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=0x5740 +CONFIG_USB_DEVICE_PRODUCT="Zephyr CDC STEval-STWinbx1" +CONFIG_USB_DEVICE_INITIALIZE_AT_BOOT=n + +# enable pin controller +CONFIG_PINCTRL=y diff --git a/boards/st/steval_stwinbx1/support/openocd.cfg b/boards/st/steval_stwinbx1/support/openocd.cfg new file mode 100644 index 00000000000..31f15356db7 --- /dev/null +++ b/boards/st/steval_stwinbx1/support/openocd.cfg @@ -0,0 +1,44 @@ +source [find interface/stlink-dap.cfg] + +set WORKAREASIZE 0x8000 + +transport select "dapdirect_swd" + +set CHIPNAME STM32U585AIIxQ +set BOARDNAME STEVAL-STWINBX1 + +# 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/st/stm32c0116_dk/Kconfig.stm32c0116_dk b/boards/st/stm32c0116_dk/Kconfig.stm32c0116_dk new file mode 100644 index 00000000000..5ec2bb6264a --- /dev/null +++ b/boards/st/stm32c0116_dk/Kconfig.stm32c0116_dk @@ -0,0 +1,5 @@ +# Copyright (c) 2024 Kickmaker +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_STM32C0116_DK + select SOC_STM32C011XX diff --git a/boards/st/stm32c0116_dk/board.cmake b/boards/st/stm32c0116_dk/board.cmake new file mode 100644 index 00000000000..92d0dbb2924 --- /dev/null +++ b/boards/st/stm32c0116_dk/board.cmake @@ -0,0 +1,8 @@ +# Copyright (c) 2024 Kickmaker +# SPDX-License-Identifier: Apache-2.0 + +board_runner_args(jlink "--device=STM32C011F6" "--speed=4000") +board_runner_args(stm32cubeprogrammer "--port=swd" "--reset-mode=hw") + +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) +include(${ZEPHYR_BASE}/boards/common/stm32cubeprogrammer.board.cmake) diff --git a/boards/st/stm32c0116_dk/board.yml b/boards/st/stm32c0116_dk/board.yml new file mode 100644 index 00000000000..1764907618b --- /dev/null +++ b/boards/st/stm32c0116_dk/board.yml @@ -0,0 +1,5 @@ +board: + name: stm32c0116_dk + vendor: st + socs: + - name: stm32c011xx diff --git a/boards/st/stm32c0116_dk/doc/img/stm32c0116_dk.jpg b/boards/st/stm32c0116_dk/doc/img/stm32c0116_dk.jpg new file mode 100644 index 00000000000..bacdc93ad4c Binary files /dev/null and b/boards/st/stm32c0116_dk/doc/img/stm32c0116_dk.jpg differ diff --git a/boards/st/stm32c0116_dk/doc/index.rst b/boards/st/stm32c0116_dk/doc/index.rst new file mode 100644 index 00000000000..a59086c2930 --- /dev/null +++ b/boards/st/stm32c0116_dk/doc/index.rst @@ -0,0 +1,154 @@ +.. _stm32c0116_dk_board: + +ST STM32C0116-DK Discovery Kit +############################## + +Overview +******** + +The STM32C0116-DK Discovery kit helps to discover features of the STM32C0 Series +microcontroller in a UFQFPN20 package. This Discovery kit features one UFQFPN20 +to DIL20 module designed with the STM32C011F6 microcontroller and allows the user to develop +and share applications. It includes an on-board ST-LINK/V2-1 to debug and program the embedded +STM32 microcontroller. Important board features include: + +.. image:: img/stm32c0116_dk.jpg + :align: center + :alt: STM32C0116-DK + +More information about the board can be found at the `STM32C0116-DK website`_. + +Hardware +******** + +The STM32C0116-DK Discovery kit provides the following hardware components: + +- STM32C011F6 microcontroller with 32 Kbytes of Flash memory and 6 Kbytes of RAM, in a UFQFPN20 package +- On-board ST-LINK/V2-1 debugger/programmer with USB re-enumeration capability: mass storage and debug port +- User LED +- Reset push-button +- 5 way joystick using a single ADC input pin +- Individual STM32 UFQFPN20 to DIL20 module +- Board connectors: + + - USB Micro-B + - DIL20 socket + - Dedicated LCD footprint + - Grove (UART) + - 2 x 10 pin headers for MCU daughterboard + - Extension connectors + +More information about STM32C011F6 can be found here: + +- `STM32C011F6 on www.st.com`_ +- `STM32C0x1 reference manual`_ + +Supported Features +================== + +The Zephyr stm32c0116_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 | ++-----------+------------+-------------------------------------+ +| CLOCK | on-chip | reset and clock control | ++-----------+------------+-------------------------------------+ +| RTC | on-chip | counter | ++-----------+------------+-------------------------------------+ +| IWDG | on-chip | independent watchdog | ++-----------+------------+-------------------------------------+ +| WWDG | on-chip | window watchdog | ++-----------+------------+-------------------------------------+ +| PWM | on-chip | pwm | ++-----------+------------+-------------------------------------+ +| ADC | on-chip | ADC Controller | ++-----------+------------+-------------------------------------+ +| die-temp | on-chip | die temperature sensor | ++-----------+------------+-------------------------------------+ +| I2C | on-chip | i2c | ++-----------+------------+-------------------------------------+ +| DMA | on-chip | Direct Memory Access | ++-----------+------------+-------------------------------------+ + +Other hardware features are not yet supported on Zephyr porting. + +The default configuration can be found in +:zephyr_file:`boards/st/stm32c0116_dk/stm32c0116_dk_defconfig` + +Pin Mapping +=========== + +STM32C0116-DK Discovery kit has 4 GPIO controllers. These controllers are responsible for pin muxing, +input/output, pull-up, etc. + +For more details please refer to `STM32C0116-DK board User Manual`_. + +Default Zephyr Peripheral Mapping: +---------------------------------- + +The STM32C0116 Discovery board is configured as follows: + +- UART_2 TX/RX : PA2/PA3 +- UART_1 TX/RX : PA9/PA10 (ST-Link Virtual Port Com) +- PWM_1_CH3 : PB6 +- ADC1_CH8 : PA8 +- LD3 : PB6 + +Programming and Debugging +************************* + +Applications for the ``stm32c0116_dk`` board configuration can be built and +flashed in the usual way (see :ref:`build_an_application` and +:ref:`application_run` for more details). + +Flashing +======== + +STM32C0116-DK Discovery kit includes an ST-LINK/V2 embedded debug tool interface. + +Flashing an application to STM32C0116-DK +------------------------------------------- + +First, connect the STM32C0116 Discovery kit 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 :ref:`hello_world` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: stm32c0116_dk + :goals: build flash + +Run a serial host program to connect with your board: + +.. code-block:: console + + $ minicom -D /dev/ttyACM0 + +You should see the following message on the console: + +.. code-block:: console + + Hello World! arm + + +.. _STM32C0116-DK website: + https://www.st.com/en/evaluation-tools/stm32c0116-dk.html + +.. _STM32C0116-DK board User Manual: + https://www.st.com/resource/en/user_manual/um2970-discovery-kit-with-stm32c011f6-mcu-stmicroelectronics.pdf + +.. _STM32C011F6 on www.st.com: + https://www.st.com/resource/en/datasheet/stm32c011f6.pdf + +.. _STM32C0x1 reference manual: + https://www.st.com/resource/en/reference_manual/rm0490-stm32c0x1-advanced-armbased-64bit-mcus-stmicroelectronics.pdf diff --git a/boards/st/stm32c0116_dk/stm32c0116_dk.dts b/boards/st/stm32c0116_dk/stm32c0116_dk.dts new file mode 100644 index 00000000000..f9791268886 --- /dev/null +++ b/boards/st/stm32c0116_dk/stm32c0116_dk.dts @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2024 Kickmaker + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include +#include + +/ { + model = "STMicroelectronics STM32C0116-DK Discovery board"; + compatible = "st,stm32c011f6-dk"; + + chosen { + zephyr,console = &usart1; + zephyr,shell-uart = &usart1; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + }; + + leds: leds { + compatible = "gpio-leds"; + green_led_3: led_3 { + gpios = <&gpiob 6 GPIO_ACTIVE_LOW>; + label = "User LD3"; + }; + }; + + pwmleds { + compatible = "pwm-leds"; + + green_pwm_led: green_pwm_led { + pwms = <&pwm1 1 PWM_MSEC(20) PWM_POLARITY_NORMAL>; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + reset_button: button { + label = "reset button"; + gpios = <&gpiof 2 GPIO_ACTIVE_LOW>; + status = "okay"; + zephyr,code = ; + }; + }; + + adc-keys { + compatible = "adc-keys"; + io-channels = <&adc1 8>; + keyup-threshold-mv = <3300>; + + select_key { + press-thresholds-mv = <0>; + zephyr,code = ; + }; + + left_key { + press-thresholds-mv = <670>; + zephyr,code = ; + }; + + down_key { + press-thresholds-mv = <1320>; + zephyr,code = ; + }; + + up_key { + press-thresholds-mv = <2010>; + zephyr,code = ; + }; + + right_key { + press-thresholds-mv = <2650>; + zephyr,code = ; + }; + }; + + aliases { + led0 = &green_led_3; + pwm-led0 = &green_pwm_led; + sw0 = &reset_button; + watchdog0 = &iwdg; + die-temp0 = &die_temp; + volt-sensor0 = &vref; + }; +}; + +&clk_hsi { + status = "okay"; +}; + +&rcc { + clocks = <&clk_hsi>; + clock-frequency = ; + ahb-prescaler = <1>; + apb1-prescaler = <1>; +}; + +&pinctrl { + remap-pa11; + remap-pa12; +}; + +&usart1 { + pinctrl-0 = <&usart1_tx_pa9 &usart1_rx_pa10>; + pinctrl-names = "default"; + current-speed = <115200>; + status = "okay"; +}; + +&usart2 { + pinctrl-0 = <&usart2_tx_pa2 &usart2_rx_pa3>; + pinctrl-names = "default"; + current-speed = <115200>; + status = "okay"; +}; + +&rtc { + clocks = <&rcc STM32_CLOCK_BUS_APB1 0x00000400>, + <&rcc STM32_SRC_LSE RTC_SEL(1)>; + status = "okay"; +}; + +&iwdg { + status = "okay"; +}; + +&timers1 { + st,prescaler = <10000>; + status = "okay"; + + pwm1: pwm { + pinctrl-0 = <&tim1_ch3_pb6>; + pinctrl-names = "default"; + status = "okay"; + }; +}; + +&adc1 { + pinctrl-0 = <&adc1_in8_pa8>; + pinctrl-names = "default"; + st,adc-clock-source = ; + st,adc-prescaler = <2>; + status = "okay"; + + #address-cells = <1>; + #size-cells = <0>; + + channel@8 { + reg = <0x8>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + zephyr,vref-mv = <3300>; + }; + +}; + +&die_temp { + status = "okay"; +}; + +&vref { + status = "okay"; +}; + +&dma1 { + status = "okay"; +}; + +&dmamux1 { + status = "okay"; +}; diff --git a/boards/st/stm32c0116_dk/stm32c0116_dk.yaml b/boards/st/stm32c0116_dk/stm32c0116_dk.yaml new file mode 100644 index 00000000000..319a90afd74 --- /dev/null +++ b/boards/st/stm32c0116_dk/stm32c0116_dk.yaml @@ -0,0 +1,19 @@ +# Copyright (c) 2024 Kickmaker +# SPDX-License-Identifier: Apache-2.0 + +identifier: stm32c0116_dk +name: STM32C0116 DK +type: mcu +arch: arm +toolchain: + - zephyr +supported: + - gpio + - counter + - watchdog + - pwm + - adc + - dma +ram: 6 +flash: 32 +vendor: st diff --git a/boards/st/stm32c0116_dk/stm32c0116_dk_defconfig b/boards/st/stm32c0116_dk/stm32c0116_dk_defconfig new file mode 100644 index 00000000000..247a0d666a5 --- /dev/null +++ b/boards/st/stm32c0116_dk/stm32c0116_dk_defconfig @@ -0,0 +1,19 @@ +# Copyright (c) 2024 Kickmaker +# SPDX-License-Identifier: Apache-2.0 + +# Serial Drivers +CONFIG_SERIAL=y +CONFIG_UART_INTERRUPT_DRIVEN=y + +# enable console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# GPIO Controller +CONFIG_GPIO=y + +# Enable Clocks +CONFIG_CLOCK_CONTROL=y + +# enable pin controller +CONFIG_PINCTRL=y diff --git a/boards/st/stm32f072b_disco/stm32f072b_disco.dts b/boards/st/stm32f072b_disco/stm32f072b_disco.dts index 363e5a565c5..de73e11af6f 100644 --- a/boards/st/stm32f072b_disco/stm32f072b_disco.dts +++ b/boards/st/stm32f072b_disco/stm32f072b_disco.dts @@ -118,7 +118,6 @@ &can1 { pinctrl-0 = <&can_rx_pb8 &can_tx_pb9>; pinctrl-names = "default"; - bus-speed = <125000>; status = "okay"; }; diff --git a/boards/st/stm32f103_mini/doc/index.rst b/boards/st/stm32f103_mini/doc/index.rst index 63d2199e4d0..c6938020f99 100644 --- a/boards/st/stm32f103_mini/doc/index.rst +++ b/boards/st/stm32f103_mini/doc/index.rst @@ -75,8 +75,6 @@ The Zephyr stm32f103_mini board configuration supports the following hardware fe +-----------+------------+-------------------------------------+ | COUNTER | on-chip | rtc | +-----------+------------+-------------------------------------+ -| RTC | on-chip | rtc | -+-----------+------------+-------------------------------------+ Other hardware features are not yet supported in this Zephyr port. diff --git a/boards/st/stm32f3_disco/doc/index.rst b/boards/st/stm32f3_disco/doc/index.rst index 8862d754fbb..d4a629a4895 100644 --- a/boards/st/stm32f3_disco/doc/index.rst +++ b/boards/st/stm32f3_disco/doc/index.rst @@ -109,6 +109,8 @@ features: +-----------+------------+-------------------------------------+ | die-temp | on-chip | die temperature sensor | +-----------+------------+-------------------------------------+ +| RTC | on-chip | rtc | ++-----------+------------+-------------------------------------+ Other hardware features are not yet supported on Zephyr porting. diff --git a/boards/st/stm32f3_disco/stm32f3_disco.dts b/boards/st/stm32f3_disco/stm32f3_disco.dts index f90c10cf71c..44a66f038be 100644 --- a/boards/st/stm32f3_disco/stm32f3_disco.dts +++ b/boards/st/stm32f3_disco/stm32f3_disco.dts @@ -185,7 +185,6 @@ zephyr_udc0: &usb { pinctrl-0 = <&can_rx_pd0 &can_tx_pd1>; pinctrl-names = "default"; status = "okay"; - bus-speed = <125000>; }; &flash0 { diff --git a/boards/st/stm32f3_disco/stm32f3_disco_B.yaml b/boards/st/stm32f3_disco/stm32f3_disco_B.yaml index 1c87cb7fd36..ebdbe230d20 100644 --- a/boards/st/stm32f3_disco/stm32f3_disco_B.yaml +++ b/boards/st/stm32f3_disco/stm32f3_disco_B.yaml @@ -21,4 +21,5 @@ supported: - adc - dac - dma + - rtc vendor: st diff --git a/boards/st/stm32f3_disco/stm32f3_disco_stm32f303xc_E.yaml b/boards/st/stm32f3_disco/stm32f3_disco_stm32f303xc_E.yaml index 13e6b0bf143..bc17f1c2d68 100644 --- a/boards/st/stm32f3_disco/stm32f3_disco_stm32f303xc_E.yaml +++ b/boards/st/stm32f3_disco/stm32f3_disco_stm32f303xc_E.yaml @@ -20,4 +20,5 @@ supported: - pwm - adc - dac + - rtc vendor: st diff --git a/boards/st/stm32f411e_disco/stm32f411e_disco_stm32f411xe_B.yaml b/boards/st/stm32f411e_disco/stm32f411e_disco_stm32f411xe_B.yaml index 05f3c979f7f..480b81537b6 100644 --- a/boards/st/stm32f411e_disco/stm32f411e_disco_stm32f411xe_B.yaml +++ b/boards/st/stm32f411e_disco/stm32f411e_disco_stm32f411xe_B.yaml @@ -1,5 +1,5 @@ identifier: stm32f411e_disco@B -name: ST STM32F411E Discovery +name: ST STM32F411E Discovery (rev. B) type: mcu arch: arm toolchain: diff --git a/boards/st/stm32f4_disco/stm32f4_disco.dts b/boards/st/stm32f4_disco/stm32f4_disco.dts index 2847c2fcfdb..163612aaf07 100644 --- a/boards/st/stm32f4_disco/stm32f4_disco.dts +++ b/boards/st/stm32f4_disco/stm32f4_disco.dts @@ -129,13 +129,11 @@ zephyr_udc0: &usbotg_fs { &can1 { pinctrl-0 = <&can1_rx_pb8 &can1_tx_pb9>; pinctrl-names = "default"; - bus-speed = <125000>; status = "disabled"; }; &can2 { pinctrl-0 = <&can2_rx_pb5 &can2_tx_pb13>; pinctrl-names = "default"; - bus-speed = <125000>; status = "okay"; }; diff --git a/boards/st/stm32f746g_disco/stm32f746g_disco.yaml b/boards/st/stm32f746g_disco/stm32f746g_disco.yaml index f3ef45a7906..5442db5bb67 100644 --- a/boards/st/stm32f746g_disco/stm32f746g_disco.yaml +++ b/boards/st/stm32f746g_disco/stm32f746g_disco.yaml @@ -16,7 +16,6 @@ supported: - gpio - pwm - counter - - sdhc - usb_device - display - memc diff --git a/boards/st/stm32f7508_dk/stm32f7508_dk.yaml b/boards/st/stm32f7508_dk/stm32f7508_dk.yaml index b474319510d..9415c4660d1 100644 --- a/boards/st/stm32f7508_dk/stm32f7508_dk.yaml +++ b/boards/st/stm32f7508_dk/stm32f7508_dk.yaml @@ -19,7 +19,6 @@ supported: - gpio - pwm - counter - - sdhc - usb_device - display - memc diff --git a/boards/st/stm32f769i_disco/stm32f769i_disco.dts b/boards/st/stm32f769i_disco/stm32f769i_disco.dts index feb0f2f11a2..03ff90c729b 100644 --- a/boards/st/stm32f769i_disco/stm32f769i_disco.dts +++ b/boards/st/stm32f769i_disco/stm32f769i_disco.dts @@ -32,6 +32,11 @@ zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM) )>; }; + otghs_ulpi_phy: otghs_ulpis_phy { + compatible = "usb-ulpi-phy"; + #phy-cells = <0>; + }; + leds { compatible = "gpio-leds"; red_led_1:led_1 { @@ -74,6 +79,13 @@ sw0 = &user_button; spi-flash0 = &mx25l51245g; }; + + quadspi_memory_avail: memory-avail@90000000 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x90000000 DT_SIZE_M(64)>; + zephyr,memory-region = "QSPI_AVAIL"; + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_IO) )>; + }; }; &clk_hse { @@ -175,7 +187,7 @@ arduino_serial: &usart6 {}; mx25l51245g: qspi-nor-flash@90000000 { compatible = "st,stm32-qspi-nor"; reg = <0x90000000 DT_SIZE_M(64)>; /* 512 Mbits */ - qspi-max-frequency = <72000000>; + qspi-max-frequency = ; status = "okay"; partitions { @@ -238,3 +250,22 @@ arduino_serial: &usart6 {}; }; }; }; + +zephyr_udc0: &usbotg_hs { + pinctrl-0 = <&usb_otg_hs_ulpi_ck_pa5 + &usb_otg_hs_ulpi_d0_pa3 + &usb_otg_hs_ulpi_d1_pb0 + &usb_otg_hs_ulpi_d2_pb1 + &usb_otg_hs_ulpi_d3_pb10 + &usb_otg_hs_ulpi_d4_pb11 + &usb_otg_hs_ulpi_d5_pb12 + &usb_otg_hs_ulpi_d6_pb13 + &usb_otg_hs_ulpi_d7_pb5 + &usb_otg_hs_ulpi_stp_pc0 + &usb_otg_hs_ulpi_dir_pi11 + &usb_otg_hs_ulpi_nxt_ph4>; + pinctrl-names = "default"; + maximum-speed = "high-speed"; + phys = <&otghs_ulpi_phy>; + status = "okay"; +}; diff --git a/boards/st/stm32f769i_disco/support/openocd.cfg b/boards/st/stm32f769i_disco/support/openocd.cfg index 1c964a0e643..8896666bc6d 100644 --- a/boards/st/stm32f769i_disco/support/openocd.cfg +++ b/boards/st/stm32f769i_disco/support/openocd.cfg @@ -2,7 +2,7 @@ source [find board/stm32f769i-disco.cfg] $_TARGETNAME configure -event gdb-attach { echo "Debugger attaching: halting execution" - reset halt + reset init gdb_breakpoint_override hard } diff --git a/boards/st/stm32h573i_dk/Kconfig.defconfig b/boards/st/stm32h573i_dk/Kconfig.defconfig index b3a733436a9..428337e59e4 100644 --- a/boards/st/stm32h573i_dk/Kconfig.defconfig +++ b/boards/st/stm32h573i_dk/Kconfig.defconfig @@ -14,4 +14,11 @@ config NET_L2_ETHERNET endif # NETWORKING +if DISK_DRIVER_SDMMC + +config SDMMC_STM32_CLOCK_CHECK + default n + +endif # DISK_DRIVER_SDMMC + endif # BOARD_STM32H573I_DK diff --git a/boards/st/stm32h573i_dk/doc/index.rst b/boards/st/stm32h573i_dk/doc/index.rst index 81d7e1ae002..72fba315ace 100644 --- a/boards/st/stm32h573i_dk/doc/index.rst +++ b/boards/st/stm32h573i_dk/doc/index.rst @@ -193,8 +193,13 @@ hardware features: +-----------+------------+-------------------------------------+ | AES | on-chip | crypto | +-----------+------------+-------------------------------------+ +| SDMMC | on-chip | disk access | ++-----------+------------+-------------------------------------+ | USB | on-chip | USB full-speed host/device bus | +-----------+------------+-------------------------------------+ +| RTC | on-chip | rtc | ++-----------+------------+-------------------------------------+ + Other hardware features are not yet supported on this Zephyr port. diff --git a/boards/st/stm32h573i_dk/stm32h573i_dk.dts b/boards/st/stm32h573i_dk/stm32h573i_dk.dts index 30401d7493a..721cea3ab6a 100644 --- a/boards/st/stm32h573i_dk/stm32h573i_dk.dts +++ b/boards/st/stm32h573i_dk/stm32h573i_dk.dts @@ -149,11 +149,9 @@ &mac { status = "okay"; - pinctrl-0 = <ð_mdc_pc1 - ð_rxd0_pc4 + pinctrl-0 = <ð_rxd0_pc4 ð_rxd1_pc5 ð_ref_clk_pa1 - ð_mdio_pa2 ð_crs_dv_pa7 ð_tx_en_pg11 ð_txd0_pg13 @@ -161,6 +159,18 @@ pinctrl-names = "default"; }; +&mdio { + status = "okay"; + pinctrl-0 = <ð_mdio_pa2 ð_mdc_pc1>; + pinctrl-names = "default"; + + ethernet-phy@0 { + compatible = "ethernet-phy"; + reg = <0x00>; + status = "okay"; + }; +}; + &flash0 { partitions { compatible = "fixed-partitions"; @@ -237,12 +247,10 @@ <&rcc STM32_SRC_PLL1_Q FDCAN_SEL(1)>; pinctrl-0 = <&fdcan1_rx_pa11 &fdcan1_tx_pa12>; pinctrl-names = "default"; - bus-speed = <125000>; - bus-speed-data = <1000000>; status = "okay"; }; -&octospi1 { +&xspi1 { pinctrl-0 = <&octospi1_io0_pb1 &octospi1_io1_pd12 &octospi1_io2_pc2 &octospi1_io3_pd13 &octospi1_io4_ph2 &octospi1_io5_ph3 @@ -254,11 +262,11 @@ status = "okay"; mx25lm51245: ospi-nor-flash@90000000 { - compatible = "st,stm32-ospi-nor"; + compatible = "st,stm32-xspi-nor"; reg = <0x90000000 DT_SIZE_M(64)>; /* 512 Mbits */ ospi-max-frequency = ; - spi-bus-width = ; - data-rate = ; + spi-bus-width = ; + data-rate = ; four-byte-opcodes; status = "okay"; @@ -275,6 +283,16 @@ }; }; +&sdmmc1 { + 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 = <&gpioh 14 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + status = "okay"; +}; + + zephyr_udc0: &usb { pinctrl-0 = <&usb_dm_pa11 &usb_dp_pa12>; pinctrl-names = "default"; diff --git a/boards/st/stm32h573i_dk/stm32h573i_dk.yaml b/boards/st/stm32h573i_dk/stm32h573i_dk.yaml index 63ec297be26..f6d5f12b173 100644 --- a/boards/st/stm32h573i_dk/stm32h573i_dk.yaml +++ b/boards/st/stm32h573i_dk/stm32h573i_dk.yaml @@ -24,4 +24,5 @@ supported: - usb_device - usb - i2c + - rtc vendor: st diff --git a/boards/st/stm32h735g_disco/stm32h735g_disco.dts b/boards/st/stm32h735g_disco/stm32h735g_disco.dts index cc504a4a6c3..41e67e551c2 100644 --- a/boards/st/stm32h735g_disco/stm32h735g_disco.dts +++ b/boards/st/stm32h735g_disco/stm32h735g_disco.dts @@ -130,11 +130,9 @@ }; &mac { - pinctrl-0 = <ð_mdc_pc1 - ð_rxd0_pc4 + pinctrl-0 = <ð_rxd0_pc4 ð_rxd1_pc5 ð_ref_clk_pa1 - ð_mdio_pa2 ð_crs_dv_pa7 ð_tx_en_pb11 ð_txd0_pb12 @@ -143,6 +141,18 @@ status = "okay"; }; +&mdio { + status = "okay"; + pinctrl-0 = <ð_mdio_pa2 ð_mdc_pc1>; + pinctrl-names = "default"; + + ethernet-phy@0 { + compatible = "ethernet-phy"; + reg = <0x00>; + status = "okay"; + }; +}; + &sdmmc1 { pinctrl-0 = <&sdmmc1_d0_pc8 &sdmmc1_d1_pc9 @@ -206,8 +216,6 @@ 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>; @@ -220,8 +228,6 @@ 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>; @@ -235,8 +241,6 @@ <&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/st/stm32h745i_disco/Kconfig.defconfig b/boards/st/stm32h745i_disco/Kconfig.defconfig new file mode 100644 index 00000000000..b6242139bfd --- /dev/null +++ b/boards/st/stm32h745i_disco/Kconfig.defconfig @@ -0,0 +1,23 @@ +# STM32H745XI DISCOVERY board configuration + +# Copyright (c) 2020 Alexander Kozhinov +# Copyright (c) 2024 Tomas Jurena +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_STM32H745I_DISCO + +if NETWORKING + +config NET_L2_ETHERNET + default y + +config ETH_STM32_HAL_MII + default y + +endif # NETWORKING + +config MEMC + default y if DISPLAY + + +endif # BOARD_STM32H745I_DISCO diff --git a/boards/st/stm32h745i_disco/Kconfig.stm32h745i_disco b/boards/st/stm32h745i_disco/Kconfig.stm32h745i_disco new file mode 100644 index 00000000000..7dacd75eb4b --- /dev/null +++ b/boards/st/stm32h745i_disco/Kconfig.stm32h745i_disco @@ -0,0 +1,9 @@ +# STM32H745XI DISCOVERY board configuration + +# Copyright (c) 2020 Alexander Kozhinov +# Copyright (c) 2024 Tomas Jurena +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_STM32H745I_DISCO + select SOC_STM32H745XX_M7 if BOARD_STM32H745I_DISCO_STM32H745XX_M7 + select SOC_STM32H745XX_M4 if BOARD_STM32H745I_DISCO_STM32H745XX_M4 diff --git a/boards/st/stm32h745i_disco/arduino_r3_connector.dtsi b/boards/st/stm32h745i_disco/arduino_r3_connector.dtsi new file mode 100644 index 00000000000..4ad2396a162 --- /dev/null +++ b/boards/st/stm32h745i_disco/arduino_r3_connector.dtsi @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2020 Alexander Kozhinov + * Copyright (c) 2024 Tomas Jurena + * + * 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 6 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 */ + }; +}; + + +arduino_i2c: &i2c1 {}; + +arduino_serial: &usart1 {}; diff --git a/boards/st/stm32h745i_disco/board.cmake b/boards/st/stm32h745i_disco/board.cmake new file mode 100644 index 00000000000..699e51ae595 --- /dev/null +++ b/boards/st/stm32h745i_disco/board.cmake @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright (c) 2020 Alexander Kozhinov +# Copyright (c) 2024 Tomas Jurena + +board_runner_args(jlink "--device=STM32H745XI" "--speed=4000") +if(CONFIG_BOARD_STM32H745I_DISCO_STM32H745XX_M7) +board_runner_args(openocd --target-handle=_CHIPNAME.cpu0) +elseif(CONFIG_BOARD_STM32H745I_DISCO_STM32H745XX_M4) +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/st/stm32h745i_disco/board.yml b/boards/st/stm32h745i_disco/board.yml new file mode 100644 index 00000000000..e1da9c4b2f4 --- /dev/null +++ b/boards/st/stm32h745i_disco/board.yml @@ -0,0 +1,5 @@ +board: + name: stm32h745i_disco + vendor: st + socs: + - name: stm32h745xx diff --git a/boards/st/stm32h745i_disco/doc/img/stm32h745i-disco.jpg b/boards/st/stm32h745i_disco/doc/img/stm32h745i-disco.jpg new file mode 100644 index 00000000000..c2e5d12d5c5 Binary files /dev/null and b/boards/st/stm32h745i_disco/doc/img/stm32h745i-disco.jpg differ diff --git a/boards/st/stm32h745i_disco/doc/index.rst b/boards/st/stm32h745i_disco/doc/index.rst new file mode 100644 index 00000000000..0b74a8903d0 --- /dev/null +++ b/boards/st/stm32h745i_disco/doc/index.rst @@ -0,0 +1,272 @@ +.. _stm32h745i_disco_board: + +ST STM32H745I Discovery +####################### + +Overview +******** + +The STM32H745I-DISCO Discovery kit is a complete demonstration and development +platform for STMicroelectronics Arm |reg| Cortex |reg|ā€‘M7 and Cortex |reg|ā€‘M4 core-based STM32H745XI microcontroller. + +The full range of hardware features available on the board helps users enhance their application +development by an evaluation of almost all peripherals (such as USB OTG FS, Ethernet 10/100Mb/s, +eMMC, USART, SAI audio DAC stereo with audio jack input and output, MEMS digital microphone, SDRAM, +Quad-SPI flash memory, and RGB interface LCD with capacitive multi-touch panel). ARDUINO |reg| Uno V3 +connectors provide easy connection to extension shields or daughterboards for specific applications. + +STLINK-V3E is integrated into the board, as an embedded in-circuit debugger and programmer for the +STM32 MCU and the USB Virtual COM port bridge + +Key Features + +- Arm |reg| Cortex |reg| core-based microcontroller with 2 Mbytes of flash memory and 1 Mbyte of RAM, in a TFBGA240+25 package +- 4.3ā€ RGB interface LCD with touch panel connector +- Ethernet compliant with IEEE-802.3-2002, and PoE +- USB OTG FS +- SAI audio codec +- One ST-MEMS digital microphone +- 2Ɨ 512-Mbit Quad-SPI NOR flash memory +- 128-Mbit SDRAM +- 4-Gbyte on-board eMMC +- 1 user and reset push-button +- Fanout daughterboard +- 2Ɨ CAN FDs +- Board connectors: + + - USB FS Micro-AB connectors + - ST-LINK Micro-B USB connector + - USB power Micro-B connector + - Ethernet RJ45 + - Stereo headset jack including analog microphone input + - Audio header for external speakers + - Tagā€‘Connect |trade| (TAG) 10-pin footprint + - Arm |reg| Cortex |reg| 10-pin 1.27 mm pitch debug connector over STDC14 footprint + - ARDUINO |reg| Uno V3 expansion connectors + - STMod+ + +- Flexible power-supply options: + + - STLINK-V3E USB connector, USB FS connector + - 5 V delivered by RJ45 (Power over Ethernet) + - 5 V delivered by ARDUINO |reg| or external connector + - USB charger + - USB power + +.. image:: img/stm32h745i-disco.jpg + :align: center + :alt: STM32H745I-DISCO + +More information about the board can be found at the `STM32H745I-DISCO website`_. +More information about STM32H747XIH6 can be found here: + +- `STM32H745XI on www.st.com`_ +- `STM32H745xx reference manual`_ +- `STM32H745xx datasheet`_ + +Supported Features +================== + +The current Zephyr stm32h745i_disco 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 | ++-----------+------------+-------------------------------------+ +| RTC | on-chip | counter | ++-----------+------------+-------------------------------------+ +| I2C | on-chip | i2c | ++-----------+------------+-------------------------------------+ +| PWM | on-chip | pwm | ++-----------+------------+-------------------------------------+ +| ETHERNET | on-chip | ethernet | ++-----------+------------+-------------------------------------+ +| SPI | on-chip | spi | ++-----------+------------+-------------------------------------+ +| QSPI NOR | on-chip | off-chip flash | ++-----------+------------+-------------------------------------+ +| FDCAN | on-chip | fdcan | ++-----------+------------+-------------------------------------+ +| FMC | on-chip | memc (SDRAM) | ++-----------+------------+-------------------------------------+ +| RTC | on-chip | rtc | ++-----------+------------+-------------------------------------+ + +Other hardware features are not yet supported on this Zephyr port. + +The default configuration per core can be found in the defconfig files: +:zephyr_file:`boards/st/stm32h745i_disco/stm32h745i_disco_stm32h745xx_m7_defconfig`` and +:zephyr_file:`boards/st/stm32h745i_disco/stm32h745i_disco_stm32h745xx_m4_defconfig` + +For more details please refer to `STM32H745-Disco UM`_. + +Default Zephyr Peripheral Mapping: +---------------------------------- + +- USART_3 TX/RX : PB10/PB11 (ST-Link Virtual Port Com) +- USART_1 TX/RX : PB6/PB7 (Arduino Serial) +- SPI_2 NSS/SCK/MISO/MOSI : PB4/PD3/PI2/PB15 (Arduino SPI) +- I2C_4 SCL/SDA: PD12, PD13 (Arduino I2C) +- USER_PB : PC13 +- LD1 : PI13 +- LD2 : PJ2 +- LD3 : PD3 + +System Clock +------------ + +STM32H745I-DISCO System Clock could be driven by an internal or external +oscillator, as well as the main PLL clock. By default, the System clock is +driven by the PLL clock at 480MHz, driven by an 25MHz high-speed external clock. + +Serial Port +----------- + +STM32H745I-DISCO board has 4 UARTs and 4 USARTs. The Zephyr console output is +assigned to UART3. Default settings are 115200 8N1. + +Resources sharing +----------------- + +The dual core nature of STM32H745 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 ``stm32h745i_disco`` board should be built per core target, +using either ``stm32h745i_disco/stm32h745xx/m7`` or ``stm32h745i_disco/stm32h745xx/m4`` as the target +(see :ref:`build_an_application` and :ref:`application_run` for more details). + +.. note:: + + Check if the on-board ST-LINK V3 has the latest firmware version. It can be done with either `STM32CubeIDE`_ or `STM32CubeProgrammer`_ + +Flashing +======== + +STM32H745I-DISCO board includes an ST-LINK/V3 embedded debug tool interface. + +Flashing operation will depend on the target and the SoC +option bytes configuration. + +By default: + + - CPU0 (Cortex-M7) boot address is set to 0x80000000 (OB: BOOT_CM7_ADD0) + - CPU1 (Cortex-M4) boot address is set to 0x81000000 (OB: BOOT_CM4_ADD0) + +Also, the out of the box default board configuration enables CM7 and CM4 boot when +board is powered (Option bytes BCM7 and BCM4 are checked). +In that configuration, Kconfig boot option ``STM32H7_BOOT_CM4_CM7`` should be selected. +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 STM32H745XI M7 Core +---------------------------------------------- +First, connect the STM32H745I-DISCO 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 :ref:`hello_world` application. + +Run a serial host program to connect with your STM32H745I-DISCO board. + +.. code-block:: console + + $ minicom -b 115200 -D /dev/ttyACM0 + +or use screen: + +.. code-block:: console + + $ screen /dev/ttyACM0 115200 + +Build and flash the application: + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: stm32h745i_disco/stm32h745xx/m7 + :goals: build flash + +You should see the following message on the console: + +.. code-block:: console + + $ Hello World! stm32h745i_disco + +.. note:: + Sometimes, flashing does not work properly. It is necessary to erase the flash + (with STM32CubeProgrammer for example) to make it work again. + +Similarly, you can build and flash samples on the M4 target. For this, please +take care of the resource sharing (UART port used for console for instance). + +Here is an example for the :zephyr:code-sample:`blinky` application on M4 core. + +.. zephyr-app-commands:: + :zephyr-app: samples/basic/blinky + :board: stm32h745i_disco/stm32h745xx/m7 + :goals: build flash + +.. note:: + + Flashing both M4 and M7 and pushing RESTART button on the board leads + to LD1 and LD2 flashing simultaneously. + +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: stm32h745i_disco/stm32h745xx/m7 + :maybe-skip-config: + :goals: debug + +Debugging with west is currently not available on Cortex M4 side. +In order to debug a Zephyr application on Cortex M4 side, you can use +`STM32CubeIDE`_. + +.. _STM32H745I-DISCO website: + https://www.st.com/en/evaluation-tools/stm32h745i-disco.html + +.. _STM32H745XI on www.st.com: + https://www.st.com/en/microcontrollers-microprocessors/stm32h745xi.html + +.. _STM32H745xx reference manual: + https://www.st.com/resource/en/reference_manual/rm0399-stm32h745755-and-stm32h747757-advanced-armbased-32bit-mcus-stmicroelectronics.pdf + +.. _STM32H745xx datasheet: + https://www.st.com/resource/en/datasheet/stm32h745xi.pdf + +.. _STM32H745-Disco UM: + https://www.st.com/resource/en/user_manual/um2488-discovery-kits-with-stm32h745xi-and-stm32h750xb-mcus-stmicroelectronics.pdf + +.. _STM32CubeProgrammer: + https://www.st.com/en/development-tools/stm32cubeprog.html + +.. _STM32CubeIDE: + https://www.st.com/en/development-tools/stm32cubeide.html diff --git a/boards/st/stm32h745i_disco/stm32h745i_disco.dtsi b/boards/st/stm32h745i_disco/stm32h745i_disco.dtsi new file mode 100644 index 00000000000..c196018316c --- /dev/null +++ b/boards/st/stm32h745i_disco/stm32h745i_disco.dtsi @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2020 Alexander Kozhinov + * Copyright (c) 2024 Tomas Jurena + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "arduino_r3_connector.dtsi" +#include + +/ { + leds: leds { + compatible = "gpio-leds"; + green_led: led_1 { + gpios = <&gpioj 2 GPIO_ACTIVE_HIGH>; + label = "User LD7"; + }; + red_led: led_2 { + gpios = <&gpioi 13 GPIO_ACTIVE_HIGH>; + label = "User LD6"; + }; + green_led_2: led_3 { + gpios = <&gpiod 3 GPIO_ACTIVE_HIGH>; + label = "User LD8"; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + user_button: button_0 { + gpios = <&gpioc 13 GPIO_ACTIVE_HIGH>; + label = "User SB1"; + zephyr,code = ; + }; + }; +}; + +&rcc { + d1cpre = <1>; + hpre = <2>; + d1ppre = <2>; + d2ppre1 = <2>; + d2ppre2 = <2>; + d3ppre = <2>; +}; + +&mailbox { + status = "okay"; +}; diff --git a/boards/st/stm32h745i_disco/stm32h745i_disco_stm32h745xx_m4.dts b/boards/st/stm32h745i_disco/stm32h745i_disco_stm32h745xx_m4.dts new file mode 100644 index 00000000000..fe16637e5ef --- /dev/null +++ b/boards/st/stm32h745i_disco/stm32h745i_disco_stm32h745xx_m4.dts @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2020 Alexander Kozhinov + * Copyright (c) 2024 Tomas Jurena + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include "stm32h745i_disco.dtsi" + +/ { + model = "STMicroelectronics STM32H745I-DISCO board"; + compatible = "st,stm32h745i-disco"; + + /* HW resources belonging to CM4 */ + chosen { + zephyr,console = &usart2; + zephyr,shell-uart = &usart2; + zephyr,sram = &sram1; + zephyr,flash = &flash1; + }; + + aliases { + led0 = &green_led; + }; +}; + +&usart2 { + pinctrl-0 = <&usart2_tx_pd5 &usart2_rx_pd6>; + pinctrl-names = "default"; + current-speed = <115200>; + status = "okay"; +}; + +&rcc { + clock-frequency = ; +}; diff --git a/boards/st/stm32h745i_disco/stm32h745i_disco_stm32h745xx_m4.yaml b/boards/st/stm32h745i_disco/stm32h745i_disco_stm32h745xx_m4.yaml new file mode 100644 index 00000000000..c54a1599298 --- /dev/null +++ b/boards/st/stm32h745i_disco/stm32h745i_disco_stm32h745xx_m4.yaml @@ -0,0 +1,17 @@ +identifier: stm32h745i_disco/stm32h745xx/m4 +name: STM32H745XI Discovery (M4) +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb +ram: 288 +flash: 1024 +supported: + - arduino_gpio + - gpio +testing: + ignore_tags: + - mpu + - nfc +vendor: st diff --git a/boards/st/stm32h745i_disco/stm32h745i_disco_stm32h745xx_m4_defconfig b/boards/st/stm32h745i_disco/stm32h745i_disco_stm32h745xx_m4_defconfig new file mode 100644 index 00000000000..03e689742d9 --- /dev/null +++ b/boards/st/stm32h745i_disco/stm32h745i_disco_stm32h745xx_m4_defconfig @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright (c) 2020 Alexander Kozhinov +# Copyright (c) 2024 Tomas Jurena + +# Enable GPIO +CONFIG_GPIO=y + +# Enable clock +CONFIG_CLOCK_CONTROL=y + +# By default SERIAL peripherals are assigned to m7 + +# Enable uart driver +#CONFIG_SERIAL=y + +# Console +#CONFIG_CONSOLE=y +#CONFIG_UART_CONSOLE=y + +# enable pin controller +CONFIG_PINCTRL=y diff --git a/boards/st/stm32h745i_disco/stm32h745i_disco_stm32h745xx_m7.dts b/boards/st/stm32h745i_disco/stm32h745i_disco_stm32h745xx_m7.dts new file mode 100644 index 00000000000..eb33539d879 --- /dev/null +++ b/boards/st/stm32h745i_disco/stm32h745i_disco_stm32h745xx_m7.dts @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2020 Alexander Kozhinov + * Copyright (c) 2024 Tomas Jurena + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include "stm32h745i_disco.dtsi" + +/ { + model = "STMicroelectronics STM32H745I-DISCO board"; + compatible = "st,stm32h745i-disco"; + + /* HW resources belonging to CM7 */ + chosen { + zephyr,console = &usart3; + zephyr,shell-uart = &usart3; + zephyr,dtcm = &dtcm; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,flash-controller = &mt25ql512ab1; + zephyr,canbus = &fdcan1; + }; + + pwmleds { + compatible = "pwm-leds"; + + green_pwm_led: green_pwm_led { + pwms = <&pwm11 1 PWM_MSEC(20) PWM_POLARITY_NORMAL>; + label = "User LD8 - PWM11"; + }; + }; + + /* RM0455 - 23.6 External device address mapping */ + 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) )>; + }; + + aliases { + led0 = &green_led; + pwm-led0 = &green_pwm_led; + sw0 = &user_button; + }; +}; + +&clk_lsi { + status = "okay"; +}; + +&clk_hsi48 { + status = "okay"; +}; + +&clk_hse { + clock-frequency = ; /* X1: 25MHz */ + status = "okay"; +}; + +&pll { + div-m = <5>; + mul-n = <192>; + div-p = <2>; + div-q = <15>; + div-r = <4>; + clocks = <&clk_hse>; + status = "okay"; +}; + +&pll2 { + div-m = <5>; + mul-n = <192>; + div-p = <2>; + div-q = <12>; + div-r = <4>; + clocks = <&clk_hse>; + status = "okay"; +}; + +&rcc { + clocks = <&pll>; + clock-frequency = ; +}; + +&usart1 { + pinctrl-0 = <&usart1_tx_pb6 &usart1_rx_pb7>; + pinctrl-names = "default"; + current-speed = <57600>; + status = "okay"; +}; + +&usart3 { + pinctrl-0 = <&usart3_tx_pb10 &usart3_rx_pb11>; + pinctrl-names = "default"; + current-speed = <115200>; + status = "okay"; +}; + +&rtc { + clocks = <&rcc STM32_CLOCK_BUS_APB4 0x00010000>, + <&rcc STM32_SRC_LSI RTC_SEL(2)>; + status = "okay"; +}; + +&timers1 { + st,prescaler = <10000>; + status = "okay"; + + pwm11: pwm { + status = "okay"; + pinctrl-0 = <&tim1_ch1_pa8>; + pinctrl-names = "default"; + }; +}; + +&mac { + status = "okay"; + /* MII */ + pinctrl-0 = <ð_ref_clk_pa1 + ð_crs_dv_pa7 + ð_rxd2_pb0 + ð_rxd3_pb1 + ð_txd2_pc2 + ð_tx_clk_pc3 + ð_rxd0_pc4 + ð_rxd1_pc5 + ð_txd3_pe2 + ð_tx_en_pg11 + ð_txd1_pg12 + ð_txd0_pg13 + ð_rx_er_pi10>; + pinctrl-names = "default"; +}; + +&mdio { + status = "okay"; + pinctrl-0 = <ð_mdio_pa2 ð_mdc_pc1>; + pinctrl-names = "default"; + + ethernet-phy@0 { + compatible = "ethernet-phy"; + reg = <0x00>; + status = "okay"; + }; +}; + +&rng { + status = "okay"; +}; + +&quadspi { + pinctrl-names = "default"; + pinctrl-0 = < + &quadspi_bk1_io0_pd11 + &quadspi_bk1_io3_pf6 + &quadspi_bk1_io2_pf7 + &quadspi_bk1_io1_pf9 + &quadspi_clk_pf10 + &quadspi_bk1_ncs_pg6 + &quadspi_bk2_io2_pg9 + &quadspi_bk2_io3_pg14 + &quadspi_bk2_io0_ph2 + &quadspi_bk2_io1_ph3 + >; + flash-id = <1>; + status = "okay"; + + mt25ql512ab1: qspi-nor-flash-1@90000000 { + compatible = "st,stm32-qspi-nor"; + reg = <0x90000000 DT_SIZE_M(64)>; /* 512 Mbits */ + qspi-max-frequency = <72000000>; + spi-bus-width = <4>; + status = "okay"; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + storage_partition: partition@0 { + reg = <0x0 DT_SIZE_M(64)>; + }; + }; + }; + + mt25ql512ab2: qspi-nor-flash-2@90000000 { + compatible = "st,stm32-qspi-nor"; + reg = <0x90000000 DT_SIZE_M(64)>; /* 512 Mbits */ + qspi-max-frequency = <72000000>; + status = "okay"; + }; +}; + +&i2c4 { + status = "okay"; + pinctrl-0 = <&i2c4_scl_pd12 &i2c4_sda_pd13>; + pinctrl-names = "default"; +}; + +&spi2 { + status = "okay"; + pinctrl-0 = <&spi2_nss_pb4 &spi2_mosi_pb15 &spi2_miso_pi2 &spi2_sck_pd3>; + pinctrl-names = "default"; +}; + +&fdcan1 { + status = "okay"; + pinctrl-0 = <&fdcan1_tx_ph13 &fdcan1_rx_ph14>; + pinctrl-names = "default"; + clocks = <&rcc STM32_CLOCK_BUS_APB1_2 0x00000100>, + <&rcc STM32_SRC_PLL2_Q FDCAN_SEL(2)>; + sample-point = <875>; + sample-point-data = <875>; + + can-transceiver { + max-bitrate = <5000000>; + }; +}; + +&fdcan2 { + status = "okay"; + pinctrl-0 = <&fdcan2_tx_pb13 &fdcan2_rx_pb5>; + pinctrl-names = "default"; + clocks = <&rcc STM32_CLOCK_BUS_APB1_2 0x00000100>, + <&rcc STM32_SRC_PLL2_Q FDCAN_SEL(2)>; + sample-point = <875>; + sample-point-data = <875>; + + can-transceiver { + max-bitrate = <5000000>; + }; +}; + +&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/st/stm32h745i_disco/stm32h745i_disco_stm32h745xx_m7.yaml b/boards/st/stm32h745i_disco/stm32h745i_disco_stm32h745xx_m7.yaml new file mode 100644 index 00000000000..ba7f0e8d940 --- /dev/null +++ b/boards/st/stm32h745i_disco/stm32h745i_disco_stm32h745xx_m7.yaml @@ -0,0 +1,24 @@ +identifier: stm32h745i_disco/stm32h745xx/m7 +name: STM32H745XI Discovery (M7) +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb +ram: 512 +flash: 1024 +supported: + - arduino_gpio + - arduino_i2c + - uart + - gpio + - counter + - i2c + - pwm + - netif:eth + - qspi + - memc + - spi + - rtc + - can +vendor: st diff --git a/boards/st/stm32h745i_disco/stm32h745i_disco_stm32h745xx_m7_defconfig b/boards/st/stm32h745i_disco/stm32h745i_disco_stm32h745xx_m7_defconfig new file mode 100644 index 00000000000..f3ba3ad3b2a --- /dev/null +++ b/boards/st/stm32h745i_disco/stm32h745i_disco_stm32h745xx_m7_defconfig @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright (c) 2020 Alexander Kozhinov +# Copyright (c) 2024 Tomas Jurena + +# Enable the internal SMPS regulator +CONFIG_POWER_SUPPLY_DIRECT_SMPS=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable HW stack protection +CONFIG_HW_STACK_PROTECTION=y + +# Enable UART ( disable to assign to M4 core) +CONFIG_SERIAL=y + +# Console ( disable to assign to M4 core) +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# Enable GPIO +CONFIG_GPIO=y + +# Enable Clock +CONFIG_CLOCK_CONTROL=y + +# enable pin controller +CONFIG_PINCTRL=y diff --git a/boards/st/stm32h745i_disco/support/openocd.cfg b/boards/st/stm32h745i_disco/support/openocd.cfg new file mode 100644 index 00000000000..cd2f2e5753b --- /dev/null +++ b/boards/st/stm32h745i_disco/support/openocd.cfg @@ -0,0 +1,30 @@ +# STM32H745XI DISCOVERY board OpenOCD ST-LINK V3 configuration +# +# Copyright (c) 2020 Alexander Kozhinov +# Copyright (c) 2024 Tomas Jurena +# SPDX-License-Identifier: Apache-2.0 +# + +source [find board/stm32h745i-disco.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/st/stm32h747i_disco/stm32h747i_disco_stm32h747xx_m7.dts b/boards/st/stm32h747i_disco/stm32h747i_disco_stm32h747xx_m7.dts index 8f27eb0f836..a660f92af17 100644 --- a/boards/st/stm32h747i_disco/stm32h747i_disco_stm32h747xx_m7.dts +++ b/boards/st/stm32h747i_disco/stm32h747i_disco_stm32h747xx_m7.dts @@ -130,9 +130,7 @@ */ status = "okay"; pinctrl-0 = <ð_ref_clk_pa1 - ð_mdio_pa2 ð_crs_dv_pa7 - ð_mdc_pc1 ð_rxd0_pc4 ð_rxd1_pc5 ð_tx_en_pg11 @@ -141,6 +139,18 @@ pinctrl-names = "default"; }; +&mdio { + status = "okay"; + pinctrl-0 = <ð_mdio_pa2 ð_mdc_pc1>; + pinctrl-names = "default"; + + ethernet-phy@0 { + compatible = "ethernet-phy"; + reg = <0x00>; + status = "okay"; + }; +}; + &rng { status = "okay"; }; diff --git a/boards/st/stm32h750b_dk/doc/index.rst b/boards/st/stm32h750b_dk/doc/index.rst index f295947a334..e450488ed4d 100644 --- a/boards/st/stm32h750b_dk/doc/index.rst +++ b/boards/st/stm32h750b_dk/doc/index.rst @@ -55,6 +55,10 @@ The current Zephyr stm32h750b_dk board configuration supports the following hard +-----------+------------+-------------------------------------+ | GPIO | on-chip | gpio | +-----------+------------+-------------------------------------+ +| QSPI NOR | on-chip | off-chip flash | ++-----------+------------+-------------------------------------+ +| RTC | on-chip | rtc | ++-----------+------------+-------------------------------------+ Other hardware features are not yet supported on Zephyr porting. diff --git a/boards/st/stm32h750b_dk/stm32h750b_dk.dts b/boards/st/stm32h750b_dk/stm32h750b_dk.dts index 7cd328e90db..bb90724dead 100644 --- a/boards/st/stm32h750b_dk/stm32h750b_dk.dts +++ b/boards/st/stm32h750b_dk/stm32h750b_dk.dts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 STMicroelectronics + * Copyright (c) 2023-2024 STMicroelectronics * * SPDX-License-Identifier: Apache-2.0 */ @@ -64,6 +64,10 @@ status = "okay"; }; +&clk_lse { + status = "okay"; +}; + &pll { div-m = <5>; mul-n = <192>; @@ -163,3 +167,9 @@ }; }; }; + +&rtc { + clocks = <&rcc STM32_CLOCK_BUS_APB4 0x00010000>, + <&rcc STM32_SRC_LSE RTC_SEL(1)>; + status = "okay"; +}; diff --git a/boards/st/stm32h750b_dk/stm32h750b_dk.yaml b/boards/st/stm32h750b_dk/stm32h750b_dk.yaml index 126376b1464..ddca938bb51 100644 --- a/boards/st/stm32h750b_dk/stm32h750b_dk.yaml +++ b/boards/st/stm32h750b_dk/stm32h750b_dk.yaml @@ -12,4 +12,6 @@ supported: - arduino_gpio - gpio - dma + - flash + - rtc vendor: st diff --git a/boards/st/stm32h7b3i_dk/stm32h7b3i_dk.dts b/boards/st/stm32h7b3i_dk/stm32h7b3i_dk.dts index 1567585b2fd..88685817706 100644 --- a/boards/st/stm32h7b3i_dk/stm32h7b3i_dk.dts +++ b/boards/st/stm32h7b3i_dk/stm32h7b3i_dk.dts @@ -156,8 +156,6 @@ 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>; status = "okay"; }; diff --git a/boards/st/stm32l1_disco/Kconfig.stm32l152c_disco b/boards/st/stm32l1_disco/Kconfig.stm32l152c_disco new file mode 100644 index 00000000000..7f1b3d88742 --- /dev/null +++ b/boards/st/stm32l1_disco/Kconfig.stm32l152c_disco @@ -0,0 +1,5 @@ +# Copyright (c) 2024 Maxin John +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_STM32L152C_DISCO + select SOC_STM32L152XC diff --git a/boards/st/stm32l1_disco/board.yml b/boards/st/stm32l1_disco/board.yml index bdca72bf548..97a69b88157 100644 --- a/boards/st/stm32l1_disco/board.yml +++ b/boards/st/stm32l1_disco/board.yml @@ -1,5 +1,9 @@ -board: - name: stm32l1_disco - vendor: st - socs: - - name: stm32l151xb +boards: + - name: stm32l1_disco + vendor: st + socs: + - name: stm32l151xb + - name: stm32l152c_disco + vendor: st + socs: + - name: stm32l152xc diff --git a/boards/st/stm32l1_disco/doc/index.rst b/boards/st/stm32l1_disco/doc/index.rst index 4e64e94fa57..30911141f93 100644 --- a/boards/st/stm32l1_disco/doc/index.rst +++ b/boards/st/stm32l1_disco/doc/index.rst @@ -16,12 +16,13 @@ packaged software examples. There are two variants of the board: -- STM32LDISCOVERY targets STM32L152RBT6, with 128K flash, 16K RAM -- 32L152CDISCOVERY targets STM32L152RCT6, with 256K flash, 32K RAM +- STM32LDISCOVERY targets STM32L152RBT6, with 128K flash, 16K RAM, 4K EEPROM +- STM32L152CDISCOVERY targets STM32L152RCT6, with 256K flash, 32K RAM, 8K EEPROM + +The STM32LDISCOVERY is no longer sold, but was widely available. +stm32l1_disco configuration enables support for STM32LDISCOVERY board and +stm32l152c_disco configuration enables support for STM32L152CDISCOVERY board. -The STM32LDISCOVERY is no longer sold, but was widely available. The current -configuration assumes only 128K flash and 16K RAM, so it builds and runs -on both variants out of the box. .. image:: img/stm32l1_disco.jpg :align: center @@ -53,7 +54,8 @@ More information about STM32L151x can be found in the `STM32L1x reference manual Supported Features ================== -The Zephyr stm32l1_disco board configuration supports the following hardware features: +The Zephyr stm32l1_disco and stm32l152c_disco board configurations support +the following hardware features: .. list-table:: Supported hardware :header-rows: 1 @@ -95,9 +97,12 @@ The Zephyr stm32l1_disco board configuration supports the following hardware fea Other hardware features are not yet supported in this Zephyr port. -The default configuration can be found in +The configuration of stm32l1_disco can be found in :zephyr_file:`boards/st/stm32l1_disco/stm32l1_disco_defconfig` +Configuration of stm32l152c_disco can be found in +:zephyr_file:`boards/st/stm32l1_disco/stm32l152c_disco_defconfig` + Connections and IOs =================== @@ -140,8 +145,9 @@ flashed in the usual way (see :ref:`build_an_application` and Flashing ======== -STM32L1DISCOVERY board includes an ST-LINK/V2 embedded debug tool interface. -This interface is supported by the openocd version included in the Zephyr SDK. +STM32L1DISCOVERY and STM32L152CDISCOVERY boards include an ST-LINK/V2 embedded +debug tool interface. This interface is supported by the openocd version +included in the Zephyr SDK. Flashing an application ----------------------- @@ -180,3 +186,6 @@ References .. _STM32L1DISCOVERY board User Manual: https://www.st.com/resource/en/user_manual/dm00027954.pdf + +.. _STM32L152CDISCOVERY board User Manual: + https://www.st.com/resource/en/user_manual/um1079-discovery-kit-with-stm32l152rc-mcu-stmicroelectronics.pdf diff --git a/boards/st/stm32l1_disco/stm32l152c_disco.dts b/boards/st/stm32l1_disco/stm32l152c_disco.dts new file mode 100644 index 00000000000..3e989ea5da7 --- /dev/null +++ b/boards/st/stm32l1_disco/stm32l152c_disco.dts @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2024 Maxin John + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include +#include + +/ { + model = "STMicroelectronics STM32L152CDISCOVERY board"; + compatible = "st,stm32l1discovery"; + + chosen { + zephyr,console = &usart1; + zephyr,shell-uart = &usart1; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + }; + + leds { + compatible = "gpio-leds"; + green_led: ld3 { + gpios = <&gpiob 7 GPIO_ACTIVE_HIGH>; + label = "User LD3"; + }; + blue_led: ld4 { + gpios = <&gpiob 6 GPIO_ACTIVE_HIGH>; + label = "User LD4"; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + user_button: button { + label = "User"; + gpios = <&gpioa 0 GPIO_ACTIVE_LOW>; + zephyr,code = ; + }; + }; + + aliases { + led0 = &green_led; + led1 = &blue_led; + sw0 = &user_button; + }; +}; + +&clk_lsi { + status = "okay"; +}; + +&clk_hsi { + status = "okay"; +}; + +&pll { + div = <4>; + mul = <8>; + /* out of the box, MCO from stlink is not enabled, unlike later discos */ + clocks = <&clk_hsi>; + status = "okay"; +}; + +&rcc { + clocks = <&pll>; + clock-frequency = ; + ahb-prescaler = <1>; + apb1-prescaler = <1>; + apb2-prescaler = <1>; +}; + +&usart1 { + pinctrl-0 = <&usart1_tx_pa9 &usart1_rx_pa10>; + pinctrl-names = "default"; + current-speed = <115200>; + status = "okay"; +}; + +&usart2 { + pinctrl-0 = <&usart2_tx_pa2 &usart2_rx_pa3>; + pinctrl-names = "default"; + current-speed = <115200>; + status = "okay"; +}; + +&usart3 { + pinctrl-0 = <&usart3_tx_pb10 &usart3_rx_pb11>; + pinctrl-names = "default"; + current-speed = <115200>; + status = "okay"; +}; + +&i2c1 { + pinctrl-0 = <&i2c1_scl_pb6 &i2c1_sda_pb7>; + pinctrl-names = "default"; + status = "okay"; + clock-frequency = ; +}; + +&i2c2 { + pinctrl-0 = <&i2c2_scl_pb10 &i2c2_sda_pb11>; + pinctrl-names = "default"; + status = "okay"; + clock-frequency = ; +}; + +&spi1 { + pinctrl-0 = <&spi1_nss_pa4 &spi1_sck_pa5 + &spi1_miso_pa6 &spi1_mosi_pa7>; + pinctrl-names = "default"; + status = "okay"; +}; + +&spi2 { + pinctrl-0 = <&spi2_nss_pb12 &spi2_sck_pb13 + &spi2_miso_pb14 &spi2_mosi_pb15>; + pinctrl-names = "default"; + status = "okay"; +}; + +&rtc { + clocks = <&rcc STM32_CLOCK_BUS_APB1 0x10000000>, + <&rcc STM32_SRC_LSI RTC_SEL(2)>; + status = "okay"; + + backup_regs { + status = "okay"; + }; +}; diff --git a/boards/st/stm32l1_disco/stm32l152c_disco.yaml b/boards/st/stm32l1_disco/stm32l152c_disco.yaml new file mode 100644 index 00000000000..9ada265eed0 --- /dev/null +++ b/boards/st/stm32l1_disco/stm32l152c_disco.yaml @@ -0,0 +1,15 @@ +identifier: stm32l152c_disco +name: ST STM32L152C Discovery +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +ram: 32 +flash: 256 +supported: + - gpio + - i2c + - spi +vendor: st diff --git a/boards/st/stm32l1_disco/stm32l152c_disco_defconfig b/boards/st/stm32l1_disco/stm32l152c_disco_defconfig new file mode 100644 index 00000000000..fd0afcb9d74 --- /dev/null +++ b/boards/st/stm32l1_disco/stm32l152c_disco_defconfig @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: Apache-2.0 + +# enable uart driver +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/st/stm32l496g_disco/stm32l496g_disco.yaml b/boards/st/stm32l496g_disco/stm32l496g_disco.yaml index 3544d15980c..15301e002c7 100644 --- a/boards/st/stm32l496g_disco/stm32l496g_disco.yaml +++ b/boards/st/stm32l496g_disco/stm32l496g_disco.yaml @@ -15,7 +15,6 @@ supported: - spi - gpio - counter - - sdhc - adc - qspi vendor: st diff --git a/boards/st/stm32l4r9i_disco/stm32l4r9i_disco.yaml b/boards/st/stm32l4r9i_disco/stm32l4r9i_disco.yaml index 89ab98c92b1..81d844caf75 100644 --- a/boards/st/stm32l4r9i_disco/stm32l4r9i_disco.yaml +++ b/boards/st/stm32l4r9i_disco/stm32l4r9i_disco.yaml @@ -18,7 +18,6 @@ supported: - i2c - pwm - rtc - - sdhc - spi - uart - usb diff --git a/boards/st/stm32l562e_dk/Kconfig.defconfig b/boards/st/stm32l562e_dk/Kconfig.defconfig index 3f15027bb35..5dea5bc3a74 100644 --- a/boards/st/stm32l562e_dk/Kconfig.defconfig +++ b/boards/st/stm32l562e_dk/Kconfig.defconfig @@ -21,7 +21,7 @@ config BT_BLUENRG_ACI config BT_HCI_ACL_FLOW_CONTROL default n -config BT_HCI_VS_EXT +config BT_HCI_VS default n endif # BT diff --git a/boards/st/stm32l562e_dk/stm32l562e_dk.yaml b/boards/st/stm32l562e_dk/stm32l562e_dk.yaml index dcbe7539d64..c2acb4cb098 100644 --- a/boards/st/stm32l562e_dk/stm32l562e_dk.yaml +++ b/boards/st/stm32l562e_dk/stm32l562e_dk.yaml @@ -19,7 +19,6 @@ supported: - dma - usart - arduino_spi - - sdhc - usb - usb_device - nvs diff --git a/boards/st/stm32l562e_dk/stm32l562e_dk_stm32l562xx_ns.yaml b/boards/st/stm32l562e_dk/stm32l562e_dk_stm32l562xx_ns.yaml index c092f8da95d..50d239c805b 100644 --- a/boards/st/stm32l562e_dk/stm32l562e_dk_stm32l562xx_ns.yaml +++ b/boards/st/stm32l562e_dk/stm32l562e_dk_stm32l562xx_ns.yaml @@ -13,7 +13,6 @@ supported: - dac - spi - arduino_spi - - sdhc - usb - usb_device ram: 192 diff --git a/boards/st/stm32u5a9j_dk/doc/index.rst b/boards/st/stm32u5a9j_dk/doc/index.rst index aed555a4057..7e3d638fa3e 100644 --- a/boards/st/stm32u5a9j_dk/doc/index.rst +++ b/boards/st/stm32u5a9j_dk/doc/index.rst @@ -83,6 +83,10 @@ hardware features: +-----------+------------+-------------------------------------+ | PWM | on-chip | pwm | +-----------+------------+-------------------------------------+ +| TIMER | on-chip | counter | ++-----------+------------+-------------------------------------+ +| RTC | on-chip | rtc | ++-----------+------------+-------------------------------------+ Other hardware features have not been enabled yet for this board. diff --git a/boards/st/stm32u5a9j_dk/stm32u5a9j_dk.dts b/boards/st/stm32u5a9j_dk/stm32u5a9j_dk.dts index 6f80a4061a4..05bdfdd34eb 100644 --- a/boards/st/stm32u5a9j_dk/stm32u5a9j_dk.dts +++ b/boards/st/stm32u5a9j_dk/stm32u5a9j_dk.dts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 STMicroelectronics + * Copyright (c) 2023-2024 STMicroelectronics * * SPDX-License-Identifier: Apache-2.0 */ @@ -89,6 +89,10 @@ msi-pll-mode; }; +&clk_lse { + status = "okay"; +}; + &pll1 { div-m = <1>; mul-n = <80>; @@ -186,6 +190,7 @@ uart0: &usart3 { }; }; +/* Connected to onboard 4-Gbyte eMMC flash memory */ &sdmmc1 { pinctrl-0 = <&sdmmc1_d0_pc8 &sdmmc1_d1_pc9 &sdmmc1_d2_pc10 &sdmmc1_d3_pc11 @@ -196,14 +201,6 @@ uart0: &usart3 { 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"; @@ -278,6 +275,12 @@ uart0: &usart3 { }; }; +&rtc { + clocks = <&rcc STM32_CLOCK_BUS_APB3 0x00200000>, + <&rcc STM32_SRC_LSE RTC_SEL(1)>; + status = "okay"; +}; + &iwdg { status = "okay"; }; diff --git a/boards/st/stm32u5a9j_dk/stm32u5a9j_dk.yaml b/boards/st/stm32u5a9j_dk/stm32u5a9j_dk.yaml index 82ada8651e9..792eda8a7b7 100644 --- a/boards/st/stm32u5a9j_dk/stm32u5a9j_dk.yaml +++ b/boards/st/stm32u5a9j_dk/stm32u5a9j_dk.yaml @@ -18,6 +18,9 @@ supported: - i2c - flash - sdmmc + - timer + - rng + - rtc ram: 2496 flash: 4096 vendor: st diff --git a/boards/st/stm32wb5mm_dk/doc/stm32wb5mm_dk.rst b/boards/st/stm32wb5mm_dk/doc/stm32wb5mm_dk.rst index a149ea79a36..51bde0110c5 100644 --- a/boards/st/stm32wb5mm_dk/doc/stm32wb5mm_dk.rst +++ b/boards/st/stm32wb5mm_dk/doc/stm32wb5mm_dk.rst @@ -170,6 +170,14 @@ Serial Port STM32WB5MM-DK board has 2 (LP)U(S)ARTs. The Zephyr console output is assigned to USART1. Default settings are ``115200 8N1``. +LEDs +---- +STM32WB5MM-DK has two types of LEDs, The resources coming from STM32WB5MMG are +shared between the RGB and IR LEDs. It is not possible to use them +simultaneously. The selection is done by JP4 and JP5 jumpers. +To use the RGB LED, JP5 must be ON and JP4 OFF. In this configuration, +GPIO_SELECT2 (PH1) is the chip select for this RGB device on SPI1. + Programming and Debugging ************************* diff --git a/boards/st/stm32wb5mm_dk/stm32wb5mm_dk.dts b/boards/st/stm32wb5mm_dk/stm32wb5mm_dk.dts index 4f4fb99cea0..6e48823ae24 100644 --- a/boards/st/stm32wb5mm_dk/stm32wb5mm_dk.dts +++ b/boards/st/stm32wb5mm_dk/stm32wb5mm_dk.dts @@ -8,6 +8,7 @@ #include #include #include +#include / { model = "STMicroelectronics STM32WB5MM Discovery Development Kit"; @@ -22,11 +23,23 @@ zephyr,flash = &flash0; zephyr,code-partition = &slot0_partition; }; + + rgb_led_strip: rgb_strip { + compatible = "ti,tlc59731"; + gpios = <&gpioa 7 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>; + chain-length = <1>; + color-mapping = ; + status = "disabled"; + }; + aliases { watchdog0 = &iwdg; die-temp0 = &die_temp; volt-sensor0 = &vref; volt-sensor1 = &vbat; + led-strip = &rgb_led_strip; }; }; @@ -136,6 +149,15 @@ zephyr_udc0: &usb { }; }; +&gpioh { + rgb_cs: rgb_cs { + gpios = <1 GPIO_ACTIVE_HIGH>; + gpio-hog; + output-high; + status = "disabled"; + }; +}; + &vref { status = "okay"; }; diff --git a/boards/vcc-gnd/yd_esp32/yd_esp32_esp32_appcpu.dts b/boards/vcc-gnd/yd_esp32/yd_esp32_appcpu.dts similarity index 100% rename from boards/vcc-gnd/yd_esp32/yd_esp32_esp32_appcpu.dts rename to boards/vcc-gnd/yd_esp32/yd_esp32_appcpu.dts diff --git a/boards/vcc-gnd/yd_esp32/yd_esp32_appcpu.yaml b/boards/vcc-gnd/yd_esp32/yd_esp32_appcpu.yaml new file mode 100644 index 00000000000..20e2f1a74c6 --- /dev/null +++ b/boards/vcc-gnd/yd_esp32/yd_esp32_appcpu.yaml @@ -0,0 +1,27 @@ +identifier: yd_esp32/esp32/appcpu +name: YD-ESP32 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/vcc-gnd/yd_esp32/yd_esp32_esp32_appcpu_defconfig b/boards/vcc-gnd/yd_esp32/yd_esp32_appcpu_defconfig similarity index 100% rename from boards/vcc-gnd/yd_esp32/yd_esp32_esp32_appcpu_defconfig rename to boards/vcc-gnd/yd_esp32/yd_esp32_appcpu_defconfig diff --git a/boards/vcc-gnd/yd_esp32/yd_esp32_esp32_appcpu.yaml b/boards/vcc-gnd/yd_esp32/yd_esp32_esp32_appcpu.yaml deleted file mode 100644 index 018b3c2b727..00000000000 --- a/boards/vcc-gnd/yd_esp32/yd_esp32_esp32_appcpu.yaml +++ /dev/null @@ -1,27 +0,0 @@ -identifier: yd_esp32/esp32/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/vcc-gnd/yd_esp32/yd_esp32_esp32_procpu.yaml b/boards/vcc-gnd/yd_esp32/yd_esp32_esp32_procpu.yaml deleted file mode 100644 index b3fc0cdf97d..00000000000 --- a/boards/vcc-gnd/yd_esp32/yd_esp32_esp32_procpu.yaml +++ /dev/null @@ -1,24 +0,0 @@ -identifier: yd_esp32/esp32/procpu -name: YD-ESP32 -type: mcu -arch: xtensa -toolchain: - - zephyr -supported: - - adc - - dac - - gpio - - i2c - - watchdog - - uart - - nvs - - pwm - - dac - - spi - - counter - - entropy -testing: - ignore_tags: - - net - - bluetooth -vendor: vcc-gnd diff --git a/boards/vcc-gnd/yd_esp32/yd_esp32_esp32_procpu.dts b/boards/vcc-gnd/yd_esp32/yd_esp32_procpu.dts similarity index 100% rename from boards/vcc-gnd/yd_esp32/yd_esp32_esp32_procpu.dts rename to boards/vcc-gnd/yd_esp32/yd_esp32_procpu.dts diff --git a/boards/vcc-gnd/yd_esp32/yd_esp32_procpu.yaml b/boards/vcc-gnd/yd_esp32/yd_esp32_procpu.yaml new file mode 100644 index 00000000000..7e8e17cf71f --- /dev/null +++ b/boards/vcc-gnd/yd_esp32/yd_esp32_procpu.yaml @@ -0,0 +1,24 @@ +identifier: yd_esp32/esp32/procpu +name: YD-ESP32 PROCPU +type: mcu +arch: xtensa +toolchain: + - zephyr +supported: + - adc + - dac + - gpio + - i2c + - watchdog + - uart + - nvs + - pwm + - dac + - spi + - counter + - entropy +testing: + ignore_tags: + - net + - bluetooth +vendor: vcc-gnd diff --git a/boards/vcc-gnd/yd_esp32/yd_esp32_esp32_procpu_defconfig b/boards/vcc-gnd/yd_esp32/yd_esp32_procpu_defconfig similarity index 100% rename from boards/vcc-gnd/yd_esp32/yd_esp32_esp32_procpu_defconfig rename to boards/vcc-gnd/yd_esp32/yd_esp32_procpu_defconfig diff --git a/boards/waveshare/esp32s3_touch_lcd_1_28/Kconfig b/boards/waveshare/esp32s3_touch_lcd_1_28/Kconfig new file mode 100644 index 00000000000..e6b26bf1d67 --- /dev/null +++ b/boards/waveshare/esp32s3_touch_lcd_1_28/Kconfig @@ -0,0 +1,6 @@ +# Copyright (c) 2024 Joel Guittet +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_ESP32S3_TOUCH_LCD_1_28 + select SOC_ESP32S3_PROCPU if BOARD_ESP32S3_TOUCH_LCD_1_28_ESP32S3_PROCPU + select SOC_ESP32S3_APPCPU if BOARD_ESP32S3_TOUCH_LCD_1_28_ESP32S3_APPCPU diff --git a/boards/waveshare/esp32s3_touch_lcd_1_28/Kconfig.defconfig b/boards/waveshare/esp32s3_touch_lcd_1_28/Kconfig.defconfig new file mode 100644 index 00000000000..33296a8e529 --- /dev/null +++ b/boards/waveshare/esp32s3_touch_lcd_1_28/Kconfig.defconfig @@ -0,0 +1,36 @@ +# Copyright (c) 2024 Joel Guittet +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_ESP32S3_TOUCH_LCD_1_28_ESP32S3_PROCPU + +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_ESP32S3_TOUCH_LCD_1_28_ESP32S3_PROCPU + +if BOARD_ESP32S3_TOUCH_LCD_1_28_ESP32S3_APPCPU + +config HEAP_MEM_POOL_ADD_SIZE_BOARD + default 256 + +endif # BOARD_ESP32S3_TOUCH_LCD_1_28_ESP32S3_APPCPU + +config ENTROPY_GENERATOR + default y + +config KERNEL_MEM_POOL + default y + +config PWM + default y if DISPLAY + +config LV_COLOR_16_SWAP + default y if LVGL diff --git a/boards/waveshare/esp32s3_touch_lcd_1_28/Kconfig.esp32s3_touch_lcd_1_28 b/boards/waveshare/esp32s3_touch_lcd_1_28/Kconfig.esp32s3_touch_lcd_1_28 new file mode 100644 index 00000000000..b62dd557d26 --- /dev/null +++ b/boards/waveshare/esp32s3_touch_lcd_1_28/Kconfig.esp32s3_touch_lcd_1_28 @@ -0,0 +1,5 @@ +# Copyright (c) 2024 Joel Guittet +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_ESP32S3_TOUCH_LCD_1_28 + select SOC_ESP32S3_R2 diff --git a/boards/waveshare/esp32s3_touch_lcd_1_28/board.cmake b/boards/waveshare/esp32s3_touch_lcd_1_28/board.cmake new file mode 100644 index 00000000000..b822d4b0833 --- /dev/null +++ b/boards/waveshare/esp32s3_touch_lcd_1_28/board.cmake @@ -0,0 +1,10 @@ +# Copyright (c) 2024 Joel Guittet +# 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/waveshare/esp32s3_touch_lcd_1_28/board.yml b/boards/waveshare/esp32s3_touch_lcd_1_28/board.yml new file mode 100644 index 00000000000..821fd367821 --- /dev/null +++ b/boards/waveshare/esp32s3_touch_lcd_1_28/board.yml @@ -0,0 +1,5 @@ +board: + name: esp32s3_touch_lcd_1_28 + vendor: waveshare + socs: + - name: esp32s3 diff --git a/boards/waveshare/esp32s3_touch_lcd_1_28/doc/index.rst b/boards/waveshare/esp32s3_touch_lcd_1_28/doc/index.rst new file mode 100644 index 00000000000..3395bcff2ee --- /dev/null +++ b/boards/waveshare/esp32s3_touch_lcd_1_28/doc/index.rst @@ -0,0 +1,123 @@ +.. _esp32s3_touch_lcd_1_28: + +Waveshare ESP32-S3-Touch-LCD-1.28 +################################# + +Overview +******** + +The ESP32-S3-Touch-LCD-1.28 is an ESP32S3 development board from Waveshare with a round LCD, +suitable to build watches or similar projects. This board integrates complete Wi-Fi and Bluetooth +Low Energy functions, an accelerometer and gyroscope, a battery charger and GPIO extension port. + +Hardware +******** + +ESP32-S3 is a low-power MCU-based system on a chip (SoC) with integrated 2.4 GHz Wi-Fi +and BluetoothĀ® Low Energy (Bluetooth LE). It consists of high-performance dual-core microprocessor +(XtensaĀ® 32-bit LX7), a low power coprocessor, a Wi-Fi baseband, a Bluetooth LE baseband, +RF module, and numerous peripherals. + +ESP32-S3-Touch-LCD-1.28 includes the following features: + +- Dual core 32-bit Xtensa Microprocessor (Tensilica LX7), running up to 240MHz +- Additional vector instructions support for AI acceleration +- 2MB of SRAM +- 16MB of FLASH +- Wi-Fi 802.11b/g/n +- Bluetooth LE 5.0 with long-range support and up to 2Mbps data rate +- Round 1.28" LCD with touchscreen controller +- Accelerometer/gyroscope +- Battery charger + +Digital interfaces: + +- 6 programmable GPIOs +- 2 open-drain outputs + +Low Power: + +- Power Management Unit with five power modes +- Ultra-Low-Power (ULP) coprocessors: ULP-RISC-V and ULP-FSM + +Security: + +- Secure boot +- Flash encryption +- 4-Kbit OTP, up to 1792 bits for users +- Cryptographic hardware acceleration: (AES-128/256, Hash, RSA, RNG, HMAC, Digital signature) + +Asymmetric Multiprocessing (AMP) +******************************** + +ESP32-S3 allows 2 different applications to be executed in ESP32-S3 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. + +For more information, check the datasheet at `ESP32-S3 Datasheet`_. + +Supported Features +================== + +Current Zephyr's ESP32-S3-Touch-LCD-1.28 board supports the following features: + ++------------+------------+-------------------------------------+ +| Interface | Controller | Driver/Component | ++============+============+=====================================+ +| UART | on-chip | serial port | ++------------+------------+-------------------------------------+ +| GPIO | on-chip | gpio | ++------------+------------+-------------------------------------+ +| PINMUX | on-chip | pinmux | ++------------+------------+-------------------------------------+ +| SPI Master | on-chip | spi | ++------------+------------+-------------------------------------+ +| TWAI/CAN | on-chip | can | ++------------+------------+-------------------------------------+ +| ADC | on-chip | adc | ++------------+------------+-------------------------------------+ +| Timers | on-chip | counter | ++------------+------------+-------------------------------------+ +| Watchdog | on-chip | watchdog | ++------------+------------+-------------------------------------+ +| TRNG | on-chip | entropy | ++------------+------------+-------------------------------------+ +| LEDC | on-chip | pwm | ++------------+------------+-------------------------------------+ +| MCPWM | on-chip | pwm | ++------------+------------+-------------------------------------+ +| PCNT | on-chip | qdec | ++------------+------------+-------------------------------------+ +| GDMA | on-chip | dma | ++------------+------------+-------------------------------------+ + +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 +******************* + +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. + +References +********** + +.. _ESP32-S3-Touch-LCD-1.28 Waveshare Wiki: https://www.waveshare.com/wiki/ESP32-S3-Touch-LCD-1.28 +.. _ESP32-S3 Datasheet: https://www.espressif.com/sites/default/files/documentation/esp32-s3-mini-1_mini-1u_datasheet_en.pdf +.. _ESP32 Technical Reference Manual: https://www.espressif.com/sites/default/files/documentation/esp32-s3_technical_reference_manual_en.pdf diff --git a/boards/waveshare/esp32s3_touch_lcd_1_28/esp32s3_touch_lcd_1_28-pinctrl.dtsi b/boards/waveshare/esp32s3_touch_lcd_1_28/esp32s3_touch_lcd_1_28-pinctrl.dtsi new file mode 100644 index 00000000000..8bb1a06d8b7 --- /dev/null +++ b/boards/waveshare/esp32s3_touch_lcd_1_28/esp32s3_touch_lcd_1_28-pinctrl.dtsi @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2024 Joel Guittet + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +&pinctrl { + + i2c1_default: i2c1_default { + group1 { + pinmux = , ; + bias-pull-up; + drive-open-drain; + output-high; + }; + }; + + ledc0_default: ledc0_default { + group1 { + pinmux = , , ; + output-enable; + }; + }; + + spim2_default: spim2_default { + group1 { + pinmux = , , ; + }; + group2 { + pinmux = ; + output-low; + }; + }; + + uart0_default: uart0_default { + group1 { + pinmux = ; + output-high; + }; + group2 { + pinmux = ; + bias-pull-up; + }; + }; +}; diff --git a/boards/waveshare/esp32s3_touch_lcd_1_28/esp32s3_touch_lcd_1_28_esp32s3_appcpu.dts b/boards/waveshare/esp32s3_touch_lcd_1_28/esp32s3_touch_lcd_1_28_esp32s3_appcpu.dts new file mode 100644 index 00000000000..50301f22c20 --- /dev/null +++ b/boards/waveshare/esp32s3_touch_lcd_1_28/esp32s3_touch_lcd_1_28_esp32s3_appcpu.dts @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2024 Joel Guittet + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include + +/ { + model = "ESP32-S3-Touch-LCD-1.28 APPCPU"; + compatible = "waveshare,esp32-s3-touch-lcd-1.28"; + + chosen { + zephyr,sram = &sram0; + }; +}; + +&cpu0 { + clock-frequency = ; +}; + +&cpu1 { + clock-frequency = ; +}; + +&flash0 { + status = "okay"; + reg = <0x0 DT_SIZE_M(16)>; + + 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>; + }; + }; +}; + +&trng0 { + status = "okay"; +}; diff --git a/boards/waveshare/esp32s3_touch_lcd_1_28/esp32s3_touch_lcd_1_28_esp32s3_appcpu.yaml b/boards/waveshare/esp32s3_touch_lcd_1_28/esp32s3_touch_lcd_1_28_esp32s3_appcpu.yaml new file mode 100644 index 00000000000..c42258133ae --- /dev/null +++ b/boards/waveshare/esp32s3_touch_lcd_1_28/esp32s3_touch_lcd_1_28_esp32s3_appcpu.yaml @@ -0,0 +1,27 @@ +identifier: esp32s3_touch_lcd_1_28/esp32s3/appcpu +name: ESP32-S3-Touch-LCD-1.28 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: waveshare diff --git a/boards/waveshare/esp32s3_touch_lcd_1_28/esp32s3_touch_lcd_1_28_esp32s3_appcpu_defconfig b/boards/waveshare/esp32s3_touch_lcd_1_28/esp32s3_touch_lcd_1_28_esp32s3_appcpu_defconfig new file mode 100644 index 00000000000..a2196414381 --- /dev/null +++ b/boards/waveshare/esp32s3_touch_lcd_1_28/esp32s3_touch_lcd_1_28_esp32s3_appcpu_defconfig @@ -0,0 +1,6 @@ +# Copyright (c) 2024 Joel Guittet +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_MAIN_STACK_SIZE=2048 +CONFIG_CLOCK_CONTROL=y +CONFIG_MINIMAL_LIBC=y diff --git a/boards/waveshare/esp32s3_touch_lcd_1_28/esp32s3_touch_lcd_1_28_esp32s3_procpu.dts b/boards/waveshare/esp32s3_touch_lcd_1_28/esp32s3_touch_lcd_1_28_esp32s3_procpu.dts new file mode 100644 index 00000000000..346c522142f --- /dev/null +++ b/boards/waveshare/esp32s3_touch_lcd_1_28/esp32s3_touch_lcd_1_28_esp32s3_procpu.dts @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2024 Joel Guittet + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include "esp32s3_touch_lcd_1_28-pinctrl.dtsi" +#include +#include +#include + +/ { + model = "ESP32-S3-Touch-LCD-1.28 PROCPU"; + compatible = "waveshare,esp32-s3-touch-lcd-1.28"; + + aliases { + i2c-1 = &i2c1; + pwm-0 = &ledc0; + pwm-lcd0 = &pwm_lcd0; + sw0 = &button0; + uart-0 = &uart0; + watchdog0 = &wdt0; + }; + + chosen { + zephyr,sram = &sram0; + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; + zephyr,display = &gc9a01; + }; + + /* Buttons */ + buttons { + compatible = "gpio-keys"; + button0: button_0 { + gpios = <&gpio0 0 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "BOOT Button"; + zephyr,code = ; + }; + }; + + /* Touch Controller */ + lvgl_pointer { + compatible = "zephyr,lvgl-pointer-input"; + input = <&cst816s>; + }; + + /* PWM */ + pwmleds { + compatible = "pwm-leds"; + pwm_lcd0: pwm_lcd0 { + pwms = <&ledc0 0 PWM_HZ(250) PWM_POLARITY_NORMAL>; + }; + }; +}; + +&cpu0 { + clock-frequency = ; +}; + +&cpu1 { + clock-frequency = ; +}; + +&flash0 { + status = "okay"; + reg = <0x0 DT_SIZE_M(16)>; + + 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>; + }; + }; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&i2c1 { + status ="okay"; + clock-frequency = ; + pinctrl-0 = <&i2c1_default>; + pinctrl-names = "default"; + + /* Hynitron CST816S Capacitive Touch Controller */ + cst816s: cst816s@15 { + status = "okay"; + compatible = "hynitron,cst816s"; + reg = <0x15>; + irq-gpios = <&gpio0 5 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + rst-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>; + }; +}; + +&ledc0 { + status = "okay"; + pinctrl-0 = <&ledc0_default>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + channel0@0 { + reg = <0x0>; + timer = <0>; + }; + channel1@1 { + reg = <0x1>; + timer = <1>; + }; + channel2@2 { + reg = <0x2>; + timer = <2>; + }; +}; + +&spi2 { + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + pinctrl-0 = <&spim2_default>; + pinctrl-names = "default"; + cs-gpios = <&gpio0 9 GPIO_ACTIVE_LOW>; + + gc9a01: gc9a01@0 { + status = "okay"; + compatible = "galaxycore,gc9x01x"; + reg = <0>; + spi-max-frequency = <100000000>; + cmd-data-gpios = <&gpio0 8 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpio0 14 GPIO_ACTIVE_LOW>; + pixel-format = ; + display-inversion; + width = <240>; + height = <240>; + }; +}; + +&trng0 { + status = "okay"; +}; + +&uart0 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart0_default>; + pinctrl-names = "default"; +}; + +&wdt0 { + status = "okay"; +}; diff --git a/boards/waveshare/esp32s3_touch_lcd_1_28/esp32s3_touch_lcd_1_28_esp32s3_procpu.yaml b/boards/waveshare/esp32s3_touch_lcd_1_28/esp32s3_touch_lcd_1_28_esp32s3_procpu.yaml new file mode 100644 index 00000000000..5c81ff792a3 --- /dev/null +++ b/boards/waveshare/esp32s3_touch_lcd_1_28/esp32s3_touch_lcd_1_28_esp32s3_procpu.yaml @@ -0,0 +1,22 @@ +identifier: esp32s3_touch_lcd_1_28/esp32s3/procpu +name: ESP32-S3-Touch-LCD-1.28 PROCPU +type: mcu +arch: xtensa +toolchain: + - zephyr +supported: + - gpio + - i2c + - spi + - watchdog + - regulator + - uart + - pwm + - pinmux + - nvs + - display +testing: + ignore_tags: + - net + - bluetooth +vendor: waveshare diff --git a/boards/waveshare/esp32s3_touch_lcd_1_28/esp32s3_touch_lcd_1_28_esp32s3_procpu_defconfig b/boards/waveshare/esp32s3_touch_lcd_1_28/esp32s3_touch_lcd_1_28_esp32s3_procpu_defconfig new file mode 100644 index 00000000000..50c7db47465 --- /dev/null +++ b/boards/waveshare/esp32s3_touch_lcd_1_28/esp32s3_touch_lcd_1_28_esp32s3_procpu_defconfig @@ -0,0 +1,12 @@ +# Copyright (c) 2024 Joel Guittet +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_MAIN_STACK_SIZE=2048 +CONFIG_GPIO=y +CONFIG_REGULATOR=y +CONFIG_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_UART_CONSOLE=y +CONFIG_CLOCK_CONTROL=y +CONFIG_INPUT=y +CONFIG_INPUT_CST816S_INTERRUPT=n diff --git a/boards/waveshare/esp32s3_touch_lcd_1_28/support/openocd.cfg b/boards/waveshare/esp32s3_touch_lcd_1_28/support/openocd.cfg new file mode 100644 index 00000000000..625341a5aa8 --- /dev/null +++ b/boards/waveshare/esp32s3_touch_lcd_1_28/support/openocd.cfg @@ -0,0 +1,10 @@ +# Copyright (c) 2024 Joel Guittet +# SPDX-License-Identifier: Apache-2.0 + +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/waveshare/open103z/waveshare_open103z.dts b/boards/waveshare/open103z/waveshare_open103z.dts index 6d2e4759548..72dd744c4c2 100644 --- a/boards/waveshare/open103z/waveshare_open103z.dts +++ b/boards/waveshare/open103z/waveshare_open103z.dts @@ -156,7 +156,6 @@ * reference: RM0008 rev20 page 205 */ status = "disabled"; - bus-speed = <125000>; }; zephyr_udc0: &usb { diff --git a/boards/weact/mini_stm32h743/mini_stm32h743.dts b/boards/weact/mini_stm32h743/mini_stm32h743.dts index 0f604ea3985..9aa6dcffc1b 100644 --- a/boards/weact/mini_stm32h743/mini_stm32h743.dts +++ b/boards/weact/mini_stm32h743/mini_stm32h743.dts @@ -88,11 +88,6 @@ pinctrl-names = "default"; cd-gpios = <&gpiod 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; status = "okay"; - - sdmmc { - compatible = "zephyr,sdmmc-disk"; - status = "okay"; - }; }; zephyr_udc0: &usbotg_fs { diff --git a/boards/weact/mini_stm32h743/mini_stm32h743.yaml b/boards/weact/mini_stm32h743/mini_stm32h743.yaml index 0ce1024b6d0..b92c045ee23 100644 --- a/boards/weact/mini_stm32h743/mini_stm32h743.yaml +++ b/boards/weact/mini_stm32h743/mini_stm32h743.yaml @@ -15,6 +15,5 @@ supported: - backup_sram - watchdog - usb - - sdhc - qspi vendor: weact diff --git a/cmake/bintools/arcmwdt/target.cmake b/cmake/bintools/arcmwdt/target.cmake index ea461771830..36f31fffba1 100644 --- a/cmake/bintools/arcmwdt/target.cmake +++ b/cmake/bintools/arcmwdt/target.cmake @@ -20,9 +20,16 @@ SET(CMAKE_C_ARCHIVE_FINISH " -sq ") find_program(CMAKE_GDB ${CROSS_COMPILE}mdb PATHS ${TOOLCHAIN_HOME} NO_DEFAULT_PATH) -# MWDT binutils don't support required features like section renaming, so we -# temporarily had to use GNU objcopy instead -find_program(CMAKE_OBJCOPY ${ZEPHYR_SDK_CROSS_COMPILE}objcopy PATHS ${ZEPHYR_SDK_INSTALL_DIR} NO_DEFAULT_PATH) -message(STATUS "Found GNU objcopy helper for MWDT: ${CMAKE_OBJCOPY} (Zephyr SDK ${SDK_VERSION})") +function(zephyr_sdk_target_cmake) + # Scoped loading of variables set by Zephyr SDK target.cmake. + include(${ZEPHYR_SDK_INSTALL_DIR}/cmake/zephyr/target.cmake) + + # MWDT binutils don't support required features like section renaming, so we + # temporarily had to use GNU objcopy instead + find_program(CMAKE_OBJCOPY ${CROSS_COMPILE}objcopy PATHS ${ZEPHYR_SDK_INSTALL_DIR} NO_DEFAULT_PATH) + message(STATUS "Found GNU objcopy helper for MWDT: ${CMAKE_OBJCOPY} (Zephyr SDK ${SDK_VERSION})") +endfunction() + +zephyr_sdk_target_cmake() include(${ZEPHYR_BASE}/cmake/bintools/arcmwdt/target_bintools.cmake) diff --git a/cmake/bintools/bintools_template.cmake b/cmake/bintools/bintools_template.cmake index 4b48ffe005a..6fa63080dd9 100644 --- a/cmake/bintools/bintools_template.cmake +++ b/cmake/bintools/bintools_template.cmake @@ -66,6 +66,7 @@ # elfconvert_flag_final : Flags that must always be applied last at the elfconvert command # elfconvert_flag_strip_all : Flag that is used for stripping all symbols when converting # elfconvert_flag_strip_debug : Flag that is used to strip debug symbols when converting +# elfconvert_flag_compress_debug_sections: Flag that is used to compress debug sections when converting # elfconvert_flag_intarget : Flag for specifying target used for infile # elfconvert_flag_outtarget : Flag for specifying target to use for converted file. # Target value must be one of those listed described by: elfconvert_formats @@ -141,6 +142,7 @@ set_property(TARGET bintools PROPERTY elfconvert_command ${CMAKE_COMMAND} -E ech set_property(TARGET bintools PROPERTY elfconvert_formats "") set_property(TARGET bintools PROPERTY elfconvert_flag "") set_property(TARGET bintools PROPERTY elfconvert_flag_final "") +set_property(TARGET bintools PROPERTY elfconvert_flag_compress_debug_sections "") set_property(TARGET bintools PROPERTY elfconvert_flag_outtarget "") set_property(TARGET bintools PROPERTY elfconvert_flag_section_remove "") set_property(TARGET bintools PROPERTY elfconvert_flag_gapfill "") diff --git a/cmake/bintools/gnu/target_bintools.cmake b/cmake/bintools/gnu/target_bintools.cmake index 8aac55b0400..f61860b31da 100644 --- a/cmake/bintools/gnu/target_bintools.cmake +++ b/cmake/bintools/gnu/target_bintools.cmake @@ -7,6 +7,7 @@ # elfconvert_flag_final : empty # elfconvert_flag_strip_all : -S # elfconvert_flag_strip_debug : -g +# elfconvert_flag_compress_debug_sections: --compress-debug-sections # elfconvert_flag_intarget : --input-target= # elfconvert_flag_outtarget : --output-target= # elfconvert_flag_section_remove: --remove-section= @@ -34,6 +35,8 @@ set_property(TARGET bintools PROPERTY elfconvert_flag_final "") set_property(TARGET bintools PROPERTY elfconvert_flag_strip_all "-S") set_property(TARGET bintools PROPERTY elfconvert_flag_strip_debug "-g") +set_property(TARGET bintools PROPERTY elfconvert_flag_compress_debug_sections "--compress-debug-sections") + set_property(TARGET bintools PROPERTY elfconvert_flag_intarget "--input-target=") set_property(TARGET bintools PROPERTY elfconvert_flag_outtarget "--output-target=") diff --git a/cmake/bintools/llvm/target_bintools.cmake b/cmake/bintools/llvm/target_bintools.cmake index 3a3e04e4388..cd3d55342b5 100644 --- a/cmake/bintools/llvm/target_bintools.cmake +++ b/cmake/bintools/llvm/target_bintools.cmake @@ -7,6 +7,7 @@ # elfconvert_flag_final : empty # elfconvert_flag_strip_all : -S # elfconvert_flag_strip_debug : -g +# elfconvert_flag_compress_debug_sections: --compress-debug-sections # elfconvert_flag_intarget : --input-target= # elfconvert_flag_outtarget : --output-target= # elfconvert_flag_section_remove: --remove-section= @@ -34,6 +35,8 @@ set_property(TARGET bintools PROPERTY elfconvert_flag_final "") set_property(TARGET bintools PROPERTY elfconvert_flag_strip_all "-S") set_property(TARGET bintools PROPERTY elfconvert_flag_strip_debug "-g") +set_property(TARGET bintools PROPERTY elfconvert_flag_compress_debug_sections "--compress-debug-sections") + set_property(TARGET bintools PROPERTY elfconvert_flag_intarget "--input-target=") set_property(TARGET bintools PROPERTY elfconvert_flag_outtarget "--output-target=") diff --git a/cmake/compiler/arcmwdt/compiler_flags.cmake b/cmake/compiler/arcmwdt/compiler_flags.cmake index 5383016795b..5d2be413dc8 100644 --- a/cmake/compiler/arcmwdt/compiler_flags.cmake +++ b/cmake/compiler/arcmwdt/compiler_flags.cmake @@ -1,5 +1,3 @@ -set_property(GLOBAL PROPERTY CSTD gnu99) - # List the warnings that are not supported for C++ compilations list(APPEND CXX_EXCLUDED_OPTIONS -Werror=implicit-int diff --git a/cmake/compiler/compiler_flags_template.cmake b/cmake/compiler/compiler_flags_template.cmake index 53e37287b9f..a18ef39d916 100644 --- a/cmake/compiler/compiler_flags_template.cmake +++ b/cmake/compiler/compiler_flags_template.cmake @@ -51,7 +51,7 @@ set_compiler_property(PROPERTY nostdinc) set_compiler_property(PROPERTY nostdinc_include) # Compiler flags for disabling C++ standard include. -set_compiler_property(TARGET compiler-cpp PROPERTY nostdincxx) +set_property(TARGET compiler-cpp PROPERTY nostdincxx) # Required C++ flags when compiling C++ code set_property(TARGET compiler-cpp PROPERTY required) diff --git a/cmake/compiler/gcc/compiler_flags.cmake b/cmake/compiler/gcc/compiler_flags.cmake index 14cd3e67889..be08cc18bad 100644 --- a/cmake/compiler/gcc/compiler_flags.cmake +++ b/cmake/compiler/gcc/compiler_flags.cmake @@ -121,7 +121,7 @@ endif() set_compiler_property(PROPERTY no_printf_return_value -fno-printf-return-value) -set_compiler_property(TARGET compiler-cpp PROPERTY nostdincxx "-nostdinc++") +set_property(TARGET compiler-cpp PROPERTY nostdincxx "-nostdinc++") # Required C++ flags when using gcc set_property(TARGET compiler-cpp PROPERTY required "-fcheck-new") diff --git a/cmake/compiler/gcc/target_arm.cmake b/cmake/compiler/gcc/target_arm.cmake index 77a718cc725..78e5fc94550 100644 --- a/cmake/compiler/gcc/target_arm.cmake +++ b/cmake/compiler/gcc/target_arm.cmake @@ -58,3 +58,12 @@ set(LLEXT_APPEND_FLAGS -mlong-calls -mthumb ) + +list(APPEND LLEXT_EDK_REMOVE_FLAGS + --sysroot=.* + -fmacro-prefix-map=.* + ) + +list(APPEND LLEXT_EDK_APPEND_FLAGS + -nodefaultlibs + ) diff --git a/cmake/compiler/host-gcc/target.cmake b/cmake/compiler/host-gcc/target.cmake index 41e36b99a27..9bc1d465057 100644 --- a/cmake/compiler/host-gcc/target.cmake +++ b/cmake/compiler/host-gcc/target.cmake @@ -36,3 +36,12 @@ foreach(file_name include/stddef.h) list(APPEND NOSTDINC ${_OUTPUT}) endforeach() + +list(APPEND LLEXT_EDK_REMOVE_FLAGS + --sysroot=.* + -fmacro-prefix-map=.* + ) + +list(APPEND LLEXT_EDK_APPEND_FLAGS + -nodefaultlibs + ) diff --git a/cmake/emu/nsim.cmake b/cmake/emu/nsim.cmake index a187cdad03e..323593fc1d8 100644 --- a/cmake/emu/nsim.cmake +++ b/cmake/emu/nsim.cmake @@ -13,14 +13,13 @@ if(CONFIG_MP_MAX_NUM_CPUS GREATER 1) set(MULTIFILES ${MDB} -multifiles=) foreach(val RANGE ${CONFIG_MP_MAX_NUM_CPUS}) if(val LESS CONFIG_MP_MAX_NUM_CPUS) - MATH(EXPR PSET_NUM "${CONFIG_MP_MAX_NUM_CPUS}-${val}") - MATH(EXPR CORE_NUM "${CONFIG_MP_MAX_NUM_CPUS}-${val}-1") - if(PSET_NUM GREATER 0) - list(APPEND MDB_OPTIONS &&) - endif() - list(APPEND MDB_OPTIONS ${MDB} -pset=${PSET_NUM} -psetname=core${CORE_NUM}) + MATH(EXPR PSET_NUM "${val}+1") + set(CORE_NUM ${val}) + list(APPEND MDB_OPTIONS && ${MDB} -pset=${PSET_NUM} -psetname=core${CORE_NUM}) if(PSET_NUM GREATER 1) list(APPEND MDB_OPTIONS -prop=download=2) + endif() + if(PSET_NUM LESS ${CONFIG_MP_MAX_NUM_CPUS}) set(MULTIFILES ${MULTIFILES}core${CORE_NUM},) else() set(MULTIFILES ${MULTIFILES}core${CORE_NUM}) diff --git a/cmake/gcc-m-cpu.cmake b/cmake/gcc-m-cpu.cmake index ae10132dfc0..8b02d7bee86 100644 --- a/cmake/gcc-m-cpu.cmake +++ b/cmake/gcc-m-cpu.cmake @@ -83,7 +83,7 @@ elseif("${ARCH}" STREQUAL "arm64") elseif(CONFIG_CPU_CORTEX_A72) set(GCC_M_CPU cortex-a72) elseif(CONFIG_CPU_CORTEX_R82) - set(GCC_M_ARCH armv8.4-a+nolse) + set(GCC_M_CPU cortex-r82) endif() elseif("${ARCH}" STREQUAL "arc") if(CONFIG_CPU_EM4_FPUS) diff --git a/cmake/linker/lld/target_base.cmake b/cmake/linker/lld/target_base.cmake index 82abe1fa142..44f43839d37 100644 --- a/cmake/linker/lld/target_base.cmake +++ b/cmake/linker/lld/target_base.cmake @@ -31,6 +31,14 @@ macro(toolchain_ld_base) ) endif() + # Global pointer relaxation is off by default in lld. Explicitly enable it if + # linker relaxations and gp usage are both allowed. + if (CONFIG_LINKER_USE_RELAX AND CONFIG_RISCV_GP) + zephyr_ld_options( + ${LINKERFLAGPREFIX},--relax-gp + ) + endif() + if(CONFIG_CPP) # LLVM lld complains: # error: section: init_array is not contiguous with other relro sections diff --git a/cmake/linker_script/common/common-ram.cmake b/cmake/linker_script/common/common-ram.cmake index 7e639043bce..04f6637a9e1 100644 --- a/cmake/linker_script/common/common-ram.cmake +++ b/cmake/linker_script/common/common-ram.cmake @@ -18,10 +18,10 @@ zephyr_linker_section_configure(SECTION device_states ) if(CONFIG_PM_DEVICE) - zephyr_iterable_section(NAME pm_device_slots GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) + zephyr_iterable_section(NAME pm_device_slots GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) endif() -zephyr_iterable_section(NAME log_dynamic GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) +zephyr_iterable_section(NAME log_dynamic GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) if(CONFIG_USERSPACE) # All kernel objects within are assumed to be either completely @@ -32,34 +32,34 @@ if(CONFIG_USERSPACE) # _static_kernel_objects_begin = .; endif() -zephyr_iterable_section(NAME k_timer GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) -zephyr_iterable_section(NAME k_mem_slab GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) -zephyr_iterable_section(NAME k_heap GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) -zephyr_iterable_section(NAME k_mutex GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) -zephyr_iterable_section(NAME k_stack GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) -zephyr_iterable_section(NAME k_msgq GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) -zephyr_iterable_section(NAME k_mbox GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) -zephyr_iterable_section(NAME k_pipe GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) -zephyr_iterable_section(NAME k_sem GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) -zephyr_iterable_section(NAME k_queue GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) -zephyr_iterable_section(NAME k_condvar GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) -zephyr_iterable_section(NAME k_event GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) +zephyr_iterable_section(NAME k_timer GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) +zephyr_iterable_section(NAME k_mem_slab GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) +zephyr_iterable_section(NAME k_heap GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) +zephyr_iterable_section(NAME k_mutex GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) +zephyr_iterable_section(NAME k_stack GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) +zephyr_iterable_section(NAME k_msgq GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) +zephyr_iterable_section(NAME k_mbox GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) +zephyr_iterable_section(NAME k_pipe GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) +zephyr_iterable_section(NAME k_sem GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) +zephyr_iterable_section(NAME k_queue GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) +zephyr_iterable_section(NAME k_condvar GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) +zephyr_iterable_section(NAME k_event GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) -zephyr_iterable_section(NAME net_buf_pool GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) +zephyr_iterable_section(NAME net_buf_pool GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) if(CONFIG_NETWORKING) - zephyr_iterable_section(NAME net_if GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) - zephyr_iterable_section(NAME net_if_dev GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) - zephyr_iterable_section(NAME net_l2 GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) - zephyr_iterable_section(NAME eth_bridge GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) + zephyr_iterable_section(NAME net_if GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) + zephyr_iterable_section(NAME net_if_dev GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) + zephyr_iterable_section(NAME net_l2 GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) + zephyr_iterable_section(NAME eth_bridge GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) endif() if(CONFIG_SENSING) - zephyr_iterable_section(NAME sensing_sensor GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) + zephyr_iterable_section(NAME sensing_sensor GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) endif() if(CONFIG_UART_MUX) - zephyr_iterable_section(NAME uart_mux GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) + zephyr_iterable_section(NAME uart_mux GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) endif() if(CONFIG_USB_DEVICE_STACK) @@ -82,8 +82,8 @@ if(CONFIG_USB_DEVICE_BOS) endif() if(CONFIG_RTIO) - zephyr_iterable_section(NAME rtio GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) - zephyr_iterable_section(NAME rtio_iodev GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) + zephyr_iterable_section(NAME rtio GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) + zephyr_iterable_section(NAME rtio_iodev GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) endif() #if(CONFIG_USERSPACE) @@ -92,43 +92,44 @@ 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) - 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) + zephyr_iterable_section(NAME ztest_suite_node GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) + zephyr_iterable_section(NAME ztest_suite_stats GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) + zephyr_iterable_section(NAME ztest_unit_test GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) + zephyr_iterable_section(NAME ztest_test_rule GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) + zephyr_iterable_section(NAME ztest_expected_result_entry GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) endif() if(CONFIG_ZBUS) - zephyr_iterable_section(NAME zbus_observer GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) - zephyr_iterable_section(NAME zbus_channel_observation_mask GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) + zephyr_iterable_section(NAME zbus_observer GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) + zephyr_iterable_section(NAME zbus_channel_observation_mask GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) endif() if(CONFIG_UVB) - zephyr_iterable_section(NAME uvb_node GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) + zephyr_iterable_section(NAME uvb_node GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) endif() if(CONFIG_LOG) - zephyr_iterable_section(NAME log_mpsc_pbuf GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) - zephyr_iterable_section(NAME log_msg_ptr GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) + zephyr_iterable_section(NAME log_mpsc_pbuf GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) + zephyr_iterable_section(NAME log_msg_ptr GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) endif() if(CONFIG_PCIE) - zephyr_iterable_section(NAME pcie_dev GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) + zephyr_iterable_section(NAME pcie_dev GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) endif() if(CONFIG_USB_DEVICE_STACK OR CONFIG_USB_DEVICE_STACK_NEXT) - zephyr_iterable_section(NAME usb_cfg_data GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) - zephyr_iterable_section(NAME usbd_contex GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) - zephyr_iterable_section(NAME usbd_class_node GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) + zephyr_iterable_section(NAME usb_cfg_data GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) + zephyr_iterable_section(NAME usbd_contex GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) + zephyr_iterable_section(NAME usbd_class_fs GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) + zephyr_iterable_section(NAME usbd_class_hs GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) endif() 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) + zephyr_iterable_section(NAME usbh_contex GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) + zephyr_iterable_section(NAME usbh_class_data GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) endif() if(CONFIG_DEVICE_MUTABLE) - zephyr_iterable_section(NAME device_mutable GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) + zephyr_iterable_section(NAME device_mutable GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) endif() diff --git a/cmake/linker_script/common/common-rom.cmake b/cmake/linker_script/common/common-rom.cmake index 77cd911ab4f..125d438b58b 100644 --- a/cmake/linker_script/common/common-rom.cmake +++ b/cmake/linker_script/common/common-rom.cmake @@ -8,7 +8,10 @@ zephyr_linker_section_obj_level(SECTION init LEVEL POST_KERNEL) zephyr_linker_section_obj_level(SECTION init LEVEL APPLICATION) zephyr_linker_section_obj_level(SECTION init LEVEL SMP) -zephyr_iterable_section(NAME device NUMERIC KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) +zephyr_linker_section(NAME deferred_init_list KVMA RAM_REGION GROUP RODATA_REGION) +zephyr_linker_section_configure(SECTION deferred_init_list INPUT ".z_deferred_init*" KEEP SORT NAME) + +zephyr_iterable_section(NAME device NUMERIC KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) if(CONFIG_GEN_SW_ISR_TABLE AND NOT CONFIG_DYNAMIC_INTERRUPTS) # ld align has been changed to subalign to provide identical behavior scatter vs. ld. @@ -89,98 +92,98 @@ zephyr_linker_section_configure( ) if(CONFIG_NET_SOCKETS) - zephyr_iterable_section(NAME net_socket_register KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) + zephyr_iterable_section(NAME net_socket_register KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) endif() if(CONFIG_NET_L2_PPP) - zephyr_iterable_section(NAME ppp_protocol_handler KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) + zephyr_iterable_section(NAME ppp_protocol_handler KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) endif() -zephyr_iterable_section(NAME bt_l2cap_fixed_chan KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) +zephyr_iterable_section(NAME bt_l2cap_fixed_chan KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) if(CONFIG_BT_CLASSIC) - zephyr_iterable_section(NAME bt_l2cap_br_fixed_chan KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) + zephyr_iterable_section(NAME bt_l2cap_br_fixed_chan KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) endif() if(CONFIG_BT_CONN) - zephyr_iterable_section(NAME bt_conn_cb KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) + zephyr_iterable_section(NAME bt_conn_cb KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) endif() -zephyr_iterable_section(NAME bt_gatt_service_static KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) +zephyr_iterable_section(NAME bt_gatt_service_static KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) if(CONFIG_BT_MESH) - zephyr_iterable_section(NAME bt_mesh_subnet_cb KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) - zephyr_iterable_section(NAME bt_mesh_app_key_cb KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) + zephyr_iterable_section(NAME bt_mesh_subnet_cb KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) + zephyr_iterable_section(NAME bt_mesh_app_key_cb KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) - zephyr_iterable_section(NAME bt_mesh_hb_cb KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) + zephyr_iterable_section(NAME bt_mesh_hb_cb KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) endif() if(CONFIG_BT_MESH_FRIEND) - zephyr_iterable_section(NAME bt_mesh_friend_cb KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) + zephyr_iterable_section(NAME bt_mesh_friend_cb KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) endif() if(CONFIG_BT_MESH_LOW_POWER) - zephyr_iterable_section(NAME bt_mesh_lpn_cb KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) + zephyr_iterable_section(NAME bt_mesh_lpn_cb KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) endif() if(CONFIG_BT_MESH_PROXY) - zephyr_iterable_section(NAME bt_mesh_proxy_cb KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) + zephyr_iterable_section(NAME bt_mesh_proxy_cb KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) endif() if(CONFIG_EC_HOST_CMD) - zephyr_iterable_section(NAME ec_host_cmd_handler KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) + zephyr_iterable_section(NAME ec_host_cmd_handler KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) endif() if(CONFIG_SETTINGS) - zephyr_iterable_section(NAME settings_handler_static KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) + zephyr_iterable_section(NAME settings_handler_static KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) endif() if(CONFIG_SENSING) - zephyr_iterable_section(NAME sensing_sensor_info KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) + zephyr_iterable_section(NAME sensing_sensor_info KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) endif() if(CONFIG_SENSOR_INFO) - zephyr_iterable_section(NAME sensor_info KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) + zephyr_iterable_section(NAME sensor_info KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) endif() if(CONFIG_SENSOR_ASYNC_API) - zephyr_iterable_section(NAME sensor_decoder_api KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) + zephyr_iterable_section(NAME sensor_decoder_api KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) endif() if(CONFIG_MCUMGR) - zephyr_iterable_section(NAME mcumgr_handler KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) + zephyr_iterable_section(NAME mcumgr_handler KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) endif() -zephyr_iterable_section(NAME k_p4wq_initparam KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) +zephyr_iterable_section(NAME k_p4wq_initparam KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) if(CONFIG_EMUL) - zephyr_iterable_section(NAME emul KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) + zephyr_iterable_section(NAME emul KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) endif() if(CONFIG_DNS_SD) - zephyr_iterable_section(NAME dns_sd_rec KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) + zephyr_iterable_section(NAME dns_sd_rec KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) endif() if(CONFIG_PCIE) - zephyr_iterable_section(NAME irq_alloc KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) + zephyr_iterable_section(NAME irq_alloc KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) endif() -zephyr_iterable_section(NAME log_strings KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) +zephyr_iterable_section(NAME log_strings KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) -zephyr_iterable_section(NAME log_const KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) +zephyr_iterable_section(NAME log_const KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) -zephyr_iterable_section(NAME shell KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) +zephyr_iterable_section(NAME shell KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) -zephyr_iterable_section(NAME shell_root_cmds KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) +zephyr_iterable_section(NAME shell_root_cmds KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) -zephyr_iterable_section(NAME shell_subcmds KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) +zephyr_iterable_section(NAME shell_subcmds KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) -zephyr_iterable_section(NAME shell_dynamic_subcmds KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) +zephyr_iterable_section(NAME shell_dynamic_subcmds KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) -zephyr_iterable_section(NAME cfb_font KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) +zephyr_iterable_section(NAME cfb_font KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) -zephyr_iterable_section(NAME tracing_backend KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) +zephyr_iterable_section(NAME tracing_backend KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) zephyr_linker_section(NAME zephyr_dbg_info KVMA RAM_REGION GROUP RODATA_REGION NOINPUT ${XIP_ALIGN_WITH_INPUT}) zephyr_linker_section_configure(SECTION zephyr_dbg_info INPUT ".zephyr_dbg_info" KEEP) @@ -191,39 +194,47 @@ if (CONFIG_DEVICE_DEPS) zephyr_linker_section_configure(SECTION device_deps INPUT .__device_deps_pass2* KEEP SORT NAME PASS NOT LINKER_DEVICE_DEPS_PASS1) endif() -zephyr_iterable_section(NAME _static_thread_data KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) +zephyr_iterable_section(NAME _static_thread_data KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) if (CONFIG_BT_IAS) - zephyr_iterable_section(NAME bt_ias_cb KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) + zephyr_iterable_section(NAME bt_ias_cb KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) endif() if (CONFIG_LOG) - zephyr_iterable_section(NAME log_link KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) - zephyr_iterable_section(NAME log_backend KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) + zephyr_iterable_section(NAME log_link KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) + zephyr_iterable_section(NAME log_backend KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) endif() if (CONFIG_HTTP_SERVER) - zephyr_iterable_section(NAME http_service_desc KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) + zephyr_iterable_section(NAME http_service_desc KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) +endif() + +if (CONFIG_COAP_SERVER) + zephyr_iterable_section(NAME coap_service KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) +endif() + +if (CONFIG_NET_MGMT) + zephyr_iterable_section(NAME net_mgmt_event_static_handler KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) endif() if(CONFIG_INPUT) - zephyr_iterable_section(NAME input_callback KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) + zephyr_iterable_section(NAME input_callback KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) endif() if(CONFIG_USBD_MSC_CLASS) - zephyr_iterable_section(NAME usbd_msc_lun KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) + zephyr_iterable_section(NAME usbd_msc_lun KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) 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) + zephyr_iterable_section(NAME zbus_channel KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) + zephyr_iterable_section(NAME zbus_observer KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) + zephyr_iterable_section(NAME zbus_channel_observation KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) endif() if(CONFIG_GNSS) - zephyr_iterable_section(NAME gnss_data_callback KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) + zephyr_iterable_section(NAME gnss_data_callback KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) endif() if(CONFIG_GNSS_SATELLITES) - zephyr_iterable_section(NAME gnss_satellites_callback KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) + zephyr_iterable_section(NAME gnss_satellites_callback KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) endif() diff --git a/cmake/linker_script/common/debug-sections.cmake b/cmake/linker_script/common/debug-sections.cmake index 397d4bdb1d7..ba6aff11c3a 100644 --- a/cmake/linker_script/common/debug-sections.cmake +++ b/cmake/linker_script/common/debug-sections.cmake @@ -1,4 +1,4 @@ -# Content of this file originates from include/linker/debug-sections.ld +# Content of this file originates from include/zephyr/linker/debug-sections.ld # Following sections are obtained via 'ld --verbose' # Stabs debugging sections. @@ -37,7 +37,7 @@ zephyr_linker_section(NAME .debug_str ADDRESS 0) zephyr_linker_section(NAME .debug_loc ADDRESS 0) zephyr_linker_section(NAME .debug_macinfo ADDRESS 0) - #SGI/MIPS DWARF 2 extensions +# SGI/MIPS DWARF 2 extensions zephyr_linker_section(NAME .debug_weaknames ADDRESS 0) zephyr_linker_section(NAME .debug_funcnames ADDRESS 0) zephyr_linker_section(NAME .debug_typenames ADDRESS 0) @@ -46,5 +46,13 @@ zephyr_linker_section(NAME .debug_varnames ADDRESS 0) # DWARF 3 zephyr_linker_section(NAME .debug_pubtypes ADDRESS 0) zephyr_linker_section(NAME .debug_ranges ADDRESS 0) -# DWARF Extension. + +# DWARF 5 +zephyr_linker_section(NAME .debug_addr ADDRESS 0) +zephyr_linker_section(NAME .debug_line_str ADDRESS 0) +zephyr_linker_section(NAME .debug_loclists ADDRESS 0) zephyr_linker_section(NAME .debug_macro ADDRESS 0) +zephyr_linker_section(NAME .debug_names ADDRESS 0) +zephyr_linker_section(NAME .debug_rnglists ADDRESS 0) +zephyr_linker_section(NAME .debug_str_offsets ADDRESS 0) +zephyr_linker_section(NAME .debug_sup ADDRESS 0) diff --git a/cmake/llext-edk.cmake b/cmake/llext-edk.cmake new file mode 100644 index 00000000000..9501133f3ab --- /dev/null +++ b/cmake/llext-edk.cmake @@ -0,0 +1,197 @@ +# Copyright (c) 2024 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +# This script generates a tarball containing all headers and flags necessary to +# build an llext extension. It does so by copying all headers accessible from +# INTERFACE_INCLUDE_DIRECTORIES and generating a Makefile.cflags file (and a +# cmake.cflags one) with all flags necessary to build the extension. +# +# The tarball can be extracted and used in the extension build system to include +# all necessary headers and flags. File paths are made relative to a few key +# directories (build/zephyr, zephyr base, west top dir and application source +# dir), to avoid leaking any information about the host system. +# +# The following arguments are expected: +# - llext_edk_name: Name of the extension, used to name the tarball and the +# install directory variable for Makefile. +# - INTERFACE_INCLUDE_DIRECTORIES: List of include directories to copy headers +# from. It should simply be the INTERFACE_INCLUDE_DIRECTORIES property of the +# zephyr_interface target. +# - AUTOCONF_H: Name of the autoconf.h file, used to generate the imacros flag. +# - llext_edk_file: Output file name for the tarball. +# - llext_cflags: Additional flags to be added to the generated flags. +# - ZEPHYR_BASE: Path to the zephyr base directory. +# - WEST_TOPDIR: Path to the west top directory. +# - APPLICATION_SOURCE_DIR: Path to the application source directory. +# - PROJECT_BINARY_DIR: Path to the project binary build directory. +# - CONFIG_LLEXT_EDK_USERSPACE_ONLY: Whether to copy syscall headers from the +# edk directory. This is necessary when building an extension that only +# supports userspace, as the syscall headers are regenerated in the edk +# directory. + +cmake_minimum_required(VERSION 3.20.0) + +set(llext_edk ${PROJECT_BINARY_DIR}/${llext_edk_name}) +set(llext_edk_inc ${llext_edk}/include) + +# Usage: +# relative_dir( ) +# +# Helper function to generate relative paths to a few key directories +# (PROJECT_BINARY_DIR, ZEPHYR_BASE, WEST_TOPDIR and APPLICATION_SOURCE_DIR). +# The generated path is relative to the key directory, and the bindir_out +# output variable is set to TRUE if the path is relative to PROJECT_BINARY_DIR. +# +function(relative_dir dir relative_out bindir_out) + cmake_path(IS_PREFIX PROJECT_BINARY_DIR ${dir} NORMALIZE to_prj_bindir) + cmake_path(IS_PREFIX ZEPHYR_BASE ${dir} NORMALIZE to_zephyr_base) + if("${WEST_TOPDIR}" STREQUAL "") + set(to_west_topdir FALSE) + else() + cmake_path(IS_PREFIX WEST_TOPDIR ${dir} NORMALIZE to_west_topdir) + endif() + cmake_path(IS_PREFIX APPLICATION_SOURCE_DIR ${dir} NORMALIZE to_app_srcdir) + + # Overall idea is to place included files in the destination dir based on the source: + # files coming from build/zephyr/generated will end up at + # /include/zephyr/include/generated, files coming from zephyr base at + # /include/zephyr/include, files from west top dir (for instance, hal modules), + # at /include and application ones at /include/. + # Finally, everything else (such as external libs not at any of those places) will end up + # at /include/, so we avoid any external lib + # stepping at any other lib toes. + if(to_prj_bindir) + cmake_path(RELATIVE_PATH dir BASE_DIRECTORY ${PROJECT_BINARY_DIR} OUTPUT_VARIABLE dir_tmp) + set(dest ${llext_edk_inc}/zephyr/${dir_tmp}) + elseif(to_zephyr_base) + cmake_path(RELATIVE_PATH dir BASE_DIRECTORY ${ZEPHYR_BASE} OUTPUT_VARIABLE dir_tmp) + set(dest ${llext_edk_inc}/zephyr/${dir_tmp}) + elseif(to_west_topdir) + cmake_path(RELATIVE_PATH dir BASE_DIRECTORY ${WEST_TOPDIR} OUTPUT_VARIABLE dir_tmp) + set(dest ${llext_edk_inc}/${dir_tmp}) + elseif(to_app_srcdir) + cmake_path(GET APPLICATION_SOURCE_DIR FILENAME app_dir) + cmake_path(RELATIVE_PATH dir BASE_DIRECTORY ${APPLICATION_SOURCE_DIR} OUTPUT_VARIABLE dir_tmp) + set(dest ${llext_edk_inc}/${app_dir}/${dir_tmp}) + else() + set(dest ${llext_edk_inc}/${dir}) + endif() + + set(${relative_out} ${dest} PARENT_SCOPE) + if(to_prj_bindir) + set(${bindir_out} TRUE PARENT_SCOPE) + else() + set(${bindir_out} FALSE PARENT_SCOPE) + endif() +endfunction() + +string(REGEX REPLACE "[^a-zA-Z0-9]" "_" llext_edk_name_sane ${llext_edk_name}) +string(TOUPPER ${llext_edk_name_sane} llext_edk_name_sane) +set(install_dir_var "${llext_edk_name_sane}_INSTALL_DIR") + +separate_arguments(LLEXT_CFLAGS NATIVE_COMMAND ${llext_cflags}) + +set(make_relative FALSE) +foreach(flag ${llext_cflags}) + if (flag STREQUAL "-imacros") + set(make_relative TRUE) + elseif (make_relative) + set(make_relative FALSE) + cmake_path(GET flag PARENT_PATH parent) + cmake_path(GET flag FILENAME name) + relative_dir(${parent} dest bindir) + cmake_path(RELATIVE_PATH dest BASE_DIRECTORY ${llext_edk} OUTPUT_VARIABLE dest_rel) + if(bindir) + list(APPEND imacros_gen_make "-imacros\$(${install_dir_var})/${dest_rel}/${name}") + list(APPEND imacros_gen_cmake "-imacros\${CMAKE_CURRENT_LIST_DIR}/${dest_rel}/${name}") + else() + list(APPEND imacros_make "-imacros\$(${install_dir_var})/${dest_rel}/${name}") + list(APPEND imacros_cmake "-imacros\${CMAKE_CURRENT_LIST_DIR}/${dest_rel}/${name}") + endif() + else() + list(APPEND new_cflags ${flag}) + endif() +endforeach() +set(LLEXT_CFLAGS ${new_cflags}) + +cmake_path(CONVERT "${INTERFACE_INCLUDE_DIRECTORIES}" TO_CMAKE_PATH_LIST include_dirs) + +set(autoconf_h_edk ${llext_edk_inc}/${AUTOCONF_H}) +cmake_path(RELATIVE_PATH AUTOCONF_H BASE_DIRECTORY ${PROJECT_BINARY_DIR} OUTPUT_VARIABLE autoconf_h_rel) + +list(APPEND base_flags_make ${llext_cflags} ${imacros_make}) +list(APPEND base_flags_cmake ${llext_cflags} ${imacros_cmake}) + +file(MAKE_DIRECTORY ${llext_edk_inc}) +foreach(dir ${include_dirs}) + if (NOT EXISTS ${dir}) + continue() + endif() + + relative_dir(${dir} dest bindir) + # Use destination parent, as the last part of the source directory is copied as well + cmake_path(GET dest PARENT_PATH dest_p) + + file(MAKE_DIRECTORY ${dest_p}) + file(COPY ${dir} DESTINATION ${dest_p} FILES_MATCHING PATTERN "*.h") + + cmake_path(RELATIVE_PATH dest BASE_DIRECTORY ${llext_edk} OUTPUT_VARIABLE dest_rel) + if(bindir) + list(APPEND inc_gen_flags_make "-I\$(${install_dir_var})/${dest_rel}") + list(APPEND inc_gen_flags_cmake "-I\${CMAKE_CURRENT_LIST_DIR}/${dest_rel}") + else() + list(APPEND inc_flags_make "-I\$(${install_dir_var})/${dest_rel}") + list(APPEND inc_flags_cmake "-I\${CMAKE_CURRENT_LIST_DIR}/${dest_rel}") + endif() + list(APPEND all_inc_flags_make "-I\$(${install_dir_var})/${dest_rel}") + list(APPEND all_inc_flags_cmake "-I\${CMAKE_CURRENT_LIST_DIR}/${dest_rel}") +endforeach() + +if(CONFIG_LLEXT_EDK_USERSPACE_ONLY) + # Copy syscall headers from edk directory, as they were regenerated there. + file(COPY ${PROJECT_BINARY_DIR}/edk/include/generated/ DESTINATION ${llext_edk_inc}/zephyr/include/generated) +endif() + +# Generate flags for Makefile +list(APPEND all_flags_make ${base_flags_make} ${imacros_gen_make} ${all_inc_flags_make}) +list(JOIN all_flags_make " " all_flags_str) +file(WRITE ${llext_edk}/Makefile.cflags "LLEXT_CFLAGS = ${all_flags_str}") + +list(JOIN all_inc_flags_make " " all_inc_flags_str) +file(APPEND ${llext_edk}/Makefile.cflags "\n\nLLEXT_ALL_INCLUDE_CFLAGS = ${all_inc_flags_str}") + +list(JOIN inc_flags_make " " inc_flags_str) +file(APPEND ${llext_edk}/Makefile.cflags "\n\nLLEXT_INCLUDE_CFLAGS = ${inc_flags_str}") + +list(JOIN inc_gen_flags_make " " inc_gen_flags_str) +file(APPEND ${llext_edk}/Makefile.cflags "\n\nLLEXT_GENERATED_INCLUDE_CFLAGS = ${inc_gen_flags_str}") + +list(JOIN base_flags_make " " base_flags_str) +file(APPEND ${llext_edk}/Makefile.cflags "\n\nLLEXT_BASE_CFLAGS = ${base_flags_str}") + +list(JOIN imacros_gen_make " " imacros_gen_str) +file(APPEND ${llext_edk}/Makefile.cflags "\n\nLLEXT_GENERATED_IMACROS_CFLAGS = ${imacros_gen_str}") + +# Generate flags for CMake +list(APPEND all_flags_cmake ${base_flags_cmake} ${imacros_gen_make} ${all_inc_flags_cmake}) +file(WRITE ${llext_edk}/cmake.cflags "set(LLEXT_CFLAGS ${all_flags_cmake})") + +file(APPEND ${llext_edk}/cmake.cflags "\n\nset(LLEXT_ALL_INCLUDE_CFLAGS ${all_inc_flags_cmake})") + +file(APPEND ${llext_edk}/cmake.cflags "\n\nset(LLEXT_INCLUDE_CFLAGS ${inc_flags_cmake})") + +file(APPEND ${llext_edk}/cmake.cflags "\n\nset(LLEXT_GENERATED_INCLUDE_CFLAGS ${inc_gen_flags_cmake})") + +file(APPEND ${llext_edk}/cmake.cflags "\n\nset(LLEXT_BASE_CFLAGS ${base_flags_cmake})") + +file(APPEND ${llext_edk}/cmake.cflags "\n\nset(LLEXT_GENERATED_IMACROS_CFLAGS ${imacros_gen_cmake})") + +# Generate the tarball +file(ARCHIVE_CREATE + OUTPUT ${llext_edk_file} + PATHS ${llext_edk} + FORMAT gnutar + COMPRESSION XZ +) + +file(REMOVE_RECURSE ${llext_edk}) diff --git a/cmake/modules/FindGnuLd.cmake b/cmake/modules/FindGnuLd.cmake index 3e137438aa1..9ee42cc82fe 100644 --- a/cmake/modules/FindGnuLd.cmake +++ b/cmake/modules/FindGnuLd.cmake @@ -48,6 +48,7 @@ execute_process(COMMAND ${CMAKE_C_COMPILER} --print-prog-name=ld.bfd OUTPUT_STRIP_TRAILING_WHITESPACE) if(EXISTS "${GNULD_LINKER}") + cmake_path(NORMAL_PATH GNULD_LINKER) set(GNULD_LINKER_IS_BFD ON CACHE BOOL "Linker BFD compatibility (compiler reported)" FORCE) else() # Need to clear it or else find_program() won't replace the value. diff --git a/cmake/modules/FindTargetTools.cmake b/cmake/modules/FindTargetTools.cmake index f74f10f2845..a1fa4bf5c67 100644 --- a/cmake/modules/FindTargetTools.cmake +++ b/cmake/modules/FindTargetTools.cmake @@ -41,10 +41,7 @@ set(CMAKE_CXX_COMPILER_FORCED 1) # variable is used for constructing the file names of the platform files # like Linux.cmake or Windows-gcc.cmake. If your target is an embedded # system without OS set CMAKE_SYSTEM_NAME to "Generic". -# -# This will force CMake to load cmake/modules/Platform/Zephyr.cmake, -# allowing Zephyr-specific embedded system features to be enabled. -set(CMAKE_SYSTEM_NAME Zephyr) +set(CMAKE_SYSTEM_NAME Generic) # https://cmake.org/cmake/help/latest/variable/CMAKE_SYSTEM_PROCESSOR.html: # The name of the CPU CMake is building for. diff --git a/cmake/modules/FindThreads.cmake b/cmake/modules/FindThreads.cmake new file mode 100644 index 00000000000..943aa9eb171 --- /dev/null +++ b/cmake/modules/FindThreads.cmake @@ -0,0 +1,42 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright (c) 2024 Google LLC. + +# FindThreads module for locating threads implementation. +# +# The module defines the following variables: +# +# 'Threads_FOUND' +# Indicates if threads are supported. +# +# 'CMAKE_THREAD_LIBS_INIT' +# The threads library to use. Zephyr provides threads implementation and no +# special flags are needed, so this will be empty. +# +# 'CMAKE_USE_PTHREADS_INIT' +# Indicates if threads are pthread compatible. +# +# This module is compatible with FindThreads module from CMake. +# The original implementation tries to find threads library using various +# methods (e.g. checking if pthread library is present or compiling example +# program to check if the implementation is provided by libc), but it's not +# able to detect pthread implementation provided by Zephyr. + +include(FindPackageHandleStandardArgs) + +set(Threads_FOUND FALSE) + +if(DEFINED CONFIG_PTHREAD) + set(Threads_FOUND TRUE) + set(CMAKE_THREAD_LIBS_INIT ) + set(CMAKE_USE_PTHREADS_INIT 1) +endif() + +find_package_handle_standard_args(Threads DEFAULT_MSG Threads_FOUND) + +if(Threads_FOUND AND NOT TARGET Threads::Threads) + # This is just an empty interface, because we don't need to provide any + # options. Nevertheless this library must exist, because third-party modules + # can link it to their own libraries. + add_library(Threads::Threads INTERFACE IMPORTED) +endif() diff --git a/cmake/modules/Platform/Zephyr.cmake b/cmake/modules/Platform/Zephyr.cmake deleted file mode 100644 index 17b55284094..00000000000 --- a/cmake/modules/Platform/Zephyr.cmake +++ /dev/null @@ -1,13 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 -# -# Copyright (c) 2024, Arduino SA - -# Perform the same initialization as the Generic platform, then enable -# dynamic library support if CONFIG_LLEXT is enabled. - -include(Platform/Generic) - -# Enable dynamic library support when CONFIG_LLEXT is enabled. -if(CONFIG_LLEXT) - set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS true) -endif() diff --git a/cmake/modules/dts.cmake b/cmake/modules/dts.cmake index d1ff4df9bcd..1cd531b7f3c 100644 --- a/cmake/modules/dts.cmake +++ b/cmake/modules/dts.cmake @@ -57,8 +57,9 @@ find_package(Dtc 1.4.6) # - ${PROJECT_BINARY_DIR}/zephyr.dts exists # - ${PROJECT_BINARY_DIR}/edt.pickle exists # - ${KCONFIG_BINARY_DIR}/Kconfig.dts exists -# - the build system will be regenerated if any devicetree files -# used in this build change, including transitive includes +# - DTS_INCLUDE_FILES is set to a ;-list of all devicetree files +# used in this build, including transitive includes (the build +# system will be regenerated if any of those files change) # - the devicetree extensions in the extensions.cmake module # will be ready for use in other CMake list files that run # after this module @@ -257,14 +258,14 @@ zephyr_dt_preprocess( # Parse the generated dependency file to find the DT sources that # were included, including any transitive includes. toolchain_parse_make_rule(${DTS_DEPS} - include_files # Output parameter + DTS_INCLUDE_FILES # Output parameter ) # Add the results to the list of files that, when change, force the # build system to re-run CMake. set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS - ${include_files} + ${DTS_INCLUDE_FILES} ${GEN_DEFINES_SCRIPT} ${GEN_DRIVER_KCONFIG_SCRIPT} ${GEN_DTS_CMAKE_SCRIPT} diff --git a/cmake/modules/extensions.cmake b/cmake/modules/extensions.cmake index a4a33ffe137..315890732c3 100644 --- a/cmake/modules/extensions.cmake +++ b/cmake/modules/extensions.cmake @@ -37,6 +37,7 @@ include(CheckCXXCompilerFlag) # 7 Linkable loadable extensions (llext) # 7.1 llext_* configuration functions # 7.2 add_llext_* build control functions +# 7.3 llext helper functions ######################################################## # 1. Zephyr-aware extensions @@ -1759,9 +1760,11 @@ function(zephyr_blobs_verify) 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.") + if(NOT EXISTS "${path}") + message(${msg_lvl} "Blob for path \"${path}\" missing. Update with: west blobs fetch") + elseif(NOT "A ${path}" IN_LIST BLOBS_LIST) + # Each path that has a correct sha256 is prefixed with an A + message(${msg_lvl} "Blob for path \"${path}\" isn't valid. Update with: west blobs fetch") endif() endforeach() else() @@ -1772,7 +1775,9 @@ function(zephyr_blobs_verify) message(VERBOSE "Verifying blob \"${path}\"") - if(NOT "${status}" STREQUAL "A") + if(NOT EXISTS "${path}") + message(${msg_lvl} "Blob for path \"${path}\" missing. Update with: west blobs fetch ${BLOBS_VERIFY_MODULE}") + elseif(NOT "${status}" STREQUAL "A") message(${msg_lvl} "Blob for path \"${path}\" isn't valid. Update with: west blobs fetch ${BLOBS_VERIFY_MODULE}") endif() endforeach() @@ -5267,13 +5272,14 @@ endfunction() # Usage: # add_llext_target( # OUTPUT -# SOURCES +# SOURCES # ) # -# Add a custom target that compiles a single source file to a .llext file. +# Add a custom target that compiles a set of source files to a .llext file. # # Output and source files must be specified using the OUTPUT and SOURCES -# arguments. Only one source file is currently supported. +# arguments. Only one source file is supported when LLEXT_TYPE_ELF_OBJECT is +# selected, since there is no linking step in that case. # # 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 @@ -5310,44 +5316,55 @@ function(add_llext_target target_name) # Source and output files must be provided zephyr_check_arguments_required_all("add_llext_target" LLEXT OUTPUT SOURCES) - # 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") + if(CONFIG_LLEXT_TYPE_ELF_OBJECT AND NOT (source_count EQUAL 1)) + message(FATAL_ERROR "add_llext_target: only one source file is supported " + "for ELF object file builds") endif() set(llext_pkg_output ${LLEXT_OUTPUT}) - set(source_file ${LLEXT_SOURCES}) + set(source_files ${LLEXT_SOURCES}) - # 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 - "$" - ) + llext_filter_zephyr_flags(LLEXT_REMOVE_FLAGS ${zephyr_flags} + zephyr_filtered_flags) # Compile the source file using current Zephyr settings but a different - # set of flags. - # This is currently arch-specific since the ARM loader for .llext files - # expects object file format, while the Xtensa one uses shared libraries. + # set of flags to obtain the desired llext object type. set(llext_lib_target ${target_name}_llext_lib) - if(CONFIG_ARM) + if(CONFIG_LLEXT_TYPE_ELF_OBJECT) # Create an object library to compile the source file - add_library(${llext_lib_target} OBJECT ${source_file}) + add_library(${llext_lib_target} OBJECT ${source_files}) set(llext_lib_output $) - elseif(CONFIG_XTENSA) + elseif(CONFIG_LLEXT_TYPE_ELF_RELOCATABLE) + + # CMake does not directly support a "RELOCATABLE" library target. + # The "SHARED" target would be similar, but that unavoidably adds + # a "-shared" flag to the linker command line which does firmly + # conflict with "-r". + # A workaround is to use an executable target and make the linker + # output a relocatable file. The output file suffix is changed so + # the result looks like the object file it actually is. + add_executable(${llext_lib_target} EXCLUDE_FROM_ALL ${source_files}) + target_link_options(${llext_lib_target} PRIVATE + $) + set_target_properties(${llext_lib_target} PROPERTIES + SUFFIX ${CMAKE_C_OUTPUT_EXTENSION}) + set(llext_lib_output $) + + # Add the llext flags to the linking step as well + target_link_options(${llext_lib_target} PRIVATE + ${LLEXT_APPEND_FLAGS} + ) + + elseif(CONFIG_LLEXT_TYPE_ELF_SHAREDLIB) # Create a shared library - add_library(${llext_lib_target} SHARED ${source_file}) + add_library(${llext_lib_target} SHARED ${source_files}) set(llext_lib_output $) # Add the llext flags to the linking step as well @@ -5396,8 +5413,8 @@ function(add_llext_target target_name) COMMAND_EXPAND_LISTS ) - # Arch-specific packaging of the built binary file into an .llext file - if(CONFIG_ARM) + # Type-specific packaging of the built binary file into an .llext file + if(CONFIG_LLEXT_TYPE_ELF_OBJECT) # No packaging required, simply copy the object file add_custom_command( @@ -5406,7 +5423,22 @@ function(add_llext_target target_name) DEPENDS ${llext_proc_target} ${llext_pkg_input} ) - elseif(CONFIG_XTENSA) + elseif(CONFIG_LLEXT_TYPE_ELF_RELOCATABLE) + + # Need to remove just some sections from the relocatable object + # (using strip in this case would remove _all_ symbols) + add_custom_command( + OUTPUT ${llext_pkg_output} + COMMAND $ + $ + $.xt.* + $${llext_pkg_input} + $${llext_pkg_output} + $ + DEPENDS ${llext_proc_target} ${llext_pkg_input} + ) + + elseif(CONFIG_LLEXT_TYPE_ELF_SHAREDLIB) # Need to strip the shared library of some sections add_custom_command( @@ -5420,8 +5452,6 @@ function(add_llext_target target_name) DEPENDS ${llext_proc_target} ${llext_pkg_input} ) - else() - message(FATAL_ERROR "add_llext_target: unsupported architecture") endif() # Add user-visible target and dependency, and fill in properties @@ -5449,7 +5479,7 @@ endfunction() # the build. The command will be executed at the specified build step and # can refer to 's properties for build-specific details. # -# The differrent build steps are: +# The different build steps are: # - PRE_BUILD: Before the llext code is linked, if the architecture uses # dynamic libraries. This step can access `lib_target` and # its own properties. @@ -5519,3 +5549,35 @@ function(add_llext_command) COMMAND_EXPAND_LISTS ) endfunction() + +# 7.3 llext helper functions + +# Usage: +# llext_filter_zephyr_flags( ) +# +# Filter out flags from a list of flags. The filter is a list of regular +# expressions that will be used to exclude flags from the input list. +# +# The resulting generator expression will be stored in the variable . +# +# Example: +# llext_filter_zephyr_flags(LLEXT_REMOVE_FLAGS zephyr_flags zephyr_filtered_flags) +# +function(llext_filter_zephyr_flags filter flags outvar) + list(TRANSFORM ${filter} + REPLACE "(.+)" "^\\1$" + OUTPUT_VARIABLE llext_remove_flags_regexp + ) + list(JOIN llext_remove_flags_regexp "|" llext_remove_flags_regexp) + if ("${llext_remove_flags_regexp}" STREQUAL "") + # an empty regexp would match anything, we actually need the opposite + # so set it to match empty strings + set(llext_remove_flags_regexp "^$") + endif() + + set(zephyr_filtered_flags + "$" + ) + + set(${outvar} ${zephyr_filtered_flags} PARENT_SCOPE) +endfunction() diff --git a/cmake/modules/kernel.cmake b/cmake/modules/kernel.cmake index 06e1642f362..b4906872a30 100644 --- a/cmake/modules/kernel.cmake +++ b/cmake/modules/kernel.cmake @@ -131,7 +131,7 @@ project(Zephyr-Kernel VERSION ${PROJECT_VERSION}) # because clang from OneApi can't recognize them as asm files on # windows now. list(APPEND CMAKE_ASM_SOURCE_FILE_EXTENSIONS "S") -enable_language(C CXX ASM) +enable_language(ASM) # The setup / configuration of the toolchain itself and the configuration of # supported compilation flags are now split, as this allows to use the toolchain @@ -168,6 +168,11 @@ set(KERNEL_STRIP_NAME ${KERNEL_NAME}.strip) set(KERNEL_META_NAME ${KERNEL_NAME}.meta) set(KERNEL_SYMBOLS_NAME ${KERNEL_NAME}.symbols) +# Enable dynamic library support when required by LLEXT. +if(CONFIG_LLEXT AND CONFIG_LLEXT_TYPE_ELF_SHAREDLIB) + set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS TRUE) +endif() + include(${BOARD_DIR}/board.cmake OPTIONAL) # If we are using a suitable ethernet driver inside qemu, then these options diff --git a/cmake/modules/shields.cmake b/cmake/modules/shields.cmake index ec172512b68..145f559b292 100644 --- a/cmake/modules/shields.cmake +++ b/cmake/modules/shields.cmake @@ -60,7 +60,7 @@ foreach(root ${BOARD_ROOT}) # from each file and looking for .overlay files in there. # Each overlay corresponds to a shield. We obtain the shield name by # removing the .overlay extension. - unset(SHIELD_LIST) + # We also create a SHIELD_DIR_${name} variable for each shield's directory. foreach(shields_refs ${shields_refs_list}) get_filename_component(shield_path ${shields_refs} DIRECTORY) file(GLOB shield_overlays RELATIVE ${shield_path} ${shield_path}/*.overlay) @@ -70,34 +70,21 @@ foreach(root ${BOARD_ROOT}) set(SHIELD_DIR_${shield} ${shield_path}) endforeach() endforeach() - - if(DEFINED SHIELD) - foreach(s ${SHIELD_AS_LIST}) - if(NOT ${s} IN_LIST SHIELD_LIST) - continue() - endif() - - list(REMOVE_ITEM SHIELD-NOTFOUND ${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 a temporary variable - set(shield_${s}_conf_file ${SHIELD_DIR_${s}}/${s}.conf) - endif() - endforeach() - endif() endforeach() # Process shields in-order if(DEFINED SHIELD) foreach(s ${SHIELD_AS_LIST}) + if(NOT ${s} IN_LIST SHIELD_LIST) + continue() + endif() + + list(REMOVE_ITEM SHIELD-NOTFOUND ${s}) + # Add .overlay to the shield_dts_files output variable. list(APPEND shield_dts_files - ${shield_${s}_dts_file} + ${SHIELD_DIR_${s}}/${s}.overlay ) # Add the shield's directory to the SHIELD_DIRS output variable. @@ -106,10 +93,11 @@ if(DEFINED SHIELD) ${SHIELD_DIR_${s}} ) - if(DEFINED shield_${s}_conf_file) + # Search for shield/shield.conf file + if(EXISTS ${SHIELD_DIR_${s}}/${s}.conf) list(APPEND shield_conf_files - ${shield_${s}_conf_file} + ${SHIELD_DIR_${s}}/${s}.conf ) endif() diff --git a/cmake/modules/unittest.cmake b/cmake/modules/unittest.cmake index 79e6c269c7c..892358999cf 100644 --- a/cmake/modules/unittest.cmake +++ b/cmake/modules/unittest.cmake @@ -58,8 +58,30 @@ include(${ZEPHYR_BASE}/cmake/kobj.cmake) add_dependencies(test_interface ${KOBJ_TYPES_H_TARGET}) gen_kobj(KOBJ_GEN_DIR) +# Generates empty header files to build +set(INCL_GENERATED_DIR ${APPLICATION_BINARY_DIR}/zephyr/include/generated) +set(INCL_GENERATED_SYSCALL_DIR ${INCL_GENERATED_DIR}/syscalls) +list(APPEND INCL_GENERATED_HEADERS + ${INCL_GENERATED_DIR}/devicetree_generated.h + ${INCL_GENERATED_DIR}/offsets.h + ${INCL_GENERATED_DIR}/syscall_list.h + ${INCL_GENERATED_DIR}/syscall_macros.h + ${INCL_GENERATED_SYSCALL_DIR}/kernel.h + ${INCL_GENERATED_SYSCALL_DIR}/kobject.h + ${INCL_GENERATED_SYSCALL_DIR}/log_core.h + ${INCL_GENERATED_SYSCALL_DIR}/log_ctrl.h + ${INCL_GENERATED_SYSCALL_DIR}/log_msg.h + ${INCL_GENERATED_SYSCALL_DIR}/sys_clock.h +) + +file(MAKE_DIRECTORY ${INCL_GENERATED_SYSCALL_DIR}) +foreach(header ${INCL_GENERATED_HEADERS}) + file(TOUCH ${header}) +endforeach() + list(APPEND INCLUDE subsys/testsuite/ztest/include/zephyr + subsys/testsuite/ztest/unittest/include subsys/testsuite/include/zephyr subsys/testsuite/ztest/include subsys/testsuite/include diff --git a/cmake/modules/version.cmake b/cmake/modules/version.cmake index 72c0424031a..16d772e2cde 100644 --- a/cmake/modules/version.cmake +++ b/cmake/modules/version.cmake @@ -36,8 +36,12 @@ # The final load of `version.cmake` will setup correct build version values. 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) + set(VERSION_FILE ${ZEPHYR_BASE}/VERSION) + set(VERSION_TYPE KERNEL) + if(DEFINED APPLICATION_SOURCE_DIR) + list(APPEND VERSION_FILE ${APPLICATION_SOURCE_DIR}/VERSION) + list(APPEND VERSION_TYPE APP) + endif() endif() foreach(type file IN ZIP_LISTS VERSION_TYPE VERSION_FILE) diff --git a/cmake/toolchain/arcmwdt/Kconfig b/cmake/toolchain/arcmwdt/Kconfig index c2ef35d3c79..3f70536b367 100644 --- a/cmake/toolchain/arcmwdt/Kconfig +++ b/cmake/toolchain/arcmwdt/Kconfig @@ -4,3 +4,7 @@ config TOOLCHAIN_ARCMWDT_SUPPORTS_THREAD_LOCAL_STORAGE def_bool y select TOOLCHAIN_SUPPORTS_THREAD_LOCAL_STORAGE + +config TOOLCHAIN_ARCMWDT_SUPPORTS_GNU_EXTENSIONS + def_bool y + select TOOLCHAIN_SUPPORTS_GNU_EXTENSIONS diff --git a/cmake/toolchain/arcmwdt/Kconfig.defconfig b/cmake/toolchain/arcmwdt/Kconfig.defconfig new file mode 100644 index 00000000000..78164376629 --- /dev/null +++ b/cmake/toolchain/arcmwdt/Kconfig.defconfig @@ -0,0 +1,5 @@ +# Copyright (c) 2024 Synopsys +# SPDX-License-Identifier: Apache-2.0 + +config PICOLIBC_SUPPORTED + default n diff --git a/cmake/toolchain/arcmwdt/generic.cmake b/cmake/toolchain/arcmwdt/generic.cmake index 3f5fded2dac..42a8331f004 100644 --- a/cmake/toolchain/arcmwdt/generic.cmake +++ b/cmake/toolchain/arcmwdt/generic.cmake @@ -23,7 +23,17 @@ find_package(Zephyr-sdk 0.15 REQUIRED) # https://github.com/zephyrproject-rtos/sdk-ng/pull/682 got merged and we switch to proper SDK # version. set(TOOLCHAIN_HOME ${ZEPHYR_SDK_INSTALL_DIR}) -include(${ZEPHYR_SDK_INSTALL_DIR}/cmake/zephyr/target.cmake) + +# On very early stage build system needs to get access to DTC preprocessor. +# MWDT has no it's own preprocessor, so here zephyr-SDK preprocessor is used. +# At the same time zephyr-SDK requires ARCH variable to be initialized before include "generic.cmake", +# but in hew HWMv2 model ARCH variable will be initialized more later. +# This workaround uses any (first awailable, independent on ARCH) toolchain from SDK for DTC preprocessing only. +# For other build stages ARCMWDT will be used. +include(${ZEPHYR_SDK_INSTALL_DIR}/cmake/zephyr/generic.cmake) +unset(TOOLCHAIN_HAS_NEWLIB CACHE) +unset(TOOLCHAIN_HAS_PICOLIBC CACHE) + set(ZEPHYR_SDK_CROSS_COMPILE ${CROSS_COMPILE}) # Handling to be improved in Zephyr SDK, to avoid overriding ZEPHYR_TOOLCHAIN_VARIANT by # find_package(Zephyr-sdk) if it's already set diff --git a/cmake/toolchain/armclang/Kconfig b/cmake/toolchain/armclang/Kconfig index 19b7bcca515..27be295057c 100644 --- a/cmake/toolchain/armclang/Kconfig +++ b/cmake/toolchain/armclang/Kconfig @@ -23,3 +23,7 @@ config ARMCLANG_STD_LIBC not provided by ARM Compiler standard libraries. endchoice + +config TOOLCHAIN_ARMCLANG_SUPPORTS_GNU_EXTENSIONS + def_bool y + select TOOLCHAIN_SUPPORTS_GNU_EXTENSIONS diff --git a/cmake/toolchain/cross-compile/Kconfig b/cmake/toolchain/cross-compile/Kconfig index d2da9acbd8d..1f2fbd37d1f 100644 --- a/cmake/toolchain/cross-compile/Kconfig +++ b/cmake/toolchain/cross-compile/Kconfig @@ -7,3 +7,10 @@ config TOOLCHAIN_CROSS_COMPILE_SUPPORTS_THREAD_LOCAL_STORAGE help Set this if the cross-compile toolchain being used for the build supports thread local storage. + +config TOOLCHAIN_CROSS_COMPILE_SUPPORTS_GNU_EXTENSIONS + bool "Cross-compile toolchain supports GNU Extensions" + select TOOLCHAIN_SUPPORTS_GNU_EXTENSIONS + help + Set this if the cross-compile toolchain being used for the build + supports GNU Extensions. diff --git a/cmake/toolchain/gnuarmemb/Kconfig b/cmake/toolchain/gnuarmemb/Kconfig index 702d503ddd9..9d34449f4c7 100644 --- a/cmake/toolchain/gnuarmemb/Kconfig +++ b/cmake/toolchain/gnuarmemb/Kconfig @@ -7,3 +7,7 @@ config TOOLCHAIN_GNUARMEMB def_bool y select HAS_NEWLIB_LIBC_NANO select NEWLIB_LIBC_SUPPORTED + +config TOOLCHAIN_GNUARMEMB_SUPPORTS_GNU_EXTENSIONS + def_bool y + select TOOLCHAIN_SUPPORTS_GNU_EXTENSIONS diff --git a/cmake/toolchain/host/Kconfig b/cmake/toolchain/host/Kconfig new file mode 100644 index 00000000000..81958491352 --- /dev/null +++ b/cmake/toolchain/host/Kconfig @@ -0,0 +1,6 @@ +# Copyright (c) 2024 Basalte bv +# SPDX-License-Identifier: Apache-2.0 + +config TOOLCHAIN_HOST_SUPPORTS_GNU_EXTENSIONS + def_bool y + select TOOLCHAIN_SUPPORTS_GNU_EXTENSIONS diff --git a/cmake/toolchain/llvm/Kconfig b/cmake/toolchain/llvm/Kconfig index 0e2e3e85863..50293b2d61e 100644 --- a/cmake/toolchain/llvm/Kconfig +++ b/cmake/toolchain/llvm/Kconfig @@ -19,6 +19,10 @@ config LLVM_USE_LLD endchoice config TOOLCHAIN_LLVM_SUPPORTS_THREAD_LOCAL_STORAGE - depends on RISCV + depends on RISCV || ARM def_bool y select TOOLCHAIN_SUPPORTS_THREAD_LOCAL_STORAGE + +config TOOLCHAIN_LLVM_SUPPORTS_GNU_EXTENSIONS + def_bool y + select TOOLCHAIN_SUPPORTS_GNU_EXTENSIONS diff --git a/cmake/toolchain/llvm/target.cmake b/cmake/toolchain/llvm/target.cmake index a2240c02364..8446e22ced8 100644 --- a/cmake/toolchain/llvm/target.cmake +++ b/cmake/toolchain/llvm/target.cmake @@ -25,8 +25,6 @@ if("${ARCH}" STREQUAL "arm") # Default ARM target supported by all processors. set(triple arm-none-eabi) endif() - - set(CMAKE_EXE_LINKER_FLAGS_INIT "--specs=nosys.specs") elseif("${ARCH}" STREQUAL "x86") if(CONFIG_64BIT) set(triple x86_64-pc-none-elf) diff --git a/cmake/usage/usage.cmake b/cmake/usage/usage.cmake index 2f4b0b76ddd..8ff24025954 100644 --- a/cmake/usage/usage.cmake +++ b/cmake/usage/usage.cmake @@ -31,6 +31,7 @@ message(" initlevels - Display the initialization sequence") message(" boards - Display supported boards") message(" shields - Display supported shields") message(" usage - Display this text") +message(" llext-edk - Build the Linkable Loadable Extension (LLEXT) Extension Development Kit (EDK)") message(" help - Display all build system targets") message("") message("Build flags:") diff --git a/doc/_scripts/redirects.py b/doc/_scripts/redirects.py index 49aec7ad039..91586470fea 100644 --- a/doc/_scripts/redirects.py +++ b/doc/_scripts/redirects.py @@ -15,17 +15,36 @@ REDIRECTS = [ # zephyr-keep-sorted-start ('application/index', 'develop/application/index'), + ('boards/arduino/uno_r4_minima/doc/index', 'boards/arduino/uno_r4/doc/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/bluetooth/audio', 'connectivity/bluetooth/api/audio/audio'), + ('connectivity/bluetooth/bap', 'connectivity/bluetooth/api/audio/bap'), ('connectivity/bluetooth/bluetooth-audio-arch', 'connectivity/bluetooth/bluetooth-le-audio-arch'), + ('connectivity/bluetooth/bluetooth-le-audio-arch', 'connectivity/bluetooth/api/audio/bluetooth-le-audio-arch'), + ('connectivity/bluetooth/cap', 'connectivity/bluetooth/api/audio/cap'), + ('connectivity/bluetooth/coordinated_sets', 'connectivity/bluetooth/api/audio/coordinated_sets'), ('connectivity/bluetooth/dis-pics', 'connectivity/bluetooth/ics/dis'), ('connectivity/bluetooth/gap-pics', 'connectivity/bluetooth/ics/gap'), ('connectivity/bluetooth/gatt-pics', 'connectivity/bluetooth/ics/gatt'), ('connectivity/bluetooth/l2cap-pics', 'connectivity/bluetooth/ics/l2cap'), + ('connectivity/bluetooth/media', 'connectivity/bluetooth/api/audio/media'), ('connectivity/bluetooth/mesh-pics', 'connectivity/bluetooth/ics/mesh'), + ('connectivity/bluetooth/microphone', 'connectivity/bluetooth/api/audio/microphone'), ('connectivity/bluetooth/overview', 'connectivity/bluetooth/features'), ('connectivity/bluetooth/rfcomm-pics', 'connectivity/bluetooth/ics/rfcomm'), + ('connectivity/bluetooth/shell/bap', 'connectivity/bluetooth/api/audio/shell/bap'), + ('connectivity/bluetooth/shell/bap_broadcast_assistant', 'connectivity/bluetooth/api/audio/shell/bap_broadcast_assistant'), + ('connectivity/bluetooth/shell/bap_scan_delegator', 'connectivity/bluetooth/api/audio/shell/bap_scan_delegator'), + ('connectivity/bluetooth/shell/cap', 'connectivity/bluetooth/api/audio/shell/cap'), + ('connectivity/bluetooth/shell/ccp', 'connectivity/bluetooth/api/audio/shell/ccp'), + ('connectivity/bluetooth/shell/csip', 'connectivity/bluetooth/api/audio/shell/csip'), + ('connectivity/bluetooth/shell/gmap', 'connectivity/bluetooth/api/audio/shell/gmap'), + ('connectivity/bluetooth/shell/mcp', 'connectivity/bluetooth/api/audio/shell/mcp'), + ('connectivity/bluetooth/shell/pbp', 'connectivity/bluetooth/api/audio/shell/pbp'), + ('connectivity/bluetooth/shell/tmap', 'connectivity/bluetooth/api/audio/shell/tmap'), ('connectivity/bluetooth/sm-pics', 'connectivity/bluetooth/ics/sm'), + ('connectivity/bluetooth/volume', 'connectivity/bluetooth/api/audio/volume'), ('connectivity/networking/networking-api-usage', 'connectivity/networking/api/index'), ('development_process/code_flow', 'project/code_flow'), ('development_process/index', 'project/index'), @@ -180,6 +199,8 @@ ('reference/usermode/overview', 'kernel/usermode/overview'), ('reference/usermode/syscalls', 'kernel/usermode/syscalls'), ('reference/util/index', 'kernel/util/index'), + ('samples/application_development/with_mcuboot/README', 'samples/sysbuild/with_mcuboot/README'), + ('samples/drivers/adc/README', 'samples/drivers/adc/adc_dt/README'), ('samples/drivers/kscan_touch', 'samples/subsys/input/input'), ('samples/drivers/led_apa102/README', 'samples/drivers/led_strip/README'), ('samples/drivers/led_lpd8806/README', 'samples/drivers/led_strip/README'), diff --git a/doc/build/dts/macros.bnf b/doc/build/dts/macros.bnf index f42f4838877..88ed70f2ba9 100644 --- a/doc/build/dts/macros.bnf +++ b/doc/build/dts/macros.bnf @@ -73,6 +73,9 @@ node-macro =/ %s"DT_N" path-id %s"_P_" prop-id %s"_FOREACH_PROP_ELEM" node-macro =/ %s"DT_N" path-id %s"_P_" prop-id %s"_FOREACH_PROP_ELEM_SEP" node-macro =/ %s"DT_N" path-id %s"_P_" prop-id %s"_FOREACH_PROP_ELEM_VARGS" node-macro =/ %s"DT_N" path-id %s"_P_" prop-id %s"_FOREACH_PROP_ELEM_SEP_VARGS" +; These are used by DT_CHILD_NUM and DT_CHILD_NUM_STATUS_OKAY macros +node-macro =/ %s"DT_N" path-id %s"_CHILD_NUM" +node-macro =/ %s"DT_N" path-id %s"_CHILD_NUM_STATUS_OKAY" ; These are used internally by DT_FOREACH_CHILD, which iterates over ; each child node. node-macro =/ %s"DT_N" path-id %s"_FOREACH_CHILD" diff --git a/doc/build/kconfig/setting.rst b/doc/build/kconfig/setting.rst index ba3ee33938a..81286311f53 100644 --- a/doc/build/kconfig/setting.rst +++ b/doc/build/kconfig/setting.rst @@ -126,7 +126,7 @@ The initial configuration for an application comes from merging configuration settings from three sources: 1. A ``BOARD``-specific configuration file stored in - :file:`boards///_defconfig` + :file:`boards///_defconfig` 2. Any CMake cache entries prefix with ``CONFIG_`` @@ -154,9 +154,6 @@ used. :file:`boards/_.conf` is used - note that this feature is deprecated, :ref:`application-file-suffixes` should be used instead. -#. Otherwise, :file:`prj_.conf` is used if it exists in the application - configuration directory. - #. Otherwise, if :file:`boards/.conf` exists in the application configuration directory, the result of merging it with :file:`prj.conf` is used. @@ -204,7 +201,7 @@ Configuring invisible Kconfig symbols When making changes to the default configuration for a board, you might have to configure invisible symbols. This is done in -:file:`boards///Kconfig.defconfig`, which is a regular +:file:`boards///Kconfig.defconfig`, which is a regular :file:`Kconfig` file. .. note:: diff --git a/doc/build/kconfig/tips.rst b/doc/build/kconfig/tips.rst index 2e50c6c8775..d66971c846b 100644 --- a/doc/build/kconfig/tips.rst +++ b/doc/build/kconfig/tips.rst @@ -1060,7 +1060,7 @@ This is logically equivalent to the following: See the `optional prompts`_ section for the meaning of the conditions on the prompts. -When ``HAS_CONFIGURABLE`` is ``n``, we now get the following configuration +When ``HAS_CONFIGURABLE_FOO`` is ``n``, we now get the following configuration output for the symbols, instead of no output: .. code-block:: cfg diff --git a/doc/build/sysbuild/index.rst b/doc/build/sysbuild/index.rst index 55c0c87504e..295b7767555 100644 --- a/doc/build/sysbuild/index.rst +++ b/doc/build/sysbuild/index.rst @@ -170,7 +170,7 @@ applying to both images debug optimizations: :board: reel_board :goals: build :west-args: --sysbuild - :gen-args: -DSB_CONFIG_BOOTLOADER_MCUBOOT=y -DCONFIG_DEBUG_OPTIMIZATIONS=y -Dmcuboot_DEBUG_OPTIMIZATIONS=y + :gen-args: -DSB_CONFIG_BOOTLOADER_MCUBOOT=y -DCONFIG_DEBUG_OPTIMIZATIONS=y -Dmcuboot_CONFIG_DEBUG_OPTIMIZATIONS=y :compact: .. group-tab:: ``cmake`` @@ -180,7 +180,7 @@ applying to both images debug optimizations: :app: share/sysbuild :board: reel_board :goals: build - :gen-args: -DAPP_DIR=samples/hello_world -DSB_CONFIG_BOOTLOADER_MCUBOOT=y -DCONFIG_DEBUG_OPTIMIZATIONS=y -Dmcuboot_DEBUG_OPTIMIZATIONS=y + :gen-args: -DAPP_DIR=samples/hello_world -DSB_CONFIG_BOOTLOADER_MCUBOOT=y -DCONFIG_DEBUG_OPTIMIZATIONS=y -Dmcuboot_CONFIG_DEBUG_OPTIMIZATIONS=y :compact: See the following subsections for more information. diff --git a/doc/connectivity/bluetooth/api/audio.rst b/doc/connectivity/bluetooth/api/audio/audio.rst similarity index 100% rename from doc/connectivity/bluetooth/api/audio.rst rename to doc/connectivity/bluetooth/api/audio/audio.rst diff --git a/doc/connectivity/bluetooth/api/bap.rst b/doc/connectivity/bluetooth/api/audio/bap.rst similarity index 100% rename from doc/connectivity/bluetooth/api/bap.rst rename to doc/connectivity/bluetooth/api/audio/bap.rst diff --git a/doc/connectivity/bluetooth/bluetooth-le-audio-arch.rst b/doc/connectivity/bluetooth/api/audio/bluetooth-le-audio-arch.rst similarity index 88% rename from doc/connectivity/bluetooth/bluetooth-le-audio-arch.rst rename to doc/connectivity/bluetooth/api/audio/bluetooth-le-audio-arch.rst index a9a43c3891a..ef4bf447d3d 100644 --- a/doc/connectivity/bluetooth/bluetooth-le-audio-arch.rst +++ b/doc/connectivity/bluetooth/api/audio/bluetooth-le-audio-arch.rst @@ -9,6 +9,23 @@ LE Audio Stack Bluetooth Audio Architecture +Overall design +************** + +The overall design of the LE Audio stack is that the implementation follows the specifications +as closely as possible, +both in terms of structure but also naming. +Most API functions are prefixed by the specification acronym +(e.g. `bt_bap` for the Basic Audio Profile (BAP) and `bt_vcp` for the Volume Control Profile (VCP)). +The functions are then further prefixed with the specific role from each profile where applicable +(e.g. :c:func:`bt_bap_unicast_client_discover` and :c:func:`bt_vcp_vol_rend_set_vol`). +There are usually a function per procedure defined by the profile or service specifications, +and additional helper or meta functions that do not correspond to procedures. + +The structure of the files generally also follow this, +where BAP related files are prefixed with `bap` and VCP related files are prefixed with `vcp`. +If the file is specific for a profile role, the role is also embedded in the file name. + Generic Audio Framework (GAF) ***************************** The Generic Audio Framework (GAF) is considered the middleware of the Bluetooth @@ -494,6 +511,92 @@ The CSIP implementation supports the following roles The API reference for media control can be found in :ref:`Bluetooth Coordinated Sets `. +Specification correctness and data location +------------------------------------------- + +The implementations are designed to ensure specification compliance as much as possible. +When a specification introduces a requirement with e.g. a **shall** then the implementation should +attempt to ensure that this requirement is always followed. +Depending on the context of this, +the implementation ensures this by rejecting invalid parameters from the application, +or from the remote devices. + +Some requirements from the specifications are not or can not be handled by the stack itself for +various reasons. +One reason when the stack cannot handle a requirement is if the data related to the requirement is +exclusively controlled by the application. +An example of this is the advertising data, +where multiple service have requirements for what to advertise and when, +but where both the advertising state and data is exclusively controlled by the application. + +Oppositely there are also requirements from the specification, +where the data related to the requirement is exclusively controlled by the stack. +An example of this is the Volume Control Service (VCS) state, +where the specifications mandata that the VCP Volume Renderer (VCS server) modify the values +without a choice, +e.g. when setting the absolutely volume. +In cases like this the application is only notified about the change with a callback, +but cannot reject the request (the stack will reject any invalid requests). + +Generally when the data is simple (like the VCS state which only take up a few bytes), +the data is kept in and controlled by the stack, +as this can ensure that the requirements can be handled by the stack, +making it easier to use a profile role correctly. +When the data is more complex (e.g. the PAC records), +the data may be kept by the application and the stack only contains a reference to it. +When the data is very application specific (e.g. advertising data), +the data is kept in and controlled by the application. + +As a rule of thumb, the return types of the callbacks for each profile implementation indicate +whether the data is controlled by the stack or the application. +For example all the callbacks for the VCP Volume Renderer have the return type of `void`, +but the return type of the BAP Unicast Server callbacks are `int`, +indicating that the application not only controls a lot of the Unicast Server data, +but can also reject the requests. +The choice of what the return type of the callbacks often depend on the specifications, +and how much control the role has in a given context. + +Things worth knowing or considering when using LE Audio +======================================================= + +This section describes a few tings to consider when contributing to or using LE Audio in Zephyr. +The things described by this section are not unique to Zephyr as they are defined by the +specifications. + +Security requirements +--------------------- + +All LE Audio services require Security Level 2 but where the key must be 128-bit and derived via an +OOB method or via LE Secure connections. +There is no Core-spec defined way of reporting this in GATT, +as ATT does not have a specific error code for missing OOB method or LE Secure Connections +(although there is a way to report wrong key size). + +In Zephyr we do not force the device to always use these, as a device that uses LE Audio may also +use other profiles and services that do not require such security. +We guard all access to services using a custom security check implemented in +:zephyr_file:`subsys/bluetooth/audio/audio.c`, where all LE Audio services must use the +internal `BT_AUDIO_CHRC` macro for proper security verification. + +Access to the LTK for encrypted SIRKs in CSIS +--------------------------------------------- + +The Coordinated Set Identification Service (CSIS) may encrypt the SIRK (set identity resolving key). +The process of encrypting the SIRK requires the LTK as the encryption key, +which is typically not exposed to higher layer implementations such as CSIS. +This does not have any effect on the security though. + +MTU requirements +---------------- + +The Basic Audio Profile (BAP) has a requirement that both sides shall support a minimum ATT_MTU of +at least 64 on the unenhanced ATT bearer or at least one enhanced ATT bearer. +The requirement comes from the preferred (or sometimes mandatory) use of GATT Write Without +Response, and where support for Write Long Characterstic Value is optional in most cases. + +If a ASCS device supports values larger than the minimum ATT_MTU of 64 octets, then it shall supoort +Read long Characterstic Value by setting :kconfig:option:`CONFIG_BT_ATT_PREPARE_COUNT` to a +non-zero value. LE Audio resources ################## diff --git a/doc/connectivity/bluetooth/api/cap.rst b/doc/connectivity/bluetooth/api/audio/cap.rst similarity index 100% rename from doc/connectivity/bluetooth/api/cap.rst rename to doc/connectivity/bluetooth/api/audio/cap.rst diff --git a/doc/connectivity/bluetooth/api/coordinated_sets.rst b/doc/connectivity/bluetooth/api/audio/coordinated_sets.rst similarity index 100% rename from doc/connectivity/bluetooth/api/coordinated_sets.rst rename to doc/connectivity/bluetooth/api/audio/coordinated_sets.rst diff --git a/doc/connectivity/bluetooth/img/ble_audio_arch.svg b/doc/connectivity/bluetooth/api/audio/img/ble_audio_arch.svg similarity index 100% rename from doc/connectivity/bluetooth/img/ble_audio_arch.svg rename to doc/connectivity/bluetooth/api/audio/img/ble_audio_arch.svg diff --git a/doc/connectivity/bluetooth/img/cap_proc.svg b/doc/connectivity/bluetooth/api/audio/img/cap_proc.svg similarity index 100% rename from doc/connectivity/bluetooth/img/cap_proc.svg rename to doc/connectivity/bluetooth/api/audio/img/cap_proc.svg diff --git a/doc/connectivity/bluetooth/img/gaf.svg b/doc/connectivity/bluetooth/api/audio/img/gaf.svg similarity index 100% rename from doc/connectivity/bluetooth/img/gaf.svg rename to doc/connectivity/bluetooth/api/audio/img/gaf.svg diff --git a/doc/connectivity/bluetooth/img/zephyr_gaf.svg b/doc/connectivity/bluetooth/api/audio/img/zephyr_gaf.svg similarity index 100% rename from doc/connectivity/bluetooth/img/zephyr_gaf.svg rename to doc/connectivity/bluetooth/api/audio/img/zephyr_gaf.svg diff --git a/doc/connectivity/bluetooth/api/media.rst b/doc/connectivity/bluetooth/api/audio/media.rst similarity index 100% rename from doc/connectivity/bluetooth/api/media.rst rename to doc/connectivity/bluetooth/api/audio/media.rst diff --git a/doc/connectivity/bluetooth/api/microphone.rst b/doc/connectivity/bluetooth/api/audio/microphone.rst similarity index 100% rename from doc/connectivity/bluetooth/api/microphone.rst rename to doc/connectivity/bluetooth/api/audio/microphone.rst diff --git a/doc/connectivity/bluetooth/api/shell/bap.rst b/doc/connectivity/bluetooth/api/audio/shell/bap.rst similarity index 100% rename from doc/connectivity/bluetooth/api/shell/bap.rst rename to doc/connectivity/bluetooth/api/audio/shell/bap.rst diff --git a/doc/connectivity/bluetooth/api/shell/bap_broadcast_assistant.rst b/doc/connectivity/bluetooth/api/audio/shell/bap_broadcast_assistant.rst similarity index 98% rename from doc/connectivity/bluetooth/api/shell/bap_broadcast_assistant.rst rename to doc/connectivity/bluetooth/api/audio/shell/bap_broadcast_assistant.rst index 5ebd7b34327..2fdd25192c1 100644 --- a/doc/connectivity/bluetooth/api/shell/bap_broadcast_assistant.rst +++ b/doc/connectivity/bluetooth/api/audio/shell/bap_broadcast_assistant.rst @@ -14,7 +14,8 @@ The Broadcast Assistant will typically be phones or laptops. The Broadcast Assistant scans for periodic advertisements and transfer information to the server. -It is necessary to have :code:`BT_DEBUG_BAP_BROADCAST_ASSISTANT` enabled for +It is necessary to have +:kconfig:option:`CONFIG_BT_BAP_BROADCAST_ASSISTANT_LOG_LEVEL_DBG` enabled for using the Broadcast Assistant interactively. When the Bluetooth stack has been initialized (:code:`bt init`), diff --git a/doc/connectivity/bluetooth/api/shell/bap_scan_delegator.rst b/doc/connectivity/bluetooth/api/audio/shell/bap_scan_delegator.rst similarity index 92% rename from doc/connectivity/bluetooth/api/shell/bap_scan_delegator.rst rename to doc/connectivity/bluetooth/api/audio/shell/bap_scan_delegator.rst index cbdbc8ecbce..ad9348c1705 100644 --- a/doc/connectivity/bluetooth/api/shell/bap_scan_delegator.rst +++ b/doc/connectivity/bluetooth/api/audio/shell/bap_scan_delegator.rst @@ -11,7 +11,8 @@ synchronization transfer (PAST) protocol. The Scan Delegator server typically resides on devices that have inputs or outputs. -It is necessary to have :code:`BT_DEBUG_BAP_SCAN_DELEGATOR` enabled for using +It is necessary to have +:kconfig:option:`CONFIG_BT_BAP_SCAN_DELEGATOR_LOG_LEVEL_DBG` enabled for using the Scan Delegator interactively. The Scan Delegator can currently only set the sync state of a receive state, but diff --git a/doc/connectivity/bluetooth/api/shell/cap.rst b/doc/connectivity/bluetooth/api/audio/shell/cap.rst similarity index 88% rename from doc/connectivity/bluetooth/api/shell/cap.rst rename to doc/connectivity/bluetooth/api/audio/shell/cap.rst index aa5854442e6..0cb65d87f79 100644 --- a/doc/connectivity/bluetooth/api/shell/cap.rst +++ b/doc/connectivity/bluetooth/api/audio/shell/cap.rst @@ -78,16 +78,39 @@ The CAP initiator also supports broadcast audio as a source. .. code-block:: console - cap_initiator --help + uart:~$ cap_initiator --help cap_initiator - Bluetooth CAP initiator shell commands Subcommands: - discover :Discover CAS - unicast_start :Unicast Start [csip] [sinks (default 1)] [sources - (default 1)] [conns ( | all) (default 1)] - unicast_list :Unicast list streams - unicast_update :Unicast Update - unicast_stop :Unicast stop streams [stream [stream [stream...]]] (all by default) - unicast_cancel :Unicast cancel current procedure + discover : Discover CAS + unicast_start : Unicast Start [csip] [sinks (default 1)] [sources + (default 1)] [conns ( | all) (default 1)] + unicast_list : Unicast list streams + unicast_update : Unicast Update + unicast_stop :Unicast stop streams [stream [stream [stream...]]] (all by default) + unicast_cancel : Unicast cancel current procedure + ac_1 : Unicast audio configuration 1 + ac_2 : Unicast audio configuration 2 + ac_3 : Unicast audio configuration 3 + ac_4 : Unicast audio configuration 4 + ac_5 : Unicast audio configuration 5 + ac_6_i : Unicast audio configuration 6(i) + ac_6_ii : Unicast audio configuration 6(ii) + ac_7_i : Unicast audio configuration 7(i) + ac_7_ii : Unicast audio configuration 7(ii) + ac_8_i : Unicast audio configuration 8(i) + ac_8_ii : Unicast audio configuration 8(ii) + ac_9_i : Unicast audio configuration 9(i) + ac_9_ii : Unicast audio configuration 9(ii) + ac_10 : Unicast audio configuration 10 + ac_11_i : Unicast audio configuration 11(i) + ac_11_ii : Unicast audio configuration 11(ii) + broadcast_start : + broadcast_update : + broadcast_stop : + broadcast_delete : + ac_12 : Broadcast audio configuration 12 + ac_13 : Broadcast audio configuration 13 + ac_14 : Broadcast audio configuration 14 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` @@ -183,7 +206,8 @@ The following commands will setup a CAP broadcast source using the 16_2_1 preset bap init bt adv-create nconn-nscan ext-adv name bt per-adv-param - cap_initiator ac_12 16_2_1 + bap preset broadcast 16_2_1 + cap_initiator ac_12 bt adv-data discov bt per-adv-data cap_initiator broadcast_start @@ -234,6 +258,7 @@ the optionally included CSIS instance by calling (:code:`cap_commander discover` cap_commander - Bluetooth CAP commander shell commands Subcommands: discover :Discover CAS + cancel :CAP commander cancel current procedure change_volume :Change volume on all connections change_volume_mute :Change volume mute state on all connections change_volume_offset :Change volume offset per connection + 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:~$ bap preset sink 32_2_gr + uart:~$ bap preset source 32_2_gs + uart:~$ gmap ac_3 + 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/audio/shell/mcp.rst similarity index 100% rename from doc/connectivity/bluetooth/api/shell/mcp.rst rename to doc/connectivity/bluetooth/api/audio/shell/mcp.rst diff --git a/doc/connectivity/bluetooth/api/shell/pbp.rst b/doc/connectivity/bluetooth/api/audio/shell/pbp.rst similarity index 100% rename from doc/connectivity/bluetooth/api/shell/pbp.rst rename to doc/connectivity/bluetooth/api/audio/shell/pbp.rst diff --git a/doc/connectivity/bluetooth/api/shell/tmap.rst b/doc/connectivity/bluetooth/api/audio/shell/tmap.rst similarity index 100% rename from doc/connectivity/bluetooth/api/shell/tmap.rst rename to doc/connectivity/bluetooth/api/audio/shell/tmap.rst diff --git a/doc/connectivity/bluetooth/api/volume.rst b/doc/connectivity/bluetooth/api/audio/volume.rst similarity index 100% rename from doc/connectivity/bluetooth/api/volume.rst rename to doc/connectivity/bluetooth/api/audio/volume.rst diff --git a/doc/connectivity/bluetooth/api/index.rst b/doc/connectivity/bluetooth/api/index.rst index e9c45edd6de..6135df5e6a2 100644 --- a/doc/connectivity/bluetooth/api/index.rst +++ b/doc/connectivity/bluetooth/api/index.rst @@ -19,24 +19,23 @@ Bluetooth LE Audio .. toctree:: :maxdepth: 1 - audio.rst - bap.rst - cap.rst - coordinated_sets.rst - media.rst - microphone.rst - volume.rst - shell/bap.rst - shell/bap_broadcast_assistant.rst - shell/bap_scan_delegator.rst - shell/cap.rst - shell/ccp.rst - shell/csip.rst - shell/gmap.rst - shell/iso.rst - shell/mcp.rst - shell/tmap.rst - shell/pbp.rst + audio/audio.rst + audio/bap.rst + audio/cap.rst + audio/coordinated_sets.rst + audio/media.rst + audio/microphone.rst + audio/volume.rst + audio/shell/bap.rst + audio/shell/bap_broadcast_assistant.rst + audio/shell/bap_scan_delegator.rst + audio/shell/cap.rst + audio/shell/ccp.rst + audio/shell/csip.rst + audio/shell/gmap.rst + audio/shell/mcp.rst + audio/shell/tmap.rst + audio/shell/pbp.rst Bluetooth LE Host ================= @@ -46,6 +45,7 @@ Bluetooth LE Host services.rst gap.rst + shell/iso.rst gatt.rst att.rst diff --git a/doc/connectivity/bluetooth/api/mesh/dfu.rst b/doc/connectivity/bluetooth/api/mesh/dfu.rst index 127d820ba7e..c83377aef85 100644 --- a/doc/connectivity/bluetooth/api/mesh/dfu.rst +++ b/doc/connectivity/bluetooth/api/mesh/dfu.rst @@ -5,7 +5,7 @@ Device Firmware Update (DFU) 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. +1.0. 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 diff --git a/doc/connectivity/bluetooth/api/shell/gmap.rst b/doc/connectivity/bluetooth/api/shell/gmap.rst deleted file mode 100644 index 11259297a5b..00000000000 --- a/doc/connectivity/bluetooth/api/shell/gmap.rst +++ /dev/null @@ -1,82 +0,0 @@ -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/bluetooth-shell.rst b/doc/connectivity/bluetooth/bluetooth-shell.rst index 82e4d0e46da..0e54ab627c9 100644 --- a/doc/connectivity/bluetooth/bluetooth-shell.rst +++ b/doc/connectivity/bluetooth/bluetooth-shell.rst @@ -166,19 +166,20 @@ For example, if you want to create a connectable and scannable advertiser and st Advertiser[0] 0x200022f0 set started You may notice that with this, the custom advertiser does not advertise the device name; you need to -enable it. Continuing from the previous example: +add it. Continuing from the previous example: .. code-block:: console uart:~$ bt adv-stop Advertiser set stopped - uart:~$ bt adv-param conn-scan name + uart:~$ bt adv-data dev-name uart:~$ bt adv-start Advertiser[0] 0x200022f0 set started -You should now see the name of the device in the advertising data. You can also set the advertising -data manually by using the :code:`bt adv-data` command. The following example shows how to set the -advertiser name with it: +You should now see the name of the device in the advertising data. You can also set a custom name by +using :code:`name ` instead of :code:`dev-name`. It is also possible to set the +advertising data manually with the :code:`bt adv-data` command. The following example shows how +to set the advertiser name with it using raw advertising data: .. code-block:: console diff --git a/doc/connectivity/bluetooth/features.rst b/doc/connectivity/bluetooth/features.rst index 09c79f48cad..b290e7fd6e6 100644 --- a/doc/connectivity/bluetooth/features.rst +++ b/doc/connectivity/bluetooth/features.rst @@ -78,10 +78,6 @@ grown to be mature and feature-rich, as can be seen in the section below. * Foundation Models included * Highly configurable, fits as small as 16k RAM devices - * IPSP/6LoWPAN for IPv6 connectivity over Bluetooth LE - - * IPSP node sample application - * Basic Bluetooth BR/EDR (Classic) support * Generic Access Profile (GAP) diff --git a/doc/connectivity/bluetooth/index.rst b/doc/connectivity/bluetooth/index.rst index c4f43563e6d..05e6ff410f7 100644 --- a/doc/connectivity/bluetooth/index.rst +++ b/doc/connectivity/bluetooth/index.rst @@ -17,7 +17,7 @@ hardware, as well as portions of a Classical Bluetooth (BR/EDR) Host layer. bluetooth-qual.rst bluetooth-arch.rst bluetooth-le-host.rst - bluetooth-le-audio-arch.rst + api/audio/bluetooth-le-audio-arch.rst bluetooth-ctlr-arch.rst bluetooth-dev.rst api/index.rst diff --git a/doc/connectivity/networking/api/http.rst b/doc/connectivity/networking/api/http.rst deleted file mode 100644 index d32748e77fa..00000000000 --- a/doc/connectivity/networking/api/http.rst +++ /dev/null @@ -1,78 +0,0 @@ -.. _http_interface: - -HTTP client -########### - -.. contents:: - :local: - :depth: 2 - -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 -either a plain TCP socket (HTTP) or a TLS socket (HTTPS). - -Sample Usage -************ - -The API of the HTTP client library has a single function. - -The following is an example of a request structure created correctly: - -.. code-block:: c - - struct http_request req = { 0 }; - static uint8_t recv_buf[512]; - - req.method = HTTP_GET; - req.url = "/"; - req.host = "localhost"; - req.protocol = "HTTP/1.1"; - req.response = response_cb; - req.recv_buf = recv_buf; - req.recv_buf_len = sizeof(recv_buf); - - /* sock is a file descriptor referencing a socket that has been connected - * to the HTTP server. - */ - ret = http_client_req(sock, &req, 5000, NULL); - -If the server responds to the request, the library provides the response to the -application through the response callback registered in the request structure. -As the library can provide the response in chunks, the application must be able -to process these. - -Together with the structure containing the response data, the callback function -also provides information about whether the library expects to receive more data. - -The following is an example of a very simple response handling function: - -.. code-block:: c - - static void response_cb(struct http_response *rsp, - enum http_final_call final_data, - void *user_data) - { - if (final_data == HTTP_DATA_MORE) { - LOG_INF("Partial data received (%zd bytes)", rsp->data_len); - } else if (final_data == HTTP_DATA_FINAL) { - LOG_INF("All the data received (%zd bytes)", rsp->data_len); - } - - LOG_INF("Response status %s", rsp->http_status); - } - -See :zephyr:code-sample:`HTTP client sample application ` for -more information about the library usage. - -API Reference -************* - -.. doxygengroup:: http_client diff --git a/doc/connectivity/networking/api/http_client.rst b/doc/connectivity/networking/api/http_client.rst new file mode 100644 index 00000000000..fa7876d8411 --- /dev/null +++ b/doc/connectivity/networking/api/http_client.rst @@ -0,0 +1,78 @@ +.. _http_client_interface: + +HTTP Client +########### + +.. contents:: + :local: + :depth: 2 + +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 +either a plain TCP socket (HTTP) or a TLS socket (HTTPS). + +Sample Usage +************ + +The API of the HTTP client library has a single function. + +The following is an example of a request structure created correctly: + +.. code-block:: c + + struct http_request req = { 0 }; + static uint8_t recv_buf[512]; + + req.method = HTTP_GET; + req.url = "/"; + req.host = "localhost"; + req.protocol = "HTTP/1.1"; + req.response = response_cb; + req.recv_buf = recv_buf; + req.recv_buf_len = sizeof(recv_buf); + + /* sock is a file descriptor referencing a socket that has been connected + * to the HTTP server. + */ + ret = http_client_req(sock, &req, 5000, NULL); + +If the server responds to the request, the library provides the response to the +application through the response callback registered in the request structure. +As the library can provide the response in chunks, the application must be able +to process these. + +Together with the structure containing the response data, the callback function +also provides information about whether the library expects to receive more data. + +The following is an example of a very simple response handling function: + +.. code-block:: c + + static void response_cb(struct http_response *rsp, + enum http_final_call final_data, + void *user_data) + { + if (final_data == HTTP_DATA_MORE) { + LOG_INF("Partial data received (%zd bytes)", rsp->data_len); + } else if (final_data == HTTP_DATA_FINAL) { + LOG_INF("All the data received (%zd bytes)", rsp->data_len); + } + + LOG_INF("Response status %s", rsp->http_status); + } + +See :zephyr:code-sample:`HTTP client sample application ` for +more information about the library usage. + +API Reference +************* + +.. doxygengroup:: http_client diff --git a/doc/connectivity/networking/api/http_server.rst b/doc/connectivity/networking/api/http_server.rst new file mode 100644 index 00000000000..362d19ac374 --- /dev/null +++ b/doc/connectivity/networking/api/http_server.rst @@ -0,0 +1,303 @@ +.. _http_server_interface: + +HTTP Server +########### + +.. contents:: + :local: + :depth: 2 + +Overview +******** + +Zephyr provides an HTTP server library, which allows to register HTTP services +and HTTP resources associated with those services. The server creates a listening +socket for every registered service, and handles incoming client connections. +It's possible to communicate over a plain TCP socket (HTTP) or a TLS socket (HTTPS). +Both, HTTP/1.1 (RFC 2616) and HTTP/2 (RFC 9113) protocol versions are supported. + +The server operation is generally transparent for the application, running in a +background thread. The application can control the server activity with +respective API functions. + +Certain resource types (for example dynamic resource) provide resource-specific +application callbacks, allowing the server to interact with the application (for +instance provide resource content, or process request payload). + +Currently, the following resource types are supported: + +* Static resources - content defined compile-time, cannot be modified at runtime + (:c:enumerator:`HTTP_RESOURCE_TYPE_STATIC`). + +* Dynamic resources - content provided at runtime by respective application + callback (:c:enumerator:`HTTP_RESOURCE_TYPE_DYNAMIC`). + +* Websocket resources - allowing to establish Websocket connections with the + server (:c:enumerator:`HTTP_RESOURCE_TYPE_WEBSOCKET`). + +Zephyr provides a sample demonstrating HTTP(s) server operation and various +resource types usage. See :zephyr:code-sample:`sockets-http-server` for more +information. + +Server Setup +************ + +A few prerequisites are needed in order to enable HTTP server functionality in +the application. + +First of all, the HTTP server has to be enabled in applications configuration file +with :kconfig:option:`CONFIG_HTTP_SERVER` Kconfig option: + +.. code-block:: cfg + :caption: ``prj.conf`` + + CONFIG_HTTP_SERVER=y + +All HTTP services and HTTP resources are placed in a dedicated linker section. +The linker section for services is predefined locally, however the application +is responsible for defining linker sections for resources associated with +respective services. Linker section names for resources should be prefixed with +``http_resource_desc_``, appended with the service name. + +Linker sections for resources should be defined in a linker file. For example, +for a service named ``my_service``, the linker section shall be defined as follows: + +.. code-block:: c + :caption: ``sections-rom.ld`` + + #include + + ITERABLE_SECTION_ROM(http_resource_desc_my_service, Z_LINK_ITERABLE_SUBALIGN) + +Finally, the linker file and linker section have to be added to your application +using CMake: + +.. code-block:: cmake + :caption: ``CMakeLists.txt`` + + zephyr_linker_sources(SECTIONS sections-rom.ld) + zephyr_linker_section(NAME http_resource_desc_my_service + KVMA RAM_REGION GROUP RODATA_REGION + SUBALIGN Z_LINK_ITERABLE_SUBALIGN) + +.. note:: + + You need to define a separate linker section for each HTTP service + registered in the system. + +Sample Usage +************ + +Services +======== + +The application needs to define an HTTP service (or multiple services), with +the same name as used for the linker section with :c:macro:`HTTP_SERVICE_DEFINE` +macro: + +.. code-block:: c + + #include + + static uint16_t http_service_port = 80; + + HTTP_SERVICE_DEFINE(my_service, "0.0.0.0", &http_service_port, 1, 10, NULL); + +Alternatively, an HTTPS service can be defined with with +:c:macro:`HTTPS_SERVICE_DEFINE`: + +.. code-block:: c + + #include + #include + + #define HTTP_SERVER_CERTIFICATE_TAG 1 + + static uint16_t https_service_port = 443; + static const sec_tag_t sec_tag_list[] = { + HTTP_SERVER_CERTIFICATE_TAG, + }; + + HTTPS_SERVICE_DEFINE(my_service, "0.0.0.0", &https_service_port, 1, 10, + NULL, sec_tag_list, sizeof(sec_tag_list)); + +.. note:: + + HTTPS services rely on TLS credentials being registered in the system. + See :ref:`sockets_tls_credentials_subsys` for information on how to + configure TLS credentials in the system. + +Once HTTP(s) service is defined, resources can be registered for it with +:c:macro:`HTTP_RESOURCE_DEFINE` macro. + +Static resources +================ + +Static resource content is defined build-time and is immutable. The following +example shows how gzip compressed webpage can be defined as a static resource +in the application: + +.. code-block:: c + + static const uint8_t index_html_gz[] = { + #include "index.html.gz.inc" + }; + + struct http_resource_detail_static index_html_gz_resource_detail = { + .common = { + .type = HTTP_RESOURCE_TYPE_STATIC, + .bitmask_of_supported_http_methods = BIT(HTTP_GET), + .content_encoding = "gzip", + }, + .static_data = index_html_gz, + .static_data_len = sizeof(index_html_gz), + }; + + HTTP_RESOURCE_DEFINE(index_html_gz_resource, my_service, "/", + &index_html_gz_resource_detail); + +The resource content and content encoding is application specific. For the above +example, a gzip compressed webpage can be generated during build, by adding the +following code to the application's ``CMakeLists.txt`` file: + +.. code-block:: cmake + :caption: ``CMakeLists.txt`` + + set(gen_dir ${ZEPHYR_BINARY_DIR}/include/generated/) + set(source_file_index src/index.html) + generate_inc_file_for_target(app ${source_file_index} ${gen_dir}/index.html.gz.inc --gzip) + +where ``src/index.html`` is the location of the webpage to be compressed. + +Dynamic resources +================= + +For dynamic resource, a resource callback is registered to exchange data between +the server and the application. The application defines a resource buffer used +to pass the request payload data from the server, and to provide response payload +to the server. The following example code shows how to register a dynamic resource +with a simple resource handler, which echoes received data back to the client: + +.. code-block:: c + + static uint8_t recv_buffer[1024]; + + static int dyn_handler(struct http_client_ctx *client, + enum http_data_status status, uint8_t *buffer, + size_t len, void *user_data) + { + #define MAX_TEMP_PRINT_LEN 32 + static char print_str[MAX_TEMP_PRINT_LEN]; + enum http_method method = client->method; + static size_t processed; + + __ASSERT_NO_MSG(buffer != NULL); + + if (status == HTTP_SERVER_DATA_ABORTED) { + LOG_DBG("Transaction aborted after %zd bytes.", processed); + processed = 0; + return 0; + } + + processed += len; + + snprintf(print_str, sizeof(print_str), "%s received (%zd bytes)", + http_method_str(method), len); + LOG_HEXDUMP_DBG(buffer, len, print_str); + + if (status == HTTP_SERVER_DATA_FINAL) { + LOG_DBG("All data received (%zd bytes).", processed); + processed = 0; + } + + /* This will echo data back to client as the buffer and recv_buffer + * point to same area. + */ + return len; + } + + struct http_resource_detail_dynamic dyn_resource_detail = { + .common = { + .type = HTTP_RESOURCE_TYPE_DYNAMIC, + .bitmask_of_supported_http_methods = + BIT(HTTP_GET) | BIT(HTTP_POST), + }, + .cb = dyn_handler, + .data_buffer = recv_buffer, + .data_buffer_len = sizeof(recv_buffer), + .user_data = NULL, + }; + + HTTP_RESOURCE_DEFINE(dyn_resource, my_service, "/dynamic", + &dyn_resource_detail); + + +The resource callback may be called multiple times for a single request, hence +the application should be able to keep track of the received data progress. + +The ``status`` field informs the application about the progress in passing +request payload from the server to the application. As long as the status +reports :c:enumerator:`HTTP_SERVER_DATA_MORE`, the application should expect +more data to be provided in a consecutive callback calls. +Once all request payload has been passed to the application, the server reports +:c:enumerator:`HTTP_SERVER_DATA_FINAL` status. In case of communication errors +during request processing (for example client closed the connection before +complete payload has been received), the server reports +:c:enumerator:`HTTP_SERVER_DATA_ABORTED`. Either of the two events indicate that +the application shall reset any progress recorded for the resource, and await +a new request to come. The server guarantees that the resource can only be +accessed by single client at a time. + +The resource callback returns the number of bytes to be replied in the response +payload to the server (provided in the resource data buffer). In case there is +no more data to be included in the response, the callback should return 0. + +The server will call the resource callback until it provided all request data +to the application, and the application reports there is no more data to include +in the reply. + +Websocket resources +=================== + +Websocket resources register an application callback, which is is called when a +Websocket connection upgrade takes place. The callback is provided with a socket +descriptor corresponding to the underlying TCP/TLS connection. Once called, +the application takes full control over the socket, i. e. is responsible to +release it when done. + +.. code-block:: c + + static int ws_socket; + static uint8_t ws_recv_buffer[1024]; + + int ws_setup(int sock, void *user_data) + { + ws_socket = sock; + return 0; + } + + struct http_resource_detail_websocket ws_resource_detail = { + .common = { + .type = HTTP_RESOURCE_TYPE_WEBSOCKET, + /* We need HTTP/1.1 Get method for upgrading */ + .bitmask_of_supported_http_methods = BIT(HTTP_GET), + }, + .cb = ws_setup, + .data_buffer = ws_recv_buffer, + .data_buffer_len = sizeof(ws_recv_buffer), + .user_data = NULL, /* Fill this for any user specific data */ + }; + + HTTP_RESOURCE_DEFINE(ws_resource, my_service, "/", &ws_resource_detail); + +The above minimalistic example shows how to register a Websocket resource with +a simple callback, used only to store the socket descriptor provided. Further +processing of the Websocket connection is application-specific, hence outside +of scope of this guide. See :zephyr:code-sample:`sockets-http-server` for an +example Websocket-based echo service implementation. + +API Reference +************* + +.. doxygengroup:: http_service +.. doxygengroup:: http_server diff --git a/doc/connectivity/networking/api/ieee802154.rst b/doc/connectivity/networking/api/ieee802154.rst index ba641b1e4e3..ab3adf53e71 100644 --- a/doc/connectivity/networking/api/ieee802154.rst +++ b/doc/connectivity/networking/api/ieee802154.rst @@ -34,8 +34,8 @@ specified. Zephyr supports both, native IEEE 802.15.4 and Thread, with 6LoWPAN. Zephyr's :ref:`thread_protocol_interface` implementation is based on `OpenThread -`_. The IPv6 header compression in 6LoWPAN is shared -among native IEEE 802.15.4 and the Bluetooth IPSP (IP support profile). +`_. The IPv6 header compression in 6LoWPAN is used for +native IEEE 802.15.4. API Reference ************* diff --git a/doc/connectivity/networking/api/net_config.rst b/doc/connectivity/networking/api/net_config.rst index 41dad04256c..85103ec11ae 100644 --- a/doc/connectivity/networking/api/net_config.rst +++ b/doc/connectivity/networking/api/net_config.rst @@ -50,9 +50,6 @@ setup the system: this option tells that the network application needs IPv6 router to exists before continuing. This means in practice that the application wants to wait until it receives IPv6 router advertisement message before continuing." - ":kconfig:option:`CONFIG_NET_CONFIG_BT_NODE`", "Enables application to operate in - Bluetooth node mode which requires GATT service to be registered and start - advertising as peripheral." Sample usage ************ diff --git a/doc/connectivity/networking/api/net_l2.rst b/doc/connectivity/networking/api/net_l2.rst index 1bf5249e5c2..da9c84e546d 100644 --- a/doc/connectivity/networking/api/net_l2.rst +++ b/doc/connectivity/networking/api/net_l2.rst @@ -24,10 +24,9 @@ object. The L2 layer dictates the API provided by the device driver, specific for that device, and optimized for working together. Currently, there are L2 layers for :ref:`Ethernet `, -:ref:`IEEE 802.15.4 Soft-MAC `, -:ref:`Bluetooth IPSP `, :ref:`CANBUS `, -:ref:`OpenThread `, Wi-Fi, and a dummy layer -example that can be used as a template for writing a new one. +:ref:`IEEE 802.15.4 Soft-MAC `, :ref:`CANBUS `, +:ref:`OpenThread `, Wi-Fi, and a dummy layer example +that can be used as a template for writing a new one. L2 layer API ************ diff --git a/doc/connectivity/networking/api/protocols.rst b/doc/connectivity/networking/api/protocols.rst index aea485b74aa..57aeaae8d02 100644 --- a/doc/connectivity/networking/api/protocols.rst +++ b/doc/connectivity/networking/api/protocols.rst @@ -10,7 +10,8 @@ Protocols coap coap_client coap_server - http + http_client + http_server lwm2m mqtt mqtt_sn diff --git a/doc/connectivity/networking/overview.rst b/doc/connectivity/networking/overview.rst index c1de9a1ab67..73876449c88 100644 --- a/doc/connectivity/networking/overview.rst +++ b/doc/connectivity/networking/overview.rst @@ -32,13 +32,12 @@ can be disabled if not needed. * Multicast Listener Discovery v2 support (`RFC 3810 `_) is enabled by default. * IPv6 header compression (6lo) is available for IPv6 connectivity for - Bluetooth IPSP (`RFC 7668 `_) and IEEE 802.15.4 networks (`RFC 4944 `_). -* **IPv4** The legacy IPv4 is supported by the networking stack. It cannot be - used by IEEE 802.15.4 or Bluetooth IPSP as those network technologies support - only IPv6. IPv4 can be used in Ethernet based networks. By default IPv4 - support is disabled. +* **IPv4** The legacy IPv4 is supported by the networking stack. It + cannot be used by IEEE 802.15.4 as this network technology supports + only IPv6. IPv4 can be used in Ethernet based networks. By default + IPv4 support is disabled. * DHCP (Dynamic Host Configuration Protocol) client is supported (`RFC 2131 `_). @@ -85,6 +84,13 @@ can be disabled if not needed. supported in similar manner when enabled with a Kconfig option. :zephyr:code-sample:`lwm2m-client` sample implements the library as an example. +* **HTTP** Hypertext Transfer Protocol client and server are supported. + :ref:`http_client_interface` library supports HTTP/1.1 (`RFC 2616`_). + :ref:`http_server_interface` library supports HTTP/1.1 (`RFC 2616`_) and + HTTP/2 (`RFC 9113`_). + :zephyr:code-sample:`sockets-http-client` and + :zephyr:code-sample:`sockets-http-server` samples are provided. + * **DNS** Domain Name Service (`RFC 1035 `_) client functionality is supported. @@ -154,7 +160,7 @@ The networking stack source code tree is organized as follows: ``subsys/net/l2/`` This is where the IP stack layer 2 code is located. This includes generic - support for Bluetooth IPSP adaptation, Ethernet, IEEE 802.15.4 and Wi-Fi. + support for Ethernet, IEEE 802.15.4 and Wi-Fi. ``subsys/net/lib/`` Application-level protocols (DNS, MQTT, etc.) and additional stack @@ -178,3 +184,9 @@ The networking stack source code tree is organized as follows: .. _LwM2M specification 1.1.1: http://openmobilealliance.org/release/LightweightM2M/V1_1_1-20190617-A/ + +.. _RFC 2616: + https://tools.ietf.org/html/rfc2616 + +.. _RFC 9113: + https://tools.ietf.org/html/rfc9113 diff --git a/doc/contribute/coding_guidelines/index.rst b/doc/contribute/coding_guidelines/index.rst index 9563cee8919..d502e389eb0 100644 --- a/doc/contribute/coding_guidelines/index.rst +++ b/doc/contribute/coding_guidelines/index.rst @@ -1212,8 +1212,8 @@ Related GitHub Issues and Pull Requests are tagged with the `Inclusive Language - * - eSPI - - * ``master / slave`` => TBD - - + - * ``master / slave`` => ``controller / target`` + - Refer to `eSPI Specification`_ for new terminology * - gPTP - * ``master / slave`` => TBD @@ -1254,6 +1254,7 @@ Related GitHub Issues and Pull Requests are tagged with the `Inclusive Language .. _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/ +.. _eSPI Specification: https://downloadmirror.intel.com/27055/327432%20espi_base_specification%20R1-5.pdf Rule A.3: Macro name collisions diff --git a/doc/develop/application/index.rst b/doc/develop/application/index.rst index 560ba951969..b8f432a4ea1 100644 --- a/doc/develop/application/index.rst +++ b/doc/develop/application/index.rst @@ -494,13 +494,11 @@ Make sure to follow these steps in order. as described in this step, this value will be used. #. If your application uses a configuration file or files other than - the usual :file:`prj.conf` (or :file:`prj_YOUR_BOARD.conf`, where - ``YOUR_BOARD`` is a board name), add lines setting the - :makevar:`CONF_FILE` variable to these files appropriately. - If multiple filenames are given, separate them by a single space or - semicolon. CMake lists can be used to build up configuration fragment - files in a modular way when you want to avoid setting :makevar:`CONF_FILE` - in a single place. For example: + the usual :file:`prj.conf`, add lines setting the :makevar:`CONF_FILE` + variable to these files appropriately. If multiple filenames are given, + separate them by a single space or semicolon. CMake lists can be used to + build up configuration fragment files in a modular way when you want to + avoid setting :makevar:`CONF_FILE` in a single place. For example: .. code-block:: cmake @@ -1143,7 +1141,7 @@ where the ``boards`` directory hosts the board you are building for: . ā”œā”€ā”€ boards - ā”‚ ā””ā”€ā”€ x86 + ā”‚ ā””ā”€ā”€ vendor ā”‚ ā””ā”€ā”€ my_custom_board ā”‚ ā”œā”€ā”€ doc ā”‚ ā”‚ ā””ā”€ā”€ img @@ -1156,9 +1154,9 @@ supported by a SOC that is available in the Zephyr tree. Boards ====== -Use the proper architecture folder name (e.g., ``x86``, ``arm``, etc.) -under ``boards`` for ``my_custom_board``. (See :ref:`boards` for a -list of board architectures.) +Use the vendor name as the folder name (which must match the vendor prefix in +:zephyr_file:`dts/bindings/vendor-prefixes.txt` if submitting upstream to Zephyr, or be +``others`` if it is not a vendor board) under ``boards`` for ``my_custom_board``. Documentation (under ``doc/``) and support files (under ``support/``) are optional, but will be needed when submitting to Zephyr. @@ -1173,9 +1171,8 @@ Zephyr board, and provide the following files:: board.h CMakeLists.txt doc/ - Kconfig.board + Kconfig.my_custom_board Kconfig.defconfig - pinmux.c support/ @@ -1214,11 +1211,10 @@ the Zephyr tree, for example: .. code-block:: none soc - ā””ā”€ā”€ arm - ā””ā”€ā”€ st_stm32 - ā”œā”€ā”€ common - ā””ā”€ā”€ stm32l0 - + ā””ā”€ā”€ st + ā””ā”€ā”€ stm32 + ā”œā”€ā”€ common + ā””ā”€ā”€ stm32l0x The file :zephyr_file:`soc/Kconfig` will create the top-level @@ -1234,8 +1230,9 @@ more SoCs into the menu. .. code-block:: none soc - ā””ā”€ā”€ arm - ā””ā”€ā”€ st_stm32 + ā””ā”€ā”€ st + ā””ā”€ā”€ stm32 + ā””ā”€ā”€ stm32l0x ā”œā”€ā”€ Kconfig ā”œā”€ā”€ Kconfig.soc ā””ā”€ā”€ Kconfig.defconfig @@ -1247,17 +1244,17 @@ An example of loading ``stm31l0`` specific Kconfig files in this structure: .. code-block:: none soc - ā””ā”€ā”€ arm - ā””ā”€ā”€ st_stm32 - ā”œā”€ā”€ Kconfig.soc - ā””ā”€ā”€ stm32l0 - ā””ā”€ā”€ Kconfig.series + ā””ā”€ā”€ st + ā””ā”€ā”€ stm32 + ā”œā”€ā”€ Kconfig.soc + ā””ā”€ā”€ stm32l0x + ā””ā”€ā”€ Kconfig.soc -can be done with the following content in ``st_stm32/Kconfig.soc``: +can be done with the following content in ``st/stm32/Kconfig.soc``: .. code-block:: none - rsource "*/Kconfig.series" + rsource "*/Kconfig.soc" Once the SOC structure is in place, you can build your application targeting this platform by specifying the location of your custom platform diff --git a/doc/develop/flash_debug/host-tools.rst b/doc/develop/flash_debug/host-tools.rst index 1fcf7fa1d8b..56dba160257 100644 --- a/doc/develop/flash_debug/host-tools.rst +++ b/doc/develop/flash_debug/host-tools.rst @@ -270,6 +270,10 @@ LinkServer west runner ``--probe`` option to pass the probe index. west flash --runner=linkserver --override /device/memory/5/flash-driver=MIMXRT500_SFDP_MXIC_OSPI_S.cfx +4. LinkServer does not install an implicit breakpoint at the reset handler. If + you would like to single step from the start of their application, you + will need to add a breakpoint at ``main`` or the reset handler manually. + .. _jlink-debug-host-tools: J-Link Debug Host Tools diff --git a/doc/develop/getting_started/index.rst b/doc/develop/getting_started/index.rst index 56fcb7e991f..e51365e34c7 100644 --- a/doc/develop/getting_started/index.rst +++ b/doc/develop/getting_started/index.rst @@ -61,7 +61,7 @@ The current minimum required version for the main dependencies are: - 3.20.5 * - `Python `_ - - 3.8 + - 3.10 * - `Devicetree compiler `_ - 1.4.6 diff --git a/doc/develop/optimizations/tools.rst b/doc/develop/optimizations/tools.rst index 79f8f986f8f..f8922092509 100644 --- a/doc/develop/optimizations/tools.rst +++ b/doc/develop/optimizations/tools.rst @@ -4,7 +4,7 @@ Optimization Tools ################## The available optimization tools let you analyse :ref:`footprint_tools` -and :ref:`data_structures` using different build system targets. +and :ref:`data_structure_tools` using different build system targets. .. _footprint_tools: @@ -195,7 +195,7 @@ To view worst-case stack usage analysis, build this with the :gen-args: -DCONFIG_STACK_USAGE=y -.. _data_structures: +.. _data_structure_tools: Data Structures **************** diff --git a/doc/develop/test/bsim.rst b/doc/develop/test/bsim.rst index d2f98295dc7..0bdc7d0fecc 100644 --- a/doc/develop/test/bsim.rst +++ b/doc/develop/test/bsim.rst @@ -21,7 +21,8 @@ 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` and :ref:`nrf5340bsim` boards documentation +In the :ref:`nrf52_bsim`, :ref:`nrf5340bsim`, +and :ref:`nrf54l15bsim` boards documentation you can find more information about how to build Zephyr targeting these particular boards, and a few examples. @@ -67,8 +68,9 @@ found in the :ref:`bsim boards tests section`. Test coverage and BabbleSim *************************** -As the :ref:`nrf52_bsim` and :ref:`nrf5340bsim` boards are based on the -POSIX architecture, you can easily collect test coverage information. +As the :ref:`nrf52_bsim` and :ref:`nrf5340bsim`, and +:ref:`nrf54l15bsim` boards are based on the POSIX architecture, you can easily collect +test coverage information. You can use the script :zephyr_file:`tests/bsim/generate_coverage_report.sh` to generate an html coverage report from tests. diff --git a/doc/develop/test/twister.rst b/doc/develop/test/twister.rst index 35f2c087eca..4f0169ecec6 100644 --- a/doc/develop/test/twister.rst +++ b/doc/develop/test/twister.rst @@ -499,9 +499,6 @@ harness_config: ordered: (default False) Check the regular expression strings in orderly or randomly fashion - repeat: - Number of times to validate the repeated regex expression - record: (optional) regex: (required) The regular expression with named subgroups to match data fields diff --git a/doc/develop/west/zephyr-cmds.rst b/doc/develop/west/zephyr-cmds.rst index 6037cb422b2..f10c4abe36b 100644 --- a/doc/develop/west/zephyr-cmds.rst +++ b/doc/develop/west/zephyr-cmds.rst @@ -74,7 +74,7 @@ See :zephyr_file:`share/zephyr-package/cmake` for details. Software bill of materials: ``west spdx`` ***************************************** -This command generates SPDX 2.2 tag-value documents, creating relationships +This command generates SPDX 2.3 tag-value documents, creating relationships from source files to the corresponding generated build files. ``SPDX-License-Identifier`` comments in source files are scanned and filled into the SPDX documents. diff --git a/doc/glossary.rst b/doc/glossary.rst index 240727d9e24..e9e892320c4 100644 --- a/doc/glossary.rst +++ b/doc/glossary.rst @@ -140,6 +140,10 @@ Glossary of Terms A number of different :term:`SoCs ` that share similar characteristics and features, and that the vendor typically names and markets together. + subsystem + A subsystem refers to a logically distinct part of the operating system + that handles specific functionality or provides certain services. + system power state System power states describe the power consumption of the system as a whole. System power states are represented by :c:enum:`pm_state`. diff --git a/doc/hardware/arch/index.rst b/doc/hardware/arch/index.rst index 85819453ba0..da33dff084b 100644 --- a/doc/hardware/arch/index.rst +++ b/doc/hardware/arch/index.rst @@ -11,3 +11,4 @@ Architecture-related Guides risc-v.rst semihost.rst x86.rst + xtensa.rst diff --git a/doc/hardware/arch/xtensa.rst b/doc/hardware/arch/xtensa.rst new file mode 100644 index 00000000000..1c0867950a4 --- /dev/null +++ b/doc/hardware/arch/xtensa.rst @@ -0,0 +1,73 @@ +.. _xtensa_developer_guide: + +Xtensa Developer Guide +###################### + +Overview +******** + +This page contains information on certain aspects when developing for +Xtensa-based platforms. + +HiFi Audio Engine DSP +********************* + +The kernel allows threads to use the HiFi Audio Engine DSP registers on boards +that support these registers. The kernel only supports the use of the HiFi +registers by threads and not ISRs. + +.. note:: + Presently, only the Intel ADSP ACE hardware platforms are configured for + HiFi support by default. + +Concepts +======== + +The kernel can be configured for an application to leverage the services +provided by the Xtensa HiFi Audio Engine DSP. Three modes of operation are +supported, which are described below. + +No HiFi registers mode +---------------------- + +This mode is used when the application has no threads that use the HiFi +registers. It is the kernel's default HiFi services mode. + +Unshared HiFi registers mode +---------------------------- + +This mode is used when the application has only a single thread that uses the +HiFi registers. The HiFi registers are left unchanged whenever a context +switch occurs. + +.. note:: + The behavior is undefined, if two or more threads attempt to use + the HiFi registers, as the kernel does not attempt to detect + (nor prevent) multiple threads from using these registers. + +Shared HiFi registers mode +-------------------------- + +This mode is used when the application has two or more threads that use HiFi +registers. When enabled, the kernel automatically allows all threads to use the +HiFi registers. During each thread context switch, the kernel saves the outgoing +thread's HiFi registers and loads the incoming thread's HiFi registers, +regardless of whether the thread utilizes them or not. + +Additional stack space may be required for each thread to account for the extra +registers that must be saved. + +Configuration Options +===================== + +The unshared HiFi registers mode is selected when configuration option +:kconfig:option:`CONFIG_XTENSA_HIFI_SHARING` is disabled but configuration +options :kconfig:option:`CONFIG_XTENSA_HIFI3` and/or +:kconfig:option:`CONFIG_XTENSA_HIFI4` are enabled. + +The shared HiFi registers mode is selected when the configuration option +:kconfig:option:`CONFIG_XTENSA_HIFI_SHARING` is enabled in addition to +configuration options :kconfig:option:`CONFIG_XTENSA_HIFI3` and/or +:kconfig:option:`CONFIG_XTENSA_HIFI4`. Threads must have sufficient +stack space for saving the HiFi register values during context switches +as described above. diff --git a/doc/hardware/peripherals/espi.rst b/doc/hardware/peripherals/espi.rst index 62d475da7b9..26436e4a2e6 100644 --- a/doc/hardware/peripherals/espi.rst +++ b/doc/hardware/peripherals/espi.rst @@ -8,7 +8,7 @@ Overview The eSPI (enhanced serial peripheral interface) is a serial bus that is based on SPI. It also features a four-wire interface (receive, transmit, clock -and slave select) and three configurations: single IO, dual IO and quad IO. +and target select) and three configurations: single IO, dual IO and quad IO. The technical advancements include lower voltage signal levels (1.8V vs. 3.3V), lower pin count, and the frequency is twice as fast (66MHz vs. 33MHz) @@ -24,4 +24,4 @@ API Reference .. doxygengroup:: espi_interface .. _eSPI interface specification: - https://www.intel.com/content/dam/support/us/en/documents/software/chipset-software/327432-004_espi_base_specification_rev1.0_cb.pdf + https://downloadmirror.intel.com/27055/327432%20espi_base_specification%20R1-5.pdf diff --git a/doc/hardware/peripherals/mipi_dbi.rst b/doc/hardware/peripherals/mipi_dbi.rst index 640030c3f0b..672eb59f8f1 100644 --- a/doc/hardware/peripherals/mipi_dbi.rst +++ b/doc/hardware/peripherals/mipi_dbi.rst @@ -7,6 +7,7 @@ The MIPI DBI driver class implements support for MIPI DBI compliant display controllers. MIPI DBI defines 3 interface types: + * Type A: Motorola 6800 parallel bus * Type B: Intel 8080 parallel bus diff --git a/doc/hardware/porting/board/board-terminology.svg b/doc/hardware/porting/board/board-terminology.svg index 60c3d8a8ebe..40eb91ab727 100644 --- a/doc/hardware/porting/board/board-terminology.svg +++ b/doc/hardware/porting/board/board-terminology.svg @@ -1,3 +1,3 @@ -
bl5340_dvk@1.2.0/nrf5340/cpuapp/ns
bl5340_dvk@1.2.0/nrf5340/cpuapp/ns
Board name
Board name
Board qualifiers
Board qualifiers
Board target
Board target
Board revision
Board revision
SoC
SoC
CPU cluster
CPU cluster
Variant
Variant
\ No newline at end of file +
bl5340_dvk@1.2.0/nrf5340/cpuapp/ns
Board name
Board qualifiers
Board target
Board revision
SoC
CPU cluster
Variant
diff --git a/doc/hardware/porting/board_porting.rst b/doc/hardware/porting/board_porting.rst index d7ff4569524..a2b7796ebfa 100644 --- a/doc/hardware/porting/board_porting.rst +++ b/doc/hardware/porting/board_porting.rst @@ -106,6 +106,8 @@ the :term:`SoC series` and :term:`SoC family` levels are not always used. | :ref:`mimx8mp_evk ` | mimx8ml8/a53 | i.MX8M Plus | i.MX8M | NXP i.MX | Arm Cortex-A53 | ARMv8-A | | +--------------------------+-------------+--------------------+--------------------+----------------+----------------------+ | | mimx8ml8/m7 | i.MX8M Plus | i.MX8M | NXP i.MX | Arm Cortex-M7 | ARMv7-M | + | +--------------------------+-------------+--------------------+--------------------+----------------+----------------------+ + | | mimx8ml8/adsp | i.MX8M Plus | i.MX8M | NXP i.MX | Cadence HIFI4 | Xtensa LX6 | +--------------------------------------------+--------------------------+-------------+--------------------+--------------------+----------------+----------------------+ Additional details about terminology can be found in the next section. @@ -486,7 +488,6 @@ controller and sets the bus speed: &can0 { status = "okay"; - bus-speed = <125000>; }; The ``&can0 { ... };`` syntax adds/overrides properties on the node with label diff --git a/doc/hardware/porting/index.rst b/doc/hardware/porting/index.rst index e6453a5ba48..91dc8b6ef38 100644 --- a/doc/hardware/porting/index.rst +++ b/doc/hardware/porting/index.rst @@ -9,5 +9,6 @@ These pages document how to port Zephyr to new hardware. :maxdepth: 1 arch.rst + soc_porting.rst board_porting.rst shields.rst diff --git a/doc/hardware/porting/soc_porting.rst b/doc/hardware/porting/soc_porting.rst new file mode 100644 index 00000000000..5f97065734b --- /dev/null +++ b/doc/hardware/porting/soc_porting.rst @@ -0,0 +1,304 @@ +.. _soc_porting_guide: + +SoC Porting Guide +################### + +To add Zephyr support for a new :term:`SoC`, you need a *SoC directory* with +various files in it, and a SoC :file:`.dtsi` in +:zephyr_file:`dts//` is required. + +SoC Definitions +*************** + +It is expected that you are familiar with the board concept in Zephyr. +A high level overview of the hardware support hierarchy and terms used in the +Zephyr documentation can be seen in :ref:`hw_support_hierarchy`. + +For SoC porting, the most important terms are: + +- SoC: the exact system on a chip the board's CPU is part of. +- SoC series: a group of tightly related SoCs. +- SoC family: a wider group of SoCs with similar characteristics. +- CPU Cluster: a cluster of one or more CPU cores. +- CPU core: a particular CPU instance of a given architecture. +- Architecture: an instruction set architecture. + +Architecture +============ + +See :ref:`architecture_porting_guide`. + + +Create your SoC directory +************************* + +Each SoC must have a unique name. Use the official name given by the SoC vendor +and check that it's not already in use. In some cases someone else may have +contributed a SoC with identical name. If the SoC name is already in use, then +you should probably improve the existing SoC instead of creating a new one. +The script ``list_hardware`` can be used to retrieve a list of all SoCs known +in Zephyr, for example ``./scripts/list_hardware.py --soc-root=. --socs`` from +the Zephyr base directory for a list of names that are already in use. + +Start by creating the directory ``zephyr/soc//soc1``, where +```` is your vendor subdirectory. + +.. note:: + A ```` subdirectory is mandatory if contributing your SoC + to Zephyr, but if your SoC is placed in a local repo, then any folder + structure under ``/soc`` is permitted. + The ```` subdirectory must match a vendor defined in the list in + :zephyr_file:`dts/bindings/vendor-prefixes.txt`. If the SoC vendor does not + have a prefix in that list, then one must be created. + +.. note:: + + The SoC directory name does not need to match the name of the SoC. + Multiple SoCs can even be defined in one directory. In Zephyr, SoCs are often + organized in sub-folders in a common SoC Family or SoC Series tree. + +Your SoC directory should look like this: + +.. code-block:: none + + soc// + ā”œā”€ā”€ soc.yml + ā”œā”€ā”€ soc.h + ā”œā”€ā”€ CMakeLists.txt + ā”œā”€ā”€ Kconfig + ā”œā”€ā”€ Kconfig.soc + ā””ā”€ā”€ Kconfig.defconfig + +Replace ```` with your SoC's name. + + +The mandatory files are: + +#. :file:`soc.yml`: a YAML file describing the high-level meta data of the + SoC such as: + - SoC name: the name of the SoC + - CPU clusters: CPU clusters if the SoC contains one or more clusters + - SoC series: the SoC series to which the SoC belong + - SoC family: the SoC family to which the series belong + +#. :file:`soc.h`: a header file which can be used to describe or provide + configuration macros for the SoC. The :file:`soc.h` will often be included in + drivers, sub-systems, boards, and other source code found in Zephyr. + +#. :file:`Kconfig.soc`: the base SoC configuration which defines a Kconfig SoC + symbol in the form of ``config SOC_`` and provides the SoC name to + the Kconfig ``SOC`` setting. + If the ``soc.yml`` describes a SoC family and series, then those must also + be defined in this file. Kconfig settings outside of the SoC tree must not be + selected. To select general Zephyr Kconfig settings the :file:`Kconfig` file + must be used. + +#. :file:`CMakeLists.txt`: CMake file loaded by the Zephyr build system. This + CMake file can define additional include paths and/or source files to be used + when a build targets the SoC. Also the base line linker script to use must be + defined. + +The optional files are: + +- :file:`Kconfig`, :file:`Kconfig.defconfig` software configuration in + :ref:`kconfig` format. These select the architecture and peripherals + available. + +Write your SoC YAML +********************* + +The SoC YAML file describes the SoC family, SoC series, and SoC at a high level. + +Detailed configurations, such as hardware description and configuration are done +in devicetree and Kconfig. + +The skeleton of a simple SoC YAML file containing just one SoC is: + +.. code-block:: yaml + + socs: + - name: + +It is possible to have multiple SoC located in the SoC folder. +For example if they belong to a common family or series it is recommended to +locate such SoC in a common tree. +Multiple SoCs and SoC series in a common folder can be described in the +:file:`soc.yml` file as: + +.. code-block:: yaml + + family: + name: + series: + - name: + socs: + - name: + cpucluster: + - name: + - name: + ... + - name: + - name: + ... + + +Write your SoC devicetree +************************* + +SoC devicetree include files are located in the :file:`/dts` folder +under a corresponding :file:`/`. + +The SoC :file:`dts///.dtsi` describes your SoC hardware in +the Devicetree Source (DTS) format and must be included by any boards which use +the SoC. + +If a highlevel :file:`.dtsi` file exists, then a good starting point is to +include this file in your :file:`.dtsi`. + +In general, :file:`.dtsi` should look like this: + +.. code-block:: devicetree + + #include /.dtsi + + / { + chosen { + /* common chosen settings for your SoC */ + }; + + cpus { + #address-cells = ; + #size-cells = ; + + cpu@0 { + device_type = "cpu"; + compatible = ""; + /* ... your CPU definitions ... */ + }; + + soc { + /* Your SoC definitions and peripherals */ + /* such as ram, clock, buses, peripherals. */ + }; + }; + +.. hint:: + It is possible to structure multiple :file:`/.dtsi` files in + sub-directories for a cleaner file system structure. For example organized + pre SoC series, like this: :file:`//.dtsi`. + + +Multiple CPU clusters +===================== + +Devicetree reflects the hardware. The memory space and peripherals available to +one CPU cluster can be very different from another CPU cluster, therefore each +CPU cluster will often have its own :file:`.dtsi` file. + +CPU cluster :file:`.dtsi` files should follow the naming scheme +:file:`_.dtsi`. A :file:`_.dtsi` file will look +similar to a SoC :file:`.dtsi` without CPU clusters. + +Write Kconfig files +******************* + +Zephyr uses the Kconfig language to configure software features. Your SoC +needs to provide some Kconfig settings before you can compile a Zephyr +application for it. + +Setting Kconfig configuration values is documented in detail in +:ref:`setting_configuration_values`. + +There is one mandatory Kconfig file in the SoC directory, and two optional +files for a SoC: + +.. code-block:: none + + soc// + ā”œā”€ā”€ Kconfig.soc + ā”œā”€ā”€ Kconfig + ā””ā”€ā”€ Kconfig.defconfig + +:file:`Kconfig.soc` + A shared Kconfig file which can be sourced both in Zephyr Kconfig and sysbuild + Kconfig trees. + + This file selects the SoC family and series in the Kconfig tree and potential + other SoC related Kconfig settings. In some cases a SOC_PART_NUMBER. + This file must not select anything outside the re-usable Kconfig SoC tree. + + A :file:`Kconfig.soc` may look like this: + + .. code-block:: kconfig + + config SOC_ + bool + + config SOC_ + bool + select SOC_SERIES_ + + config SOC + default "SoC name" if SOC_ + + Notice that ``SOC_NAME`` is a pure upper case version of the SoC name. + + The Kconfig ``SOC`` setting is globally defined as a string and therefore the + :file:`Kconfig.soc` file shall only define the default string value and not + the type. Notice that the string value must match the SoC name used in the + :file:`soc.yml` file. + +:file:`Kconfig` + Included by :zephyr_file:`soc/Kconfig`. + + This file can add Kconfig settings which are specific to the current SoC. + + The :file:`Kconfig` will often indicate given hardware support using a setting + of the form ``HAS_``. + + .. code-block:: kconfig + + config SOC_ + select ARM + select CPU_HAS_FPU + + If the setting name is identical to an existing Kconfig setting in Zephyr and + only modifies the default value of said setting, then + :file:`Kconfig.defconfig` should be used instead. + +:file:`Kconfig.defconfig` + SoC specific default values for Kconfig options. + + Not all SoCs have a :file:`Kconfig.defconfig` file. + + The entire file should be inside a pair of ``if SOC_`` / ``endif`` + or ``if SOC_SERIES_`` / ``endif``, like this: + + .. code-block:: kconfig + + if SOC_ + + config NUM_IRQS + default 32 + + endif # SOC_ + +Multiple CPU clusters +===================== + +CPU clusters must provide additional Kconfig settings in the :file:`Kconfig.soc` +file. This will usually be in the form of ``SOC__`` so for +a given ``soc1`` with two clusters ``clusterA`` and ``clusterB``, then this +will look like: + +SoC's When a SoC defines CPU cluster + + .. code-block:: kconfig + + config SOC_SOC1_CLUSTERA + bool + select SOC_SOC1 + + config SOC_SOC1_CLUSTERB + bool + select SOC_SOC1 diff --git a/doc/introduction/index.rst b/doc/introduction/index.rst index f8b841ae300..af67331aa29 100644 --- a/doc/introduction/index.rst +++ b/doc/introduction/index.rst @@ -23,6 +23,14 @@ The Zephyr kernel supports multiple architectures, including: The full list of supported boards based on these architectures can be found :ref:`here `. +In the context of the Zephyr OS, a :term:`subsystem` refers to a logically distinct +part of the operating system that handles specific functionality or provides +certain services. Subsystems can include components such as networking, +file systems, device driver classes, power management, and communication protocols, +among others. Each subsystem is designed to be modular and can be configured, +customized, and extended to meet the requirements of different embedded +applications. + Licensing ********* diff --git a/doc/kernel/code-relocation.rst b/doc/kernel/code-relocation.rst index 599cdedccbd..73633c2f40e 100644 --- a/doc/kernel/code-relocation.rst +++ b/doc/kernel/code-relocation.rst @@ -135,13 +135,21 @@ Relocating libraries Libraries can be relocated using the LIBRARY argument to ``zephyr_code_relocation()`` with the library name. For example, the following -snippet will relocate kernel code to ITCM and serial drivers to SRAM2: +snippet will relocate serial drivers to SRAM2: .. code-block:: none - zephyr_code_relocate(LIBRARY kernel LOCATION ITCM_TEXT) zephyr_code_relocate(LIBRARY drivers__serial LOCATION SRAM2) +Tips +==== + +Take care if relocating kernel/arch files, some contain early initialization +code that executes before code relocation takes place. + +Additional MPU/MMU configuration may be required to ensure that the +destination memory region is configured to allow code execution. + Samples/ Tests ============== diff --git a/doc/kernel/drivers/index.rst b/doc/kernel/drivers/index.rst index 51b31de006f..fcc2e667650 100644 --- a/doc/kernel/drivers/index.rst +++ b/doc/kernel/drivers/index.rst @@ -373,6 +373,24 @@ Drivers and other system utilities can determine whether startup is still in pre-kernel states by using the :c:func:`k_is_pre_kernel` function. +Deferred initialization +*********************** + +Initialization of devices can also be deferred to a later time. In this case, +the device is not automatically initialized by Zephyr at boot time. Instead, +the device is initialized when the application calls :c:func:`device_init`. +To defer a device driver initialization, add the property ``zephyr,deferred-init`` +to the associated device node in the DTS file. For example: + +.. code-block:: devicetree + + / { + a-driver@40000000 { + reg = <0x40000000 0x1000>; + zephyr,deferred-init; + }; + }; + System Drivers ************** diff --git a/doc/kernel/memory_management/demand_paging.rst b/doc/kernel/memory_management/demand_paging.rst index 13a04cd2833..e870c8740e2 100644 --- a/doc/kernel/memory_management/demand_paging.rst +++ b/doc/kernel/memory_management/demand_paging.rst @@ -53,6 +53,10 @@ Page Frame addresses. For every page frame, a ``struct z_page_frame`` is instantiated to store metadata. Flags for each page frame: + * ``Z_PAGE_FRAME_FREE`` indicates a page frame is unused and on the list of + free page frames. When this flag is set, none of the other flags are + meaningful and they must not be modified. + * ``Z_PAGE_FRAME_PINNED`` indicates a page frame is pinned in memory and should never be paged out. diff --git a/doc/kernel/services/polling.rst b/doc/kernel/services/polling.rst index 71937648a93..46e586badb6 100644 --- a/doc/kernel/services/polling.rst +++ b/doc/kernel/services/polling.rst @@ -156,7 +156,7 @@ In case of success, :c:func:`k_poll` returns 0. If it times out, it returns void do_stuff(void) { - rc = k_poll(events, 2, 1000); + rc = k_poll(events, ARRAY_SIZE(events), K_MSEC(1000)); if (rc == 0) { if (events[0].state == K_POLL_STATE_SEM_AVAILABLE) { k_sem_take(events[0].sem, 0); @@ -183,7 +183,7 @@ to :c:macro:`K_POLL_STATE_NOT_READY` by the user. void do_stuff(void) { for(;;) { - rc = k_poll(events, 2, K_FOREVER); + rc = k_poll(events, ARRAY_SIZE(events), K_FOREVER); if (events[0].state == K_POLL_STATE_SEM_AVAILABLE) { k_sem_take(events[0].sem, 0); } else if (events[1].state == K_POLL_STATE_FIFO_DATA_AVAILABLE) { @@ -243,7 +243,11 @@ pass extra information to the thread waiting on the event. k_poll(events, 1, K_FOREVER); - if (events.signal->result == 0x1337) { + int signaled, result; + + k_poll_signal_check(&signal, &signaled, &result); + + if (signaled && (result == 0x1337)) { // A-OK! } else { // weird error @@ -256,8 +260,10 @@ pass extra information to the thread waiting on the event. k_poll_signal_raise(&signal, 0x1337); } -If the signal is to be polled in a loop, *both* its event state and its -**signaled** field *must* be reset on each iteration if it has been signaled. +If the signal is to be polled in a loop, *both* its event state must be +reset to :c:macro:`K_POLL_STATE_NOT_READY` *and* its ``result`` must be +reset using :c:func:`k_poll_signal_reset()` on each iteration if it has +been signaled. .. code-block:: c @@ -275,13 +281,17 @@ If the signal is to be polled in a loop, *both* its event state and its for (;;) { k_poll(events, 1, K_FOREVER); - if (events[0].signal->result == 0x1337) { + int signaled, result; + + k_poll_signal_check(&signal, &signaled, &result); + + if (signaled && (result == 0x1337)) { // A-OK! } else { // weird error } - events[0].signal->signaled = 0; + k_poll_signal_reset(signal); events[0].state = K_POLL_STATE_NOT_READY; } } diff --git a/doc/kernel/usermode/memory_domain.rst b/doc/kernel/usermode/memory_domain.rst index a1ddcd395e9..f830cc981b9 100644 --- a/doc/kernel/usermode/memory_domain.rst +++ b/doc/kernel/usermode/memory_domain.rst @@ -74,10 +74,24 @@ Thread Stack ************ Any thread running in user mode will need access to its own stack buffer. -On context switch into a user mode thread, a dedicated MPU region will be -programmed with the bounds of the stack buffer. A thread exceeding its stack -buffer will start pushing data onto memory it doesn't have access to and a -memory access violation exception will be generated. +On context switch into a user mode thread, a dedicated MPU region or MMU +page table entries will be programmed with the bounds of the stack buffer. +A thread exceeding its stack buffer will start pushing data onto memory +it doesn't have access to and a memory access violation exception will be +generated. + +Note that user threads have access to the stacks of other user threads in +the same memory domain. This is the minimum required for architectures to +support memory domains. Architecture can further restrict access to stacks +so each user thread only has access to its own stack if such architecture +advertises this capability via +:kconfig:option:`CONFIG_ARCH_MEM_DOMAIN_SUPPORTS_ISOLATED_STACKS`. +This behavior is enabled by default if supported and can be selectively +disabled via :kconfig:option:`CONFIG_MEM_DOMAIN_ISOLATED_STACKS` if +architecture supports both operating modes. However, some architectures +may decide to enable this all the time, and thus this option cannot be +disabled. Regardless of these kconfigs, user threads cannot access +the stacks of other user threads outside of their memory domains. Thread Resource Pools ********************* diff --git a/doc/releases/index.rst b/doc/releases/index.rst index 544f721994b..4310b11d5d8 100644 --- a/doc/releases/index.rst +++ b/doc/releases/index.rst @@ -103,6 +103,10 @@ in the migration guide. This includes: - Anything else that can affect the compilation or runtime behavior of an existing application +Each entry in the migration guide must include a brief explanation of the change +as well as refer to the Pull Request that introduced it, in order for the user +to be able to understand the context of the change. + .. toctree:: :maxdepth: 1 :glob: diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index ffe93262cff..d230eb6b508 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -476,6 +476,9 @@ Bluetooth * `BT_ISO_TIMESTAMP_NONE` has been removed and the `ts` parameter of :c:func:`bt_iso_chan_send` has as well. :c:func:`bt_iso_chan_send` now always sends without timestamp. To send with a timestamp, :c:func:`bt_iso_chan_send_ts` can be used. +* The ``CONFIG_BT_HCI_RESERVE`` and ``CONFIG_BT_HCI_RAW_RESERVE`` Kconfig options were removed. All + buffers get by default one byte of headroom now, which HCI transport implementations can rely on + (whether they need it or not). Bluetooth Mesh ============== diff --git a/doc/releases/migration-guide-3.7.rst b/doc/releases/migration-guide-3.7.rst index 0a45c6337cb..cc9a8b1bce7 100644 --- a/doc/releases/migration-guide-3.7.rst +++ b/doc/releases/migration-guide-3.7.rst @@ -20,7 +20,7 @@ Build System * Completely overhauled the way SoCs and boards are defined. This requires all out-of-tree SoCs and boards to be ported to the new model. See the - :ref:`hw_model_v2` for more detailed information. + :ref:`hw_model_v2` for more detailed information. (:github:`69607`) Kernel ****** @@ -29,11 +29,22 @@ Boards ****** * Reordered D1 and D0 in the `pro_micro` connector gpio-map for SparkFun Pro Micro RP2040 to match - original Pro Micro definition. Out-of-tree shields must be updated to reflect this change. + original Pro Micro definition. Out-of-tree shields must be updated to reflect this change. (:github:`69994`) +* ITE: Rename all SoC variant Kconfig options, e.g., ``CONFIG_SOC_IT82202_AX`` is renamed to + ``CONFIG_SOC_IT82202AX``. + All symbols are renamed as follows: ``SOC_IT81202BX``, ``SOC_IT81202CX``, ``SOC_IT81302BX``, + ``SOC_IT81302CX``, ``SOC_IT82002AW``, ``SOC_IT82202AX``, ``SOC_IT82302AX``. + And, rename the ``SOC_SERIES_ITE_IT8XXX2`` to ``SOC_SERIES_IT8XXX2``. (:github:`71680`) Modules ******* +MbedTLS +======= + +* The hash algorithms SHA-384, SHA-512, MD5 and SHA-1 are not enabled by default anymore. + Their respective Kconfig options now need to be explicitly enabled to be able to use them. + MCUboot ======= @@ -49,7 +60,7 @@ Device Drivers and Devicetree compatible :dtcompatible:`nxp,pit-channel` and configure as below. The :kconfig:option:`CONFIG_COUNTER_MCUX_PIT` has also been renamed to :kconfig:option:`CONFIG_COUNTER_NXP_PIT` with regards to the renaming - of the binding for the pit. + of the binding for the pit. (:github:`66336`) example: .. code-block:: devicetree @@ -70,6 +81,74 @@ Device Drivers and Devicetree }; }; +* The :dtcompatible:`nxp,kinetis-ethernet` has been deprecated in favor of + :dtcompatible:`nxp,enet`. All in tree SOCs were converted to use this new schema. + Thus, all boards using NXP's ENET peripheral will need to align to this binding + in DT, which also comes with a different version driver. Alternatively, + the Ethernet node can be deleted and redefined as the old binding to use + the deprecated legacy driver. The primary advantage of the new binding + is to be able to abstract an arbitrary phy through the mdio API. (:github:`70400`) + Example of a basic board level ENET DT definition: + + .. code-block:: devicetree + + &enet_mac { + status = "okay"; + pinctrl-0 = <&pinmux_enet>; + pinctrl-names = "default"; + phy-handle = <&phy>; + zephyr,random-mac-address; + phy-connection-type = "rmii"; + }; + + &enet_mdio { + status = "okay"; + pinctrl-0 = <&pinmux_enet_mdio>; + pinctrl-names = "default"; + phy: phy@3 { + compatible = "ethernet-phy"; + reg = <3>; + status = "okay"; + }; + }; + +* Some of the driver API structs have been rename to have the required ``_driver_api`` suffix. (:github:`72182`) + The following types have been renamed: + + * ``emul_sensor_backend_api`` to :c:struct:`emul_sensor_driver_api` + * ``emul_bbram_backend_api`` to :c:struct:`emul_bbram_driver_api` + * ``usbc_ppc_drv`` to :c:struct:`usbc_ppc_driver_api` + +* The driver for :dtcompatible:`maxim,max31790` got split up into a MFD and an + actual PWM driver. (:github:`68433`) + Previously, an instance of this device could have been defined like this: + + .. code-block:: devicetree + + max31790_max31790: max31790@20 { + compatible = "maxim,max31790"; + status = "okay"; + reg = <0x20>; + pwm-controller; + #pwm-cells = <2>; + }; + + This can be converted to: + + .. code-block:: devicetree + + max31790_max31790: max31790@20 { + compatible = "maxim,max31790"; + status = "okay"; + reg = <0x20>; + + max31790_max31790_pwm: max31790_max31790_pwm { + compatible = "maxim,max31790-pwm"; + status = "okay"; + pwm-controller; + #pwm-cells = <2>; + }; + }; Analog-to-Digital Converter (ADC) ================================= @@ -77,14 +156,23 @@ Analog-to-Digital Converter (ADC) Bluetooth HCI ============= + * The ``BT_HCI_VS_EXT`` Kconfig option was deleted and the feature is now included in the + :kconfig:option:`BT_HCI_VS` Kconfig option. + * The ``BT_HCI_VS_EVT`` Kconfig option was removed, since vendor event support is implicit if + the :kconfig:option:`BT_HCI_VS` option is enabled. + * The bt_read_static_addr() API was removed. This wasn't really a completely public API, but + since it was exposed by the public hci_driver.h header file the removal is mentioned here. + Enable the :kconfig:option:`BT_HCI_VS` Kconfig option instead, and use vendor specific HCI + commands API to get the Controller's Bluetooth static address when available. + Charger ======= * Dropped ``constant-charge-current-max-microamp`` property in ``charger_max20335`` driver because - it did not reflect real chip functionality. + it did not reflect real chip functionality. (:github:`69910`) * Added enum key to ``constant-charge-voltage-max-microvolt`` property in ``maxim,max20335-charger`` - binding to indicate invalid devicetree values at build time. + binding to indicate invalid devicetree values at build time. (:github:`69910`) Controller Area Network (CAN) ============================= @@ -102,7 +190,9 @@ Controller Area Network (CAN) * ``phase-seg1-data`` * ``phase-seg1-data`` -* Support for manual bus-off recovery was reworked: + (:github:`68714`) + +* Support for manual bus-off recovery was reworked (:github:`69460`): * Automatic bus recovery will always be enabled upon driver initialization regardless of Kconfig options. Since CAN controllers are initialized in "stopped" state, no unwanted bus-off recovery @@ -123,12 +213,75 @@ Controller Area Network (CAN) Display ======= +* ST7735R based displays now use the MIPI DBI driver class. These displays + must now be declared within a MIPI DBI driver wrapper device, which will + manage interfacing with the display. Note that the `cmd-data-gpios` pin has + changed polarity with this update, to align better with the new + `dc-gpios` name. For an example, see below: + + .. code-block:: devicetree + + /* Legacy ST7735R display definition */ + &spi0 { + st7735r: st7735r@0 { + compatible = "sitronix,st7735r"; + reg = <0>; + spi-max-frequency = <32000000>; + reset-gpios = <&gpio0 6 GPIO_ACTIVE_LOW>; + cmd-data-gpios = <&gpio0 12 GPIO_ACTIVE_LOW>; + ... + }; + }; + + /* New display definition with MIPI DBI device */ + + #include + + ... + + mipi_dbi { + compatible = "zephyr,mipi-dbi-spi"; + reset-gpios = <&gpio0 6 GPIO_ACTIVE_LOW>; + dc-gpios = <&gpio0 12 GPIO_ACTIVE_HIGH>; + spi-dev = <&spi0>; + #address-cells = <1>; + #size-cells = <0>; + + st7735r: st7735r@0 { + compatible = "sitronix,st7735r"; + reg = <0>; + mipi-max-frequency = <32000000>; + mipi-mode = ; + ... + }; + }; + +Enhanced Serial Peripheral Interface (eSPI) +=========================================== + +* The macros ``ESPI_SLAVE_TO_MASTER`` and ``ESPI_MASTER_TO_SLAVE`` were renamed to + ``ESPI_TARGET_TO_CONTROLLER`` and ``ESPI_CONTROLLER_TO_TARGET`` respectively to reflect + the new terminology in eSPI 1.5 specification. + The enum values ``ESPI_VWIRE_SIGNAL_SLV_BOOT_STS``, ``ESPI_VWIRE_SIGNAL_SLV_BOOT_DONE`` and + all ``ESPI_VWIRE_SIGNAL_SLV_GPIO_`` signals were renamed to + ``ESPI_VWIRE_SIGNAL_TARGET_BOOT_STS``, ``ESPI_VWIRE_SIGNAL_TARGET_BOOT_DONE`` and + ``ESPI_VWIRE_SIGNAL_TARGET_GPIO_`` respectively to reflect the new terminology + in eSPI 1.5 specification. (:github:`68492`) + Flash ===== General Purpose I/O (GPIO) ========================== +GNSS +==== + +* Basic power management support has been added to the ``gnss-nmea-generic`` driver. + If ``CONFIG_PM_DEVICE=y`` the driver is now initialized in suspended mode and the + application needs to call :c:func:`pm_device_action_run` with :c:macro:`PM_DEVICE_ACTION_RESUME` + to start up the driver. (:github:`71774`) + Input ===== @@ -136,7 +289,11 @@ Input relative to the raw ADC values, similarly to min and max. The data structures and properties have been renamed to reflect that (from ``out-deadzone`` to ``in-deadzone``) and when migrating to the new definition the value should be - scaled accordingly. + scaled accordingly. (:github:`70377`) + +* The ``holtek,ht16k33-keyscan`` driver has been converted to use the + :ref:`input` subsystem, callbacks have to be migrated to use the input APIs, + :dtcompatible:`zephyr,kscan-input` can be used for backward compatibility. (:github:`69875`) Interrupt Controller ==================== @@ -145,7 +302,15 @@ LED Strip ========= * The property ``in-gpios`` defined in :dtcompatible:`worldsemi,ws2812-gpio` has been - renamed to ``gpios``. + renamed to ``gpios``. (:github:`68514`) + +* The ``chain-length`` and ``color-mapping`` properties have been added to all LED strip bindings + and are now mandatory. + +* Added a new mandatory ``length`` function which returns the length (number of pixels) of an LED + strip device. + +* Made ``update_channels`` function optional and removed unimplemented functions. Sensors ======= @@ -156,6 +321,24 @@ Serial Timer ===== +regulator +========= + +* The :dtcompatible:`nxp,vref` driver no longer supports the ground selection function, + as this setting should not be modified by the user. The DT property ``nxp,ground-select`` + has been removed, users should remove this property from their devicetree if it is present. + (:github:`70642`) + +Watchdog +======== + +* The ``nuvoton,npcx-watchdog`` driver has been changed to extend the max timeout period. + The time of one watchdog count varies with the different pre-scalar settings. + Removed :kconfig:option:`CONFIG_WDT_NPCX_DELAY_CYCLES` because it is no longer suitable to + set the leading warning time. + Instead, added the :kconfig:option:`CONFIG_WDT_NPCX_WARNING_LEADING_TIME_MS` to set + the leading warning time in milliseconds. + Bluetooth ********* @@ -167,9 +350,27 @@ Bluetooth Mesh got ``const`` qualifier too. The model's metadata structure and metadata raw value can be declared as permanent constants in the non-volatile memory. (:github:`69679`) +* The model metadata pointer declaration of :c:struct:`bt_mesh_model` has been changed + to a single ``const *`` and redundant metadata pointer from :c:struct:`bt_mesh_health_srv` + is removed. Consequently, :code:`BT_MESH_MODEL_HEALTH_SRV` definition is changed + to use variable argument notation. Now, when your implementation + supports :kconfig:option:`CONFIG_BT_MESH_LARGE_COMP_DATA_SRV` and when you need to + specify metadata for Health Server model, simply pass metadata as the last argument + to the :code:`BT_MESH_MODEL_HEALTH_SRV` macro, otherwise omit the last argument. (:github:`71281`) + Bluetooth Audio =============== +* :kconfig:option:`CONFIG_BT_ASCS`, :kconfig:option:`CONFIG_BT_PERIPHERAL` and + :kconfig:option:`CONFIG_BT_ISO_PERIPHERAL` are not longer `select`ed automatically when + enabling :kconfig:option:`CONFIG_BT_BAP_UNICAST_SERVER`, and these must now be set explicitly + in the project configuration file. (:github:`71993`) +* The discover callback functions :code:`bt_cap_initiator_cb.unicast_discovery_complete`` and + :code:`bt_cap_commander_cb.discovery_complete`` for CAP now contain an additional parameter for + the set member. + This needs to be added to all instances of CAP discovery callback functions defined. + (:github:`72797`) + Bluetooth Classic ================= @@ -178,6 +379,24 @@ Bluetooth Classic Removed the :kconfig:option:`CONFIG_BT_BREDR`. It is replaced by new option :kconfig:option:`CONFIG_BT_CLASSIC`. (:github:`69651`) +Bluetooth Host +============== + +* The advertiser options :code:`BT_LE_ADV_OPT_USE_NAME` and :code:`BT_LE_ADV_OPT_FORCE_NAME_IN_AD` + are deprecated in this release. The application need to include the device name explicitly. One + way to do it is by adding the following to the advertising data or scan response data passed to + the host: + + .. code-block:: c + + BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1) + + (:github:`71686`) + +* The field :code:`init_credits` in :c:type:`bt_l2cap_le_endpoint` has been removed as it was no + longer used in Zephyr 3.4.0 and later. Any references to this field should be removed. No further + action is needed. + Networking ********** @@ -195,8 +414,7 @@ Networking * The zperf zperf_results struct is changed to support 64 bits transferred bytes (total_len) and test duration (time_in_us and client_time_in_us), instead of 32 bits. This will make - the long-duration zperf test show with correct throughput result. - (:github:`69500`) + the long-duration zperf test show with correct throughput result. (:github:`69500`) * Each IPv4 address assigned to a network interface has an IPv4 netmask tied to it instead of being set for the whole interface. @@ -230,24 +448,60 @@ Networking ``CONFIG_NET_TCP_RETRY_COUNT`` instead to control the total timeout at the TCP level. (:github:`70731`) +* In LwM2M API, the callback type :c:type:`lwm2m_engine_set_data_cb_t` has now an additional + parameter ``offset``. This parameter is used to indicate the offset of the data + during a Coap Block-wise transfer. Any post write, validate or some firmware callbacks + should be updated to include this parameter. (:github:`72590`) + + + Other Subsystems **************** +hawkBit +======= + +* :kconfig:option:`CONFIG_HAWKBIT_PORT` is now an int instead of a string. + :kconfig:option:`CONFIG_SETTINGS` needs to be enabled to use hawkBit, as it now uses the + settings subsystem to store the hawkBit configuration. (:github:`68806`) + LoRaWAN ======= MCUmgr ====== +* The support for SHA-256 (when using checksum/hash functions), previously provided + by either TinyCrypt or MbedTLS, is now provided by either PSA or MbedTLS. + PSA is the recommended API going forward, however, if it is not already enabled + (:kconfig:option:`CONFIG_MBEDTLS_PSA_CRYPTO_CLIENT`) and you have tight code size + constraints, you may be able to save 1.3 KB by using MbedTLS instead. + Modem ===== * The ``CONFIG_MODEM_CHAT_LOG_BUFFER`` Kconfig option was - renamed to :kconfig:option:`MODEM_CHAT_LOG_BUFFER_SIZE`. + renamed to :kconfig:option:`CONFIG_MODEM_CHAT_LOG_BUFFER_SIZE`. (:github:`70405`) Shell ===== +State Machine Framework +======================= + +* The :c:macro:`SMF_CREATE_STATE` macro now always takes 5 arguments. The amount of arguments is + now independent of the values of :kconfig:option:`CONFIG_SMF_ANCESTOR_SUPPORT` and + :kconfig:option:`CONFIG_SMF_INITIAL_TRANSITION`. If the additional arguments are not used, they + have to be set to ``NULL``. (:github:`71250`) +* SMF now follows a more UML-like transition flow when the transition source is a parent of the + state called by :c:func:`smf_run_state`. Exit actions up to (but not including) the Least Common + Ancestor of the transition source and target state will be executed, as will entry actions from + (but not including) the LCA down to the target state. (:github:`71675`) +* Previously, calling :c:func:`smf_set_state` with a ``new_state`` set to NULL would execute all + exit actions from the current state to the topmost parent, with the expectation the topmost exit + action would terminate the state machine. Passing ``NULL`` is now not allowed. Instead create a + 'terminate' state at the top level, and call :c:func:`smf_set_terminate` from its entry action. + ZBus ==== @@ -257,13 +511,19 @@ Userspace Architectures ************* -* Function :c:func:`arch_start_cpu` has been renamed to :c:func:`arch_cpu_start`. +* Function :c:func:`arch_start_cpu` has been renamed to :c:func:`arch_cpu_start`. (:github:`64987`) * x86 * Kconfigs ``CONFIG_DISABLE_SSBD`` and ``CONFIG_ENABLE_EXTENDED_IBRS`` are deprecated. Use :kconfig:option:`CONFIG_X86_DISABLE_SSBD` and - :kconfig:option:`CONFIG_X86_ENABLE_EXTENDED_IBRS` instead. + :kconfig:option:`CONFIG_X86_ENABLE_EXTENDED_IBRS` instead. (:github:`69690`) + +* POSIX arch: + + * LLVM fuzzing support has been refactored. A test application now needs to provide its own + ``LLVMFuzzerTestOneInput()`` hook instead of relying on a board provided one. Check + ``samples/subsys/debug/fuzz/`` for an example. (:github:`71378`) Xtensa ====== diff --git a/doc/releases/release-notes-3.5.rst b/doc/releases/release-notes-3.5.rst index 0ae90dd5c3e..dbe295829a6 100644 --- a/doc/releases/release-notes-3.5.rst +++ b/doc/releases/release-notes-3.5.rst @@ -430,7 +430,7 @@ Build system and infrastructure * Build time priority checking: enable build time priority checking by default. This fails the build if the initialization sequence in the final ELF file does not match the devicetree hierarchy. It can be turned off by disabling - the :kconfig:option:`COFNIG_CHECK_INIT_PRIORITIES` option. + the :kconfig:option:`CONFIG_CHECK_INIT_PRIORITIES` option. * Added a new ``initlevels`` target for printing the final device and :c:macro:`SYS_INIT` initialization sequence from the final ELF file. diff --git a/doc/releases/release-notes-3.7.rst b/doc/releases/release-notes-3.7.rst index d362eac0598..aff99963d78 100644 --- a/doc/releases/release-notes-3.7.rst +++ b/doc/releases/release-notes-3.7.rst @@ -12,6 +12,7 @@ Major enhancements with this release include: * A new, completely overhauled hardware model has been introduced. This changes the way both SoCs and boards are named, defined and constructed in Zephyr. Additional information can be found in the :ref:`board_porting_guide`. +* Zephyr now requires Python 3.10 or higher An overview of the changes required or recommended when migrating your application from Zephyr v3.6.0 to Zephyr v3.7.0 can be found in the separate :ref:`migration guide`. @@ -28,6 +29,41 @@ https://docs.zephyrproject.org/latest/security/vulnerabilities.html * CVE-2024-3077 `Zephyr project bug tracker GHSA-gmfv-4vfh-2mh8 `_ +* CVE-2024-4785: Under embargo until 2024-08-07 + +API Changes +*********** + +Removed APIs in this release +============================ + + * The Bluetooth subsystem specific debug symbols are removed. They have been replaced with the + Zephyr logging ones. + + * Removed deprecated ``pcie_probe`` and ``pcie_bdf_lookup`` functions from the PCIe APIs. + +Deprecated in this release +========================== + + * Bluetooth advertiser options :code:`BT_LE_ADV_OPT_USE_NAME` and + :code:`BT_LE_ADV_OPT_FORCE_NAME_IN_AD` are now deprecated. That means the following macro are + deprecated: + + * :c:macro:`BT_LE_ADV_CONN_NAME` + * :c:macro:`BT_LE_ADV_CONN_NAME_AD` + * :c:macro:`BT_LE_ADV_NCONN_NAME` + * :c:macro:`BT_LE_EXT_ADV_CONN_NAME` + * :c:macro:`BT_LE_EXT_ADV_SCAN_NAME` + * :c:macro:`BT_LE_EXT_ADV_NCONN_NAME` + * :c:macro:`BT_LE_EXT_ADV_CODED_NCONN_NAME` + + Application developer will now need to set the advertised name themselves by updating the advertising data + or the scan response data. + + * SPI + + * Deprecated :c:func:`spi_is_ready` API function has been removed. + Architectures ************* @@ -35,15 +71,37 @@ Architectures * ARM +* RISC-V + + * Implemented frame-pointer based stack unwinding. + + * The fatal error message triggered from a fault now contains the callee-saved-registers states. + * Xtensa +Kernel +****** + + * Added :c:func:`k_uptime_seconds` function to simplify `k_uptime_get() / 1000` usage. + Bluetooth ********* +* Audio + + * Removed ``err`` from :c:struct:`bt_bap_broadcast_assistant_cb.recv_state_removed` as it was + redundant. + +* Host * Added Nordic UART Service (NUS), enabled by the :kconfig:option:`CONFIG_BT_ZEPHYR_NUS`. This Service exposes the ability to declare multiple instances of the GATT service, allowing multiple serial endpoints to be used for different purposes. + * Implemented Hands-free Audio Gateway (AG), enabled by the :kconfig:option:`CONFIG_BT_HFP_AG`. + It works as a device that is the gateway of the audio. Typical device acting as Audio + Gateway is cellular phone. It controls the device (Hands-free Unit), that is the remote + audio input and output mechanism. + Boards & SoC Support ******************** @@ -51,6 +109,8 @@ Boards & SoC Support * Made these changes in other SoC series: + * ITE: Rename the Kconfig symbol for all ITE SoC variants. + * Added support for these ARM boards: * Added support for these Xtensa boards: @@ -61,11 +121,27 @@ Boards & SoC Support * Made these changes for native/POSIX boards: + * Introduced the simulated :ref:`nrf54l15bsim` target. + + * LLVM fuzzing support has been refactored while adding support for it in native_sim. + * Added support for these following shields: Build system and Infrastructure ******************************* + * CI-enabled blackbox tests were added in order to verify correctness of the vast majority of Twister flags. + + * A ``socs`` folder for applications has been introduced that allows for Kconfig fragments and + devicetree overlays that should apply to any board target using a particular SoC and board + qualifier. + + * :ref:`Board/SoC flashing configuration` settings have been added. + + * Deprecated the global CSTD cmake property in favor of the :kconfig:option:`CONFIG_STD_C` + choice to select the C Standard version. Additionally subsystems can select a minimum + required C Standard version, with for example :kconfig:option:`CONFIG_REQUIRES_STD_C11`. + Drivers and Sensors ******************* @@ -87,6 +163,10 @@ Drivers and Sensors * Deprecated the :c:func:`can_calc_prescaler` API function, as it allows for bitrate errors. Bitrate errors between nodes on the same network leads to them drifting apart after the start-of-frame (SOF) synchronization has taken place, leading to bus errors. + * Added :c:func:`can_get_bitrate_min` and :c:func:`can_get_bitrate_max` for retrieving the minimum + and maximum supported bitrate for a given CAN controller/CAN transceiver combination, reflecting + that retrieving the bitrate limits can no longer fail. Deprecated the existing + :c:func:`can_get_min_bitrate` and :c:func:`can_get_max_bitrate` API functions. * Extended support for automatic sample point location to also cover :c:func:`can_calc_timing` and :c:func:`can_calc_timing_data`. * Added optional ``min-bitrate`` devicetree property for CAN transceivers. @@ -120,8 +200,18 @@ Drivers and Sensors * Entropy +* eSPI + + * Renamed eSPI virtual wire direction macros and enum values to match the new terminology in + eSPI 1.5 specification. + * Ethernet + * Deperecated eth_mcux driver in favor of the reworked nxp_enet driver. + * Driver nxp_enet is no longer experimental. + * All boards and SOCs with :dtcompatible:`nxp,kinetis-ethernet` compatible nodes + reworked to use the new :dtcompatible:`nxp,enet` binding. + * Flash * GNSS @@ -138,6 +228,11 @@ Drivers and Sensors * Input +* LED Strip + + * The ``chain-length`` and ``color-mapping`` properties have been added to all LED strip + bindings. + * MDIO * MFD @@ -164,6 +259,9 @@ Drivers and Sensors * Sensor + * Added TMP114 driver + * Added DS18S20 1-wire temperature sensor driver. + * Serial * Added driver to support UART over Bluetooth LE using NUS (Nordic UART Service). This driver @@ -176,6 +274,11 @@ Drivers and Sensors * W1 +* Watchdog + + * Added :kconfig:option:`CONFIG_WDT_NPCX_WARNING_LEADING_TIME_MS` to set the leading warning time + in milliseconds. Removed no longer used :kconfig:option:`CONFIG_WDT_NPCX_DELAY_CYCLES`. + * Wi-Fi * Added support for configuring RTS threshold. With this, users can set the RTS threshold value or @@ -204,6 +307,13 @@ Networking * :c:func:`lwm2m_set_bulk` + * Added new ``offset`` parameter to :c:type:`lwm2m_engine_set_data_cb_t` callback type. + This affects post write and validate callbacks as well as some firmware callbacks. + +* IPSP: + + * Removed IPSP support. ``CONFIG_NET_L2_BT`` does not exist anymore. + USB *** @@ -215,6 +325,27 @@ Libraries / Subsystems * Management + * hawkBit + + * The hawkBit subsystem has been reworked to use the settings subsystem to store the hawkBit + configuration. + + * By enabling :kconfig:option:`CONFIG_HAWKBIT_SET_SETTINGS_RUNTIME`, the hawkBit settings can + be configured at runtime. Use the :c:func:`hawkbit_set_config` function to set the hawkBit + configuration. It can also be set via the hawkBit shell, by using the ``hawkbit set`` + command. + + * When using the hawkBit autohandler and an update is installed, the device will now + automatically reboot after the installation is complete. + + * By enabling :kconfig:option:`CONFIG_HAWKBIT_CUSTOM_DEVICE_ID`, a callback function can be + registered to set the device ID. Use the :c:func:`hawkbit_set_device_identity_cb` function to + register the callback. + + * By enabling :kconfig:option:`CONFIG_HAWKBIT_CUSTOM_ATTRIBUTES`, a callback function can be + registered to set the device attributes that are sent to the hawkBit server. Use the + :c:func:`hawkbit_set_custom_data_cb` function to register the callback. + * Logging * By enabling :kconfig:option:`CONFIG_LOG_BACKEND_NET_USE_DHCPV4_OPTION`, the IP address of the @@ -228,6 +359,9 @@ Libraries / Subsystems * Crypto + * MbedTLS was updated to 3.6.0. Release notes can be found at: + https://github.com/Mbed-TLS/mbedtls/releases/tag/v3.6.0 + * Random * Besides the existing :c:func:`sys_rand32_get` function, :c:func:`sys_rand8_get`, @@ -238,6 +372,13 @@ Libraries / Subsystems * SD +* State Machine Framework + + * The :c:macro:`SMF_CREATE_STATE` macro now always takes 5 arguments. + * Transition sources that are parents of the state that was run now choose the correct Least + Common Ancestor for executing Exit and Entry Actions. + * Passing ``NULL`` to :c:func:`smf_set_state` is now not allowed. + * Storage * FAT FS: It is now possible to expose file system formatting functionality for FAT without also diff --git a/doc/requirements.txt b/doc/requirements.txt index 983a29d2f18..bb12e241930 100644 --- a/doc/requirements.txt +++ b/doc/requirements.txt @@ -1,7 +1,7 @@ # DOC: used to generate docs breathe>=4.34 -sphinx~=7.1.0 +sphinx sphinx_rtd_theme~=2.0 sphinx-tabs sphinxcontrib-svg2pdfconverter diff --git a/doc/security/vulnerabilities.rst b/doc/security/vulnerabilities.rst index 468098fa0cc..33ebd3f3d9b 100644 --- a/doc/security/vulnerabilities.rst +++ b/doc/security/vulnerabilities.rst @@ -1713,3 +1713,8 @@ This has been fixed in main for v3.7.0 - `PR 69396 fix for main `_ + +CVE-2024-4785 +------------- + +Under embargo until 2024-08-07 diff --git a/doc/services/debugging/index.rst b/doc/services/debugging/index.rst index c1a455f5b1c..259fd894ac4 100644 --- a/doc/services/debugging/index.rst +++ b/doc/services/debugging/index.rst @@ -10,3 +10,4 @@ Debugging coredump.rst gdbstub.rst debugmon.rst + mipi_stp_decoder.rst diff --git a/doc/services/debugging/mipi_stp_decoder.rst b/doc/services/debugging/mipi_stp_decoder.rst new file mode 100644 index 00000000000..dfba9c7e99b --- /dev/null +++ b/doc/services/debugging/mipi_stp_decoder.rst @@ -0,0 +1,43 @@ +.. _mipi_stp_decoder: + +MIPI STP Decoder +################ + +The MIPI System Trace Protocol (MIPI STP) was developed as a generic base protocol that can +be shared by multiple application-specific trace protocols. It serves as a wrapper protocol +that merges disparate streams that typically contain different trace protocols from different +trace sources. Stream consists of opcode (shortest is 4 bit long) followed by optional data and +optional timestamp. There are opcodes for data (8, 16, 32, 64 bit data marked/not marked, with or +without timestamp), stream recognition (master and channel), synchronization (ASYNC opcode) and +others. + +One example where protocol is used is ARM Coresight STM (System Trace Macrocell) where data +written to Stimulus Port registers maps directly to STP stream. + +This module can be used to perform on-chip decoding of the data stream. STP v2 is used. + +Usage +##### + +Decoder is initialized with a callback. A callback is called on each decoded opcode. +Decoder has internal state since there are dependency between opcodes (e.g. timestamp can be +relative). Decoder can be in synchronization or not. Initial state is configurable. +If decoder is not synchronized to the stream then it decodes each nibble in search for ASYNC opcode. +Loss of synchronization can be indicated to the decoder by calling +:c:func:`mipi_stp_decoder_sync_loss`. :c:func:`mipi_stp_decoder_decode` is used to decode the data. + +Limitations +########### + +There are following limitations: + +* Decoder supports only little endian architectures. +* When decoding nibbles, it is more efficient when core supports unaligned memory access. + Implementation supports optimized version with unaligned memory access and generic one. + Optimized version is used for ARM Cortex-M (expect for M0). +* Limited set of the most common opcodes is implemented. + +API documentation +***************** + +.. doxygengroup:: mipi_stp_decoder_apis diff --git a/doc/services/pm/api/index.rst b/doc/services/pm/api/index.rst index bbf80ab61ae..8b37060ff7f 100644 --- a/doc/services/pm/api/index.rst +++ b/doc/services/pm/api/index.rst @@ -1,7 +1,7 @@ .. _pm_api: -Power Management -################ +Power Management APIs +##################### System PM APIs ************** diff --git a/doc/services/pm/device.rst b/doc/services/pm/device.rst index 773ce0a6901..055591c5f2c 100644 --- a/doc/services/pm/device.rst +++ b/doc/services/pm/device.rst @@ -18,7 +18,7 @@ Zephyr supports two methods of device power management: .. _pm-device-runtime-pm: Device Runtime Power Management -******************************* +=============================== Device runtime power management involves coordinated interaction between device drivers, subsystems, and applications. While device drivers @@ -70,7 +70,7 @@ For more information, see :ref:`pm-device-runtime`. .. _pm-device-system-pm: System-Managed Device Power Management -************************************** +====================================== When using this method, device power management is mostly done inside :c:func:`pm_system_suspend()` along with entering a CPU or SOC power state. @@ -231,6 +231,40 @@ support in a device driver. PM_DEVICE_DT_INST_GET(0), NULL, NULL, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, NULL); +.. _pm-device-shell: + +Shell Commands +************** + +Power management actions can be triggered from shell commands for testing +purposes. To do that, enable the :kconfig:option:`CONFIG_PM_DEVICE_SHELL` +option and issue a ``pm`` command on a device from the shell, for example: + +.. code-block:: console + + uart:~$ device list + - buttons (active) + uart:~$ pm suspend buttons + uart:~$ device list + devices: + - buttons (suspended) + +To print the power management state of a device, enable +:kconfig:option:`CONFIG_DEVICE_SHELL` and use the ``device list`` command, for +example: + +.. code-block:: console + + uart:~$ device list + devices: + - i2c@40003000 (active) + - buttons (active, usage=1) + - leds (READY) + +In this case, ``leds`` does not support PM, ``i2c`` supports PM with manual +suspend and resume actions and it's currently active, ``buttons`` supports +runtime PM and it's currently active with one user. + .. _pm-device-busy: Busy Status Indication @@ -285,9 +319,12 @@ later calling :c:func:`pm_device_wakeup_enable`. It is responsibility of driver or the application to do any additional configuration required by the device to support it. -Power Domain -************ +Examples +******** + +Some helpful examples showing device power management features: -Power domain on Zephyr is represented as a regular device. The power management -subsystem ensures that a domain is resumed before and suspended after devices -using it. For more details, see :ref:`pm-power-domain`. +* :zephyr_file:`samples/subsys/pm/device_pm/` +* :zephyr_file:`tests/subsys/pm/power_mgmt/` +* :zephyr_file:`tests/subsys/pm/device_wakeup_api/` +* :zephyr_file:`tests/subsys/pm/device_driver_init/` diff --git a/doc/services/pm/device_runtime.rst b/doc/services/pm/device_runtime.rst index b0dd57db02e..a8b21fa2f29 100644 --- a/doc/services/pm/device_runtime.rst +++ b/doc/services/pm/device_runtime.rst @@ -226,3 +226,12 @@ asynchronous API: /* "put" device (decreases usage count, schedule suspend if no more users) */ return pm_device_runtime_put_async(dev, K_NO_WAIT); } + +Examples +******** + +Some helpful examples showing device runtime power management features: + +* :zephyr_file:`tests/subsys/pm/device_runtime_api/` +* :zephyr_file:`tests/subsys/pm/device_power_domains/` +* :zephyr_file:`tests/subsys/pm/power_domain/` diff --git a/doc/services/pm/overview.rst b/doc/services/pm/overview.rst index 2395ce44a95..6e8edfa0052 100644 --- a/doc/services/pm/overview.rst +++ b/doc/services/pm/overview.rst @@ -6,10 +6,9 @@ are designed to be architecture and SOC independent. This enables power management implementations to be easily adapted to different SOCs and architectures. -The architecture and SOC independence is achieved by separating the core -infrastructure and the SOC specific implementations. The SOC specific -implementations are abstracted to the application and the OS using hardware -abstraction layers. +The architecture and SOC independence is achieved by separating the core PM +infrastructure from implementations of the SOC specific components. +Thus a coherent abstraction is presented to the rest of the OS and the application layer. The power management features are classified into the following categories. diff --git a/doc/services/pm/power_domain.rst b/doc/services/pm/power_domain.rst index e50109be5c2..feab6998c6e 100644 --- a/doc/services/pm/power_domain.rst +++ b/doc/services/pm/power_domain.rst @@ -178,3 +178,11 @@ They can safely be ignored though. It is responsibility of driver or the application to set the domain as "wakeup" source if a device depending on it is used as "wakeup" source. + +Examples +******** + +Some helpful examples showing power domain features: + +* :zephyr_file:`samples/subsys/pm/device_power_domains/` +* :zephyr_file:`samples/subsys/pm/power_domain/` diff --git a/doc/services/pm/system.rst b/doc/services/pm/system.rst index f3e52b93d87..d6ec306a200 100644 --- a/doc/services/pm/system.rst +++ b/doc/services/pm/system.rst @@ -3,17 +3,21 @@ System Power Management ####################### -The kernel enters the idle state when it has nothing to schedule. If enabled via -the :kconfig:option:`CONFIG_PM` Kconfig option, the Power Management -Subsystem can put an idle system in one of the supported power states, based -on the selected power management policy and the duration of the idle time -allotted by the kernel. - -It is an application responsibility to set up a wake up event. A wake up event -will typically be an interrupt triggered by one of the SoC peripheral modules -such as a SysTick, RTC, counter, or GPIO. Depending on the power mode entered, -only some SoC peripheral modules may be active and can be used as a wake up -source. +Introduction +************ + +The kernel enters the idle state when it has nothing to schedule. +Enabling :kconfig:option:`CONFIG_PM` allows the kernel to call upon the +power management subsystem to put an idle system into one of the supported power states. +The kernel requests an amount of time it would like to suspend, then the PM subsystem decides +the appropriate power state to transition to based on the configured power management policy. + +It is the application's responsibility to set up a wake-up event. +A wake-up event will typically be an interrupt triggered by an SoC peripheral module. +Examples include a SysTick, RTC, counter, or GPIO. +Keep in mind that depending on the SoC and the power mode in question, +not all peripherals may be active, and therefore +some wake-up sources may not be usable in all power modes. The following diagram describes system power management: @@ -64,24 +68,15 @@ The following diagram describes system power management: pm_system_resume:e -> lock:e [constraint=false lhed="cluster_0"] } -Some handful examples using different power management features: - -* :zephyr_file:`samples/boards/stm32/power_mgmt/blinky/` -* :zephyr_file:`samples/boards/esp32/deep_sleep/` -* :zephyr_file:`samples/subsys/pm/device_pm/` -* :zephyr_file:`tests/subsys/pm/power_mgmt/` -* :zephyr_file:`tests/subsys/pm/power_mgmt_soc/` -* :zephyr_file:`tests/subsys/pm/power_states_api/` Power States ============ -The power management subsystem contains a set of states based on -power consumption and context retention. +The power management subsystem defines a set of states described by the +power consumption and context retention associated with each of them. -The list of available power states is defined by :c:enum:`pm_state`. In -general power states with higher indexes will offer greater power savings and -have higher wake latencies. +The set of power states is defined by :c:enum:`pm_state`. In general, lower power states +(higher index in the enum) will offer greater power savings and have higher wake latencies. Power Management Policies ========================= @@ -91,9 +86,11 @@ The power management subsystem supports the following power management policies: * Residency based * Application defined -The policy manager is responsible for informing the power subsystem which -power state the system should transition to based on states defined by the -platform and other constraints such as a list of allowed states. +The policy manager is the component of the power management subsystem responsible +for deciding which power state the system should transition to. +The policy manager can only choose between states that have been defined for the platform. +Other constraints placed upon the decision may include locks disallowing certain power states, +or various kinds of minimum and maximum latency values, depending on the policy. More details on the states definition can be found in the :dtcompatible:`zephyr,power-state` binding documentation. @@ -101,18 +98,16 @@ More details on the states definition can be found in the Residency --------- -The power management system enters the power state which offers the highest -power savings, and with a minimum residency value (see -:dtcompatible:`zephyr,power-state`) less than or equal to the scheduled system -idle time duration. +Under the residency policy, the system will enter the power state which offers the highest +power savings, with the constraint that the sum of the minimum residency value (see +:dtcompatible:`zephyr,power-state`) and the latency to exit the mode must be +less than or equal to the system idle time duration scheduled by the kernel. -This policy also accounts for the time necessary to become active -again. The core logic used by this policy to select the best power -state is: +Thus the core logic can be summarized with the following expression: .. code-block:: c - if (time_to_next_scheduled_event >= (state.min_residency_us + state.exit_latency))) { + if (time_to_next_scheduled_event >= (state.min_residency_us + state.exit_latency)) { return state } @@ -120,9 +115,9 @@ Application ----------- The application defines the power management policy by implementing the -:c:func:`pm_policy_next_state` function. In this policy the application is free +:c:func:`pm_policy_next_state` function. In this policy, the application is free to decide which power state the system should transition to based on the -remaining time for the next scheduled timeout. +remaining time until the next scheduled timeout. An example of an application that defines its own policy can be found in :zephyr_file:`tests/subsys/pm/power_mgmt/`. @@ -131,7 +126,19 @@ Policy and Power States ------------------------ The power management subsystem allows different Zephyr components and -applications to configure the policy manager to block system from transitioning +applications to configure the policy manager to block the system from transitioning into certain power states. This can be used by devices when executing tasks in background to prevent the system from going to a specific state where it would -lose context. +lose context. See :c:func:`pm_policy_state_lock_get`. + +Examples +======== + +Some helpful examples showing different power management features: + +* :zephyr_file:`samples/boards/stm32/power_mgmt/blinky/` +* :zephyr_file:`samples/boards/esp32/deep_sleep/` +* :zephyr_file:`samples/subsys/pm/device_pm/` +* :zephyr_file:`tests/subsys/pm/power_mgmt/` +* :zephyr_file:`tests/subsys/pm/power_mgmt_soc/` +* :zephyr_file:`tests/subsys/pm/power_states_api/` diff --git a/doc/services/portability/posix/aep/aep-pse51.svg b/doc/services/portability/posix/aep/aep-pse51.svg new file mode 100644 index 00000000000..17cf806c834 --- /dev/null +++ b/doc/services/portability/posix/aep/aep-pse51.svg @@ -0,0 +1,17 @@ + + + + + + + /* TODO: Change color based on dark / light modes */ + + + System + Interfaces + + PSE51 + PSE52 + PSE53 + + diff --git a/doc/services/portability/posix/aep/aep-pse52.svg b/doc/services/portability/posix/aep/aep-pse52.svg new file mode 100644 index 00000000000..f5fd66d1d7a --- /dev/null +++ b/doc/services/portability/posix/aep/aep-pse52.svg @@ -0,0 +1,17 @@ + + + + + + + /* TODO: Change color based on dark / light modes */ + + + System + Interfaces + + PSE51 + PSE52 + PSE53 + + diff --git a/doc/services/portability/posix/aep/aep-pse53.svg b/doc/services/portability/posix/aep/aep-pse53.svg new file mode 100644 index 00000000000..0fea6558b48 --- /dev/null +++ b/doc/services/portability/posix/aep/aep-pse53.svg @@ -0,0 +1,17 @@ + + + + + + + /* TODO: Change color based on dark / light modes */ + + + System + Interfaces + + PSE51 + PSE52 + PSE53 + + diff --git a/doc/services/portability/posix/aep/index.rst b/doc/services/portability/posix/aep/index.rst index fdc2716b2e2..a8f214ef2aa 100644 --- a/doc/services/portability/posix/aep/index.rst +++ b/doc/services/portability/posix/aep/index.rst @@ -8,11 +8,34 @@ subprofiling options of `IEEE 1003.1-2017`_. The single-purpose realtime system are listed below, for reference, in terms that agree with the current POSIX-1 standard. PSE54 is not considered at this time. +System Interfaces +================= + +The required POSIX :ref:`System Interfaces` are supported for +each Application Environment Profile. + +.. figure:: si.svg + :align: center + :scale: 150% + :alt: Required System Interfaces + + System Interfaces + .. _posix_aep_pse51: Minimal Realtime System Profile (PSE51) ======================================= +The *Minimal Realtime System Profile* (PSE51) includes all of the +:ref:`System Interfaces` along with several additional features. + +.. figure:: aep-pse51.svg + :align: center + :scale: 150% + :alt: Minimal Realtime System Profile (PSE51) + + Minimal Realtime System Profile (PSE51) + .. Conforming implementations shall define _POSIX_AEP_REALTIME_MINIMAL to the value 200312L .. csv-table:: PSE51 System Interfaces @@ -25,43 +48,47 @@ Minimal Realtime System Profile (PSE51) :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, yes, - POSIX_THREADS_BASE, yes, :ref:`ā€ ` - XSI_THREADS_EXT, yes, + :ref:`POSIX_C_LANG_JUMP `, yes, + :ref:`POSIX_C_LANG_SUPPORT `, yes, + :ref:`POSIX_DEVICE_IO `,, + :ref:`POSIX_SIGNALS `,, + :ref:`POSIX_SINGLE_PROCESS `, yes, + :ref:`POSIX_THREADS_BASE `, yes, + :ref:`XSI_THREADS_EXT `, yes, .. 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, + :ref:`_POSIX_FSYNC `, 200809L, :kconfig:option:`CONFIG_POSIX_FSYNC` + :ref:`_POSIX_MEMLOCK `, -1, + :ref:`_POSIX_MEMLOCK_RANGE `, -1, + :ref:`_POSIX_MONOTONIC_CLOCK `, 200809L, :kconfig:option:`CONFIG_POSIX_CLOCK` + :ref:`_POSIX_SHARED_MEMORY_OBJECTS `, -1, + :ref:`_POSIX_SYNCHRONIZED_IO `, -1, + :ref:`_POSIX_THREAD_ATTR_STACKADDR`, 200809L, :kconfig:option:`CONFIG_PTHREAD` + :ref:`_POSIX_THREAD_ATTR_STACKSIZE`, 200809L, :kconfig:option:`CONFIG_PTHREAD` + :ref:`_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:`ā€ `) + :ref:`_POSIX_THREAD_PRIORITY_SCHEDULING`, 200809L, :kconfig:option:`CONFIG_POSIX_PRIORITY_SCHEDULING` _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) ========================================== +The *Realtime Controller System Profile* (PSE52) includes all features from PSE51 and the +:ref:`System Interfaces`. + +.. figure:: aep-pse52.svg + :align: center + :scale: 150% + :alt: Realtime Controller System Profile (PSE52) + + Realtime Controller System Profile (PSE52) + .. Conforming implementations shall define _POSIX_AEP_REALTIME_CONTROLLER to the value 200312L .. csv-table:: PSE52 System Interfaces @@ -74,42 +101,15 @@ Realtime Controller System Profile (PSE52) :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, yes, - POSIX_THREADS_BASE, yes, :ref:`ā€ ` - XSI_THREADS_EXT, yes, + :ref:`POSIX_C_LANG_MATH `, yes, + :ref:`POSIX_FD_MGMT `,, + :ref:`POSIX_FILE_SYSTEM `,, .. 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` + :ref:`_POSIX_MESSAGE_PASSING `, 200809L, :kconfig:option:`CONFIG_POSIX_MQUEUE` _POSIX_TRACE, -1, _POSIX_TRACE_EVENT_FILTER, -1, _POSIX_TRACE_LOG, -1, @@ -119,6 +119,16 @@ Realtime Controller System Profile (PSE52) Dedicated Realtime System Profile (PSE53) ========================================= +The *Dedicated Realtime System Profile* (PSE53) includes all features from PSE52, PSE51, and the +:ref:`System Interfaces`. + +.. figure:: aep-pse53.svg + :align: center + :scale: 150% + :alt: Dedicated Realtime System Profile (PSE53) + + Dedicated Realtime System Profile (PSE53) + .. Conforming implementations shall define _POSIX_AEP_REALTIME_DEDICATED to the value 200312L .. csv-table:: PSE53 System Interfaces @@ -131,58 +141,21 @@ Dedicated Realtime System Profile (PSE53) :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_NETWORKING ` - POSIX_PIPE,, :ref:`ā€ ` - POSIX_SIGNALS,, :ref:`ā€ ` - POSIX_SIGNAL_JUMP,, :ref:`ā€ ` - POSIX_SINGLE_PROCESS, yes, - POSIX_THREADS_BASE, yes, :ref:`ā€ ` - XSI_THREADS_EXT, yes, + :ref:`POSIX_NETWORKING `, yes, + :ref:`POSIX_PIPE `,, + :ref:`POSIX_SIGNAL_JUMP `,, .. 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, + :ref:`_POSIX_PRIORITY_SCHEDULING `, -1, + _POSIX_RAW_SOCKETS, 200809L, :kconfig:option:`CONFIG_NET_SOCKETS_PACKET` + _POSIX_SPAWN, -1, :ref:`ā€ ` + _POSIX_SPORADIC_SERVER, -1, :ref:`ā€ ` .. _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/aep/si.svg b/doc/services/portability/posix/aep/si.svg new file mode 100644 index 00000000000..a26f28e09be --- /dev/null +++ b/doc/services/portability/posix/aep/si.svg @@ -0,0 +1,17 @@ + + + + + + + /* TODO: Change color based on dark / light modes */ + + + System + Interfaces + + PSE51 + PSE52 + PSE53 + + diff --git a/doc/services/portability/posix/conformance/index.rst b/doc/services/portability/posix/conformance/index.rst index 2b2e687d94e..69e77eed89c 100644 --- a/doc/services/portability/posix/conformance/index.rst +++ b/doc/services/portability/posix/conformance/index.rst @@ -54,18 +54,20 @@ POSIX System Interfaces 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. +.. _posix_system_interfaces_required: + .. csv-table:: POSIX System Interfaces :header: Symbol, Support, Remarks :widths: 50, 10, 50 _POSIX_VERSION, 200809L, - _POSIX_ASYNCHRONOUS_IO, -1, :ref:`ā€ ` + :ref:`_POSIX_ASYNCHRONOUS_IO`, 200809L, :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`, 200809L, :kconfig:option:`CONFIG_PTHREAD_IPC` - _POSIX_REALTIME_SIGNALS, -1, :ref:`ā€ ` + :ref:`_POSIX_REALTIME_SIGNALS`, -1, :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, @@ -80,22 +82,22 @@ POSIX System Interfaces _POSIX_ADVISORY_INFO, -1, _POSIX_CPUTIME, 200809L, :kconfig:option:`CONFIG_POSIX_CLOCK` - _POSIX_FSYNC, -1, + :ref:`_POSIX_FSYNC`, 200809L, :kconfig:option:`CONFIG_POSIX_FSYNC` _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` + :ref:`_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` + :ref:`_POSIX_PRIORITY_SCHEDULING`, 200809L, :kconfig:option:`CONFIG_POSIX_PRIORITY_SCHEDULING` + _POSIX_RAW_SOCKETS, 200809L, :kconfig:option:`CONFIG_NET_SOCKETS_PACKET` _POSIX_SHARED_MEMORY_OBJECTS, -1, - _POSIX_SPAWN, -1, - _POSIX_SPORADIC_SERVER, -1, + _POSIX_SPAWN, -1, :ref:`ā€ ` + _POSIX_SPORADIC_SERVER, -1, :ref:`ā€ ` _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_CPUTIME, -1, _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` @@ -146,7 +148,7 @@ XSI System Interfaces :header: Symbol, Support, Remarks :widths: 50, 10, 50 - _POSIX_FSYNC, -1, :ref:`ā€ ` + :ref:`_POSIX_FSYNC`, 200809L, :kconfig:option:`CONFIG_POSIX_FSYNC` :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, diff --git a/doc/services/portability/posix/implementation/index.rst b/doc/services/portability/posix/implementation/index.rst index 361b0405576..1a3756ae2c0 100644 --- a/doc/services/portability/posix/implementation/index.rst +++ b/doc/services/portability/posix/implementation/index.rst @@ -18,7 +18,7 @@ Unlike other multi-purpose POSIX operating systems .. 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. + build time. See :ref:`System Calls ` for more information. Design ====== @@ -73,5 +73,5 @@ Some general design considerations: } - 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 + :ref:`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/option_groups/index.rst b/doc/services/portability/posix/option_groups/index.rst index afb3c184448..e284af76d02 100644 --- a/doc/services/portability/posix/option_groups/index.rst +++ b/doc/services/portability/posix/option_groups/index.rst @@ -151,6 +151,31 @@ Group. For more information on developing Zephyr applications in the C programming language, please refer to :ref:`details`. +.. _posix_option_group_realtime_signals: + +POSIX_REALTIME_SIGNALS +====================== + +.. csv-table:: POSIX_REALTIME_SIGNALS + :header: API, Supported + :widths: 50,10 + + sigqueue(), + sigtimedwait(), + sigwaitinfo(), + +.. _posix_option_group_signal_jump: + +POSIX_SIGNAL_JUMP +================= + +.. csv-table:: POSIX_SIGNAL_JUMP + :header: API, Supported + :widths: 50,10 + + siglongjmp(), + sigsetjmp(), + .. _posix_option_group_single_process: POSIX_SINGLE_PROCESS @@ -289,6 +314,42 @@ POSIX_CLOCK_SELECTION pthread_condattr_setclock(),yes clock_nanosleep(),yes +.. _posix_option_group_file_system: + +POSIX_FILE_SYSTEM +================= + +.. csv-table:: POSIX_FILE_SYSTEM + :header: API, Supported + :widths: 50,10 + + access(), + chdir(), + closedir(), yes + creat(), + fchdir(), + fpathconf(), + fstat(), + fstatvfs(), + getcwd(), + link(), + mkdir(), yes + mkstemp(), + opendir(), yes + pathconf(), + readdir(), yes + remove(), + rename(), yes + rewinddir(), + rmdir(), + stat(), yes + statvfs(), + tmpfile(), + tmpnam(), + truncate(), + unlink(), yes + utime(), + .. _posix_option_group_networking: POSIX_NETWORKING @@ -352,6 +413,16 @@ POSIX_NETWORKING sockatmark(),yes (will fail with ``ENOSYS``:ref:`ā€ `) socketpair(),yes +.. _posix_option_group_pipe: + +POSIX_PIPE +========== + +.. csv-table:: POSIX_PIPE + :header: API, Supported + :widths: 50,10 + + pipe(), .. _posix_option_group_semaphores: @@ -406,12 +477,107 @@ POSIX_TIMERS timer_getoverrun(),yes timer_settime(),yes +.. _posix_option_group_fd_mgmt: + +POSIX_FD_MGMT +============= + +This table lists service support status in Zephyr for `POSIX_FD_MGMT`: + +.. csv-table:: POSIX_FD_MGMT + :header: API, Supported + :widths: 50,10 + + dup(), + dup2(), + fcntl(), + fgetpos(), + fseek(), + fseeko(), + fsetpos(), + ftell(), + ftello(), + ftruncate(),yes + lseek(), + rewind(), + +.. _posix_option_group_file_locking: + +POSIX_FILE_LOCKING +================== + +This table lists service support status in Zephyr for `POSIX_FD_MGMT`: + +.. csv-table:: POSIX_FILE_LOCKING + :header: API, Supported + :widths: 50,10 + + flockfile(), + ftrylockfile(), + funlockfile(), + getc_unlocked(), + getchar_unlocked(), + putc_unlocked(), + putchar_unlocked(), .. _posix_options: Additional POSIX Options ======================== +.. _posix_option_asynchronous_io: + +_POSIX_ASYNCHRONOUS_IO +++++++++++++++++++++++ + +.. csv-table:: _POSIX_ASYNCHRONOUS_IO + :header: API, Supported + :widths: 50,10 + + aio_cancel(),yes (will fail with ``ENOSYS``:ref:`ā€ `) + aio_error(),yes (will fail with ``ENOSYS``:ref:`ā€ `) + aio_fsync(),yes (will fail with ``ENOSYS``:ref:`ā€ `) + aio_read(),yes (will fail with ``ENOSYS``:ref:`ā€ `) + aio_return(),yes (will fail with ``ENOSYS``:ref:`ā€ `) + aio_suspend(),yes (will fail with ``ENOSYS``:ref:`ā€ `) + aio_write(),yes (will fail with ``ENOSYS``:ref:`ā€ `) + lio_listio(),yes (will fail with ``ENOSYS``:ref:`ā€ `) + +.. _posix_option_fsync: + +_POSIX_FSYNC +++++++++++++ + +.. csv-table:: _POSIX_FSYNC + :header: API, Supported + :widths: 50,10 + + fsync(),yes + +.. _posix_option_memlock: + +_POSIX_MEMLOCK +++++++++++++++ + +.. csv-table:: _POSIX_MEMLOCK + :header: API, Supported + :widths: 50,10 + + mlockall(), + munlockall(), + +.. _posix_option_memlock_range: + +_POSIX_MEMLOCK_RANGE +++++++++++++++++++++ + +.. csv-table:: _POSIX_MEMLOCK_RANGE + :header: API, Supported + :widths: 50,10 + + mlock(), + munlock(), + .. _posix_option_message_passing: _POSIX_MESSAGE_PASSING @@ -430,11 +596,22 @@ _POSIX_MESSAGE_PASSING mq_setattr(),yes mq_unlink(),yes -_POSIX_PRIORITY_SCHEDULING -++++++++++++++++++++++++++ +.. _posix_option_monotonic_clock: + +_POSIX_MONOTONIC_CLOCK +++++++++++++++++++++++ + +.. csv-table:: _POSIX_MONOTONIC_CLOCK + :header: API, Supported + :widths: 50,10 + + CLOCK_MONOTONIC,yes .. _posix_option_priority_scheduling: +_POSIX_PRIORITY_SCHEDULING +++++++++++++++++++++++++++ + .. csv-table:: _POSIX_PRIORITY_SCHEDULING :header: API, Supported :widths: 50,10 @@ -469,6 +646,33 @@ _POSIX_READER_WRITER_LOCKS pthread_rwlockattr_init(),yes pthread_rwlockattr_setpshared(),yes +.. _posix_shared_memory_objects: + +_POSIX_SHARED_MEMORY_OBJECTS +++++++++++++++++++++++++++++ + +.. csv-table:: _POSIX_SHARED_MEMORY_OBJECTS + :header: API, Supported + :widths: 50,10 + + mmap(), + munmap(), + shm_open(), + shm_unlink(), + +.. _posix_option_synchronized_io: + +_POSIX_SYNCHRONIZED_IO +++++++++++++++++++++++ + +.. csv-table:: _POSIX_SYNCHRONIZED_IO + :header: API, Supported + :widths: 50,10 + + fdatasync(), + fsync(),yes + msync(), + .. _posix_option_thread_attr_stackaddr: _POSIX_THREAD_ATTR_STACKADDR @@ -481,6 +685,18 @@ _POSIX_THREAD_ATTR_STACKADDR pthread_attr_getstackaddr(),yes pthread_attr_setstackaddr(),yes +.. _posix_option_thread_cputime: + +_POSIX_THREAD_CPUTIME ++++++++++++++++++++++ + +.. csv-table:: _POSIX_THREAD_CPUTIME + :header: API, Supported + :widths: 50,10 + + CLOCK_THREAD_CPUTIME_ID,yes + pthread_getcpuclockid(),yes + .. _posix_option_thread_attr_stacksize: _POSIX_THREAD_ATTR_STACKSIZE @@ -572,10 +788,9 @@ _XOPEN_STREAMS getmsg(), yes (will fail with ``ENOSYS``:ref:`ā€ `) getpmsg(), yes (will fail with ``ENOSYS``:ref:`ā€ `) ioctl(),yes - isastream(), + isastream(),yes (will fail with ``ENOSYS``:ref:`ā€ `) putmsg(), yes (will fail with ``ENOSYS``:ref:`ā€ `) putpmsg(), - .. _Subprofiling Considerations: https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_subprofiles.html diff --git a/doc/services/portability/posix/overview/aep.svg b/doc/services/portability/posix/overview/aep.svg new file mode 100644 index 00000000000..d98bc8e6f73 --- /dev/null +++ b/doc/services/portability/posix/overview/aep.svg @@ -0,0 +1,17 @@ + + + + + + + /* TODO: Change color based on dark / light modes */ + + + System + Interfaces + + PSE51 + PSE52 + PSE53 + + diff --git a/doc/services/portability/posix/overview/index.rst b/doc/services/portability/posix/overview/index.rst index 4ef1f9a596d..cd00b68b1a7 100644 --- a/doc/services/portability/posix/overview/index.rst +++ b/doc/services/portability/posix/overview/index.rst @@ -38,11 +38,13 @@ Benefits of POSIX support in Zephyr include: 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 Zephyr supports running multiple :ref:`threads ` (possibly in an +:ref:`SMP ` configuration), as well as +:ref:`Virtual Memory and MMUs `, Zephyr code and data normally share a +common address space that is partitioned into separate :ref:`Memory Domains `. 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, @@ -50,7 +52,15 @@ and experience limited user interaction. In such systems, full POSIX conformance 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). +as part of `IEEE 1003.13-2003`_ (also known as POSIX.13-2003). Each AEP adds incrementally more +features over the required :ref:`POSIX System Interfaces `. + +.. figure:: aep.svg + :align: center + :scale: 150% + :alt: POSIX Application Environment Profiles (AEP) + + POSIX Application Environment Profiles (AEP) * Minimal Realtime System Profile (:ref:`PSE51 `) * Realtime Controller System Profile (:ref:`PSE52 `) diff --git a/doc/services/smf/index.rst b/doc/services/smf/index.rst index ad15393120f..9b5ee62af76 100644 --- a/doc/services/smf/index.rst +++ b/doc/services/smf/index.rst @@ -39,7 +39,7 @@ By default, a state can have no ancestor states, resulting in a flat state machine. But to enable the creation of a hierarchical state machine, the :kconfig:option:`CONFIG_SMF_ANCESTOR_SUPPORT` option must be enabled. -By default, the hierarchical state machine does not support initial transitions +By default, the hierarchical state machines do not support initial transitions to child states on entering a superstate. To enable them the :kconfig:option:`CONFIG_SMF_INITIAL_TRANSITION` option must be enabled. @@ -47,12 +47,6 @@ The following macro can be used for easy state creation: * :c:macro:`SMF_CREATE_STATE` Create a state -.. note:: The :c:macro:`SMF_CREATE_STATE` macro takes an additional parameter - for the parent state when :kconfig:option:`CONFIG_SMF_ANCESTOR_SUPPORT` is - enabled . The :c:macro:`SMF_CREATE_STATE` macro takes two additional - parameters for the parent state and initial transition when the - :kconfig:option:`CONFIG_SMF_INITIAL_TRANSITION` option is enabled. - State Machine Creation ====================== @@ -62,9 +56,9 @@ enum. For example, the following creates three flat states:: enum demo_state { S0, S1, S2 }; const struct smf_state demo_states[] = { - [S0] = SMF_CREATE_STATE(s0_entry, s0_run, s0_exit), - [S1] = SMF_CREATE_STATE(s1_entry, s1_run, s1_exit), - [S2] = SMF_CREATE_STATE(s2_entry, s2_run, s2_exit) + [S0] = SMF_CREATE_STATE(s0_entry, s0_run, s0_exit, NULL, NULL), + [S1] = SMF_CREATE_STATE(s1_entry, s1_run, s1_exit, NULL, NULL), + [S2] = SMF_CREATE_STATE(s2_entry, s2_run, s2_exit, NULL, NULL) }; And this example creates three hierarchical states:: @@ -72,9 +66,9 @@ And this example creates three hierarchical states:: enum demo_state { S0, S1, S2 }; const struct smf_state demo_states[] = { - [S0] = SMF_CREATE_STATE(s0_entry, s0_run, s0_exit, parent_s0), - [S1] = SMF_CREATE_STATE(s1_entry, s1_run, s1_exit, parent_s12), - [S2] = SMF_CREATE_STATE(s2_entry, s2_run, s2_exit, parent_s12) + [S0] = SMF_CREATE_STATE(s0_entry, s0_run, s0_exit, parent_s0, NULL), + [S1] = SMF_CREATE_STATE(s1_entry, s1_run, s1_exit, parent_s12, NULL), + [S2] = SMF_CREATE_STATE(s2_entry, s2_run, s2_exit, parent_s12, NULL) }; @@ -93,31 +87,29 @@ from parent state S0 to child state S2:: }; To set the initial state, the :c:func:`smf_set_initial` function should be -called. It has the following prototype: -``void smf_set_initial(smf_ctx *ctx, smf_state *state)`` +called. To transition from one state to another, the :c:func:`smf_set_state` -function is used and it has the following prototype: -``void smf_set_state(smf_ctx *ctx, smf_state *state)`` +function is used. .. note:: If :kconfig:option:`CONFIG_SMF_INITIAL_TRANSITION` is not set, :c:func:`smf_set_initial` and :c:func:`smf_set_state` function should not be passed a parent state as the parent state does not know which child state to transition to. Transitioning to a parent state is OK if an initial transition to a child state is defined. A well-formed - HSM will have initial transitions defined for all parent states. + HSM should have initial transitions defined for all parent states. -.. note:: While the state machine is running, smf_set_state should only be - called from the Entry and Run functions. Calling smf_set_state from the - Exit functions doesn't make sense and will generate a warning. +.. note:: While the state machine is running, :c:func:`smf_set_state` should + only be called from the Entry or Run function. Calling + :c:func:`smf_set_state` from Exit functions will generate a warning in the + log and no transition will occur. State Machine Execution ======================= To run the state machine, the :c:func:`smf_run_state` function should be called in some application dependent way. An application should cease calling -smf_run_state if it returns a non-zero value. The function has the following -prototype: ``int32_t smf_run_state(smf_ctx *ctx)`` +smf_run_state if it returns a non-zero value. Preventing Parent Run Actions ============================= @@ -130,13 +122,38 @@ State Machine Termination ========================= To terminate the state machine, the :c:func:`smf_set_terminate` function -should be called. It can be called from the entry, run, or exit action. The -function takes a non-zero user defined value that's returned by the -:c:func:`smf_run_state` function. The function has the following prototype: -``void smf_set_terminate(smf_ctx *ctx, int32_t val)`` +should be called. It can be called from the entry, run, or exit actions. The +function takes a non-zero user defined value that will be returned by the +:c:func:`smf_run_state` function. + +UML State Machines +================== + +SMF follows UML hierarchical state machine rules for transitions i.e., the +entry and exit actions of the least common ancestor are not executed on +transition, unless said transition is a transition to self. + +The UML Specification for StateMachines may be found in chapter 14 of the UML +specification available here: https://www.omg.org/spec/UML/ + +SMF breaks from UML rules in: + +1. Executing the actions associated with the transition within the context + of the source state, rather than after the exit actions are performed. +2. Only allowing external transitions to self, not to sub-states. A transition + from a superstate to a child state is treated as a local transition. +3. Prohibiting transitions using :c:func:`smf_set_state` in exit actions. + +SMF also does not provide any pseudostates except the Initial Pseudostate. +Terminate pseudostates can be modelled by calling :c:func:`smf_set_terminate` +from the entry action of a 'terminate' state. Orthogonal regions are modelled +by calling :c:func:`smf_run_state` for each region. + +State Machine Examples +====================== Flat State Machine Example -========================== +************************** This example turns the following state diagram into code using the SMF, where the initial state is S0. @@ -211,11 +228,11 @@ Code:: /* Populate state table */ static const struct smf_state demo_states[] = { - [S0] = SMF_CREATE_STATE(s0_entry, s0_run, s0_exit), + [S0] = SMF_CREATE_STATE(s0_entry, s0_run, s0_exit, NULL, NULL), /* State S1 does not have an entry action */ - [S1] = SMF_CREATE_STATE(NULL, s1_run, s1_exit), + [S1] = SMF_CREATE_STATE(NULL, s1_run, s1_exit, NULL, NULL), /* State S2 does not have an exit action */ - [S2] = SMF_CREATE_STATE(s2_entry, s2_run, NULL), + [S2] = SMF_CREATE_STATE(s2_entry, s2_run, NULL, NULL, NULL), }; int main(void) @@ -238,7 +255,7 @@ Code:: } Hierarchical State Machine Example -================================== +********************************** This example turns the following state diagram into code using the SMF, where S0 and S1 share a parent state and S0 is the initial state. @@ -314,12 +331,12 @@ Code:: /* Populate state table */ static const struct smf_state demo_states[] = { /* Parent state does not have a run action */ - [PARENT] = SMF_CREATE_STATE(parent_entry, NULL, parent_exit, NULL), + [PARENT] = SMF_CREATE_STATE(parent_entry, NULL, parent_exit, NULL, NULL), /* Child states do not have entry or exit actions */ - [S0] = SMF_CREATE_STATE(NULL, s0_run, NULL, &demo_states[PARENT]), - [S1] = SMF_CREATE_STATE(NULL, s1_run, NULL, &demo_states[PARENT]), + [S0] = SMF_CREATE_STATE(NULL, s0_run, NULL, &demo_states[PARENT], NULL), + [S1] = SMF_CREATE_STATE(NULL, s1_run, NULL, &demo_states[PARENT], NULL), /* State S2 do ot have entry or exit actions and no parent */ - [S2] = SMF_CREATE_STATE(NULL, s2_run, NULL, NULL), + [S2] = SMF_CREATE_STATE(NULL, s2_run, NULL, NULL, NULL), }; int main(void) @@ -348,17 +365,14 @@ When designing hierarchical state machines, the following should be considered: re-execute the ancestor\'s entry action or execute the exit action. For example, the parent_entry function is not called when transitioning from S0 to S1, nor is the parent_exit function called. - - Ancestor exit actions are executed after the sibling exit actions. For - example, the s1_exit function is called before the parent_exit function - is called. + - Ancestor exit actions are executed after the exit action of the current + state. For example, the s1_exit function is called before the parent_exit + function is called. - The parent_run function only executes if the child_run function does not call either :c:func:`smf_set_state` or :c:func:`smf_set_handled`. - - Transitions to self in super-states containing sub-states are not supported. - Transitions to self from the most-nested child state are supported and will - call the exit and entry function of the child state correctly. Event Driven State Machine Example -================================== +********************************** Events are not explicitly part of the State Machine Framework but an event driven state machine can be implemented using Zephyr :ref:`events`. @@ -445,8 +459,8 @@ Code:: /* Populate state table */ static const struct smf_state demo_states[] = { - [S0] = SMF_CREATE_STATE(s0_entry, s0_run, NULL), - [S1] = SMF_CREATE_STATE(s1_entry, s1_run, NULL), + [S0] = SMF_CREATE_STATE(s0_entry, s0_run, NULL, NULL, NULL), + [S1] = SMF_CREATE_STATE(s1_entry, s1_run, NULL, NULL, NULL), }; void button_pressed(const struct device *dev, @@ -505,47 +519,55 @@ Code:: } } -Hierarchical State Machine Example With Initial Transitions -=========================================================== +State Machine Example With Initial Transitions And Transition To Self +********************************************************************* + +:zephyr_file:`tests/lib/smf/src/test_lib_self_transition_smf.c` defines a state +machine for testing the initial transitions and transitions to self in a parent +state. The statechart for this test is below. -:zephyr_file:`tests/lib/smf/src/test_lib_initial_transitions_smf.c` defines -a state machine for testing initial transitions and :c:func:`smf_set_handled`. -The statechart for this test is below. .. graphviz:: - :caption: Test state machine for initial transitions and ``smf_set_handled`` + :caption: Test state machine for UML State Transitions digraph smf_hierarchical_initial { compound=true; node [style = rounded]; - smf_set_initial [shape=plaintext]; + "smf_set_initial()" [shape=plaintext fontname=Courier]; ab_init_state [shape = point]; STATE_A [shape = box]; STATE_B [shape = box]; STATE_C [shape = box]; STATE_D [shape = box]; + DC[shape=point height=0 width=0 label=<>] - subgraph cluster_ab { - label = "PARENT_AB"; + subgraph cluster_root { + label = "ROOT"; style = rounded; - ab_init_state -> STATE_A; - STATE_A -> STATE_B; - } - subgraph cluster_c { - label = "PARENT_C"; - style = rounded; - STATE_C -> STATE_C + subgraph cluster_ab { + label = "PARENT_AB"; + style = rounded; + ab_init_state -> STATE_A; + STATE_A -> STATE_B; + } + + subgraph cluster_c { + label = "PARENT_C"; + style = rounded; + STATE_B -> STATE_C [ltail=cluster_ab] + } + + STATE_C -> DC [ltail=cluster_c, dir=none]; + DC -> STATE_C [lhead=cluster_c]; + STATE_C -> STATE_D } - smf_set_initial -> STATE_A [lhead=cluster_ab] - STATE_B -> STATE_C - STATE_C -> STATE_D + "smf_set_initial()" -> STATE_A [lhead=cluster_ab] } - API Reference -************* +============= .. doxygengroup:: smf diff --git a/doc/services/storage/disk/nvme.rst b/doc/services/storage/disk/nvme.rst index efb6a3d7e1f..8debbdb1890 100644 --- a/doc/services/storage/disk/nvme.rst +++ b/doc/services/storage/disk/nvme.rst @@ -12,9 +12,10 @@ Driver design ************* The driver is sliced up in 3 main parts: -- NVMe controller :zephyr_file:`drivers/disk/nvme/nvme_controller.c` -- NVMe commands :zephyr_file:`drivers/disk/nvme/nvme_cmd.c` -- NVMe namespace :zephyr_file:`drivers/disk/nvme/nvme_namespace.c` + +- NVMe controller: :zephyr_file:`drivers/disk/nvme/nvme_controller.c` +- NVMe commands: :zephyr_file:`drivers/disk/nvme/nvme_cmd.c` +- NVMe namespace: :zephyr_file:`drivers/disk/nvme/nvme_namespace.c` Where the NVMe controller is the root of the device driver. This is the one that will get device driver instances. Note that this is only what DTS describes: the NVMe controller, and none of its namespaces (disks). diff --git a/doc/zephyr.doxyfile.in b/doc/zephyr.doxyfile.in index 7ba2abe0cc5..268f2337802 100644 --- a/doc/zephyr.doxyfile.in +++ b/doc/zephyr.doxyfile.in @@ -2408,7 +2408,11 @@ PREDEFINED = __DOXYGEN__ \ __syscall= \ __syscall_always_inline= \ __must_check= \ - "ATOMIC_DEFINE(x, y)=atomic_t x[ATOMIC_BITMAP_SIZE(y)]" + "ATOMIC_DEFINE(x, y)=atomic_t x[ATOMIC_BITMAP_SIZE(y)]" \ + "ZTEST(suite, fn)=void fn(void)" \ + "ZTEST_USER(suite, fn)=void fn(void)" \ + "ZTEST_USER_F(suite, fn)=void fn(void)" \ + "ZTEST_F(suite, fn)=void fn(void)" # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this # tag can be used to specify a list of macro names that should be expanded. The diff --git a/drivers/adc/CMakeLists.txt b/drivers/adc/CMakeLists.txt index ae0ebcb5b54..cd4006bccd7 100644 --- a/drivers/adc/CMakeLists.txt +++ b/drivers/adc/CMakeLists.txt @@ -50,3 +50,4 @@ zephyr_library_sources_ifdef(CONFIG_ADC_AD559X adc_ad559x.c) zephyr_library_sources_ifdef(CONFIG_ADC_LTC2451 adc_ltc2451.c) zephyr_library_sources_ifdef(CONFIG_ADC_NUMAKER adc_numaker.c) zephyr_library_sources_ifdef(CONFIG_ADC_ENE_KB1200 adc_ene_kb1200.c) +zephyr_library_sources_ifdef(CONFIG_ADC_MCUX_GAU adc_mcux_gau_adc.c) diff --git a/drivers/adc/Kconfig.ad559x b/drivers/adc/Kconfig.ad559x index 7c5f65bb745..70cb0474a02 100644 --- a/drivers/adc/Kconfig.ad559x +++ b/drivers/adc/Kconfig.ad559x @@ -1,5 +1,5 @@ # Copyright (c) 2023 Grinn -# SPDX -License-Identifier: Apache-2.0 +# SPDX-License-Identifier: Apache-2.0 config ADC_AD559X bool "AD559x ADC driver" diff --git a/drivers/adc/Kconfig.mcux b/drivers/adc/Kconfig.mcux index 725ec32c2c8..a61e7068e88 100644 --- a/drivers/adc/Kconfig.mcux +++ b/drivers/adc/Kconfig.mcux @@ -41,6 +41,14 @@ config ADC_MCUX_ETC help Enable the MCUX ADC ETC driver. +config ADC_MCUX_GAU + bool "MCUX GAU ADC driver" + default y + depends on DT_HAS_NXP_GAU_ADC_ENABLED + select ADC_CONFIGURABLE_INPUTS + help + Enable the GAU ADC driver + if ADC_MCUX_ADC16 choice diff --git a/drivers/adc/adc_ad559x.c b/drivers/adc/adc_ad559x.c index 43db99ac408..21ee1e62e18 100644 --- a/drivers/adc/adc_ad559x.c +++ b/drivers/adc/adc_ad559x.c @@ -21,6 +21,11 @@ LOG_MODULE_REGISTER(adc_ad559x, CONFIG_ADC_LOG_LEVEL); #define AD559X_ADC_RD_POINTER 0x40 #define AD559X_ADC_RESOLUTION 12U +#define AD559X_ADC_VREF_MV 2500U + +#define AD559X_ADC_RES_IND_BIT BIT(15) +#define AD559X_ADC_RES_CHAN_MASK GENMASK(14, 12) +#define AD559X_ADC_RES_VAL_MASK GENMASK(11, 0) struct adc_ad559x_config { const struct device *mfd_dev; @@ -102,6 +107,7 @@ static int adc_ad559x_read_channel(const struct device *dev, uint8_t channel, ui { const struct adc_ad559x_config *config = dev->config; uint16_t val; + uint8_t conv_channel; int ret; /* Select channel */ @@ -141,11 +147,27 @@ static int adc_ad559x_read_channel(const struct device *dev, uint8_t channel, ui } val = sys_be16_to_cpu(val); - if (channel >= 1) { - val -= channel * BIT(AD559X_ADC_RESOLUTION); + + /* + * Invalid data: + * See "ADC section" in "Theory of operation" chapter. + * Valid ADC result has MSB bit set to 0. + */ + if ((val & AD559X_ADC_RES_IND_BIT) != 0) { + return -EAGAIN; + } + + /* + * Invalid channel converted: + * See "ADC section" in "Theory of operation" chapter. + * Conversion result contains channel number which should match requested channel. + */ + conv_channel = FIELD_GET(AD559X_ADC_RES_CHAN_MASK, val); + if (conv_channel != channel) { + return -EIO; } - *result = val; + *result = val & AD559X_ADC_RES_VAL_MASK; } return 0; @@ -241,9 +263,11 @@ static int adc_ad559x_init(const struct device *dev) (k_thread_entry_t)adc_ad559x_acquisition_thread, data, NULL, NULL, CONFIG_ADC_AD559X_ACQUISITION_THREAD_PRIO, 0, K_NO_WAIT); - ret = k_thread_name_set(tid, "adc_ad559x"); - if (ret < 0) { - return ret; + if (IS_ENABLED(CONFIG_THREAD_NAME)) { + ret = k_thread_name_set(tid, "adc_ad559x"); + if (ret < 0) { + return ret; + } } adc_context_unlock_unconditionally(&data->ctx); @@ -257,6 +281,7 @@ static const struct adc_driver_api adc_ad559x_api = { #ifdef CONFIG_ADC_ASYNC .read_async = adc_ad559x_read_async, #endif + .ref_internal = AD559X_ADC_VREF_MV, }; #define ADC_AD559X_DEFINE(inst) \ diff --git a/drivers/adc/adc_ene_kb1200.c b/drivers/adc/adc_ene_kb1200.c index 27d903abd2b..51b0eb93bbb 100644 --- a/drivers/adc/adc_ene_kb1200.c +++ b/drivers/adc/adc_ene_kb1200.c @@ -67,7 +67,7 @@ static int adc_kb1200_start_read(const struct device *dev, const struct adc_sequ { const struct adc_kb1200_config *config = dev->config; struct adc_kb1200_data *data = dev->data; - int error; + int error = 0; if (!sequence->channels || (sequence->channels & ~BIT_MASK(ADC_MAX_CHAN))) { printk("Invalid ADC channels.\n"); diff --git a/drivers/adc/adc_mcux_gau_adc.c b/drivers/adc/adc_mcux_gau_adc.c new file mode 100644 index 00000000000..137c33feeaf --- /dev/null +++ b/drivers/adc/adc_mcux_gau_adc.c @@ -0,0 +1,392 @@ +/* + * Copyright 2022-2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nxp_gau_adc + +#include +#include +#include +#include + +LOG_MODULE_REGISTER(adc_mcux_gau_adc, CONFIG_ADC_LOG_LEVEL); + +#define ADC_CONTEXT_USES_KERNEL_TIMER +#include "adc_context.h" + +#include + +#define NUM_ADC_CHANNELS 16 + +struct mcux_gau_adc_config { + ADC_Type *base; + void (*irq_config_func)(const struct device *dev); + adc_clock_divider_t clock_div; + adc_analog_portion_power_mode_t power_mode; + bool input_gain_buffer; + adc_calibration_ref_t cal_volt; +}; + +struct mcux_gau_adc_data { + const struct device *dev; + struct adc_context ctx; + adc_channel_source_t channel_sources[NUM_ADC_CHANNELS]; + uint8_t scan_length; + uint16_t *results; + size_t results_length; + uint16_t *repeat; + struct k_work read_samples_work; +}; + +static int mcux_gau_adc_channel_setup(const struct device *dev, + const struct adc_channel_cfg *channel_cfg) +{ + const struct mcux_gau_adc_config *config = dev->config; + struct mcux_gau_adc_data *data = dev->data; + ADC_Type *base = config->base; + uint8_t channel_id = channel_cfg->channel_id; + uint8_t source_channel = channel_cfg->input_positive; + uint32_t tmp_reg; + + if (channel_cfg->differential) { + LOG_ERR("Differential channels not yet supported"); + return -ENOTSUP; + } + + if (channel_id >= NUM_ADC_CHANNELS) { + LOG_ERR("ADC does not support more than %d channels", NUM_ADC_CHANNELS); + return -ENOTSUP; + } + + if (source_channel > 12 && source_channel != 15) { + LOG_ERR("Invalid source channel"); + return -EINVAL; + } + + /* Set Acquisition/Warmup time */ + tmp_reg = base->ADC_REG_INTERVAL; + base->ADC_REG_INTERVAL &= ~ADC_ADC_REG_INTERVAL_WARMUP_TIME_MASK; + base->ADC_REG_INTERVAL &= ~ADC_ADC_REG_INTERVAL_BYPASS_WARMUP_MASK; + if (channel_cfg->acquisition_time == 0) { + base->ADC_REG_INTERVAL |= ADC_ADC_REG_INTERVAL_BYPASS_WARMUP_MASK; + } else if (channel_cfg->acquisition_time <= 32) { + base->ADC_REG_INTERVAL |= + ADC_ADC_REG_INTERVAL_WARMUP_TIME(channel_cfg->acquisition_time - 1); + } else { + LOG_ERR("Invalid acquisition time requested of ADC"); + return -EINVAL; + } + /* If user changed the warmup time, warn */ + if (base->ADC_REG_INTERVAL != tmp_reg) { + LOG_WRN("Acquisition/Warmup time is global to entire ADC peripheral, " + "i.e. channel_setup will override this property for all previous channels."); + } + + /* Set Input Gain */ + tmp_reg = base->ADC_REG_ANA; + base->ADC_REG_ANA &= ~ADC_ADC_REG_ANA_INBUF_GAIN_MASK; + if (channel_cfg->gain == ADC_GAIN_1) { + base->ADC_REG_ANA |= ADC_ADC_REG_ANA_INBUF_GAIN(kADC_InputGain1); + } else if (channel_cfg->gain == ADC_GAIN_1_2) { + base->ADC_REG_ANA |= ADC_ADC_REG_ANA_INBUF_GAIN(kADC_InputGain0P5); + } else if (channel_cfg->gain == ADC_GAIN_2) { + base->ADC_REG_ANA |= ADC_ADC_REG_ANA_INBUF_GAIN(kADC_InputGain2); + } else { + LOG_ERR("Invalid gain"); + return -EINVAL; + } + /* If user changed the gain, warn */ + if (base->ADC_REG_ANA != tmp_reg) { + LOG_WRN("Input gain is global to entire ADC peripheral, " + "i.e. channel_setup will override this property for all previous channels."); + } + + /* Set Reference voltage of ADC */ + tmp_reg = base->ADC_REG_ANA; + base->ADC_REG_ANA &= ~ADC_ADC_REG_ANA_VREF_SEL_MASK; + if (channel_cfg->reference == ADC_REF_INTERNAL) { + base->ADC_REG_ANA |= ADC_ADC_REG_ANA_VREF_SEL(kADC_Vref1P2V); + } else if (channel_cfg->reference == ADC_REF_EXTERNAL0) { + base->ADC_REG_ANA |= ADC_ADC_REG_ANA_VREF_SEL(kADC_VrefExternal); + } else if (channel_cfg->reference == ADC_REF_VDD_1) { + base->ADC_REG_ANA |= ADC_ADC_REG_ANA_VREF_SEL(kADC_Vref1P8V); + } else { + LOG_ERR("Vref not supported"); + return -ENOTSUP; + } + /* if user changed the reference voltage, warn */ + if (base->ADC_REG_ANA != tmp_reg) { + LOG_WRN("Reference voltage is global to entire ADC peripheral, " + "i.e. channel_setup will override this property for all previous channels."); + } + + data->channel_sources[channel_id] = source_channel; + + return 0; +} + +static void mcux_gau_adc_read_samples(struct k_work *work) +{ + struct mcux_gau_adc_data *data = + CONTAINER_OF(work, struct mcux_gau_adc_data, + read_samples_work); + const struct device *dev = data->dev; + const struct mcux_gau_adc_config *config = dev->config; + ADC_Type *base = config->base; + + /* using this variable to prevent buffer overflow */ + size_t length = data->results_length; + + while ((ADC_GetFifoDataCount(base) > 0) && (--length > 0)) { + *(data->results++) = (uint16_t)ADC_GetConversionResult(base); + } + + adc_context_on_sampling_done(&data->ctx, dev); +} + + +static void mcux_gau_adc_isr(const struct device *dev) +{ + const struct mcux_gau_adc_config *config = dev->config; + struct mcux_gau_adc_data *data = dev->data; + ADC_Type *base = config->base; + + if (ADC_GetStatusFlags(base) & kADC_DataReadyInterruptFlag) { + /* Clear flag to avoid infinite interrupt */ + ADC_ClearStatusFlags(base, kADC_DataReadyInterruptFlag); + + /* offload and do not block during irq */ + k_work_submit(&data->read_samples_work); + } else { + LOG_ERR("ADC received unimplemented interrupt"); + } +} + +static void adc_context_start_sampling(struct adc_context *ctx) +{ + struct mcux_gau_adc_data *data = + CONTAINER_OF(ctx, struct mcux_gau_adc_data, ctx); + const struct mcux_gau_adc_config *config = data->dev->config; + ADC_Type *base = config->base; + + ADC_StopConversion(base); + ADC_DoSoftwareTrigger(base); +} + +static void adc_context_update_buffer_pointer(struct adc_context *ctx, + bool repeat_sampling) +{ + struct mcux_gau_adc_data *data = + CONTAINER_OF(ctx, struct mcux_gau_adc_data, ctx); + + if (repeat_sampling) { + data->results = data->repeat; + } +} + +static int mcux_gau_adc_do_read(const struct device *dev, + const struct adc_sequence *sequence) +{ + const struct mcux_gau_adc_config *config = dev->config; + ADC_Type *base = config->base; + struct mcux_gau_adc_data *data = dev->data; + uint8_t num_channels = 0; + + /* if user selected channel >= NUM_ADC_CHANNELS that is invalid */ + if (sequence->channels & (0xFFFF << NUM_ADC_CHANNELS)) { + LOG_ERR("Invalid channels selected for sequence"); + return -EINVAL; + } + + /* Count channels */ + for (int i = 0; i < NUM_ADC_CHANNELS; i++) { + num_channels += ((sequence->channels & (0x1 << i)) ? 1 : 0); + } + + /* Buffer must hold (number of samples per channel) * (number of channels) samples */ + if ((sequence->options != NULL && sequence->buffer_size < + ((1 + sequence->options->extra_samplings) * num_channels)) || + (sequence->options == NULL && sequence->buffer_size < num_channels)) { + LOG_ERR("Buffer size too small"); + return -ENOMEM; + } + + /* Set scan length in data struct for isr to understand & set scan length register */ + base->ADC_REG_CONFIG &= ~ADC_ADC_REG_CONFIG_SCAN_LENGTH_MASK; + data->scan_length = num_channels; + /* Register Value is 1 less than what it represents */ + base->ADC_REG_CONFIG |= ADC_ADC_REG_CONFIG_SCAN_LENGTH(data->scan_length - 1); + + /* Set up scan channels */ + for (int channel = 0; channel < NUM_ADC_CHANNELS; channel++) { + if (sequence->channels & (0x1 << channel)) { + ADC_SetScanChannel(base, + data->scan_length - num_channels--, + data->channel_sources[channel]); + } + } + + /* Set resolution of ADC */ + base->ADC_REG_ANA &= ~ADC_ADC_REG_ANA_RES_SEL_MASK; + /* odd numbers are for differential channels */ + if (sequence->resolution == 12 || sequence->resolution == 11) { + base->ADC_REG_ANA |= ADC_ADC_REG_ANA_RES_SEL(kADC_Resolution12Bit); + } else if (sequence->resolution == 14 || sequence->resolution == 13) { + base->ADC_REG_ANA |= ADC_ADC_REG_ANA_RES_SEL(kADC_Resolution14Bit); + } else if (sequence->resolution == 16 || sequence->resolution == 15) { + base->ADC_REG_ANA |= ADC_ADC_REG_ANA_RES_SEL(kADC_Resolution16Bit); + } else { + LOG_ERR("Invalid resolution"); + return -EINVAL; + } + + /* Set oversampling */ + base->ADC_REG_CONFIG &= ~ADC_ADC_REG_CONFIG_AVG_SEL_MASK; + if (sequence->oversampling == 0) { + base->ADC_REG_CONFIG |= ADC_ADC_REG_CONFIG_AVG_SEL(kADC_AverageNone); + } else if (sequence->oversampling == 1) { + base->ADC_REG_CONFIG |= ADC_ADC_REG_CONFIG_AVG_SEL(kADC_Average2); + } else if (sequence->oversampling == 2) { + base->ADC_REG_CONFIG |= ADC_ADC_REG_CONFIG_AVG_SEL(kADC_Average4); + } else if (sequence->oversampling == 3) { + base->ADC_REG_CONFIG |= ADC_ADC_REG_CONFIG_AVG_SEL(kADC_Average8); + } else if (sequence->oversampling == 4) { + base->ADC_REG_CONFIG |= ADC_ADC_REG_CONFIG_AVG_SEL(kADC_Average16); + } else { + LOG_ERR("Invalid oversampling setting"); + return -EINVAL; + } + + /* Calibrate if requested */ + if (sequence->calibrate) { + if (ADC_DoAutoCalibration(base, config->cal_volt)) { + LOG_WRN("Calibration of ADC failed!"); + } + } + + data->results = sequence->buffer; + data->results_length = sequence->buffer_size; + data->repeat = sequence->buffer; + + adc_context_start_read(&data->ctx, sequence); + + return adc_context_wait_for_completion(&data->ctx); +} + +static int mcux_gau_adc_read(const struct device *dev, + const struct adc_sequence *sequence) +{ + struct mcux_gau_adc_data *data = dev->data; + int error; + + adc_context_lock(&data->ctx, false, NULL); + error = mcux_gau_adc_do_read(dev, sequence); + adc_context_release(&data->ctx, error); + return error; +} + +#ifdef CONFIG_ADC_ASYNC +static int mcux_gau_adc_read_async(const struct device *dev, + const struct adc_sequence *sequence, + struct k_poll_signal *async) +{ + struct mcux_gau_adc_data *data = dev->data; + int error; + + adc_context_lock(&data->ctx, true, async); + error = mcux_gau_adc_do_read(dev, sequence); + adc_context_release(&data->ctx, error); + return error; +} +#endif + + +static int mcux_gau_adc_init(const struct device *dev) +{ + const struct mcux_gau_adc_config *config = dev->config; + struct mcux_gau_adc_data *data = dev->data; + ADC_Type *base = config->base; + adc_config_t adc_config; + + data->dev = dev; + + LOG_DBG("Initializing ADC"); + + ADC_GetDefaultConfig(&adc_config); + + /* DT configs */ + adc_config.clockDivider = config->clock_div; + adc_config.powerMode = config->power_mode; + adc_config.enableInputGainBuffer = config->input_gain_buffer; + adc_config.triggerSource = kADC_TriggerSourceSoftware; + + adc_config.inputMode = kADC_InputSingleEnded; + /* One shot meets the needs of the current zephyr adc context/api */ + adc_config.conversionMode = kADC_ConversionOneShot; + /* since using one shot mode, just interrupt on one sample (agnostic to # channels) */ + adc_config.fifoThreshold = kADC_FifoThresholdData1; + /* 32 bit width not supported in this driver; zephyr seems to use 16 bit */ + adc_config.resultWidth = kADC_ResultWidth16; + adc_config.enableDMA = false; + adc_config.enableADC = true; + + ADC_Init(base, &adc_config); + + if (ADC_DoAutoCalibration(base, config->cal_volt)) { + LOG_WRN("Calibration of ADC failed!"); + } + + ADC_ClearStatusFlags(base, kADC_DataReadyInterruptFlag); + + config->irq_config_func(dev); + ADC_EnableInterrupts(base, kADC_DataReadyInterruptEnable); + + k_work_init(&data->read_samples_work, &mcux_gau_adc_read_samples); + + adc_context_init(&data->ctx); + adc_context_unlock_unconditionally(&data->ctx); + + return 0; +} + +static const struct adc_driver_api mcux_gau_adc_driver_api = { + .channel_setup = mcux_gau_adc_channel_setup, + .read = mcux_gau_adc_read, +#ifdef CONFIG_ADC_ASYNC + .read_async = mcux_gau_adc_read_async, +#endif + .ref_internal = 1200, +}; + + +#define GAU_ADC_MCUX_INIT(n) \ + \ + static void mcux_gau_adc_config_func_##n(const struct device *dev); \ + \ + static const struct mcux_gau_adc_config mcux_gau_adc_config_##n = { \ + .base = (ADC_Type *)DT_INST_REG_ADDR(n), \ + .irq_config_func = mcux_gau_adc_config_func_##n, \ + /* Minus one because DT starts at 1, HAL enum starts at 0 */ \ + .clock_div = DT_INST_PROP(n, nxp_clock_divider) - 1, \ + .power_mode = DT_INST_ENUM_IDX(n, nxp_power_mode), \ + .input_gain_buffer = DT_INST_PROP(n, nxp_input_buffer), \ + .cal_volt = DT_INST_ENUM_IDX(n, nxp_calibration_voltage), \ + }; \ + \ + static struct mcux_gau_adc_data mcux_gau_adc_data_##n = {0}; \ + \ + DEVICE_DT_INST_DEFINE(n, &mcux_gau_adc_init, NULL, \ + &mcux_gau_adc_data_##n, &mcux_gau_adc_config_##n, \ + POST_KERNEL, CONFIG_ADC_INIT_PRIORITY, \ + &mcux_gau_adc_driver_api); \ + \ + static void mcux_gau_adc_config_func_##n(const struct device *dev) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), \ + mcux_gau_adc_isr, DEVICE_DT_INST_GET(n), 0); \ + irq_enable(DT_INST_IRQN(n)); \ + } + +DT_INST_FOREACH_STATUS_OKAY(GAU_ADC_MCUX_INIT) diff --git a/drivers/adc/adc_mcux_lpadc.c b/drivers/adc/adc_mcux_lpadc.c index b15790ccb9d..02c6e7ac648 100644 --- a/drivers/adc/adc_mcux_lpadc.c +++ b/drivers/adc/adc_mcux_lpadc.c @@ -1,5 +1,5 @@ /* - * Copyright 2023 NXP + * Copyright 2023-2024 NXP * Copyright (c) 2020 Toby Firth * * Based on adc_mcux_adc16.c and adc_mcux_adc12.c, which are: @@ -14,14 +14,14 @@ #include #include #include -#include #include - +#include #include #define LOG_LEVEL CONFIG_ADC_LOG_LEVEL #include #include +#include LOG_MODULE_REGISTER(nxp_mcux_lpadc); /* @@ -35,7 +35,6 @@ LOG_MODULE_REGISTER(nxp_mcux_lpadc); #define ADC_CONTEXT_USES_KERNEL_TIMER #include "adc_context.h" - struct mcux_lpadc_config { ADC_Type *base; lpadc_reference_voltage_source_t voltage_ref; @@ -46,6 +45,8 @@ struct mcux_lpadc_config { void (*irq_config_func)(const struct device *dev); const struct pinctrl_dev_config *pincfg; const struct device **ref_supplies; + const struct device *clock_dev; + clock_control_subsys_t clock_subsys; }; struct mcux_lpadc_data { @@ -57,17 +58,79 @@ struct mcux_lpadc_data { lpadc_conv_command_config_t cmd_config[CONFIG_LPADC_CHANNEL_COUNT]; }; +static int mcux_lpadc_acquisition_time_setup(const struct device *dev, uint16_t acq_time, + lpadc_conv_command_config_t *cmd) +{ + const struct mcux_lpadc_config *config = dev->config; + uint32_t adc_freq_hz = 0; + uint32_t conversion_factor = 0; + uint32_t acquisition_time_value = ADC_ACQ_TIME_VALUE(acq_time); + uint8_t acquisition_time_unit = ADC_ACQ_TIME_UNIT(acq_time); + + if (ADC_ACQ_TIME_DEFAULT == acquisition_time_value) { + return 0; + } + + /* If the acquisition time is expressed in ADC ticks, then directly compare + * the acquisition time with configuration items (3, 5, 7, etc. ADC ticks) + * supported by the LPADC. The conversion factor is set to 1 (means do not need + * to convert configuration items from ADC ticks to nanoseconds). + * If the acquisition time is expressed in microseconds or nanoseconds, First + * calculate the ADC cycle based on the ADC clock, then convert the configuration + * items supported by LPADC into nanoseconds, and finally compare the acquisition + * time with configuration items. The conversion factor is equal to the ADC cycle + * (means convert configuration items from ADC ticks to nanoseconds). + */ + if (ADC_ACQ_TIME_TICKS == acquisition_time_unit) { + conversion_factor = 1; + } else { + if (clock_control_get_rate(config->clock_dev, config->clock_subsys, &adc_freq_hz)) { + LOG_ERR("Get clock rate failed"); + return -EINVAL; + } + + conversion_factor = 1000000000 / adc_freq_hz; + + if (ADC_ACQ_TIME_MICROSECONDS == acquisition_time_unit) { + acquisition_time_value *= 1000; + } + } + if ((3 * conversion_factor) >= acquisition_time_value) { + cmd->sampleTimeMode = kLPADC_SampleTimeADCK3; + } else if ((5 * conversion_factor) >= acquisition_time_value) { + cmd->sampleTimeMode = kLPADC_SampleTimeADCK5; + } else if ((7 * conversion_factor) >= acquisition_time_value) { + cmd->sampleTimeMode = kLPADC_SampleTimeADCK7; + } else if ((11 * conversion_factor) >= acquisition_time_value) { + cmd->sampleTimeMode = kLPADC_SampleTimeADCK11; + } else if ((19 * conversion_factor) >= acquisition_time_value) { + cmd->sampleTimeMode = kLPADC_SampleTimeADCK19; + } else if ((35 * conversion_factor) >= acquisition_time_value) { + cmd->sampleTimeMode = kLPADC_SampleTimeADCK35; + } else if ((67 * conversion_factor) >= acquisition_time_value) { + cmd->sampleTimeMode = kLPADC_SampleTimeADCK67; + } else if ((131 * conversion_factor) >= acquisition_time_value) { + cmd->sampleTimeMode = kLPADC_SampleTimeADCK131; + } else { + return -EINVAL; + } + + return 0; +} static int mcux_lpadc_channel_setup(const struct device *dev, const struct adc_channel_cfg *channel_cfg) { - - + const struct mcux_lpadc_config *config = dev->config; + const struct device **regulator = config->ref_supplies; + uint16_t vref_mv = CONTAINER_OF(channel_cfg, struct adc_dt_spec, channel_cfg)->vref_mv; + int32_t vref_uv = (int32_t)((uint32_t)vref_mv * 1000); struct mcux_lpadc_data *data = dev->data; lpadc_conv_command_config_t *cmd; uint8_t channel_side; uint8_t channel_num; + int err; /* User may configure maximum number of active channels */ if (channel_cfg->channel_id >= CONFIG_LPADC_CHANNEL_COUNT) { @@ -75,11 +138,6 @@ static int mcux_lpadc_channel_setup(const struct device *dev, return -EINVAL; } - if (channel_cfg->acquisition_time != ADC_ACQ_TIME_DEFAULT) { - LOG_ERR("Invalid channel acquisition time"); - return -EINVAL; - } - /* Select ADC CMD register to configure based off channel ID */ cmd = &data->cmd_config[channel_cfg->channel_id]; @@ -93,6 +151,12 @@ static int mcux_lpadc_channel_setup(const struct device *dev, LPADC_GetDefaultConvCommandConfig(cmd); + /* Configure LPADC acquisition time. */ + if (mcux_lpadc_acquisition_time_setup(dev, channel_cfg->acquisition_time, cmd)) { + LOG_ERR("LPADC acquisition time setting failed"); + return -EINVAL; + } + if (channel_cfg->differential) { /* Channel pairs must match in differential mode */ if ((ADC_CMDL_ADCH(channel_cfg->input_positive)) != @@ -141,8 +205,25 @@ static int mcux_lpadc_channel_setup(const struct device *dev, } #endif - if (channel_cfg->reference != ADC_REF_EXTERNAL0) { - LOG_ERR("Invalid channel reference"); + /* + * ADC_REF_EXTERNAL1: Use SoC internal regulator as LPADC reference voltage. + * ADC_REF_EXTERNAL0: Use other voltage source (maybe also within the SoCs) + * as LPADC reference voltage, like VREFH, VDDA, etc. + */ + if (channel_cfg->reference == ADC_REF_EXTERNAL1) { + LOG_DBG("ref external1"); + if (*regulator != NULL) { + err = regulator_set_voltage(*regulator, vref_uv, vref_uv); + if (err < 0) { + return err; + } + } else { + return -EINVAL; + } + } else if (channel_cfg->reference == ADC_REF_EXTERNAL0) { + LOG_DBG("ref external0"); + } else { + LOG_DBG("ref not support"); return -EINVAL; } @@ -493,6 +574,8 @@ static const struct adc_driver_api mcux_lpadc_driver_api = { .irq_config_func = mcux_lpadc_config_func_##n, \ .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ .ref_supplies = mcux_lpadc_ref_supplies_##n, \ + .clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)), \ + .clock_subsys = (clock_control_subsys_t)DT_INST_CLOCKS_CELL(n, name),\ }; \ static struct mcux_lpadc_data mcux_lpadc_data_##n = { \ ADC_CONTEXT_INIT_TIMER(mcux_lpadc_data_##n, ctx), \ diff --git a/drivers/adc/adc_numaker.c b/drivers/adc/adc_numaker.c index 4fae17f422d..42d3b7ad5dd 100644 --- a/drivers/adc/adc_numaker.c +++ b/drivers/adc/adc_numaker.c @@ -17,6 +17,7 @@ #include #define ADC_CONTEXT_USES_KERNEL_TIMER +#define ADC_CONTEXT_ENABLE_ON_COMPLETE #include "adc_context.h" LOG_MODULE_REGISTER(adc_numaker, CONFIG_ADC_LOG_LEVEL); @@ -45,6 +46,7 @@ struct adc_numaker_data { uint16_t *repeat_buffer; bool is_differential; uint32_t channels; + uint32_t acq_time; }; static int adc_numaker_channel_setup(const struct device *dev, @@ -54,9 +56,13 @@ static int adc_numaker_channel_setup(const struct device *dev, 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 ((ADC_ACQ_TIME_UNIT(chan_cfg->acquisition_time) != ADC_ACQ_TIME_TICKS) || + (ADC_ACQ_TIME_VALUE(chan_cfg->acquisition_time) > 255)) { + LOG_ERR("Selected ADC acquisition time is not in 0~255 ticks"); + return -EINVAL; + } } + data->acq_time = ADC_ACQ_TIME_VALUE(chan_cfg->acquisition_time); if (chan_cfg->gain != ADC_GAIN_1) { LOG_ERR("Not support channel gain"); @@ -115,9 +121,6 @@ static void adc_numaker_isr(const struct device *dev) 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. @@ -151,9 +154,6 @@ static void adc_numaker_isr(const struct device *dev) eadc->SCTL[module_id] = 0; } - /* Disable ADC */ - EADC_Close(eadc); - /* Inform sampling is done */ adc_context_on_sampling_done(&data->ctx, data->dev); } @@ -179,6 +179,8 @@ static void m_adc_numaker_start_scan(const struct device *dev) channel_mask &= ~BIT(channel_id); EADC_ConfigSampleModule(eadc, module_id, EADC_SOFTWARE_TRIGGER, channel_id); + /* Set sample module external sampling time to 0 */ + EADC_SetExtendSampleTime(eadc, module_id, data->acq_time); } /* Clear the A/D ADINT0 interrupt flag for safe */ @@ -221,6 +223,19 @@ static void adc_context_update_buffer_pointer(struct adc_context *ctx, } } +static void adc_context_on_complete(struct adc_context *ctx, int status) +{ + struct adc_numaker_data *data = + CONTAINER_OF(ctx, struct adc_numaker_data, ctx); + const struct adc_numaker_config *cfg = data->dev->config; + EADC_T *eadc = cfg->eadc_base; + + ARG_UNUSED(status); + + /* Disable ADC */ + EADC_Close(eadc); +} + static int m_adc_numaker_start_read(const struct device *dev, const struct adc_sequence *sequence) { @@ -243,14 +258,9 @@ static int m_adc_numaker_start_read(const struct device *dev, /* Enable the A/D converter */ if (data->is_differential) { - err = EADC_Open(eadc, EADC_CTL_DIFFEN_DIFFERENTIAL); + 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; + EADC_Open(eadc, EADC_CTL_DIFFEN_SINGLE_END); } data->buffer = sequence->buffer; diff --git a/drivers/adc/adc_tla2021.c b/drivers/adc/adc_tla2021.c index 8c68c8b81ee..c86e5587816 100644 --- a/drivers/adc/adc_tla2021.c +++ b/drivers/adc/adc_tla2021.c @@ -288,7 +288,7 @@ static int tla2021_init(const struct device *dev) static const struct adc_driver_api tla2021_driver_api = { .channel_setup = tla2021_channel_setup, .read = tla2021_read, - .ref_internal = 2048, + .ref_internal = 4096, #ifdef CONFIG_ADC_ASYNC .read_async = tla2021_read_async, #endif diff --git a/drivers/audio/mpxxdtyy.c b/drivers/audio/mpxxdtyy.c index 4be45e47c67..784dddb4581 100644 --- a/drivers/audio/mpxxdtyy.c +++ b/drivers/audio/mpxxdtyy.c @@ -90,7 +90,8 @@ int sw_filter_lib_run(TPDMFilter_InitStruct *pdm_filter, void *pdm_block, void *pcm_block, size_t pdm_size, size_t pcm_size) { - int i; + int i, j; + int pdm_offset; uint8_t a, b; if (pdm_block == NULL || pcm_block == NULL || pdm_filter == NULL) { @@ -118,25 +119,35 @@ int sw_filter_lib_run(TPDMFilter_InitStruct *pdm_filter, } } - switch (pdm_filter[0].Decimation) { - case 64: - for (i = 0; i < pdm_filter[0].In_MicChannels; i++) { - Open_PDM_Filter_64(&((uint8_t *) pdm_block)[i], - &((uint16_t *) pcm_block)[i], - pdm_filter->MaxVolume, - &pdm_filter[i]); - } - break; - case 128: + for (j = 0; j < pcm_size / 2; j += pdm_filter[0].Fs / 1000) { + /* + * The number of PDM bytes per PCM sample is the decimation factor + * divided by the number of bits per byte (8). We need to skip a number of + * PDM bytes equivalent to the number of PCM samples, times the number of + * channels. + */ + pdm_offset = j * (pdm_filter[0].Decimation / 8) * pdm_filter[0].In_MicChannels; + for (i = 0; i < pdm_filter[0].In_MicChannels; i++) { - Open_PDM_Filter_128(&((uint8_t *) pdm_block)[i], - &((uint16_t *) pcm_block)[i], - pdm_filter->MaxVolume, - &pdm_filter[i]); + switch (pdm_filter[0].Decimation) { + case 64: + Open_PDM_Filter_64(&((uint8_t *) pdm_block)[pdm_offset + i], + &((uint16_t *) pcm_block)[j + i], + pdm_filter->MaxVolume, + &pdm_filter[i]); + break; + + case 128: + Open_PDM_Filter_128(&((uint8_t *) pdm_block)[pdm_offset + i], + &((uint16_t *) pcm_block)[j + i], + pdm_filter->MaxVolume, + &pdm_filter[i]); + break; + + default: + return -EINVAL; + } } - break; - default: - return -EINVAL; } return 0; diff --git a/drivers/bbram/bbram_it8xxx2_emul.c b/drivers/bbram/bbram_it8xxx2_emul.c index 901a09835f1..fea04112c0d 100644 --- a/drivers/bbram/bbram_it8xxx2_emul.c +++ b/drivers/bbram/bbram_it8xxx2_emul.c @@ -45,7 +45,7 @@ static int it8xxx2_emul_backend_get_data(const struct emul *target, size_t offse return 0; } -static const struct emul_bbram_backend_api it8xxx2_emul_backend_api = { +static const struct emul_bbram_driver_api it8xxx2_emul_backend_api = { .set_data = it8xxx2_emul_backend_set_data, .get_data = it8xxx2_emul_backend_get_data, }; diff --git a/drivers/bbram/bbram_microchip_mcp7940n_emul.c b/drivers/bbram/bbram_microchip_mcp7940n_emul.c index 56a84825948..d1206c42a16 100644 --- a/drivers/bbram/bbram_microchip_mcp7940n_emul.c +++ b/drivers/bbram/bbram_microchip_mcp7940n_emul.c @@ -135,7 +135,7 @@ static int mcp7940n_emul_backend_get_data(const struct emul *target, size_t offs return 0; } -static const struct emul_bbram_backend_api mcp7940n_emul_backend_api = { +static const struct emul_bbram_driver_api mcp7940n_emul_backend_api = { .set_data = mcp7940n_emul_backend_set_data, .get_data = mcp7940n_emul_backend_get_data, }; diff --git a/drivers/bbram/bbram_npcx_emul.c b/drivers/bbram/bbram_npcx_emul.c index 799e158eefd..354c7e8bb8f 100644 --- a/drivers/bbram/bbram_npcx_emul.c +++ b/drivers/bbram/bbram_npcx_emul.c @@ -45,7 +45,7 @@ static int npcx_emul_backend_get_data(const struct emul *target, size_t offset, return 0; } -static const struct emul_bbram_backend_api npcx_emul_backend_api = { +static const struct emul_bbram_driver_api npcx_emul_backend_api = { .set_data = npcx_emul_backend_set_data, .get_data = npcx_emul_backend_get_data, }; diff --git a/drivers/bluetooth/hci/CMakeLists.txt b/drivers/bluetooth/hci/CMakeLists.txt index adda6ea0e2a..ab1df047ce1 100644 --- a/drivers/bluetooth/hci/CMakeLists.txt +++ b/drivers/bluetooth/hci/CMakeLists.txt @@ -33,3 +33,4 @@ 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) +zephyr_library_sources_ifdef(CONFIG_BT_DA1469X hci_da1469x.c) diff --git a/drivers/bluetooth/hci/Kconfig b/drivers/bluetooth/hci/Kconfig index ad1d9da2df2..1b4bc9fdb25 100644 --- a/drivers/bluetooth/hci/Kconfig +++ b/drivers/bluetooth/hci/Kconfig @@ -109,6 +109,12 @@ config BT_PSOC6_BLESS PSOC6 BLESS driver with BLE Controller which operates in Single CPU mode. +config BT_DA1469X + bool "DA1469x HCI driver" + help + Bluetooth HCI driver for communication with CMAC core + on DA1469x MCU. + config BT_NO_DRIVER bool "No default HCI driver" select BT_HAS_HCI_VS diff --git a/drivers/bluetooth/hci/cyw43xxx.c b/drivers/bluetooth/hci/cyw43xxx.c index be3299e9218..8da6192610d 100644 --- a/drivers/bluetooth/hci/cyw43xxx.c +++ b/drivers/bluetooth/hci/cyw43xxx.c @@ -19,13 +19,15 @@ #include #include -#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HCI_DRIVER) #define LOG_LEVEL CONFIG_BT_HCI_DRIVER_LOG_LEVEL #include LOG_MODULE_REGISTER(cyw43xxx_driver); #include +BUILD_ASSERT(DT_PROP(DT_CHOSEN(zephyr_bt_uart), hw_flow_control) == 1, + "hw_flow_control must be enabled for HCI H4 UART"); + #define DT_DRV_COMPAT infineon_cyw43xxx_bt_hci /* BT settling time after power on */ diff --git a/drivers/bluetooth/hci/h4.c b/drivers/bluetooth/hci/h4.c index 96a27f19a75..16b28b52586 100644 --- a/drivers/bluetooth/hci/h4.c +++ b/drivers/bluetooth/hci/h4.c @@ -30,13 +30,6 @@ LOG_MODULE_REGISTER(bt_driver); #include "../util.h" -#define H4_NONE 0x00 -#define H4_CMD 0x01 -#define H4_ACL 0x02 -#define H4_SCO 0x03 -#define H4_EVT 0x04 -#define H4_ISO 0x05 - static K_KERNEL_STACK_DEFINE(rx_thread_stack, CONFIG_BT_DRV_RX_STACK_SIZE); static struct k_thread rx_thread_data; @@ -78,20 +71,20 @@ static inline void h4_get_type(void) /* Get packet type */ if (uart_fifo_read(h4_dev, &rx.type, 1) != 1) { LOG_WRN("Unable to read H:4 packet type"); - rx.type = H4_NONE; + rx.type = BT_HCI_H4_NONE; return; } switch (rx.type) { - case H4_EVT: + case BT_HCI_H4_EVT: rx.remaining = sizeof(rx.evt); rx.hdr_len = rx.remaining; break; - case H4_ACL: + case BT_HCI_H4_ACL: rx.remaining = sizeof(rx.acl); rx.hdr_len = rx.remaining; break; - case H4_ISO: + case BT_HCI_H4_ISO: if (IS_ENABLED(CONFIG_BT_ISO)) { rx.remaining = sizeof(rx.iso); rx.hdr_len = rx.remaining; @@ -100,7 +93,7 @@ static inline void h4_get_type(void) __fallthrough; default: LOG_ERR("Unknown H:4 type 0x%02x", rx.type); - rx.type = H4_NONE; + rx.type = BT_HCI_H4_NONE; } } @@ -185,7 +178,7 @@ static inline void copy_hdr(struct net_buf *buf) static void reset_rx(void) { - rx.type = H4_NONE; + rx.type = BT_HCI_H4_NONE; rx.remaining = 0U; rx.have_hdr = false; rx.hdr_len = 0U; @@ -197,11 +190,11 @@ static struct net_buf *get_rx(k_timeout_t timeout) LOG_DBG("type 0x%02x, evt 0x%02x", rx.type, rx.evt.evt); switch (rx.type) { - case H4_EVT: + case BT_HCI_H4_EVT: return bt_buf_get_evt(rx.evt.evt, rx.discardable, timeout); - case H4_ACL: + case BT_HCI_H4_ACL: return bt_buf_get_rx(BT_BUF_ACL_IN, timeout); - case H4_ISO: + case BT_HCI_H4_ISO: if (IS_ENABLED(CONFIG_BT_ISO)) { return bt_buf_get_rx(BT_BUF_ISO_IN, timeout); } @@ -329,7 +322,7 @@ static inline void read_payload(void) buf = rx.buf; rx.buf = NULL; - if (rx.type == H4_EVT) { + if (rx.type == BT_HCI_H4_EVT) { bt_buf_set_type(buf, BT_BUF_EVT); } else { bt_buf_set_type(buf, BT_BUF_ACL_IN); @@ -344,16 +337,16 @@ static inline void read_payload(void) static inline void read_header(void) { switch (rx.type) { - case H4_NONE: + case BT_HCI_H4_NONE: h4_get_type(); return; - case H4_EVT: + case BT_HCI_H4_EVT: get_evt_hdr(); break; - case H4_ACL: + case BT_HCI_H4_ACL: get_acl_hdr(); break; - case H4_ISO: + case BT_HCI_H4_ISO: if (IS_ENABLED(CONFIG_BT_ISO)) { get_iso_hdr(); break; @@ -391,14 +384,14 @@ static inline void process_tx(void) if (!tx.type) { switch (bt_buf_get_type(tx.buf)) { case BT_BUF_ACL_OUT: - tx.type = H4_ACL; + tx.type = BT_HCI_H4_ACL; break; case BT_BUF_CMD: - tx.type = H4_CMD; + tx.type = BT_HCI_H4_CMD; break; case BT_BUF_ISO_OUT: if (IS_ENABLED(CONFIG_BT_ISO)) { - tx.type = H4_ISO; + tx.type = BT_HCI_H4_ISO; break; } __fallthrough; @@ -410,7 +403,7 @@ static inline void process_tx(void) bytes = uart_fifo_fill(h4_dev, &tx.type, 1); if (bytes != 1) { LOG_WRN("Unable to send H:4 type"); - tx.type = H4_NONE; + tx.type = BT_HCI_H4_NONE; return; } } @@ -427,7 +420,7 @@ static inline void process_tx(void) } done: - tx.type = H4_NONE; + tx.type = BT_HCI_H4_NONE; net_buf_unref(tx.buf); tx.buf = net_buf_get(&tx.fifo, K_NO_WAIT); if (!tx.buf) { diff --git a/drivers/bluetooth/hci/hci_ambiq.c b/drivers/bluetooth/hci/hci_ambiq.c index b0c6ee43337..ec3a0b944fe 100644 --- a/drivers/bluetooth/hci/hci_ambiq.c +++ b/drivers/bluetooth/hci/hci_ambiq.c @@ -25,11 +25,6 @@ LOG_MODULE_REGISTER(bt_hci_driver); #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 @@ -272,11 +267,11 @@ static void bt_spi_rx_thread(void *p1, void *p2, void *p3) } switch (rxmsg[PACKET_TYPE]) { - case HCI_EVT: + case BT_HCI_H4_EVT: buf = bt_hci_evt_recv(&rxmsg[PACKET_TYPE + PACKET_TYPE_SIZE], (len - PACKET_TYPE_SIZE)); break; - case HCI_ACL: + case BT_HCI_H4_ACL: buf = bt_hci_acl_recv(&rxmsg[PACKET_TYPE + PACKET_TYPE_SIZE], (len - PACKET_TYPE_SIZE)); break; @@ -306,10 +301,10 @@ static int bt_hci_send(struct net_buf *buf) switch (bt_buf_get_type(buf)) { case BT_BUF_ACL_OUT: - net_buf_push_u8(buf, HCI_ACL); + net_buf_push_u8(buf, BT_HCI_H4_ACL); break; case BT_BUF_CMD: - net_buf_push_u8(buf, HCI_CMD); + net_buf_push_u8(buf, BT_HCI_H4_CMD); break; default: LOG_ERR("Unsupported type"); diff --git a/drivers/bluetooth/hci/hci_b91.c b/drivers/bluetooth/hci/hci_b91.c index 61f4ffc2f6c..9909718e94b 100644 --- a/drivers/bluetooth/hci/hci_b91.c +++ b/drivers/bluetooth/hci/hci_b91.c @@ -15,10 +15,6 @@ #include LOG_MODULE_REGISTER(bt_hci_driver_b91); -#define HCI_CMD 0x01 -#define HCI_ACL 0x02 -#define HCI_EVT 0x04 - #define HCI_BT_B91_TIMEOUT K_MSEC(2000) static K_SEM_DEFINE(hci_send_sem, 1, 1); @@ -148,11 +144,11 @@ static void hci_b91_host_rcv_pkt(uint8_t *data, uint16_t len) len -= sizeof(pkt_indicator); switch (pkt_indicator) { - case HCI_EVT: + case BT_HCI_H4_EVT: buf = bt_b91_evt_recv(data, len); break; - case HCI_ACL: + case BT_HCI_H4_ACL: buf = bt_b91_acl_recv(data, len); break; @@ -186,11 +182,11 @@ static int bt_b91_send(struct net_buf *buf) switch (bt_buf_get_type(buf)) { case BT_BUF_ACL_OUT: - type = HCI_ACL; + type = BT_HCI_H4_ACL; break; case BT_BUF_CMD: - type = HCI_CMD; + type = BT_HCI_H4_CMD; break; default: diff --git a/drivers/bluetooth/hci/hci_da1469x.c b/drivers/bluetooth/hci/hci_da1469x.c new file mode 100644 index 00000000000..8935244472a --- /dev/null +++ b/drivers/bluetooth/hci/hci_da1469x.c @@ -0,0 +1,489 @@ +/* hci_da1469x.c - DA1469x CMAC IPC Bluetooth driver */ + +/* + * Copyright (c) 2023 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#define LOG_LEVEL CONFIG_BT_HCI_DRIVER_LOG_LEVEL +#include + +LOG_MODULE_REGISTER(hci_da1469x); + +static K_KERNEL_STACK_DEFINE(rng_thread_stack, CONFIG_BT_RX_STACK_SIZE); +static struct k_thread rng_thread_data; +struct k_sem rng_sem; + +static K_KERNEL_STACK_DEFINE(rx_thread_stack, CONFIG_BT_RX_STACK_SIZE); +static struct k_thread rx_thread_data; + +static struct { + struct net_buf *buf; + struct k_fifo fifo; + + uint16_t remaining; + uint16_t discard; + + bool have_hdr; + bool discardable; + + uint8_t hdr_len; + + uint8_t type; + union { + struct bt_hci_evt_hdr evt; + struct bt_hci_acl_hdr acl; + struct bt_hci_iso_hdr iso; + uint8_t hdr[4]; + }; +} rx = { + .fifo = Z_FIFO_INITIALIZER(rx.fifo), +}; + +static void h4_get_type(void) +{ + /* Get packet type */ + if (cmac_mbox_read(&rx.type, 1) != 1) { + LOG_WRN("Unable to read H:4 packet type"); + rx.type = BT_HCI_H4_NONE; + return; + } + + switch (rx.type) { + case BT_HCI_H4_EVT: + rx.remaining = sizeof(rx.evt); + rx.hdr_len = rx.remaining; + break; + case BT_HCI_H4_ACL: + rx.remaining = sizeof(rx.acl); + rx.hdr_len = rx.remaining; + break; + case BT_HCI_H4_ISO: + if (IS_ENABLED(CONFIG_BT_ISO)) { + rx.remaining = sizeof(rx.iso); + rx.hdr_len = rx.remaining; + break; + } + __fallthrough; + default: + LOG_ERR("Unknown H:4 type 0x%02x", rx.type); + rx.type = BT_HCI_H4_NONE; + } +} + +static void h4_read_hdr(void) +{ + int bytes_read = rx.hdr_len - rx.remaining; + int ret; + + ret = cmac_mbox_read(rx.hdr + bytes_read, rx.remaining); + if (unlikely(ret < 0)) { + LOG_ERR("Unable to read from mailbox (ret %d)", ret); + } else { + rx.remaining -= ret; + } +} + +static inline void get_acl_hdr(void) +{ + h4_read_hdr(); + + if (!rx.remaining) { + struct bt_hci_acl_hdr *hdr = &rx.acl; + + rx.remaining = sys_le16_to_cpu(hdr->len); + LOG_DBG("Got ACL header. Payload %u bytes", rx.remaining); + rx.have_hdr = true; + } +} + +static inline void get_iso_hdr(void) +{ + h4_read_hdr(); + + if (!rx.remaining) { + struct bt_hci_iso_hdr *hdr = &rx.iso; + + rx.remaining = bt_iso_hdr_len(sys_le16_to_cpu(hdr->len)); + LOG_DBG("Got ISO header. Payload %u bytes", rx.remaining); + rx.have_hdr = true; + } +} + +static inline void get_evt_hdr(void) +{ + struct bt_hci_evt_hdr *hdr = &rx.evt; + + h4_read_hdr(); + + if (rx.hdr_len == sizeof(*hdr) && rx.remaining < sizeof(*hdr)) { + switch (rx.evt.evt) { + case BT_HCI_EVT_LE_META_EVENT: + rx.remaining++; + rx.hdr_len++; + break; + } + } + + if (!rx.remaining) { + if (rx.evt.evt == BT_HCI_EVT_LE_META_EVENT && + (rx.hdr[sizeof(*hdr)] == BT_HCI_EVT_LE_ADVERTISING_REPORT)) { + LOG_DBG("Marking adv report as discardable"); + rx.discardable = true; + } + + rx.remaining = hdr->len - (rx.hdr_len - sizeof(*hdr)); + LOG_DBG("Got event header. Payload %u bytes", hdr->len); + rx.have_hdr = true; + } +} + + +static inline void copy_hdr(struct net_buf *buf) +{ + net_buf_add_mem(buf, rx.hdr, rx.hdr_len); +} + +static void reset_rx(void) +{ + rx.type = BT_HCI_H4_NONE; + rx.remaining = 0U; + rx.have_hdr = false; + rx.hdr_len = 0U; + rx.discardable = false; +} + +static struct net_buf *get_rx(k_timeout_t timeout) +{ + LOG_DBG("type 0x%02x, evt 0x%02x", rx.type, rx.evt.evt); + + switch (rx.type) { + case BT_HCI_H4_EVT: + return bt_buf_get_evt(rx.evt.evt, rx.discardable, timeout); + case BT_HCI_H4_ACL: + return bt_buf_get_rx(BT_BUF_ACL_IN, timeout); + case BT_HCI_H4_ISO: + if (IS_ENABLED(CONFIG_BT_ISO)) { + return bt_buf_get_rx(BT_BUF_ISO_IN, timeout); + } + } + + return NULL; +} + +static void rx_thread(void *p1, void *p2, void *p3) +{ + struct net_buf *buf; + + ARG_UNUSED(p1); + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + LOG_DBG("started"); + + while (1) { + LOG_DBG("rx.buf %p", rx.buf); + + /* We can only do the allocation if we know the initial + * header, since Command Complete/Status events must use the + * original command buffer (if available). + */ + if (rx.have_hdr && !rx.buf) { + rx.buf = get_rx(K_FOREVER); + LOG_DBG("Got rx.buf %p", rx.buf); + if (rx.remaining > net_buf_tailroom(rx.buf)) { + LOG_ERR("Not enough space in buffer"); + rx.discard = rx.remaining; + reset_rx(); + } else { + copy_hdr(rx.buf); + } + } + + /* Let the ISR continue receiving new packets */ + irq_enable(CMAC2SYS_IRQn); + + buf = net_buf_get(&rx.fifo, K_FOREVER); + do { + irq_enable(CMAC2SYS_IRQn); + + LOG_DBG("Calling bt_recv(%p)", buf); + bt_recv(buf); + + /* Give other threads a chance to run if the ISR + * is receiving data so fast that rx.fifo never + * or very rarely goes empty. + */ + k_yield(); + + irq_disable(CMAC2SYS_IRQn); + buf = net_buf_get(&rx.fifo, K_NO_WAIT); + } while (buf); + } +} + +static size_t h4_discard(size_t len) +{ + uint8_t buf[33]; + int err; + + err = cmac_mbox_read(buf, MIN(len, sizeof(buf))); + if (unlikely(err < 0)) { + LOG_ERR("Unable to read from mailbox (err %d)", err); + return 0; + } + + return err; +} + +static inline void read_payload(void) +{ + struct net_buf *buf; + int read; + + if (!rx.buf) { + size_t buf_tailroom; + + rx.buf = get_rx(K_NO_WAIT); + if (!rx.buf) { + if (rx.discardable) { + LOG_WRN("Discarding event 0x%02x", rx.evt.evt); + rx.discard = rx.remaining; + reset_rx(); + return; + } + + LOG_WRN("Failed to allocate, deferring to rx_thread"); + irq_disable(CMAC2SYS_IRQn); + return; + } + + LOG_DBG("Allocated rx.buf %p", rx.buf); + + buf_tailroom = net_buf_tailroom(rx.buf); + if (buf_tailroom < rx.remaining) { + LOG_ERR("Not enough space in buffer %u/%zu", rx.remaining, buf_tailroom); + rx.discard = rx.remaining; + reset_rx(); + return; + } + + copy_hdr(rx.buf); + } + + read = cmac_mbox_read(net_buf_tail(rx.buf), rx.remaining); + if (unlikely(read < 0)) { + LOG_ERR("Failed to read mailbox (err %d)", read); + return; + } + + net_buf_add(rx.buf, read); + rx.remaining -= read; + + LOG_DBG("got %d bytes, remaining %u", read, rx.remaining); + LOG_DBG("Payload (len %u): %s", rx.buf->len, bt_hex(rx.buf->data, rx.buf->len)); + + if (rx.remaining) { + return; + } + + buf = rx.buf; + rx.buf = NULL; + + if (rx.type == BT_HCI_H4_EVT) { + bt_buf_set_type(buf, BT_BUF_EVT); + } else { + bt_buf_set_type(buf, BT_BUF_ACL_IN); + } + + reset_rx(); + + LOG_DBG("Putting buf %p to rx fifo", buf); + net_buf_put(&rx.fifo, buf); +} + +static inline void read_header(void) +{ + switch (rx.type) { + case BT_HCI_H4_NONE: + h4_get_type(); + return; + case BT_HCI_H4_EVT: + get_evt_hdr(); + break; + case BT_HCI_H4_ACL: + get_acl_hdr(); + break; + case BT_HCI_H4_ISO: + if (IS_ENABLED(CONFIG_BT_ISO)) { + get_iso_hdr(); + break; + } + __fallthrough; + default: + CODE_UNREACHABLE; + return; + } + + if (rx.have_hdr && rx.buf) { + if (rx.remaining > net_buf_tailroom(rx.buf)) { + LOG_ERR("Not enough space in buffer"); + rx.discard = rx.remaining; + reset_rx(); + } else { + copy_hdr(rx.buf); + } + } +} + +static inline void process_rx(void) +{ + LOG_DBG("remaining %u discard %u have_hdr %u rx.buf %p len %u", rx.remaining, rx.discard, + rx.have_hdr, rx.buf, rx.buf ? rx.buf->len : 0); + + if (rx.discard) { + rx.discard -= h4_discard(rx.discard); + return; + } + + if (rx.have_hdr) { + read_payload(); + } else { + read_header(); + } +} + +/* Called by HAL when data in CMAC mailbox is available to read */ +void cmac_read_req(void) +{ + while (cmac_mbox_has_data()) { + process_rx(); + } +} + +/* Called by HAL when CMAC requests host to put more data in rng buffer */ +void cmac_rng_req(void) +{ + k_sem_give(&rng_sem); +} + +static void rng_thread(void *p1, void *p2, void *p3) +{ + uint32_t word; + + ARG_UNUSED(p1); + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + while (1) { + k_sem_take(&rng_sem, K_FOREVER); + + while (cmac_rand_needs_data()) { + word = sys_rand32_get(); + cmac_rand_fill(&word, 1); + } + + cmac_signal(); + } +} + +static int bt_da1469x_open(void) +{ + k_tid_t tid; + + tid = k_thread_create(&rx_thread_data, rx_thread_stack, + K_KERNEL_STACK_SIZEOF(rx_thread_stack), + rx_thread, NULL, NULL, NULL, + K_PRIO_COOP(CONFIG_BT_RX_PRIO), + 0, K_NO_WAIT); + k_thread_name_set(tid, "bt_rx_thread"); + + k_sem_init(&rng_sem, 0, 1); + + tid = k_thread_create(&rng_thread_data, rng_thread_stack, + K_KERNEL_STACK_SIZEOF(rng_thread_stack), + rng_thread, NULL, NULL, NULL, + K_PRIO_COOP(CONFIG_BT_RX_PRIO), + 0, K_NO_WAIT); + k_thread_name_set(tid, "bt_rng_thread"); + + cmac_enable(); + irq_enable(CMAC2SYS_IRQn); + + return 0; +} + +#ifdef CONFIG_BT_HCI_HOST +static int bt_da1469x_close(void) +{ + irq_disable(CMAC2SYS_IRQn); + cmac_disable(); + + return 0; +} +#endif /* CONFIG_BT_HCI_HOST */ + +static int bt_da1469x_send(struct net_buf *buf) +{ + switch (bt_buf_get_type(buf)) { + case BT_BUF_ACL_OUT: + LOG_DBG("ACL: buf %p type %u len %u", buf, bt_buf_get_type(buf), buf->len); + net_buf_push_u8(buf, BT_HCI_H4_ACL); + break; + case BT_BUF_CMD: + LOG_DBG("CMD: buf %p type %u len %u", buf, bt_buf_get_type(buf), buf->len); + net_buf_push_u8(buf, BT_HCI_H4_CMD); + break; + default: + LOG_ERR("Unsupported type"); + return -EINVAL; + } + + cmac_mbox_write(buf->data, buf->len); + + net_buf_unref(buf); + + return 0; +} + +static const struct bt_hci_driver drv = { + .name = "BT DA1469x", + .bus = BT_HCI_DRIVER_BUS_IPM, + .open = bt_da1469x_open, + .close = bt_da1469x_close, + .send = bt_da1469x_send, +}; + +static int bt_da1469x_init(void) +{ + irq_disable(CMAC2SYS_IRQn); + + bt_hci_driver_register(&drv); + + cmac_disable(); + cmac_load_image(); + cmac_configure_pdc(); + cmac_configure_shm(); + + IRQ_CONNECT(CMAC2SYS_IRQn, 0, cmac_cmac2sys_isr, NULL, 0); + + return 0; +} + +SYS_INIT(bt_da1469x_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE); diff --git a/drivers/bluetooth/hci/hci_esp32.c b/drivers/bluetooth/hci/hci_esp32.c index cddecbd5123..311dddf916c 100644 --- a/drivers/bluetooth/hci/hci_esp32.c +++ b/drivers/bluetooth/hci/hci_esp32.c @@ -17,12 +17,6 @@ #include LOG_MODULE_REGISTER(bt_hci_driver_esp32); -#define HCI_CMD 0x01 -#define HCI_ACL 0x02 -#define HCI_SCO 0x03 -#define HCI_EVT 0x04 -#define HCI_ISO 0x05 - #define HCI_BT_ESP32_TIMEOUT K_MSEC(2000) static K_SEM_DEFINE(hci_send_sem, 1, 1); @@ -196,15 +190,15 @@ static int hci_esp_host_rcv_pkt(uint8_t *data, uint16_t len) remaining -= sizeof(pkt_indicator); switch (pkt_indicator) { - case HCI_EVT: + case BT_HCI_H4_EVT: buf = bt_esp_evt_recv(data, remaining); break; - case HCI_ACL: + case BT_HCI_H4_ACL: buf = bt_esp_acl_recv(data, remaining); break; - case HCI_SCO: + case BT_HCI_H4_SCO: buf = bt_esp_iso_recv(data, remaining); break; @@ -241,13 +235,13 @@ static int bt_esp32_send(struct net_buf *buf) switch (bt_buf_get_type(buf)) { case BT_BUF_ACL_OUT: - pkt_indicator = HCI_ACL; + pkt_indicator = BT_HCI_H4_ACL; break; case BT_BUF_CMD: - pkt_indicator = HCI_CMD; + pkt_indicator = BT_HCI_H4_CMD; break; case BT_BUF_ISO_OUT: - pkt_indicator = HCI_ISO; + pkt_indicator = BT_HCI_H4_ISO; break; default: LOG_ERR("Unknown type %u", bt_buf_get_type(buf)); diff --git a/drivers/bluetooth/hci/hci_psoc6_bless.c b/drivers/bluetooth/hci/hci_psoc6_bless.c index 9f56eba7f60..af6804f2f17 100644 --- a/drivers/bluetooth/hci/hci_psoc6_bless.c +++ b/drivers/bluetooth/hci/hci_psoc6_bless.c @@ -23,7 +23,6 @@ #include #include -#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HCI_DRIVER) #define LOG_LEVEL CONFIG_BT_HCI_DRIVER_LOG_LEVEL #include LOG_MODULE_REGISTER(psoc6_bless); @@ -33,11 +32,6 @@ LOG_MODULE_REGISTER(psoc6_bless); #define DT_DRV_COMPAT infineon_cat1_bless_hci -#define PACKET_TYPE_HCI_COMMAND 0X1 -#define PACKET_TYPE_HCI_ACL_DATA 0x2 -#define PACKET_TYPE_HCI_SYNCHRONOUS 0X3 -#define PACKET_TYPE_HCI_EVENT 0X4 - #define BLE_LOCK_TMOUT_MS (1000) #define BLE_THREAD_SEM_TMOUT_MS (1000) @@ -112,7 +106,7 @@ static void psoc6_bless_events_handler(uint32_t eventCode, void *eventParam) hci_rx = eventParam; switch (hci_rx->packetType) { - case PACKET_TYPE_HCI_EVENT: + case BT_HCI_H4_EVT: buf = bt_buf_get_evt(hci_rx->data[0], 0, K_NO_WAIT); if (!buf) { LOG_ERR("Failed to allocate the buffer for RX: EVENT "); @@ -120,7 +114,7 @@ static void psoc6_bless_events_handler(uint32_t eventCode, void *eventParam) } break; - case PACKET_TYPE_HCI_ACL_DATA: + case BT_HCI_H4_ACL: buf = bt_buf_get_rx(BT_BUF_ACL_IN, K_NO_WAIT); if (!buf) { LOG_ERR("Failed to allocate the buffer for RX: ACL "); @@ -168,10 +162,10 @@ static int psoc6_bless_send(struct net_buf *buf) switch (bt_buf_get_type(buf)) { case BT_BUF_ACL_OUT: - hci_tx_pkt.packetType = PACKET_TYPE_HCI_ACL_DATA; + hci_tx_pkt.packetType = BT_HCI_H4_ACL; break; case BT_BUF_CMD: - hci_tx_pkt.packetType = PACKET_TYPE_HCI_COMMAND; + hci_tx_pkt.packetType = BT_HCI_H4_CMD; break; default: net_buf_unref(buf); diff --git a/drivers/bluetooth/hci/hci_spi_st.c b/drivers/bluetooth/hci/hci_spi_st.c index b2b252e0712..d45dbb592a1 100644 --- a/drivers/bluetooth/hci/hci_spi_st.c +++ b/drivers/bluetooth/hci/hci_spi_st.c @@ -29,11 +29,6 @@ #include LOG_MODULE_REGISTER(bt_driver); -#define HCI_CMD 0x01 -#define HCI_ACL 0x02 -#define HCI_SCO 0x03 -#define HCI_EVT 0x04 -#define HCI_ISO 0x05 /* ST Proprietary extended event */ #define HCI_EXT_EVT 0x82 @@ -378,10 +373,10 @@ static int bt_spi_rx_buf_construct(uint8_t *msg, struct net_buf **bufp, uint16_t } /* 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 */ + /* Manage event as regular BT_HCI_H4_EVT */ __fallthrough; #endif /* DT_HAS_COMPAT_STATUS_OKAY(st_hci_spi_v2) */ - case HCI_EVT: + case BT_HCI_H4_EVT: switch (msg[EVT_HEADER_EVENT]) { case BT_HCI_EVT_VENDOR: /* Run event through interface handler */ @@ -419,7 +414,7 @@ static int bt_spi_rx_buf_construct(uint8_t *msg, struct net_buf **bufp, uint16_t } #endif /* DT_HAS_COMPAT_STATUS_OKAY(st_hci_spi_v1) */ break; - case HCI_ACL: + case BT_HCI_H4_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); @@ -431,7 +426,7 @@ static int bt_spi_rx_buf_construct(uint8_t *msg, struct net_buf **bufp, uint16_t net_buf_add_mem(buf, &msg[1], len); break; #if defined(CONFIG_BT_ISO) - case HCI_ISO: + case BT_HCI_H4_ISO: struct bt_hci_iso_hdr iso_hdr; buf = bt_buf_get_rx(BT_BUF_ISO_IN, timeout); @@ -440,12 +435,12 @@ static int bt_spi_rx_buf_construct(uint8_t *msg, struct net_buf **bufp, uint16_t len = sizeof(iso_hdr) + bt_iso_hdr_len(sys_le16_to_cpu(iso_hdr.len)); } else { LOG_ERR("No available ISO buffers!"); - return NULL; + return -ENOMEM; } if (len > net_buf_tailroom(buf)) { LOG_ERR("ISO too long: %d", len); net_buf_unref(buf); - return NULL; + return -ENOMEM; } net_buf_add_mem(buf, &msg[1], len); break; @@ -529,14 +524,14 @@ static int bt_spi_send(struct net_buf *buf) switch (bt_buf_get_type(buf)) { case BT_BUF_ACL_OUT: - net_buf_push_u8(buf, HCI_ACL); + net_buf_push_u8(buf, BT_HCI_H4_ACL); break; case BT_BUF_CMD: - net_buf_push_u8(buf, HCI_CMD); + net_buf_push_u8(buf, BT_HCI_H4_CMD); break; #if defined(CONFIG_BT_ISO) case BT_BUF_ISO_OUT: - net_buf_push_u8(buf, HCI_ISO); + net_buf_push_u8(buf, BT_HCI_H4_ISO); break; #endif /* CONFIG_BT_ISO */ default: diff --git a/drivers/bluetooth/hci/hci_stm32wba.c b/drivers/bluetooth/hci/hci_stm32wba.c index 9a9d3a1b1c3..67b87a5aa25 100644 --- a/drivers/bluetooth/hci/hci_stm32wba.c +++ b/drivers/bluetooth/hci/hci_stm32wba.c @@ -29,12 +29,6 @@ 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, \ @@ -225,14 +219,14 @@ static int receive_data(const uint8_t *data, size_t len, len -= sizeof(pkt_indicator); switch (pkt_indicator) { - case HCI_EVT: + case BT_HCI_H4_EVT: buf = treat_evt(data, len); break; - case HCI_ACL: + case BT_HCI_H4_ACL: buf = treat_acl(data, len + 1, ext_data, ext_len); break; - case HCI_ISO: - case HCI_SCO: + case BT_HCI_H4_ISO: + case BT_HCI_H4_SCO: buf = treat_iso(data, len + 1, ext_data, ext_len); break; default: @@ -289,13 +283,13 @@ static int bt_hci_stm32wba_send(struct net_buf *buf) switch (bt_buf_get_type(buf)) { case BT_BUF_ACL_OUT: - pkt_indicator = HCI_ACL; + pkt_indicator = BT_HCI_H4_ACL; break; case BT_BUF_CMD: - pkt_indicator = HCI_CMD; + pkt_indicator = BT_HCI_H4_CMD; break; case BT_BUF_ISO_OUT: - pkt_indicator = HCI_ISO; + pkt_indicator = BT_HCI_H4_ISO; break; default: LOG_ERR("Unknown type %u", bt_buf_get_type(buf)); diff --git a/drivers/bluetooth/hci/ipc.c b/drivers/bluetooth/hci/ipc.c index aa5e67b0029..54a8556d138 100644 --- a/drivers/bluetooth/hci/ipc.c +++ b/drivers/bluetooth/hci/ipc.c @@ -18,12 +18,6 @@ #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; @@ -218,15 +212,15 @@ static void bt_ipc_rx(const uint8_t *data, size_t len) remaining -= sizeof(pkt_indicator); switch (pkt_indicator) { - case IPC_EVT: + case BT_HCI_H4_EVT: buf = bt_ipc_evt_recv(data, remaining); break; - case IPC_ACL: + case BT_HCI_H4_ACL: buf = bt_ipc_acl_recv(data, remaining); break; - case IPC_ISO: + case BT_HCI_H4_ISO: buf = bt_ipc_iso_recv(data, remaining); break; @@ -237,19 +231,7 @@ static void bt_ipc_rx(const uint8_t *data, size_t len) 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:"); } @@ -264,13 +246,13 @@ static int bt_ipc_send(struct net_buf *buf) switch (bt_buf_get_type(buf)) { case BT_BUF_ACL_OUT: - pkt_indicator = IPC_ACL; + pkt_indicator = BT_HCI_H4_ACL; break; case BT_BUF_CMD: - pkt_indicator = IPC_CMD; + pkt_indicator = BT_HCI_H4_CMD; break; case BT_BUF_ISO_OUT: - pkt_indicator = IPC_ISO; + pkt_indicator = BT_HCI_H4_ISO; break; default: LOG_ERR("Unknown type %u", bt_buf_get_type(buf)); diff --git a/drivers/bluetooth/hci/ipm_stm32wb.c b/drivers/bluetooth/hci/ipm_stm32wb.c index 85fc875f139..48c5dd0a99c 100644 --- a/drivers/bluetooth/hci/ipm_stm32wb.c +++ b/drivers/bluetooth/hci/ipm_stm32wb.c @@ -46,11 +46,6 @@ static void sysevt_received(void *pdata); #include LOG_MODULE_REGISTER(hci_ipm); -#define HCI_CMD 0x01 -#define HCI_ACL 0x02 -#define HCI_SCO 0x03 -#define HCI_EVT 0x04 - #define STM32WB_C2_LOCK_TIMEOUT K_MSEC(500) static K_SEM_DEFINE(c2_started, 0, 1); @@ -181,7 +176,7 @@ static void bt_ipm_rx_thread(void *p1, void *p2, void *p3) k_sem_take(&ipm_busy, K_FOREVER); switch (hcievt->evtserial.type) { - case HCI_EVT: + case BT_HCI_H4_EVT: LOG_DBG("EVT: hcievt->evtserial.evt.evtcode: 0x%02x", hcievt->evtserial.evt.evtcode); switch (hcievt->evtserial.evt.evtcode) { @@ -222,7 +217,7 @@ static void bt_ipm_rx_thread(void *p1, void *p2, void *p3) net_buf_add_mem(buf, &hcievt->evtserial.evt, buf_add_len); break; - case HCI_ACL: + case BT_HCI_H4_ACL: acl = &(((TL_AclDataPacket_t *)hcievt)->AclDataSerial); buf = bt_buf_get_rx(BT_BUF_ACL_IN, K_FOREVER); acl_hdr.handle = acl->handle; @@ -362,7 +357,7 @@ static int bt_ipm_send(struct net_buf *buf) case BT_BUF_ACL_OUT: LOG_DBG("ACL: buf %p type %u len %u", buf, bt_buf_get_type(buf), buf->len); k_sem_take(&acl_data_ack, K_FOREVER); - net_buf_push_u8(buf, HCI_ACL); + net_buf_push_u8(buf, BT_HCI_H4_ACL); memcpy((void *) &((TL_AclDataPacket_t *)HciAclDataBuffer)->AclDataSerial, buf->data, buf->len); @@ -370,7 +365,7 @@ static int bt_ipm_send(struct net_buf *buf) break; case BT_BUF_CMD: LOG_DBG("CMD: buf %p type %u len %u", buf, bt_buf_get_type(buf), buf->len); - ble_cmd_buff->cmdserial.type = HCI_CMD; + ble_cmd_buff->cmdserial.type = BT_HCI_H4_CMD; ble_cmd_buff->cmdserial.cmd.plen = buf->len; memcpy((void *)&ble_cmd_buff->cmdserial.cmd, buf->data, buf->len); diff --git a/drivers/bluetooth/hci/spi.c b/drivers/bluetooth/hci/spi.c index 471af574fdc..26d8f32afd0 100644 --- a/drivers/bluetooth/hci/spi.c +++ b/drivers/bluetooth/hci/spi.c @@ -21,11 +21,6 @@ #include LOG_MODULE_REGISTER(bt_driver); -#define HCI_CMD 0x01 -#define HCI_ACL 0x02 -#define HCI_SCO 0x03 -#define HCI_EVT 0x04 - /* Special Values */ #define SPI_WRITE 0x0A #define SPI_READ 0x0B @@ -189,7 +184,7 @@ static struct net_buf *bt_spi_rx_buf_construct(uint8_t *msg) int len; switch (msg[PACKET_TYPE]) { - case HCI_EVT: + case BT_HCI_H4_EVT: switch (msg[EVT_HEADER_EVENT]) { case BT_HCI_EVT_VENDOR: /* Run event through interface handler */ @@ -220,7 +215,7 @@ static struct net_buf *bt_spi_rx_buf_construct(uint8_t *msg) } net_buf_add_mem(buf, &msg[1], len); break; - case HCI_ACL: + case BT_HCI_H4_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); @@ -317,10 +312,10 @@ static int bt_spi_send(struct net_buf *buf) switch (bt_buf_get_type(buf)) { case BT_BUF_ACL_OUT: - net_buf_push_u8(buf, HCI_ACL); + net_buf_push_u8(buf, BT_HCI_H4_ACL); break; case BT_BUF_CMD: - net_buf_push_u8(buf, HCI_CMD); + net_buf_push_u8(buf, BT_HCI_H4_CMD); break; default: LOG_ERR("Unsupported type"); diff --git a/drivers/bluetooth/hci/userchan.c b/drivers/bluetooth/hci/userchan.c index 7c2db034850..4c7b178fa6d 100644 --- a/drivers/bluetooth/hci/userchan.c +++ b/drivers/bluetooth/hci/userchan.c @@ -46,13 +46,6 @@ struct sockaddr_hci { #define SOL_HCI 0 -/* Bluetooth spec v5.4 Vol 4, Part A Table 2.1 */ -#define H4_CMD 0x01 -#define H4_ACL 0x02 -#define H4_SCO 0x03 -#define H4_EVT 0x04 -#define H4_ISO 0x05 - static K_KERNEL_STACK_DEFINE(rx_thread_stack, CONFIG_ARCH_POSIX_RECOMMENDED_STACK_SIZE); static struct k_thread rx_thread_data; @@ -73,7 +66,7 @@ static struct net_buf *get_rx(const uint8_t *buf) k_timeout_t timeout = K_FOREVER; switch (buf[0]) { - case H4_EVT: + case BT_HCI_H4_EVT: if (buf[1] == BT_HCI_EVT_LE_META_EVENT && (buf[3] == BT_HCI_EVT_LE_ADVERTISING_REPORT)) { discardable = true; @@ -81,9 +74,9 @@ static struct net_buf *get_rx(const uint8_t *buf) } return bt_buf_get_evt(buf[1], discardable, timeout); - case H4_ACL: + case BT_HCI_H4_ACL: return bt_buf_get_rx(BT_BUF_ACL_IN, K_FOREVER); - case H4_ISO: + case BT_HCI_H4_ISO: if (IS_ENABLED(CONFIG_BT_ISO)) { return bt_buf_get_rx(BT_BUF_ISO_IN, K_FOREVER); } @@ -109,7 +102,7 @@ static uint16_t packet_len(const uint8_t *buf) const uint8_t *hdr = &buf[sizeof(type)]; switch (type) { - case H4_CMD: { + case BT_HCI_H4_CMD: { const struct bt_hci_cmd_hdr *cmd = (const struct bt_hci_cmd_hdr *)hdr; /* Parameter Total Length */ @@ -117,7 +110,7 @@ static uint16_t packet_len(const uint8_t *buf) header_len = BT_HCI_CMD_HDR_SIZE; break; } - case H4_ACL: { + case BT_HCI_H4_ACL: { const struct bt_hci_acl_hdr *acl = (const struct bt_hci_acl_hdr *)hdr; /* Data Total Length */ @@ -125,7 +118,7 @@ static uint16_t packet_len(const uint8_t *buf) header_len = BT_HCI_ACL_HDR_SIZE; break; } - case H4_SCO: { + case BT_HCI_H4_SCO: { const struct bt_hci_sco_hdr *sco = (const struct bt_hci_sco_hdr *)hdr; /* Data_Total_Length */ @@ -133,7 +126,7 @@ static uint16_t packet_len(const uint8_t *buf) header_len = BT_HCI_SCO_HDR_SIZE; break; } - case H4_EVT: { + case BT_HCI_H4_EVT: { const struct bt_hci_evt_hdr *evt = (const struct bt_hci_evt_hdr *)hdr; /* Parameter Total Length */ @@ -141,7 +134,7 @@ static uint16_t packet_len(const uint8_t *buf) header_len = BT_HCI_EVT_HDR_SIZE; break; } - case H4_ISO: { + case BT_HCI_H4_ISO: { const struct bt_hci_iso_hdr *iso = (const struct bt_hci_iso_hdr *)hdr; /* ISO_Data_Load_Length parameter */ @@ -258,14 +251,14 @@ static int uc_send(struct net_buf *buf) switch (bt_buf_get_type(buf)) { case BT_BUF_ACL_OUT: - net_buf_push_u8(buf, H4_ACL); + net_buf_push_u8(buf, BT_HCI_H4_ACL); break; case BT_BUF_CMD: - net_buf_push_u8(buf, H4_CMD); + net_buf_push_u8(buf, BT_HCI_H4_CMD); break; case BT_BUF_ISO_OUT: if (IS_ENABLED(CONFIG_BT_ISO)) { - net_buf_push_u8(buf, H4_ISO); + net_buf_push_u8(buf, BT_HCI_H4_ISO); break; } __fallthrough; diff --git a/drivers/cache/CMakeLists.txt b/drivers/cache/CMakeLists.txt index 23cb11afb6a..a10d98ce68f 100644 --- a/drivers/cache/CMakeLists.txt +++ b/drivers/cache/CMakeLists.txt @@ -6,5 +6,6 @@ zephyr_library() zephyr_library_property(ALLOW_EMPTY TRUE) zephyr_library_sources_ifdef(CONFIG_CACHE_ASPEED cache_aspeed.c) +zephyr_library_sources_ifdef(CONFIG_CACHE_ANDES cache_andes.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 4dcb64f488a..be3fc2ce193 100644 --- a/drivers/cache/Kconfig +++ b/drivers/cache/Kconfig @@ -20,5 +20,6 @@ comment "Device Drivers" source "drivers/cache/Kconfig.aspeed" source "drivers/cache/Kconfig.nrf" +source "drivers/cache/Kconfig.andes" endif # CACHE diff --git a/drivers/cache/Kconfig.andes b/drivers/cache/Kconfig.andes new file mode 100644 index 00000000000..8c566ab24cd --- /dev/null +++ b/drivers/cache/Kconfig.andes @@ -0,0 +1,33 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright (c) 2024 ANDES Technology Inc. + +DT_COMPAT_ANDESTECH_L2C := andestech,l2c + +config CACHE_ANDES +bool "ANDES external cache driver" + default y + depends on SOC_FAMILY_ANDES_V5 + select CACHE_HAS_DRIVER + imply DCACHE_LINE_SIZE_DETECT + imply ICACHE_LINE_SIZE_DETECT + help + This option enables the CACHE driver for ANDES V5 series SOC. + +if CACHE_ANDES + +config L2C_INCLUSIVE_POLICY + bool + depends on $(dt_compat_enabled,$(DT_COMPAT_ANDESTECH_L2C)) + help + When L2 cache is inclusive of L1, CPU only needs to perform operations + on L2 cache, instead of on both L1 and L2 caches. + +config CACHE_ANDES_INIT_PRIORITY + int "Andes cache driver init priority" + default 60 + help + This option controls the priority of the cache initialization. + Lower values indicate earlier initialization. + +endif # CACHE_ANDES diff --git a/drivers/cache/cache_andes.c b/drivers/cache/cache_andes.c new file mode 100644 index 00000000000..e9907cfaa46 --- /dev/null +++ b/drivers/cache/cache_andes.c @@ -0,0 +1,553 @@ +/* + * Copyright (c) 2024 Andes Technology Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "soc_v5.h" + +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(cache_andes, CONFIG_CACHE_LOG_LEVEL); + +/* L1 CCTL Command */ +#define CCTL_L1D_VA_INVAL 0 +#define CCTL_L1D_VA_WB 1 +#define CCTL_L1D_VA_WBINVAL 2 +#define CCTL_L1D_WBINVAL_ALL 6 +#define CCTL_L1D_WB_ALL 7 +#define CCTL_L1I_VA_INVAL 8 +#define CCTL_L1D_INVAL_ALL 23 +#define CCTL_L1I_IX_INVAL 24 + +/* mcache_ctl bitfield */ +#define MCACHE_CTL_IC_EN BIT(0) +#define MCACHE_CTL_DC_EN BIT(1) +#define MCACHE_CTL_CCTL_SUEN BIT(8) +#define MCACHE_CTL_DC_COHEN BIT(19) +#define MCACHE_CTL_DC_COHSTA BIT(20) + +/* micm_cfg bitfield */ +#define MICM_CFG_ISET BIT_MASK(3) +#define MICM_CFG_IWAY_SHIFT 3 +#define MICM_CFG_ISZ_SHIFT 6 + +/* mdcm_cfg bitfield */ +#define MDCM_CFG_DSZ_SHIFT 6 + +/* mmsc_cfg bitfield */ +#define MMSC_CFG_CCTLCSR BIT(16) +#define MMSC_CFG_VCCTL_2 BIT(19) +#define MMSC_CFG_MSC_EXT BIT(31) +#define MMSC_CFG_RVARCH BIT64(52) + +/* mmsc_cfg2 bitfield */ +#define MMSC_CFG2_RVARCH BIT(20) + +/* mrvarch_cfg bitfield */ +#define MRVARCH_CFG_SMEPMP BIT(4) + +#define K_CACHE_WB BIT(0) +#define K_CACHE_INVD BIT(1) +#define K_CACHE_WB_INVD (K_CACHE_WB | K_CACHE_INVD) + +struct cache_config { + uint32_t instr_line_size; + uint32_t data_line_size; + uint32_t l2_cache_size; + uint32_t l2_cache_inclusive; +}; + +static struct cache_config cache_cfg; +static struct k_spinlock lock; + +#if DT_NODE_HAS_COMPAT_STATUS(DT_INST(0, andestech_l2c), andestech_l2c, okay) +#include "cache_andes_l2.h" +#else +static ALWAYS_INLINE void nds_l2_cache_enable(void) { } +static ALWAYS_INLINE void nds_l2_cache_disable(void) { } +static ALWAYS_INLINE int nds_l2_cache_range(void *addr, size_t size, int op) { return 0; } +static ALWAYS_INLINE int nds_l2_cache_all(int op) { return 0; } +static ALWAYS_INLINE int nds_l2_cache_is_inclusive(void) { return 0; } +static ALWAYS_INLINE int nds_l2_cache_init(void) { return 0; } +#endif /* DT_NODE_HAS_COMPAT_STATUS(DT_INST(0, andestech_l2c), andestech_l2c, okay) */ + +static ALWAYS_INLINE int nds_cctl_range_operations(void *addr, size_t size, int line_size, int cmd) +{ + unsigned long last_byte, align_addr; + unsigned long status = csr_read(mstatus); + + last_byte = (unsigned long)addr + size - 1; + align_addr = ROUND_DOWN(addr, line_size); + + /* + * In memory access privilige U mode, applications should use ucctl CSRs + * for VA type commands. + */ + if ((status & MSTATUS_MPRV) && !(status & MSTATUS_MPP)) { + while (align_addr <= last_byte) { + csr_write(NDS_UCCTLBEGINADDR, align_addr); + csr_write(NDS_UCCTLCOMMAND, cmd); + align_addr += line_size; + } + } else { + while (align_addr <= last_byte) { + csr_write(NDS_MCCTLBEGINADDR, align_addr); + csr_write(NDS_MCCTLCOMMAND, cmd); + align_addr += line_size; + } + } + + return 0; +} + +static ALWAYS_INLINE int nds_l1i_cache_all(int op) +{ + unsigned long sets, ways, end; + unsigned long status = csr_read(mstatus); + + if (csr_read(NDS_MMSC_CFG) & MMSC_CFG_VCCTL_2) { + /* + * In memory access privilige U mode, applications can only use + * VA type commands for specific range. + */ + if ((status & MSTATUS_MPRV) && !(status & MSTATUS_MPP)) { + return -ENOTSUP; + } + } + + if (op == K_CACHE_INVD) { + sets = 0x40 << (csr_read(NDS_MICM_CFG) & MICM_CFG_ISET); + ways = ((csr_read(NDS_MICM_CFG) >> MICM_CFG_IWAY_SHIFT) & BIT_MASK(3)) + 1; + end = ways * sets * cache_cfg.instr_line_size; + + for (int i = 0; i < end; i += cache_cfg.instr_line_size) { + csr_write(NDS_MCCTLBEGINADDR, i); + csr_write(NDS_MCCTLCOMMAND, CCTL_L1I_IX_INVAL); + } + } + + return 0; +} + +static ALWAYS_INLINE int nds_l1d_cache_all(int op) +{ + unsigned long status = csr_read(mstatus); + + if (csr_read(NDS_MMSC_CFG) & MMSC_CFG_VCCTL_2) { + /* + * In memory access privilige U mode, applications can only use + * VA type commands for specific range. + */ + if ((status & MSTATUS_MPRV) && !(status & MSTATUS_MPP)) { + return -ENOTSUP; + } + } + + switch (op) { + case K_CACHE_WB: + csr_write(NDS_MCCTLCOMMAND, CCTL_L1D_WB_ALL); + break; + case K_CACHE_INVD: + csr_write(NDS_MCCTLCOMMAND, CCTL_L1D_INVAL_ALL); + break; + case K_CACHE_WB_INVD: + csr_write(NDS_MCCTLCOMMAND, CCTL_L1D_WBINVAL_ALL); + break; + default: + return -ENOTSUP; + } + + return 0; +} + +static ALWAYS_INLINE int nds_l1i_cache_range(void *addr, size_t size, int op) +{ + unsigned long cmd; + + if (op == K_CACHE_INVD) { + cmd = CCTL_L1I_VA_INVAL; + nds_cctl_range_operations(addr, size, cache_cfg.instr_line_size, cmd); + } + + return 0; +} + +static ALWAYS_INLINE int nds_l1d_cache_range(void *addr, size_t size, int op) +{ + unsigned long cmd; + + switch (op) { + case K_CACHE_WB: + cmd = CCTL_L1D_VA_WB; + break; + case K_CACHE_INVD: + cmd = CCTL_L1D_VA_INVAL; + break; + case K_CACHE_WB_INVD: + cmd = CCTL_L1D_VA_WBINVAL; + break; + default: + return -ENOTSUP; + } + + nds_cctl_range_operations(addr, size, cache_cfg.data_line_size, cmd); + + return 0; +} + +void cache_data_enable(void) +{ + if (IS_ENABLED(CONFIG_SMP) && (CONFIG_MP_MAX_NUM_CPUS > 1)) { + return; + } + + K_SPINLOCK(&lock) { + nds_l2_cache_enable(); + + /* Enable D-cache coherence management */ + csr_set(NDS_MCACHE_CTL, MCACHE_CTL_DC_COHEN); + + /* Check if CPU support CM or not. */ + if (csr_read(NDS_MCACHE_CTL) & MCACHE_CTL_DC_COHEN) { + /* Wait for cache coherence enabling completed */ + while (!(csr_read(NDS_MCACHE_CTL) & MCACHE_CTL_DC_COHSTA)) { + ; + } + } + + /* Enable D-cache */ + csr_set(NDS_MCACHE_CTL, MCACHE_CTL_DC_EN); + } +} + +void cache_data_disable(void) +{ + unsigned long status = csr_read(mstatus); + + if (IS_ENABLED(CONFIG_SMP) && (CONFIG_MP_MAX_NUM_CPUS > 1)) { + return; + } + + if (csr_read(NDS_MMSC_CFG) & MMSC_CFG_VCCTL_2) { + if ((status & MSTATUS_MPRV) && !(status & MSTATUS_MPP)) { + if (!cache_cfg.l2_cache_inclusive) { + return; + } + } + } + + K_SPINLOCK(&lock) { + if (cache_cfg.l2_cache_inclusive) { + nds_l2_cache_all(K_CACHE_WB_INVD); + } else { + nds_l1d_cache_all(K_CACHE_WB_INVD); + nds_l2_cache_all(K_CACHE_WB_INVD); + } + + csr_clear(NDS_MCACHE_CTL, MCACHE_CTL_DC_EN); + + /* Check if CPU support CM or not. */ + if (csr_read(NDS_MCACHE_CTL) & MCACHE_CTL_DC_COHSTA) { + csr_clear(NDS_MCACHE_CTL, MCACHE_CTL_DC_COHEN); + /* Wait for cache coherence disabling completed */ + while (csr_read(NDS_MCACHE_CTL) & MCACHE_CTL_DC_COHSTA) { + ; + } + } + nds_l2_cache_disable(); + } +} + +void cache_instr_enable(void) +{ + if (IS_ENABLED(CONFIG_SMP) && (CONFIG_MP_MAX_NUM_CPUS > 1)) { + return; + } + + csr_set(NDS_MCACHE_CTL, MCACHE_CTL_IC_EN); +} + +void cache_instr_disable(void) +{ + if (IS_ENABLED(CONFIG_SMP) && (CONFIG_MP_MAX_NUM_CPUS > 1)) { + return; + } + + csr_clear(NDS_MCACHE_CTL, MCACHE_CTL_IC_EN); +} + +int cache_data_invd_all(void) +{ + unsigned long ret = 0; + + K_SPINLOCK(&lock) { + if (cache_cfg.l2_cache_inclusive) { + ret |= nds_l2_cache_all(K_CACHE_WB); + ret |= nds_l2_cache_all(K_CACHE_INVD); + } else { + ret |= nds_l1d_cache_all(K_CACHE_WB); + ret |= nds_l2_cache_all(K_CACHE_WB); + ret |= nds_l2_cache_all(K_CACHE_INVD); + ret |= nds_l1d_cache_all(K_CACHE_INVD); + } + } + + return ret; +} + +int cache_data_invd_range(void *addr, size_t size) +{ + unsigned long ret = 0; + + K_SPINLOCK(&lock) { + if (cache_cfg.l2_cache_inclusive) { + ret |= nds_l2_cache_range(addr, size, K_CACHE_INVD); + } else { + ret |= nds_l2_cache_range(addr, size, K_CACHE_INVD); + ret |= nds_l1d_cache_range(addr, size, K_CACHE_INVD); + } + } + + return ret; +} + +int cache_instr_invd_all(void) +{ + unsigned long ret = 0; + + if (IS_ENABLED(CONFIG_SMP) && (CONFIG_MP_MAX_NUM_CPUS > 1)) { + return -ENOTSUP; + } + + if (IS_ENABLED(CONFIG_RISCV_PMP)) { + /* CCTL IX type command is not to RISC-V Smepmp */ + if (IS_ENABLED(CONFIG_64BIT)) { + if (csr_read(NDS_MMSC_CFG) & MMSC_CFG_RVARCH) { + if (csr_read(NDS_MRVARCH_CFG) & MRVARCH_CFG_SMEPMP) { + return -ENOTSUP; + } + } + } else { + if ((csr_read(NDS_MMSC_CFG) & MMSC_CFG_MSC_EXT) && + (csr_read(NDS_MMSC_CFG2) & MMSC_CFG2_RVARCH)) { + if (csr_read(NDS_MRVARCH_CFG) & MRVARCH_CFG_SMEPMP) { + return -ENOTSUP; + } + } + } + } + + K_SPINLOCK(&lock) { + ret |= nds_l1i_cache_all(K_CACHE_INVD); + } + + return ret; +} + +int cache_instr_invd_range(void *addr, size_t size) +{ + unsigned long ret = 0; + + if (IS_ENABLED(CONFIG_SMP) && (CONFIG_MP_MAX_NUM_CPUS > 1)) { + ARG_UNUSED(addr); + ARG_UNUSED(size); + + return -ENOTSUP; + } + + K_SPINLOCK(&lock) { + ret |= nds_l1i_cache_range(addr, size, K_CACHE_INVD); + } + + return ret; +} + +int cache_data_flush_all(void) +{ + unsigned long ret = 0; + + K_SPINLOCK(&lock) { + if (cache_cfg.l2_cache_inclusive) { + ret |= nds_l2_cache_all(K_CACHE_WB); + } else { + ret |= nds_l1d_cache_all(K_CACHE_WB); + ret |= nds_l2_cache_all(K_CACHE_WB); + } + } + + return ret; +} + +int cache_data_flush_range(void *addr, size_t size) +{ + unsigned long ret = 0; + + K_SPINLOCK(&lock) { + if (cache_cfg.l2_cache_inclusive) { + ret |= nds_l2_cache_range(addr, size, K_CACHE_WB); + } else { + ret |= nds_l1d_cache_range(addr, size, K_CACHE_WB); + ret |= nds_l2_cache_range(addr, size, K_CACHE_WB); + } + } + + return ret; +} + +int cache_data_flush_and_invd_all(void) +{ + unsigned long ret = 0; + + K_SPINLOCK(&lock) { + if (cache_cfg.l2_cache_size) { + if (cache_cfg.l2_cache_inclusive) { + ret |= nds_l2_cache_all(K_CACHE_WB_INVD); + } else { + ret |= nds_l1d_cache_all(K_CACHE_WB); + ret |= nds_l2_cache_all(K_CACHE_WB_INVD); + ret |= nds_l1d_cache_all(K_CACHE_INVD); + } + } else { + ret |= nds_l1d_cache_all(K_CACHE_WB_INVD); + } + } + + return ret; +} + +int cache_data_flush_and_invd_range(void *addr, size_t size) +{ + unsigned long ret = 0; + + K_SPINLOCK(&lock) { + if (cache_cfg.l2_cache_size) { + if (cache_cfg.l2_cache_inclusive) { + ret |= nds_l2_cache_range(addr, size, K_CACHE_WB_INVD); + } else { + ret |= nds_l1d_cache_range(addr, size, K_CACHE_WB); + ret |= nds_l2_cache_range(addr, size, K_CACHE_WB_INVD); + ret |= nds_l1d_cache_range(addr, size, K_CACHE_INVD); + } + } else { + ret |= nds_l1d_cache_range(addr, size, K_CACHE_WB_INVD); + } + } + + return ret; +} + +int cache_instr_flush_all(void) +{ + return -ENOTSUP; +} + +int cache_instr_flush_and_invd_all(void) +{ + return -ENOTSUP; +} + +int cache_instr_flush_range(void *addr, size_t size) +{ + ARG_UNUSED(addr); + ARG_UNUSED(size); + + return -ENOTSUP; +} + +int cache_instr_flush_and_invd_range(void *addr, size_t size) +{ + ARG_UNUSED(addr); + ARG_UNUSED(size); + + return -ENOTSUP; +} + +#if IS_ENABLED(CONFIG_DCACHE_LINE_SIZE_DETECT) +size_t cache_data_line_size_get(void) +{ + return cache_cfg.data_line_size; +} +#endif /* IS_ENABLED(CONFIG_DCACHE_LINE_SIZE_DETECT) */ + +#if IS_ENABLED(CONFIG_ICACHE_LINE_SIZE_DETECT) +size_t cache_instr_line_size_get(void) +{ + return cache_cfg.instr_line_size; +} +#endif /* IS_ENABLED(CONFIG_ICACHE_LINE_SIZE_DETECT) */ + +static int andes_cache_init(void) +{ + unsigned long line_size; + + if (IS_ENABLED(CONFIG_ICACHE)) { + line_size = (csr_read(NDS_MICM_CFG) >> MICM_CFG_ISZ_SHIFT) & BIT_MASK(3); + + if (line_size == 0) { + LOG_ERR("Platform doesn't support I-cache, " + "please disable CONFIG_ICACHE"); + } +#if IS_ENABLED(CONFIG_ICACHE_LINE_SIZE_DETECT) + /* Icache line size */ + if (line_size <= 5) { + cache_cfg.instr_line_size = 1 << (line_size + 2); + } else { + LOG_ERR("Unknown line size of I-cache"); + } +#elif (CONFIG_ICACHE_LINE_SIZE != 0) + cache_cfg.instr_line_size = CONFIG_ICACHE_LINE_SIZE; +#elif DT_NODE_HAS_PROP(DT_PATH(cpus, cpu_0), i_cache_line_size) + cache_cfg.instr_line_size = + DT_PROP(DT_PATH(cpus, cpu_0), "i_cache_line_size"); +#else + LOG_ERR("Please specific the i-cache-line-size " + "CPU0 property of the DT"); +#endif /* IS_ENABLED(CONFIG_ICACHE_LINE_SIZE_DETECT) */ + } + + if (IS_ENABLED(CONFIG_DCACHE)) { + line_size = (csr_read(NDS_MDCM_CFG) >> MDCM_CFG_DSZ_SHIFT) & BIT_MASK(3); + if (line_size == 0) { + LOG_ERR("Platform doesn't support D-cache, " + "please disable CONFIG_DCACHE"); + } +#if IS_ENABLED(CONFIG_DCACHE_LINE_SIZE_DETECT) + /* Dcache line size */ + if (line_size <= 5) { + cache_cfg.data_line_size = 1 << (line_size + 2); + } else { + LOG_ERR("Unknown line size of D-cache"); + } +#elif (CONFIG_DCACHE_LINE_SIZE != 0) + cache_cfg.data_line_size = CONFIG_DCACHE_LINE_SIZE; +#elif DT_NODE_HAS_PROP(DT_PATH(cpus, cpu_0), d_cache_line_size) + cache_cfg.data_line_size = + DT_PROP(DT_PATH(cpus, cpu_0), "d_cache_line_size"); +#else + LOG_ERR("Please specific the d-cache-line-size " + "CPU0 property of the DT"); +#endif /* IS_ENABLED(CONFIG_DCACHE_LINE_SIZE_DETECT) */ + } + + if (!(csr_read(NDS_MMSC_CFG) & MMSC_CFG_CCTLCSR)) { + LOG_ERR("Platform doesn't support I/D cache operation"); + } + + if (csr_read(NDS_MMSC_CFG) & MMSC_CFG_VCCTL_2) { + if (IS_ENABLED(CONFIG_PMP_STACK_GUARD)) { + csr_set(NDS_MCACHE_CTL, MCACHE_CTL_CCTL_SUEN); + } + } + + cache_cfg.l2_cache_size = nds_l2_cache_init(); + cache_cfg.l2_cache_inclusive = nds_l2_cache_is_inclusive(); + + return 0; +} + +SYS_INIT(andes_cache_init, PRE_KERNEL_1, CONFIG_CACHE_ANDES_INIT_PRIORITY); diff --git a/drivers/cache/cache_andes_l2.h b/drivers/cache/cache_andes_l2.h new file mode 100644 index 00000000000..d6de7551821 --- /dev/null +++ b/drivers/cache/cache_andes_l2.h @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2024 Andes Technology Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_CACHE_CACHE_ANDES_L2_H_ +#define ZEPHYR_DRIVERS_CACHE_CACHE_ANDES_L2_H_ + +#include +#include +#include + +#define L2C_BASE DT_REG_ADDR_BY_IDX(DT_INST(0, andestech_l2c), 0) + +/* L2 cache Register Offset */ +#define L2C_CONFIG (L2C_BASE + 0x00) +#define L2C_CTRL (L2C_BASE + 0x08) +#define L2C_CCTLCMD(hart_id) \ + (L2C_BASE + 0x40 + (hart_id * l2_cache_cfg.cmd_offset)) +#define L2C_CCTLACC(hart_id) \ + (L2C_BASE + 0x48 + (hart_id * l2_cache_cfg.cmd_offset)) +#define L2C_CCTLST(hart_id) \ + (L2C_BASE + 0x80 + (hart_id * l2_cache_cfg.status_offset)) + +/* L2 cache config registers bitfields */ +#define L2C_CONFIG_SIZE_SHIFT 7 +#define L2C_CONFIG_MAP BIT(20) +#define L2C_CONFIG_VERSION_SHIFT 24 + +/* L2 cache control registers bitfields */ +#define L2C_CTRL_CEN BIT(0) +#define L2C_CTRL_IPFDPT_3 GENMASK(4, 3) +#define L2C_CTRL_DPFDPT_8 GENMASK(7, 6) + +/* L2 cache CCTL Access Line registers bitfields */ +#define L2C_CCTLACC_WAY_SHIFT 28 + +/* L2 CCTL Command */ +#define CCTL_L2_IX_INVAL 0x00 +#define CCTL_L2_IX_WB 0x01 +#define CCTL_L2_PA_INVAL 0x08 +#define CCTL_L2_PA_WB 0x09 +#define CCTL_L2_PA_WBINVAL 0x0a +#define CCTL_L2_WBINVAL_ALL 0x12 + +#define K_CACHE_WB BIT(0) +#define K_CACHE_INVD BIT(1) +#define K_CACHE_WB_INVD (K_CACHE_WB | K_CACHE_INVD) + +struct nds_l2_cache_config { + uint32_t size; + uint32_t cmd_offset; + uint32_t status_offset; + uint16_t status_shift; + uint8_t version; +}; + +static struct nds_l2_cache_config l2_cache_cfg; + +static ALWAYS_INLINE int nds_l2_cache_is_inclusive(void) +{ + return IS_ENABLED(CONFIG_L2C_INCLUSIVE_POLICY) && + (l2_cache_cfg.version > 15); + +} + +static ALWAYS_INLINE void nds_l2_cache_wait_status(uint8_t hart_id) +{ + uint32_t status; + + do { + status = sys_read32(L2C_CCTLST(hart_id)); + status >>= hart_id * l2_cache_cfg.status_shift; + status &= BIT_MASK(4); + } while (status == 1); +} + +static ALWAYS_INLINE int nds_l2_cache_all(int op) +{ + /* L2 cache fixed to 64 byte cache line size and 16 way */ + const unsigned long line_size = 64, ways = 16; + unsigned long sets, index, cmd; + uint8_t hart_id; + unsigned long status = csr_read(mstatus); + + if (!l2_cache_cfg.size) { + return -ENOTSUP; + } + + if (csr_read(NDS_MMSC_CFG) & MMSC_CFG_VCCTL_2) { + if ((status & MSTATUS_MPRV) && !(status & MSTATUS_MPP)) { + if (!nds_l2_cache_is_inclusive()) { + return -ENOTSUP; + } + } + } + + switch (op) { + case K_CACHE_WB: + cmd = CCTL_L2_IX_WB; + break; + case K_CACHE_INVD: + cmd = CCTL_L2_IX_INVAL; + break; + case K_CACHE_WB_INVD: + cmd = CCTL_L2_WBINVAL_ALL; + break; + default: + return -ENOTSUP; + } + + hart_id = arch_proc_id(); + + if (op == K_CACHE_WB_INVD) { + sys_write32(CCTL_L2_WBINVAL_ALL, L2C_CCTLCMD(hart_id)); + + /* Wait L2 CCTL Commands finished */ + nds_l2_cache_wait_status(hart_id); + } else { + sets = l2_cache_cfg.size / (ways * line_size); + /* Invalidate all cache line by each way and each set */ + for (int j = 0; j < ways; j++) { + /* Index of way */ + index = j << L2C_CCTLACC_WAY_SHIFT; + for (int i = 0; i < sets; i++) { + /* Index of set */ + index += line_size; + + /* Invalidate each cache line */ + sys_write32(index, L2C_CCTLACC(hart_id)); + sys_write32(cmd, L2C_CCTLCMD(hart_id)); + + /* Wait L2 CCTL Commands finished */ + nds_l2_cache_wait_status(hart_id); + } + } + } + + return 0; +} + +static ALWAYS_INLINE int nds_l2_cache_range(void *addr, size_t size, int op) +{ + const unsigned long line_size = 64; + unsigned long last_byte, align_addr, cmd; + uint8_t hart_id; + + if (!l2_cache_cfg.size) { + return -ENOTSUP; + } + + switch (op) { + case K_CACHE_WB: + cmd = CCTL_L2_PA_WB; + break; + case K_CACHE_INVD: + cmd = CCTL_L2_PA_INVAL; + break; + case K_CACHE_WB_INVD: + cmd = CCTL_L2_PA_WBINVAL; + break; + default: + return -ENOTSUP; + } + + last_byte = (unsigned long)addr + size - 1; + align_addr = ROUND_DOWN(addr, line_size); + hart_id = arch_proc_id(); + + while (align_addr <= last_byte) { + sys_write32(align_addr, L2C_CCTLACC(hart_id)); + sys_write32(cmd, L2C_CCTLCMD(hart_id)); + align_addr += line_size; + + /* Wait L2 CCTL Commands finished */ + nds_l2_cache_wait_status(hart_id); + } + + return 0; +} + +static ALWAYS_INLINE void nds_l2_cache_enable(void) +{ + if (l2_cache_cfg.size) { + uint32_t l2c_ctrl = sys_read32(L2C_CTRL); + + if (!(l2c_ctrl & L2C_CTRL_CEN)) { + WRITE_BIT(l2c_ctrl, 0, true); + sys_write32(l2c_ctrl, L2C_CTRL); + } + } +} + +static ALWAYS_INLINE void nds_l2_cache_disable(void) +{ + if (l2_cache_cfg.size) { + uint32_t l2c_ctrl = sys_read32(L2C_CTRL); + + if (l2c_ctrl & L2C_CTRL_CEN) { + WRITE_BIT(l2c_ctrl, 0, false); + sys_write32(l2c_ctrl, L2C_CTRL); + } + } +} + +static ALWAYS_INLINE int nds_l2_cache_init(void) +{ + unsigned long line_size; + +#if IS_ENABLED(CONFIG_SYSCON) +#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(syscon), andestech_atcsmu100, okay) + uint32_t system_cfg; + const struct device *syscon_dev = DEVICE_DT_GET(DT_NODELABEL(syscon)); + + if (device_is_ready(syscon_dev)) { + /* Check L2 cache feature from SMU */ + syscon_read_reg(syscon_dev, 0x08, &system_cfg); + + /* Platform doesn't support L2 cache controller */ + if (!(system_cfg & BIT(8))) { + l2_cache_cfg.size = 0; + return 0; + } + } else { + LOG_ERR("Andes cache driver should be initialized after " + "syscon driver initialization"); + return 0; + } +#endif /* andestech_atcsmu100 dts node status okay */ +#endif /* IS_ENABLED(CONFIG_SYSCON) */ + + uint32_t l2c_ctrl; + + line_size = (sys_read32(L2C_CONFIG) >> L2C_CONFIG_SIZE_SHIFT) & BIT_MASK(7); + l2_cache_cfg.size = line_size * 128 * 1024; + + if (sys_read32(L2C_CONFIG) & L2C_CONFIG_MAP) { + l2_cache_cfg.cmd_offset = 0x10; + l2_cache_cfg.status_offset = 0; + l2_cache_cfg.status_shift = 4; + } else { + l2_cache_cfg.cmd_offset = 0x1000; + l2_cache_cfg.status_offset = 0x1000; + l2_cache_cfg.status_shift = 0; + } + + l2_cache_cfg.version = (sys_read32(L2C_CONFIG) >> L2C_CONFIG_VERSION_SHIFT) & BIT_MASK(8); + + /* Initializing L2 cache instruction, data prefetch depth */ + l2c_ctrl = sys_read32(L2C_CTRL); + l2c_ctrl |= (L2C_CTRL_IPFDPT_3 | L2C_CTRL_DPFDPT_8); + + /* Writeback and invalidate all I/D-Cache before setting L2C */ + __asm__ volatile ("fence.i"); + sys_write32(l2c_ctrl, L2C_CTRL); + + if (IS_ENABLED(CONFIG_SMP)) { + if (l2_cache_cfg.size) { + l2c_ctrl = sys_read32(L2C_CTRL); + + if (!(l2c_ctrl & L2C_CTRL_CEN)) { + WRITE_BIT(l2c_ctrl, 0, true); + sys_write32(l2c_ctrl, L2C_CTRL); + } + } + } + + return l2_cache_cfg.size; +} + +#endif /* ZEPHYR_DRIVERS_CACHE_CACHE_ANDES_L2_H_ */ diff --git a/drivers/can/Kconfig b/drivers/can/Kconfig index 4f929ba32f8..7f6b12453a2 100644 --- a/drivers/can/Kconfig +++ b/drivers/can/Kconfig @@ -23,6 +23,21 @@ config CAN_INIT_PRIORITY help CAN driver device initialization priority. +config CAN_DEFAULT_BITRATE + int "Default CAN bitrate" + default 125000 + help + Default initial CAN bitrate in bits/s. This can be overridden per CAN controller using the + "bus-speed" devicetree property. + +config CAN_DEFAULT_BITRATE_DATA + int "Default CAN data phase bitrate" + default 1000000 + depends on CAN_FD_MODE + help + Default initial CAN data phase bitrate in bits/s. This can be overridden per CAN controller + using the "bus-speed-data" devicetree property. + config CAN_SHELL bool "CAN shell" depends on SHELL diff --git a/drivers/can/Kconfig.mcux b/drivers/can/Kconfig.mcux index e995a19ab6f..a0e3e00fdda 100644 --- a/drivers/can/Kconfig.mcux +++ b/drivers/can/Kconfig.mcux @@ -59,5 +59,6 @@ config CAN_MCUX_MCAN depends on CLOCK_CONTROL select CAN_MCAN select PINCTRL + select RESET help Enable support for mcux mcan driver. diff --git a/drivers/can/can_common.c b/drivers/can/can_common.c index cb2e7c3ebcd..e1a51005861 100644 --- a/drivers/can/can_common.c +++ b/drivers/can/can_common.c @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -35,6 +36,25 @@ int z_impl_can_send(const struct device *dev, const struct can_frame *frame, void *user_data) { const struct can_driver_api *api = (const struct can_driver_api *)dev->api; + uint32_t id_mask; + + CHECKIF(frame == NULL) { + return -EINVAL; + } + + if ((frame->flags & CAN_FRAME_IDE) != 0U) { + id_mask = CAN_EXT_ID_MASK; + } else { + id_mask = CAN_STD_ID_MASK; + } + + CHECKIF((frame->id & ~(id_mask)) != 0U) { + LOG_ERR("invalid frame with %s (%d-bit) CAN ID 0x%0*x", + (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); + return -EINVAL; + } if (callback == NULL) { struct can_tx_default_cb_ctx ctx; @@ -55,6 +75,34 @@ int z_impl_can_send(const struct device *dev, const struct can_frame *frame, return api->send(dev, frame, timeout, callback, user_data); } +int can_add_rx_filter(const struct device *dev, can_rx_callback_t callback, + void *user_data, const struct can_filter *filter) +{ + const struct can_driver_api *api = (const struct can_driver_api *)dev->api; + uint32_t id_mask; + + CHECKIF(callback == NULL || filter == NULL) { + return -EINVAL; + } + + if ((filter->flags & CAN_FILTER_IDE) != 0U) { + id_mask = CAN_EXT_ID_MASK; + } else { + id_mask = CAN_STD_ID_MASK; + } + + CHECKIF(((filter->id & ~(id_mask)) != 0U) || ((filter->mask & ~(id_mask)) != 0U)) { + LOG_ERR("invalid 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); + return -EINVAL; + } + + return api->add_rx_filter(dev, callback, user_data, filter); +} + static void can_msgq_put(const struct device *dev, struct can_frame *frame, void *user_data) { struct k_msgq *msgq = (struct k_msgq *)user_data; @@ -351,22 +399,12 @@ int z_impl_can_set_timing(const struct device *dev, int z_impl_can_set_bitrate(const struct device *dev, uint32_t bitrate) { struct can_timing timing = { 0 }; - uint32_t min_bitrate; - uint32_t max_bitrate; + uint32_t min = can_get_bitrate_min(dev); + uint32_t max = can_get_bitrate_max(dev); uint16_t sample_pnt; int ret; - (void)can_get_min_bitrate(dev, &min_bitrate); - - ret = can_get_max_bitrate(dev, &max_bitrate); - if (ret == -ENOSYS) { - /* Maximum bitrate unknown */ - max_bitrate = 0; - } else if (ret < 0) { - return ret; - } - - if ((bitrate < min_bitrate) || (((max_bitrate > 0) && (bitrate > max_bitrate)))) { + if ((bitrate < min) || (bitrate > max)) { return -ENOTSUP; } @@ -407,22 +445,12 @@ int z_impl_can_set_timing_data(const struct device *dev, int z_impl_can_set_bitrate_data(const struct device *dev, uint32_t bitrate_data) { struct can_timing timing_data = { 0 }; - uint32_t min_bitrate; - uint32_t max_bitrate; + uint32_t min = can_get_bitrate_min(dev); + uint32_t max = can_get_bitrate_max(dev); uint16_t sample_pnt; int ret; - (void)can_get_min_bitrate(dev, &min_bitrate); - - ret = can_get_max_bitrate(dev, &max_bitrate); - if (ret == -ENOSYS) { - /* Maximum bitrate unknown */ - max_bitrate = 0; - } else if (ret < 0) { - return ret; - } - - if ((bitrate_data < min_bitrate) || ((max_bitrate > 0) && (bitrate_data > max_bitrate))) { + if ((bitrate_data < min) || (bitrate_data > max)) { return -ENOTSUP; } diff --git a/drivers/can/can_fake.c b/drivers/can/can_fake.c index 508894b53d0..3b345d5a7da 100644 --- a/drivers/can/can_fake.c +++ b/drivers/can/can_fake.c @@ -146,16 +146,22 @@ static const struct can_driver_api fake_can_driver_api = { #endif /* CONFIG_CAN_FD_MODE */ }; -#define FAKE_CAN_INIT(inst) \ - static const struct fake_can_config fake_can_config_##inst = { \ - .common = CAN_DT_DRIVER_CONFIG_INST_GET(inst, 0, 0), \ - }; \ - \ - 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, \ +#ifdef CONFIG_CAN_FD_MODE +#define FAKE_CAN_MAX_BITRATE 8000000 +#else /* CONFIG_CAN_FD_MODE */ +#define FAKE_CAN_MAX_BITRATE 1000000 +#endif /* !CONFIG_CAN_FD_MODE */ + +#define FAKE_CAN_INIT(inst) \ + static const struct fake_can_config fake_can_config_##inst = { \ + .common = CAN_DT_DRIVER_CONFIG_INST_GET(inst, 0, FAKE_CAN_MAX_BITRATE), \ + }; \ + \ + 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); DT_INST_FOREACH_STATUS_OKAY(FAKE_CAN_INIT) diff --git a/drivers/can/can_handlers.c b/drivers/can/can_handlers.c index a7f89d5837a..b762b80d920 100644 --- a/drivers/can/can_handlers.c +++ b/drivers/can/can_handlers.c @@ -45,25 +45,21 @@ static inline int z_vrfy_can_get_core_clock(const struct device *dev, } #include -static inline int z_vrfy_can_get_min_bitrate(const struct device *dev, - uint32_t *min_bitrate) +static inline uint32_t z_vrfy_can_get_bitrate_min(const struct device *dev) { K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_CAN)); - K_OOPS(K_SYSCALL_MEMORY_WRITE(min_bitrate, sizeof(*min_bitrate))); - return z_impl_can_get_min_bitrate(dev, min_bitrate); + return z_impl_can_get_bitrate_min(dev); } -#include +#include -static inline int z_vrfy_can_get_max_bitrate(const struct device *dev, - uint32_t *max_bitrate) +static inline uint32_t z_vrfy_can_get_bitrate_max(const struct device *dev) { 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); + return z_impl_can_get_bitrate_max(dev); } -#include +#include static inline const struct can_timing *z_vrfy_can_get_timing_min(const struct device *dev) { diff --git a/drivers/can/can_loopback.c b/drivers/can/can_loopback.c index 433b623de6a..9d287768593 100644 --- a/drivers/can/can_loopback.c +++ b/drivers/can/can_loopback.c @@ -112,8 +112,6 @@ static int can_loopback_send(const struct device *dev, uint8_t max_dlc = CAN_MAX_DLC; int ret; - __ASSERT_NO_MSG(callback != NULL); - 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", @@ -442,17 +440,23 @@ static int can_loopback_init(const struct device *dev) return 0; } -#define CAN_LOOPBACK_INIT(inst) \ - static const struct can_loopback_config can_loopback_config_##inst = { \ - .common = CAN_DT_DRIVER_CONFIG_INST_GET(inst, 0, 0), \ - }; \ - \ - 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, \ +#ifdef CONFIG_CAN_FD_MODE +#define CAN_LOOPBACK_MAX_BITRATE 8000000 +#else /* CONFIG_CAN_FD_MODE */ +#define CAN_LOOPBACK_MAX_BITRATE 1000000 +#endif /* !CONFIG_CAN_FD_MODE */ + +#define CAN_LOOPBACK_INIT(inst) \ + static const struct can_loopback_config can_loopback_config_##inst = { \ + .common = CAN_DT_DRIVER_CONFIG_INST_GET(inst, 0, CAN_LOOPBACK_MAX_BITRATE), \ + }; \ + \ + 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 4a83017196b..9f3d41368b9 100644 --- a/drivers/can/can_mcan.c +++ b/drivers/can/can_mcan.c @@ -463,7 +463,10 @@ static void can_mcan_state_change_handler(const struct device *dev) uint32_t cccr; int err; - (void)can_mcan_get_state(dev, &state, &err_cnt); + err = can_mcan_get_state(dev, &state, &err_cnt); + if (err != 0) { + return; + } if (state_cb != NULL) { state_cb(dev, state, err_cnt, state_cb_data); @@ -921,8 +924,6 @@ int can_mcan_send(const struct device *dev, const struct can_frame *frame, k_tim (frame->flags & CAN_FRAME_FDF) != 0U ? "FD frame" : "", (frame->flags & CAN_FRAME_BRS) != 0U ? "BRS" : ""); - __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) { @@ -1164,10 +1165,6 @@ int can_mcan_add_rx_filter(const struct device *dev, can_rx_callback_t callback, const struct can_mcan_callbacks *cbs = config->callbacks; int filter_id; - if (callback == NULL) { - return -EINVAL; - } - if ((filter->flags & ~(CAN_FILTER_IDE)) != 0U) { LOG_ERR("unsupported CAN filter flags 0x%02x", filter->flags); return -ENOTSUP; diff --git a/drivers/can/can_mcp2515.c b/drivers/can/can_mcp2515.c index 283bd325262..b7720a7ab47 100644 --- a/drivers/can/can_mcp2515.c +++ b/drivers/can/can_mcp2515.c @@ -537,8 +537,6 @@ static int mcp2515_send(const struct device *dev, uint8_t len; uint8_t tx_frame[MCP2515_FRAME_LEN]; - __ASSERT_NO_MSG(callback != NULL); - if (frame->dlc > CAN_MAX_DLC) { LOG_ERR("DLC of %d exceeds maximum (%d)", frame->dlc, CAN_MAX_DLC); diff --git a/drivers/can/can_mcp251xfd.c b/drivers/can/can_mcp251xfd.c index d11f64d6dbb..8e1fef06168 100644 --- a/drivers/can/can_mcp251xfd.c +++ b/drivers/can/can_mcp251xfd.c @@ -496,8 +496,6 @@ static int mcp251xfd_send(const struct device *dev, const struct can_frame *msg, msg->flags & CAN_FRAME_FDF ? "FD frame" : "", msg->flags & CAN_FRAME_BRS ? "BRS" : ""); - __ASSERT_NO_MSG(callback != NULL); - if (!dev_data->common.started) { return -ENETDOWN; } @@ -559,7 +557,6 @@ static int mcp251xfd_add_rx_filter(const struct device *dev, can_rx_callback_t r int filter_idx; int ret; - __ASSERT(rx_cb != NULL, "rx_cb can not be null"); k_mutex_lock(&dev_data->mutex, K_FOREVER); for (filter_idx = 0; filter_idx < CONFIG_CAN_MAX_FILTER ; filter_idx++) { diff --git a/drivers/can/can_mcux_flexcan.c b/drivers/can/can_mcux_flexcan.c index 38642ca3d99..c4109c89c61 100644 --- a/drivers/can/can_mcux_flexcan.c +++ b/drivers/can/can_mcux_flexcan.c @@ -671,8 +671,6 @@ static int mcux_flexcan_send(const struct device *dev, uint8_t max_dlc = CAN_MAX_DLC; int alloc; - __ASSERT_NO_MSG(callback != NULL); - 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 | @@ -772,8 +770,6 @@ static int mcux_flexcan_add_rx_filter(const struct device *dev, int alloc = -ENOSPC; int i; - __ASSERT_NO_MSG(callback); - if ((filter->flags & ~(CAN_FILTER_IDE)) != 0) { LOG_ERR("unsupported CAN filter flags 0x%02x", filter->flags); return -ENOTSUP; @@ -1377,7 +1373,7 @@ static const struct can_driver_api mcux_flexcan_fd_driver_api = { #ifdef CONFIG_CAN_MCUX_FLEXCAN_FD #define FLEXCAN_MAX_BITRATE(id) \ - COND_CODE_1(DT_NODE_HAS_COMPAT(DT_DRV_INST(id), FLEXCAN_FD_DRV_COMPAT), \ + COND_CODE_1(DT_INST_NODE_HAS_COMPAT(id, FLEXCAN_FD_DRV_COMPAT), \ (8000000), (1000000)) #else /* CONFIG_CAN_MCUX_FLEXCAN_FD */ #define FLEXCAN_MAX_BITRATE(id) 1000000 @@ -1385,7 +1381,7 @@ static const struct can_driver_api mcux_flexcan_fd_driver_api = { #ifdef CONFIG_CAN_MCUX_FLEXCAN_FD #define FLEXCAN_DRIVER_API(id) \ - COND_CODE_1(DT_NODE_HAS_COMPAT(DT_DRV_INST(id), FLEXCAN_FD_DRV_COMPAT), \ + COND_CODE_1(DT_INST_NODE_HAS_COMPAT(id, FLEXCAN_FD_DRV_COMPAT), \ (mcux_flexcan_fd_driver_api), \ (mcux_flexcan_driver_api)) #else /* CONFIG_CAN_MCUX_FLEXCAN_FD */ @@ -1407,7 +1403,7 @@ static const struct can_driver_api mcux_flexcan_fd_driver_api = { DT_INST_CLOCKS_CELL(id, name), \ .clk_source = DT_INST_PROP(id, clk_source), \ IF_ENABLED(CONFIG_CAN_MCUX_FLEXCAN_FD, ( \ - .flexcan_fd = DT_NODE_HAS_COMPAT(DT_DRV_INST(id), FLEXCAN_FD_DRV_COMPAT), \ + .flexcan_fd = DT_INST_NODE_HAS_COMPAT(id, FLEXCAN_FD_DRV_COMPAT), \ )) \ .irq_config_func = mcux_flexcan_irq_config_##id, \ .irq_enable_func = mcux_flexcan_irq_enable_##id, \ diff --git a/drivers/can/can_mcux_mcan.c b/drivers/can/can_mcux_mcan.c index 2ca5d3e0277..5a984279ae5 100644 --- a/drivers/can/can_mcux_mcan.c +++ b/drivers/can/can_mcux_mcan.c @@ -11,6 +11,7 @@ #include #include #include +#include LOG_MODULE_REGISTER(can_mcux_mcan, CONFIG_CAN_LOG_LEVEL); @@ -27,6 +28,7 @@ struct mcux_mcan_config { clock_control_subsys_t clock_subsys; void (*irq_config_func)(const struct device *dev); const struct pinctrl_dev_config *pincfg; + const struct reset_dt_spec reset; }; static int mcux_mcan_read_reg(const struct device *dev, uint16_t reg, uint32_t *val) @@ -91,6 +93,16 @@ static int mcux_mcan_init(const struct device *dev) return -ENODEV; } + if (!device_is_ready(mcux_config->reset.dev)) { + LOG_ERR("Reset device not ready"); + return -ENODEV; + } + + err = reset_line_toggle(mcux_config->reset.dev, mcux_config->reset.id); + if (err) { + return err; + } + err = pinctrl_apply_state(mcux_config->pincfg, PINCTRL_STATE_DEFAULT); if (err) { return err; @@ -197,6 +209,7 @@ static const struct can_mcan_ops mcux_mcan_ops = { DT_INST_CLOCKS_CELL(n, name), \ .irq_config_func = mcux_mcan_irq_config_##n, \ .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + .reset = RESET_DT_SPEC_INST_GET(n), \ }; \ \ static const struct can_mcan_config can_mcan_config_##n = \ diff --git a/drivers/can/can_native_linux.c b/drivers/can/can_native_linux.c index fb3ff59caa9..040e6080726 100644 --- a/drivers/can/can_native_linux.c +++ b/drivers/can/can_native_linux.c @@ -138,8 +138,6 @@ static int can_native_linux_send(const struct device *dev, const struct can_fram (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) { diff --git a/drivers/can/can_nxp_s32_canxl.c b/drivers/can/can_nxp_s32_canxl.c index a5683750696..9d1e2626ab0 100644 --- a/drivers/can/can_nxp_s32_canxl.c +++ b/drivers/can/can_nxp_s32_canxl.c @@ -464,8 +464,6 @@ static int can_nxp_s32_add_rx_filter(const struct device *dev, int mb_indx; uint32_t mask; - __ASSERT_NO_MSG(callback != NULL); - if ((filter->flags & ~(CAN_FILTER_IDE)) != 0) { LOG_ERR("unsupported CAN filter flags 0x%02x", filter->flags); return -ENOTSUP; @@ -555,8 +553,6 @@ static int can_nxp_s32_send(const struct device *dev, enum can_state state; int alloc, mb_indx; - __ASSERT_NO_MSG(callback != NULL); - #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); diff --git a/drivers/can/can_rcar.c b/drivers/can/can_rcar.c index eacebb9222b..d1607a6797a 100644 --- a/drivers/can/can_rcar.c +++ b/drivers/can/can_rcar.c @@ -888,9 +888,6 @@ static int can_rcar_send(const struct device *dev, const struct can_frame *frame "extended" : "standard" , (frame->flags & CAN_FRAME_RTR) != 0 ? "yes" : "no"); - __ASSERT_NO_MSG(callback != NULL); - __ASSERT(frame->dlc == 0U || frame->data != NULL, "Dataptr is null"); - if (frame->dlc > CAN_MAX_DLC) { LOG_ERR("DLC of %d exceeds maximum (%d)", frame->dlc, CAN_MAX_DLC); diff --git a/drivers/can/can_shell.c b/drivers/can/can_shell.c index 66cb4c127c9..6c0744879ae 100644 --- a/drivers/can/can_shell.c +++ b/drivers/can/can_shell.c @@ -280,9 +280,9 @@ static int cmd_can_show(const struct shell *sh, size_t argc, char **argv) const struct can_timing *timing_max; struct can_bus_err_cnt err_cnt; enum can_state state; - uint32_t max_bitrate = 0; - int max_std_filters = 0; - int max_ext_filters = 0; + uint32_t bitrate_max; + int max_std_filters; + int max_ext_filters; uint32_t core_clock; can_mode_t cap; int err; @@ -298,11 +298,7 @@ static int cmd_can_show(const struct shell *sh, size_t argc, char **argv) return err; } - err = can_get_max_bitrate(dev, &max_bitrate); - if (err != 0 && err != -ENOSYS) { - shell_error(sh, "failed to get maximum bitrate (err %d)", err); - return err; - } + bitrate_max = can_get_bitrate_max(dev); max_std_filters = can_get_max_filters(dev, false); if (max_std_filters < 0 && max_std_filters != -ENOSYS) { @@ -329,7 +325,7 @@ static int cmd_can_show(const struct shell *sh, size_t argc, char **argv) } shell_print(sh, "core clock: %d Hz", core_clock); - shell_print(sh, "max bitrate: %d bps", max_bitrate); + shell_print(sh, "max bitrate: %d bps", bitrate_max); shell_print(sh, "max std filters: %d", max_std_filters); shell_print(sh, "max ext filters: %d", max_ext_filters); diff --git a/drivers/can/can_sja1000.c b/drivers/can/can_sja1000.c index b9cdc146822..871f0fdb00d 100644 --- a/drivers/can/can_sja1000.c +++ b/drivers/can/can_sja1000.c @@ -378,8 +378,6 @@ int can_sja1000_send(const struct device *dev, const struct can_frame *frame, k_ uint8_t cmr; uint8_t sr; - __ASSERT_NO_MSG(callback != NULL); - if (frame->dlc > CAN_MAX_DLC) { LOG_ERR("TX frame DLC %u exceeds maximum (%d)", frame->dlc, CAN_MAX_DLC); return -EINVAL; diff --git a/drivers/can/can_stm32_bxcan.c b/drivers/can/can_stm32_bxcan.c index c89e1c3724e..c21099c04b3 100644 --- a/drivers/can/can_stm32_bxcan.c +++ b/drivers/can/can_stm32_bxcan.c @@ -761,7 +761,7 @@ static int can_stm32_send(const struct device *dev, const struct can_frame *fram const struct can_stm32_config *cfg = dev->config; struct can_stm32_data *data = dev->data; CAN_TypeDef *can = cfg->can; - uint32_t transmit_status_register = can->TSR; + uint32_t transmit_status_register = 0; CAN_TxMailBox_TypeDef *mailbox = NULL; struct can_stm32_mailbox *mb = NULL; @@ -774,9 +774,6 @@ static int can_stm32_send(const struct device *dev, const struct can_frame *fram , (frame->flags & CAN_FRAME_IDE) != 0 ? "extended" : "standard" , (frame->flags & CAN_FRAME_RTR) != 0 ? "yes" : "no"); - __ASSERT_NO_MSG(callback != NULL); - __ASSERT(frame->dlc == 0U || frame->data != NULL, "Dataptr is null"); - if (frame->dlc > CAN_MAX_DLC) { LOG_ERR("DLC of %d exceeds maximum (%d)", frame->dlc, CAN_MAX_DLC); return -EINVAL; @@ -796,6 +793,7 @@ static int can_stm32_send(const struct device *dev, const struct can_frame *fram } k_mutex_lock(&data->inst_mutex, K_FOREVER); + transmit_status_register = can->TSR; while (!(transmit_status_register & CAN_TSR_TME)) { k_mutex_unlock(&data->inst_mutex); LOG_DBG("Transmit buffer full"); diff --git a/drivers/can/can_xmc4xxx.c b/drivers/can/can_xmc4xxx.c index cde7cf0654d..8eddf05b96e 100644 --- a/drivers/can/can_xmc4xxx.c +++ b/drivers/can/can_xmc4xxx.c @@ -156,8 +156,6 @@ static int can_xmc4xxx_send(const struct device *dev, const struct can_frame *ms 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; } diff --git a/drivers/can/transceiver/can_transceiver_gpio.c b/drivers/can/transceiver/can_transceiver_gpio.c index e6aaacc8c34..3f7bbca688f 100644 --- a/drivers/can/transceiver/can_transceiver_gpio.c +++ b/drivers/can/transceiver/can_transceiver_gpio.c @@ -120,6 +120,11 @@ static const struct can_transceiver_driver_api can_transceiver_gpio_driver_api = (.name##_gpio = GPIO_DT_SPEC_INST_GET(inst, name##_gpios),)) #define CAN_TRANSCEIVER_GPIO_INIT(inst) \ + BUILD_ASSERT(DT_INST_NODE_HAS_PROP(inst, enable_gpios) || \ + DT_INST_NODE_HAS_PROP(inst, standby_gpios), \ + "Missing GPIO property on " \ + DT_NODE_FULL_NAME(DT_DRV_INST(inst))); \ + \ static const struct can_transceiver_gpio_config can_transceiver_gpio_config_##inst = { \ CAN_TRANSCEIVER_GPIO_COND(inst, enable) \ CAN_TRANSCEIVER_GPIO_COND(inst, standby) \ diff --git a/drivers/clock_control/Kconfig.smartbond b/drivers/clock_control/Kconfig.smartbond index d20907c6001..49ac7c7c660 100644 --- a/drivers/clock_control/Kconfig.smartbond +++ b/drivers/clock_control/Kconfig.smartbond @@ -8,3 +8,14 @@ config CLOCK_CONTROL_SMARTBOND depends on SOC_FAMILY_RENESAS_SMARTBOND help Enable driver for Clock Control subsystem found in SmartBond + +if CLOCK_CONTROL_SMARTBOND + +config SMARTBOND_LP_OSC_CALIBRATION_INTERVAL + int "Low-power oscillators calibration interval" + default 1 + range 1 10 + help + Time in seconds between calibration of low power clock RC32K and RCX. + +endif # CLOCK_CONTROL_SMARTBOND diff --git a/drivers/clock_control/clock_control_mcux_ccm_rev2.c b/drivers/clock_control/clock_control_mcux_ccm_rev2.c index 877d43fc7cd..f3e7c59aea3 100644 --- a/drivers/clock_control/clock_control_mcux_ccm_rev2.c +++ b/drivers/clock_control/clock_control_mcux_ccm_rev2.c @@ -133,6 +133,12 @@ static int mcux_ccm_get_subsys_rate(const struct device *dev, return 0; #endif +#ifdef CONFIG_COUNTER_MCUX_TPM + case IMX_CCM_TPM_CLK: + clock_root = kCLOCK_Root_Tpm1 + instance; + break; +#endif + #ifdef CONFIG_MEMC_MCUX_FLEXSPI case IMX_CCM_FLEXSPI_CLK: clock_root = kCLOCK_Root_Flexspi1; @@ -146,6 +152,12 @@ static int mcux_ccm_get_subsys_rate(const struct device *dev, clock_root = kCLOCK_Root_Bus + instance; break; #endif + +#ifdef CONFIG_ADC_MCUX_LPADC + case IMX_CCM_LPADC1_CLK: + clock_root = kCLOCK_Root_Adc1 + instance; + break; +#endif default: return -EINVAL; } diff --git a/drivers/clock_control/clock_control_mcux_scg.c b/drivers/clock_control/clock_control_mcux_scg.c index 690c133dd16..526bb06bc7d 100644 --- a/drivers/clock_control/clock_control_mcux_scg.c +++ b/drivers/clock_control/clock_control_mcux_scg.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2019-2021 Vestas Wind Systems A/S + * Copyright 2024 NXP * * Based on clock_control_mcux_sim.c, which is: * Copyright (c) 2017, NXP @@ -60,33 +61,57 @@ static int mcux_scg_get_rate(const struct device *dev, case KINETIS_SCG_FIRC_CLK: clock_name = kCLOCK_ScgFircClk; break; +#if (defined(FSL_FEATURE_SCG_HAS_SPLL) && FSL_FEATURE_SCG_HAS_SPLL) case KINETIS_SCG_SPLL_CLK: clock_name = kCLOCK_ScgSysPllClk; break; +#endif /* (defined(FSL_FEATURE_SCG_HAS_SPLL) && FSL_FEATURE_SCG_HAS_SPLL) */ +#if (defined(FSL_FEATURE_SCG_HAS_LPFLL) && FSL_FEATURE_SCG_HAS_LPFLL) + case KINETIS_SCG_SPLL_CLK: + clock_name = kCLOCK_ScgLpFllClk; + break; +#endif /* (defined(FSL_FEATURE_SCG_HAS_LPFLL) && FSL_FEATURE_SCG_HAS_LPFLL) */ +#if (defined(FSL_FEATURE_SCG_HAS_SOSCDIV1) && FSL_FEATURE_SCG_HAS_SOSCDIV1) case KINETIS_SCG_SOSC_ASYNC_DIV1_CLK: clock_name = kCLOCK_ScgSysOscAsyncDiv1Clk; break; +#endif /* (defined(FSL_FEATURE_SCG_HAS_SOSCDIV1) && FSL_FEATURE_SCG_HAS_SOSCDIV1) */ case KINETIS_SCG_SOSC_ASYNC_DIV2_CLK: clock_name = kCLOCK_ScgSysOscAsyncDiv2Clk; break; +#if (defined(FSL_FEATURE_SCG_HAS_SIRCDIV1) && FSL_FEATURE_SCG_HAS_SIRCDIV1) case KINETIS_SCG_SIRC_ASYNC_DIV1_CLK: clock_name = kCLOCK_ScgSircAsyncDiv1Clk; break; +#endif /* (defined(FSL_FEATURE_SCG_HAS_SIRCDIV1) && FSL_FEATURE_SCG_HAS_SIRCDIV1) */ case KINETIS_SCG_SIRC_ASYNC_DIV2_CLK: clock_name = kCLOCK_ScgSircAsyncDiv2Clk; break; +#if (defined(FSL_FEATURE_FSL_FEATURE_SCG_HAS_FIRCDIV1) && FSL_FEATURE_SCG_HAS_FIRCDIV1) case KINETIS_SCG_FIRC_ASYNC_DIV1_CLK: clock_name = kCLOCK_ScgFircAsyncDiv1Clk; break; +#endif /* (defined(FSL_FEATURE_FSL_FEATURE_SCG_HAS_FIRCDIV1) && FSL_FEATURE_SCG_HAS_FIRCDIV1) */ case KINETIS_SCG_FIRC_ASYNC_DIV2_CLK: clock_name = kCLOCK_ScgFircAsyncDiv2Clk; break; +#if (defined(FSL_FEATURE_SCG_HAS_SPLLDIV1) && FSL_FEATURE_SCG_HAS_SPLLDIV1) case KINETIS_SCG_SPLL_ASYNC_DIV1_CLK: clock_name = kCLOCK_ScgSysPllAsyncDiv1Clk; break; +#endif /* (defined(FSL_FEATURE_SCG_HAS_SPLLDIV1) && FSL_FEATURE_SCG_HAS_SPLLDIV1) */ +#if (defined(FSL_FEATURE_SCG_HAS_SPLL) && FSL_FEATURE_SCG_HAS_SPLL) case KINETIS_SCG_SPLL_ASYNC_DIV2_CLK: clock_name = kCLOCK_ScgSysPllAsyncDiv2Clk; break; +#endif /* (defined(FSL_FEATURE_SCG_HAS_SPLL) && FSL_FEATURE_SCG_HAS_SPLL) */ +#if (defined(FSL_FEATURE_SCG_HAS_FLLDIV1) && FSL_FEATURE_SCG_HAS_FLLDIV1) + case KINETIS_SCG_LPFLL_ASYNC_DIV2_CLK: + clock_name = kCLOCK_ScgSysLPFllAsyncDiv2Clk; + break; +#endif /* (defined(FSL_FEATURE_SCG_HAS_FLLDIV1) && FSL_FEATURE_SCG_HAS_FLLDIV1) */ + + default: LOG_ERR("Unsupported clock name"); return -EINVAL; diff --git a/drivers/clock_control/clock_control_mcux_sim.c b/drivers/clock_control/clock_control_mcux_sim.c index ed74ff941f5..8fdaa4a0ac5 100644 --- a/drivers/clock_control/clock_control_mcux_sim.c +++ b/drivers/clock_control/clock_control_mcux_sim.c @@ -54,6 +54,9 @@ static int mcux_sim_get_subsys_rate(const struct device *dev, case KINETIS_SIM_ENET_CLK: clock_name = kCLOCK_CoreSysClk; break; + case KINETIS_SIM_ENET_1588_CLK: + clock_name = kCLOCK_Osc0ErClk; + 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 45f2d9cf47f..93a9f1db4ac 100644 --- a/drivers/clock_control/clock_control_mcux_syscon.c +++ b/drivers/clock_control/clock_control_mcux_syscon.c @@ -297,6 +297,21 @@ static int mcux_lpc_syscon_clock_control_get_subsys_rate( *rate = CLOCK_GetLcdClkFreq(); break; #endif + +#if defined(CONFIG_ADC_MCUX_LPADC) + case MCUX_LPADC1_CLK: +#if (FSL_FEATURE_SOC_LPADC_COUNT == 1) + *rate = CLOCK_GetAdcClkFreq(); +#else + *rate = CLOCK_GetAdcClkFreq(0); +#endif + break; +#if (FSL_FEATURE_SOC_LPADC_COUNT == 2) + case MCUX_LPADC2_CLK: + *rate = CLOCK_GetAdcClkFreq(1); + break; +#endif +#endif /* CONFIG_ADC_MCUX_LPADC */ } return 0; diff --git a/drivers/clock_control/clock_control_npcx.c b/drivers/clock_control/clock_control_npcx.c index dcc4a925c99..eec3604aa77 100644 --- a/drivers/clock_control/clock_control_npcx.c +++ b/drivers/clock_control/clock_control_npcx.c @@ -105,6 +105,9 @@ static int npcx_clock_control_get_subsys_rate(const struct device *dev, case NPCX_CLOCK_BUS_FMCLK: *rate = FMCLK; break; + case NPCX_CLOCK_BUS_MCLKD: + *rate = OFMCLK/(MCLKD_SL + 1); + break; default: *rate = 0U; /* Invalid parameters */ @@ -185,6 +188,13 @@ BUILD_ASSERT(APBSRC_CLK / (APB4DIV_VAL + 1) <= MAX_OFMCLK && (APB4DIV_VAL + 1) % (FPRED_VAL + 1) == 0, "Invalid APB4_CLK setting"); #endif +#if defined(CONFIG_I3C_NPCX) +BUILD_ASSERT(OFMCLK / (MCLKD_SL + 1) <= MHZ(50) && + OFMCLK / (MCLKD_SL + 1) >= MHZ(40), + "Invalid MCLKD_SL setting"); +BUILD_ASSERT(APBSRC_CLK / (APB4DIV_VAL + 1) >= MHZ(20), + "Invalid PDMA CLK setting"); +#endif static int npcx_clock_control_init(const struct device *dev) { @@ -222,6 +232,7 @@ static int npcx_clock_control_init(const struct device *dev) inst_cdcg->HFCBCD = VAL_HFCBCD; inst_cdcg->HFCBCD1 = VAL_HFCBCD1; inst_cdcg->HFCBCD2 = VAL_HFCBCD2; + inst_cdcg->HFCBCD3 = VAL_HFCBCD3; /* * Power-down (turn off clock) the modules initially for better diff --git a/drivers/clock_control/clock_control_smartbond.c b/drivers/clock_control/clock_control_smartbond.c index 60c98f8668a..6da9c88b9a5 100644 --- a/drivers/clock_control/clock_control_smartbond.c +++ b/drivers/clock_control/clock_control_smartbond.c @@ -10,7 +10,9 @@ #include #include #include +#include #include +#include LOG_MODULE_REGISTER(clock_control, CONFIG_CLOCK_CONTROL_LOG_LEVEL); @@ -30,12 +32,15 @@ struct lpc_clock_state { .rc32k_freq = DT_PROP(DT_NODELABEL(rc32k), clock_frequency), }; -#define CALIBRATION_INTERVAL (DT_NODE_HAS_STATUS(DT_NODELABEL(rcx), okay) ? \ - DT_PROP(DT_NODELABEL(rcx), calibration_interval) : \ - DT_PROP(DT_NODELABEL(rc32k), calibration_interval)) +#define CALIBRATION_INTERVAL CONFIG_SMARTBOND_LP_OSC_CALIBRATION_INTERVAL + +#ifdef CONFIG_TIMER_READS_ITS_FREQUENCY_AT_RUNTIME +extern int z_clock_hw_cycles_per_sec; +#endif static void calibration_work_cb(struct k_work *work); static void xtal32k_settle_work_cb(struct k_work *work); +static enum smartbond_clock smartbond_source_clock(enum smartbond_clock clk); static K_WORK_DELAYABLE_DEFINE(calibration_work, calibration_work_cb); static K_WORK_DELAYABLE_DEFINE(xtal32k_settle_work, xtal32k_settle_work_cb); @@ -46,19 +51,30 @@ static void calibration_work_cb(struct k_work *work) da1469x_clock_lp_rcx_calibrate(); lpc_clock_state.rcx_ready = true; lpc_clock_state.rcx_freq = da1469x_clock_lp_rcx_freq_get(); - k_work_schedule(&calibration_work, - K_MSEC(1000 * CALIBRATION_INTERVAL)); LOG_DBG("RCX calibration done, RCX freq: %d", (int)lpc_clock_state.rcx_freq); - } else if (lpc_clock_state.rc32k_started) { + } + if (lpc_clock_state.rc32k_started) { da1469x_clock_lp_rc32k_calibrate(); lpc_clock_state.rc32k_ready = true; lpc_clock_state.rc32k_freq = da1469x_clock_lp_rc32k_freq_get(); - k_work_schedule(&calibration_work, - K_MSEC(1000 * CALIBRATION_INTERVAL)); LOG_DBG("RC32K calibration done, RC32K freq: %d", (int)lpc_clock_state.rc32k_freq); } + k_work_schedule(&calibration_work, + K_MSEC(1000 * CALIBRATION_INTERVAL)); +#ifdef CONFIG_TIMER_READS_ITS_FREQUENCY_AT_RUNTIME + switch (smartbond_source_clock(SMARTBOND_CLK_LP_CLK)) { + case SMARTBOND_CLK_RCX: + z_clock_hw_cycles_per_sec = lpc_clock_state.rcx_freq; + break; + case SMARTBOND_CLK_RC32K: + z_clock_hw_cycles_per_sec = lpc_clock_state.rc32k_freq; + break; + default: + break; + } +#endif } static void xtal32k_settle_work_cb(struct k_work *work) @@ -75,7 +91,7 @@ static void smartbond_start_rc32k(void) CRG_TOP->CLK_RC32K_REG |= CRG_TOP_CLK_RC32K_REG_RC32K_ENABLE_Msk; } lpc_clock_state.rc32k_started = true; - if (!lpc_clock_state.rc32k_ready && (CALIBRATION_INTERVAL > 0)) { + if (!lpc_clock_state.rc32k_ready) { if (!k_work_is_pending(&calibration_work.work)) { k_work_schedule(&calibration_work, K_MSEC(1000 * CALIBRATION_INTERVAL)); @@ -90,7 +106,7 @@ static void smartbond_start_rcx(void) da1469x_clock_lp_rcx_enable(); lpc_clock_state.rcx_started = true; } - if (!lpc_clock_state.rcx_ready && (CALIBRATION_INTERVAL > 0)) { + if (!lpc_clock_state.rcx_ready) { if (!k_work_is_pending(&calibration_work.work)) { k_work_schedule(&calibration_work, K_MSEC(1000 * CALIBRATION_INTERVAL)); @@ -161,6 +177,8 @@ static inline int smartbond_clock_control_off(const struct device *dev, switch (clk) { case SMARTBOND_CLK_RC32K: + BUILD_ASSERT(DT_NODE_HAS_STATUS(DT_NODELABEL(rc32k), okay), + "RC32K is not allowed to be turned off"); if (((CRG_TOP->CLK_CTRL_REG & CRG_TOP_CLK_CTRL_REG_LP_CLK_SEL_Msk) >> CRG_TOP_CLK_CTRL_REG_LP_CLK_SEL_Pos) != 0) { CRG_TOP->CLK_RC32K_REG &= ~CRG_TOP_CLK_RC32K_REG_RC32K_ENABLE_Msk; @@ -305,30 +323,6 @@ static void smartbond_clock_control_off_by_ord(const struct device *dev, smartbond_clock_control_off(dev, (clock_control_subsys_rate_t)clk); } -static void -qspi_set_read_pipe_delay(uint8_t delay) -{ - QSPIC->QSPIC_CTRLMODE_REG = - (QSPIC->QSPIC_CTRLMODE_REG & ~QSPIC_QSPIC_CTRLMODE_REG_QSPIC_PCLK_MD_Msk) | - (delay << QSPIC_QSPIC_CTRLMODE_REG_QSPIC_PCLK_MD_Pos) | - QSPIC_QSPIC_CTRLMODE_REG_QSPIC_RPIPE_EN_Msk; -} - -static void -qspi_set_cs_delay(uint32_t sys_clock_freq, uint32_t read_delay_ns, uint32_t erase_delay_ns) -{ - sys_clock_freq /= 100000; - uint32_t read_delay_cyc = ((read_delay_ns * sys_clock_freq) + 9999) / 10000; - uint32_t erase_delay_cyc = ((erase_delay_ns * sys_clock_freq) + 9999) / 10000; - - QSPIC->QSPIC_BURSTCMDB_REG = - (QSPIC->QSPIC_BURSTCMDB_REG & ~QSPIC_QSPIC_BURSTCMDB_REG_QSPIC_CS_HIGH_MIN_Msk) | - read_delay_cyc << QSPIC_QSPIC_BURSTCMDB_REG_QSPIC_CS_HIGH_MIN_Pos; - QSPIC->QSPIC_ERASECMDB_REG = - (QSPIC->QSPIC_ERASECMDB_REG & ~QSPIC_QSPIC_ERASECMDB_REG_QSPIC_ERS_CS_HI_Msk) | - (erase_delay_cyc << QSPIC_QSPIC_ERASECMDB_REG_QSPIC_ERS_CS_HI_Pos); -} - int z_smartbond_select_lp_clk(enum smartbond_clock lp_clk) { int rc = 0; @@ -350,12 +344,52 @@ int z_smartbond_select_lp_clk(enum smartbond_clock lp_clk) } if (rc == 0) { +#ifdef CONFIG_TIMER_READS_ITS_FREQUENCY_AT_RUNTIME + switch (lp_clk) { + case SMARTBOND_CLK_RCX: + z_clock_hw_cycles_per_sec = lpc_clock_state.rcx_freq; + break; + case SMARTBOND_CLK_RC32K: + z_clock_hw_cycles_per_sec = lpc_clock_state.rc32k_freq; + break; + default: + z_clock_hw_cycles_per_sec = 32768; + break; + } +#endif CRG_TOP->CLK_CTRL_REG = (CRG_TOP->CLK_CTRL_REG & ~clk_sel_msk) | clk_sel; } return rc; } +static void smartbond_clock_control_update_memory_settings(uint32_t sys_clock_freq) +{ + if (sys_clock_freq > 32000000) { + da1469x_qspi_set_read_pipe_delay(QSPIC_ID, 7); +#if DT_NODE_HAS_STATUS(DT_NODELABEL(memc), okay) + da1469x_qspi_set_read_pipe_delay(QSPIC2_ID, 7); +#endif + } else { + da1469x_qspi_set_read_pipe_delay(QSPIC_ID, 2); +#if DT_NODE_HAS_STATUS(DT_NODELABEL(memc), okay) + da1469x_qspi_set_read_pipe_delay(QSPIC2_ID, 2); +#endif + } + + da1469x_qspi_set_cs_delay(QSPIC_ID, SystemCoreClock, + DT_PROP(DT_NODELABEL(flash_controller), read_cs_idle_delay), + DT_PROP(DT_NODELABEL(flash_controller), erase_cs_idle_delay)); +#if DT_NODE_HAS_STATUS(DT_NODELABEL(memc), okay) + da1469x_qspi_set_cs_delay(QSPIC2_ID, SystemCoreClock, + DT_PROP(DT_NODELABEL(memc), read_cs_idle_min_ns), + DT_PROP_OR(DT_NODELABEL(memc), erase_cs_idle_min_ns, 0)); +#if DT_PROP(DT_NODELABEL(memc), is_ram) + da1469x_qspi_set_tcem(SystemCoreClock, DT_PROP(DT_NODELABEL(memc), tcem_max_us)); +#endif +#endif +} + int z_smartbond_select_sys_clk(enum smartbond_clock sys_clk) { uint32_t sys_clock_freq; @@ -370,12 +404,7 @@ int z_smartbond_select_sys_clk(enum smartbond_clock sys_clk) /* When PLL is selected as system clock qspi read pipe delay must be set to 7 */ if (sys_clock_freq > 32000000) { - qspi_set_read_pipe_delay(7); - qspi_set_cs_delay(SystemCoreClock, - DT_PROP(DT_NODELABEL(flash_controller), - read_cs_idle_delay), - DT_PROP(DT_NODELABEL(flash_controller), - erase_cs_idle_delay)); + smartbond_clock_control_update_memory_settings(sys_clock_freq); } if (sys_clk == SMARTBOND_CLK_RC32M) { @@ -391,12 +420,7 @@ int z_smartbond_select_sys_clk(enum smartbond_clock sys_clk) /* When switching back from PLL to 32MHz read pipe delay may be set to 2 */ if (SystemCoreClock <= 32000000) { - qspi_set_read_pipe_delay(2); - qspi_set_cs_delay(SystemCoreClock, - DT_PROP(DT_NODELABEL(flash_controller), - read_cs_idle_delay), - DT_PROP(DT_NODELABEL(flash_controller), - erase_cs_idle_delay)); + smartbond_clock_control_update_memory_settings(SystemCoreClock); } return 0; @@ -420,6 +444,11 @@ int smartbond_clocks_init(const struct device *dev) ARG_UNUSED(dev); +#if DT_NODE_HAS_STATUS(DT_NODELABEL(memc), okay) + /* Make sure QSPIC2 is enabled */ + da1469x_clock_amba_enable(CRG_TOP_CLK_AMBA_REG_QSPI2_ENABLE_Msk); +#endif + #define ENABLE_OSC(clock) smartbond_clock_control_on_by_ord(dev, DT_DEP_ORD(clock)) #define DISABLE_OSC(clock) if (DT_NODE_HAS_STATUS(clock, disabled)) { \ smartbond_clock_control_off_by_ord(dev, DT_DEP_ORD(clock)); \ @@ -459,9 +488,36 @@ static struct clock_control_driver_api smartbond_clock_control_api = { .get_rate = smartbond_clock_control_get_rate, }; +#if CONFIG_PM_DEVICE +static int smartbond_clocks_pm_action(const struct device *dev, enum pm_device_action action) +{ + switch (action) { + case PM_DEVICE_ACTION_SUSPEND: + break; + case PM_DEVICE_ACTION_RESUME: +#if DT_NODE_HAS_STATUS(DT_NODELABEL(memc), okay) + /* Make sure QSPIC2 is enabled */ + da1469x_clock_amba_enable(CRG_TOP_CLK_AMBA_REG_QSPI2_ENABLE_Msk); +#endif + /* + * Make sure the flash controller has correct settings as clock restoration + * might have been performed upon waking up. + */ + smartbond_clock_control_update_memory_settings(SystemCoreClock); + break; + default: + return -ENOTSUP; + } + + return 0; +} +#endif + +PM_DEVICE_DT_DEFINE(DT_NODELABEL(osc), smartbond_clocks_pm_action); + DEVICE_DT_DEFINE(DT_NODELABEL(osc), &smartbond_clocks_init, - NULL, + PM_DEVICE_DT_GET(DT_NODELABEL(osc)), NULL, NULL, PRE_KERNEL_1, CONFIG_CLOCK_CONTROL_INIT_PRIORITY, diff --git a/drivers/console/xtensa_sim_console.c b/drivers/console/xtensa_sim_console.c index 316162ddc0c..1d52f93af73 100644 --- a/drivers/console/xtensa_sim_console.c +++ b/drivers/console/xtensa_sim_console.c @@ -25,6 +25,14 @@ int arch_printk_char_out(int c) register int ret_err __asm__ ("a3"); buf[0] = (char)c; + + if (buf[0] == '\n') { + buf[1] = buf[0]; + buf[0] = '\r'; + a3++; + a5++; + } + __asm__ volatile ("simcall" : "=a" (ret_val), "=a" (ret_err) : "a" (a2), "a" (a3), "a" (a4), "a" (a5) diff --git a/drivers/counter/CMakeLists.txt b/drivers/counter/CMakeLists.txt index e9a0d3c1563..bdb7f88c9bd 100644 --- a/drivers/counter/CMakeLists.txt +++ b/drivers/counter/CMakeLists.txt @@ -28,6 +28,7 @@ zephyr_library_sources_ifdef(CONFIG_COUNTER_CMOS counter_cmos.c) zephyr_library_sources_ifdef(CONFIG_COUNTER_MCUX_GPT counter_mcux_gpt.c) zephyr_library_sources_ifdef(CONFIG_COUNTER_MCUX_QTMR counter_mcux_qtmr.c) zephyr_library_sources_ifdef(CONFIG_COUNTER_MCUX_SNVS counter_mcux_snvs.c) +zephyr_library_sources_ifdef(CONFIG_COUNTER_MCUX_TPM counter_mcux_tpm.c) zephyr_library_sources_ifdef(CONFIG_COUNTER_XEC counter_mchp_xec.c) zephyr_library_sources_ifdef(CONFIG_COUNTER_MCUX_LPTMR counter_mcux_lptmr.c) zephyr_library_sources_ifdef(CONFIG_COUNTER_MAXIM_DS3231 maxim_ds3231.c) diff --git a/drivers/counter/Kconfig b/drivers/counter/Kconfig index 3684b2c63c6..803ba05b850 100644 --- a/drivers/counter/Kconfig +++ b/drivers/counter/Kconfig @@ -60,6 +60,8 @@ source "drivers/counter/Kconfig.mcux_qtmr" source "drivers/counter/Kconfig.mcux_snvs" +source "drivers/counter/Kconfig.mcux_tpm" + source "drivers/counter/Kconfig.xec" source "drivers/counter/Kconfig.mcux_lptmr" diff --git a/drivers/counter/Kconfig.mcux_tpm b/drivers/counter/Kconfig.mcux_tpm new file mode 100644 index 00000000000..3ecb4c71df2 --- /dev/null +++ b/drivers/counter/Kconfig.mcux_tpm @@ -0,0 +1,11 @@ +# MCUXpresso SDK TPM + +# Copyright 2023-2024 NXP +# SPDX-License-Identifier: Apache-2.0 + +config COUNTER_MCUX_TPM + bool "MCUX TPM counter driver" + default y + depends on DT_HAS_NXP_TPM_TIMER_ENABLED + help + Enable support for mcux Timer PWM Module (TPM) counter driver. diff --git a/drivers/counter/Kconfig.nxp_mrt b/drivers/counter/Kconfig.nxp_mrt index a395ada36b4..cf3bb84558f 100644 --- a/drivers/counter/Kconfig.nxp_mrt +++ b/drivers/counter/Kconfig.nxp_mrt @@ -3,7 +3,9 @@ config COUNTER_NXP_MRT bool "NXP MRT driver" - default y if DT_HAS_NXP_MRT_CHANNEL_ENABLED && \ + default y + depends on DT_HAS_NXP_MRT_CHANNEL_ENABLED && \ DT_HAS_NXP_MRT_ENABLED + select RESET help Enable driver for the NXP Multirate Timer (MRT). diff --git a/drivers/counter/Kconfig.nxp_pit b/drivers/counter/Kconfig.nxp_pit index fc330dd6c4d..272a93c0141 100644 --- a/drivers/counter/Kconfig.nxp_pit +++ b/drivers/counter/Kconfig.nxp_pit @@ -5,7 +5,8 @@ config COUNTER_NXP_PIT bool "NXP PIT driver" - default y if DT_HAS_NXP_PIT_CHANNEL_ENABLED && \ + default y + depends on DT_HAS_NXP_PIT_CHANNEL_ENABLED && \ DT_HAS_NXP_PIT_ENABLED help Enable support for the NXP Periodic Interrupt Timer (PIT). diff --git a/drivers/counter/counter_andes_atcpit100.c b/drivers/counter/counter_andes_atcpit100.c index 5252c2c56cb..3fc69215f60 100644 --- a/drivers/counter/counter_andes_atcpit100.c +++ b/drivers/counter/counter_andes_atcpit100.c @@ -103,12 +103,6 @@ static void atcpit100_irq_handler(void *arg) if (int_status & TIMER0_CHANNEL(i)) { int_enable &= ~TIMER0_CHANNEL(i); ch_enable &= ~TIMER0_CHANNEL(i); - - cb = data->ch_data[i].alarm_callback; - data->ch_data[i].alarm_callback = NULL; - - cur_ticks = get_current_tick(dev, 3); - cb(dev, i, cur_ticks, data->ch_data[i].alarm_user_data); } } @@ -118,6 +112,17 @@ static void atcpit100_irq_handler(void *arg) /* Clear interrupt status */ sys_write32(int_status, PIT_ISTA(dev)); + + for (i = 0; i < CH_NUM_PER_COUNTER; i++) { + if (int_status & TIMER0_CHANNEL(i)) { + cur_ticks = get_current_tick(dev, 3); + cb = data->ch_data[i].alarm_callback; + data->ch_data[i].alarm_callback = NULL; + if (cb != NULL) { + cb(dev, i, cur_ticks, data->ch_data[i].alarm_user_data); + } + } + } } static int counter_atcpit100_init(const struct device *dev) @@ -494,7 +499,7 @@ static const struct counter_driver_api atcpit100_driver_api = { NULL, \ &atcpit100_data_##n, \ &atcpit100_config_##n, \ - POST_KERNEL, \ + PRE_KERNEL_1, \ CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \ &atcpit100_driver_api); \ \ diff --git a/drivers/counter/counter_ll_stm32_rtc.c b/drivers/counter/counter_ll_stm32_rtc.c index 128586a4a0a..cab26b1eeea 100644 --- a/drivers/counter/counter_ll_stm32_rtc.c +++ b/drivers/counter/counter_ll_stm32_rtc.c @@ -191,7 +191,7 @@ static int rtc_stm32_start(const struct device *dev) /* Enable RTC bus clock */ if (clock_control_on(clk, (clock_control_subsys_t) &cfg->pclken[0]) != 0) { - LOG_ERR("clock op failed\n"); + LOG_ERR("RTC clock enabling failed\n"); return -EIO; } #else @@ -212,9 +212,9 @@ static int rtc_stm32_stop(const struct device *dev) 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"); + /* Disable RTC bus clock */ + if (clock_control_off(clk, (clock_control_subsys_t) &cfg->pclken[0]) != 0) { + LOG_ERR("RTC clock disabling failed\n"); return -EIO; } #else diff --git a/drivers/counter/counter_ll_stm32_timer.c b/drivers/counter/counter_ll_stm32_timer.c index 869b31a31f7..8f6b1ffd1f4 100644 --- a/drivers/counter/counter_ll_stm32_timer.c +++ b/drivers/counter/counter_ll_stm32_timer.c @@ -42,9 +42,7 @@ static void(*const set_timer_compare[TIMER_MAX_CH])(TIM_TypeDef *, }; /** Channel to compare get function mapping. */ -#if !defined(CONFIG_SOC_SERIES_STM32F4X) && \ - !defined(CONFIG_SOC_SERIES_STM32G4X) && \ - !defined(CONFIG_SOC_SERIES_STM32MP1X) +#if !defined(CONFIG_SOC_SERIES_STM32MP1X) static uint32_t(*const get_timer_compare[TIMER_MAX_CH])(const TIM_TypeDef *) = { LL_TIM_OC_GetCompareCH1, LL_TIM_OC_GetCompareCH2, LL_TIM_OC_GetCompareCH3, LL_TIM_OC_GetCompareCH4, @@ -69,9 +67,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_STM32F4X) && \ - !defined(CONFIG_SOC_SERIES_STM32G4X) && \ - !defined(CONFIG_SOC_SERIES_STM32MP1X) +#if !defined(CONFIG_SOC_SERIES_STM32MP1X) static uint32_t(*const check_it_enabled[TIMER_MAX_CH])(const TIM_TypeDef *) = { LL_TIM_IsEnabledIT_CC1, LL_TIM_IsEnabledIT_CC2, LL_TIM_IsEnabledIT_CC3, LL_TIM_IsEnabledIT_CC4, diff --git a/drivers/counter/counter_mcux_tpm.c b/drivers/counter/counter_mcux_tpm.c new file mode 100644 index 00000000000..089629d2b5b --- /dev/null +++ b/drivers/counter/counter_mcux_tpm.c @@ -0,0 +1,300 @@ +/* + * Copyright 2023-2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nxp_tpm_timer + +#include +#include +#include +#include + +#include + +LOG_MODULE_REGISTER(mcux_tpm, CONFIG_COUNTER_LOG_LEVEL); + +#define DEV_CFG(_dev) ((const struct mcux_tpm_config *)(_dev)->config) +#define DEV_DATA(_dev) ((struct mcux_tpm_data *)(_dev)->data) + +struct mcux_tpm_config { + struct counter_config_info info; + + DEVICE_MMIO_NAMED_ROM(tpm_mmio); + + const struct device *clock_dev; + clock_control_subsys_t clock_subsys; + + tpm_clock_source_t tpm_clock_source; + tpm_clock_prescale_t prescale; +}; + +struct mcux_tpm_data { + DEVICE_MMIO_NAMED_RAM(tpm_mmio); + counter_alarm_callback_t alarm_callback; + counter_top_callback_t top_callback; + uint32_t freq; + void *alarm_user_data; + void *top_user_data; +}; + +static TPM_Type *get_base(const struct device *dev) +{ + return (TPM_Type *)DEVICE_MMIO_NAMED_GET(dev, tpm_mmio); +} + +static int mcux_tpm_start(const struct device *dev) +{ + const struct mcux_tpm_config *config = dev->config; + TPM_Type *base = get_base(dev); + + TPM_StartTimer(base, config->tpm_clock_source); + + return 0; +} + +static int mcux_tpm_stop(const struct device *dev) +{ + TPM_Type *base = get_base(dev); + + TPM_StopTimer(base); + + return 0; +} + +static int mcux_tpm_get_value(const struct device *dev, uint32_t *ticks) +{ + TPM_Type *base = get_base(dev); + + *ticks = TPM_GetCurrentTimerCount(base); + + return 0; +} + +static int mcux_tpm_set_alarm(const struct device *dev, uint8_t chan_id, + const struct counter_alarm_cfg *alarm_cfg) +{ + TPM_Type *base = get_base(dev); + uint32_t current = TPM_GetCurrentTimerCount(base); + uint32_t top_value = base->MOD; + struct mcux_tpm_data *data = dev->data; + uint32_t ticks = alarm_cfg->ticks; + + if (chan_id != kTPM_Chnl_0) { + LOG_ERR("Invalid channel id"); + return -EINVAL; + } + + if (ticks > (top_value)) + return -EINVAL; + + if ((alarm_cfg->flags & COUNTER_ALARM_CFG_ABSOLUTE) == 0) { + if (top_value - current >= ticks) + ticks += current; + else + ticks -= top_value - current; + } + + if (data->alarm_callback) + return -EBUSY; + + data->alarm_callback = alarm_cfg->callback; + data->alarm_user_data = alarm_cfg->user_data; + + TPM_SetupOutputCompare(base, kTPM_Chnl_0, kTPM_NoOutputSignal, ticks); + TPM_EnableInterrupts(base, kTPM_Chnl0InterruptEnable); + + return 0; +} + +static int mcux_tpm_cancel_alarm(const struct device *dev, uint8_t chan_id) +{ + TPM_Type *base = get_base(dev); + struct mcux_tpm_data *data = dev->data; + + if (chan_id != kTPM_Chnl_0) { + LOG_ERR("Invalid channel id"); + return -EINVAL; + } + + TPM_DisableInterrupts(base, kTPM_Chnl0InterruptEnable); + data->alarm_callback = NULL; + + return 0; +} + +void mcux_tpm_isr(const struct device *dev) +{ + TPM_Type *base = get_base(dev); + struct mcux_tpm_data *data = dev->data; + uint32_t current = TPM_GetCurrentTimerCount(base); + uint32_t status; + + status = TPM_GetStatusFlags(base) & (kTPM_Chnl0Flag | kTPM_TimeOverflowFlag); + TPM_ClearStatusFlags(base, status); + barrier_dsync_fence_full(); + + if ((status & kTPM_Chnl0Flag) && data->alarm_callback) { + TPM_DisableInterrupts(base, + kTPM_Chnl0InterruptEnable); + counter_alarm_callback_t alarm_cb = data->alarm_callback; + + data->alarm_callback = NULL; + alarm_cb(dev, 0, current, data->alarm_user_data); + } + + if ((status & kTPM_TimeOverflowFlag) && data->top_callback) { + data->top_callback(dev, data->top_user_data); + } +} + +static uint32_t mcux_tpm_get_pending_int(const struct device *dev) +{ + TPM_Type *base = get_base(dev); + + return (TPM_GetStatusFlags(base) & kTPM_Chnl0Flag); +} + +static int mcux_tpm_set_top_value(const struct device *dev, + const struct counter_top_cfg *cfg) +{ + const struct mcux_tpm_config *config = dev->config; + TPM_Type *base = get_base(dev); + struct mcux_tpm_data *data = dev->data; + + if (data->alarm_callback) + return -EBUSY; + + /* Check if timer already enabled. */ +#if defined(FSL_FEATURE_TPM_HAS_SC_CLKS) && FSL_FEATURE_TPM_HAS_SC_CLKS + if (base->SC & TPM_SC_CLKS_MASK) { +#else + if (base->SC & TPM_SC_CMOD_MASK) { +#endif + /* Timer already enabled, check flags before resetting */ + if (cfg->flags & COUNTER_TOP_CFG_DONT_RESET) + return -ENOTSUP; + + TPM_StopTimer(base); + base->CNT = 0; + TPM_SetTimerPeriod(base, cfg->ticks); + TPM_StartTimer(base, config->tpm_clock_source); + } else { + base->CNT = 0; + TPM_SetTimerPeriod(base, cfg->ticks); + } + + data->top_callback = cfg->callback; + data->top_user_data = cfg->user_data; + + TPM_EnableInterrupts(base, kTPM_TimeOverflowInterruptEnable); + + return 0; +} + +static uint32_t mcux_tpm_get_top_value(const struct device *dev) +{ + TPM_Type *base = get_base(dev); + + return base->MOD; +} + +static uint32_t mcux_tpm_get_freq(const struct device *dev) +{ + struct mcux_tpm_data *data = dev->data; + + return data->freq; +} + +static int mcux_tpm_init(const struct device *dev) +{ + const struct mcux_tpm_config *config = dev->config; + struct mcux_tpm_data *data = dev->data; + tpm_config_t tpmConfig; + uint32_t input_clock_freq; + TPM_Type *base; + + DEVICE_MMIO_NAMED_MAP(dev, tpm_mmio, K_MEM_CACHE_NONE | K_MEM_DIRECT_MAP); + + if (!device_is_ready(config->clock_dev)) { + LOG_ERR("clock control device not ready"); + return -ENODEV; + } + + if (clock_control_on(config->clock_dev, config->clock_subsys)) { + LOG_ERR("Could not turn on clock"); + return -EINVAL; + } + + if (clock_control_get_rate(config->clock_dev, config->clock_subsys, + &input_clock_freq)) { + LOG_ERR("Could not get clock frequency"); + return -EINVAL; + } + + data->freq = input_clock_freq / (1U << config->prescale); + + TPM_GetDefaultConfig(&tpmConfig); + tpmConfig.prescale = config->prescale; + base = get_base(dev); + TPM_Init(base, &tpmConfig); + + /* Set the modulo to max value. */ + base->MOD = TPM_MAX_COUNTER_VALUE(base); + + return 0; +} + +static const struct counter_driver_api mcux_tpm_driver_api = { + .start = mcux_tpm_start, + .stop = mcux_tpm_stop, + .get_value = mcux_tpm_get_value, + .set_alarm = mcux_tpm_set_alarm, + .cancel_alarm = mcux_tpm_cancel_alarm, + .set_top_value = mcux_tpm_set_top_value, + .get_pending_int = mcux_tpm_get_pending_int, + .get_top_value = mcux_tpm_get_top_value, + .get_freq = mcux_tpm_get_freq, +}; + +#define TO_TPM_PRESCALE_DIVIDE(val) _DO_CONCAT(kTPM_Prescale_Divide_, val) + +#define TPM_DEVICE_INIT_MCUX(n) \ + static struct mcux_tpm_data mcux_tpm_data_ ## n; \ + \ + static const struct mcux_tpm_config mcux_tpm_config_ ## n = { \ + DEVICE_MMIO_NAMED_ROM_INIT(tpm_mmio, 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), \ + .tpm_clock_source = kTPM_SystemClock, \ + .prescale = TO_TPM_PRESCALE_DIVIDE(DT_INST_PROP(n, prescaler)), \ + .info = { \ + .max_top_value = TPM_MAX_COUNTER_VALUE(TPM(n)), \ + .freq = 0, \ + .channels = 1, \ + .flags = COUNTER_CONFIG_INFO_COUNT_UP, \ + }, \ + }; \ + \ + static int mcux_tpm_## n ##_init(const struct device *dev); \ + DEVICE_DT_INST_DEFINE(n, \ + mcux_tpm_## n ##_init, \ + NULL, \ + &mcux_tpm_data_ ## n, \ + &mcux_tpm_config_ ## n, \ + POST_KERNEL, \ + CONFIG_COUNTER_INIT_PRIORITY, \ + &mcux_tpm_driver_api); \ + \ + static int mcux_tpm_## n ##_init(const struct device *dev) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(n), \ + DT_INST_IRQ(n, priority), \ + mcux_tpm_isr, DEVICE_DT_INST_GET(n), 0); \ + irq_enable(DT_INST_IRQN(n)); \ + return mcux_tpm_init(dev); \ + } \ + +DT_INST_FOREACH_STATUS_OKAY(TPM_DEVICE_INIT_MCUX) diff --git a/drivers/counter/counter_nrfx_timer.c b/drivers/counter/counter_nrfx_timer.c index 1fe3a98f8d7..bd6af3c5d3c 100644 --- a/drivers/counter/counter_nrfx_timer.c +++ b/drivers/counter/counter_nrfx_timer.c @@ -15,8 +15,6 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME, LOG_LEVEL); #define DT_DRV_COMPAT nordic_nrf_timer -#define TIMER_CLOCK(timer_instance) NRF_TIMER_BASE_FREQUENCY_GET(timer_instance) - #define CC_TO_ID(cc_num) (cc_num - 2) #define ID_TO_CC(idx) (nrf_timer_cc_channel_t)(idx + 2) @@ -419,6 +417,14 @@ static const struct counter_driver_api counter_nrfx_driver_api = { irq_handler, DEVICE_DT_INST_GET(idx), 0)) \ ) +#if !defined(CONFIG_SOC_SERIES_BSIM_NRFXX) +#define CHECK_MAX_FREQ(idx) \ + BUILD_ASSERT(DT_INST_PROP(idx, max_frequency) == \ + NRF_TIMER_BASE_FREQUENCY_GET((NRF_TIMER_Type *)DT_INST_REG_ADDR(idx))) +#else +#define CHECK_MAX_FREQ(idx) +#endif + #define COUNTER_NRFX_TIMER_DEVICE(idx) \ BUILD_ASSERT(DT_INST_PROP(idx, prescaler) <= \ TIMER_PRESCALER_PRESCALER_Msk, \ @@ -448,7 +454,7 @@ static const struct counter_driver_api counter_nrfx_driver_api = { static MAYBE_CONST_CONFIG struct counter_nrfx_config nrfx_counter_##idx##_config = { \ .info = { \ .max_top_value = (uint32_t)BIT64_MASK(DT_INST_PROP(idx, max_bit_width)),\ - .freq = TIMER_CLOCK((NRF_TIMER_Type *)DT_INST_REG_ADDR(idx)) / \ + .freq = DT_INST_PROP(idx, max_frequency) / \ BIT(DT_INST_PROP(idx, prescaler)), \ .flags = COUNTER_CONFIG_INFO_COUNT_UP, \ .channels = CC_TO_ID(DT_INST_PROP(idx, cc_num)), \ @@ -457,6 +463,7 @@ static const struct counter_driver_api counter_nrfx_driver_api = { .timer = (NRF_TIMER_Type *)DT_INST_REG_ADDR(idx), \ LOG_INSTANCE_PTR_INIT(log, LOG_MODULE_NAME, idx) \ }; \ + CHECK_MAX_FREQ(idx); \ DEVICE_DT_INST_DEFINE(idx, \ counter_##idx##_init, \ NULL, \ diff --git a/drivers/counter/counter_nxp_mrt.c b/drivers/counter/counter_nxp_mrt.c index 209d0314b3e..2ad62385d8e 100644 --- a/drivers/counter/counter_nxp_mrt.c +++ b/drivers/counter/counter_nxp_mrt.c @@ -21,6 +21,8 @@ #include #include #include +#include + #include #define LOG_MODULE_NAME counter_mrt @@ -55,6 +57,7 @@ struct nxp_mrt_config { void (*irq_config_func)(const struct device *dev); struct nxp_mrt_channel_data *const *data; const struct device *const *channels; + const struct reset_dt_spec reset; }; static int nxp_mrt_stop(const struct device *dev) @@ -210,6 +213,17 @@ 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; + int ret = 0; + + if (!device_is_ready(config->reset.dev)) { + LOG_ERR("Reset device not ready"); + return -ENODEV; + } + + ret = reset_line_toggle(config->reset.dev, config->reset.id); + if (ret) { + return ret; + } clock_control_on(config->clock_dev, config->clock_subsys); @@ -331,6 +345,7 @@ struct counter_driver_api nxp_mrt_api = { .irq_config_func = nxp_mrt_##n##_irq_config_func, \ .data = nxp_mrt_##n##_channel_datas, \ .channels = nxp_mrt_##n##_channels, \ + .reset = RESET_DT_SPEC_INST_GET(n), \ }; \ \ /* Init parent device in order to handle ISR and init. */ \ diff --git a/drivers/counter/counter_nxp_pit.c b/drivers/counter/counter_nxp_pit.c index 5cf192a73c4..6640b1aa2f2 100644 --- a/drivers/counter/counter_nxp_pit.c +++ b/drivers/counter/counter_nxp_pit.c @@ -187,7 +187,9 @@ static void nxp_pit_isr(const struct device *dev) flags = PIT_GetStatusFlags(config->base, channel); if (flags) { PIT_ClearStatusFlags(config->base, channel, flags); - data->top_callback(dev, data->top_user_data); + if (data->top_callback) { + data->top_callback(dev, data->top_user_data); + } } } #endif /* DT_NODE_HAS_PROP(DT_COMPAT_GET_ANY_STATUS_OKAY(nxp_pit), interrupts) */ diff --git a/drivers/counter/maxim_ds3231.c b/drivers/counter/maxim_ds3231.c index d1436ecb3ae..c6b8e08b79c 100644 --- a/drivers/counter/maxim_ds3231.c +++ b/drivers/counter/maxim_ds3231.c @@ -234,7 +234,7 @@ int maxim_ds3231_stat_update(const struct device *dev, /* * Look for current users of the interrupt/square-wave signal and - * enable monitoring iff at least one consumer is active. + * enable monitoring if and only if at least one consumer is active. */ static void validate_isw_monitoring(const struct device *dev) { diff --git a/drivers/crypto/CMakeLists.txt b/drivers/crypto/CMakeLists.txt index 68b63aef6ee..4cdf7a6e8b8 100644 --- a/drivers/crypto/CMakeLists.txt +++ b/drivers/crypto/CMakeLists.txt @@ -11,5 +11,6 @@ zephyr_library_sources_ifdef(CONFIG_CRYPTO_INTEL_SHA crypto_intel_sha.c) zephyr_library_sources_ifdef(CONFIG_CRYPTO_NPCX_SHA crypto_npcx_sha.c) zephyr_library_sources_ifdef(CONFIG_CRYPTO_MCHP_XEC_SYMCR crypto_mchp_xec_symcr.c) zephyr_library_sources_ifdef(CONFIG_CRYPTO_IT8XXX2_SHA crypto_it8xxx2_sha.c) +zephyr_library_sources_ifdef(CONFIG_CRYPTO_IT8XXX2_SHA_V2 crypto_it8xxx2_sha_v2.c) zephyr_library_sources_ifdef(CONFIG_CRYPTO_MCUX_DCP crypto_mcux_dcp.c) zephyr_library_link_libraries_ifdef(CONFIG_MBEDTLS mbedTLS) diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 5342441038e..451a524c810 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -52,6 +52,7 @@ config CRYPTO_MBEDTLS_SHIM bool "MbedTLS shim driver [EXPERIMENTAL]" select MBEDTLS select MBEDTLS_ENABLE_HEAP + select MBEDTLS_MAC_SHA512_ENABLED select EXPERIMENTAL help Enable mbedTLS shim layer compliant with crypto APIs. You will need diff --git a/drivers/crypto/Kconfig.it8xxx2 b/drivers/crypto/Kconfig.it8xxx2 index d38062db84c..8c14dbfd64d 100644 --- a/drivers/crypto/Kconfig.it8xxx2 +++ b/drivers/crypto/Kconfig.it8xxx2 @@ -11,3 +11,14 @@ config CRYPTO_IT8XXX2_SHA This driver supports SHA256 hardware accelerator of the it8xxx2 series. It requires 256 + 256 bytes in the RAM's first 4k-bytes to calculate SHA256 hash. + +config CRYPTO_IT8XXX2_SHA_V2 + bool "ITE IT8XXX2 SHA V2 driver" + default y + depends on DT_HAS_ITE_IT8XXX2_SHA_V2_ENABLED + select SOC_IT8XXX2_SHA256_HW_ACCELERATE + help + Enable ITE IT8XXX2 SHA V2 driver. + This driver supports SHA256 hardware accelerator of the it82xx2 series. + It requires 1024 + 256 bytes in the RAM's first 4k-bytes to calculate + SHA256 hash. diff --git a/drivers/crypto/crypto_it8xxx2_sha_v2.c b/drivers/crypto/crypto_it8xxx2_sha_v2.c new file mode 100644 index 00000000000..48eae76c673 --- /dev/null +++ b/drivers/crypto/crypto_it8xxx2_sha_v2.c @@ -0,0 +1,350 @@ +/* + * Copyright (c) 2024 ITE Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT ite_it8xxx2_sha_v2 + +#include +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(sha_it8xxx2, CONFIG_CRYPTO_LOG_LEVEL); + +BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 1, + "support only one sha compatible node"); + +#define IT8XXX2_SHA_REGS_BASE DT_REG_ADDR(DT_NODELABEL(sha0)) + +/* 0x00: SHA Control Register */ +#define IT8XXX2_REG_SHACR (0x00) +#define IT8XXX2_SEL1SHA1 BIT(6) +#define IT8XXX2_SELSHA2ALL (BIT(5) | BIT(4)) +#define IT8XXX2_SHAWB BIT(2) +#define IT8XXX2_SHAINI BIT(1) +#define IT8XXX2_SHAEXE BIT(0) +/* 0x01: SHA Status Register */ +#define IT8XXX2_REG_SHASR (0x01) +#define IT8XXX2_SHAIE BIT(3) +#define IT8XXX2_SHAIS BIT(2) +#define IT8XXX2_SHABUSY BIT(0) +/* 0x02: SHA Execution Counter Register */ +#define IT8XXX2_REG_SHAECR (0x02) +#define IT8XXX2_SHAEXEC_64Byte 0x0 +#define IT8XXX2_SHAEXEC_512Byte 0x7 +#define IT8XXX2_SHAEXEC_1KByte 0xf +/* 0x03: SHA DLM Base Address 0 Register */ +#define IT8XXX2_REG_SHADBA0R (0x03) +/* 0x04: SHA DLM Base Address 1 Register */ +#define IT8XXX2_REG_SHADBA1R (0x04) + +#define SHA_SHA256_HASH_LEN 32 +#define SHA_SHA256_BLOCK_LEN 64 +#define SHA_SHA256_SRAM_BUF 1024 +#define SHA_SHA256_HASH_LEN_WORDS (SHA_SHA256_HASH_LEN / sizeof(uint32_t)) +#define SHA_SHA256_BLOCK_LEN_WORDS (SHA_SHA256_BLOCK_LEN / sizeof(uint32_t)) +#define SHA_SHA256_SRAM_BUF_WORDS (SHA_SHA256_SRAM_BUF / sizeof(uint32_t)) +#define SHA_SHA256_CALCULATE_TIMEOUT_US 150 +#define SHA_SHA256_WRITE_BACK_TIMEOUT_US 45 +#define SHA_SHA256_WAIT_NEXT_CLOCK_TIME_US 15 + +/* + * This struct is used by the hardware and must be stored in RAM first 4k-byte + * and aligned on a 256-byte boundary. + */ +struct chip_sha256_ctx { + union { + /* SHA data buffer */ + uint32_t w_sha[SHA_SHA256_SRAM_BUF_WORDS]; + uint8_t w_input[SHA_SHA256_SRAM_BUF]; + }; + /* H[0] ~ H[7] */ + uint32_t h[SHA_SHA256_HASH_LEN_WORDS]; + uint32_t sha_init; + uint32_t w_input_index; + uint32_t total_len; +} __aligned(256); + +Z_GENERIC_SECTION(.__sha256_ram_block) struct chip_sha256_ctx chip_ctx; + +static void it8xxx2_sha256_init(bool init_k) +{ + chip_ctx.sha_init = init_k; + chip_ctx.w_input_index = 0; + chip_ctx.total_len = 0; + + /* Set DLM address for input data */ + sys_write8(((uint32_t)&chip_ctx) & 0xc0, + IT8XXX2_SHA_REGS_BASE + IT8XXX2_REG_SHADBA0R); + sys_write8(((uint32_t)&chip_ctx) >> 8, + IT8XXX2_SHA_REGS_BASE + IT8XXX2_REG_SHADBA1R); +} + +static int it8xxx2_sha256_module_calculation(void) +{ + struct gctrl_it8xxx2_regs *const gctrl_regs = GCTRL_IT8XXX2_REGS_BASE; + uint32_t key, count; + uint8_t sha_ctrl; + bool timeout = true; + + sha_ctrl = sys_read8(IT8XXX2_SHA_REGS_BASE + IT8XXX2_REG_SHACR); + + if (chip_ctx.sha_init) { + sha_ctrl |= (IT8XXX2_SHAINI | IT8XXX2_SHAEXE); + chip_ctx.sha_init = 0; + } else { + sha_ctrl |= IT8XXX2_SHAEXE; + } + + /* + * Global interrupt is disabled because the CPU cannot access memory + * via the DLM (Data Local Memory) bus while HW module is computing + * hash. + */ + key = irq_lock(); + /* Crypto use SRAM */ + gctrl_regs->GCTRL_PMER3 |= IT8XXX2_GCTRL_SRAM_CRYPTO_USED; + sys_write8(sha_ctrl, IT8XXX2_SHA_REGS_BASE + IT8XXX2_REG_SHACR); + + /* + * HW 64 bytes data calculation ~= 4us; + * HW 1024 bytes data calculation ~= 66us. + */ + for (count = 0; count <= (SHA_SHA256_CALCULATE_TIMEOUT_US / + SHA_SHA256_WAIT_NEXT_CLOCK_TIME_US); count++) { + /* Delay 15us */ + gctrl_regs->GCTRL_WNCKR = IT8XXX2_GCTRL_WN65K; + + if ((sys_read8(IT8XXX2_SHA_REGS_BASE + IT8XXX2_REG_SHASR) & IT8XXX2_SHAIS)) { + timeout = 0; + break; + } + } + + sys_write8(IT8XXX2_SHAIS, IT8XXX2_SHA_REGS_BASE + IT8XXX2_REG_SHASR); + /* CPU use SRAM */ + gctrl_regs->GCTRL_PMER3 &= ~IT8XXX2_GCTRL_SRAM_CRYPTO_USED; + gctrl_regs->GCTRL_PMER3; + irq_unlock(key); + + if (timeout) { + LOG_ERR("HW execute sha256 calculation timeout"); + it8xxx2_sha256_init(true); + + return -ETIMEDOUT; + } + + chip_ctx.w_input_index = 0; + + return 0; +} + +static int it8xxx2_hash_handler(struct hash_ctx *ctx, struct hash_pkt *pkt, + bool finish) +{ + struct gctrl_it8xxx2_regs *const gctrl_regs = GCTRL_IT8XXX2_REGS_BASE; + uint32_t rem_len = pkt->in_len; + uint32_t in_buf_idx = 0; + uint32_t i, key, count; + uint8_t sha_ctrl; + bool timeout = true; + int ret; + + while (rem_len) { + /* Data length >= 1KB */ + if (rem_len >= SHA_SHA256_SRAM_BUF) { + rem_len = rem_len - SHA_SHA256_SRAM_BUF; + + for (i = 0; i < SHA_SHA256_SRAM_BUF; i++) { + chip_ctx.w_input[chip_ctx.w_input_index++] = + pkt->in_buf[in_buf_idx++]; + } + + /* HW automatically load 1KB data from DLM */ + sys_write8(IT8XXX2_SHAEXEC_1KByte, + IT8XXX2_SHA_REGS_BASE + IT8XXX2_REG_SHAECR); + ret = it8xxx2_sha256_module_calculation(); + + if (ret) { + return ret; + } + } else { + /* 0 <= Data length < 1KB */ + while (rem_len) { + rem_len--; + chip_ctx.w_input[chip_ctx.w_input_index++] = + pkt->in_buf[in_buf_idx++]; + + /* + * If fill full 64byte then execute HW calculation. + * If not, will execute in later finish block. + */ + if (chip_ctx.w_input_index >= SHA_SHA256_BLOCK_LEN) { + /* HW automatically load 64Bytes data from DLM */ + sys_write8(IT8XXX2_SHAEXEC_64Byte, + IT8XXX2_SHA_REGS_BASE + IT8XXX2_REG_SHAECR); + ret = it8xxx2_sha256_module_calculation(); + + if (ret) { + return ret; + } + } + } + } + } + + chip_ctx.total_len += pkt->in_len; + + if (finish) { + uint32_t *ob_ptr = (uint32_t *)pkt->out_buf; + + /* Pre-processing (Padding) */ + memset(&chip_ctx.w_input[chip_ctx.w_input_index], + 0, SHA_SHA256_BLOCK_LEN - chip_ctx.w_input_index); + chip_ctx.w_input[chip_ctx.w_input_index] = 0x80; + + /* + * Handles the boundary case of rest data: + * Because the last eight bytes are bit length field of sha256 rule. + * If the data index >= 56, it needs to trigger HW to calculate, + * then fill 0 data and the last eight bytes bit length, and calculate again. + */ + if (chip_ctx.w_input_index >= 56) { + /* HW automatically load 64Bytes data from DLM */ + sys_write8(IT8XXX2_SHAEXEC_64Byte, + IT8XXX2_SHA_REGS_BASE + IT8XXX2_REG_SHAECR); + ret = it8xxx2_sha256_module_calculation(); + + if (ret) { + return ret; + } + memset(&chip_ctx.w_input[chip_ctx.w_input_index], + 0, SHA_SHA256_BLOCK_LEN - chip_ctx.w_input_index); + } + + /* + * Since input data (big-endian) are copied 1byte by 1byte to + * it8xxx2 memory (little-endian), so the bit length needs to + * be transformed into big-endian format and then write to memory. + */ + chip_ctx.w_sha[15] = sys_cpu_to_be32(chip_ctx.total_len * 8); + + /* HW automatically load 64Bytes data from DLM */ + sys_write8(IT8XXX2_SHAEXEC_64Byte, IT8XXX2_SHA_REGS_BASE + IT8XXX2_REG_SHAECR); + ret = it8xxx2_sha256_module_calculation(); + + if (ret) { + return ret; + } + + /* HW write back the hash result to DLM */ + /* Set DLM address for input data */ + sys_write8(((uint32_t)&chip_ctx.h) & 0xc0, + IT8XXX2_SHA_REGS_BASE + IT8XXX2_REG_SHADBA0R); + sys_write8(((uint32_t)&chip_ctx.h) >> 8, + IT8XXX2_SHA_REGS_BASE + IT8XXX2_REG_SHADBA1R); + + key = irq_lock(); + /* Crypto use SRAM */ + gctrl_regs->GCTRL_PMER3 |= IT8XXX2_GCTRL_SRAM_CRYPTO_USED; + sha_ctrl = sys_read8(IT8XXX2_SHA_REGS_BASE + IT8XXX2_REG_SHACR); + sys_write8(sha_ctrl | IT8XXX2_SHAWB, IT8XXX2_SHA_REGS_BASE + IT8XXX2_REG_SHACR); + + /* HW write back the hash result to DLM ~= 1us */ + for (count = 0; count <= (SHA_SHA256_WRITE_BACK_TIMEOUT_US / + SHA_SHA256_WAIT_NEXT_CLOCK_TIME_US); count++) { + /* Delay 15us */ + gctrl_regs->GCTRL_WNCKR = IT8XXX2_GCTRL_WN65K; + + if ((sys_read8(IT8XXX2_SHA_REGS_BASE + IT8XXX2_REG_SHASR) + & IT8XXX2_SHAIS)) { + timeout = 0; + break; + } + } + + sys_write8(IT8XXX2_SHAIS, IT8XXX2_SHA_REGS_BASE + IT8XXX2_REG_SHASR); + /* CPU use SRAM */ + gctrl_regs->GCTRL_PMER3 &= ~IT8XXX2_GCTRL_SRAM_CRYPTO_USED; + gctrl_regs->GCTRL_PMER3; + irq_unlock(key); + + if (timeout) { + LOG_ERR("HW write back hash timeout"); + it8xxx2_sha256_init(true); + + return -ETIMEDOUT; + } + + for (i = 0; i < SHA_SHA256_HASH_LEN_WORDS; i++) { + ob_ptr[i] = chip_ctx.h[i]; + } + + it8xxx2_sha256_init(true); + } + + return 0; +} + +static int it8xxx2_hash_session_free(const struct device *dev, + struct hash_ctx *ctx) +{ + it8xxx2_sha256_init(true); + + return 0; +} + +static inline int it8xxx2_query_hw_caps(const struct device *dev) +{ + return (CAP_SEPARATE_IO_BUFS | CAP_SYNC_OPS); +} + +static int it8xxx2_hash_begin_session(const struct device *dev, + struct hash_ctx *ctx, enum hash_algo algo) +{ + if (algo != CRYPTO_HASH_ALGO_SHA256) { + LOG_ERR("Unsupported algorithm"); + return -EINVAL; + } + + if (ctx->flags & ~(it8xxx2_query_hw_caps(dev))) { + LOG_ERR("Unsupported flag"); + return -EINVAL; + } + + it8xxx2_sha256_init(true); + ctx->hash_hndlr = it8xxx2_hash_handler; + + return 0; +} + +static int it8xxx2_sha_init(const struct device *dev) +{ + struct gctrl_it8xxx2_regs *const gctrl_regs = GCTRL_IT8XXX2_REGS_BASE; + + /* CPU use SRAM */ + gctrl_regs->GCTRL_PMER3 &= ~IT8XXX2_GCTRL_SRAM_CRYPTO_USED; + gctrl_regs->GCTRL_PMER3; + + it8xxx2_sha256_init(true); + + /* Select SHA-2 Family, SHA-256 */ + sys_write8(0, IT8XXX2_SHA_REGS_BASE + IT8XXX2_REG_SHACR); + /* SHA interrupt disable */ + sys_write8(0, IT8XXX2_SHA_REGS_BASE + IT8XXX2_REG_SHASR); + + return 0; +} + +static struct crypto_driver_api it8xxx2_crypto_api = { + .hash_begin_session = it8xxx2_hash_begin_session, + .hash_free_session = it8xxx2_hash_session_free, + .query_hw_caps = it8xxx2_query_hw_caps, +}; + +DEVICE_DT_INST_DEFINE(0, &it8xxx2_sha_init, NULL, NULL, NULL, POST_KERNEL, + CONFIG_CRYPTO_INIT_PRIORITY, &it8xxx2_crypto_api); diff --git a/drivers/crypto/crypto_smartbond.c b/drivers/crypto/crypto_smartbond.c index 5b003875b93..9a9d1edeff9 100644 --- a/drivers/crypto/crypto_smartbond.c +++ b/drivers/crypto/crypto_smartbond.c @@ -12,7 +12,11 @@ #include #include #include +#include #include +#include +#include +#include #include LOG_MODULE_REGISTER(crypto_smartbond_crypto, CONFIG_CRYPTO_LOG_LEVEL); @@ -114,6 +118,21 @@ static void smartbond_crypto_isr(const void *arg) } } +static inline void crypto_smartbond_pm_policy_state_lock_get(const struct device *dev) +{ + /* + * Prevent the SoC from entering the normal sleep state as PDC does not support + * waking up the application core following AES/HASH events. + */ + pm_policy_state_lock_get(PM_STATE_STANDBY, PM_ALL_SUBSTATES); +} + +static inline void crypto_smartbond_pm_policy_state_lock_put(const struct device *dev) +{ + /* Allow the SoC to enter the normal sleep state once AES/HASH operations are done. */ + pm_policy_state_lock_put(PM_STATE_STANDBY, PM_ALL_SUBSTATES); +} + static bool crypto_smartbond_lock_session(const struct device *dev) { bool lock = false; @@ -123,6 +142,9 @@ static bool crypto_smartbond_lock_session(const struct device *dev) if (!in_use) { in_use = true; + /* Prevent sleep as long as a cryptographic session is in place */ + da1469x_pd_acquire(MCU_PD_DOMAIN_SYS); + crypto_smartbond_pm_policy_state_lock_get(dev); crypto_smartbond_set_status(true); lock = true; } @@ -141,6 +163,8 @@ static void crypto_smartbond_unlock_session(const struct device *dev) if (in_use) { in_use = false; crypto_smartbond_set_status(false); + crypto_smartbond_pm_policy_state_lock_put(dev); + da1469x_pd_release_nowait(MCU_PD_DOMAIN_SYS); } k_sem_give(&data->session_sem); @@ -913,6 +937,33 @@ static struct crypto_driver_api crypto_smartbond_driver_api = { .query_hw_caps = crypto_smartbond_query_hw_caps }; +#if defined(CONFIG_PM_DEVICE) || defined(CONFIG_PM_DEVICE_RUNTIME) +static int crypto_smartbond_pm_action(const struct device *dev, + enum pm_device_action action) +{ + int ret = 0; + + switch (action) { + case PM_DEVICE_ACTION_SUSPEND: + /* + * No need to perform any actions here as the AES/HASH controller + * should already be turned off. + */ + break; + case PM_DEVICE_ACTION_RESUME: + /* + * No need to perform any actions here as the AES/HASH controller + * will be initialized upon acquiring a cryptographic session. + */ + break; + default: + return -ENOTSUP; + } + + return ret; +} +#endif + static int crypto_smartbond_init(const struct device *dev) { struct crypto_smartbond_data *data = dev->data; @@ -931,9 +982,17 @@ static int crypto_smartbond_init(const struct device *dev) IRQ_CONNECT(SMARTBOND_IRQN, SMARTBOND_IRQ_PRIO, smartbond_crypto_isr, DEVICE_DT_INST_GET(0), 0); + /* Controller should be initialized once a crypyographic session is requested */ crypto_smartbond_set_status(false); +#ifdef CONFIG_PM_DEVICE_RUNTIME + /* Make sure device state is marked as suspended */ + pm_device_init_suspended(dev); + + return pm_device_runtime_enable(dev); +#else return 0; +#endif } /* @@ -944,10 +1003,13 @@ static int crypto_smartbond_init(const struct device *dev) BUILD_ASSERT((inst) == 0, \ "multiple instances are not supported"); \ \ + PM_DEVICE_DT_INST_DEFINE(inst, crypto_smartbond_pm_action); \ + \ static struct crypto_smartbond_data crypto_smartbond_data_##inst; \ \ DEVICE_DT_INST_DEFINE(0, \ - crypto_smartbond_init, NULL, \ + crypto_smartbond_init, \ + PM_DEVICE_DT_INST_GET(inst), \ &crypto_smartbond_data_##inst, NULL, \ POST_KERNEL, \ CONFIG_CRYPTO_INIT_PRIORITY, \ diff --git a/drivers/dac/CMakeLists.txt b/drivers/dac/CMakeLists.txt index 4e1f72bb71d..d6869cc234a 100644 --- a/drivers/dac/CMakeLists.txt +++ b/drivers/dac/CMakeLists.txt @@ -10,6 +10,7 @@ zephyr_library_sources_ifdef(CONFIG_DAC_MCUX_DAC32 dac_mcux_dac32.c) zephyr_library_sources_ifdef(CONFIG_DAC_STM32 dac_stm32.c) zephyr_library_sources_ifdef(CONFIG_DAC_SAM dac_sam.c) zephyr_library_sources_ifdef(CONFIG_DAC_SAM0 dac_sam0.c) +zephyr_library_sources_ifdef(CONFIG_DAC_DACX0501 dac_dacx0501.c) zephyr_library_sources_ifdef(CONFIG_DAC_DACX0508 dac_dacx0508.c) zephyr_library_sources_ifdef(CONFIG_DAC_DACX3608 dac_dacx3608.c) zephyr_library_sources_ifdef(CONFIG_DAC_LTC166X dac_ltc166x.c) @@ -20,4 +21,6 @@ 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_AD559X dac_ad559x.c) zephyr_library_sources_ifdef(CONFIG_DAC_AD56XX dac_ad56xx.c) +zephyr_library_sources_ifdef(CONFIG_DAC_AD569X dac_ad569x.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE dac_handlers.c) +zephyr_library_sources_ifdef(CONFIG_DAC_MCUX_GAU dac_mcux_gau.c) diff --git a/drivers/dac/Kconfig b/drivers/dac/Kconfig index 97edb2c0bcf..08680b96404 100644 --- a/drivers/dac/Kconfig +++ b/drivers/dac/Kconfig @@ -37,6 +37,8 @@ source "drivers/dac/Kconfig.sam" source "drivers/dac/Kconfig.sam0" +source "drivers/dac/Kconfig.dacx0501" + source "drivers/dac/Kconfig.dacx0508" source "drivers/dac/Kconfig.dacx3608" @@ -55,4 +57,6 @@ source "drivers/dac/Kconfig.ad56xx" source "drivers/dac/Kconfig.ad559x" +source "drivers/dac/Kconfig.ad569x" + endif # DAC diff --git a/drivers/dac/Kconfig.ad559x b/drivers/dac/Kconfig.ad559x index 5266680199f..7bfcccb492e 100644 --- a/drivers/dac/Kconfig.ad559x +++ b/drivers/dac/Kconfig.ad559x @@ -1,5 +1,5 @@ # Copyright (c) 2023 Grinn -# SPDX -License-Identifier: Apache-2.0 +# SPDX-License-Identifier: Apache-2.0 config DAC_AD559X bool "AD559x DAC driver" diff --git a/drivers/dac/Kconfig.ad569x b/drivers/dac/Kconfig.ad569x new file mode 100644 index 00000000000..0b6b6ab2e10 --- /dev/null +++ b/drivers/dac/Kconfig.ad569x @@ -0,0 +1,10 @@ +# Copyright (c) 2024 Jan Kubiznak +# SPDX-License-Identifier: Apache-2.0 + +config DAC_AD569X + bool "Analog Devices AD5691 / AD5692 / AD5693 DAC driver" + default y + select I2C + depends on DT_HAS_ADI_AD5691_ENABLED || DT_HAS_ADI_AD5692_ENABLED || DT_HAS_ADI_AD5693_ENABLED + help + Enable the driver for the Analog Devices AD569X. diff --git a/drivers/dac/Kconfig.dacx0501 b/drivers/dac/Kconfig.dacx0501 new file mode 100644 index 00000000000..0481816e46e --- /dev/null +++ b/drivers/dac/Kconfig.dacx0501 @@ -0,0 +1,23 @@ +# DAC configuration options + +# Copyright (c) 2023 Google, LLC. +# +# SPDX-License-Identifier: Apache-2.0 + +config DAC_DACX0501 + bool "TI DACx0501 DAC driver" + default y + depends on DT_HAS_TI_DACX0501_ENABLED + select I2C + help + Enable the driver for the TI DACx0501. + +if DAC_DACX0501 + +config DAC_DACX0501_INIT_PRIORITY + int "Init priority" + default 80 + help + TI DACx0501 DAC device driver initialization priority. Must be greater than I2C_INIT_PRIORITY. + +endif # DAC_DACX0501 diff --git a/drivers/dac/Kconfig.mcux b/drivers/dac/Kconfig.mcux index 87869775d03..417e1b9be94 100644 --- a/drivers/dac/Kconfig.mcux +++ b/drivers/dac/Kconfig.mcux @@ -31,3 +31,10 @@ config DAC_MCUX_DAC32_TESTOUT depends on DAC_MCUX_DAC32 help Enable the DAC test output. + +config DAC_MCUX_GAU + bool "NXP GAU DAC driver" + default y + depends on DT_HAS_NXP_GAU_DAC_ENABLED + help + Enable the driver for the NXP GAU DAC. diff --git a/drivers/dac/dac_ad569x.c b/drivers/dac/dac_ad569x.c new file mode 100644 index 00000000000..13b7d705b30 --- /dev/null +++ b/drivers/dac/dac_ad569x.c @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2024 Jan Kubiznak + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(dac_ad569x, CONFIG_DAC_LOG_LEVEL); + +#define AD569X_CTRL_GAIN(x) FIELD_PREP(BIT(11), x) +#define AD569X_CTRL_REF(x) FIELD_PREP(BIT(12), x) +#define AD569X_CTRL_PD(x) FIELD_PREP(BIT_MASK(2) << 13, x) +#define AD569X_CTRL_RESET(x) FIELD_PREP(BIT(15), x) + +#define AD569X_CMD_WRITE 0x10 +#define AD569X_CMD_UPDATE 0x20 +#define AD569X_CMD_WRITE_AND_UPDATE 0x30 +#define AD569X_CMD_CONFIGURE 0x40 + +#define AD569X_CTRL_NO_RESET 0x00 +#define AD569X_CTRL_PERFORM_RESET 0x01 + +struct ad569x_config { + struct i2c_dt_spec bus; + uint8_t resolution; + uint8_t gain; + uint8_t voltage_reference; + uint8_t power_down_mode; +}; + +static int ad569x_write(const struct device *dev, uint8_t command, uint16_t value) +{ + const struct ad569x_config *config = dev->config; + + uint8_t tx_data[3]; + + tx_data[0] = command; + sys_put_be16(value, tx_data + 1); + + return i2c_write_dt(&config->bus, tx_data, sizeof(tx_data)); +} + +static int ad569x_read(const struct device *dev, uint16_t *value) +{ + const struct ad569x_config *config = dev->config; + + uint8_t rx_data[2]; + int ret; + + ret = i2c_read_dt(&config->bus, rx_data, sizeof(rx_data)); + if (ret != 0) { + return ret; + } + + *value = sys_get_be16(rx_data); + + return ret; +} + +static int ad569x_channel_setup(const struct device *dev, const struct dac_channel_cfg *channel_cfg) +{ + const struct ad569x_config *config = dev->config; + + if (channel_cfg->channel_id > 0) { + LOG_ERR("invalid channel %d", channel_cfg->channel_id); + return -EINVAL; + } + + if (channel_cfg->resolution != config->resolution) { + LOG_ERR("invalid resolution %d", channel_cfg->resolution); + return -EINVAL; + } + + return 0; +} + +static int ad569x_sw_reset(const struct device *dev) +{ + uint16_t reg = AD569X_CTRL_RESET(AD569X_CTRL_PERFORM_RESET); + int ret; + + LOG_DBG("reset %s", dev->name); + + /* Ignore return value, since device gives NAK after receiving RESET request */ + ad569x_write(dev, AD569X_CMD_CONFIGURE, reg); + + /* Check that DAC output is reset */ + ret = ad569x_read(dev, ®); + if (ret != 0) { + LOG_ERR("failed to read value"); + return ret; + } + + if (reg != 0) { + LOG_ERR("failed to reset DAC output"); + ret = -EIO; + } + + return 0; +} + +static int ad569x_write_value(const struct device *dev, uint8_t channel, uint32_t value) +{ + const struct ad569x_config *config = dev->config; + + if (channel > 0) { + LOG_ERR("invalid channel %d", channel); + return -EINVAL; + } + + if (value > (BIT(config->resolution) - 1)) { + LOG_ERR("invalid value %d", value); + return -EINVAL; + } + + return ad569x_write(dev, AD569X_CMD_WRITE_AND_UPDATE, value); +} + +static int ad569x_init(const struct device *dev) +{ + const struct ad569x_config *config = dev->config; + int ret; + + if (!i2c_is_ready_dt(&config->bus)) { + return -ENODEV; + } + + ret = ad569x_sw_reset(dev); + if (ret != 0) { + LOG_ERR("failed to perform sw reset"); + return ret; + } + + LOG_DBG("configure %s: gain %d, voltage reference %d, power down mode %d", dev->name, + config->gain, config->voltage_reference, config->power_down_mode); + + uint16_t ctrl_reg = AD569X_CTRL_GAIN(config->gain) | + AD569X_CTRL_REF(config->voltage_reference) | + AD569X_CTRL_PD(config->power_down_mode); + + ret = ad569x_write(dev, AD569X_CMD_CONFIGURE, ctrl_reg); + if (ret != 0) { + LOG_ERR("failed to configure the device"); + return ret; + } + + return 0; +} + +static const struct dac_driver_api ad569x_driver_api = { + .channel_setup = ad569x_channel_setup, + .write_value = ad569x_write_value, +}; + +#define INST_DT_AD569X(index, name, res) \ + static const struct ad569x_config config_##name##_##index = { \ + .bus = I2C_DT_SPEC_INST_GET(index), \ + .resolution = res, \ + .gain = DT_INST_ENUM_IDX(index, gain), \ + .voltage_reference = DT_INST_ENUM_IDX(index, voltage_reference), \ + .power_down_mode = DT_INST_ENUM_IDX(index, power_down_mode), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(index, ad569x_init, NULL, NULL, &config_##name##_##index, \ + POST_KERNEL, CONFIG_DAC_INIT_PRIORITY, &ad569x_driver_api); + +#define DT_DRV_COMPAT adi_ad5691 +#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) +#define DAC_AD5691_RESOLUTION 12 +DT_INST_FOREACH_STATUS_OKAY_VARGS(INST_DT_AD569X, DT_DRV_COMPAT, DAC_AD5691_RESOLUTION) +#endif +#undef DT_DRV_COMPAT + +#define DT_DRV_COMPAT adi_ad5692 +#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) +#define DAC_AD5692_RESOLUTION 14 +DT_INST_FOREACH_STATUS_OKAY_VARGS(INST_DT_AD569X, DT_DRV_COMPAT, DAC_AD5692_RESOLUTION) +#endif +#undef DT_DRV_COMPAT + +#define DT_DRV_COMPAT adi_ad5693 +#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) +#define DAC_AD5693_RESOLUTION 16 +DT_INST_FOREACH_STATUS_OKAY_VARGS(INST_DT_AD569X, DT_DRV_COMPAT, DAC_AD5693_RESOLUTION) +#endif +#undef DT_DRV_COMPAT diff --git a/drivers/dac/dac_dacx0501.c b/drivers/dac/dac_dacx0501.c new file mode 100644 index 00000000000..f8ee999dee1 --- /dev/null +++ b/drivers/dac/dac_dacx0501.c @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2024 Google LLC. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @brief Driver for Texas Instruments DACx0501 series + * + * Device driver for the Texas Instruments DACx0501 series of devices: DAC60501, DAC70501 and + * DAC80501: Digital to Analog Converters with a single channel output and with 12, 14 and 16 + * bits resolution respectively. Data sheet can be found here: + * https://www.ti.com/lit/ds/symlink/dac80501.pdf + */ + +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(dac_dacx0501, CONFIG_DAC_LOG_LEVEL); + +#define DACX0501_REG_DEVICE_ID 0x01U +#define DACX0501_REG_SYNC 0x02U +#define DACX0501_REG_CONFIG 0x03U +#define DACX0501_REG_GAIN 0x04U +#define DACX0501_REG_TRIGGER 0x05U +#define DACX0501_REG_STATUS 0x07U +#define DACX0501_REG_DAC 0x08U + +#define DACX0501_MASK_DEVICE_ID_RES GENMASK(14, 12) +#define DACX0501_MASK_CONFIG_REF_PWDWN BIT(8) +#define DACX0501_MASK_CONFIG_DAC_PWDWN BIT(0) +#define DACX0501_MASK_GAIN_BUFF_GAIN BIT(0) +#define DACX0501_MASK_GAIN_REFDIV_EN BIT(8) +#define DACX0501_MASK_TRIGGER_SOFT_RESET (BIT(1) | BIT(3)) +#define DACX0501_MASK_STATUS_REF_ALM BIT(0) + +/* Specifies the source of the reference voltage. */ +enum voltage_reference_source { + REF_INTERNAL, /* Internal 2.5V voltage reference. */ + REF_EXTERNAL, /* External pin voltage reference. */ +}; + +/* Specifies the reference voltage multiplier. */ +enum output_gain { + VM_MUL2, /* Multiplies by 2. */ + VM_MUL1, /* Multiplies by 1. */ + VM_DIV2, /* Multiplies by 0.5 */ +}; + +struct dacx0501_config { + struct i2c_dt_spec i2c_spec; + enum voltage_reference_source voltage_reference; + enum output_gain output_gain; +}; + +struct dacx0501_data { + /* Number of bits in the DAC register: Either 12, 14 or 16. */ + uint8_t resolution; +}; + +static int dacx0501_reg_read(const struct device *dev, const uint8_t addr, uint16_t *data) +{ + const struct dacx0501_config *config = dev->config; + uint8_t raw_data[2]; + int status; + + status = i2c_write_read_dt(&config->i2c_spec, &addr, sizeof(addr), raw_data, + sizeof(raw_data)); + if (status != 0) { + return status; + } + + /* DAC is big endian. */ + *data = sys_get_be16(raw_data); + return 0; +} + +static int dacx0501_reg_write(const struct device *dev, uint8_t addr, uint16_t data) +{ + const struct dacx0501_config *config = dev->config; + uint8_t write_cmd[3] = {addr}; + + /* DAC is big endian. */ + sys_put_be16(data, write_cmd + 1); + + return i2c_write_dt(&config->i2c_spec, write_cmd, sizeof(write_cmd)); +} + +static int dacx0501_channel_setup(const struct device *dev, + const struct dac_channel_cfg *channel_cfg) +{ + struct dacx0501_data *data = dev->data; + + /* DACx0501 series only has a single output channel. */ + if (channel_cfg->channel_id != 0) { + LOG_ERR("Unsupported channel %d", channel_cfg->channel_id); + return -ENOTSUP; + } + + if (channel_cfg->resolution != data->resolution) { + LOG_ERR("Unsupported resolution %d. Actual: %d", channel_cfg->resolution, + data->resolution); + return -ENOTSUP; + } + + return 0; +} + +static int dacx0501_write_value(const struct device *dev, uint8_t channel, uint32_t value) +{ + struct dacx0501_data *data = dev->data; + + if (channel != 0) { + LOG_ERR("dacx0501: Unsupported channel %d", channel); + return -ENOTSUP; + } + + if (value >= (1 << data->resolution)) { + LOG_ERR("dacx0501: Value %d out of range", value); + return -EINVAL; + } + + value <<= (16 - data->resolution); + + return dacx0501_reg_write(dev, DACX0501_REG_DAC, value); +} + +static int dacx0501_init(const struct device *dev) +{ + const struct dacx0501_config *config = dev->config; + struct dacx0501_data *data = dev->data; + uint16_t device_id; + int status; + + if (!i2c_is_ready_dt(&config->i2c_spec)) { + LOG_ERR("I2C bus %s not ready", config->i2c_spec.bus->name); + return -ENODEV; + } + + status = dacx0501_reg_read(dev, DACX0501_REG_DEVICE_ID, &device_id); + if (status != 0) { + LOG_ERR("read DEVICE_ID register failed"); + return status; + } + + /* See DEVICE_ID register RES field in the data sheet. */ + data->resolution = 16 - 2 * FIELD_GET(DACX0501_MASK_DEVICE_ID_RES, device_id); + + status = dacx0501_reg_write(dev, DACX0501_REG_CONFIG, + FIELD_PREP(DACX0501_MASK_CONFIG_REF_PWDWN, + config->voltage_reference == REF_EXTERNAL)); + if (status != 0) { + LOG_ERR("write CONFIG register failed"); + return status; + } + + status = dacx0501_reg_write( + dev, DACX0501_REG_GAIN, + FIELD_PREP(DACX0501_MASK_GAIN_REFDIV_EN, config->output_gain == VM_DIV2) | + FIELD_PREP(DACX0501_MASK_GAIN_BUFF_GAIN, config->output_gain == VM_MUL2)); + if (status != 0) { + LOG_ERR("GAIN Register update failed"); + return status; + } + + return 0; +} + +static const struct dac_driver_api dacx0501_driver_api = { + .channel_setup = dacx0501_channel_setup, + .write_value = dacx0501_write_value, +}; + +#define DT_DRV_COMPAT ti_dacx0501 + +#define DACX0501_DEFINE(n) \ + static struct dacx0501_data dacx0501_data_##n = {}; \ + static const struct dacx0501_config dacx0501_config_##n = { \ + .i2c_spec = I2C_DT_SPEC_INST_GET(n), \ + .voltage_reference = \ + _CONCAT(REF_, DT_STRING_UPPER_TOKEN(DT_DRV_INST(n), voltage_reference)), \ + .output_gain = _CONCAT(VM_, DT_STRING_UPPER_TOKEN(DT_DRV_INST(n), output_gain)), \ + }; \ + DEVICE_DT_INST_DEFINE(n, &dacx0501_init, NULL, &dacx0501_data_##n, &dacx0501_config_##n, \ + POST_KERNEL, CONFIG_DAC_DACX0501_INIT_PRIORITY, \ + &dacx0501_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(DACX0501_DEFINE) diff --git a/drivers/dac/dac_mcux_gau.c b/drivers/dac/dac_mcux_gau.c new file mode 100644 index 00000000000..ba4835b1c70 --- /dev/null +++ b/drivers/dac/dac_mcux_gau.c @@ -0,0 +1,116 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nxp_gau_dac + +#include + +#include + +#define LOG_LEVEL CONFIG_DAC_LOG_LEVEL +#include +#include +LOG_MODULE_REGISTER(nxp_gau_dac); + +struct nxp_gau_dac_config { + DAC_Type *base; + dac_conversion_rate_t conversion_rate : 2; + dac_reference_voltage_source_t voltage_ref : 1; + dac_output_voltage_range_t output_range : 2; +}; + +static inline dac_channel_id_t convert_channel_id(uint8_t channel_id) +{ + switch (channel_id) { + case 0: return kDAC_ChannelA; + case 1: return kDAC_ChannelB; + default: + LOG_ERR("Invalid DAC channel ID"); + return -EINVAL; + }; +} + +static int nxp_gau_dac_channel_setup(const struct device *dev, + const struct dac_channel_cfg *channel_cfg) +{ + const struct nxp_gau_dac_config *config = dev->config; + dac_channel_config_t dac_channel_config = {0}; + + if (channel_cfg->resolution != 10) { + LOG_ERR("DAC only support 10 bit resolution"); + return -EINVAL; + } + + if (channel_cfg->buffered) { + /* External and internal output are mutually exclusive */ + LOG_WRN("Note: buffering DAC output to pad disconnects internal output"); + } + + dac_channel_config.waveType = kDAC_WaveNormal; + dac_channel_config.outMode = channel_cfg->buffered ? + kDAC_ChannelOutputPAD : kDAC_ChannelOutputInternal; + dac_channel_config.timingMode = kDAC_NonTimingCorrelated; + dac_channel_config.enableTrigger = false; + dac_channel_config.enableDMA = false; + dac_channel_config.enableConversion = true; + + DAC_SetChannelConfig(config->base, + (uint32_t)convert_channel_id(channel_cfg->channel_id), + &dac_channel_config); + + return 0; +}; + +static int nxp_gau_dac_write_value(const struct device *dev, + uint8_t channel, uint32_t value) +{ + const struct nxp_gau_dac_config *config = dev->config; + + DAC_SetChannelData(config->base, + (uint32_t)convert_channel_id(channel), + (uint16_t)value); + return 0; +}; + +static const struct dac_driver_api nxp_gau_dac_driver_api = { + .channel_setup = nxp_gau_dac_channel_setup, + .write_value = nxp_gau_dac_write_value, +}; + +static int nxp_gau_dac_init(const struct device *dev) +{ + const struct nxp_gau_dac_config *config = dev->config; + dac_config_t dac_cfg; + + DAC_GetDefaultConfig(&dac_cfg); + + dac_cfg.conversionRate = config->conversion_rate; + dac_cfg.refSource = config->voltage_ref; + dac_cfg.rangeSelect = config->output_range; + + DAC_Init(config->base, &dac_cfg); + + return 0; +}; + +#define NXP_GAU_DAC_INIT(inst) \ + \ + const struct nxp_gau_dac_config nxp_gau_dac_##inst##_config = { \ + .base = (DAC_Type *) DT_INST_REG_ADDR(inst), \ + .voltage_ref = DT_INST_ENUM_IDX(inst, nxp_dac_reference), \ + .conversion_rate = DT_INST_ENUM_IDX(inst, nxp_conversion_rate), \ + .output_range = DT_INST_ENUM_IDX(inst, \ + nxp_output_voltage_range), \ + }; \ + \ + \ + DEVICE_DT_INST_DEFINE(inst, &nxp_gau_dac_init, NULL, \ + NULL, \ + &nxp_gau_dac_##inst##_config, \ + POST_KERNEL, CONFIG_DAC_INIT_PRIORITY, \ + &nxp_gau_dac_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(NXP_GAU_DAC_INIT) diff --git a/drivers/dai/intel/ssp/ssp.c b/drivers/dai/intel/ssp/ssp.c index 447a31c235f..215f9912d57 100644 --- a/drivers/dai/intel/ssp/ssp.c +++ b/drivers/dai/intel/ssp/ssp.c @@ -18,24 +18,119 @@ LOG_MODULE_REGISTER(LOG_DOMAIN); #include "ssp.h" -#define DT_DRV_COMPAT intel_ssp_dai #define dai_set_drvdata(dai, data) (dai->priv_data = data) #define dai_get_drvdata(dai) dai->priv_data -#define dai_get_mn(dai) dai->plat_data.mn_inst -#define dai_get_ftable(dai) dai->plat_data.ftable -#define dai_get_fsources(dai) dai->plat_data.fsources -#define dai_mn_base(dai) dai->plat_data.mn_inst->base -#define dai_base(dai) dai->plat_data.base -#define dai_ip_base(dai) dai->plat_data.ip_base -#define dai_shim_base(dai) dai->plat_data.shim_base -#define dai_hdamlssp_base(dai) dai->plat_data.hdamlssp_base -#define dai_i2svss_base(dai) dai->plat_data.i2svss_base +#define dai_get_plat_data(dai) dai->ssp_plat_data +#define dai_get_mn(dai) dai->ssp_plat_data->mn_inst +#define dai_get_ftable(dai) dai->ssp_plat_data->ftable +#define dai_get_fsources(dai) dai->ssp_plat_data->fsources +#define dai_mn_base(dai) dai->ssp_plat_data->mn_inst->base +#define dai_base(dai) dai->ssp_plat_data->base +#define dai_ip_base(dai) dai->ssp_plat_data->ip_base +#define dai_shim_base(dai) dai->ssp_plat_data->shim_base +#define dai_hdamlssp_base(dai) dai->ssp_plat_data->hdamlssp_base +#define dai_i2svss_base(dai) dai->ssp_plat_data->i2svss_base #define DAI_DIR_PLAYBACK 0 #define DAI_DIR_CAPTURE 1 #define SSP_ARRAY_INDEX(dir) dir == DAI_DIR_RX ? DAI_DIR_CAPTURE : DAI_DIR_PLAYBACK +static const char irq_name_level5_z[] = "level5"; + +static struct dai_intel_ssp_freq_table ssp_freq_table[] = { + { DT_PROP(DT_NODELABEL(audioclk), clock_frequency), + DT_PROP(DT_NODELABEL(audioclk), clock_frequency) / 1000}, + { DT_PROP(DT_NODELABEL(sysclk), clock_frequency), + DT_PROP(DT_NODELABEL(sysclk), clock_frequency) / 1000}, + { DT_PROP(DT_NODELABEL(pllclk), clock_frequency), + DT_PROP(DT_NODELABEL(pllclk), clock_frequency) / 1000}, +}; + +static uint32_t ssp_freq_sources[] = { + DAI_INTEL_SSP_CLOCK_AUDIO_CARDINAL, + DAI_INTEL_SSP_CLOCK_XTAL_OSCILLATOR, + DAI_INTEL_SSP_CLOCK_PLL_FIXED, +}; + +static struct dai_intel_ssp_mn ssp_mn_divider = { + .base = DT_REG_ADDR_BY_IDX(DT_NODELABEL(ssp0), 1), +}; + + +#define INTEL_SSP_INST_DEFINE(node_id) { \ + .is_initialized = false, \ + .is_power_en = false, \ + .acquire_count = 0, \ + .ssp_index = DT_PROP(node_id, ssp_index), \ + .base = DT_REG_ADDR_BY_IDX(node_id, 0), \ + IF_ENABLED(DT_NODE_EXISTS(DT_NODELABEL(sspbase)), \ + (.ip_base = DT_REG_ADDR_BY_IDX(DT_NODELABEL(sspbase), 0),)) \ + .shim_base = DT_REG_ADDR_BY_IDX(DT_NODELABEL(shim), 0), \ + IF_ENABLED(DT_NODE_EXISTS(DT_NODELABEL(hdamlssp)), \ + (.hdamlssp_base = DT_REG_ADDR(DT_NODELABEL(hdamlssp)),))\ + IF_ENABLED(DT_PROP_HAS_IDX(node_id, i2svss, 0), \ + (.i2svss_base = DT_PROP_BY_IDX(node_id, i2svss, 0),)) \ + .irq = DT_NUM_IRQS(node_id), \ + .irq_name = irq_name_level5_z, \ + .fifo[DAI_DIR_PLAYBACK].offset = \ + DT_REG_ADDR_BY_IDX(node_id, 0) + SSDR, \ + .fifo[DAI_DIR_PLAYBACK].handshake = \ + DT_DMAS_CELL_BY_NAME(node_id, tx, channel), \ + .fifo[DAI_DIR_CAPTURE].offset = \ + DT_REG_ADDR_BY_IDX(node_id, 0) + SSDR, \ + .fifo[DAI_DIR_CAPTURE].handshake = \ + DT_DMAS_CELL_BY_NAME(node_id, rx, channel), \ + .mn_inst = &ssp_mn_divider, \ + .ftable = ssp_freq_table, \ + .fsources = ssp_freq_sources, \ + .clk_active = 0, \ +}, + +static struct dai_intel_ssp_plat_data ssp_plat_data_table[] = { + DT_FOREACH_STATUS_OKAY(intel_ssp, INTEL_SSP_INST_DEFINE) +}; + + +static uint32_t ssp_get_instance_count(void) +{ + return ARRAY_SIZE(ssp_plat_data_table); +} + + +static struct dai_intel_ssp_plat_data *ssp_get_device_instance(uint32_t ssp_index) +{ + uint32_t ssp_instance = ssp_get_instance_count(); + uint32_t i; + + for (i = 0; i < ssp_instance; i++) { + if (ssp_plat_data_table[i].ssp_index == ssp_index) { + return &ssp_plat_data_table[i]; + } + } + + return NULL; +} + +static void ssp_acquire_port(struct dai_intel_ssp_plat_data *ssp) +{ + ssp->acquire_count++; +} + +static void ssp_release_port(struct dai_intel_ssp_plat_data *ssp) +{ + if (ssp->acquire_count == 0) { + return; + } + + --ssp->acquire_count; +} + +static bool ssp_is_acquired(struct dai_intel_ssp_plat_data *ssp) +{ + return (ssp->acquire_count != 0); +} + static void dai_ssp_update_bits(struct dai_intel_ssp *dp, uint32_t reg, uint32_t mask, uint32_t val) { uint32_t dest = dai_base(dp) + reg; @@ -629,14 +724,14 @@ static int dai_ssp_mn_set_bclk(struct dai_intel_ssp *dp, uint32_t dai_index, uin return ret; } -static void dai_ssp_mn_release_bclk(struct dai_intel_ssp *dp, uint32_t dai_index) +static void dai_ssp_mn_release_bclk(struct dai_intel_ssp *dp, uint32_t ssp_index) { struct dai_intel_ssp_mn *mp = dai_get_mn(dp); k_spinlock_key_t key; bool mn_in_use; key = k_spin_lock(&mp->lock); - mp->bclk_sources[dai_index] = MN_BCLK_SOURCE_NONE; + mp->bclk_sources[ssp_index] = MN_BCLK_SOURCE_NONE; mn_in_use = dai_ssp_is_bclk_source_in_use(dp, MN_BCLK_SOURCE_MN); /* release the M/N clock source if not used */ @@ -647,15 +742,15 @@ static void dai_ssp_mn_release_bclk(struct dai_intel_ssp *dp, uint32_t dai_index k_spin_unlock(&mp->lock, key); } -static void dai_ssp_mn_reset_bclk_divider(struct dai_intel_ssp *dp, uint32_t dai_index) +static void dai_ssp_mn_reset_bclk_divider(struct dai_intel_ssp *dp, uint32_t ssp_index) { struct dai_intel_ssp_mn *mp = dai_get_mn(dp); k_spinlock_key_t key; key = k_spin_lock(&mp->lock); - sys_write32(1, dai_mn_base(dp) + MN_MDIV_M_VAL(dai_index)); - sys_write32(1, dai_mn_base(dp) + MN_MDIV_N_VAL(dai_index)); + sys_write32(1, dai_mn_base(dp) + MN_MDIV_M_VAL(ssp_index)); + sys_write32(1, dai_mn_base(dp) + MN_MDIV_N_VAL(ssp_index)); k_spin_unlock(&mp->lock, key); } @@ -672,131 +767,131 @@ static int dai_ssp_poll_for_register_delay(uint32_t reg, uint32_t mask, return 0; } -static inline void dai_ssp_pm_runtime_dis_ssp_clk_gating(struct dai_intel_ssp *dp, uint32_t index) +static inline void dai_ssp_pm_runtime_dis_ssp_clk_gating(struct dai_intel_ssp *dp, + uint32_t ssp_index) { #if CONFIG_DAI_SSP_CLK_FORCE_DYNAMIC_CLOCK_GATING uint32_t shim_reg; shim_reg = sys_read32(dai_shim_base(dp) + SHIM_CLKCTL) | - (index < CONFIG_DAI_INTEL_SSP_NUM_BASE ? - SHIM_CLKCTL_I2SFDCGB(index) : - SHIM_CLKCTL_I2SEFDCGB(index - + (ssp_index < CONFIG_DAI_INTEL_SSP_NUM_BASE ? + SHIM_CLKCTL_I2SFDCGB(ssp_index) : + SHIM_CLKCTL_I2SEFDCGB(ssp_index - CONFIG_DAI_INTEL_SSP_NUM_BASE)); sys_write32(shim_reg, dai_shim_base(dp) + SHIM_CLKCTL); - LOG_INF("index %d CLKCTL %08x", index, shim_reg); + LOG_INF("ssp_index %d CLKCTL %08x", ssp_index, shim_reg); #endif } -static inline void dai_ssp_pm_runtime_en_ssp_clk_gating(struct dai_intel_ssp *dp, uint32_t index) +static inline void dai_ssp_pm_runtime_en_ssp_clk_gating(struct dai_intel_ssp *dp, + uint32_t ssp_index) { #if CONFIG_DAI_SSP_CLK_FORCE_DYNAMIC_CLOCK_GATING uint32_t shim_reg; shim_reg = sys_read32(dai_shim_base(dp) + SHIM_CLKCTL) & - ~(index < CONFIG_DAI_INTEL_SSP_NUM_BASE ? - SHIM_CLKCTL_I2SFDCGB(index) : - SHIM_CLKCTL_I2SEFDCGB(index - + ~(ssp_index < CONFIG_DAI_INTEL_SSP_NUM_BASE ? + SHIM_CLKCTL_I2SFDCGB(ssp_index) : + SHIM_CLKCTL_I2SEFDCGB(ssp_index - CONFIG_DAI_INTEL_SSP_NUM_BASE)); sys_write32(shim_reg, dai_shim_base(dp) + SHIM_CLKCTL); - LOG_INF("index %d CLKCTL %08x", index, shim_reg); + LOG_INF("ssp_index %d CLKCTL %08x", ssp_index, shim_reg); #endif } -static void dai_ssp_pm_runtime_en_ssp_power(struct dai_intel_ssp *dp, uint32_t index) +static void dai_ssp_pm_runtime_en_ssp_power(struct dai_intel_ssp *dp, uint32_t ssp_index) { #if CONFIG_DAI_SSP_HAS_POWER_CONTROL int ret; - LOG_INF("SSP%d", dp->index); + LOG_INF("SSP%d", ssp_index); #if CONFIG_SOC_INTEL_ACE15_MTPM || CONFIG_SOC_SERIES_INTEL_ADSP_CAVS - sys_write32(sys_read32(dai_ip_base(dp) + I2SLCTL_OFFSET) | I2SLCTL_SPA(index), + sys_write32(sys_read32(dai_ip_base(dp) + I2SLCTL_OFFSET) | I2SLCTL_SPA(ssp_index), dai_ip_base(dp) + I2SLCTL_OFFSET); /* Check if powered on. */ ret = dai_ssp_poll_for_register_delay(dai_ip_base(dp) + I2SLCTL_OFFSET, - I2SLCTL_CPA(index), I2SLCTL_CPA(index), + I2SLCTL_CPA(ssp_index), I2SLCTL_CPA(ssp_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) | - I2SLCTL_SPA(index), + I2SLCTL_SPA(ssp_index), 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), I2SLCTL_CPA(index), + I2SLCTL_CPA(ssp_index), I2SLCTL_CPA(ssp_index), DAI_INTEL_SSP_MAX_SEND_TIME_PER_SAMPLE); #else #error need to define SOC #endif if (ret) { - LOG_WRN("SSP%d: timeout", dp->index); + LOG_WRN("SSP%d: timeout", ssp_index); } #else ARG_UNUSED(dp); - ARG_UNUSED(index); + ARG_UNUSED(ssp_index); #endif /* CONFIG_DAI_SSP_HAS_POWER_CONTROL */ } -static void dai_ssp_pm_runtime_dis_ssp_power(struct dai_intel_ssp *dp, uint32_t index) +static void dai_ssp_pm_runtime_dis_ssp_power(struct dai_intel_ssp *dp, uint32_t ssp_index) { #if CONFIG_DAI_SSP_HAS_POWER_CONTROL int ret; - LOG_INF("SSP%d", dp->index); + LOG_INF("SSP%d", ssp_index); #if CONFIG_SOC_INTEL_ACE15_MTPM || CONFIG_SOC_SERIES_INTEL_ADSP_CAVS - sys_write32(sys_read32(dai_ip_base(dp) + I2SLCTL_OFFSET) & (~I2SLCTL_SPA(index)), + sys_write32(sys_read32(dai_ip_base(dp) + I2SLCTL_OFFSET) & (~I2SLCTL_SPA(ssp_index)), dai_ip_base(dp) + I2SLCTL_OFFSET); /* Check if powered off. */ ret = dai_ssp_poll_for_register_delay(dai_ip_base(dp) + I2SLCTL_OFFSET, - I2SLCTL_CPA(index), 0, + I2SLCTL_CPA(ssp_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)), + sys_write32(sys_read32(dai_hdamlssp_base(dp) + I2SLCTL_OFFSET) & (~I2SLCTL_SPA(ssp_index)), dai_hdamlssp_base(dp) + I2SLCTL_OFFSET); /* Check if powered off. */ ret = dai_ssp_poll_for_register_delay(dai_hdamlssp_base(dp) + I2SLCTL_OFFSET, - I2SLCTL_CPA(index), 0, + I2SLCTL_CPA(ssp_index), 0, DAI_INTEL_SSP_MAX_SEND_TIME_PER_SAMPLE); #else #error need to define SOC #endif if (ret) { - LOG_WRN("SSP%d: timeout", dp->index); + LOG_WRN("SSP%d: timeout", ssp_index); } #else ARG_UNUSED(dp); - ARG_UNUSED(index); + ARG_UNUSED(ssp_index); #endif /* CONFIG_DAI_SSP_HAS_POWER_CONTROL */ } static void dai_ssp_program_channel_map(struct dai_intel_ssp *dp, - const struct dai_config *cfg, uint32_t index) + const struct dai_config *cfg, uint32_t ssp_index) { #ifdef CONFIG_SOC_INTEL_ACE20_LNL uint16_t pcmsycm = cfg->link_config; - struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp); + /* Set upper slot number from configuration */ + pcmsycm = pcmsycm | (dp->ssp_plat_data->params.tdm_slots - 1) << 4; - /* Set upper slot number from configuration */ - pcmsycm = pcmsycm | (ssp->params.tdm_slots - 1) << 4; - - if (DAI_INTEL_SSP_IS_BIT_SET(pcmsycm, 15)) { - uint32_t reg_add = dai_ip_base(dp) + 0x1000 * index + PCMS0CM_OFFSET; + if (DAI_INTEL_SSP_IS_BIT_SET(cfg->link_config, 15)) { + uint32_t reg_add = dai_ip_base(dp) + 0x1000 * ssp_index + PCMS0CM_OFFSET; /* Program HDA output stream parameters */ sys_write16((pcmsycm & 0xffff), reg_add); } else { - uint32_t reg_add = dai_ip_base(dp) + 0x1000 * index + PCMS1CM_OFFSET; + uint32_t reg_add = dai_ip_base(dp) + 0x1000 * ssp_index + PCMS1CM_OFFSET; /* Program HDA input stream parameters */ sys_write16((pcmsycm & 0xffff), reg_add); } #else ARG_UNUSED(dp); ARG_UNUSED(cfg); - ARG_UNUSED(index); + ARG_UNUSED(ssp_index); #endif /* CONFIG_SOC_INTEL_ACE20_LNL */ } @@ -859,8 +954,9 @@ static void ssp_empty_rx_fifo_on_start(struct dai_intel_ssp *dp) 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; + struct dai_intel_ssp_plat_data *ssp_plat_data = dai_get_plat_data(dp); + uint64_t sample_ticks = ssp_plat_data->params.fsync_rate ? + 1000000 / ssp_plat_data->params.fsync_rate : 0; uint32_t retry = DAI_INTEL_SSP_RX_FLUSH_RETRY_MAX; uint32_t entries[2]; uint32_t i, sssr; @@ -900,20 +996,24 @@ static void ssp_empty_rx_fifo_on_stop(struct dai_intel_ssp *dp) static int dai_ssp_mclk_prepare_enable(struct dai_intel_ssp *dp) { - struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp); - int ret; + struct dai_intel_ssp_plat_data *ssp_plat_data = dai_get_plat_data(dp); + int ret = 0; - if (ssp->clk_active & SSP_CLK_MCLK_ACTIVE) { + if (ssp_plat_data->clk_active & SSP_CLK_MCLK_ACTIVE) { return 0; } /* MCLK config */ - ret = dai_ssp_mn_set_mclk(dp, ssp->params.mclk_id, ssp->params.mclk_rate); + if (ssp_plat_data->clk_active & SSP_CLK_MCLK_IS_NEEDED) { + ret = dai_ssp_mn_set_mclk(dp, ssp_plat_data->params.mclk_id, + ssp_plat_data->params.mclk_rate); + } + if (ret < 0) { - LOG_ERR("invalid mclk_rate = %d for mclk_id = %d", ssp->params.mclk_rate, - ssp->params.mclk_id); + LOG_ERR("invalid mclk_rate = %d for mclk_id = %d", ssp_plat_data->params.mclk_rate, + ssp_plat_data->params.mclk_id); } else { - ssp->clk_active |= SSP_CLK_MCLK_ACTIVE; + ssp_plat_data->clk_active |= SSP_CLK_MCLK_ACTIVE; } return ret; @@ -921,15 +1021,17 @@ static int dai_ssp_mclk_prepare_enable(struct dai_intel_ssp *dp) static void dai_ssp_mclk_disable_unprepare(struct dai_intel_ssp *dp) { - struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp); + struct dai_intel_ssp_plat_data *ssp_plat_data = dai_get_plat_data(dp); - if (!(ssp->clk_active & SSP_CLK_MCLK_ACTIVE)) { + if (!(ssp_plat_data->clk_active & SSP_CLK_MCLK_ACTIVE)) { return; } - dai_ssp_mn_release_mclk(dp, ssp->params.mclk_id); + if (ssp_plat_data->clk_active & SSP_CLK_MCLK_IS_NEEDED) { + dai_ssp_mn_release_mclk(dp, ssp_plat_data->params.mclk_id); + } - ssp->clk_active &= ~SSP_CLK_MCLK_ACTIVE; + ssp_plat_data->clk_active &= ~SSP_CLK_MCLK_ACTIVE; } static int dai_ssp_bclk_prepare_enable(struct dai_intel_ssp *dp) @@ -937,37 +1039,40 @@ static int dai_ssp_bclk_prepare_enable(struct dai_intel_ssp *dp) #if !(CONFIG_INTEL_MN) struct dai_intel_ssp_freq_table *ft = dai_get_ftable(dp); #endif - struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp); - struct dai_config *config = &ssp->config; + struct dai_intel_ssp_plat_data *ssp_plat_data = dai_get_plat_data(dp); uint32_t sscr0; uint32_t mdiv; bool need_ecs = false; int ret = 0; - if (ssp->clk_active & SSP_CLK_BCLK_ACTIVE) { + if (ssp_plat_data->clk_active & SSP_CLK_BCLK_ACTIVE) { return 0; } + if (!(ssp_plat_data->clk_active & SSP_CLK_BCLK_IS_NEEDED)) { + goto out; + } + sscr0 = sys_read32(dai_base(dp) + SSCR0); #if CONFIG_INTEL_MN /* BCLK config */ - ret = dai_ssp_mn_set_bclk(dp, config->dai_index, ssp->params.bclk_rate, + ret = dai_ssp_mn_set_bclk(dp, dp->dai_index, ssp_plat_data->params.bclk_rate, &mdiv, &need_ecs); if (ret < 0) { - LOG_ERR("invalid bclk_rate = %d for dai_index = %d", - ssp->params.bclk_rate, config->dai_index); + LOG_ERR("invalid bclk_rate = %d for ssp_index = %d", + ssp_plat_data->params.bclk_rate, dp->dai_index); goto out; } #else - if (ft[DAI_INTEL_SSP_DEFAULT_IDX].freq % ssp->params.bclk_rate != 0) { - LOG_ERR("invalid bclk_rate = %d for dai_index = %d", - ssp->params.bclk_rate, config->dai_index); + if (ft[DAI_INTEL_SSP_DEFAULT_IDX].freq % ssp_plat_data->params.bclk_rate != 0) { + LOG_ERR("invalid bclk_rate = %d for ssp_index = %d", + ssp_plat_data->params.bclk_rate, dp->dai_index); ret = -EINVAL; goto out; } - mdiv = ft[DAI_INTEL_SSP_DEFAULT_IDX].freq / ssp->params.bclk_rate; + mdiv = ft[DAI_INTEL_SSP_DEFAULT_IDX].freq / ssp_plat_data->params.bclk_rate; #endif if (need_ecs) { @@ -993,7 +1098,7 @@ static int dai_ssp_bclk_prepare_enable(struct dai_intel_ssp *dp) LOG_INF("sscr0 = 0x%08x", sscr0); out: if (!ret) { - ssp->clk_active |= SSP_CLK_BCLK_ACTIVE; + ssp_plat_data->clk_active |= SSP_CLK_BCLK_ACTIVE; } return ret; @@ -1001,29 +1106,32 @@ static int dai_ssp_bclk_prepare_enable(struct dai_intel_ssp *dp) static void dai_ssp_bclk_disable_unprepare(struct dai_intel_ssp *dp) { - struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp); + struct dai_intel_ssp_plat_data *ssp_plat_data = dai_get_plat_data(dp); - if (!(ssp->clk_active & SSP_CLK_BCLK_ACTIVE)) { + if (!(ssp_plat_data->clk_active & SSP_CLK_BCLK_ACTIVE)) { return; } #if CONFIG_INTEL_MN - dai_ssp_mn_release_bclk(dp, dp->index); + if (ssp_plat_data->clk_active & SSP_CLK_BCLK_IS_NEEDED) { + dai_ssp_mn_release_bclk(dp, ssp_plat_data->ssp_index); + } #endif - ssp->clk_active &= ~SSP_CLK_BCLK_ACTIVE; + ssp_plat_data->clk_active &= ~SSP_CLK_BCLK_ACTIVE; } static void dai_ssp_log_ssp_data(struct dai_intel_ssp *dp) { - LOG_INF("dai index: %u", dp->index); - LOG_INF("plat_data base: %u", dp->plat_data.base); - LOG_INF("plat_data irq: %u", dp->plat_data.irq); - LOG_INF("plat_data fifo playback offset: %u", dp->plat_data.fifo[DAI_DIR_PLAYBACK].offset); + LOG_INF("dai index: %u", dp->dai_index); + LOG_INF("plat_data base: %u", dp->ssp_plat_data->base); + LOG_INF("plat_data irq: %u", dp->ssp_plat_data->irq); + LOG_INF("plat_data fifo playback offset: %u", + dp->ssp_plat_data->fifo[DAI_DIR_PLAYBACK].offset); LOG_INF("plat_data fifo playback handshake: %u", - dp->plat_data.fifo[DAI_DIR_PLAYBACK].handshake); + dp->ssp_plat_data->fifo[DAI_DIR_PLAYBACK].handshake); LOG_INF("plat_data fifo capture offset: %u", - dp->plat_data.fifo[DAI_DIR_CAPTURE].offset); + dp->ssp_plat_data->fifo[DAI_DIR_CAPTURE].offset); LOG_INF("plat_data fifo capture handshake: %u", - dp->plat_data.fifo[DAI_DIR_CAPTURE].handshake); + dp->ssp_plat_data->fifo[DAI_DIR_CAPTURE].handshake); } /* Digital Audio interface formatting */ @@ -1031,6 +1139,7 @@ static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_co const void *bespoke_cfg) { struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp); + struct dai_intel_ssp_plat_data *ssp_plat_data = dai_get_plat_data(dp); struct dai_intel_ssp_freq_table *ft = dai_get_ftable(dp); uint32_t sscr0; uint32_t sscr1; @@ -1066,14 +1175,16 @@ static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_co key = k_spin_lock(&dp->lock); /* ignore config if SSP is already configured */ - if (ssp->state[DAI_DIR_PLAYBACK] > DAI_STATE_READY || - ssp->state[DAI_DIR_CAPTURE] > DAI_STATE_READY) { - if (!memcmp(&ssp->params, bespoke_cfg, sizeof(struct dai_intel_ipc3_ssp_params))) { + if (dp->state[DAI_DIR_PLAYBACK] > DAI_STATE_READY || + dp->state[DAI_DIR_CAPTURE] > DAI_STATE_READY) { + if (!memcmp(&ssp_plat_data->params, bespoke_cfg, + sizeof(struct dai_intel_ipc3_ssp_params))) { LOG_INF("Already configured. Ignore config"); goto clk; } - if (ssp->clk_active & (SSP_CLK_MCLK_ACTIVE | SSP_CLK_BCLK_ACTIVE)) { + if (ssp_plat_data->clk_active & + (SSP_CLK_MCLK_ACTIVE | SSP_CLK_BCLK_ACTIVE)) { LOG_WRN("SSP active, cannot change config"); goto clk; } @@ -1081,7 +1192,7 @@ static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_co /* safe to proceed and change HW config */ } - LOG_INF("SSP%d", dp->index); + LOG_INF("SSP%d", dp->dai_index); /* reset SSP settings */ /* sscr0 dynamic settings are DSS, EDSS, SCR, FRDC, ECS */ @@ -1104,7 +1215,7 @@ static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_co sspsp = 0; ssp->config = *config; - memcpy(&ssp->params, bespoke_cfg, sizeof(struct dai_intel_ipc3_ssp_params)); + memcpy(&ssp_plat_data->params, bespoke_cfg, sizeof(struct dai_intel_ipc3_ssp_params)); /* sspsp2 no dynamic setting */ sspsp2 = 0x0; @@ -1116,26 +1227,29 @@ static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_co ssto = 0x0; /* sstsa dynamic setting is TTSA, default 2 slots */ - sstsa = SSTSA_SSTSA(ssp->params.tx_slots); + sstsa = SSTSA_SSTSA(ssp_plat_data->params.tx_slots); /* ssrsa dynamic setting is RTSA, default 2 slots */ - ssrsa = SSRSA_SSRSA(ssp->params.rx_slots); + ssrsa = SSRSA_SSRSA(ssp_plat_data->params.rx_slots); switch (config->format & DAI_INTEL_IPC3_SSP_FMT_CLOCK_PROVIDER_MASK) { case DAI_INTEL_IPC3_SSP_FMT_CBP_CFP: sscr1 |= SSCR1_SCLKDIR | SSCR1_SFRMDIR; break; case DAI_INTEL_IPC3_SSP_FMT_CBC_CFC: + ssp_plat_data->clk_active |= SSP_CLK_MCLK_IS_NEEDED | SSP_CLK_BCLK_IS_NEEDED; sscr1 |= SSCR1_SCFR; cfs = true; break; case DAI_INTEL_IPC3_SSP_FMT_CBP_CFC: + ssp_plat_data->clk_active |= SSP_CLK_MCLK_IS_NEEDED; sscr1 |= SSCR1_SCLKDIR; /* FIXME: this mode has not been tested */ cfs = true; break; case DAI_INTEL_IPC3_SSP_FMT_CBC_CFP: + ssp_plat_data->clk_active |= SSP_CLK_MCLK_IS_NEEDED | SSP_CLK_BCLK_IS_NEEDED; sscr1 |= SSCR1_SCFR | SSCR1_SFRMDIR; /* FIXME: this mode has not been tested */ break; @@ -1166,7 +1280,7 @@ static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_co } /* supporting bclk idle state */ - if (ssp->params.clks_control & DAI_INTEL_IPC3_SSP_CLKCTRL_BCLK_IDLE_HIGH) { + if (ssp_plat_data->params.clks_control & DAI_INTEL_IPC3_SSP_CLKCTRL_BCLK_IDLE_HIGH) { /* bclk idle state high */ sspsp |= SSPSP_SCMODE((inverted_bclk ^ 0x3) & 0x3); } else { @@ -1179,20 +1293,20 @@ static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_co /* Additional hardware settings */ /* Receiver Time-out Interrupt Disabled/Enabled */ - sscr1 |= (ssp->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_TINTE) ? + sscr1 |= (ssp_plat_data->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_TINTE) ? SSCR1_TINTE : 0; /* Peripheral Trailing Byte Interrupts Disable/Enable */ - sscr1 |= (ssp->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_PINTE) ? + sscr1 |= (ssp_plat_data->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_PINTE) ? SSCR1_PINTE : 0; /* Enable/disable internal loopback. Output of transmit serial * shifter connected to input of receive serial shifter, internally. */ - sscr1 |= (ssp->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_LBM) ? + sscr1 |= (ssp_plat_data->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_LBM) ? SSCR1_LBM : 0; - if (ssp->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_LBM) { + if (ssp_plat_data->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_LBM) { LOG_INF("going for loopback!"); } else { LOG_INF("no loopback!"); @@ -1201,69 +1315,70 @@ static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_co /* Transmit data are driven at the same/opposite clock edge specified * in SSPSP.SCMODE[1:0] */ - sscr2 |= (ssp->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_SMTATF) ? + sscr2 |= (ssp_plat_data->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_SMTATF) ? SSCR2_SMTATF : 0; /* Receive data are sampled at the same/opposite clock edge specified * in SSPSP.SCMODE[1:0] */ - sscr2 |= (ssp->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_MMRATF) ? + sscr2 |= (ssp_plat_data->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_MMRATF) ? SSCR2_MMRATF : 0; /* Enable/disable the fix for PSP consumer mode TXD wait for frame * de-assertion before starting the second channel */ - sscr2 |= (ssp->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_PSPSTWFDFD) ? + sscr2 |= (ssp_plat_data->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_PSPSTWFDFD) ? SSCR2_PSPSTWFDFD : 0; /* Enable/disable the fix for PSP provider mode FSRT with dummy stop & * frame end padding capability */ - sscr2 |= (ssp->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_PSPSRWFDFD) ? + sscr2 |= (ssp_plat_data->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_PSPSRWFDFD) ? SSCR2_PSPSRWFDFD : 0; - if (!ssp->params.mclk_rate || - ssp->params.mclk_rate > ft[DAI_INTEL_SSP_MAX_FREQ_INDEX].freq) { - LOG_ERR("invalid MCLK = %d Hz (valid < %d)", ssp->params.mclk_rate, + if (!ssp_plat_data->params.mclk_rate || + ssp_plat_data->params.mclk_rate > ft[DAI_INTEL_SSP_MAX_FREQ_INDEX].freq) { + LOG_ERR("invalid MCLK = %d Hz (valid < %d)", ssp_plat_data->params.mclk_rate, ft[DAI_INTEL_SSP_MAX_FREQ_INDEX].freq); ret = -EINVAL; goto out; } - if (!ssp->params.bclk_rate || ssp->params.bclk_rate > ssp->params.mclk_rate) { - LOG_ERR("BCLK %d Hz = 0 or > MCLK %d Hz", ssp->params.bclk_rate, - ssp->params.mclk_rate); + if (!ssp_plat_data->params.bclk_rate || + ssp_plat_data->params.bclk_rate > ssp_plat_data->params.mclk_rate) { + LOG_ERR("BCLK %d Hz = 0 or > MCLK %d Hz", ssp_plat_data->params.bclk_rate, + ssp_plat_data->params.mclk_rate); ret = -EINVAL; goto out; } /* calc frame width based on BCLK and rate - must be divisible */ - if (ssp->params.bclk_rate % ssp->params.fsync_rate) { - LOG_ERR("BCLK %d is not divisible by rate %d", ssp->params.bclk_rate, - ssp->params.fsync_rate); + if (ssp_plat_data->params.bclk_rate % ssp_plat_data->params.fsync_rate) { + LOG_ERR("BCLK %d is not divisible by rate %d", ssp_plat_data->params.bclk_rate, + ssp_plat_data->params.fsync_rate); ret = -EINVAL; goto out; } /* must be enough BCLKs for data */ - bdiv = ssp->params.bclk_rate / ssp->params.fsync_rate; - if (bdiv < ssp->params.tdm_slot_width * ssp->params.tdm_slots) { + bdiv = ssp_plat_data->params.bclk_rate / ssp_plat_data->params.fsync_rate; + if (bdiv < ssp_plat_data->params.tdm_slot_width * ssp_plat_data->params.tdm_slots) { LOG_ERR("not enough BCLKs need %d", - ssp->params.tdm_slot_width * ssp->params.tdm_slots); + ssp_plat_data->params.tdm_slot_width * ssp_plat_data->params.tdm_slots); ret = -EINVAL; goto out; } /* tdm_slot_width must be <= 38 for SSP */ - if (ssp->params.tdm_slot_width > 38) { - LOG_ERR("tdm_slot_width %d > 38", ssp->params.tdm_slot_width); + if (ssp_plat_data->params.tdm_slot_width > 38) { + LOG_ERR("tdm_slot_width %d > 38", ssp_plat_data->params.tdm_slot_width); ret = -EINVAL; goto out; } - bdiv_min = ssp->params.tdm_slots * - (ssp->params.tdm_per_slot_padding_flag ? - ssp->params.tdm_slot_width : ssp->params.sample_valid_bits); + bdiv_min = ssp_plat_data->params.tdm_slots * + (ssp_plat_data->params.tdm_per_slot_padding_flag ? + ssp_plat_data->params.tdm_slot_width : ssp_plat_data->params.sample_valid_bits); if (bdiv < bdiv_min) { LOG_ERR("bdiv(%d) < bdiv_min(%d)", bdiv, bdiv_min); ret = -EINVAL; @@ -1283,7 +1398,7 @@ static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_co start_delay = true; - sscr0 |= SSCR0_FRDC(ssp->params.tdm_slots); + sscr0 |= SSCR0_FRDC(ssp_plat_data->params.tdm_slots); if (bdiv % 2) { LOG_ERR("bdiv %d is not divisible by 2", bdiv); @@ -1331,7 +1446,7 @@ static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_co /* default start_delay value is set to false */ - sscr0 |= SSCR0_FRDC(ssp->params.tdm_slots); + sscr0 |= SSCR0_FRDC(ssp_plat_data->params.tdm_slots); /* LJDFD enable */ sscr2 &= ~SSCR2_LJDFD; @@ -1387,19 +1502,19 @@ static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_co /* default start_delay value is set to false */ - sscr0 |= SSCR0_MOD | SSCR0_FRDC(ssp->params.tdm_slots); + sscr0 |= SSCR0_MOD | SSCR0_FRDC(ssp_plat_data->params.tdm_slots); /* set asserted frame length */ frame_len = 1; /* default */ - if (cfs && ssp->params.frame_pulse_width > 0 && - ssp->params.frame_pulse_width <= + if (cfs && ssp_plat_data->params.frame_pulse_width > 0 && + ssp_plat_data->params.frame_pulse_width <= DAI_INTEL_IPC3_SSP_FRAME_PULSE_WIDTH_MAX) { - frame_len = ssp->params.frame_pulse_width; + frame_len = ssp_plat_data->params.frame_pulse_width; } /* frame_pulse_width must less or equal 38 */ - if (ssp->params.frame_pulse_width > + if (ssp_plat_data->params.frame_pulse_width > DAI_INTEL_IPC3_SSP_FRAME_PULSE_WIDTH_MAX) { LOG_ERR("frame_pulse_width > %d", DAI_INTEL_IPC3_SSP_FRAME_PULSE_WIDTH_MAX); ret = -EINVAL; @@ -1413,20 +1528,20 @@ static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_co */ sspsp |= SSPSP_SFRMP(!inverted_frame); - active_tx_slots = POPCOUNT(ssp->params.tx_slots); - active_rx_slots = POPCOUNT(ssp->params.rx_slots); + active_tx_slots = POPCOUNT(ssp_plat_data->params.tx_slots); + active_rx_slots = POPCOUNT(ssp_plat_data->params.rx_slots); /* * handle TDM mode, TDM mode has padding at the end of * each slot. The amount of padding is equal to result of * subtracting slot width and valid bits per slot. */ - if (ssp->params.tdm_per_slot_padding_flag) { - frame_end_padding = bdiv - ssp->params.tdm_slots * - ssp->params.tdm_slot_width; + if (ssp_plat_data->params.tdm_per_slot_padding_flag) { + frame_end_padding = bdiv - ssp_plat_data->params.tdm_slots * + ssp_plat_data->params.tdm_slot_width; - slot_end_padding = ssp->params.tdm_slot_width - - ssp->params.sample_valid_bits; + slot_end_padding = ssp_plat_data->params.tdm_slot_width - + ssp_plat_data->params.sample_valid_bits; if (slot_end_padding > DAI_INTEL_IPC3_SSP_SLOT_PADDING_MAX) { @@ -1456,7 +1571,7 @@ static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_co sspsp |= SSPSP_SFRMWDTH(frame_len); - data_size = ssp->params.sample_valid_bits; + data_size = ssp_plat_data->params.sample_valid_bits; if (data_size > 16) { sscr0 |= (SSCR0_EDSS | SSCR0_DSIZE(data_size - 16)); @@ -1465,7 +1580,7 @@ static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_co } /* setting TFT and RFT */ - switch (ssp->params.sample_valid_bits) { + switch (ssp_plat_data->params.sample_valid_bits) { case 16: /* use 2 bytes for each slot */ sample_width = 2; @@ -1476,7 +1591,7 @@ static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_co sample_width = 4; break; default: - LOG_ERR("sample_valid_bits %d", ssp->params.sample_valid_bits); + LOG_ERR("sample_valid_bits %d", ssp_plat_data->params.sample_valid_bits); ret = -EINVAL; goto out; } @@ -1506,27 +1621,28 @@ static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_co LOG_INF("ssrsa = 0x%08x, sstsa = 0x%08x", ssrsa, sstsa); - ssp->state[DAI_DIR_PLAYBACK] = DAI_STATE_PRE_RUNNING; - ssp->state[DAI_DIR_CAPTURE] = DAI_STATE_PRE_RUNNING; + dp->state[DAI_DIR_PLAYBACK] = DAI_STATE_PRE_RUNNING; + dp->state[DAI_DIR_CAPTURE] = DAI_STATE_PRE_RUNNING; clk: switch (config->options & DAI_INTEL_IPC3_SSP_CONFIG_FLAGS_CMD_MASK) { case DAI_INTEL_IPC3_SSP_CONFIG_FLAGS_HW_PARAMS: - if (ssp->params.clks_control & DAI_INTEL_IPC3_SSP_CLKCTRL_MCLK_ES) { + if (ssp_plat_data->params.clks_control & DAI_INTEL_IPC3_SSP_CLKCTRL_MCLK_ES) { ret = dai_ssp_mclk_prepare_enable(dp); if (ret < 0) { goto out; } - ssp->clk_active |= SSP_CLK_MCLK_ES_REQ; + ssp_plat_data->clk_active |= SSP_CLK_MCLK_ES_REQ; - LOG_INF("hw_params stage: enabled MCLK clocks for SSP%d...", dp->index); + LOG_INF("hw_params stage: enabled MCLK clocks for SSP%d...", + dp->dai_index); } - if (ssp->params.clks_control & DAI_INTEL_IPC3_SSP_CLKCTRL_BCLK_ES) { + if (ssp_plat_data->params.clks_control & DAI_INTEL_IPC3_SSP_CLKCTRL_BCLK_ES) { bool enable_sse = false; - if (!(ssp->clk_active & SSP_CLK_BCLK_ACTIVE)) { + if (!(ssp_plat_data->clk_active & SSP_CLK_BCLK_ACTIVE)) { enable_sse = true; } @@ -1535,39 +1651,43 @@ static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_co goto out; } - ssp->clk_active |= SSP_CLK_BCLK_ES_REQ; + ssp_plat_data->clk_active |= SSP_CLK_BCLK_ES_REQ; if (enable_sse) { /* enable port */ dai_ssp_update_bits(dp, SSCR0, SSCR0_SSE, SSCR0_SSE); - LOG_INF("SSE set for SSP%d", dp->index); + LOG_INF("SSE set for SSP%d", ssp_plat_data->ssp_index); } - LOG_INF("hw_params stage: enabled BCLK clocks for SSP%d...", dp->index); + LOG_INF("hw_params stage: enabled BCLK clocks for SSP%d...", + ssp_plat_data->ssp_index); } break; case DAI_INTEL_IPC3_SSP_CONFIG_FLAGS_HW_FREE: /* 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) { - LOG_INF("hw_free stage: ignore since SSP%d still in use", dp->index); + if (dp->state[DAI_DIR_CAPTURE] != DAI_STATE_PRE_RUNNING || + dp->state[DAI_DIR_PLAYBACK] != DAI_STATE_PRE_RUNNING) { + LOG_INF("hw_free stage: ignore since SSP%d still in use", + dp->dai_index); break; } - if (ssp->params.clks_control & DAI_INTEL_IPC3_SSP_CLKCTRL_BCLK_ES) { - LOG_INF("hw_free stage: releasing BCLK clocks for SSP%d...", dp->index); - if (ssp->clk_active & SSP_CLK_BCLK_ACTIVE) { + if (ssp_plat_data->params.clks_control & DAI_INTEL_IPC3_SSP_CLKCTRL_BCLK_ES) { + LOG_INF("hw_free stage: releasing BCLK clocks for SSP%d...", + dp->dai_index); + if (ssp_plat_data->clk_active & SSP_CLK_BCLK_ACTIVE) { dai_ssp_update_bits(dp, SSCR0, SSCR0_SSE, 0); - LOG_INF("SSE clear for SSP%d", dp->index); + LOG_INF("SSE clear for SSP%d", dp->dai_index); } dai_ssp_bclk_disable_unprepare(dp); - ssp->clk_active &= ~SSP_CLK_BCLK_ES_REQ; + ssp_plat_data->clk_active &= ~SSP_CLK_BCLK_ES_REQ; } - if (ssp->params.clks_control & DAI_INTEL_IPC3_SSP_CLKCTRL_MCLK_ES) { - LOG_INF("hw_free stage: releasing MCLK clocks for SSP%d...", dp->index); + if (ssp_plat_data->params.clks_control & DAI_INTEL_IPC3_SSP_CLKCTRL_MCLK_ES) { + LOG_INF("hw_free stage: releasing MCLK clocks for SSP%d...", + dp->dai_index); dai_ssp_mclk_disable_unprepare(dp); - ssp->clk_active &= ~SSP_CLK_MCLK_ES_REQ; + ssp_plat_data->clk_active &= ~SSP_CLK_MCLK_ES_REQ; } break; default: @@ -1756,7 +1876,6 @@ static int dai_ssp_set_clock_control_ver_1(struct dai_intel_ssp *dp, static void dai_ssp_set_reg_config(struct dai_intel_ssp *dp, const struct dai_config *cfg, const struct dai_intel_ipc4_ssp_config *regs) { - struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp); uint32_t ssc0, sstsa, ssrsa, sscr1; ssc0 = regs->ssc0; @@ -1764,7 +1883,7 @@ static void dai_ssp_set_reg_config(struct dai_intel_ssp *dp, const struct dai_co ssrsa = SSRSA_GET(regs->ssrsa); sscr1 = regs->ssc1 & ~(SSCR1_RSRE | SSCR1_TSRE); - LOG_ERR("SSP%d configuration:", dp->index); + LOG_INF("SSP%d configuration:", dp->dai_index); if (regs->sstsa & SSTSA_TXEN || regs->ssrsa & SSRSA_RXEN || regs->ssc1 & (SSCR1_RSRE | SSCR1_TSRE)) { LOG_INF(" Ignoring %s%s%s%sfrom blob", @@ -1794,18 +1913,27 @@ static void dai_ssp_set_reg_config(struct dai_intel_ssp *dp, const struct dai_co LOG_INF(" ssioc = 0x%08x, ssrsa = 0x%08x, sstsa = 0x%08x", regs->ssioc, ssrsa, sstsa); - ssp->params.sample_valid_bits = SSCR0_DSIZE_GET(ssc0); + dp->ssp_plat_data->params.sample_valid_bits = SSCR0_DSIZE_GET(ssc0); if (ssc0 & SSCR0_EDSS) { - ssp->params.sample_valid_bits += 16; + dp->ssp_plat_data->params.sample_valid_bits += 16; } - ssp->params.tdm_slots = SSCR0_FRDC_GET(ssc0); - ssp->params.tx_slots = SSTSA_GET(sstsa); - ssp->params.rx_slots = SSRSA_GET(ssrsa); - ssp->params.fsync_rate = cfg->rate; + dp->ssp_plat_data->params.tdm_slots = SSCR0_FRDC_GET(ssc0); + dp->ssp_plat_data->params.tx_slots = SSTSA_GET(sstsa); + dp->ssp_plat_data->params.rx_slots = SSRSA_GET(ssrsa); + dp->ssp_plat_data->params.fsync_rate = cfg->rate; + + /* MCLK is needed if SSP is FS and/or BCLK provider */ + if (!(regs->ssc1 & (SSCR1_SCLKDIR | SSCR1_SFRMDIR))) { + dp->ssp_plat_data->clk_active |= SSP_CLK_MCLK_IS_NEEDED; + /* BCLK is only needed if SSP is BCLK provider */ + if (!(regs->ssc1 & SSCR1_SCLKDIR)) { + dp->ssp_plat_data->clk_active |= SSP_CLK_BCLK_IS_NEEDED; + } + } - ssp->state[DAI_DIR_PLAYBACK] = DAI_STATE_PRE_RUNNING; - ssp->state[DAI_DIR_CAPTURE] = DAI_STATE_PRE_RUNNING; + dp->state[DAI_DIR_PLAYBACK] = DAI_STATE_PRE_RUNNING; + dp->state[DAI_DIR_CAPTURE] = DAI_STATE_PRE_RUNNING; } static int dai_ssp_set_config_blob(struct dai_intel_ssp *dp, const struct dai_config *cfg, @@ -1813,34 +1941,42 @@ static int dai_ssp_set_config_blob(struct dai_intel_ssp *dp, const struct dai_co { const struct dai_intel_ipc4_ssp_configuration_blob_ver_1_5 *blob15 = spec_config; const struct dai_intel_ipc4_ssp_configuration_blob *blob = spec_config; - struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp); + struct dai_intel_ssp_plat_data *ssp_plat_data = dai_get_plat_data(dp); int err; /* set config only once for playback or capture */ - if (ssp->state[DAI_DIR_PLAYBACK] > DAI_STATE_READY || - ssp->state[DAI_DIR_CAPTURE] > DAI_STATE_READY) + if (ssp_plat_data->is_initialized) { + dp->state[DAI_DIR_PLAYBACK] = DAI_STATE_PRE_RUNNING; + dp->state[DAI_DIR_CAPTURE] = DAI_STATE_PRE_RUNNING; return 0; + } if (blob15->version == SSP_BLOB_VER_1_5) { err = dai_ssp_parse_aux_data(dp, spec_config); if (err) return err; dai_ssp_set_reg_config(dp, cfg, &blob15->i2s_ssp_config); - err = dai_ssp_set_clock_control_ver_1_5(dp, &blob15->i2s_mclk_control); - if (err) - return err; + if (ssp_plat_data->clk_active & SSP_CLK_MCLK_IS_NEEDED) { + err = dai_ssp_set_clock_control_ver_1_5(dp, &blob15->i2s_mclk_control); + if (err) + return err; + } } else { dai_ssp_set_reg_config(dp, cfg, &blob->i2s_driver_config.i2s_config); - err = dai_ssp_set_clock_control_ver_1(dp, &blob->i2s_driver_config.mclk_config); - if (err) - return err; + if (ssp_plat_data->clk_active & SSP_CLK_MCLK_IS_NEEDED) { + err = dai_ssp_set_clock_control_ver_1(dp, + &blob->i2s_driver_config.mclk_config); + if (err) + return err; + } } - ssp->clk_active |= SSP_CLK_MCLK_ES_REQ; + ssp_plat_data->clk_active |= SSP_CLK_MCLK_ES_REQ; /* enable port */ dai_ssp_update_bits(dp, SSCR0, SSCR0_SSE, SSCR0_SSE); - ssp->clk_active |= SSP_CLK_BCLK_ES_REQ; + ssp_plat_data->clk_active |= SSP_CLK_BCLK_ES_REQ; + ssp_plat_data->is_initialized = true; return 0; } @@ -1852,14 +1988,14 @@ static int dai_ssp_set_config_blob(struct dai_intel_ssp *dp, const struct dai_co */ static int dai_ssp_pre_start(struct dai_intel_ssp *dp) { - struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp); + struct dai_intel_ssp_plat_data *ssp_plat_data = dai_get_plat_data(dp); int ret = 0; /* * We will test if mclk/bclk is configured in * ssp_mclk/bclk_prepare_enable/disable functions */ - if (!(ssp->clk_active & SSP_CLK_MCLK_ES_REQ)) { + if (!(ssp_plat_data->clk_active & SSP_CLK_MCLK_ES_REQ)) { /* MCLK config */ ret = dai_ssp_mclk_prepare_enable(dp); if (ret < 0) { @@ -1867,7 +2003,7 @@ static int dai_ssp_pre_start(struct dai_intel_ssp *dp) } } - if (!(ssp->clk_active & SSP_CLK_BCLK_ES_REQ)) { + if (!(ssp_plat_data->clk_active & SSP_CLK_BCLK_ES_REQ)) { ret = dai_ssp_bclk_prepare_enable(dp); } @@ -1881,17 +2017,17 @@ static int dai_ssp_pre_start(struct dai_intel_ssp *dp) */ static void dai_ssp_post_stop(struct dai_intel_ssp *dp) { - struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp); + struct dai_intel_ssp_plat_data *ssp_plat_data = dai_get_plat_data(dp); /* release clocks if SSP is inactive */ - if (ssp->state[DAI_DIR_PLAYBACK] != DAI_STATE_RUNNING && - ssp->state[DAI_DIR_CAPTURE] != DAI_STATE_RUNNING) { - if (!(ssp->clk_active & SSP_CLK_BCLK_ES_REQ)) { - LOG_INF("releasing BCLK clocks for SSP%d...", dp->index); + if (dp->state[DAI_DIR_PLAYBACK] != DAI_STATE_RUNNING && + dp->state[DAI_DIR_CAPTURE] != DAI_STATE_RUNNING) { + if (!(ssp_plat_data->clk_active & SSP_CLK_BCLK_ES_REQ)) { + LOG_INF("releasing BCLK clocks for SSP%d...", dp->dai_index); dai_ssp_bclk_disable_unprepare(dp); } - if (!(ssp->clk_active & SSP_CLK_MCLK_ES_REQ)) { - LOG_INF("releasing MCLK clocks for SSP%d...", dp->index); + if (!(ssp_plat_data->clk_active & SSP_CLK_MCLK_ES_REQ)) { + LOG_INF("releasing MCLK clocks for SSP%d...", dp->dai_index); dai_ssp_mclk_disable_unprepare(dp); } } @@ -1899,25 +2035,25 @@ static void dai_ssp_post_stop(struct dai_intel_ssp *dp) static void dai_ssp_early_start(struct dai_intel_ssp *dp, int direction) { - struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp); + struct dai_intel_ssp_plat_data *ssp_plat_data = dai_get_plat_data(dp); k_spinlock_key_t key; key = k_spin_lock(&dp->lock); /* RX fifo must be cleared before start */ if (direction == DAI_DIR_CAPTURE) { - LOG_INF("SSP%d RX", dp->index); + LOG_INF("SSP%d RX", dp->dai_index); ssp_empty_rx_fifo_on_start(dp); } else { - LOG_INF("SSP%d TX", dp->index); + LOG_INF("SSP%d TX", dp->dai_index); } /* request mclk/bclk */ dai_ssp_pre_start(dp); - if (!(ssp->clk_active & SSP_CLK_BCLK_ES_REQ)) { + if (!(ssp_plat_data->clk_active & SSP_CLK_BCLK_ES_REQ)) { /* enable port */ - LOG_INF("SSP%d: set SSE", dp->index); + LOG_INF("SSP%d: set SSE", dp->dai_index); dai_ssp_update_bits(dp, SSCR0, SSCR0_SSE, SSCR0_SSE); } @@ -1935,16 +2071,17 @@ static void dai_ssp_start(struct dai_intel_ssp *dp, int direction) /* enable DMA */ if (direction == DAI_DIR_PLAYBACK) { - LOG_INF("SSP%d TX", dp->index); + LOG_INF("SSP%d TX", dp->dai_index); dai_ssp_update_bits(dp, SSCR1, SSCR1_TSRE, SSCR1_TSRE); dai_ssp_update_bits(dp, SSTSA, SSTSA_TXEN, SSTSA_TXEN); } else { - LOG_INF("SSP%d RX", dp->index); + LOG_INF("SSP%d RX", dp->dai_index); dai_ssp_update_bits(dp, SSCR1, SSCR1_RSRE, SSCR1_RSRE); dai_ssp_update_bits(dp, SSRSA, SSRSA_RXEN, SSRSA_RXEN); } - ssp->state[direction] = DAI_STATE_RUNNING; + dp->state[direction] = DAI_STATE_RUNNING; + ssp_acquire_port(dp->ssp_plat_data); /* * Wait to get valid fifo status in clock consumer mode. TODO it's @@ -1968,6 +2105,7 @@ static void dai_ssp_start(struct dai_intel_ssp *dp, int direction) static void dai_ssp_stop(struct dai_intel_ssp *dp, int direction) { struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp); + struct dai_intel_ssp_plat_data *ssp_plat_data = dai_get_plat_data(dp); k_spinlock_key_t key; key = k_spin_lock(&dp->lock); @@ -1988,64 +2126,68 @@ static void dai_ssp_stop(struct dai_intel_ssp *dp, int direction) /* stop Rx if neeed */ if (direction == DAI_DIR_CAPTURE && - ssp->state[DAI_DIR_CAPTURE] != DAI_STATE_PRE_RUNNING) { - LOG_INF("SSP%d RX", dp->index); + dp->state[DAI_DIR_CAPTURE] != DAI_STATE_PRE_RUNNING) { + LOG_INF("SSP%d RX", dp->dai_index); dai_ssp_update_bits(dp, SSRSA, SSRSA_RXEN, 0); 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; + dp->state[DAI_DIR_CAPTURE] = DAI_STATE_PRE_RUNNING; + ssp_release_port(ssp_plat_data); } /* stop Tx if needed */ if (direction == DAI_DIR_PLAYBACK && - ssp->state[DAI_DIR_PLAYBACK] != DAI_STATE_PRE_RUNNING) { - LOG_INF("SSP%d TX", dp->index); + dp->state[DAI_DIR_PLAYBACK] != DAI_STATE_PRE_RUNNING) { + LOG_INF("SSP%d TX", dp->dai_index); 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; + dp->state[DAI_DIR_PLAYBACK] = DAI_STATE_PRE_RUNNING; + ssp_release_port(ssp_plat_data); } /* 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 && + if (dp->state[DAI_DIR_CAPTURE] == DAI_STATE_PRE_RUNNING && + dp->state[DAI_DIR_PLAYBACK] == DAI_STATE_PRE_RUNNING && COND_CODE_1(CONFIG_INTEL_ADSP_CAVS, - (!(ssp->clk_active & SSP_CLK_BCLK_ES_REQ)), (true))) { - LOG_INF("SSP%d: clear SSE", dp->index); - dai_ssp_update_bits(dp, SSCR0, SSCR0_SSE, 0); + (!(ssp_plat_data->clk_active & SSP_CLK_BCLK_ES_REQ)), (true))) { + + if (!ssp_is_acquired(ssp_plat_data)) { + dai_ssp_update_bits(dp, SSCR0, SSCR0_SSE, 0); + LOG_INF("%s SSE clear SSP%d", __func__, ssp_plat_data->ssp_index); + } } - dai_ssp_post_stop(dp); + if (!ssp_is_acquired(ssp_plat_data)) { + dai_ssp_post_stop(dp); + } k_spin_unlock(&dp->lock, key); } static void dai_ssp_pause(struct dai_intel_ssp *dp, int direction) { - struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp); - if (direction == DAI_DIR_CAPTURE) { - LOG_INF("SSP%d RX", dp->index); + LOG_INF("SSP%d RX", dp->dai_index); } else { - LOG_INF("SSP%d TX", dp->index); + LOG_INF("SSP%d TX", dp->dai_index); } - ssp->state[direction] = DAI_STATE_PAUSED; + dp->state[direction] = DAI_STATE_PAUSED; } static int dai_ssp_trigger(const struct device *dev, enum dai_dir dir, enum dai_trigger_cmd cmd) { struct dai_intel_ssp *dp = (struct dai_intel_ssp *)dev->data; - struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp); int array_index = SSP_ARRAY_INDEX(dir); - LOG_DBG("SSP%d: cmd %d", dp->index, cmd); + LOG_DBG("SSP%d: cmd %d", dp->dai_index, cmd); switch (cmd) { case DAI_TRIGGER_START: - if (ssp->state[array_index] == DAI_STATE_PAUSED || - ssp->state[array_index] == DAI_STATE_PRE_RUNNING) { + if (dp->state[array_index] == DAI_STATE_PAUSED || + dp->state[array_index] == DAI_STATE_PRE_RUNNING) { dai_ssp_start(dp, array_index); } break; @@ -2070,6 +2212,7 @@ static int dai_ssp_config_get(const struct device *dev, struct dai_config *cfg, struct dai_config *params = (struct dai_config *)dev->config; struct dai_intel_ssp *dp = (struct dai_intel_ssp *)dev->data; struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp); + struct dai_intel_ssp_plat_data *ssp_plat_data = dai_get_plat_data(dp); if (!cfg) { return -EINVAL; @@ -2080,15 +2223,15 @@ static int dai_ssp_config_get(const struct device *dev, struct dai_config *cfg, return 0; } - params->rate = ssp->params.fsync_rate; + params->rate = ssp_plat_data->params.fsync_rate; if (dir == DAI_DIR_PLAYBACK) { - params->channels = POPCOUNT(ssp->params.tx_slots); + params->channels = POPCOUNT(ssp_plat_data->params.tx_slots); } else { - params->channels = POPCOUNT(ssp->params.rx_slots); + params->channels = POPCOUNT(ssp_plat_data->params.rx_slots); } - params->word_size = ssp->params.sample_valid_bits; + params->word_size = ssp_plat_data->params.sample_valid_bits; *cfg = *params; @@ -2106,7 +2249,7 @@ static int dai_ssp_config_set(const struct device *dev, const struct dai_config } else { ret = dai_ssp_set_config_blob(dp, cfg, bespoke_cfg); } - dai_ssp_program_channel_map(dp, cfg, dp->index); + dai_ssp_program_channel_map(dp, cfg, dp->ssp_index); return ret; } @@ -2115,19 +2258,20 @@ static const struct dai_properties *dai_ssp_get_properties(const struct device * { struct dai_intel_ssp *dp = (struct dai_intel_ssp *)dev->data; struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp); + struct dai_intel_ssp_plat_data *ssp_plat_data = dai_get_plat_data(dp); struct dai_properties *prop = &ssp->props; int array_index = SSP_ARRAY_INDEX(dir); - prop->fifo_address = dp->plat_data.fifo[array_index].offset; - prop->dma_hs_id = dp->plat_data.fifo[array_index].handshake; + prop->fifo_address = ssp_plat_data->fifo[array_index].offset; + prop->dma_hs_id = ssp_plat_data->fifo[array_index].handshake; - if (ssp->clk_active & SSP_CLK_BCLK_ACTIVE) { + if (ssp_plat_data->clk_active & SSP_CLK_BCLK_ACTIVE) { prop->reg_init_delay = 0; } else { - prop->reg_init_delay = ssp->params.bclk_delay; + prop->reg_init_delay = ssp_plat_data->params.bclk_delay; } - LOG_INF("SSP%u: fifo %u, handshake %u, init delay %u", dp->index, prop->fifo_address, + LOG_INF("SSP%u: fifo %u, handshake %u, init delay %u", dp->dai_index, prop->fifo_address, prop->dma_hs_id, prop->reg_init_delay); return prop; @@ -2135,6 +2279,7 @@ static const struct dai_properties *dai_ssp_get_properties(const struct device * static int dai_ssp_probe(struct dai_intel_ssp *dp) { + struct dai_intel_ssp_plat_data *ssp_plat_data = dai_get_plat_data(dp); struct dai_intel_ssp_pdata *ssp; if (dai_get_drvdata(dp)) { @@ -2144,47 +2289,59 @@ static int dai_ssp_probe(struct dai_intel_ssp *dp) /* allocate private data */ ssp = k_calloc(1, sizeof(*ssp)); if (!ssp) { - LOG_ERR("SSP%d: alloc failed", dp->index); + LOG_ERR("SSP%d: alloc failed", ssp_plat_data->ssp_index); return -ENOMEM; } dai_set_drvdata(dp, ssp); - ssp->state[DAI_DIR_PLAYBACK] = DAI_STATE_READY; - ssp->state[DAI_DIR_CAPTURE] = DAI_STATE_READY; + dp->state[DAI_DIR_PLAYBACK] = DAI_STATE_READY; + dp->state[DAI_DIR_CAPTURE] = DAI_STATE_READY; + + if (ssp_plat_data->is_power_en) { + return 0; + } #if CONFIG_INTEL_MN /* Reset M/N, power-gating functions need it */ - dai_ssp_mn_reset_bclk_divider(dp, dp->index); + dai_ssp_mn_reset_bclk_divider(dp, ssp_plat_data->ssp_index); #endif /* Enable SSP power */ - dai_ssp_pm_runtime_en_ssp_power(dp, dp->index); + dai_ssp_pm_runtime_en_ssp_power(dp, ssp_plat_data->ssp_index); /* Disable dynamic clock gating before touching any register */ - dai_ssp_pm_runtime_dis_ssp_clk_gating(dp, dp->index); + dai_ssp_pm_runtime_dis_ssp_clk_gating(dp, ssp_plat_data->ssp_index); + + ssp_plat_data->is_power_en = true; return 0; } static int dai_ssp_remove(struct dai_intel_ssp *dp) { - dai_ssp_pm_runtime_en_ssp_clk_gating(dp, dp->index); + struct dai_intel_ssp_plat_data *ssp_plat_data = dai_get_plat_data(dp); + + dai_ssp_pm_runtime_en_ssp_clk_gating(dp, ssp_plat_data->ssp_index); dai_ssp_mclk_disable_unprepare(dp); dai_ssp_bclk_disable_unprepare(dp); /* Disable SSP power */ - dai_ssp_pm_runtime_dis_ssp_power(dp, dp->index); + dai_ssp_pm_runtime_dis_ssp_power(dp, ssp_plat_data->ssp_index); k_free(dai_get_drvdata(dp)); dai_set_drvdata(dp, NULL); + ssp_plat_data->is_initialized = false; + ssp_plat_data->is_power_en = false; + return 0; } static int ssp_pm_action(const struct device *dev, enum pm_device_action action) { struct dai_intel_ssp *dp = (struct dai_intel_ssp *)dev->data; + switch (action) { case PM_DEVICE_ACTION_SUSPEND: dai_ssp_remove(dp); @@ -2203,8 +2360,19 @@ static int ssp_pm_action(const struct device *dev, enum pm_device_action action) return 0; } +static int dai_intel_ssp_init_device(const struct device *dev) +{ + struct dai_intel_ssp *dp = (struct dai_intel_ssp *)dev->data; + + dp->ssp_plat_data = ssp_get_device_instance(dp->ssp_index); + + return 0; +}; + static int ssp_init(const struct device *dev) { + dai_intel_ssp_init_device(dev); + if (pm_device_on_power_domain(dev)) { pm_device_init_off(dev); } else { @@ -2223,60 +2391,20 @@ static struct dai_driver_api dai_intel_ssp_api_funcs = { .get_properties = dai_ssp_get_properties, }; -static struct dai_intel_ssp_freq_table ssp_freq_table[] = { - { DT_PROP(DT_NODELABEL(audioclk), clock_frequency), - DT_PROP(DT_NODELABEL(audioclk), clock_frequency) / 1000}, - { DT_PROP(DT_NODELABEL(sysclk), clock_frequency), - DT_PROP(DT_NODELABEL(sysclk), clock_frequency) / 1000}, - { DT_PROP(DT_NODELABEL(pllclk), clock_frequency), - DT_PROP(DT_NODELABEL(pllclk), clock_frequency) / 1000}, -}; - -static uint32_t ssp_freq_sources[] = { - DAI_INTEL_SSP_CLOCK_AUDIO_CARDINAL, - DAI_INTEL_SSP_CLOCK_XTAL_OSCILLATOR, - DAI_INTEL_SSP_CLOCK_PLL_FIXED, -}; -static struct dai_intel_ssp_mn ssp_mn_divider = { - .base = DT_REG_ADDR_BY_IDX(DT_NODELABEL(ssp0), 1), -}; +#define DT_DRV_COMPAT intel_ssp_dai -static const char irq_name_level5_z[] = "level5"; - -#define DAI_INTEL_SSP_DEVICE_INIT(n) \ - static struct dai_config dai_intel_ssp_config_##n = { \ - .type = DAI_INTEL_SSP, \ - .dai_index = n, \ - }; \ - static struct dai_intel_ssp dai_intel_ssp_data_##n = { \ - .index = n, \ - .plat_data = { \ - .base = DT_INST_REG_ADDR_BY_IDX(n, 0), \ - IF_ENABLED(DT_NODE_EXISTS(DT_NODELABEL(sspbase)), \ - (.ip_base = DT_REG_ADDR_BY_IDX(DT_NODELABEL(sspbase), 0),))\ - .shim_base = DT_REG_ADDR_BY_IDX(DT_NODELABEL(shim), 0), \ - IF_ENABLED(DT_NODE_EXISTS(DT_NODELABEL(hdamlssp)), \ - (.hdamlssp_base = DT_REG_ADDR(DT_NODELABEL(hdamlssp)),))\ - IF_ENABLED(DT_INST_PROP_HAS_IDX(n, i2svss, 0), \ - (.i2svss_base = DT_INST_PROP_BY_IDX(n, i2svss, 0),))\ - .irq = n, \ - .irq_name = irq_name_level5_z, \ - .fifo[DAI_DIR_PLAYBACK].offset = \ - DT_INST_REG_ADDR_BY_IDX(n, 0) + SSDR, \ - .fifo[DAI_DIR_PLAYBACK].handshake = \ - DT_INST_DMAS_CELL_BY_NAME(n, tx, channel), \ - .fifo[DAI_DIR_CAPTURE].offset = \ - DT_INST_REG_ADDR_BY_IDX(n, 0) + SSDR, \ - .fifo[DAI_DIR_CAPTURE].handshake = \ - DT_INST_DMAS_CELL_BY_NAME(n, rx, channel), \ - .mn_inst = &ssp_mn_divider, \ - .ftable = ssp_freq_table, \ - .fsources = ssp_freq_sources, \ - }, \ +#define DAI_INTEL_SSP_DEVICE_INIT(n) \ + static struct dai_config dai_intel_ssp_config_##n = { \ + .type = DAI_INTEL_SSP, \ + .dai_index = DT_INST_REG_ADDR(n), \ + }; \ + static struct dai_intel_ssp dai_intel_ssp_data_##n = { \ + .dai_index = DT_INST_REG_ADDR(n), \ + .ssp_index = DT_PROP(DT_INST_PARENT(n), ssp_index), \ }; \ \ - PM_DEVICE_DT_INST_DEFINE(n, ssp_pm_action); \ + PM_DEVICE_DT_INST_DEFINE(n, ssp_pm_action); \ \ DEVICE_DT_INST_DEFINE(n, \ ssp_init, PM_DEVICE_DT_INST_GET(n), \ diff --git a/drivers/dai/intel/ssp/ssp.h b/drivers/dai/intel/ssp/ssp.h index 5a187730dd5..8c3e248a0d9 100644 --- a/drivers/dai/intel/ssp/ssp.h +++ b/drivers/dai/intel/ssp/ssp.h @@ -211,10 +211,12 @@ /* SSP flush retry counts maximum */ #define DAI_INTEL_SSP_RX_FLUSH_RETRY_MAX 16 -#define SSP_CLK_MCLK_ES_REQ BIT(0) -#define SSP_CLK_MCLK_ACTIVE BIT(1) -#define SSP_CLK_BCLK_ES_REQ BIT(2) -#define SSP_CLK_BCLK_ACTIVE BIT(3) +#define SSP_CLK_MCLK_IS_NEEDED BIT(0) +#define SSP_CLK_MCLK_ES_REQ BIT(1) +#define SSP_CLK_MCLK_ACTIVE BIT(2) +#define SSP_CLK_BCLK_IS_NEEDED BIT(3) +#define SSP_CLK_BCLK_ES_REQ BIT(4) +#define SSP_CLK_BCLK_ACTIVE BIT(5) #define I2SLCTL_OFFSET 0x04 @@ -242,14 +244,23 @@ /** \brief Offset of MCLK Divider x Ratio Register. */ #define MN_MDIVR(x) (0x180 + (x) * 0x4) + +/** \brief Enables the output of MCLK Divider. + * On ACE+ there is a single divider for all MCLKs + */ +#define MN_MDIVCTRL_M_DIV_ENABLE(x) BIT(0) + #else #define MN_MDIVCTRL 0x0 #define MN_MDIVR(x) (0x80 + (x) * 0x4) -#endif -/** \brief Enables the output of MCLK Divider. */ +/** \brief Enables the output of MCLK Divider. + * Each MCLK divider can be enabled separately. + */ #define MN_MDIVCTRL_M_DIV_ENABLE(x) BIT(x) +#endif + /** \brief Bits for setting MCLK source clock. */ #define MCDSS(x) DAI_INTEL_SSP_SET_BITS(17, 16, x) @@ -316,6 +327,10 @@ struct dai_intel_ssp_plat_fifo_data { }; struct dai_intel_ssp_plat_data { + uint32_t ssp_index; + int acquire_count; + bool is_initialized; + bool is_power_en; uint32_t base; uint32_t ip_base; uint32_t shim_base; @@ -330,24 +345,25 @@ struct dai_intel_ssp_plat_data { struct dai_intel_ssp_mn *mn_inst; struct dai_intel_ssp_freq_table *ftable; uint32_t *fsources; + uint32_t clk_active; + struct dai_intel_ipc3_ssp_params params; }; struct dai_intel_ssp_pdata { uint32_t sscr0; uint32_t sscr1; uint32_t psp; - uint32_t state[2]; - uint32_t clk_active; struct dai_config config; struct dai_properties props; - struct dai_intel_ipc3_ssp_params params; }; struct dai_intel_ssp { - uint32_t index; /**< index */ + uint32_t dai_index; + uint32_t ssp_index; + uint32_t state[2]; struct k_spinlock lock; /**< locking mechanism */ int sref; /**< simple ref counter, guarded by lock */ - struct dai_intel_ssp_plat_data plat_data; + struct dai_intel_ssp_plat_data *ssp_plat_data; void *priv_data; }; diff --git a/drivers/dai/nxp/sai/sai.c b/drivers/dai/nxp/sai/sai.c index c61e6115a80..8deb17e06a1 100644 --- a/drivers/dai/nxp/sai/sai.c +++ b/drivers/dai/nxp/sai/sai.c @@ -696,7 +696,7 @@ static int sai_trigger_start(const struct device *dev, struct sai_data *data; const struct sai_config *cfg; uint32_t old_state; - int ret; + int ret, i; data = dev->data; cfg = dev->config; @@ -733,7 +733,12 @@ static int sai_trigger_start(const struct device *dev, 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? */ + /* avoid initial underrun by writing a frame's worth of 0s */ + if (dir == DAI_DIR_TX) { + for (i = 0; i < data->cfg.channels; i++) { + SAI_WriteData(UINT_TO_I2S(data->regmap), cfg->tx_dline, 0x0); + } + } /* TODO: for now, only DMA mode is supported */ SAI_TX_RX_DMA_ENABLE_DISABLE(dir, data->regmap, true); diff --git a/drivers/disk/CMakeLists.txt b/drivers/disk/CMakeLists.txt index 0b786e89c5b..0202238a1d2 100644 --- a/drivers/disk/CMakeLists.txt +++ b/drivers/disk/CMakeLists.txt @@ -7,6 +7,7 @@ zephyr_library() zephyr_library_sources_ifdef(CONFIG_DISK_DRIVER_FLASH flashdisk.c) zephyr_library_sources_ifdef(CONFIG_DISK_DRIVER_RAM ramdisk.c) +zephyr_library_sources_ifdef(CONFIG_DISK_DRIVER_LOOPBACK loopback_disk.c) zephyr_library_sources_ifdef(CONFIG_SDMMC_STM32 sdmmc_stm32.c) zephyr_library_sources_ifdef(CONFIG_SDMMC_SUBSYS sdmmc_subsys.c) diff --git a/drivers/disk/Kconfig b/drivers/disk/Kconfig index 1412de04f98..9c1723e6e8d 100644 --- a/drivers/disk/Kconfig +++ b/drivers/disk/Kconfig @@ -12,6 +12,7 @@ source "drivers/disk/Kconfig.ram" source "drivers/disk/Kconfig.flash" source "drivers/disk/Kconfig.sdmmc" source "drivers/disk/Kconfig.mmc" +source "drivers/disk/Kconfig.loopback" rsource "nvme/Kconfig" diff --git a/drivers/disk/Kconfig.loopback b/drivers/disk/Kconfig.loopback new file mode 100644 index 00000000000..9b429cc8739 --- /dev/null +++ b/drivers/disk/Kconfig.loopback @@ -0,0 +1,22 @@ +# Copyright (c) 2024 Embedded Solutions GmbH +# SPDX-License-Identifier: Apache-2.0 + +menuconfig DISK_DRIVER_LOOPBACK + bool "Loopback Disk" + depends on FILE_SYSTEM + help + Enables mounting the contents of a file as a separate disk. + +if DISK_DRIVER_LOOPBACK + +config LOOPBACK_DISK_SECTOR_SIZE + int "Loopback disk sector size" + default 512 + help + Sets the sector size used for loopback-mounted disks. + +module = LOOPBACK_DISK +module-str = loopback_disk +source "subsys/logging/Kconfig.template.log_config" + +endif # DISK_DRIVER_LOOPBACK diff --git a/drivers/disk/Kconfig.sdmmc b/drivers/disk/Kconfig.sdmmc index a5463eff529..b1999b64eff 100644 --- a/drivers/disk/Kconfig.sdmmc +++ b/drivers/disk/Kconfig.sdmmc @@ -52,7 +52,8 @@ config SDMMC_STM32 config SDMMC_STM32_HWFC bool "STM32 SDMMC Hardware Flow control" depends on SDMMC_STM32 - depends on SOC_SERIES_STM32H7X || \ + depends on SOC_SERIES_STM32H5X || \ + SOC_SERIES_STM32H7X || \ SOC_SERIES_STM32F7X || \ SOC_SERIES_STM32L4X || \ SOC_SERIES_STM32L5X diff --git a/drivers/disk/loopback_disk.c b/drivers/disk/loopback_disk.c new file mode 100644 index 00000000000..50b7beeaabc --- /dev/null +++ b/drivers/disk/loopback_disk.c @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2023-2024 Embedded Solutions GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include + +LOG_MODULE_REGISTER(loopback_disk_access, CONFIG_LOOPBACK_DISK_LOG_LEVEL); + +#define LOOPBACK_SECTOR_SIZE CONFIG_LOOPBACK_DISK_SECTOR_SIZE + +static inline struct loopback_disk_access *get_ctx(struct disk_info *info) +{ + return CONTAINER_OF(info, struct loopback_disk_access, info); +} + +static int loopback_disk_access_init(struct disk_info *disk) +{ + return 0; +} +static int loopback_disk_access_status(struct disk_info *disk) +{ + return DISK_STATUS_OK; +} +static int loopback_disk_access_read(struct disk_info *disk, uint8_t *data_buf, + uint32_t start_sector, uint32_t num_sector) +{ + struct loopback_disk_access *ctx = get_ctx(disk); + + int ret = fs_seek(&ctx->file, start_sector * LOOPBACK_SECTOR_SIZE, FS_SEEK_SET); + + if (ret != 0) { + LOG_ERR("Failed to seek backing file: %d", ret); + return ret; + } + + const size_t total_len = num_sector * LOOPBACK_SECTOR_SIZE; + size_t len_left = total_len; + + while (len_left > 0) { + ret = fs_read(&ctx->file, data_buf, len_left); + if (ret < 0) { + LOG_ERR("Failed to read from backing file: %d", ret); + return ret; + } + if (ret == 0) { + LOG_WRN("Tried to read past end of backing file"); + return -EIO; + } + __ASSERT(ret <= len_left, + "fs_read returned more than we asked for: %d instead of %ld", ret, + len_left); + len_left -= ret; + } + + return 0; +} +static int loopback_disk_access_write(struct disk_info *disk, const uint8_t *data_buf, + uint32_t start_sector, uint32_t num_sector) +{ + struct loopback_disk_access *ctx = get_ctx(disk); + + if (start_sector + num_sector > ctx->num_sectors) { + LOG_WRN("Tried to write past end of backing file"); + return -EIO; + } + + int ret = fs_seek(&ctx->file, start_sector * LOOPBACK_SECTOR_SIZE, FS_SEEK_SET); + + if (ret != 0) { + LOG_ERR("Failed to seek backing file: %d", ret); + return ret; + } + + const size_t total_len = num_sector * LOOPBACK_SECTOR_SIZE; + size_t buf_offset = 0; + + while (buf_offset < total_len) { + ret = fs_write(&ctx->file, &data_buf[buf_offset], total_len - buf_offset); + if (ret < 0) { + LOG_ERR("Failed to write to backing file: %d", ret); + return ret; + } + if (ret == 0) { + LOG_ERR("0-byte write to backing file"); + return -EIO; + } + buf_offset += ret; + } + + return 0; +} +static int loopback_disk_access_ioctl(struct disk_info *disk, uint8_t cmd, void *buff) +{ + struct loopback_disk_access *ctx = get_ctx(disk); + + switch (cmd) { + case DISK_IOCTL_GET_SECTOR_COUNT: { + *(uint32_t *)buff = ctx->num_sectors; + return 0; + } + case DISK_IOCTL_GET_SECTOR_SIZE: { + *(uint32_t *)buff = LOOPBACK_SECTOR_SIZE; + return 0; + } + case DISK_IOCTL_CTRL_SYNC: + return fs_sync(&ctx->file); + default: + return -ENOTSUP; + } +} + +static const struct disk_operations loopback_disk_operations = { + .init = loopback_disk_access_init, + .status = loopback_disk_access_status, + .read = loopback_disk_access_read, + .write = loopback_disk_access_write, + .ioctl = loopback_disk_access_ioctl, +}; + +int loopback_disk_access_register(struct loopback_disk_access *ctx, const char *file_path, + const char *disk_access_name) +{ + ctx->file_path = file_path; + + ctx->info.name = disk_access_name; + ctx->info.ops = &loopback_disk_operations; + + struct fs_dirent entry; + int ret = fs_stat(ctx->file_path, &entry); + + if (ret != 0) { + LOG_ERR("Failed to stat backing file: %d", ret); + return ret; + } + if (entry.size % LOOPBACK_SECTOR_SIZE != 0) { + LOG_WRN("Backing file is not a multiple of sector size (%d bytes), " + "rounding down: %ld bytes", + LOOPBACK_SECTOR_SIZE, entry.size); + } + ctx->num_sectors = entry.size / LOOPBACK_SECTOR_SIZE; + + fs_file_t_init(&ctx->file); + ret = fs_open(&ctx->file, ctx->file_path, FS_O_READ | FS_O_WRITE); + if (ret != 0) { + LOG_ERR("Failed to open backing file: %d", ret); + return ret; + } + + ret = disk_access_register(&ctx->info); + if (ret != 0) { + LOG_ERR("Failed to register disk access: %d", ret); + return ret; + } + + return 0; +} + +int loopback_disk_access_unregister(struct loopback_disk_access *ctx) +{ + int ret; + + ret = disk_access_unregister(&ctx->info); + if (ret != 0) { + LOG_ERR("Failed to unregister disk access: %d", ret); + return ret; + } + ctx->info.name = NULL; + ctx->info.ops = NULL; + + ret = fs_close(&ctx->file); + if (ret != 0) { + LOG_ERR("Failed to close backing file: %d", ret); + return ret; + } + + return 0; +} diff --git a/drivers/display/Kconfig.mcux_elcdif b/drivers/display/Kconfig.mcux_elcdif index 43f90374380..48c4857a8eb 100644 --- a/drivers/display/Kconfig.mcux_elcdif +++ b/drivers/display/Kconfig.mcux_elcdif @@ -60,8 +60,13 @@ choice MCUX_ELCDIF_PXP_ROTATE_DIRECTION prompt "Rotation angle of PXP" help Set rotation angle of PXP. The ELCDIF cannot detect the correct - rotation angle based on the call to display_write, so the user - should configure it here. + rotation angle based on the call to display_write, so the user should + configure it here. In order for PXP rotation to work, calls to + display_write MUST supply a framebuffer equal in size to screen width + and height (without rotation applied). Note that the width and + height settings of the screen in devicetree should not be modified + from their values in the default screen orientation when using this + functionality. config MCUX_ELCDIF_PXP_ROTATE_0 bool "Rotate display by 0 degrees" @@ -72,17 +77,19 @@ config MCUX_ELCDIF_PXP_ROTATE_0 config MCUX_ELCDIF_PXP_ROTATE_90 bool "Rotate display by 90 degrees" help - Rotate display clockwise by 90 degrees + Rotate display counter-clockwise by 90 degrees. + For LVGL, this corresponds to a rotation of 270 degrees config MCUX_ELCDIF_PXP_ROTATE_180 bool "Rotate display by 180 degrees" help - Rotate display clockwise by 180 degrees + Rotate display counter-clockwise by 180 degrees config MCUX_ELCDIF_PXP_ROTATE_270 bool "Rotate display by 270 degrees" help - Rotate display clockwise by 270 degrees + Rotate display counter-clockwise by 270 degrees + For LVGL, this corresponds to a rotation of 90 degrees endchoice diff --git a/drivers/display/Kconfig.st7735r b/drivers/display/Kconfig.st7735r index 94153eca585..387665ace45 100644 --- a/drivers/display/Kconfig.st7735r +++ b/drivers/display/Kconfig.st7735r @@ -7,6 +7,6 @@ config ST7735R bool "ST7735R/ST7735S display driver" default y depends on DT_HAS_SITRONIX_ST7735R_ENABLED - select SPI + select MIPI_DBI help Enable driver for ST7735R/ST7735S display driver. diff --git a/drivers/display/display_hx8394.c b/drivers/display/display_hx8394.c index b14846ae343..e6e67161d32 100644 --- a/drivers/display/display_hx8394.c +++ b/drivers/display/display_hx8394.c @@ -406,6 +406,37 @@ const uint8_t hx8394_cmd3[] = {0xC6U, 0xEDU}; const uint8_t tear_config[] = {HX8394_SET_TEAR, HX8394_TEAR_VBLANK}; +static ssize_t hx8394_mipi_tx(const struct device *mipi_dev, uint8_t channel, + const void *buf, size_t len) +{ + /* Send MIPI transfers using low power mode */ + struct mipi_dsi_msg msg = { + .tx_buf = buf, + .tx_len = len, + .flags = MIPI_DSI_MSG_USE_LPM, + }; + + switch (len) { + case 0U: + msg.type = MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM; + break; + + case 1U: + msg.type = MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM; + break; + + case 2U: + msg.type = MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM; + break; + + default: + msg.type = MIPI_DSI_GENERIC_LONG_WRITE; + break; + } + + return mipi_dsi_transfer(mipi_dev, channel, &msg); +} + static int hx8394_write(const struct device *dev, const uint16_t x, const uint16_t y, const struct display_buffer_descriptor *desc, @@ -477,7 +508,7 @@ static int hx8394_set_orientation(const struct device *dev, default: return -ENOTSUP; } - return mipi_dsi_generic_write(config->mipi_dsi, config->channel, param, 2); + return hx8394_mipi_tx(config->mipi_dsi, config->channel, param, 2); } static void hx8394_get_capabilities(const struct device *dev, @@ -557,66 +588,66 @@ static int hx8394_init(const struct device *dev) k_sleep(K_MSEC(50)); } /* Enable extended commands */ - ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel, - enable_extension, sizeof(enable_extension)); + ret = hx8394_mipi_tx(config->mipi_dsi, config->channel, + enable_extension, sizeof(enable_extension)); if (ret < 0) { return ret; } /* Set the number of lanes to DSISETUP0 parameter */ setmipi[1] |= (config->num_of_lanes - 1); - ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel, - setmipi, sizeof(setmipi)); + ret = hx8394_mipi_tx(config->mipi_dsi, config->channel, + setmipi, sizeof(setmipi)); if (ret < 0) { return ret; } /* Set scan direction */ - ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel, - address_config, sizeof(address_config)); + ret = hx8394_mipi_tx(config->mipi_dsi, config->channel, + address_config, sizeof(address_config)); if (ret < 0) { return ret; } /* Set voltage and current targets */ - ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel, - power_config, sizeof(power_config)); + ret = hx8394_mipi_tx(config->mipi_dsi, config->channel, + power_config, sizeof(power_config)); if (ret < 0) { return ret; } /* Setup display line count and front/back porch size */ - ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel, - line_config, sizeof(line_config)); + ret = hx8394_mipi_tx(config->mipi_dsi, config->channel, + line_config, sizeof(line_config)); if (ret < 0) { return ret; } /* Setup display cycle counts (in counts of TCON CLK) */ - ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel, - cycle_config, sizeof(cycle_config)); + ret = hx8394_mipi_tx(config->mipi_dsi, config->channel, + cycle_config, sizeof(cycle_config)); if (ret < 0) { return ret; } /* Set group delay values */ - ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel, - gip0_config, sizeof(gip0_config)); + ret = hx8394_mipi_tx(config->mipi_dsi, config->channel, + gip0_config, sizeof(gip0_config)); if (ret < 0) { return ret; } /* Set group clock selections */ - ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel, - gip1_config, sizeof(gip1_config)); + ret = hx8394_mipi_tx(config->mipi_dsi, config->channel, + gip1_config, sizeof(gip1_config)); if (ret < 0) { return ret; } /* Set group clock selections for GS mode */ - ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel, - gip2_config, sizeof(gip2_config)); + ret = hx8394_mipi_tx(config->mipi_dsi, config->channel, + gip2_config, sizeof(gip2_config)); if (ret < 0) { return ret; } @@ -627,15 +658,15 @@ static int hx8394_init(const struct device *dev) */ k_msleep(1); /* Set VCOM voltage config */ - ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel, - vcom_config, sizeof(vcom_config)); + ret = hx8394_mipi_tx(config->mipi_dsi, config->channel, + vcom_config, sizeof(vcom_config)); if (ret < 0) { return ret; } /* Set manufacturer supplied gamma values */ - ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel, - gamma_config, sizeof(gamma_config)); + ret = hx8394_mipi_tx(config->mipi_dsi, config->channel, + gamma_config, sizeof(gamma_config)); if (ret < 0) { return ret; } @@ -643,15 +674,15 @@ static int hx8394_init(const struct device *dev) /* This command is not documented in datasheet, but is included * in the display initialization done by MCUXpresso SDK */ - ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel, - hx8394_cmd1, sizeof(hx8394_cmd1)); + ret = hx8394_mipi_tx(config->mipi_dsi, config->channel, + hx8394_cmd1, sizeof(hx8394_cmd1)); if (ret < 0) { return ret; } /* Set panel to BGR mode, and reverse colors */ - ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel, - panel_config, sizeof(panel_config)); + ret = hx8394_mipi_tx(config->mipi_dsi, config->channel, + panel_config, sizeof(panel_config)); if (ret < 0) { return ret; } @@ -659,8 +690,8 @@ static int hx8394_init(const struct device *dev) /* This command is not documented in datasheet, but is included * in the display initialization done by MCUXpresso SDK */ - ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel, - hx8394_cmd2, sizeof(hx8394_cmd2)); + ret = hx8394_mipi_tx(config->mipi_dsi, config->channel, + hx8394_cmd2, sizeof(hx8394_cmd2)); if (ret < 0) { return ret; } @@ -668,43 +699,43 @@ static int hx8394_init(const struct device *dev) /* Write values to manufacturer register banks */ param[0] = HX8394_SETBANK; param[1] = 0x2; - ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel, - param, 2); + ret = hx8394_mipi_tx(config->mipi_dsi, config->channel, + param, 2); if (ret < 0) { return ret; } - ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel, - hx8394_bank2, sizeof(hx8394_bank2)); + ret = hx8394_mipi_tx(config->mipi_dsi, config->channel, + hx8394_bank2, sizeof(hx8394_bank2)); if (ret < 0) { return ret; } param[1] = 0x0; - ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel, - param, 2); + ret = hx8394_mipi_tx(config->mipi_dsi, config->channel, + param, 2); if (ret < 0) { return ret; } /* Select bank 1 */ param[1] = 0x1; - ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel, - param, 2); + ret = hx8394_mipi_tx(config->mipi_dsi, config->channel, + param, 2); if (ret < 0) { return ret; } - ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel, - hx8394_bank1, sizeof(hx8394_bank1)); + ret = hx8394_mipi_tx(config->mipi_dsi, config->channel, + hx8394_bank1, sizeof(hx8394_bank1)); if (ret < 0) { return ret; } /* Select bank 0 */ param[1] = 0x0; - ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel, - param, 2); + ret = hx8394_mipi_tx(config->mipi_dsi, config->channel, + param, 2); if (ret < 0) { return ret; } - ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel, - hx8394_bank0, sizeof(hx8394_bank0)); + ret = hx8394_mipi_tx(config->mipi_dsi, config->channel, + hx8394_bank0, sizeof(hx8394_bank0)); if (ret < 0) { return ret; } @@ -712,27 +743,31 @@ static int hx8394_init(const struct device *dev) /* This command is not documented in datasheet, but is included * in the display initialization done by MCUXpresso SDK */ - ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel, - hx8394_cmd3, sizeof(hx8394_cmd3)); + ret = hx8394_mipi_tx(config->mipi_dsi, config->channel, + hx8394_cmd3, sizeof(hx8394_cmd3)); if (ret < 0) { return ret; } - ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel, - tear_config, sizeof(tear_config)); + ret = hx8394_mipi_tx(config->mipi_dsi, config->channel, + tear_config, sizeof(tear_config)); if (ret < 0) { return ret; } - ret = mipi_dsi_dcs_write(config->mipi_dsi, config->channel, - MIPI_DCS_EXIT_SLEEP_MODE, NULL, 0); + param[0] = MIPI_DCS_EXIT_SLEEP_MODE; + + ret = hx8394_mipi_tx(config->mipi_dsi, config->channel, + param, 1); if (ret < 0) { return ret; } /* We must delay 120ms after exiting sleep mode per datasheet */ k_sleep(K_MSEC(120)); - ret = mipi_dsi_dcs_write(config->mipi_dsi, config->channel, - MIPI_DCS_SET_DISPLAY_ON, NULL, 0); + + param[0] = MIPI_DCS_SET_DISPLAY_ON; + ret = hx8394_mipi_tx(config->mipi_dsi, config->channel, + param, 1); if (config->bl_gpio.port != NULL) { ret = gpio_pin_configure_dt(&config->bl_gpio, GPIO_OUTPUT_ACTIVE); diff --git a/drivers/display/display_mcux_elcdif.c b/drivers/display/display_mcux_elcdif.c index e4b45f89d40..4252a98e859 100644 --- a/drivers/display/display_mcux_elcdif.c +++ b/drivers/display/display_mcux_elcdif.c @@ -190,6 +190,9 @@ static int mcux_elcdif_write(const struct device *dev, const uint16_t x, const u return ret; } k_sem_take(&dev_data->pxp_done, K_FOREVER); + } else { + LOG_WRN("PXP rotation will not work correctly unless a full sized " + "framebuffer is provided"); } #endif /* CONFIG_MCUX_ELCDIF_PXP */ diff --git a/drivers/display/display_renesas_lcdc.c b/drivers/display/display_renesas_lcdc.c index c09b48ac003..ab12cc23a00 100644 --- a/drivers/display/display_renesas_lcdc.c +++ b/drivers/display/display_renesas_lcdc.c @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include LOG_MODULE_REGISTER(smartbond_display, CONFIG_DISPLAY_LOG_LEVEL); @@ -72,6 +74,10 @@ struct display_smartbond_data { struct k_sem dma_sync_sem; /* Granted DMA channel used for memory transfers */ int dma_channel; +#if defined(CONFIG_PM_DEVICE) || defined(CONFIG_PM_DEVICE_RUNTIME) + /* Flag to determine if device suspension is allowed */ + bool is_sleep_allowed; +#endif }; struct display_smartbond_config { @@ -180,6 +186,44 @@ static void smartbond_display_isr(const void *arg) k_sem_give(&data->sync_sem); } +static void display_smartbond_dma_cb(const struct device *dma, void *arg, + uint32_t id, int status) +{ + struct display_smartbond_data *data = arg; + + if (status < 0) { + LOG_WRN("DMA transfer did not complete"); + } + + k_sem_give(&data->dma_sync_sem); +} + +static int display_smartbond_dma_config(const struct device *dev) +{ + struct display_smartbond_data *data = dev->data; + + data->dma = DEVICE_DT_GET(DT_NODELABEL(dma)); + if (!device_is_ready(data->dma)) { + LOG_ERR("DMA device is not ready"); + return -ENODEV; + } + + data->dma_cfg.channel_direction = MEMORY_TO_MEMORY; + data->dma_cfg.user_data = data; + data->dma_cfg.dma_callback = display_smartbond_dma_cb; + data->dma_cfg.block_count = 1; + data->dma_cfg.head_block = &data->dma_block_cfg; + + /* Request an arbitrary DMA channel */ + data->dma_channel = dma_request_channel(data->dma, NULL); + if (data->dma_channel < 0) { + LOG_ERR("Could not acquire a DMA channel"); + return -EIO; + } + + return 0; +} + static int display_smartbond_resume(const struct device *dev) { const struct display_smartbond_config *config = dev->config; @@ -207,47 +251,43 @@ static int display_smartbond_resume(const struct device *dev) } #endif + ret = display_smartbond_dma_config(dev); + if (ret < 0) { + return ret; + } + return display_smartbond_configure(dev); } -static void display_smartbond_dma_cb(const struct device *dma, void *arg, - uint32_t id, int status) +#if defined(CONFIG_PM_DEVICE) || defined(CONFIG_PM_DEVICE_RUNTIME) +static void display_smartbond_dma_deconfig(const struct device *dev) { - struct display_smartbond_data *data = arg; + struct display_smartbond_data *data = dev->data; - if (status < 0) { - LOG_WRN("DMA transfer did not complete"); - } + __ASSERT(data->dma, "DMA should be already initialized"); - k_sem_give(&data->dma_sync_sem); + dma_release_channel(data->dma, data->dma_channel); } -static int display_smartbond_dma_config(const struct device *dev) +static int display_smartbond_suspend(const struct device *dev) { - struct display_smartbond_data *data = dev->data; + const struct display_smartbond_config *config = dev->config; + int ret; - data->dma = DEVICE_DT_GET(DT_NODELABEL(dma)); - if (!device_is_ready(data->dma)) { - LOG_ERR("DMA device is not ready"); - return -ENODEV; + /* Select sleep state; it's OK if settings fails for any reason */ + ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_SLEEP); + if (ret < 0) { + LOG_WRN("Could not apply DISPLAY pins' sleep state"); } - data->dma_cfg.channel_direction = MEMORY_TO_MEMORY; - data->dma_cfg.user_data = data; - data->dma_cfg.dma_callback = display_smartbond_dma_cb; - data->dma_cfg.block_count = 1; - data->dma_cfg.head_block = &data->dma_block_cfg; + /* Disable host controller to minimize power consumption */ + da1469x_lcdc_set_status(false, false, 0); - /* Request an arbitrary DMA channel */ - data->dma_channel = dma_request_channel(data->dma, NULL); - if (data->dma_channel < 0) { - LOG_ERR("Could not acquire a DMA channel"); - return -EIO; - } + display_smartbond_dma_deconfig(dev); return 0; } - +#endif static int display_smartbond_init(const struct device *dev) { @@ -271,33 +311,25 @@ static int display_smartbond_init(const struct device *dev) } } - ret = display_smartbond_resume(dev); - if (ret < 0) { - return ret; - } - - ret = display_smartbond_dma_config(dev); - if (ret < 0) { - return ret; - } - IRQ_CONNECT(SMARTBOND_IRQN, SMARTBOND_IRQ_PRIO, smartbond_display_isr, DEVICE_DT_INST_GET(0), 0); -#if CONFIG_PM - /* - * When in continues mode, the display device should always be refreshed - * and so the controller is not allowed to be turned off. The latter, is - * powered by PD_SYS which is turned off when the SoC enters the extended - * sleep state. By acquiring PD_SYS, the deep sleep state is prevented - * and the system enters the low-power state (i.e. ARM WFI) when possible. - * - * XXX CONFIG_PM_DEVICE_RUNTIME is no supported yet! - */ - da1469x_pd_acquire_noconf(MCU_PD_DOMAIN_SYS); +#ifdef CONFIG_PM_DEVICE_RUNTIME + /* Make sure device state is marked as suspended */ + pm_device_init_suspended(dev); + + ret = pm_device_runtime_enable(dev); + + /* Sleep is allowed until the device is explicitly resumed on application level. */ + if (ret == 0) { + data->is_sleep_allowed = true; + } +#else + /* Resume if either PM is not used at all or if PM without runtime is used. */ + ret = display_smartbond_resume(dev); #endif - return 0; + return ret; } static int display_smartbond_blanking_on(const struct device *dev) @@ -323,6 +355,14 @@ static int display_smartbond_blanking_on(const struct device *dev) } } +#if defined(CONFIG_PM_DEVICE) || defined(CONFIG_PM_DEVICE_RUNTIME) + /* + * At this moment the display panel should be turned off and so the device + * can enter the suspend state. + */ + data->is_sleep_allowed = true; +#endif + k_sem_give(&data->device_sem); return ret; @@ -351,6 +391,14 @@ static int display_smartbond_blanking_off(const struct device *dev) */ LCDC->LCDC_MODE_REG &= ~LCDC_LCDC_MODE_REG_LCDC_FORCE_BLANK_Msk; +#if defined(CONFIG_PM_DEVICE) || defined(CONFIG_PM_DEVICE_RUNTIME) + /* + * At this moment the display should be turned on and so the device + * cannot enter the suspend state. + */ + data->is_sleep_allowed = false; +#endif + k_sem_give(&data->device_sem); return ret; @@ -515,6 +563,36 @@ static int display_smartbond_write(const struct device *dev, return 0; } +#if defined(CONFIG_PM_DEVICE) || defined(CONFIG_PM_DEVICE_RUNTIME) +static int display_smartbond_pm_action(const struct device *dev, enum pm_device_action action) +{ + /* Initialize with an error code that should abort sleeping */ + int ret = -EBUSY; + struct display_smartbond_data *data = dev->data; + + switch (action) { + case PM_DEVICE_ACTION_SUSPEND: + /* Sleep is only allowed whne display blanking is activated */ + if (data->is_sleep_allowed) { + (void)display_smartbond_suspend(dev); + ret = 0; + } + break; + case PM_DEVICE_ACTION_RESUME: + __ASSERT_NO_MSG(data->is_sleep_allowed); + /* + * The resume error code should not be taken into consideration + * by the PM subsystem + */ + ret = display_smartbond_resume(dev); + break; + default: + ret = -ENOTSUP; + } + + return ret; +} +#endif static struct display_driver_api display_smartbond_driver_api = { .write = display_smartbond_write, @@ -527,6 +605,7 @@ static struct display_driver_api display_smartbond_driver_api = { #define SMARTBOND_DISPLAY_INIT(inst) \ PINCTRL_DT_INST_DEFINE(inst); \ + PM_DEVICE_DT_INST_DEFINE(inst, display_smartbond_pm_action); \ \ __aligned(4) static uint8_t buffer_ ## inst[(((DT_INST_PROP(inst, width) * \ DISPLAY_SMARTBOND_PIXEL_SIZE(inst)) + 0x3) & ~0x3) * \ @@ -572,7 +651,7 @@ static struct display_driver_api display_smartbond_driver_api = { }; \ \ \ - DEVICE_DT_INST_DEFINE(inst, display_smartbond_init, NULL, \ + DEVICE_DT_INST_DEFINE(inst, display_smartbond_init, PM_DEVICE_DT_INST_GET(inst), \ &display_smartbond_data_## inst, \ &display_smartbond_config_## inst, \ POST_KERNEL, \ diff --git a/drivers/display/display_sdl.c b/drivers/display/display_sdl.c index f21288d1b0f..e929a775f9b 100644 --- a/drivers/display/display_sdl.c +++ b/drivers/display/display_sdl.c @@ -235,13 +235,13 @@ static int sdl_display_write(const struct device *dev, const uint16_t x, "Pitch in descriptor is larger than screen size"); __ASSERT(desc->height <= config->height, "Height in descriptor is larger than screen size"); - __ASSERT(x + desc->pitch <= config->width, + __ASSERT(x + desc->width <= config->width, "Writing outside screen boundaries in horizontal direction"); __ASSERT(y + desc->height <= config->height, "Writing outside screen boundaries in vertical direction"); if (desc->width > desc->pitch || - x + desc->pitch > config->width || + x + desc->width > config->width || y + desc->height > config->height) { return -EINVAL; } diff --git a/drivers/display/display_st7735r.c b/drivers/display/display_st7735r.c index 88c282d89f8..1626cb5204b 100644 --- a/drivers/display/display_st7735r.c +++ b/drivers/display/display_st7735r.c @@ -5,6 +5,7 @@ * Copyright (c) 2019 PHYTEC Messtechnik GmbH * Copyright (c) 2020 Endian Technologies AB * Copyright (c) 2020 Kim BĆøndergaard + * Copyright 2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -14,7 +15,7 @@ #include "display_st7735r.h" #include -#include +#include #include #include #include @@ -23,15 +24,14 @@ #include LOG_MODULE_REGISTER(display_st7735r, CONFIG_DISPLAY_LOG_LEVEL); -#define ST7735R_RESET_TIME K_MSEC(1) +#define ST7735R_RESET_TIME 1 #define ST7735R_EXIT_SLEEP_TIME K_MSEC(120) #define ST7735R_PIXEL_SIZE 2u struct st7735r_config { - struct spi_dt_spec bus; - struct gpio_dt_spec cmd_data; - struct gpio_dt_spec reset; + const struct device *mipi_dev; + const struct mipi_dbi_config dbi_config; uint16_t height; uint16_t width; uint8_t madctl; @@ -68,38 +68,13 @@ static void st7735r_set_lcd_margins(const struct device *dev, data->y_offset = y_offset; } -static void st7735r_set_cmd(const struct device *dev, int is_cmd) -{ - const struct st7735r_config *config = dev->config; - - gpio_pin_set_dt(&config->cmd_data, is_cmd); -} - static int st7735r_transmit_hold(const struct device *dev, uint8_t cmd, const uint8_t *tx_data, size_t tx_count) { const struct st7735r_config *config = dev->config; - struct spi_buf tx_buf = { .buf = &cmd, .len = 1 }; - struct spi_buf_set tx_bufs = { .buffers = &tx_buf, .count = 1 }; - int ret; - - st7735r_set_cmd(dev, 1); - ret = spi_write_dt(&config->bus, &tx_bufs); - if (ret < 0) { - return ret; - } - if (tx_data != NULL) { - tx_buf.buf = (void *)tx_data; - tx_buf.len = tx_count; - st7735r_set_cmd(dev, 0); - ret = spi_write_dt(&config->bus, &tx_bufs); - if (ret < 0) { - return ret; - } - } - - return 0; + return mipi_dbi_command_write(config->mipi_dev, &config->dbi_config, + cmd, tx_data, tx_count); } static int st7735r_transmit(const struct device *dev, uint8_t cmd, @@ -109,7 +84,7 @@ static int st7735r_transmit(const struct device *dev, uint8_t cmd, int ret; ret = st7735r_transmit_hold(dev, cmd, tx_data, tx_count); - spi_release_dt(&config->bus); + mipi_dbi_release(config->mipi_dev, &config->dbi_config); return ret; } @@ -133,11 +108,8 @@ static int st7735r_reset_display(const struct device *dev) int ret; LOG_DBG("Resetting display"); - if (config->reset.port != NULL) { - gpio_pin_set_dt(&config->reset, 1); - k_sleep(ST7735R_RESET_TIME); - gpio_pin_set_dt(&config->reset, 0); - } else { + ret = mipi_dbi_reset(config->mipi_dev, ST7735R_RESET_TIME); + if (ret != 0) { ret = st7735r_transmit(dev, ST7735R_CMD_SW_RESET, NULL, 0); if (ret < 0) { return ret; @@ -204,12 +176,12 @@ static int st7735r_write(const struct device *dev, { const struct st7735r_config *config = dev->config; const uint8_t *write_data_start = (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; int ret; + enum display_pixel_format fmt; + struct display_buffer_descriptor mipi_desc; __ASSERT(desc->width <= desc->pitch, "Pitch is smaller than width"); __ASSERT((desc->pitch * ST7735R_PIXEL_SIZE * desc->height) @@ -225,9 +197,24 @@ static int st7735r_write(const struct device *dev, if (desc->pitch > desc->width) { write_h = 1U; nbr_of_writes = desc->height; + mipi_desc.height = 1; + mipi_desc.buf_size = desc->pitch * ST7735R_PIXEL_SIZE; } else { write_h = desc->height; nbr_of_writes = 1U; + mipi_desc.height = desc->height; + mipi_desc.buf_size = desc->width * ST7735R_PIXEL_SIZE * write_h; + } + + mipi_desc.width = desc->width; + /* Per MIPI API, pitch must always match width */ + mipi_desc.pitch = desc->width; + + + if (!(config->madctl & ST7735R_MADCTL_BGR) != !config->rgb_is_inverted) { + fmt = PIXEL_FORMAT_BGR_565; + } else { + fmt = PIXEL_FORMAT_RGB_565; } ret = st7735r_transmit_hold(dev, ST7735R_CMD_RAMWR, @@ -237,14 +224,13 @@ static int st7735r_write(const struct device *dev, goto out; } - tx_bufs.buffers = &tx_buf; - tx_bufs.count = 1; - write_data_start += (desc->pitch * ST7735R_PIXEL_SIZE); for (write_cnt = 1U; write_cnt < nbr_of_writes; ++write_cnt) { - tx_buf.buf = (void *)write_data_start; - tx_buf.len = desc->width * ST7735R_PIXEL_SIZE * write_h; - ret = spi_write_dt(&config->bus, &tx_bufs); + ret = mipi_dbi_write_display(config->mipi_dev, + &config->dbi_config, + write_data_start, + &mipi_desc, + fmt); if (ret < 0) { goto out; } @@ -254,7 +240,7 @@ static int st7735r_write(const struct device *dev, ret = 0; out: - spi_release_dt(&config->bus); + mipi_dbi_release(config->mipi_dev, &config->dbi_config); return ret; } @@ -445,36 +431,11 @@ static int st7735r_init(const struct device *dev) const struct st7735r_config *config = dev->config; int ret; - if (!spi_is_ready_dt(&config->bus)) { - LOG_ERR("SPI bus %s not ready", config->bus.bus->name); - return -ENODEV; - } - - if (config->reset.port != NULL) { - if (!gpio_is_ready_dt(&config->reset)) { - LOG_ERR("Reset GPIO port for display not ready"); - return -ENODEV; - } - - ret = gpio_pin_configure_dt(&config->reset, - GPIO_OUTPUT_INACTIVE); - if (ret) { - LOG_ERR("Couldn't configure reset pin"); - return ret; - } - } - - if (!gpio_is_ready_dt(&config->cmd_data)) { - LOG_ERR("cmd/DATA GPIO port not ready"); + if (!device_is_ready(config->mipi_dev)) { + LOG_ERR("MIPI bus %s not ready", config->mipi_dev->name); return -ENODEV; } - ret = gpio_pin_configure_dt(&config->cmd_data, GPIO_OUTPUT); - if (ret) { - LOG_ERR("Couldn't configure cmd/DATA pin"); - return ret; - } - ret = st7735r_reset_display(dev); if (ret < 0) { LOG_ERR("Couldn't reset display"); @@ -530,11 +491,13 @@ static const struct display_driver_api st7735r_api = { #define ST7735R_INIT(inst) \ const static struct st7735r_config st7735r_config_ ## inst = { \ - .bus = SPI_DT_SPEC_INST_GET( \ - inst, SPI_OP_MODE_MASTER | SPI_WORD_SET(8) | \ - SPI_HOLD_ON_CS | SPI_LOCK_ON, 0), \ - .cmd_data = GPIO_DT_SPEC_INST_GET(inst, cmd_data_gpios), \ - .reset = GPIO_DT_SPEC_INST_GET_OR(inst, reset_gpios, {}), \ + .mipi_dev = DEVICE_DT_GET(DT_INST_PARENT(inst)), \ + .dbi_config = MIPI_DBI_CONFIG_DT_INST(inst, \ + SPI_OP_MODE_MASTER | \ + ((DT_INST_PROP(inst, mipi_mode) == \ + MIPI_DBI_MODE_SPI_4WIRE) ? SPI_WORD_SET(8) : \ + SPI_WORD_SET(9)) | \ + SPI_HOLD_ON_CS | SPI_LOCK_ON, 0), \ .width = DT_INST_PROP(inst, width), \ .height = DT_INST_PROP(inst, height), \ .madctl = DT_INST_PROP(inst, madctl), \ diff --git a/drivers/display/display_st7789v.c b/drivers/display/display_st7789v.c index 0d3a9eb37aa..72ae4eb0436 100644 --- a/drivers/display/display_st7789v.c +++ b/drivers/display/display_st7789v.c @@ -37,6 +37,7 @@ struct st7789v_config { uint8_t gamma; uint8_t colmod; uint8_t lcm; + bool inversion_on; uint8_t porch_param[5]; uint8_t cmd2en_param[4]; uint8_t pwctrl1_param[2]; @@ -298,7 +299,11 @@ static void st7789v_lcd_init(const struct device *dev) tmp = config->gamma; st7789v_transmit(dev, ST7789V_CMD_GAMSET, &tmp, 1); - st7789v_transmit(dev, ST7789V_CMD_INV_ON, NULL, 0); + if (config->inversion_on) { + st7789v_transmit(dev, ST7789V_CMD_INV_ON, NULL, 0); + } else { + st7789v_transmit(dev, ST7789V_CMD_INV_OFF, NULL, 0); + } st7789v_transmit(dev, ST7789V_CMD_PVGAMCTRL, (uint8_t *)config->pvgam_param, @@ -411,6 +416,7 @@ static const struct display_driver_api st7789v_api = { .gamma = DT_INST_PROP(inst, gamma), \ .colmod = DT_INST_PROP(inst, colmod), \ .lcm = DT_INST_PROP(inst, lcm), \ + .inversion_on = !DT_INST_PROP(inst, inversion_off), \ .porch_param = DT_INST_PROP(inst, porch_param), \ .cmd2en_param = DT_INST_PROP(inst, cmd2en_param), \ .pwctrl1_param = DT_INST_PROP(inst, pwctrl1_param), \ diff --git a/drivers/dma/dma_andes_atcdmac300.c b/drivers/dma/dma_andes_atcdmac300.c index 2f817242fbe..8f67a3cacd9 100644 --- a/drivers/dma/dma_andes_atcdmac300.c +++ b/drivers/dma/dma_andes_atcdmac300.c @@ -273,7 +273,7 @@ static int dma_atcdmac300_config(const struct device *dev, uint32_t channel, ch_ctrl |= DMA_CH_CTRL_INTABT; /* Disable the error callback */ - if (!cfg->error_callback_en) { + if (!cfg->error_callback_dis) { ch_ctrl |= DMA_CH_CTRL_INTERR; } diff --git a/drivers/dma/dma_emul.c b/drivers/dma/dma_emul.c index 235593df624..5397540ba1e 100644 --- a/drivers/dma/dma_emul.c +++ b/drivers/dma/dma_emul.c @@ -129,7 +129,7 @@ static const char *dma_emul_xfer_config_to_string(const struct dma_config *cfg) "\n\tslot: %u" "\n\tchannel_direction: %u" "\n\tcomplete_callback_en: %u" - "\n\terror_callback_en: %u" + "\n\terror_callback_dis: %u" "\n\tsource_handshake: %u" "\n\tdest_handshake: %u" "\n\tchannel_priority: %u" @@ -148,7 +148,7 @@ static const char *dma_emul_xfer_config_to_string(const struct dma_config *cfg) "\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->error_callback_dis, 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, @@ -248,11 +248,11 @@ static void dma_emul_work_handler(struct k_work *work) if (state == DMA_EMUL_CHANNEL_STOPPED) { LOG_DBG("asynchronously canceled"); - if (xfer_config.error_callback_en) { + if (!xfer_config.error_callback_dis) { xfer_config.dma_callback(dev, xfer_config.user_data, channel, -ECANCELED); } else { - LOG_DBG("error_callback_en is not set (async " + LOG_DBG("error_callback_dis is not set (async " "cancel)"); } goto out; diff --git a/drivers/dma/dma_mchp_xec.c b/drivers/dma/dma_mchp_xec.c index dd79ae21bc8..699aa5deef8 100644 --- a/drivers/dma/dma_mchp_xec.c +++ b/drivers/dma/dma_mchp_xec.c @@ -272,7 +272,7 @@ static int check_blocks(struct dma_xec_channel *chdata, struct dma_block_config * dma_slot - peripheral source/target ID. Not used for Mem2Mem * channel_direction - HW supports Mem2Mem, Mem2Periph, and Periph2Mem * complete_callback_en - if true invoke callback on completion (no error) - * error_callback_en - if true invoke callback on error + * error_callback_dis - if true disable callback on error * source_handshake - 0=HW, 1=SW * dest_handshake - 0=HW, 1=SW * channel_priority - 4-bit field. HW implements round-robin only. @@ -384,7 +384,7 @@ static int dma_xec_configure(const struct device *dev, uint32_t channel, if (config->complete_callback_en) { chdata->flags |= BIT(DMA_XEC_CHAN_FLAGS_CB_EOB_POS); } - if (config->error_callback_en) { /* disable callback on errors ? */ + if (config->error_callback_dis) { /* disable callback on errors ? */ chdata->flags |= BIT(DMA_XEC_CHAN_FLAGS_CB_ERR_DIS_POS); } @@ -690,7 +690,7 @@ static int dmac_xec_pm_action(const struct device *dev, * completion_callback_en * 0 = invoke at completion of all blocks * 1 = invoke at completin of each block - * error_callback_en + * error_callback_dis * 0 = invoke on all errors * 1 = disabled, do not invoke on errors */ diff --git a/drivers/dma/dma_sam0.c b/drivers/dma/dma_sam0.c index 690598b8d3f..fde5a250e84 100644 --- a/drivers/dma/dma_sam0.c +++ b/drivers/dma/dma_sam0.c @@ -125,7 +125,7 @@ static int dma_sam0_config(const struct device *dev, uint32_t channel, /* Enable the interrupts */ DMA_REGS->CHINTENSET.reg = DMAC_CHINTENSET_TCMPL; - if (!config->error_callback_en) { + if (!config->error_callback_dis) { DMA_REGS->CHINTENSET.reg = DMAC_CHINTENSET_TERR; } else { DMA_REGS->CHINTENCLR.reg = DMAC_CHINTENSET_TERR; @@ -179,7 +179,7 @@ static int dma_sam0_config(const struct device *dev, uint32_t channel, /* Enable the interrupts */ chcfg->CHINTENSET.reg = DMAC_CHINTENSET_TCMPL; - if (!config->error_callback_en) { + if (!config->error_callback_dis) { chcfg->CHINTENSET.reg = DMAC_CHINTENSET_TERR; } else { chcfg->CHINTENCLR.reg = DMAC_CHINTENSET_TERR; diff --git a/drivers/dma/dma_sam_xdmac.c b/drivers/dma/dma_sam_xdmac.c index 7919c5770d1..569085e5766 100644 --- a/drivers/dma/dma_sam_xdmac.c +++ b/drivers/dma/dma_sam_xdmac.c @@ -264,7 +264,7 @@ static int sam_xdmac_config(const struct device *dev, uint32_t channel, channel_cfg.dus = 0U; channel_cfg.cie = (cfg->complete_callback_en ? XDMAC_CIE_BIE : XDMAC_CIE_LIE) - | (cfg->error_callback_en ? XDMAC_INT_ERR : 0); + | (cfg->error_callback_dis ? 0 : XDMAC_INT_ERR); ret = sam_xdmac_channel_configure(dev, channel, &channel_cfg); if (ret < 0) { diff --git a/drivers/dma/dma_sedi.c b/drivers/dma/dma_sedi.c index 7c4ffa72e57..03f43e87580 100644 --- a/drivers/dma/dma_sedi.c +++ b/drivers/dma/dma_sedi.c @@ -57,7 +57,7 @@ static void dma_handler(sedi_dma_t dma_device, int channel, int event_id, (config->complete_callback_en)) { config->dma_callback(dev, config->user_data, channel, 0); - } else if (config->error_callback_en) { + } else if (!config->error_callback_dis) { config->dma_callback(dev, config->user_data, channel, event_id); } diff --git a/drivers/dma/dma_smartbond.c b/drivers/dma/dma_smartbond.c index 79305c77d6a..855e56b9aff 100644 --- a/drivers/dma/dma_smartbond.c +++ b/drivers/dma/dma_smartbond.c @@ -483,7 +483,7 @@ static int dma_smartbond_config(const struct device *dev, uint32_t channel, stru } /* Error handling is not supported; just warn user. */ - if (cfg->error_callback_en) { + if (!cfg->error_callback_dis) { LOG_WRN("Error handling is not supported"); } diff --git a/drivers/dma/dma_stm32.h b/drivers/dma/dma_stm32.h index f21cb07e183..553e09838d8 100644 --- a/drivers/dma/dma_stm32.h +++ b/drivers/dma/dma_stm32.h @@ -52,7 +52,11 @@ uint32_t dma_stm32_slot_to_channel(uint32_t id); #endif typedef void (*dma_stm32_clear_flag_func)(DMA_TypeDef *DMAx); +#if !defined(CONFIG_SOC_SERIES_STM32G0X) typedef uint32_t (*dma_stm32_check_flag_func)(DMA_TypeDef *DMAx); +#else +typedef uint32_t (*dma_stm32_check_flag_func)(const DMA_TypeDef *DMAx); +#endif bool dma_stm32_is_tc_active(DMA_TypeDef *DMAx, uint32_t id); void dma_stm32_clear_tc(DMA_TypeDef *DMAx, uint32_t id); diff --git a/drivers/dma/dma_xmc4xxx.c b/drivers/dma/dma_xmc4xxx.c index 1b20d2ec577..26acef93e9f 100644 --- a/drivers/dma/dma_xmc4xxx.c +++ b/drivers/dma/dma_xmc4xxx.c @@ -294,7 +294,7 @@ static int dma_xmc4xxx_config(const struct device *dev, uint32_t channel, struct XMC_DMA_CH_EnableEvent(dma, channel, XMC_DMA_CH_EVENT_BLOCK_TRANSFER_COMPLETE); } - if (config->error_callback_en) { + if (!config->error_callback_dis) { XMC_DMA_CH_EnableEvent(dma, channel, XMC_DMA_CH_EVENT_ERROR); } diff --git a/drivers/dma/dmamux_stm32.c b/drivers/dma/dmamux_stm32.c index bca6514190e..d12a294eb7f 100644 --- a/drivers/dma/dmamux_stm32.c +++ b/drivers/dma/dmamux_stm32.c @@ -70,19 +70,24 @@ uint32_t table_ll_channel[] = { LISTIFY(DT_INST_PROP(0, dma_channels), DMAMUX_CHANNEL, (,)) }; -uint32_t (*func_ll_is_active_so[])(DMAMUX_Channel_TypeDef *DMAMUXx) = { +#if !defined(CONFIG_SOC_SERIES_STM32G0X) +#define dmamux_channel_typedef DMAMUX_Channel_TypeDef +#else +#define dmamux_channel_typedef const DMAMUX_Channel_TypeDef +#endif +uint32_t (*func_ll_is_active_so[])(dmamux_channel_typedef * DMAMUXx) = { LISTIFY(DT_INST_PROP(0, dma_channels), IS_ACTIVE_FLAG_SOX, (,)) }; -void (*func_ll_clear_so[])(DMAMUX_Channel_TypeDef *DMAMUXx) = { +void (*func_ll_clear_so[])(dmamux_channel_typedef * DMAMUXx) = { LISTIFY(DT_INST_PROP(0, dma_channels), CLEAR_FLAG_SOX, (,)) }; -uint32_t (*func_ll_is_active_rgo[])(DMAMUX_Channel_TypeDef *DMAMUXx) = { +uint32_t (*func_ll_is_active_rgo[])(dmamux_channel_typedef * DMAMUXx) = { LISTIFY(DT_INST_PROP(0, dma_generators), IS_ACTIVE_FLAG_RGOX, (,)) }; -void (*func_ll_clear_rgo[])(DMAMUX_Channel_TypeDef *DMAMUXx) = { +void (*func_ll_clear_rgo[])(dmamux_channel_typedef * DMAMUXx) = { LISTIFY(DT_INST_PROP(0, dma_generators), CLEAR_FLAG_RGOX, (,)) }; diff --git a/drivers/entropy/CMakeLists.txt b/drivers/entropy/CMakeLists.txt index 1ea31981857..5fd383d4b64 100644 --- a/drivers/entropy/CMakeLists.txt +++ b/drivers/entropy/CMakeLists.txt @@ -41,8 +41,4 @@ if (CONFIG_FAKE_ENTROPY_NRF_PRNG) "This is not secure and should therefore never be used in a product.") endif() -if (CONFIG_BUILD_WITH_TFM) - target_include_directories(${ZEPHYR_CURRENT_LIBRARY} PRIVATE - $/api_ns/interface/include - ) -endif() +zephyr_library_link_libraries_ifdef(CONFIG_BUILD_WITH_TFM tfm_api) diff --git a/drivers/entropy/entropy_smartbond.c b/drivers/entropy/entropy_smartbond.c index 28b6f08e100..80f9ef1510c 100644 --- a/drivers/entropy/entropy_smartbond.c +++ b/drivers/entropy/entropy_smartbond.c @@ -10,6 +10,11 @@ #include #include #include +#include +#include + +#include +LOG_MODULE_REGISTER(smartbond_entropy, CONFIG_ENTROPY_LOG_LEVEL); #define DT_DRV_COMPAT renesas_smartbond_trng @@ -312,11 +317,11 @@ static int entropy_smartbond_get_entropy_isr(const struct device *dev, uint8_t * } NVIC_ClearPendingIRQ(IRQN); - if (random_word_get(buf) != 0) { + if (random_word_get(bytes) != 0) { continue; } - while (ptr < limit) { + while (ptr < limit && len) { buf[--len] = *ptr++; } /* Store remaining data for later use */ @@ -334,6 +339,51 @@ static int entropy_smartbond_get_entropy_isr(const struct device *dev, uint8_t * return cnt; } +#if defined(CONFIG_PM_DEVICE) || defined(CONFIG_PM_DEVICE_RUNTIME) +/* + * TRNG is powered by PD_SYS which is the same power domain used to power the SoC. + * Entering the sleep state should not be allowed for as long as the ISR and thread + * SW FIFOs are being filled with random numbers. + */ +static inline bool entropy_is_sleep_allowed(void) +{ + return !(TRNG->TRNG_CTRL_REG & TRNG_TRNG_CTRL_REG_TRNG_ENABLE_Msk); +} + +static int entropy_smartbond_pm_action(const struct device *dev, enum pm_device_action action) +{ + /* Initialize with an error code that should abort sleeping */ + int ret = -EBUSY; + + switch (action) { + case PM_DEVICE_ACTION_RESUME: + __ASSERT_NO_MSG(entropy_is_sleep_allowed()); + + /* + * No need to turn on TRNG. It should be done when we the space in the FIFOs + * are below the defined ISR and thread FIFO's thresholds. + * + * \sa CONFIG_ENTROPY_SMARTBOND_THR_THRESHOLD + * \sa CONFIG_ENTROPY_SMARTBOND_ISR_THRESHOLD + * + */ + ret = 0; + break; + case PM_DEVICE_ACTION_SUSPEND: + /* Sleep is only allowed when there is no TRNG activity */ + if (entropy_is_sleep_allowed()) { + /* At this point TRNG should be disabled; no need to turn it off. */ + ret = 0; + } + break; + default: + ret = -ENOTSUP; + } + + return ret; +} +#endif + static const struct entropy_driver_api entropy_smartbond_api_funcs = { .get_entropy = entropy_smartbond_get_entropy, .get_entropy_isr = entropy_smartbond_get_entropy_isr}; @@ -361,8 +411,18 @@ static int entropy_smartbond_init(const struct device *dev) trng_enable(true); +#ifdef CONFIG_PM_DEVICE_RUNTIME + /* Make sure device state is marked as suspended */ + pm_device_init_suspended(dev); + + return pm_device_runtime_enable(dev); +#endif + return 0; } -DEVICE_DT_INST_DEFINE(0, entropy_smartbond_init, NULL, &entropy_smartbond_data, NULL, PRE_KERNEL_1, - CONFIG_ENTROPY_INIT_PRIORITY, &entropy_smartbond_api_funcs); +PM_DEVICE_DT_INST_DEFINE(0, entropy_smartbond_pm_action); + +DEVICE_DT_INST_DEFINE(0, entropy_smartbond_init, PM_DEVICE_DT_INST_GET(0), + &entropy_smartbond_data, NULL, PRE_KERNEL_1, + CONFIG_ENTROPY_INIT_PRIORITY, &entropy_smartbond_api_funcs); diff --git a/drivers/espi/Kconfig.it8xxx2 b/drivers/espi/Kconfig.it8xxx2 index e018f869515..6c19eb2514c 100644 --- a/drivers/espi/Kconfig.it8xxx2 +++ b/drivers/espi/Kconfig.it8xxx2 @@ -127,4 +127,19 @@ config ESPI_IT8XXX2_PNPCFG_DEVICE_KBC_MOUSE With this option enabled, EC will send IRQ12 signal to host when the KBC mouse output buffer is full. +# On IT8xxx2 series, this configuration option has limitation: +# Port 80 and 81 I/O cycles share the same interrupt source and there is no +# status bit to indicate which cycle triggered the interrupt and data registers +# of these two ports are read only. Hence EC have to read these two data +# registers at the same time in the ISR. +# It means that the Host must alwasy write 2 bytes of data to port 80 otherwise +# port 81 data will not be updated. +config ESPI_IT8XXX2_PORT_81_CYCLE + bool "EC accepts 0x81 I/O cycle from eSPI transaction" + depends on ESPI_PERIPHERAL_DEBUG_PORT_80 + help + With this option enabled, EC will accept 0x81 I/O cycle from the Host. + This allows EC to accept 2 bytes of port 80 data written from the Host. + (e.g. using iotools: iotools io_write16 0x80 0x1234) + endif #ESPI_IT8XXX2 diff --git a/drivers/espi/Kconfig.npcx b/drivers/espi/Kconfig.npcx index d746d89f961..884b5cdd4d9 100644 --- a/drivers/espi/Kconfig.npcx +++ b/drivers/espi/Kconfig.npcx @@ -45,7 +45,8 @@ config ESPI_NPCX_BYPASS_CH_ENABLE_FATAL_ERROR config ESPI_NPCX_PERIPHERAL_DEBUG_PORT_80_MULTI_BYTE bool "Host can write 1/2/4 bytes of Port80 data in a eSPI transaction" - depends on SOC_SERIES_NPCX9 && ESPI_PERIPHERAL_DEBUG_PORT_80 + depends on (SOC_SERIES_NPCX9 || SOC_SERIES_NPCX4) && ESPI_PERIPHERAL_DEBUG_PORT_80 + select RING_BUFFER help EC can accept 1/2/4 bytes of Port 80 data written from the Host in an eSPI transaction. @@ -61,6 +62,7 @@ config ESPI_NPCX_PERIPHERAL_DEBUG_PORT_80_RING_BUF_SIZE config ESPI_TAF_NPCX bool "Nuvoton NPCX embedded controller (EC) ESPI TAF driver" depends on SOC_SERIES_NPCX4 + depends on FLASH help This option enables the Intel Enhanced Serial Peripheral Interface Target Attached Flash (eSPI TAF) for NPCX4 family of processors. diff --git a/drivers/espi/espi_it8xxx2.c b/drivers/espi/espi_it8xxx2.c index 6694cf013ff..f0510c7f1f5 100644 --- a/drivers/espi/espi_it8xxx2.c +++ b/drivers/espi/espi_it8xxx2.c @@ -517,7 +517,11 @@ static void port80_it8xxx2_isr(const struct device *dev) ESPI_PERIPHERAL_NODATA }; - evt.evt_data = gctrl->GCTRL_P80HDR; + if (IS_ENABLED(CONFIG_ESPI_IT8XXX2_PORT_81_CYCLE)) { + evt.evt_data = gctrl->GCTRL_P80HDR | (gctrl->GCTRL_P81HDR << 8); + } else { + evt.evt_data = gctrl->GCTRL_P80HDR; + } /* Write 1 to clear this bit */ gctrl->GCTRL_P80H81HSR |= BIT(0); @@ -529,8 +533,13 @@ static void port80_it8xxx2_init(const struct device *dev) ARG_UNUSED(dev); struct gctrl_it8xxx2_regs *const gctrl = ESPI_IT8XXX2_GET_GCTRL_BASE; - /* Accept Port 80h Cycle */ - gctrl->GCTRL_SPCTRL1 |= IT8XXX2_GCTRL_ACP80; + /* Accept Port 80h (and 81h) Cycle */ + if (IS_ENABLED(CONFIG_ESPI_IT8XXX2_PORT_81_CYCLE)) { + gctrl->GCTRL_SPCTRL1 |= + (IT8XXX2_GCTRL_ACP80 | IT8XXX2_GCTRL_ACP81); + } else { + gctrl->GCTRL_SPCTRL1 |= IT8XXX2_GCTRL_ACP80; + } IRQ_CONNECT(IT8XXX2_PORT_80_IRQ, 0, port80_it8xxx2_isr, DEVICE_DT_INST_GET(0), 0); irq_enable(IT8XXX2_PORT_80_IRQ); @@ -597,10 +606,10 @@ static const struct vw_channel_t vw_channel_list[] = { VW_CHAN(ESPI_VWIRE_SIGNAL_PME, 0x04, BIT(3), BIT(7)), VW_CHAN(ESPI_VWIRE_SIGNAL_WAKE, 0x04, BIT(2), BIT(6)), VW_CHAN(ESPI_VWIRE_SIGNAL_OOB_RST_ACK, 0x04, BIT(0), BIT(4)), - VW_CHAN(ESPI_VWIRE_SIGNAL_SLV_BOOT_STS, 0x05, BIT(3), BIT(7)), + VW_CHAN(ESPI_VWIRE_SIGNAL_TARGET_BOOT_STS, 0x05, BIT(3), BIT(7)), VW_CHAN(ESPI_VWIRE_SIGNAL_ERR_NON_FATAL, 0x05, BIT(2), BIT(6)), VW_CHAN(ESPI_VWIRE_SIGNAL_ERR_FATAL, 0x05, BIT(1), BIT(5)), - VW_CHAN(ESPI_VWIRE_SIGNAL_SLV_BOOT_DONE, 0x05, BIT(0), BIT(4)), + VW_CHAN(ESPI_VWIRE_SIGNAL_TARGET_BOOT_DONE, 0x05, BIT(0), BIT(4)), VW_CHAN(ESPI_VWIRE_SIGNAL_HOST_RST_ACK, 0x06, BIT(3), BIT(7)), VW_CHAN(ESPI_VWIRE_SIGNAL_RST_CPU_INIT, 0x06, BIT(2), BIT(6)), VW_CHAN(ESPI_VWIRE_SIGNAL_SMI, 0x06, BIT(1), BIT(5)), @@ -1598,9 +1607,9 @@ static void espi_it8xxx2_oob_ch_en_isr(const struct device *dev, bool enable) static void espi_it8xxx2_flash_ch_en_isr(const struct device *dev, bool enable) { if (enable) { - espi_it8xxx2_send_vwire(dev, ESPI_VWIRE_SIGNAL_SLV_BOOT_STS, 1); + espi_it8xxx2_send_vwire(dev, ESPI_VWIRE_SIGNAL_TARGET_BOOT_STS, 1); espi_it8xxx2_send_vwire(dev, - ESPI_VWIRE_SIGNAL_SLV_BOOT_DONE, 1); + ESPI_VWIRE_SIGNAL_TARGET_BOOT_DONE, 1); } espi_it8xxx2_ch_notify_system_state(dev, ESPI_CHANNEL_FLASH, enable); diff --git a/drivers/espi/espi_mchp_xec.c b/drivers/espi/espi_mchp_xec.c index 58678914862..88af24554a1 100644 --- a/drivers/espi/espi_mchp_xec.c +++ b/drivers/espi/espi_mchp_xec.c @@ -113,107 +113,107 @@ enum mchp_smvw_regs { }; /* Microchip canonical virtual wire mapping - * ------------------------------------------------------------------------| - * VW Idx | VW reg | SRC_ID3 | SRC_ID2 | SRC_ID1 | SRC_ID0 | - * ------------------------------------------------------------------------| + * --------------------------------------------------------------------------------| + * VW Idx | VW reg | SRC_ID3 | SRC_ID2 | SRC_ID1 | SRC_ID0 | + * --------------------------------------------------------------------------------| * System Event Virtual Wires - * ------------------------------------------------------------------------| - * 2h | MSVW00 | res | SLP_S5# | SLP_S4# | SLP_S3# | - * 3h | MSVW01 | res | OOB_RST_WARN | PLTRST# | SUS_STAT# | - * 4h | SMVW00 | PME# | WAKE# | res | OOB_RST_ACK | - * 5h | SMVW01 | SLV_BOOT_STS | ERR_NONFATAL | ERR_FATAL | SLV_BT_DONE | - * 6h | SMVW02 | HOST_RST_ACK | RCIN# | SMI# | SCI# | - * 7h | MSVW02 | res | res | res | HOS_RST_WARN| - * ------------------------------------------------------------------------| + * --------------------------------------------------------------------------------| + * 2h | MSVW00 | res | SLP_S5# | SLP_S4# | SLP_S3# | + * 3h | MSVW01 | res | OOB_RST_WARN | PLTRST# | SUS_STAT# | + * 4h | SMVW00 | PME# | WAKE# | res | OOB_RST_ACK | + * 5h | SMVW01 | TARGET_BOOT_STS | ERR_NONFATAL | ERR_FATAL | TARGET_BOOT_DONE | + * 6h | SMVW02 | HOST_RST_ACK | RCIN# | SMI# | SCI# | + * 7h | MSVW02 | res | res | res | HOS_RST_WARN | + * --------------------------------------------------------------------------------| * Platform specific virtual wires - * ------------------------------------------------------------------------| - * 40h | SMVW03 | res | res | DNX_ACK | SUS_ACK# | - * 41h | MSVW03 | SLP_A# | res | SUS_PDNACK| SUS_WARN# | - * 42h | MSVW04 | res | res | SLP_WLAN# | SLP_LAN# | - * 43h | MSVW05 | generic | generic | generic | generic | - * 44h | MSVW06 | generic | generic | generic | generic | - * 45h | SMVW04 | generic | generic | generic | generic | - * 46h | SMVW05 | generic | generic | generic | generic | - * 47h | MSVW07 | res | res | res | HOST_C10 | - * 4Ah | MSVW08 | res | res | DNX_WARN | res | - * 50h | SMVW06 | ESPI_OCB_3 | ESPI_OCB_2 | ESPI_OCB_1| ESPI_OCB_0 | + * --------------------------------------------------------------------------------| + * 40h | SMVW03 | res | res | DNX_ACK | SUS_ACK# | + * 41h | MSVW03 | SLP_A# | res | SUS_PDNACK| SUS_WARN# | + * 42h | MSVW04 | res | res | SLP_WLAN# | SLP_LAN# | + * 43h | MSVW05 | generic | generic | generic | generic | + * 44h | MSVW06 | generic | generic | generic | generic | + * 45h | SMVW04 | generic | generic | generic | generic | + * 46h | SMVW05 | generic | generic | generic | generic | + * 47h | MSVW07 | res | res | res | HOST_C10 | + * 4Ah | MSVW08 | res | res | DNX_WARN | res | + * 50h | SMVW06 | ESPI_OCB_3 | ESPI_OCB_2 | ESPI_OCB_1| ESPI_OCB_0 | */ static const struct xec_signal vw_tbl[] = { /* MSVW00 */ [ESPI_VWIRE_SIGNAL_SLP_S3] = {MCHP_MSVW00, ESPI_VWIRE_SRC_ID0, - ESPI_MASTER_TO_SLAVE}, + ESPI_CONTROLLER_TO_TARGET}, [ESPI_VWIRE_SIGNAL_SLP_S4] = {MCHP_MSVW00, ESPI_VWIRE_SRC_ID1, - ESPI_MASTER_TO_SLAVE}, + ESPI_CONTROLLER_TO_TARGET}, [ESPI_VWIRE_SIGNAL_SLP_S5] = {MCHP_MSVW00, ESPI_VWIRE_SRC_ID2, - ESPI_MASTER_TO_SLAVE}, + ESPI_CONTROLLER_TO_TARGET}, /* MSVW01 */ [ESPI_VWIRE_SIGNAL_SUS_STAT] = {MCHP_MSVW01, ESPI_VWIRE_SRC_ID0, - ESPI_MASTER_TO_SLAVE}, + ESPI_CONTROLLER_TO_TARGET}, [ESPI_VWIRE_SIGNAL_PLTRST] = {MCHP_MSVW01, ESPI_VWIRE_SRC_ID1, - ESPI_MASTER_TO_SLAVE}, + ESPI_CONTROLLER_TO_TARGET}, [ESPI_VWIRE_SIGNAL_OOB_RST_WARN] = {MCHP_MSVW01, ESPI_VWIRE_SRC_ID2, - ESPI_MASTER_TO_SLAVE}, + ESPI_CONTROLLER_TO_TARGET}, /* SMVW00 */ [ESPI_VWIRE_SIGNAL_OOB_RST_ACK] = {MCHP_SMVW00, ESPI_VWIRE_SRC_ID0, - ESPI_SLAVE_TO_MASTER}, + ESPI_TARGET_TO_CONTROLLER}, [ESPI_VWIRE_SIGNAL_WAKE] = {MCHP_SMVW00, ESPI_VWIRE_SRC_ID2, - ESPI_SLAVE_TO_MASTER}, + ESPI_TARGET_TO_CONTROLLER}, [ESPI_VWIRE_SIGNAL_PME] = {MCHP_SMVW00, ESPI_VWIRE_SRC_ID3, - ESPI_SLAVE_TO_MASTER}, + ESPI_TARGET_TO_CONTROLLER}, /* SMVW01 */ - [ESPI_VWIRE_SIGNAL_SLV_BOOT_DONE] = {MCHP_SMVW01, ESPI_VWIRE_SRC_ID0, - ESPI_SLAVE_TO_MASTER}, + [ESPI_VWIRE_SIGNAL_TARGET_BOOT_DONE] = {MCHP_SMVW01, ESPI_VWIRE_SRC_ID0, + ESPI_TARGET_TO_CONTROLLER}, [ESPI_VWIRE_SIGNAL_ERR_FATAL] = {MCHP_SMVW01, ESPI_VWIRE_SRC_ID1, - ESPI_SLAVE_TO_MASTER}, + ESPI_TARGET_TO_CONTROLLER}, [ESPI_VWIRE_SIGNAL_ERR_NON_FATAL] = {MCHP_SMVW01, ESPI_VWIRE_SRC_ID2, - ESPI_SLAVE_TO_MASTER}, - [ESPI_VWIRE_SIGNAL_SLV_BOOT_STS] = {MCHP_SMVW01, ESPI_VWIRE_SRC_ID3, - ESPI_SLAVE_TO_MASTER}, + ESPI_TARGET_TO_CONTROLLER}, + [ESPI_VWIRE_SIGNAL_TARGET_BOOT_STS] = {MCHP_SMVW01, ESPI_VWIRE_SRC_ID3, + ESPI_TARGET_TO_CONTROLLER}, /* SMVW02 */ [ESPI_VWIRE_SIGNAL_SCI] = {MCHP_SMVW02, ESPI_VWIRE_SRC_ID0, - ESPI_SLAVE_TO_MASTER}, + ESPI_TARGET_TO_CONTROLLER}, [ESPI_VWIRE_SIGNAL_SMI] = {MCHP_SMVW02, ESPI_VWIRE_SRC_ID1, - ESPI_SLAVE_TO_MASTER}, + ESPI_TARGET_TO_CONTROLLER}, [ESPI_VWIRE_SIGNAL_RST_CPU_INIT] = {MCHP_SMVW02, ESPI_VWIRE_SRC_ID2, - ESPI_SLAVE_TO_MASTER}, + ESPI_TARGET_TO_CONTROLLER}, [ESPI_VWIRE_SIGNAL_HOST_RST_ACK] = {MCHP_SMVW02, ESPI_VWIRE_SRC_ID3, - ESPI_SLAVE_TO_MASTER}, + ESPI_TARGET_TO_CONTROLLER}, /* MSVW02 */ [ESPI_VWIRE_SIGNAL_HOST_RST_WARN] = {MCHP_MSVW02, ESPI_VWIRE_SRC_ID0, - ESPI_MASTER_TO_SLAVE}, + ESPI_CONTROLLER_TO_TARGET}, /* SMVW03 */ [ESPI_VWIRE_SIGNAL_SUS_ACK] = {MCHP_SMVW03, ESPI_VWIRE_SRC_ID0, - ESPI_SLAVE_TO_MASTER}, + ESPI_TARGET_TO_CONTROLLER}, [ESPI_VWIRE_SIGNAL_DNX_ACK] = {MCHP_SMVW03, ESPI_VWIRE_SRC_ID1, - ESPI_SLAVE_TO_MASTER}, + ESPI_TARGET_TO_CONTROLLER}, /* MSVW03 */ [ESPI_VWIRE_SIGNAL_SUS_WARN] = {MCHP_MSVW03, ESPI_VWIRE_SRC_ID0, - ESPI_MASTER_TO_SLAVE}, + ESPI_CONTROLLER_TO_TARGET}, [ESPI_VWIRE_SIGNAL_SUS_PWRDN_ACK] = {MCHP_MSVW03, ESPI_VWIRE_SRC_ID1, - ESPI_MASTER_TO_SLAVE}, + ESPI_CONTROLLER_TO_TARGET}, [ESPI_VWIRE_SIGNAL_SLP_A] = {MCHP_MSVW03, ESPI_VWIRE_SRC_ID3, - ESPI_MASTER_TO_SLAVE}, + ESPI_CONTROLLER_TO_TARGET}, /* MSVW04 */ [ESPI_VWIRE_SIGNAL_SLP_LAN] = {MCHP_MSVW04, ESPI_VWIRE_SRC_ID0, - ESPI_MASTER_TO_SLAVE}, + ESPI_CONTROLLER_TO_TARGET}, [ESPI_VWIRE_SIGNAL_SLP_WLAN] = {MCHP_MSVW04, ESPI_VWIRE_SRC_ID1, - ESPI_MASTER_TO_SLAVE}, + ESPI_CONTROLLER_TO_TARGET}, /* MSVW07 */ [ESPI_VWIRE_SIGNAL_HOST_C10] = {MCHP_MSVW07, ESPI_VWIRE_SRC_ID0, - ESPI_MASTER_TO_SLAVE}, + ESPI_CONTROLLER_TO_TARGET}, /* MSVW08 */ [ESPI_VWIRE_SIGNAL_DNX_WARN] = {MCHP_MSVW08, ESPI_VWIRE_SRC_ID1, - ESPI_MASTER_TO_SLAVE}, + ESPI_CONTROLLER_TO_TARGET}, /* SMVW06 */ [ESPI_VWIRE_SIGNAL_OCB_0] = {MCHP_SMVW06, ESPI_VWIRE_SRC_ID0, - ESPI_SLAVE_TO_MASTER}, + ESPI_TARGET_TO_CONTROLLER}, [ESPI_VWIRE_SIGNAL_OCB_1] = {MCHP_SMVW06, ESPI_VWIRE_SRC_ID1, - ESPI_SLAVE_TO_MASTER}, + ESPI_TARGET_TO_CONTROLLER}, [ESPI_VWIRE_SIGNAL_OCB_2] = {MCHP_SMVW06, ESPI_VWIRE_SRC_ID2, - ESPI_SLAVE_TO_MASTER}, + ESPI_TARGET_TO_CONTROLLER}, [ESPI_VWIRE_SIGNAL_OCB_3] = {MCHP_SMVW06, ESPI_VWIRE_SRC_ID3, - ESPI_SLAVE_TO_MASTER}, + ESPI_TARGET_TO_CONTROLLER}, }; /* Buffer size are expressed in bytes */ @@ -445,14 +445,14 @@ static int espi_xec_send_vwire(const struct device *dev, return -EINVAL; } - if (signal_info.dir == ESPI_MASTER_TO_SLAVE) { + if (signal_info.dir == ESPI_CONTROLLER_TO_TARGET) { ESPI_MSVW_REG *reg = &(ESPI_M2S_VW_REGS->MSVW00) + xec_id; uint8_t *p8 = (uint8_t *)®->SRC; *(p8 + (uintptr_t) src_id) = level; } - if (signal_info.dir == ESPI_SLAVE_TO_MASTER) { + if (signal_info.dir == ESPI_TARGET_TO_CONTROLLER) { ESPI_SMVW_REG *reg = &(ESPI_S2M_VW_REGS->SMVW00) + xec_id; uint8_t *p8 = (uint8_t *)®->SRC; @@ -483,12 +483,12 @@ static int espi_xec_receive_vwire(const struct device *dev, return -EINVAL; } - if (signal_info.dir == ESPI_MASTER_TO_SLAVE) { + if (signal_info.dir == ESPI_CONTROLLER_TO_TARGET) { ESPI_MSVW_REG *reg = &(ESPI_M2S_VW_REGS->MSVW00) + xec_id; *level = ((reg->SRC >> (src_id << 3)) & 0x01ul); } - if (signal_info.dir == ESPI_SLAVE_TO_MASTER) { + if (signal_info.dir == ESPI_TARGET_TO_CONTROLLER) { ESPI_SMVW_REG *reg = &(ESPI_S2M_VW_REGS->SMVW00) + xec_id; *level = ((reg->SRC >> (src_id << 3)) & 0x01ul); } @@ -748,17 +748,17 @@ static int espi_xec_manage_callback(const struct device *dev, } #ifdef CONFIG_ESPI_AUTOMATIC_BOOT_DONE_ACKNOWLEDGE -static void send_slave_bootdone(const struct device *dev) +static void send_target_bootdone(const struct device *dev) { int ret; uint8_t boot_done; - ret = espi_xec_receive_vwire(dev, ESPI_VWIRE_SIGNAL_SLV_BOOT_DONE, + ret = espi_xec_receive_vwire(dev, ESPI_VWIRE_SIGNAL_TARGET_BOOT_DONE, &boot_done); if (!ret && !boot_done) { - /* SLAVE_BOOT_DONE & SLAVE_LOAD_STS have to be sent together */ - espi_xec_send_vwire(dev, ESPI_VWIRE_SIGNAL_SLV_BOOT_STS, 1); - espi_xec_send_vwire(dev, ESPI_VWIRE_SIGNAL_SLV_BOOT_DONE, 1); + /* TARGET_BOOT_DONE & TARGET_LOAD_STS have to be sent together */ + espi_xec_send_vwire(dev, ESPI_VWIRE_SIGNAL_TARGET_BOOT_STS, 1); + espi_xec_send_vwire(dev, ESPI_VWIRE_SIGNAL_TARGET_BOOT_DONE, 1); } } #endif @@ -994,7 +994,7 @@ static void espi_vwire_chanel_isr(const struct device *dev) /* VW channel interrupt can disabled at this point */ MCHP_GIRQ_ENCLR(config->bus_girq_id) = MCHP_ESPI_VW_EN_GIRQ_VAL; #ifdef CONFIG_ESPI_AUTOMATIC_BOOT_DONE_ACKNOWLEDGE - send_slave_bootdone(dev); + send_target_bootdone(dev); #endif } @@ -1086,7 +1086,7 @@ static void espi_flash_isr(const struct device *dev) if (status & MCHP_ESPI_FC_STS_CHAN_EN) { espi_init_flash(dev); - /* Indicate flash channel is ready to eSPI master */ + /* Indicate flash channel is ready to eSPI controller */ ESPI_CAP_REGS->FC_RDY = MCHP_ESPI_FC_READY; evt.evt_data = 1; } @@ -1197,7 +1197,7 @@ static void vw_sus_warn_isr(const struct device *dev) notify_host_warning(dev, ESPI_VWIRE_SIGNAL_SUS_WARN); /* Configure spare VW register SMVW06 to VW index 50h. As per * per microchip recommendation, spare VW register should be - * configured between SLAVE_BOOT_LOAD_DONE = 1 VW event and + * configured between TARGET_BOOT_LOAD_DONE = 1 VW event and * point where SUS_ACK=1 VW is sent to SOC. */ espi_config_vw_ocb(); diff --git a/drivers/espi/espi_mchp_xec_v2.c b/drivers/espi/espi_mchp_xec_v2.c index a1a5acefd93..46276db97b4 100644 --- a/drivers/espi/espi_mchp_xec_v2.c +++ b/drivers/espi/espi_mchp_xec_v2.c @@ -122,28 +122,28 @@ static const struct xec_signal vw_tbl[] = { MCHP_DT_ESPI_VW_ENTRY(ESPI_VWIRE_SIGNAL_PME, vw_pme_n), MCHP_DT_ESPI_VW_ENTRY(ESPI_VWIRE_SIGNAL_WAKE, vw_wake_n), MCHP_DT_ESPI_VW_ENTRY(ESPI_VWIRE_SIGNAL_OOB_RST_ACK, vw_oob_rst_ack), - MCHP_DT_ESPI_VW_ENTRY(ESPI_VWIRE_SIGNAL_SLV_BOOT_STS, vw_slave_boot_status), + MCHP_DT_ESPI_VW_ENTRY(ESPI_VWIRE_SIGNAL_TARGET_BOOT_STS, vw_target_boot_status), MCHP_DT_ESPI_VW_ENTRY(ESPI_VWIRE_SIGNAL_ERR_NON_FATAL, vw_error_non_fatal), MCHP_DT_ESPI_VW_ENTRY(ESPI_VWIRE_SIGNAL_ERR_FATAL, vw_error_fatal), - MCHP_DT_ESPI_VW_ENTRY(ESPI_VWIRE_SIGNAL_SLV_BOOT_DONE, vw_slave_boot_done), + MCHP_DT_ESPI_VW_ENTRY(ESPI_VWIRE_SIGNAL_TARGET_BOOT_DONE, vw_target_boot_done), MCHP_DT_ESPI_VW_ENTRY(ESPI_VWIRE_SIGNAL_HOST_RST_ACK, vw_host_rst_ack), MCHP_DT_ESPI_VW_ENTRY(ESPI_VWIRE_SIGNAL_RST_CPU_INIT, vw_rcin_n), MCHP_DT_ESPI_VW_ENTRY(ESPI_VWIRE_SIGNAL_SMI, vw_smi_n), MCHP_DT_ESPI_VW_ENTRY(ESPI_VWIRE_SIGNAL_SCI, vw_sci_n), MCHP_DT_ESPI_VW_ENTRY(ESPI_VWIRE_SIGNAL_DNX_ACK, vw_dnx_ack), MCHP_DT_ESPI_VW_ENTRY(ESPI_VWIRE_SIGNAL_SUS_ACK, vw_sus_ack_n), - MCHP_DT_ESPI_VW_ENTRY(ESPI_VWIRE_SIGNAL_SLV_GPIO_0, vw_t2c_gpio_0), - MCHP_DT_ESPI_VW_ENTRY(ESPI_VWIRE_SIGNAL_SLV_GPIO_1, vw_t2c_gpio_1), - MCHP_DT_ESPI_VW_ENTRY(ESPI_VWIRE_SIGNAL_SLV_GPIO_2, vw_t2c_gpio_2), - MCHP_DT_ESPI_VW_ENTRY(ESPI_VWIRE_SIGNAL_SLV_GPIO_3, vw_t2c_gpio_3), - MCHP_DT_ESPI_VW_ENTRY(ESPI_VWIRE_SIGNAL_SLV_GPIO_4, vw_t2c_gpio_4), - MCHP_DT_ESPI_VW_ENTRY(ESPI_VWIRE_SIGNAL_SLV_GPIO_5, vw_t2c_gpio_5), - MCHP_DT_ESPI_VW_ENTRY(ESPI_VWIRE_SIGNAL_SLV_GPIO_6, vw_t2c_gpio_6), - MCHP_DT_ESPI_VW_ENTRY(ESPI_VWIRE_SIGNAL_SLV_GPIO_7, vw_t2c_gpio_7), - MCHP_DT_ESPI_VW_ENTRY(ESPI_VWIRE_SIGNAL_SLV_GPIO_8, vw_t2c_gpio_8), - MCHP_DT_ESPI_VW_ENTRY(ESPI_VWIRE_SIGNAL_SLV_GPIO_9, vw_t2c_gpio_9), - MCHP_DT_ESPI_VW_ENTRY(ESPI_VWIRE_SIGNAL_SLV_GPIO_10, vw_t2c_gpio_10), - MCHP_DT_ESPI_VW_ENTRY(ESPI_VWIRE_SIGNAL_SLV_GPIO_11, vw_t2c_gpio_11), + MCHP_DT_ESPI_VW_ENTRY(ESPI_VWIRE_SIGNAL_TARGET_GPIO_0, vw_t2c_gpio_0), + MCHP_DT_ESPI_VW_ENTRY(ESPI_VWIRE_SIGNAL_TARGET_GPIO_1, vw_t2c_gpio_1), + MCHP_DT_ESPI_VW_ENTRY(ESPI_VWIRE_SIGNAL_TARGET_GPIO_2, vw_t2c_gpio_2), + MCHP_DT_ESPI_VW_ENTRY(ESPI_VWIRE_SIGNAL_TARGET_GPIO_3, vw_t2c_gpio_3), + MCHP_DT_ESPI_VW_ENTRY(ESPI_VWIRE_SIGNAL_TARGET_GPIO_4, vw_t2c_gpio_4), + MCHP_DT_ESPI_VW_ENTRY(ESPI_VWIRE_SIGNAL_TARGET_GPIO_5, vw_t2c_gpio_5), + MCHP_DT_ESPI_VW_ENTRY(ESPI_VWIRE_SIGNAL_TARGET_GPIO_6, vw_t2c_gpio_6), + MCHP_DT_ESPI_VW_ENTRY(ESPI_VWIRE_SIGNAL_TARGET_GPIO_7, vw_t2c_gpio_7), + MCHP_DT_ESPI_VW_ENTRY(ESPI_VWIRE_SIGNAL_TARGET_GPIO_8, vw_t2c_gpio_8), + MCHP_DT_ESPI_VW_ENTRY(ESPI_VWIRE_SIGNAL_TARGET_GPIO_9, vw_t2c_gpio_9), + MCHP_DT_ESPI_VW_ENTRY(ESPI_VWIRE_SIGNAL_TARGET_GPIO_10, vw_t2c_gpio_10), + MCHP_DT_ESPI_VW_ENTRY(ESPI_VWIRE_SIGNAL_TARGET_GPIO_11, vw_t2c_gpio_11), }; /* Buffer size are expressed in bytes */ @@ -311,13 +311,13 @@ static int espi_xec_send_vwire(const struct device *dev, dir = (signal_info.flags >> MCHP_DT_ESPI_VW_FLAG_DIR_POS) & BIT(0); - if (dir == ESPI_MASTER_TO_SLAVE) { + if (dir == ESPI_CONTROLLER_TO_TARGET) { regaddr = xec_msvw_addr(dev, xec_id); sys_write8(level, regaddr + MSVW_BI_SRC0 + src_id); } - if (dir == ESPI_SLAVE_TO_MASTER) { + if (dir == ESPI_TARGET_TO_CONTROLLER) { regaddr = xec_smvw_addr(dev, xec_id); sys_write8(level, regaddr + SMVW_BI_SRC0 + src_id); @@ -356,12 +356,12 @@ static int espi_xec_receive_vwire(const struct device *dev, dir = (signal_info.flags >> MCHP_DT_ESPI_VW_FLAG_DIR_POS) & BIT(0); - if (dir == ESPI_MASTER_TO_SLAVE) { + if (dir == ESPI_CONTROLLER_TO_TARGET) { regaddr = xec_msvw_addr(dev, xec_id); *level = sys_read8(regaddr + MSVW_BI_SRC0 + src_id) & BIT(0); } - if (dir == ESPI_SLAVE_TO_MASTER) { + if (dir == ESPI_TARGET_TO_CONTROLLER) { regaddr = xec_smvw_addr(dev, xec_id); *level = sys_read8(regaddr + SMVW_BI_SRC0 + src_id) & BIT(0); } @@ -631,12 +631,12 @@ static void send_slave_bootdone(const struct device *dev) int ret; uint8_t boot_done; - ret = espi_xec_receive_vwire(dev, ESPI_VWIRE_SIGNAL_SLV_BOOT_DONE, + ret = espi_xec_receive_vwire(dev, ESPI_VWIRE_SIGNAL_TARGET_BOOT_DONE, &boot_done); if (!ret && !boot_done) { /* SLAVE_BOOT_DONE & SLAVE_LOAD_STS have to be sent together */ - espi_xec_send_vwire(dev, ESPI_VWIRE_SIGNAL_SLV_BOOT_STS, 1); - espi_xec_send_vwire(dev, ESPI_VWIRE_SIGNAL_SLV_BOOT_DONE, 1); + espi_xec_send_vwire(dev, ESPI_VWIRE_SIGNAL_TARGET_BOOT_STS, 1); + espi_xec_send_vwire(dev, ESPI_VWIRE_SIGNAL_TARGET_BOOT_DONE, 1); } } #endif @@ -1414,7 +1414,7 @@ static void xec_vw_cfg_properties(const struct xec_signal *p, uint32_t regaddr, */ static void xec_vw_config(const struct device *dev) { - for (int i = ESPI_VWIRE_SIGNAL_SLV_GPIO_0; i < ARRAY_SIZE(vw_tbl); i++) { + for (int i = ESPI_VWIRE_SIGNAL_TARGET_GPIO_0; i < ARRAY_SIZE(vw_tbl); i++) { const struct xec_signal *p = &vw_tbl[i]; uint32_t regaddr = xec_smvw_addr(dev, p->xec_reg_idx); uint8_t dir = (p->flags >> MCHP_DT_ESPI_VW_FLAG_DIR_POS) & BIT(0); diff --git a/drivers/espi/espi_npcx.c b/drivers/espi/espi_npcx.c index 15cb5d489dc..05d7b60e2ea 100644 --- a/drivers/espi/espi_npcx.c +++ b/drivers/espi/espi_npcx.c @@ -153,10 +153,10 @@ static const struct npcx_vw_out_config vw_out_tbl[] = { NPCX_DT_VW_OUT_CONF(ESPI_VWIRE_SIGNAL_WAKE, vw_wake), NPCX_DT_VW_OUT_CONF(ESPI_VWIRE_SIGNAL_PME, vw_pme), /* index 05h (Out) */ - NPCX_DT_VW_OUT_CONF(ESPI_VWIRE_SIGNAL_SLV_BOOT_DONE, vw_slv_boot_done), + NPCX_DT_VW_OUT_CONF(ESPI_VWIRE_SIGNAL_TARGET_BOOT_DONE, vw_slv_boot_done), NPCX_DT_VW_OUT_CONF(ESPI_VWIRE_SIGNAL_ERR_FATAL, vw_err_fatal), NPCX_DT_VW_OUT_CONF(ESPI_VWIRE_SIGNAL_ERR_NON_FATAL, vw_err_non_fatal), - NPCX_DT_VW_OUT_CONF(ESPI_VWIRE_SIGNAL_SLV_BOOT_STS, + NPCX_DT_VW_OUT_CONF(ESPI_VWIRE_SIGNAL_TARGET_BOOT_STS, vw_slv_boot_sts_with_done), /* index 06h (Out) */ NPCX_DT_VW_OUT_CONF(ESPI_VWIRE_SIGNAL_SCI, vw_sci), @@ -171,15 +171,15 @@ static const struct npcx_vw_out_config vw_out_gpio_tbl1[] = { /* Only NPCX9 and later series support this feature */ #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), - NPCX_DT_VW_OUT_CONF(ESPI_VWIRE_SIGNAL_SLV_GPIO_2, vw_slv_gpio_2), - NPCX_DT_VW_OUT_CONF(ESPI_VWIRE_SIGNAL_SLV_GPIO_3, vw_slv_gpio_3), + NPCX_DT_VW_OUT_CONF(ESPI_VWIRE_SIGNAL_TARGET_GPIO_0, vw_slv_gpio_0), + NPCX_DT_VW_OUT_CONF(ESPI_VWIRE_SIGNAL_TARGET_GPIO_1, vw_slv_gpio_1), + NPCX_DT_VW_OUT_CONF(ESPI_VWIRE_SIGNAL_TARGET_GPIO_2, vw_slv_gpio_2), + NPCX_DT_VW_OUT_CONF(ESPI_VWIRE_SIGNAL_TARGET_GPIO_3, vw_slv_gpio_3), /* index 51h (Out) */ - NPCX_DT_VW_OUT_CONF(ESPI_VWIRE_SIGNAL_SLV_GPIO_4, vw_slv_gpio_4), - NPCX_DT_VW_OUT_CONF(ESPI_VWIRE_SIGNAL_SLV_GPIO_5, vw_slv_gpio_5), - NPCX_DT_VW_OUT_CONF(ESPI_VWIRE_SIGNAL_SLV_GPIO_6, vw_slv_gpio_6), - NPCX_DT_VW_OUT_CONF(ESPI_VWIRE_SIGNAL_SLV_GPIO_7, vw_slv_gpio_7), + NPCX_DT_VW_OUT_CONF(ESPI_VWIRE_SIGNAL_TARGET_GPIO_4, vw_slv_gpio_4), + NPCX_DT_VW_OUT_CONF(ESPI_VWIRE_SIGNAL_TARGET_GPIO_5, vw_slv_gpio_5), + NPCX_DT_VW_OUT_CONF(ESPI_VWIRE_SIGNAL_TARGET_GPIO_6, vw_slv_gpio_6), + NPCX_DT_VW_OUT_CONF(ESPI_VWIRE_SIGNAL_TARGET_GPIO_7, vw_slv_gpio_7), #endif }; @@ -363,7 +363,7 @@ static uint32_t espi_taf_parse(const struct device *dev) 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)) { + if ((taf_pckt.len == 0) && (taf_pckt.type == NPCX_ESPI_TAF_REQ_READ)) { taf_pckt.len = KB(4); } @@ -372,7 +372,7 @@ static uint32_t espi_taf_parse(const struct device *dev) 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) { + if (taf_pckt.type == 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]; @@ -415,27 +415,7 @@ static void espi_bus_flash_rx_isr(const struct device *dev) #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 +#endif /* CONFIG_ESPI_FLASH_CHANNEL */ const struct espi_bus_isr espi_bus_isr_tbl[] = { NPCX_ESPI_BUS_INT_ITEM(BERR, espi_bus_err_isr), @@ -447,7 +427,6 @@ 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 }; @@ -618,11 +597,11 @@ static void espi_vw_send_bootload_done(const struct device *dev) uint8_t boot_done; ret = espi_npcx_receive_vwire(dev, - ESPI_VWIRE_SIGNAL_SLV_BOOT_DONE, &boot_done); + ESPI_VWIRE_SIGNAL_TARGET_BOOT_DONE, &boot_done); LOG_DBG("%s: %d", __func__, boot_done); if (!ret && !boot_done) { /* Send slave boot status bit with done bit at the same time. */ - espi_npcx_send_vwire(dev, ESPI_VWIRE_SIGNAL_SLV_BOOT_STS, 1); + espi_npcx_send_vwire(dev, ESPI_VWIRE_SIGNAL_TARGET_BOOT_STS, 1); } } @@ -773,7 +752,7 @@ static int espi_npcx_send_vwire(const struct device *dev, return -EINVAL; } - if (signal >= ESPI_VWIRE_SIGNAL_SLV_GPIO_0) { + if (signal >= ESPI_VWIRE_SIGNAL_TARGET_GPIO_0) { vw_tbl = vw_out_gpio_tbl1; vw_tbl_size = ARRAY_SIZE(vw_out_gpio_tbl1); reg_name = "VWGPSM"; @@ -797,7 +776,7 @@ static int espi_npcx_send_vwire(const struct device *dev, bitmask = vw_tbl[sig_idx].bitmask; /* Get wire field and set/clear wire bit */ - if (signal >= ESPI_VWIRE_SIGNAL_SLV_GPIO_0) { + if (signal >= ESPI_VWIRE_SIGNAL_TARGET_GPIO_0) { val = GET_FIELD(inst->VWGPSM[reg_idx], NPCX_VWEVSM_WIRE); } else { val = GET_FIELD(inst->VWEVSM[reg_idx], NPCX_VWEVSM_WIRE); @@ -809,7 +788,7 @@ static int espi_npcx_send_vwire(const struct device *dev, val &= ~bitmask; } - if (signal >= ESPI_VWIRE_SIGNAL_SLV_GPIO_0) { + if (signal >= ESPI_VWIRE_SIGNAL_TARGET_GPIO_0) { SET_FIELD(inst->VWGPSM[reg_idx], NPCX_VWEVSM_WIRE, val); reg_val = inst->VWGPSM[reg_idx]; } else { @@ -1416,6 +1395,10 @@ static int espi_npcx_init(const struct device *dev) /* Configure host sub-modules which HW blocks belong to core domain */ npcx_host_init_subs_core_domain(dev, &data->callbacks); +#if defined(CONFIG_ESPI_FLASH_CHANNEL) && defined(CONFIG_ESPI_SAF) + npcx_init_taf(dev, &data->callbacks); +#endif + /* eSPI Bus interrupt installation */ IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), diff --git a/drivers/espi/espi_taf_npcx.c b/drivers/espi/espi_taf_npcx.c index 722b26730e8..c1760f7adf9 100644 --- a/drivers/espi/espi_taf_npcx.c +++ b/drivers/espi/espi_taf_npcx.c @@ -17,6 +17,14 @@ LOG_MODULE_REGISTER(espi_taf, CONFIG_ESPI_LOG_LEVEL); static const struct device *const spi_dev = DEVICE_DT_GET(DT_ALIAS(taf_flash)); +enum ESPI_TAF_ERASE_LEN { + NPCX_ESPI_TAF_ERASE_LEN_4KB, + NPCX_ESPI_TAF_ERASE_LEN_32KB, + NPCX_ESPI_TAF_ERASE_LEN_64KB, + NPCX_ESPI_TAF_ERASE_LEN_128KB, + NPCX_ESPI_TAF_ERASE_LEN_MAX, +}; + struct espi_taf_npcx_config { uintptr_t base; uintptr_t mapped_addr; @@ -26,9 +34,19 @@ struct espi_taf_npcx_config { }; struct espi_taf_npcx_data { - sys_slist_t callbacks; + sys_slist_t *callbacks; + const struct device *host_dev; + uint8_t taf_type; + uint8_t taf_tag; + uint32_t address; + uint16_t length; + uint32_t src[16]; + struct k_work work; }; +static struct espi_taf_npcx_data npcx_espi_taf_data; +static struct espi_callback espi_taf_cb; + #define HAL_INSTANCE(dev) \ ((struct espi_reg *)((const struct espi_taf_npcx_config *) \ (dev)->config)->base) @@ -45,6 +63,24 @@ struct espi_taf_npcx_data { GET_FIELD(inst->FLASH_PRTR_HADDR[i], NPCX_FLASH_PRTR_HADDR) \ << GET_FIELD_POS(NPCX_FLASH_PRTR_HADDR)) | 0xFFF; +static void espi_taf_get_pckt(const struct device *dev, struct espi_taf_npcx_data *pckt, + struct espi_event event) +{ + struct espi_taf_pckt *data_ptr; + + data_ptr = (struct espi_taf_pckt *)event.evt_data; + + pckt->taf_type = data_ptr->type; + pckt->length = data_ptr->len; + pckt->taf_tag = data_ptr->tag; + pckt->address = data_ptr->addr; + + if (data_ptr->type == NPCX_ESPI_TAF_REQ_WRITE) { + memcpy(pckt->src, data_ptr->src, sizeof(pckt->src)); + } +} + +#if defined(CONFIG_ESPI_TAF_MANUAL_MODE) /* 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) @@ -73,6 +109,7 @@ static bool espi_taf_check_read_protect(const struct device *dev, uint32_t addr, return false; } +#endif /* Check access region of write request is protected or not */ static bool espi_taf_check_write_protect(const struct device *dev, uint32_t addr, @@ -107,11 +144,16 @@ static int espi_taf_npcx_configure(const struct device *dev, const struct espi_s { struct espi_reg *const inst = HAL_INSTANCE(dev); + if (cfg->nflash_devices == 0U) { + return -EINVAL; + } + #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; } @@ -173,10 +215,17 @@ static int espi_taf_npcx_activate(const struct device *dev) static bool espi_taf_npcx_channel_ready(const struct device *dev) { struct espi_reg *const inst = HAL_INSTANCE(dev); + uint8_t ret = + GET_FIELD(inst->FLASHCFG, NPCX_FLASHCFG_FLCAPA) & NPCX_FLASH_SHARING_CAP_SUPP_TAF; - if (!IS_BIT_SET(inst->ESPICFG, NPCX_ESPICFG_FLCHANMODE)) { + if (ret != NPCX_FLASH_SHARING_CAP_SUPP_TAF) { return false; } + + if (!device_is_ready(spi_dev)) { + return false; + } + return true; } @@ -214,52 +263,58 @@ static void taf_release_flash_np_free(const struct device *dev) inst->FLASHCTL = tmp; } -static int taf_npcx_completion_handler(const struct device *dev, uint32_t *buffer) +static int taf_npcx_completion_handler(const struct device *dev, uint8_t type, uint8_t tag, + uint16_t len, 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; + struct npcx_taf_head taf_head; + uint16_t i, size; + uint32_t tx_buf[16]; + + taf_head.pkt_len = NPCX_TAF_CMP_HEADER_LEN + len; + taf_head.type = type; + taf_head.tag_hlen = (tag << 4) | ((len & 0xF00) >> 8); + taf_head.llen = len & 0xFF; + + memcpy(&tx_buf[0], &taf_head, sizeof(struct npcx_taf_head)); + + if (type == CYC_SCS_CMP_WITH_DATA_ONLY || type == CYC_SCS_CMP_WITH_DATA_FIRST || + type == CYC_SCS_CMP_WITH_DATA_MIDDLE || type == CYC_SCS_CMP_WITH_DATA_LAST) { + memcpy(&tx_buf[1], buffer, (uint8_t)(len)); + } /* 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)) { + if (WAIT_FOR(!IS_BIT_SET(inst->FLASHCTL, NPCX_FLASHCTL_FLASH_TX_AVAIL), + NPCX_FLASH_CHK_TIMEOUT, NULL) == false) { 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 */ + size = DIV_ROUND_UP((uint8_t)(tx_buf[0]) + 1, sizeof(uint32_t)); for (i = 0; i < size; i++) { - inst->FLASHTXBUF[i] = buffer[i]; + inst->FLASHTXBUF[i] = tx_buf[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)) { + if ((type != CYC_SCS_CMP_WITH_DATA_FIRST) && (type != CYC_SCS_CMP_WITH_DATA_MIDDLE)) { taf_release_flash_np_free(dev); } return 0; } +#if defined(CONFIG_ESPI_TAF_MANUAL_MODE) 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; @@ -267,7 +322,7 @@ static int espi_taf_npcx_flash_read(const struct device *dev, struct espi_saf_pa 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; + uint8_t read_buf[64]; int rc; if (flash_req_size > target_max_size) { @@ -297,21 +352,14 @@ static int espi_taf_npcx_flash_read(const struct device *dev, struct espi_saf_pa } 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); + rc = flash_read(spi_dev, addr, &read_buf[0], 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); + rc = taf_npcx_completion_handler(dev, cycle_type, taf_data_ptr->tag, len, + (uint32_t *)&read_buf[0]); if (rc) { LOG_ERR("espi taf completion handler fail"); return rc; @@ -330,12 +378,12 @@ static int espi_taf_npcx_flash_read(const struct device *dev, struct espi_saf_pa return 0; } +#endif 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, @@ -350,13 +398,8 @@ static int espi_taf_npcx_flash_write(const struct device *dev, struct espi_saf_p 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); + rc = taf_npcx_completion_handler(dev, CYC_SCS_CMP_WITHOUT_DATA, taf_data_ptr->tag, 0x0, + NULL); if (rc) { LOG_ERR("espi taf completion handler fail"); return rc; @@ -367,13 +410,19 @@ static int espi_taf_npcx_flash_write(const struct device *dev, struct espi_saf_p static int espi_taf_npcx_flash_erase(const struct device *dev, struct espi_saf_packet *pckt) { + int erase_blk[] = {KB(4), KB(32), KB(64), KB(128)}; 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; + uint32_t len; int rc; + if ((pckt->len < 0) || (pckt->len >= NPCX_ESPI_TAF_ERASE_LEN_MAX)) { + LOG_ERR("Invalid erase block size"); + return -EINVAL; + } + + len = erase_blk[pckt->len]; + if (espi_taf_check_write_protect(dev, addr, len, taf_data_ptr->tag)) { LOG_ERR("Access protection region"); return -EINVAL; @@ -385,13 +434,8 @@ static int espi_taf_npcx_flash_erase(const struct device *dev, struct espi_saf_p 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); + rc = taf_npcx_completion_handler(dev, CYC_SCS_CMP_WITHOUT_DATA, taf_data_ptr->tag, 0x0, + NULL); if (rc) { LOG_ERR("espi taf completion handler fail"); return rc; @@ -402,19 +446,11 @@ static int espi_taf_npcx_flash_erase(const struct device *dev, struct espi_saf_p 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; + struct espi_taf_npcx_pckt *taf_data_ptr = (struct espi_taf_npcx_pckt *)pckt->buf; 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); + rc = taf_npcx_completion_handler(dev, CYC_UNSCS_CMP_WITHOUT_DATA_ONLY, taf_data_ptr->tag, + 0x0, NULL); if (rc) { LOG_ERR("espi taf completion handler fail"); return rc; @@ -423,6 +459,67 @@ static int espi_taf_npcx_flash_unsuccess(const struct device *dev, struct espi_s return 0; } +static void espi_taf_work(struct k_work *item) +{ + struct espi_taf_npcx_data *info = CONTAINER_OF(item, struct espi_taf_npcx_data, work); + int ret = 0; + + struct espi_taf_npcx_pckt taf_data; + struct espi_saf_packet pckt_taf; + + pckt_taf.flash_addr = info->address; + pckt_taf.len = info->length; + taf_data.tag = info->taf_tag; + if (info->taf_type == NPCX_ESPI_TAF_REQ_WRITE) { + taf_data.data = (uint8_t *)info->src; + } else { + taf_data.data = NULL; + } + pckt_taf.buf = (uint8_t *)&taf_data; + + switch (info->taf_type) { +#if defined(CONFIG_ESPI_TAF_MANUAL_MODE) + case NPCX_ESPI_TAF_REQ_READ: + ret = espi_taf_npcx_flash_read(info->host_dev, &pckt_taf); + break; +#endif + case NPCX_ESPI_TAF_REQ_ERASE: + ret = espi_taf_npcx_flash_erase(info->host_dev, &pckt_taf); + break; + case NPCX_ESPI_TAF_REQ_WRITE: + ret = espi_taf_npcx_flash_write(info->host_dev, &pckt_taf); + break; + } + + if (ret != 0) { + ret = espi_taf_npcx_flash_unsuccess(info->host_dev, &pckt_taf); + } +} + +static void espi_taf_event_handler(const struct device *dev, struct espi_callback *cb, + struct espi_event event) +{ + if ((event.evt_type != ESPI_BUS_SAF_NOTIFICATION) || + (event.evt_details != ESPI_CHANNEL_FLASH)) { + return; + } + + espi_taf_get_pckt(dev, &npcx_espi_taf_data, event); + k_work_submit(&npcx_espi_taf_data.work); +} + +int npcx_init_taf(const struct device *dev, sys_slist_t *callbacks) +{ + espi_init_callback(&espi_taf_cb, espi_taf_event_handler, ESPI_BUS_SAF_NOTIFICATION); + espi_add_callback(dev, &espi_taf_cb); + + npcx_espi_taf_data.host_dev = dev; + npcx_espi_taf_data.callbacks = callbacks; + k_work_init(&npcx_espi_taf_data.work, espi_taf_work); + + return 0; +} + static int espi_taf_npcx_init(const struct device *dev) { struct espi_reg *const inst = HAL_INSTANCE(dev); @@ -444,14 +541,8 @@ static const struct espi_saf_driver_api espi_taf_npcx_driver_api = { .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), diff --git a/drivers/espi/host_subs_npcx.c b/drivers/espi/host_subs_npcx.c index 41810666604..51802586c8c 100644 --- a/drivers/espi/host_subs_npcx.c +++ b/drivers/espi/host_subs_npcx.c @@ -191,6 +191,7 @@ struct host_sub_npcx_data host_sub_data; #define NPCX_C2H_TRANSACTION_TIMEOUT_US 200 /* Logical Device Number Assignments */ +#define EC_CFG_LDN_SP 0x03 #define EC_CFG_LDN_MOUSE 0x05 #define EC_CFG_LDN_KBC 0x06 #define EC_CFG_LDN_SHM 0x0F @@ -205,6 +206,13 @@ struct host_sub_npcx_data host_sub_data; #define EC_CFG_IDX_DATA_IO_ADDR_H 0x62 #define EC_CFG_IDX_DATA_IO_ADDR_L 0x63 +/* LDN Activation Enable */ +#define EC_CFG_IDX_CTRL_LDN_ENABLE 0x01 + +/* Index of SuperI/O Control and Configuration Registers */ +#define EC_CFG_IDX_SUPERIO_SIOCF9 0x29 +#define EC_CFG_IDX_SUPERIO_SIOCF9_CKEN 2 + /* Index of Special Logical Device Configuration (Shared Memory Module) */ #define EC_CFG_IDX_SHM_CFG 0xF1 #define EC_CFG_IDX_SHM_WND1_ADDR_0 0xF4 @@ -217,6 +225,11 @@ struct host_sub_npcx_data host_sub_data; #define EC_CFG_IDX_SHM_WND2_ADDR_3 0xFB #define EC_CFG_IDX_SHM_DP80_ADDR_RANGE 0xFD +/* Index of Special Logical Device Configuration (Serial Port/Host UART) */ +#define EC_CFG_IDX_SP_CFG 0xF0 +/* Enable selection of bank 2 and 3 for the Serial Port */ +#define EC_CFG_IDX_SP_CFG_BK_SL_ENABLE 7 + /* Host sub-device local inline functions */ static inline uint8_t host_shd_mem_wnd_size_sl(uint32_t size) { @@ -995,10 +1008,10 @@ void npcx_host_init_subs_host_domain(void) * modules by setting bit 0 in its Control (index is 0x30) reg. */ host_c2h_write_io_cfg_reg(EC_CFG_IDX_LDN, EC_CFG_LDN_KBC); - host_c2h_write_io_cfg_reg(EC_CFG_IDX_CTRL, 0x01); + host_c2h_write_io_cfg_reg(EC_CFG_IDX_CTRL, EC_CFG_IDX_CTRL_LDN_ENABLE); host_c2h_write_io_cfg_reg(EC_CFG_IDX_LDN, EC_CFG_LDN_MOUSE); - host_c2h_write_io_cfg_reg(EC_CFG_IDX_CTRL, 0x01); + host_c2h_write_io_cfg_reg(EC_CFG_IDX_CTRL, EC_CFG_IDX_CTRL_LDN_ENABLE); } if (IS_ENABLED(CONFIG_ESPI_PERIPHERAL_HOST_IO)) { @@ -1007,7 +1020,7 @@ void npcx_host_init_subs_host_domain(void) * module by setting bit 0 in its Control (index is 0x30) reg. */ host_c2h_write_io_cfg_reg(EC_CFG_IDX_LDN, EC_CFG_LDN_ACPI); - host_c2h_write_io_cfg_reg(EC_CFG_IDX_CTRL, 0x01); + host_c2h_write_io_cfg_reg(EC_CFG_IDX_CTRL, EC_CFG_IDX_CTRL_LDN_ENABLE); } if (IS_ENABLED(CONFIG_ESPI_PERIPHERAL_EC_HOST_CMD) || @@ -1028,7 +1041,7 @@ void npcx_host_init_subs_host_domain(void) (CONFIG_ESPI_PERIPHERAL_HOST_CMD_DATA_PORT_NUM + 4) & 0xff); #endif /* Enable 'Host Command' io port (PM Channel 2) */ - host_c2h_write_io_cfg_reg(EC_CFG_IDX_CTRL, 0x01); + host_c2h_write_io_cfg_reg(EC_CFG_IDX_CTRL, EC_CFG_IDX_CTRL_LDN_ENABLE); /* Select 'Shared Memory' bank which LDN are 0x0F */ host_c2h_write_io_cfg_reg(EC_CFG_IDX_LDN, EC_CFG_LDN_SHM); @@ -1053,8 +1066,23 @@ void npcx_host_init_subs_host_domain(void) host_c2h_write_io_cfg_reg(EC_CFG_IDX_SHM_DP80_ADDR_RANGE, 0x0f); } /* Enable SHM direct memory access */ - host_c2h_write_io_cfg_reg(EC_CFG_IDX_CTRL, 0x01); + host_c2h_write_io_cfg_reg(EC_CFG_IDX_CTRL, EC_CFG_IDX_CTRL_LDN_ENABLE); } + + if (IS_ENABLED(CONFIG_ESPI_PERIPHERAL_UART)) { + /* Select Serial Port banks which LDN are 0x03. */ + host_c2h_write_io_cfg_reg(EC_CFG_IDX_LDN, EC_CFG_LDN_SP); + /* Enable SIO_CLK */ + host_c2h_write_io_cfg_reg(EC_CFG_IDX_SUPERIO_SIOCF9, + host_c2h_read_io_cfg_reg(EC_CFG_IDX_SUPERIO_SIOCF9) | + BIT(EC_CFG_IDX_SUPERIO_SIOCF9_CKEN)); + /* Enable Bank Select */ + host_c2h_write_io_cfg_reg(EC_CFG_IDX_SP_CFG, + host_c2h_read_io_cfg_reg(EC_CFG_IDX_SP_CFG) | + BIT(EC_CFG_IDX_SP_CFG_BK_SL_ENABLE)); + host_c2h_write_io_cfg_reg(EC_CFG_IDX_CTRL, EC_CFG_IDX_CTRL_LDN_ENABLE); + } + LOG_DBG("Hos sub-modules configurations are done!"); } diff --git a/drivers/ethernet/CMakeLists.txt b/drivers/ethernet/CMakeLists.txt index f8c2ee04df5..02b8f96bc9b 100644 --- a/drivers/ethernet/CMakeLists.txt +++ b/drivers/ethernet/CMakeLists.txt @@ -28,7 +28,6 @@ zephyr_library_sources_ifdef(CONFIG_ETH_ENC424J600 eth_enc424j600.c) zephyr_library_sources_ifdef(CONFIG_ETH_ESP32 eth_esp32.c) zephyr_library_sources_ifdef(CONFIG_DSA_KSZ8XXX dsa_ksz8xxx.c) zephyr_library_sources_ifdef(CONFIG_ETH_LITEETH eth_liteeth.c) -zephyr_library_sources_ifdef(CONFIG_ETH_MCUX eth_mcux.c) zephyr_library_sources_ifdef(CONFIG_ETH_SMSC911X eth_smsc911x.c) zephyr_library_sources_ifdef(CONFIG_ETH_STELLARIS eth_stellaris.c) zephyr_library_sources_ifdef(CONFIG_ETH_STM32_HAL eth_stm32_hal.c) @@ -40,7 +39,6 @@ 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) @@ -68,3 +66,4 @@ endif() add_subdirectory(phy) add_subdirectory(eth_nxp_enet_qos) +add_subdirectory(nxp_enet) diff --git a/drivers/ethernet/Kconfig b/drivers/ethernet/Kconfig index 12283d39012..f54d659b7c0 100644 --- a/drivers/ethernet/Kconfig +++ b/drivers/ethernet/Kconfig @@ -52,7 +52,6 @@ config ETH_QEMU_EXTRA_ARGS source "drivers/ethernet/Kconfig.enc28j60" source "drivers/ethernet/Kconfig.enc424j600" source "drivers/ethernet/Kconfig.esp32" -source "drivers/ethernet/Kconfig.mcux" source "drivers/ethernet/Kconfig.e1000" source "drivers/ethernet/Kconfig.sam_gmac" source "drivers/ethernet/Kconfig.stm32_hal" @@ -73,13 +72,14 @@ 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/eth_nxp_enet_qos/Kconfig" source "drivers/ethernet/phy/Kconfig" +source "drivers/ethernet/nxp_enet/Kconfig" + endif # "Ethernet Drivers" config ETH_INIT_PRIORITY diff --git a/drivers/ethernet/Kconfig.dsa b/drivers/ethernet/Kconfig.dsa index c6b78f0a463..1974ce97f18 100644 --- a/drivers/ethernet/Kconfig.dsa +++ b/drivers/ethernet/Kconfig.dsa @@ -4,9 +4,14 @@ # Lukasz Majewski # SPDX-License-Identifier: Apache-2.0 +config ETH_DSA_SUPPORT + bool + help + Set by an ethernet driver that supports DSA. + menuconfig NET_DSA bool "Distributed Switch Architecture support" - depends on ETH_MCUX || ETH_SAM_GMAC || ETH_STM32_HAL + depends on ETH_DSA_SUPPORT help Enable Distributed Switch Architecture support. For now it only supports Kinetics and STM32 ENET drivers. diff --git a/drivers/ethernet/Kconfig.mcux b/drivers/ethernet/Kconfig.mcux deleted file mode 100644 index c9b8e4fb6f2..00000000000 --- a/drivers/ethernet/Kconfig.mcux +++ /dev/null @@ -1,113 +0,0 @@ -# ETH_MCUX Ethernet driver configuration options - -# Copyright (c) 2016-2017 ARM Ltd -# SPDX-License-Identifier: Apache-2.0 - -menuconfig ETH_MCUX - bool "MCUX Ethernet driver" - default y - depends on DT_HAS_NXP_KINETIS_ETHERNET_ENABLED - select NOCACHE_MEMORY if HAS_MCUX_CACHE && CPU_HAS_DCACHE - select ARM_MPU if CPU_CORTEX_M7 - select NET_POWER_MANAGEMENT if PM_DEVICE - help - Enable MCUX Ethernet driver. Note, this driver performs one shot PHY - setup. There is no support for PHY disconnect, reconnect or - configuration change. - -if ETH_MCUX - -config ETH_MCUX_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_MCUX_PROMISCUOUS_MODE - bool "Promiscuous mode" - help - Place the Ethernet receiver in promiscuous mode. This may be useful - for debugging and not needed for normal work. - -config ETH_MCUX_RMII_EXT_CLK - bool "RMII clock from external sources" - help - Setting this option will configure MCUX clock block to feed RMII - reference clock from external source (ENET_1588_CLKIN) - -config ETH_MCUX_NO_PHY_SMI - bool "Do not use SMI for PHY communication" - help - Some PHY devices, with DSA capabilities do not use SMI for - communication with MAC ENET controller. Other busses - like SPI - or I2C are used instead. - -config ETH_MCUX_PHY_TICK_MS - int "PHY poll period (ms)" - default 1000 - range 100 30000 - help - Set the PHY status polling period. - -config ETH_MCUX_PHY_EXTRA_DEBUG - bool "Additional detailed PHY debug" - help - Enable additional PHY related debug information related to - PHY status polling. - -config ETH_MCUX_RX_BUFFERS - int "Number of MCUX RX buffers" - default 6 - range 6 16 - help - Set the number of RX buffers provided to the MCUX driver. - -config ETH_MCUX_PHY_RESET - bool "Reset the PHY at boot" - help - Reset the ethernet PHY at boot. Requires dts properties int-gpios and - reset-gpios to be present. - -config ETH_MCUX_TX_BUFFERS - int "Number of MCUX TX buffers" - default 1 - range 1 16 - help - Set the number of TX buffers provided to the MCUX driver. - -config ETH_MCUX_HW_ACCELERATION - bool "Hardware acceleration" - help - Enable hardware acceleration for the following: - - IPv4, UDP and TCP checksum (both Rx and Tx) - -config PTP_CLOCK_MCUX - bool "MCUX PTP clock driver support" - default y - depends on PTP_CLOCK || NET_L2_PTP - help - Enable MCUX PTP clock support. - -if PTP_CLOCK_MCUX - -config ETH_MCUX_PTP_CLOCK_SRC_HZ - int "Frequency of the clock source for the PTP timer" - default 50000000 if SOC_SERIES_KINETIS_K6X - default 50000000 if SOC_SERIES_IMXRT10XX - default 24000000 if SOC_SERIES_IMXRT11XX - help - Set the frequency in Hz sourced to the PTP timer. - If the value is set properly, the timer will be accurate. - -config ETH_MCUX_PTP_CLOCK_INIT_PRIO - int - default 85 - help - MCUX PTP Clock initialization priority level. There is - a dependency from the network stack that this device - initializes before network stack (NET_INIT_PRIO). - -endif # PTP_CLOCK_MCUX - -endif # ETH_MCUX diff --git a/drivers/ethernet/Kconfig.nxp_enet b/drivers/ethernet/Kconfig.nxp_enet deleted file mode 100644 index a6182ade32d..00000000000 --- a/drivers/ethernet/Kconfig.nxp_enet +++ /dev/null @@ -1,54 +0,0 @@ -# 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.sam_gmac b/drivers/ethernet/Kconfig.sam_gmac index 66f833a381d..7037c313a00 100644 --- a/drivers/ethernet/Kconfig.sam_gmac +++ b/drivers/ethernet/Kconfig.sam_gmac @@ -11,6 +11,7 @@ menuconfig ETH_SAM_GMAC DT_HAS_ATMEL_SAM0_GMAC_ENABLED select NOCACHE_MEMORY if ARCH_HAS_NOCACHE_MEMORY_SUPPORT select MDIO + select ETH_DSA_SUPPORT help Enable Atmel SAM MCU Family Ethernet driver. diff --git a/drivers/ethernet/Kconfig.stm32_hal b/drivers/ethernet/Kconfig.stm32_hal index 8161ea31f5f..6bd0c65f9b9 100644 --- a/drivers/ethernet/Kconfig.stm32_hal +++ b/drivers/ethernet/Kconfig.stm32_hal @@ -11,6 +11,8 @@ menuconfig ETH_STM32_HAL select USE_STM32_HAL_ETH select NOCACHE_MEMORY if SOC_SERIES_STM32H7X && CPU_CORTEX_M7 select HWINFO + select ETH_DSA_SUPPORT + select MDIO if SOC_SERIES_STM32H5X || SOC_SERIES_STM32H7X imply CRC help Enable STM32 HAL based Ethernet driver. It is available for @@ -28,7 +30,7 @@ config ETH_STM32_HAL_API_V2 Use the new HAL driver instead of the legacy one. config ETH_STM32_HAL_API_V1 - bool "Use new HAL driver" + bool "Use legacy HAL driver" depends on !SOC_SERIES_STM32H5X select DEPRECATED if SOC_SERIES_STM32H7X || SOC_SERIES_STM32F4X || SOC_SERIES_STM32F7X help diff --git a/drivers/ethernet/dsa_ksz8xxx.c b/drivers/ethernet/dsa_ksz8xxx.c index 964cd3505d3..9cf136f7b01 100644 --- a/drivers/ethernet/dsa_ksz8xxx.c +++ b/drivers/ethernet/dsa_ksz8xxx.c @@ -16,6 +16,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_ETHERNET_LOG_LEVEL); #include #include #include +#include #if defined(CONFIG_DSA_SPI) #include @@ -280,9 +281,9 @@ static int dsa_ksz8xxx_switch_setup(const struct ksz8xxx_data *pdev) #if defined(CONFIG_DSA_KSZ_TAIL_TAGGING) /* Enable tail tag feature */ - dsa_ksz8xxx_read_reg(pdev, KSZ8863_GLOBAL_CTRL10, &tmp); + dsa_ksz8xxx_read_reg(pdev, KSZ8863_GLOBAL_CTRL1, &tmp); tmp |= KSZ8863_GLOBAL_CTRL1_TAIL_TAG_EN; - dsa_ksz8xxx_write_reg(pdev, KSZ8863_GLOBAL_CTRL10, tmp); + dsa_ksz8xxx_write_reg(pdev, KSZ8863_GLOBAL_CTRL1, tmp); #else /* Disable tail tag feature */ dsa_ksz8xxx_read_reg(pdev, KSZ8863_GLOBAL_CTRL1, &tmp); @@ -1065,7 +1066,8 @@ static struct dsa_api dsa_api_f = { const struct dsa_slave_config dsa_0_slave_##slave##_config = { \ .mac_addr = DT_PROP_OR(slave, local_mac_address, {0}) \ }; \ - NET_DEVICE_DT_DEFINE_INSTANCE(slave, \ + NET_DEVICE_INIT_INSTANCE(CONCAT(dsa_slave_port_, slave), \ + "lan" STRINGIFY(n), \ n, \ dsa_port_init, \ NULL, \ diff --git a/drivers/ethernet/eth_liteeth.c b/drivers/ethernet/eth_liteeth.c index 332ad5e6571..5fc2780fdae 100644 --- a/drivers/ethernet/eth_liteeth.c +++ b/drivers/ethernet/eth_liteeth.c @@ -180,6 +180,25 @@ static void eth_irq_handler(const struct device *port) } } +static int eth_set_config(const struct device *dev, enum ethernet_config_type type, + const struct ethernet_config *config) +{ + struct eth_liteeth_dev_data *context = dev->data; + int ret = -ENOTSUP; + + switch (type) { + case ETHERNET_CONFIG_TYPE_MAC_ADDRESS: + memcpy(context->mac_addr, config->mac_address.addr, sizeof(context->mac_addr)); + ret = net_if_set_link_addr(context->iface, context->mac_addr, + sizeof(context->mac_addr), NET_LINK_ETHERNET); + break; + default: + break; + } + + return ret; +} + #ifdef CONFIG_ETH_LITEETH_0 static struct eth_liteeth_dev_data eth_data = { @@ -247,6 +266,7 @@ static enum ethernet_hw_caps eth_caps(const struct device *dev) static const struct ethernet_api eth_api = { .iface_api.init = eth_iface_init, .get_capabilities = eth_caps, + .set_config = eth_set_config, .send = eth_tx }; diff --git a/drivers/ethernet/eth_stm32_hal.c b/drivers/ethernet/eth_stm32_hal.c index 10391a5458e..0da1411c311 100644 --- a/drivers/ethernet/eth_stm32_hal.c +++ b/drivers/ethernet/eth_stm32_hal.c @@ -23,6 +23,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #include #include #include +#include #include #include #include @@ -57,6 +58,11 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32H5X) +#define DEVICE_PHY_BY_NAME(n) \ + DEVICE_DT_GET(DT_CHILD(DT_INST_CHILD(n, mdio), ethernet_phy_0)) + +static const struct device *eth_stm32_phy_dev = DEVICE_PHY_BY_NAME(0); + #define PHY_BSR ((uint16_t)0x0001U) /*!< Transceiver Basic Status Register */ #define PHY_LINKED_STATUS ((uint16_t)0x0004U) /*!< Valid link established */ @@ -211,8 +217,9 @@ static HAL_StatusTypeDef read_eth_phy_register(ETH_HandleTypeDef *heth, uint32_t PHYReg, uint32_t *RegVal) { -#if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32H5X) || \ - defined(CONFIG_ETH_STM32_HAL_API_V2) +#if defined(CONFIG_MDIO) + return phy_read(eth_stm32_phy_dev, PHYReg, RegVal); +#elif defined(CONFIG_ETH_STM32_HAL_API_V2) return HAL_ETH_ReadPHYRegister(heth, PHYAddr, PHYReg, RegVal); #else ARG_UNUSED(PHYAddr); @@ -1225,7 +1232,6 @@ static int eth_initialize(const struct device *dev) setup_mac_filter(heth); - LOG_DBG("MAC %02x:%02x:%02x:%02x:%02x:%02x", dev_data->mac_addr[0], dev_data->mac_addr[1], dev_data->mac_addr[2], dev_data->mac_addr[3], diff --git a/drivers/ethernet/eth_w5500.c b/drivers/ethernet/eth_w5500.c index a44ac78b7b0..6f726c1c1eb 100644 --- a/drivers/ethernet/eth_w5500.c +++ b/drivers/ethernet/eth_w5500.c @@ -39,8 +39,6 @@ static int w5500_spi_read(const struct device *dev, uint32_t addr, { const struct w5500_config *cfg = dev->config; int ret; - /* 3 bytes as 0x010203 during command phase */ - uint8_t tmp[len + 3]; uint8_t cmd[3] = { addr >> 8, @@ -55,22 +53,24 @@ static int w5500_spi_read(const struct device *dev, uint32_t addr, .buffers = &tx_buf, .count = 1, }; - const struct spi_buf rx_buf = { - .buf = tmp, - .len = ARRAY_SIZE(tmp), + /* skip the default dummy 0x010203 */ + const struct spi_buf rx_buf[2] = { + { + .buf = NULL, + .len = 3 + }, + { + .buf = data, + .len = len + }, }; const struct spi_buf_set rx = { - .buffers = &rx_buf, - .count = 1, + .buffers = rx_buf, + .count = ARRAY_SIZE(rx_buf), }; ret = spi_transceive_dt(&cfg->spi, &tx, &rx); - if (!ret) { - /* skip the default dummy 0x010203 */ - memcpy(data, &tmp[3], len); - } - return ret; } @@ -468,7 +468,7 @@ static struct ethernet_api w5500_api_funcs = { .send = w5500_tx, }; -static int w5500_hw_reset(const struct device *dev) +static int w5500_soft_reset(const struct device *dev) { int ret; uint8_t mask = 0; @@ -502,14 +502,7 @@ static void w5500_set_macaddr(const struct device *dev) struct w5500_runtime *ctx = dev->data; #if DT_INST_PROP(0, zephyr_random_mac_address) - /* override vendor bytes */ - memset(ctx->mac_addr, '\0', sizeof(ctx->mac_addr)); - ctx->mac_addr[0] = WIZNET_OUI_B0; - ctx->mac_addr[1] = WIZNET_OUI_B1; - ctx->mac_addr[2] = WIZNET_OUI_B2; - if (ctx->generate_mac) { - ctx->generate_mac(ctx->mac_addr); - } + gen_random_mac(ctx->mac_addr, WIZNET_OUI_B0, WIZNET_OUI_B1, WIZNET_OUI_B2); #endif w5500_spi_write(dev, W5500_SHAR, ctx->mac_addr, sizeof(ctx->mac_addr)); @@ -531,11 +524,6 @@ static void w5500_memory_configure(const struct device *dev) } } -static void w5500_random_mac(uint8_t *mac_addr) -{ - gen_random_mac(mac_addr, WIZNET_OUI_B0, WIZNET_OUI_B1, WIZNET_OUI_B2); -} - static int w5500_init(const struct device *dev) { int err; @@ -583,7 +571,7 @@ static int w5500_init(const struct device *dev) k_usleep(500); } - err = w5500_hw_reset(dev); + err = w5500_soft_reset(dev); if (err) { LOG_ERR("Reset failed"); return err; @@ -605,6 +593,7 @@ static int w5500_init(const struct device *dev) (void *)dev, NULL, NULL, K_PRIO_COOP(CONFIG_ETH_W5500_RX_THREAD_PRIO), 0, K_NO_WAIT); + k_thread_name_set(&ctx->thread, "eth_w5500"); LOG_INF("W5500 Initialized"); @@ -615,7 +604,6 @@ static struct w5500_runtime w5500_0_runtime = { #if NODE_HAS_VALID_MAC_ADDR(DT_DRV_INST(0)) .mac_addr = DT_INST_PROP(0, local_mac_address), #endif - .generate_mac = w5500_random_mac, .tx_sem = Z_SEM_INITIALIZER(w5500_0_runtime.tx_sem, 1, UINT_MAX), .int_sem = Z_SEM_INITIALIZER(w5500_0_runtime.int_sem, diff --git a/drivers/ethernet/eth_w5500_priv.h b/drivers/ethernet/eth_w5500_priv.h index 21df5f62421..79383d9004b 100644 --- a/drivers/ethernet/eth_w5500_priv.h +++ b/drivers/ethernet/eth_w5500_priv.h @@ -83,8 +83,6 @@ struct w5500_config { struct spi_dt_spec spi; struct gpio_dt_spec interrupt; struct gpio_dt_spec reset; - void (*config_func)(void); - uint8_t full_duplex; int32_t timeout; }; @@ -99,7 +97,6 @@ struct w5500_runtime { struct k_sem tx_sem; struct k_sem int_sem; bool link_up; - void (*generate_mac)(uint8_t *mac); uint8_t buf[NET_ETH_MAX_FRAME_SIZE]; }; diff --git a/drivers/ethernet/nxp_enet/CMakeLists.txt b/drivers/ethernet/nxp_enet/CMakeLists.txt new file mode 100644 index 00000000000..777a1624ff1 --- /dev/null +++ b/drivers/ethernet/nxp_enet/CMakeLists.txt @@ -0,0 +1,5 @@ +# Copyright 2024 NXP +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library_sources_ifdef(CONFIG_ETH_NXP_ENET eth_nxp_enet.c) +zephyr_library_sources_ifdef(CONFIG_ETH_MCUX eth_mcux.c) diff --git a/drivers/ethernet/nxp_enet/Kconfig b/drivers/ethernet/nxp_enet/Kconfig new file mode 100644 index 00000000000..d2eb4d07135 --- /dev/null +++ b/drivers/ethernet/nxp_enet/Kconfig @@ -0,0 +1,186 @@ +# NXP ENET ethernet drivers configuration options + +# Copyright (c) 2016-2017 ARM Ltd +# Copyright 2024 NXP +# SPDX-License-Identifier: Apache-2.0 + +menu "NXP ENET" + +choice NXP_ENET_DRIVER + prompt "NXP ENET Driver Version" + default ETH_NXP_ENET if DT_HAS_NXP_ENET_MAC_ENABLED + default ETH_MCUX if DT_HAS_NXP_KINETIS_ETHERNET_ENABLED + depends on DT_HAS_NXP_ENET_MAC_ENABLED || DT_HAS_NXP_KINETIS_ETHERNET_ENABLED + +config ETH_NXP_ENET + bool "NXP ENET Ethernet driver" + select NOCACHE_MEMORY if HAS_MCUX_CACHE + select ARM_MPU if CPU_CORTEX_M7 + select MDIO if DT_HAS_NXP_ENET_MDIO_ENABLED + select NET_POWER_MANAGEMENT if (PM_DEVICE && SOC_FAMILY_KINETIS) + select ETH_DSA_SUPPORT + help + Enable NXP ENET Ethernet driver. + +config ETH_MCUX + bool "MCUX Ethernet driver" + select NOCACHE_MEMORY if HAS_MCUX_CACHE && CPU_HAS_DCACHE + select ARM_MPU if CPU_CORTEX_M7 + select NET_POWER_MANAGEMENT if PM_DEVICE + select ETH_DSA_SUPPORT + select DEPRECATED + help + Enable deprecated legacy MCUX Ethernet driver. + Note, this driver performs one shot PHY setup. + There is no support for PHY disconnect, reconnect or configuration change. + +endchoice + +if ETH_NXP_ENET + +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_HW_ACCELERATION + bool "Hardware acceleration" + default y + help + Enable hardware acceleration for the following: + - IPv4, UDP and TCP checksum (both Rx and Tx) + +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. + +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_THREAD_PRIORITY + int "NXP ENET driver RX cooperative thread priority" + default 2 + help + ENET MAC Driver handles RX in cooperative workqueue thread. + This options sets the priority of that thread. + +endif # ETH_NXP_ENET + +if ETH_MCUX + +config ETH_MCUX_PROMISCUOUS_MODE + bool "Promiscuous mode" + help + Place the Ethernet receiver in promiscuous mode. This may be useful + for debugging and not needed for normal work. + +config ETH_MCUX_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_MCUX_HW_ACCELERATION + bool "Hardware acceleration" + default y + help + Enable hardware acceleration for the following: + - IPv4, UDP and TCP checksum (both Rx and Tx) + +config ETH_MCUX_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_MCUX_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. + +menu "Legacy driver options" + +config ETH_MCUX_RMII_EXT_CLK + bool "RMII clock from external sources" + help + Setting this option will configure MCUX clock block to feed RMII + reference clock from external source (ENET_1588_CLKIN) + +config ETH_MCUX_NO_PHY_SMI + bool "Do not use SMI for PHY communication" + help + Some PHY devices, with DSA capabilities do not use SMI for + communication with MAC ENET controller. Other busses - like SPI + or I2C are used instead. + +config ETH_MCUX_PHY_TICK_MS + int "PHY poll period (ms)" + default 1000 + range 100 30000 + help + Set the PHY status polling period. + +config ETH_MCUX_PHY_EXTRA_DEBUG + bool "Additional detailed PHY debug" + help + Enable additional PHY related debug information related to + PHY status polling. + +config ETH_MCUX_PHY_RESET + bool "Reset the PHY at boot" + help + Reset the ethernet PHY at boot. Requires dts properties int-gpios and + reset-gpios to be present. + +config PTP_CLOCK_MCUX + bool "MCUX PTP clock driver support" + default y + depends on PTP_CLOCK || NET_L2_PTP + help + Enable MCUX PTP clock support. + +if PTP_CLOCK_MCUX + +config ETH_MCUX_PTP_CLOCK_SRC_HZ + int "Frequency of the clock source for the PTP timer" + default 50000000 if SOC_SERIES_KINETIS_K6X + default 50000000 if SOC_SERIES_IMXRT10XX + default 24000000 if SOC_SERIES_IMXRT11XX + help + Set the frequency in Hz sourced to the PTP timer. + If the value is set properly, the timer will be accurate. + +config ETH_MCUX_PTP_CLOCK_INIT_PRIO + int + default 85 + help + MCUX PTP Clock initialization priority level. There is + a dependency from the network stack that this device + initializes before network stack (NET_INIT_PRIO). + +endif # PTP_CLOCK_MCUX + +endmenu # Legacy options + +endif # ETH_MCUX + +endmenu # NXP ENET diff --git a/drivers/ethernet/eth_mcux.c b/drivers/ethernet/nxp_enet/eth_mcux.c similarity index 99% rename from drivers/ethernet/eth_mcux.c rename to drivers/ethernet/nxp_enet/eth_mcux.c index 441c7bcdfc4..2ac0296d6b2 100644 --- a/drivers/ethernet/eth_mcux.c +++ b/drivers/ethernet/nxp_enet/eth_mcux.c @@ -56,7 +56,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #include #endif -#include "eth.h" +#include "../eth.h" #define PHY_OMS_OVERRIDE_REG 0x16U /* The PHY Operation Mode Strap Override register. */ #define PHY_OMS_STATUS_REG 0x17U /* The PHY Operation Mode Strap Status register. */ diff --git a/drivers/ethernet/eth_nxp_enet.c b/drivers/ethernet/nxp_enet/eth_nxp_enet.c similarity index 81% rename from drivers/ethernet/eth_nxp_enet.c rename to drivers/ethernet/nxp_enet/eth_nxp_enet.c index 6659c4f92a5..befa92b91ae 100644 --- a/drivers/ethernet/eth_nxp_enet.c +++ b/drivers/ethernet/nxp_enet/eth_nxp_enet.c @@ -1,8 +1,8 @@ /* NXP ENET MAC Driver * - * Copyright 2023 NXP + * Copyright 2023-2024 NXP * - * Inspiration from eth_mcux.c, which is: + * Inspiration from eth_mcux.c, which was: * Copyright (c) 2016-2017 ARM Ltd * Copyright (c) 2016 Linaro Ltd * Copyright (c) 2018 Intel Corporation @@ -19,52 +19,62 @@ #include LOG_MODULE_REGISTER(LOG_MODULE_NAME); -/* - ************ - * Includes * - ************ - */ - #include #include #include #include +#include + #include #include #include +#include +#include #include + #include #include -#include -#include -#include -#include + +#ifdef CONFIG_PTP_CLOCK #include -#if defined(CONFIG_NET_DSA) +#endif + +#ifdef CONFIG_NET_DSA #include #endif -#include "fsl_enet.h" +#if defined(CONFIG_NET_POWER_MANAGEMENT) && defined(CONFIG_PM_DEVICE) +#include +#endif -/* - *********** - * Defines * - *********** - */ +#include "../eth.h" +#include +#include +#include -#define RING_ID 0 +#define FREESCALE_OUI_B0 0x00 +#define FREESCALE_OUI_B1 0x04 +#define FREESCALE_OUI_B2 0x9f -/* - ********************* - * Driver Structures * - ********************* - */ +#if defined(CONFIG_SOC_SERIES_IMXRT10XX) +#define ETH_NXP_ENET_UNIQUE_ID (OCOTP->CFG1 ^ OCOTP->CFG2) +#elif defined(CONFIG_SOC_SERIES_IMXRT11XX) +#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 +#define ETH_NXP_ENET_UNIQUE_ID 0xFFFFFF +#error "Unsupported SOC" +#endif + +#define RING_ID 0 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); + bool generate_mac; + bool unique_mac; const struct pinctrl_dev_config *pincfg; enet_buffer_config_t buffer_config; uint8_t phy_mode; @@ -81,10 +91,8 @@ struct nxp_enet_mac_data { 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_work rx_work; + const struct device *dev; struct k_sem rx_thread_sem; struct k_mutex tx_frame_buf_mutex; struct k_mutex rx_frame_buf_mutex; @@ -92,30 +100,27 @@ struct nxp_enet_mac_data { 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 */ + uint8_t *tx_frame_buf; + uint8_t *rx_frame_buf; }; -/* - ******************** - * Helper Functions * - ******************** - */ +static K_THREAD_STACK_DEFINE(enet_rx_stack, CONFIG_ETH_NXP_ENET_RX_THREAD_STACK_SIZE); +static struct k_work_q rx_work_queue; + +static int rx_queue_init(void) +{ + struct k_work_queue_config cfg = {.name = "ENET_RX"}; + + k_work_queue_init(&rx_work_queue); + k_work_queue_start(&rx_work_queue, enet_rx_stack, + K_THREAD_STACK_SIZEOF(enet_rx_stack), + K_PRIO_COOP(CONFIG_ETH_NXP_ENET_RX_THREAD_PRIORITY), + &cfg); + + return 0; +} + +SYS_INIT(rx_queue_init, POST_KERNEL, 0); static inline struct net_if *get_iface(struct nxp_enet_mac_data *data) { @@ -187,12 +192,6 @@ static const struct device *eth_nxp_enet_get_ptp_clock(const struct device *dev) } #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; @@ -207,7 +206,6 @@ static int eth_nxp_enet_tx(const struct device *dev, struct net_pkt *pkt) /* 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); @@ -321,12 +319,6 @@ static int eth_nxp_enet_set_config(const struct device *dev, return -ENOTSUP; } -/* - ***************************** - * Ethernet RX Functionality * - ***************************** - */ - static int eth_nxp_enet_rx(const struct device *dev) { const struct nxp_enet_mac_config *config = dev->config; @@ -429,29 +421,24 @@ static int eth_nxp_enet_rx(const struct device *dev) return -EIO; } -static void eth_nxp_enet_rx_thread(void *arg1, void *unused1, void *unused2) +static void eth_nxp_enet_rx_thread(struct k_work *work) { - const struct device *dev = arg1; + struct nxp_enet_mac_data *data = + CONTAINER_OF(work, struct nxp_enet_mac_data, rx_work); + const struct device *dev = data->dev; const struct nxp_enet_mac_config *config = dev->config; - struct nxp_enet_mac_data *data = dev->data; + int ret; - 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); - } + if (k_sem_take(&data->rx_thread_sem, K_FOREVER)) { + return; } -} -/* - **************************** - * PHY management functions * - **************************** - */ + do { + ret = eth_nxp_enet_rx(dev); + } while (ret == 1); + + ENET_EnableInterrupts(config->base, kENET_RxFrameInterrupt); +} static int nxp_enet_phy_reset_and_configure(const struct device *phy) { @@ -511,12 +498,6 @@ static int nxp_enet_phy_init(const struct device *dev) 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) { @@ -543,22 +524,13 @@ static void eth_callback(ENET_Type *base, enet_handle_t *handle, 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. */ + default: break; } } @@ -577,21 +549,16 @@ static void eth_nxp_enet_isr(const struct device *dev) uint32_t eir = ENET_GetInterruptStatus(config->base); - if (eir & (kENET_RxBufferInterrupt | kENET_RxFrameInterrupt)) { + if (eir & (kENET_RxFrameInterrupt)) { ENET_ReceiveIRQHandler(ENET_IRQ_HANDLER_ARGS(config->base, &data->enet_handle)); - ENET_DisableInterrupts(config->base, - kENET_RxFrameInterrupt | kENET_RxBufferInterrupt); + ENET_DisableInterrupts(config->base, kENET_RxFrameInterrupt); + k_work_submit_to_queue(&rx_work_queue, &data->rx_work); } 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); } @@ -599,11 +566,17 @@ static void eth_nxp_enet_isr(const struct device *dev) irq_unlock(irq_lock_key); } -/* - ****************** - * Initialization * - ****************** - */ +static inline void nxp_enet_unique_mac(uint8_t *mac_addr) +{ + uint32_t id = ETH_NXP_ENET_UNIQUE_ID; + + mac_addr[0] = FREESCALE_OUI_B0; + mac_addr[1] = FREESCALE_OUI_B1; + mac_addr[2] = FREESCALE_OUI_B2; + mac_addr[3] = FIELD_GET(0xFF0000, id); + mac_addr[4] = FIELD_GET(0x00FF00, id); + mac_addr[5] = FIELD_GET(0x0000FF, id); +} static int eth_nxp_enet_init(const struct device *dev) { @@ -618,7 +591,6 @@ static int eth_nxp_enet_init(const struct device *dev) 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); @@ -627,27 +599,23 @@ static int eth_nxp_enet_init(const struct device *dev) #if defined(CONFIG_PTP_CLOCK_NXP_ENET) k_sem_init(&data->ptp_ts_sem, 0, 1); #endif + k_work_init(&data->rx_work, eth_nxp_enet_rx_thread); - if (config->generate_mac) { - config->generate_mac(data->mac_addr); + if (config->unique_mac) { + nxp_enet_unique_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"); + if (config->generate_mac) { + gen_random_mac(data->mac_addr, + FREESCALE_OUI_B0, FREESCALE_OUI_B1, FREESCALE_OUI_B2); + } - /* 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)) { @@ -710,6 +678,50 @@ static int eth_nxp_enet_init(const struct device *dev) return 0; } +#if defined(CONFIG_NET_POWER_MANAGEMENT) +static int eth_nxp_enet_device_pm_action(const struct device *dev, enum pm_device_action action) +{ + const struct nxp_enet_mac_config *config = dev->config; + struct nxp_enet_mac_data *data = dev->data; + int ret; + + if (!device_is_ready(config->clock_dev)) { + return -ENODEV; + } + + if (action == PM_DEVICE_ACTION_SUSPEND) { + LOG_DBG("Suspending"); + + ret = net_if_suspend(data->iface); + if (ret) { + return ret; + } + + ENET_Reset(config->base); + ENET_Down(config->base); + clock_control_off(config->clock_dev, (clock_control_subsys_t)config->clock_subsys); + } else if (action == PM_DEVICE_ACTION_RESUME) { + LOG_DBG("Resuming"); + + clock_control_on(config->clock_dev, (clock_control_subsys_t)config->clock_subsys); + eth_nxp_enet_init(dev); + net_if_resume(data->iface); + } else { + return -ENOTSUP; + } + + return 0; +} + +#define ETH_NXP_ENET_PM_DEVICE_INIT(n) \ + PM_DEVICE_DT_INST_DEFINE(n, eth_nxp_enet_device_pm_action); +#define ETH_NXP_ENET_PM_DEVICE_GET(n) PM_DEVICE_DT_INST_GET(n) + +#else +#define ETH_NXP_ENET_PM_DEVICE_INIT(n) +#define ETH_NXP_ENET_PM_DEVICE_GET(n) NULL +#endif /* CONFIG_NET_POWER_MANAGEMENT */ + #ifdef CONFIG_NET_DSA #define NXP_ENET_SEND_FUNC dsa_tx #else @@ -736,71 +748,6 @@ static const struct ethernet_api api_funcs = { 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_IMXRT10XX) -#define ETH_NXP_ENET_UNIQUE_ID (OCOTP->CFG1 ^ OCOTP->CFG2) -#elif defined(CONFIG_SOC_SERIES_IMXRT11XX) -#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)) @@ -852,8 +799,14 @@ static const struct ethernet_api api_funcs = { .txFrameInfo = NULL #endif +#define NXP_ENET_NODE_HAS_MAC_ADDR_CHECK(n) \ + BUILD_ASSERT(NODE_HAS_VALID_MAC_ADDR(DT_DRV_INST(n)) || \ + DT_INST_PROP(n, zephyr_random_mac_address) || \ + DT_INST_PROP(n, nxp_unique_mac), \ + "MAC address not specified on ENET DT node"); + #define NXP_ENET_MAC_INIT(n) \ - NXP_ENET_GENERATE_MAC(n) \ + NXP_ENET_NODE_HAS_MAC_ADDR_CHECK(n) \ \ PINCTRL_DT_INST_DEFINE(n); \ \ @@ -909,7 +862,9 @@ static const struct ethernet_api api_funcs = { .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) \ + .generate_mac = DT_INST_PROP(n, \ + zephyr_random_mac_address), \ + .unique_mac = DT_INST_PROP(n, nxp_unique_mac), \ }; \ \ static _nxp_enet_driver_buffer_section uint8_t \ @@ -918,21 +873,22 @@ static const struct ethernet_api api_funcs = { 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, \ + .dev = DEVICE_DT_INST_GET(n), \ + .mac_addr = DT_INST_PROP_OR(n, local_mac_address, {0}), \ }; \ \ - ETH_NET_DEVICE_DT_INST_DEFINE(n, eth_nxp_enet_init, NULL, \ + ETH_NXP_ENET_PM_DEVICE_INIT(n) \ + \ + ETH_NET_DEVICE_DT_INST_DEFINE(n, eth_nxp_enet_init, \ + ETH_NXP_ENET_PM_DEVICE_GET(n), \ &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 diff --git a/drivers/ethernet/phy/Kconfig b/drivers/ethernet/phy/Kconfig index 26446974995..8ff32b8fee2 100644 --- a/drivers/ethernet/phy/Kconfig +++ b/drivers/ethernet/phy/Kconfig @@ -36,9 +36,7 @@ config PHY_GENERIC_MII config PHY_ADIN2111 bool "ADIN2111 PHY driver" default y - depends on DT_HAS_ADI_ADIN2111_PHY_ENABLED - depends on ETH_ADIN2111 - depends on MDIO_ADIN2111 + depends on DT_HAS_ADI_ADIN2111_PHY_ENABLED || DT_HAS_ADI_ADIN1100_PHY_ENABLED help Enable ADIN2111 PHY driver. diff --git a/drivers/ethernet/phy/phy_adin2111.c b/drivers/ethernet/phy/phy_adin2111.c index eb90eddd013..380def0ebe7 100644 --- a/drivers/ethernet/phy/phy_adin2111.c +++ b/drivers/ethernet/phy/phy_adin2111.c @@ -6,9 +6,14 @@ */ #include -LOG_MODULE_REGISTER(phy_adin2111, CONFIG_PHY_LOG_LEVEL); +#if DT_NODE_HAS_STATUS(DT_INST(0, adi_adin2111_phy), okay) #define DT_DRV_COMPAT adi_adin2111_phy +#else +#define DT_DRV_COMPAT adi_adin1100_phy +#endif + +LOG_MODULE_REGISTER(DT_DRV_COMPAT, CONFIG_PHY_LOG_LEVEL); #include #include @@ -23,20 +28,28 @@ LOG_MODULE_REGISTER(phy_adin2111, CONFIG_PHY_LOG_LEVEL); /* PHYs out of reset check retry delay */ #define ADIN2111_PHY_AWAIT_DELAY_POLL_US 15U -/* Number of retries for PHYs out of reset check */ -#define ADIN2111_PHY_AWAIT_RETRY_COUNT 200U +/* + * Number of retries for PHYs out of reset check, + * rmii variants as ADIN11XX need 70ms maximum after hw reset to be up, + * so the increasing the count for that, as default 25ms (sw reset) + 45. + */ +#define ADIN2111_PHY_AWAIT_RETRY_COUNT 3000U /* PHY's software powerdown check retry delay */ #define ADIN2111_PHY_SFT_PD_DELAY_POLL_US 15U /* Number of retries for PHY's software powerdown check */ #define ADIN2111_PHY_SFT_PD_RETRY_COUNT 200U +/* Software reset, CLK_25 disabled time*/ +#define ADIN1100_PHY_SFT_RESET_MS 25U + /* PHYs autonegotiation complete timeout */ #define ADIN2111_AN_COMPLETE_AWAIT_TIMEOUT_MS 3000U /* ADIN2111 PHY identifier */ #define ADIN2111_PHY_ID 0x0283BCA1U #define ADIN1110_PHY_ID 0x0283BC91U +#define ADIN1100_PHY_ID 0x0283BC81U /* System Interrupt Mask Register */ #define ADIN2111_PHY_CRSM_IRQ_MASK 0x0020U @@ -77,17 +90,26 @@ LOG_MODULE_REGISTER(phy_adin2111, CONFIG_PHY_LOG_LEVEL); /* LED 0 Enable */ #define ADIN2111_PHY_LED_CNTRL_LED0_EN BIT(7) +/* MMD bridge regs */ +#define ADIN1100_MMD_ACCESS_CNTRL 0x0DU +#define ADIN1100_MMD_ACCESS 0x0EU + struct phy_adin2111_config { const struct device *mdio; uint8_t phy_addr; bool led0_en; bool led1_en; bool tx_24v; + bool mii; }; struct phy_adin2111_data { + const struct device *dev; struct phy_link_state state; struct k_sem sem; + struct k_work_delayable monitor_work; + phy_callback_t cb; + void *cb_data; }; static inline int phy_adin2111_c22_read(const struct device *dev, uint16_t reg, @@ -106,22 +128,62 @@ static inline int phy_adin2111_c22_write(const struct device *dev, uint16_t reg, return mdio_write(cfg->mdio, cfg->phy_addr, reg, val); } -static inline int phy_adin2111_c45_write(const struct device *dev, uint16_t devad, - uint16_t reg, uint16_t val) +static int phy_adin2111_c45_setup_dev_reg(const struct device *dev, uint16_t devad, + uint16_t reg) { const struct phy_adin2111_config *cfg = dev->config; + int rval; - return mdio_write_c45(cfg->mdio, cfg->phy_addr, devad, reg, val); + rval = mdio_write(cfg->mdio, cfg->phy_addr, ADIN1100_MMD_ACCESS_CNTRL, devad); + if (rval < 0) { + return rval; + } + rval = mdio_write(cfg->mdio, cfg->phy_addr, ADIN1100_MMD_ACCESS, reg); + if (rval < 0) { + return rval; + } + + return mdio_write(cfg->mdio, cfg->phy_addr, ADIN1100_MMD_ACCESS_CNTRL, devad | BIT(14)); } -static inline int phy_adin2111_c45_read(const struct device *dev, uint16_t devad, - uint16_t reg, uint16_t *val) +static int phy_adin2111_c45_read(const struct device *dev, uint16_t devad, + uint16_t reg, uint16_t *val) { const struct phy_adin2111_config *cfg = dev->config; + int rval; + + if (cfg->mii) { + /* Using C22 -> devad bridge */ + rval = phy_adin2111_c45_setup_dev_reg(dev, devad, reg); + if (rval < 0) { + return rval; + } + + return mdio_read(cfg->mdio, cfg->phy_addr, ADIN1100_MMD_ACCESS, val); + } return mdio_read_c45(cfg->mdio, cfg->phy_addr, devad, reg, val); } +static int phy_adin2111_c45_write(const struct device *dev, uint16_t devad, + uint16_t reg, uint16_t val) +{ + const struct phy_adin2111_config *cfg = dev->config; + int rval; + + if (cfg->mii) { + /* Using C22 -> devad bridge */ + rval = phy_adin2111_c45_setup_dev_reg(dev, devad, reg); + if (rval < 0) { + return rval; + } + + return mdio_write(cfg->mdio, cfg->phy_addr, ADIN1100_MMD_ACCESS, val); + } + + return mdio_write_c45(cfg->mdio, cfg->phy_addr, devad, reg, val); +} + static int phy_adin2111_reg_read(const struct device *dev, uint16_t reg_addr, uint32_t *data) { @@ -304,6 +366,84 @@ static int phy_adin2111_cfg_link(const struct device *dev, return -ENOTSUP; } +static int phy_adin2111_reset(const struct device *dev) +{ + int ret; + + ret = phy_adin2111_c22_write(dev, MII_BMCR, MII_BMCR_RESET); + if (ret < 0) { + return ret; + } + + k_msleep(ADIN1100_PHY_SFT_RESET_MS); + + return 0; +} + +static void invoke_link_cb(const struct device *dev) +{ + struct phy_adin2111_data *const data = dev->data; + struct phy_link_state state; + + if (data->cb == NULL) { + return; + } + + data->cb(dev, &state, data->cb_data); +} + +static int update_link_state(const struct device *dev) +{ + struct phy_adin2111_data *const data = dev->data; + const struct phy_adin2111_config *config = dev->config; + struct phy_link_state old_state; + uint16_t bmsr; + int ret; + + ret = phy_adin2111_c22_read(dev, MII_BMSR, &bmsr); + if (ret < 0) { + return ret; + } + + old_state = data->state; + data->state.is_up = !!(bmsr & MII_BMSR_LINK_STATUS); + + if (old_state.speed != data->state.speed || old_state.is_up != data->state.is_up) { + + LOG_INF("PHY (%d) Link is %s", config->phy_addr, data->state.is_up ? "up" : "down"); + + if (data->state.is_up == false) { + return 0; + } + + invoke_link_cb(dev); + + LOG_INF("PHY (%d) Link speed %s Mb, %s duplex\n", config->phy_addr, + (PHY_LINK_IS_SPEED_100M(data->state.speed) ? "100" : "10"), + PHY_LINK_IS_FULL_DUPLEX(data->state.speed) ? "full" : "half"); + } + + return 0; +} + +static void monitor_work_handler(struct k_work *work) +{ + struct k_work_delayable *dwork = k_work_delayable_from_work(work); + struct phy_adin2111_data *const data = + CONTAINER_OF(dwork, struct phy_adin2111_data, monitor_work); + const struct device *dev = data->dev; + int rc; + + k_sem_take(&data->sem, K_FOREVER); + + rc = update_link_state(dev); + + k_sem_give(&data->sem); + + /* Submit delayed work */ + k_work_reschedule(&data->monitor_work, K_MSEC(CONFIG_PHY_MONITOR_PERIOD)); +} + static int phy_adin2111_init(const struct device *dev) { const struct phy_adin2111_config *const cfg = dev->config; @@ -313,9 +453,21 @@ static int phy_adin2111_init(const struct device *dev) bool tx_24v_supported = false; int ret; + data->dev = dev; data->state.is_up = false; data->state.speed = LINK_FULL_10BASE_T; + /* + * For adin1100 and further mii stuff, + * reset may not be performed from the mac layer, doing a clean reset here. + */ + if (cfg->mii) { + ret = phy_adin2111_reset(dev); + if (ret < 0) { + return ret; + } + } + ret = phy_adin2111_await_phy(dev); if (ret < 0) { LOG_ERR("PHY %u didn't come out of reset, %d", @@ -330,7 +482,7 @@ static int phy_adin2111_init(const struct device *dev) return -ENODEV; } - if (phy_id != ADIN2111_PHY_ID && phy_id != ADIN1110_PHY_ID) { + if (phy_id != ADIN2111_PHY_ID && phy_id != ADIN1110_PHY_ID && phy_id != ADIN1100_PHY_ID) { LOG_ERR("PHY %u unexpected PHY ID %X", cfg->phy_addr, phy_id); return -EINVAL; } @@ -447,6 +599,11 @@ static int phy_adin2111_init(const struct device *dev) return ret; } + if (cfg->mii) { + k_work_init_delayable(&data->monitor_work, monitor_work_handler); + monitor_work_handler(&data->monitor_work.work); + } + /** * done, PHY is in software powerdown (SFT PD) * exit software powerdown, PHY 1 has to exit before PHY 2 @@ -458,10 +615,17 @@ static int phy_adin2111_init(const struct device *dev) static int phy_adin2111_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; + struct phy_adin2111_data *const data = dev->data; + + data->cb = cb; + data->cb_data = user_data; + + /* Invoke the callback to notify the caller of the current + * link status. + */ + invoke_link_cb(dev); + + return 0; } static const struct ethphy_driver_api phy_adin2111_api = { @@ -479,6 +643,8 @@ static const struct ethphy_driver_api phy_adin2111_api = { .led0_en = DT_INST_PROP(n, led0_en), \ .led1_en = DT_INST_PROP(n, led1_en), \ .tx_24v = !(DT_INST_PROP(n, disable_tx_mode_24v)), \ + IF_ENABLED(DT_HAS_COMPAT_STATUS_OKAY(adi_adin1100_phy), \ + (.mii = 1)) \ }; \ static struct phy_adin2111_data phy_adin2111_data_##n = { \ .sem = Z_SEM_INITIALIZER(phy_adin2111_data_##n.sem, 1, 1), \ diff --git a/drivers/ethernet/phy/phy_microchip_ksz8081.c b/drivers/ethernet/phy/phy_microchip_ksz8081.c index 10d7f78172c..5eaf269f2b7 100644 --- a/drivers/ethernet/phy/phy_microchip_ksz8081.c +++ b/drivers/ethernet/phy/phy_microchip_ksz8081.c @@ -1,5 +1,5 @@ /* - * Copyright 2023 NXP + * Copyright 2023-2024 NXP * * Inspiration from phy_mii.c, which is: * Copyright (c) 2021 IP-Logix Inc. @@ -65,6 +65,9 @@ static int phy_mc_ksz8081_read(const struct device *dev, const struct mc_ksz8081_config *config = dev->config; int ret; + /* Make sure excessive bits 16-31 are reset */ + *data = 0U; + ret = mdio_read(config->mdio_dev, config->addr, reg_addr, (uint16_t *)data); if (ret) { return ret; @@ -117,7 +120,10 @@ static int phy_mc_ksz8081_autonegotiate(const struct device *dev) do { if (timeout-- == 0) { LOG_DBG("PHY (%d) autonegotiation timed out", config->addr); - return -ETIMEDOUT; + /* The value -ETIMEDOUT can be returned by PHY read/write functions, so + * return -ENETDOWN instead to distinguish link timeout from PHY timeout. + */ + return -ENETDOWN; } k_msleep(100); @@ -161,6 +167,7 @@ static int phy_mc_ksz8081_get_link(const struct device *dev, state->is_up = bmsr & MII_BMSR_LINK_STATUS; if (!state->is_up) { + k_mutex_unlock(&data->mutex); goto result; } @@ -200,9 +207,11 @@ static int phy_mc_ksz8081_get_link(const struct device *dev, 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"); + if (state->is_up) { + 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; @@ -254,11 +263,59 @@ static int phy_mc_ksz8081_static_cfg(const struct device *dev) return 0; } +static int phy_mc_ksz8081_reset(const struct device *dev) +{ +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(mc_reset_gpio) + const struct mc_ksz8081_config *config = dev->config; +#endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(mc_reset_gpio) */ + struct mc_ksz8081_data *data = dev->data; + int ret; + + /* Lock mutex */ + ret = k_mutex_lock(&data->mutex, K_FOREVER); + if (ret) { + LOG_ERR("PHY mutex lock error"); + return ret; + } + +#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_set_dt(&config->reset_gpio, 0); + if (ret) { + goto done; + } + + /* 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); + goto done; +skip_reset_gpio: +#endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(mc_reset_gpio) */ + ret = phy_mc_ksz8081_write(dev, MII_BMCR, MII_BMCR_RESET); + if (ret) { + goto done; + } + /* Wait for 500 ms as specified by datasheet */ + k_busy_wait(USEC_PER_MSEC * 500); + +done: + /* Unlock mutex */ + k_mutex_unlock(&data->mutex); + return ret; +} + 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; + struct phy_link_state state = {}; int ret; uint32_t anar; @@ -272,6 +329,12 @@ static int phy_mc_ksz8081_cfg_link(const struct device *dev, /* We are going to reconfigure the phy, don't need to monitor until done */ k_work_cancel_delayable(&data->phy_monitor_work); + /* Reset PHY */ + ret = phy_mc_ksz8081_reset(dev); + if (ret) { + goto done; + } + /* DT configurations */ ret = phy_mc_ksz8081_static_cfg(dev); if (ret) { @@ -316,19 +379,28 @@ static int phy_mc_ksz8081_cfg_link(const struct device *dev, /* (re)do autonegotiation */ ret = phy_mc_ksz8081_autonegotiate(dev); - if (ret) { + if (ret && (ret != -ENETDOWN)) { LOG_ERR("Error in autonegotiation"); goto done; } /* Get link status */ - ret = phy_mc_ksz8081_get_link(dev, &data->state); + ret = phy_mc_ksz8081_get_link(dev, &state); + + if (ret == 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); + } + } /* 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"); + if (data->state.is_up) { + 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 */ @@ -362,7 +434,7 @@ static void phy_mc_ksz8081_monitor_work_handler(struct k_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; + struct phy_link_state state = {}; int rc; rc = phy_mc_ksz8081_get_link(dev, &state); @@ -407,30 +479,21 @@ static int phy_mc_ksz8081_init(const struct device *dev) 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; + if (config->reset_gpio.port) { + ret = gpio_pin_configure_dt(&config->reset_gpio, GPIO_OUTPUT_ACTIVE); + if (ret) { + return ret; + } } +#endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(mc_reset_gpio) */ - /* 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); + /* Reset PHY */ + ret = phy_mc_ksz8081_reset(dev); 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); diff --git a/drivers/flash/CMakeLists.txt b/drivers/flash/CMakeLists.txt index ac7564c4708..54b9178c091 100644 --- a/drivers/flash/CMakeLists.txt +++ b/drivers/flash/CMakeLists.txt @@ -42,6 +42,7 @@ zephyr_library_sources_ifdef(CONFIG_FLASH_NPCX_FIU_QSPI flash_npcx_fiu_qspi.c) zephyr_library_sources_ifdef(CONFIG_FLASH_NPCX_FIU_NOR flash_npcx_fiu_nor.c) zephyr_library_sources_ifdef(CONFIG_FLASH_STM32_QSPI flash_stm32_qspi.c) zephyr_library_sources_ifdef(CONFIG_FLASH_STM32_OSPI flash_stm32_ospi.c) +zephyr_library_sources_ifdef(CONFIG_FLASH_STM32_XSPI flash_stm32_xspi.c) zephyr_library_sources_ifdef(CONFIG_FLASH_MCUX_FLEXSPI_MX25UM51345G flash_mcux_flexspi_mx25um51345g.c) zephyr_library_sources_ifdef(CONFIG_FLASH_MCUX_FLEXSPI_NOR flash_mcux_flexspi_nor.c) zephyr_library_sources_ifdef(CONFIG_FLASH_MCUX_FLEXSPI_HYPERFLASH flash_mcux_flexspi_hyperflash.c) diff --git a/drivers/flash/Kconfig b/drivers/flash/Kconfig index 6a1f816aa55..441a7986878 100644 --- a/drivers/flash/Kconfig +++ b/drivers/flash/Kconfig @@ -132,6 +132,8 @@ source "drivers/flash/Kconfig.stm32_qspi" source "drivers/flash/Kconfig.stm32_ospi" +source "drivers/flash/Kconfig.stm32_xspi" + source "drivers/flash/Kconfig.sam0" source "drivers/flash/Kconfig.sam" diff --git a/drivers/flash/Kconfig.ambiq b/drivers/flash/Kconfig.ambiq index cc84c0faf39..5ce028bba96 100644 --- a/drivers/flash/Kconfig.ambiq +++ b/drivers/flash/Kconfig.ambiq @@ -2,11 +2,12 @@ # SPDX-License-Identifier: Apache-2.0 config FLASH_AMBIQ - bool "Ambiq flash driver on MRAM" + bool "Ambiq flash driver on MRAM or flash" 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. + Enables Ambiq flash driver on MRAM (e.g. Apollo4x) or + flash (e.g. Apollo3x). diff --git a/drivers/flash/Kconfig.nordic_qspi_nor b/drivers/flash/Kconfig.nordic_qspi_nor index ff652f60822..4acce558567 100644 --- a/drivers/flash/Kconfig.nordic_qspi_nor +++ b/drivers/flash/Kconfig.nordic_qspi_nor @@ -6,6 +6,7 @@ menuconfig NORDIC_QSPI_NOR default y depends on DT_HAS_NORDIC_QSPI_NOR_ENABLED select FLASH_HAS_DRIVER_ENABLED + select FLASH_HAS_PAGE_LAYOUT select NRFX_QSPI select FLASH_JESD216 select PINCTRL diff --git a/drivers/flash/Kconfig.nrf_rram b/drivers/flash/Kconfig.nrf_rram index 68efde1ab30..a729b57bc28 100644 --- a/drivers/flash/Kconfig.nrf_rram +++ b/drivers/flash/Kconfig.nrf_rram @@ -8,6 +8,7 @@ menuconfig SOC_FLASH_NRF_RRAM bool "Nordic Semiconductor flash driver for nRF RRAM" default y depends on DT_HAS_NORDIC_RRAM_CONTROLLER_ENABLED + select NRFX_RRAMC select FLASH_HAS_DRIVER_ENABLED select FLASH_HAS_PAGE_LAYOUT select FLASH_NRF_FORCE_ALT @@ -66,4 +67,17 @@ config SOC_FLASH_NRF_TIMEOUT_MULTIPLIER the multiplication would allow erasing all nRF flash pages in blocking mode. +config NRF_RRAM_REGION_ADDRESS_RESOLUTION + hex + default 0x400 + help + RRAMC's region protection address resolution. + Applies to region with configurable start address. + +config NRF_RRAM_REGION_SIZE_UNIT + hex + default 0x400 + help + Base unit for the size of RRAMC's region protection. + endif # SOC_FLASH_NRF_RRAM diff --git a/drivers/flash/Kconfig.simulator b/drivers/flash/Kconfig.simulator index b9f432a298f..e32a2a72bb0 100644 --- a/drivers/flash/Kconfig.simulator +++ b/drivers/flash/Kconfig.simulator @@ -26,7 +26,8 @@ config FLASH_SIMULATOR_DOUBLE_WRITES bool "Allow program units to be programmed more than once" help If selected, writing to a non-erased program unit will succeed, otherwise, it will return an error. - Keep in mind that write operations can only pull bits to zero, regardless. + Keep in mind that write operations can only change value of a bit from erase-value to the + opposite. config FLASH_SIMULATOR_SIMULATE_TIMING bool "Hardware timing simulation" diff --git a/drivers/flash/Kconfig.stm32 b/drivers/flash/Kconfig.stm32 index 1ba8c33a7ec..72481c5ae6e 100644 --- a/drivers/flash/Kconfig.stm32 +++ b/drivers/flash/Kconfig.stm32 @@ -64,6 +64,7 @@ config FLASH_STM32_READOUT_PROTECTION_PERMANENT_ALLOW config FLASH_STM32_BLOCK_REGISTERS bool "Extended operation for blocking option and control registers" + select FLASH_HAS_EX_OP default n help Enables flash extended operations that can be used to disable access @@ -71,4 +72,11 @@ config FLASH_STM32_BLOCK_REGISTERS registers improves system security, because flash content (or protection settings) can't be changed even when exploit was found. +config STM32_MEMMAP + bool "NOR Flash in MemoryMapped for XiP" + depends on XIP + help + This option enables the XIP mode for the external NOR flash + mounted on STM32 boards. + endif # SOC_FLASH_STM32 diff --git a/drivers/flash/Kconfig.stm32_xspi b/drivers/flash/Kconfig.stm32_xspi new file mode 100644 index 00000000000..3bea03801f3 --- /dev/null +++ b/drivers/flash/Kconfig.stm32_xspi @@ -0,0 +1,18 @@ +# STM32 xSPI flash driver configuration options + +# Copyright (c) 2024 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +config FLASH_STM32_XSPI + bool "STM32 XSPI Flash driver" + default y + depends on DT_HAS_ST_STM32_XSPI_ENABLED && DT_HAS_ST_STM32_XSPI_NOR_ENABLED + select USE_STM32_HAL_XSPI + select USE_STM32_LL_DLYB + select FLASH_HAS_DRIVER_ENABLED + select FLASH_JESD216 + select FLASH_PAGE_LAYOUT + select FLASH_HAS_PAGE_LAYOUT + + help + Enable XSPI-NOR support on the STM32 family of processors. diff --git a/drivers/flash/flash_ambiq.c b/drivers/flash/flash_ambiq.c index fdc852c04ca..30ce8524045 100644 --- a/drivers/flash/flash_ambiq.c +++ b/drivers/flash/flash_ambiq.c @@ -15,15 +15,19 @@ 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 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) +#if (CONFIG_SOC_SERIES_APOLLO4X) +#define MIN_WRITE_SIZE 16 +#else +#define MIN_WRITE_SIZE 4 +#endif /* CONFIG_SOC_SERIES_APOLLO4X */ #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!"); + "The flash write block size must be a multiple of MIN_WRITE_SIZE!"); #define FLASH_ERASE_BYTE 0xFF #define FLASH_ERASE_WORD \ @@ -77,7 +81,7 @@ static int flash_ambiq_write(const struct device *dev, off_t offset, const void ARG_UNUSED(dev); int ret = 0; - uint32_t critical = 0; + unsigned int key = 0; uint32_t aligned[FLASH_WRITE_BLOCK_SIZE / sizeof(uint32_t)] = {0}; uint32_t *src = (uint32_t *)data; @@ -96,22 +100,31 @@ static int flash_ambiq_write(const struct device *dev, off_t offset, const void FLASH_SEM_TAKE(); - critical = am_hal_interrupt_master_disable(); + key = irq_lock(); + 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++; } +#if (CONFIG_SOC_SERIES_APOLLO4X) 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)); +#elif (CONFIG_SOC_SERIES_APOLLO3X) + ret = am_hal_flash_program_main( + AM_HAL_FLASH_PROGRAM_KEY, aligned, + (uint32_t *)(SOC_NV_FLASH_ADDR + offset + i * FLASH_WRITE_BLOCK_SIZE), + FLASH_WRITE_BLOCK_SIZE / sizeof(uint32_t)); +#endif /* CONFIG_SOC_SERIES_APOLLO4X */ if (ret) { break; } } - am_hal_interrupt_master_set(critical); + + irq_unlock(key); FLASH_SEM_GIVE(); @@ -128,17 +141,42 @@ static int flash_ambiq_erase(const struct device *dev, off_t offset, size_t len) return -EINVAL; } - /* The erase address and length alignment check will be done in HAL.*/ - if (len == 0) { return 0; } +#if (CONFIG_SOC_SERIES_APOLLO4X) + /* The erase address and length alignment check will be done in HAL.*/ +#elif (CONFIG_SOC_SERIES_APOLLO3X) + if ((offset % FLASH_ERASE_BLOCK_SIZE) != 0) { + LOG_ERR("offset 0x%lx is not on a page boundary", (long)offset); + return -EINVAL; + } + + if ((len % FLASH_ERASE_BLOCK_SIZE) != 0) { + LOG_ERR("len %zu is not multiple of a page size", len); + return -EINVAL; + } +#endif /* CONFIG_SOC_SERIES_APOLLO4X */ + FLASH_SEM_TAKE(); +#if (CONFIG_SOC_SERIES_APOLLO4X) 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))); +#elif (CONFIG_SOC_SERIES_APOLLO3X) + unsigned int key = 0; + + key = irq_lock(); + + ret = am_hal_flash_page_erase( + AM_HAL_FLASH_PROGRAM_KEY, + AM_HAL_FLASH_ADDR2INST(((uint32_t)SOC_NV_FLASH_ADDR + offset)), + AM_HAL_FLASH_ADDR2PAGE(((uint32_t)SOC_NV_FLASH_ADDR + offset))); + + irq_unlock(key); +#endif /* CONFIG_SOC_SERIES_APOLLO4X */ FLASH_SEM_GIVE(); diff --git a/drivers/flash/flash_andes_qspi.c b/drivers/flash/flash_andes_qspi.c index 6a3c0b72ca1..f8c7dfd96dd 100644 --- a/drivers/flash/flash_andes_qspi.c +++ b/drivers/flash/flash_andes_qspi.c @@ -548,10 +548,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; - ret = read_sfdp(dev, 0, u.raw, sizeof(u.raw)); + ret = read_sfdp(dev, 0, u_header.raw, sizeof(u_header.raw)); if (ret != 0) { LOG_ERR("SFDP read failed: %d", ret); return ret; @@ -582,11 +582,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; ret = read_sfdp(dev, - jesd216_param_addr(php), u.dw, sizeof(u.dw)); + jesd216_param_addr(php), u_param.dw, sizeof(u_param.dw)); if (ret != 0) { break; @@ -609,7 +609,7 @@ static int spi_nor_process_sfdp(const struct device *dev) .len_dw = config->bfp_len, }; - ret = spi_nor_process_bfp(dev, &bfp_hdr, cfg->bfp); + ret = spi_nor_process_bfp(dev, &bfp_hdr, config->bfp); #else #error Unhandled SFDP choice #endif @@ -825,10 +825,10 @@ static int flash_andes_qspi_init(const struct device *dev) #ifndef CONFIG_FLASH_ANDES_QSPI_SFDP_RUNTIME - if (memcmp(jedec_id, cfg->jedec_id, sizeof(jedec_id)) != 0) { + if (memcmp(jedec_id, config->jedec_id, sizeof(jedec_id)) != 0) { LOG_ERR("Device id %02x %02x %02x does not match config" "%02x %02x %02x", jedec_id[0], jedec_id[1], jedec_id[2], - cfg->jedec_id[0], cfg->jedec_id[1], cfg->jedec_id[2]); + config->jedec_id[0], config->jedec_id[1], config->jedec_id[2]); return -EINVAL; } #endif diff --git a/drivers/flash/flash_esp32.c b/drivers/flash/flash_esp32.c index 3ce3777d829..e6b3ef13edf 100644 --- a/drivers/flash/flash_esp32.c +++ b/drivers/flash/flash_esp32.c @@ -80,7 +80,11 @@ static int flash_esp32_read(const struct device *dev, off_t address, void *buffe ret = esp_flash_read_encrypted(NULL, address, buffer, length); } flash_esp32_sem_give(dev); - return ret; + if (ret != 0) { + LOG_ERR("esp_flash_read failed %d", ret); + return -EIO; + } + return 0; } static int flash_esp32_write(const struct device *dev, @@ -97,7 +101,12 @@ static int flash_esp32_write(const struct device *dev, ret = esp_flash_write_encrypted(NULL, address, buffer, length); } flash_esp32_sem_give(dev); - return ret; + + if (ret != 0) { + LOG_ERR("esp_flash_write failed %d", ret); + return -EIO; + } + return 0; } static int flash_esp32_erase(const struct device *dev, off_t start, size_t len) @@ -105,7 +114,11 @@ static int flash_esp32_erase(const struct device *dev, off_t start, size_t len) flash_esp32_sem_take(dev); int ret = esp_flash_erase_region(NULL, start, len); flash_esp32_sem_give(dev); - return ret; + if (ret != 0) { + LOG_ERR("esp_flash_erase_region failed %d", ret); + return -EIO; + } + return 0; } #if CONFIG_FLASH_PAGE_LAYOUT diff --git a/drivers/flash/flash_mcux_flexspi_nor.c b/drivers/flash/flash_mcux_flexspi_nor.c index bfcef6daebd..175e75554f2 100644 --- a/drivers/flash/flash_mcux_flexspi_nor.c +++ b/drivers/flash/flash_mcux_flexspi_nor.c @@ -52,8 +52,10 @@ enum { READ_STATUS_REG, ERASE_CHIP, READ_JESD216, + /* Entries after this should be for scratch commands */ + FLEXSPI_INSTR_PROG_END, /* Used for temporary commands during initialization */ - SCRATCH_CMD, + SCRATCH_CMD = FLEXSPI_INSTR_PROG_END, SCRATCH_CMD2, /* Must be last entry */ FLEXSPI_INSTR_END, @@ -718,22 +720,23 @@ static int flash_flexspi_nor_config_flash(struct flash_flexspi_nor_data *data, /* Check to see if we can enable 4 byte addressing */ ret = jesd216_bfp_decode_dw16(&header->phdr[0], bfp, &dw16); - if (ret < 0) { - return ret; - } - - /* Attempt to enable 4 byte addressing */ - ret = flash_flexspi_nor_4byte_enable(data, flexspi_lut, dw16.enter_4ba); if (ret == 0) { - /* Use 4 byte address width */ - addr_width = 32; - /* Update LUT for ERASE_SECTOR and ERASE_BLOCK to use 32 bit addr */ - flexspi_lut[ERASE_SECTOR][0] = FLEXSPI_LUT_SEQ( - kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_SE, - kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, addr_width); - flexspi_lut[ERASE_BLOCK][0] = FLEXSPI_LUT_SEQ( - kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_BE, - kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, addr_width); + /* Attempt to enable 4 byte addressing */ + ret = flash_flexspi_nor_4byte_enable(data, flexspi_lut, + dw16.enter_4ba); + if (ret == 0) { + /* Use 4 byte address width */ + addr_width = 32; + /* Update LUT for ERASE_SECTOR and ERASE_BLOCK to use 32 bit addr */ + flexspi_lut[ERASE_SECTOR][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, + SPI_NOR_CMD_SE, kFLEXSPI_Command_RADDR_SDR, + kFLEXSPI_1PAD, addr_width); + flexspi_lut[ERASE_BLOCK][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, + SPI_NOR_CMD_BE, kFLEXSPI_Command_RADDR_SDR, + kFLEXSPI_1PAD, addr_width); + } } /* Extract the read command. * Note- enhanced XIP not currently supported, nor is 4-4-4 mode. @@ -764,20 +767,21 @@ static int flash_flexspi_nor_config_flash(struct flash_flexspi_nor_data *data, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x0); /* Read 1S-4S-4S enable method */ ret = jesd216_bfp_decode_dw15(&header->phdr[0], bfp, &dw15); - if (ret < 0) { - return ret; - } - ret = flash_flexspi_nor_quad_enable(data, flexspi_lut, dw15.qer); - if (ret < 0) { - return ret; + if (ret == 0) { + ret = flash_flexspi_nor_quad_enable(data, flexspi_lut, + dw15.qer); + if (ret == 0) { + /* Now, install 1S-1S-4S page program command */ + flexspi_lut[PAGE_PROGRAM][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, + SPI_NOR_CMD_PP_1_1_4, kFLEXSPI_Command_RADDR_SDR, + kFLEXSPI_1PAD, addr_width); + flexspi_lut[PAGE_PROGRAM][1] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_4PAD, + 0x4, kFLEXSPI_Command_STOP, + kFLEXSPI_1PAD, 0x0); + } } - /* Now, install 1S-1S-4S page program command */ - flexspi_lut[PAGE_PROGRAM][0] = FLEXSPI_LUT_SEQ( - kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_PP_1_1_4, - kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, addr_width); - flexspi_lut[PAGE_PROGRAM][1] = FLEXSPI_LUT_SEQ( - kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_4PAD, 0x4, - kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x0); } else if (jesd216_bfp_read_support(&header->phdr[0], bfp, JESD216_MODE_122, &instr) > 0) { @@ -817,7 +821,8 @@ static int flash_flexspi_nor_config_flash(struct flash_flexspi_nor_data *data, /* Now, read DW14 to determine the polling method we should use while programming */ ret = jesd216_bfp_decode_dw14(&header->phdr[0], bfp, &dw14); if (ret < 0) { - return ret; + /* Default to legacy polling mode */ + dw14.poll_options = 0x0; } if (dw14.poll_options & BIT(1)) { /* Read instruction used for polling is 0x70 */ @@ -1014,7 +1019,7 @@ static int flash_flexspi_nor_probe(struct flash_flexspi_nor_data *data) */ ret = memc_flexspi_set_device_config(&data->controller, &data->config, (uint32_t *)flexspi_lut, - FLEXSPI_INSTR_END * MEMC_FLEXSPI_CMD_PER_SEQ, + FLEXSPI_INSTR_PROG_END * MEMC_FLEXSPI_CMD_PER_SEQ, data->port); if (ret < 0) { return ret; diff --git a/drivers/flash/flash_simulator.c b/drivers/flash/flash_simulator.c index ccbc28edfe4..12cd8607855 100644 --- a/drivers/flash/flash_simulator.c +++ b/drivers/flash/flash_simulator.c @@ -268,7 +268,7 @@ static int flash_sim_write(const struct device *dev, const off_t offset, #if FLASH_SIMULATOR_ERASE_VALUE == 0xFF *(MOCK_FLASH(offset + i)) &= *((uint8_t *)data + i); #else - *(MOCK_FLASH(offset + i)) = *((uint8_t *)data + i); + *(MOCK_FLASH(offset + i)) |= *((uint8_t *)data + i); #endif } diff --git a/drivers/flash/flash_stm32_ospi.c b/drivers/flash/flash_stm32_ospi.c index fa9df2937e7..e2a22fba6cf 100644 --- a/drivers/flash/flash_stm32_ospi.c +++ b/drivers/flash/flash_stm32_ospi.c @@ -36,6 +36,9 @@ LOG_MODULE_REGISTER(flash_stm32_ospi, CONFIG_FLASH_LOG_LEVEL); (_CONCAT(HAL_OSPIM_, DT_STRING_TOKEN(STM32_OSPI_NODE, prop))), \ ((default_value))) +#define DT_OSPI_PROP_OR(prop, default_value) \ + DT_PROP_OR(STM32_OSPI_NODE, prop, default_value) + /* Get the base address of the flash from the DTS node */ #define STM32_OSPI_BASE_ADDRESS DT_INST_REG_ADDR(0) @@ -2094,17 +2097,17 @@ static int flash_stm32_ospi_init(const struct device *dev) OSPIM_CfgTypeDef ospi_mgr_cfg = {0}; if (dev_data->hospi.Instance == OCTOSPI1) { - ospi_mgr_cfg.ClkPort = 1; - ospi_mgr_cfg.DQSPort = 1; - ospi_mgr_cfg.NCSPort = 1; + ospi_mgr_cfg.ClkPort = DT_OSPI_PROP_OR(clk_port, 1); + ospi_mgr_cfg.DQSPort = DT_OSPI_PROP_OR(dqs_port, 1); + ospi_mgr_cfg.NCSPort = DT_OSPI_PROP_OR(ncs_port, 1); ospi_mgr_cfg.IOLowPort = DT_OSPI_IO_PORT_PROP_OR(io_low_port, HAL_OSPIM_IOPORT_1_LOW); ospi_mgr_cfg.IOHighPort = DT_OSPI_IO_PORT_PROP_OR(io_high_port, HAL_OSPIM_IOPORT_1_HIGH); } else if (dev_data->hospi.Instance == OCTOSPI2) { - ospi_mgr_cfg.ClkPort = 2; - ospi_mgr_cfg.DQSPort = 2; - ospi_mgr_cfg.NCSPort = 2; + ospi_mgr_cfg.ClkPort = DT_OSPI_PROP_OR(clk_port, 2); + ospi_mgr_cfg.DQSPort = DT_OSPI_PROP_OR(dqs_port, 2); + ospi_mgr_cfg.NCSPort = DT_OSPI_PROP_OR(ncs_port, 2); ospi_mgr_cfg.IOLowPort = DT_OSPI_IO_PORT_PROP_OR(io_low_port, HAL_OSPIM_IOPORT_2_LOW); ospi_mgr_cfg.IOHighPort = DT_OSPI_IO_PORT_PROP_OR(io_high_port, diff --git a/drivers/flash/flash_stm32_qspi.c b/drivers/flash/flash_stm32_qspi.c index 326c1129a36..adec32e8e4e 100644 --- a/drivers/flash/flash_stm32_qspi.c +++ b/drivers/flash/flash_stm32_qspi.c @@ -12,8 +12,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -385,6 +387,66 @@ static bool qspi_address_is_valid(const struct device *dev, off_t addr, return (addr >= 0) && ((uint64_t)addr + (uint64_t)size <= flash_size); } +#ifdef CONFIG_STM32_MEMMAP +/* Must be called inside qspi_lock_thread(). */ +static int stm32_qspi_set_memory_mapped(const struct device *dev) +{ + int ret; + HAL_StatusTypeDef hal_ret; + struct flash_stm32_qspi_data *dev_data = dev->data; + + QSPI_CommandTypeDef cmd = { + .Instruction = SPI_NOR_CMD_READ, + .Address = 0, + .InstructionMode = QSPI_INSTRUCTION_1_LINE, + .AddressMode = QSPI_ADDRESS_1_LINE, + .DataMode = QSPI_DATA_1_LINE, + }; + + qspi_set_address_size(dev, &cmd); + if (IS_ENABLED(STM32_QSPI_USE_QUAD_IO)) { + ret = qspi_prepare_quad_read(dev, &cmd); + if (ret < 0) { + return ret; + } + } + + QSPI_MemoryMappedTypeDef mem_mapped = { + .TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE, + }; + + hal_ret = HAL_QSPI_MemoryMapped(&dev_data->hqspi, &cmd, &mem_mapped); + if (hal_ret != 0) { + LOG_ERR("%d: Failed to enable memory mapped", hal_ret); + return -EIO; + } + + LOG_DBG("MemoryMap mode enabled"); + return 0; +} + +static bool stm32_qspi_is_memory_mapped(const struct device *dev) +{ + struct flash_stm32_qspi_data *dev_data = dev->data; + + return READ_BIT(dev_data->hqspi.Instance->CCR, QUADSPI_CCR_FMODE) == QUADSPI_CCR_FMODE; +} + +static int stm32_qspi_abort(const struct device *dev) +{ + struct flash_stm32_qspi_data *dev_data = dev->data; + HAL_StatusTypeDef hal_ret; + + hal_ret = HAL_QSPI_Abort(&dev_data->hqspi); + if (hal_ret != HAL_OK) { + LOG_ERR("%d: QSPI abort failed", hal_ret); + return -EIO; + } + + return 0; +} +#endif + static int flash_stm32_qspi_read(const struct device *dev, off_t addr, void *data, size_t size) { @@ -401,6 +463,27 @@ static int flash_stm32_qspi_read(const struct device *dev, off_t addr, return 0; } +#ifdef CONFIG_STM32_MEMMAP + qspi_lock_thread(dev); + + /* Do reads through memory-mapping instead of indirect */ + if (!stm32_qspi_is_memory_mapped(dev)) { + ret = stm32_qspi_set_memory_mapped(dev); + if (ret != 0) { + LOG_ERR("READ: failed to set memory mapped"); + goto end; + } + } + + __ASSERT_NO_MSG(stm32_qspi_is_memory_mapped(dev)); + + uintptr_t mmap_addr = STM32_QSPI_BASE_ADDRESS + addr; + + LOG_DBG("Memory-mapped read from 0x%08lx, len %zu", mmap_addr, size); + memcpy(data, (void *)mmap_addr, size); + ret = 0; + goto end; +#else QSPI_CommandTypeDef cmd = { .Instruction = SPI_NOR_CMD_READ, .Address = addr, @@ -420,7 +503,10 @@ static int flash_stm32_qspi_read(const struct device *dev, off_t addr, qspi_lock_thread(dev); ret = qspi_read_access(dev, &cmd, data, size); + goto end; +#endif +end: qspi_unlock_thread(dev); return ret; @@ -482,6 +568,17 @@ static int flash_stm32_qspi_write(const struct device *dev, off_t addr, qspi_lock_thread(dev); +#ifdef CONFIG_STM32_MEMMAP + if (stm32_qspi_is_memory_mapped(dev)) { + /* Abort ongoing transfer to force CS high/BUSY deasserted */ + ret = stm32_qspi_abort(dev); + if (ret != 0) { + LOG_ERR("Failed to abort memory-mapped access before write"); + goto end; + } + } +#endif + while (size > 0) { size_t to_write = size; @@ -517,7 +614,9 @@ static int flash_stm32_qspi_write(const struct device *dev, off_t addr, break; } } + goto end; +end: qspi_unlock_thread(dev); return ret; @@ -555,6 +654,17 @@ static int flash_stm32_qspi_erase(const struct device *dev, off_t addr, qspi_set_address_size(dev, &cmd_erase); qspi_lock_thread(dev); +#ifdef CONFIG_STM32_MEMMAP + if (stm32_qspi_is_memory_mapped(dev)) { + /* Abort ongoing transfer to force CS high/BUSY deasserted */ + ret = stm32_qspi_abort(dev); + if (ret != 0) { + LOG_ERR("Failed to abort memory-mapped access before erase"); + goto end; + } + } +#endif + while ((size > 0) && (ret == 0)) { cmd_erase.Address = addr; qspi_send_cmd(dev, &cmd_write_en); @@ -596,7 +706,9 @@ static int flash_stm32_qspi_erase(const struct device *dev, off_t addr, } qspi_wait_until_ready(dev); } + goto end; +end: qspi_unlock_thread(dev); return ret; @@ -1283,7 +1395,12 @@ static int flash_stm32_qspi_init(const struct device *dev) HAL_QSPI_Init(&dev_data->hqspi); -#if DT_NODE_HAS_PROP(DT_NODELABEL(quadspi), flash_id) +#if DT_NODE_HAS_PROP(DT_NODELABEL(quadspi), flash_id) && \ + defined(QUADSPI_CR_FSEL) + /* + * Some stm32 mcu with quadspi (like stm32l47x or stm32l48x) + * does not support Dual-Flash Mode + */ uint8_t qspi_flash_id = DT_PROP(DT_NODELABEL(quadspi), flash_id); HAL_QSPI_SetFlashID(&dev_data->hqspi, @@ -1367,9 +1484,20 @@ static int flash_stm32_qspi_init(const struct device *dev) } #endif /* CONFIG_FLASH_PAGE_LAYOUT */ +#ifdef CONFIG_STM32_MEMMAP + ret = stm32_qspi_set_memory_mapped(dev); + if (ret != 0) { + LOG_ERR("Failed to enable memory-mapped mode: %d", ret); + return ret; + } + LOG_INF("Memory-mapped NOR quad-flash at 0x%lx (0x%x bytes)", + (long)(STM32_QSPI_BASE_ADDRESS), + dev_cfg->flash_size); +#else LOG_INF("NOR quad-flash at 0x%lx (0x%x bytes)", (long)(STM32_QSPI_BASE_ADDRESS), dev_cfg->flash_size); +#endif return 0; } diff --git a/drivers/flash/flash_stm32_xspi.c b/drivers/flash/flash_stm32_xspi.c new file mode 100644 index 00000000000..ae08e1d07cd --- /dev/null +++ b/drivers/flash/flash_stm32_xspi.c @@ -0,0 +1,2072 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * ************************************************************************** + * xSPI flash controller driver for stm32 serie with xSPI periherals + * This driver is based on the stm32Cube HAL XSPI driver + * with one xspi DTS NODE + * ************************************************************************** + */ +#define DT_DRV_COMPAT st_stm32_xspi_nor + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "spi_nor.h" +#include "jesd216.h" + +#include +LOG_MODULE_REGISTER(flash_stm32_xspi, CONFIG_FLASH_LOG_LEVEL); + +#define STM32_XSPI_NODE DT_INST_PARENT(0) + +#define DT_XSPI_IO_PORT_PROP_OR(prop, default_value) \ + COND_CODE_1(DT_NODE_HAS_PROP(STM32_XSPI_NODE, prop), \ + (_CONCAT(HAL_XSPIM_, DT_STRING_TOKEN(STM32_XSPI_NODE, prop))), \ + ((default_value))) + +/* Get the base address of the flash from the DTS node */ +#define STM32_XSPI_BASE_ADDRESS DT_INST_REG_ADDR(0) + +#define STM32_XSPI_RESET_GPIO DT_INST_NODE_HAS_PROP(0, reset_gpios) + +#define STM32_XSPI_DLYB_BYPASSED DT_PROP(STM32_XSPI_NODE, dlyb_bypass) + +#include "flash_stm32_xspi.h" + +static inline void xspi_lock_thread(const struct device *dev) +{ + struct flash_stm32_xspi_data *dev_data = dev->data; + + k_sem_take(&dev_data->sem, K_FOREVER); +} + +static inline void xspi_unlock_thread(const struct device *dev) +{ + struct flash_stm32_xspi_data *dev_data = dev->data; + + k_sem_give(&dev_data->sem); +} + +static int xspi_send_cmd(const struct device *dev, XSPI_RegularCmdTypeDef *cmd) +{ + struct flash_stm32_xspi_data *dev_data = dev->data; + HAL_StatusTypeDef hal_ret; + + LOG_DBG("Instruction 0x%x", cmd->Instruction); + + dev_data->cmd_status = 0; + + hal_ret = HAL_XSPI_Command(&dev_data->hxspi, cmd, HAL_XSPI_TIMEOUT_DEFAULT_VALUE); + if (hal_ret != HAL_OK) { + LOG_ERR("%d: Failed to send XSPI instruction", hal_ret); + return -EIO; + } + LOG_DBG("CCR 0x%x", dev_data->hxspi.Instance->CCR); + + return dev_data->cmd_status; +} + +static int xspi_read_access(const struct device *dev, XSPI_RegularCmdTypeDef *cmd, + uint8_t *data, const size_t size) +{ + struct flash_stm32_xspi_data *dev_data = dev->data; + HAL_StatusTypeDef hal_ret; + + LOG_DBG("Instruction 0x%x", cmd->Instruction); + + cmd->DataLength = size; + + dev_data->cmd_status = 0; + + hal_ret = HAL_XSPI_Command(&dev_data->hxspi, cmd, HAL_XSPI_TIMEOUT_DEFAULT_VALUE); + if (hal_ret != HAL_OK) { + LOG_ERR("%d: Failed to send XSPI instruction", hal_ret); + return -EIO; + } + + hal_ret = HAL_XSPI_Receive_IT(&dev_data->hxspi, data); + + if (hal_ret != HAL_OK) { + LOG_ERR("%d: Failed to read data", hal_ret); + return -EIO; + } + + k_sem_take(&dev_data->sync, K_FOREVER); + + return dev_data->cmd_status; +} + +static int xspi_write_access(const struct device *dev, XSPI_RegularCmdTypeDef *cmd, + const uint8_t *data, const size_t size) +{ + const struct flash_stm32_xspi_config *dev_cfg = dev->config; + struct flash_stm32_xspi_data *dev_data = dev->data; + HAL_StatusTypeDef hal_ret; + + LOG_DBG("Instruction 0x%x", cmd->Instruction); + + cmd->DataLength = size; + + dev_data->cmd_status = 0; + + /* in OPI/STR the 3-byte AddressWidth is not supported by the NOR flash */ + if ((dev_cfg->data_mode == XSPI_OCTO_MODE) && + (cmd->AddressWidth != HAL_XSPI_ADDRESS_32_BITS)) { + LOG_ERR("XSPI wr in OPI/STR mode is for 32bit address only"); + return -EIO; + } + + hal_ret = HAL_XSPI_Command(&dev_data->hxspi, cmd, HAL_XSPI_TIMEOUT_DEFAULT_VALUE); + if (hal_ret != HAL_OK) { + LOG_ERR("%d: Failed to send XSPI instruction", hal_ret); + return -EIO; + } + + hal_ret = HAL_XSPI_Transmit_IT(&dev_data->hxspi, (uint8_t *)data); + + if (hal_ret != HAL_OK) { + LOG_ERR("%d: Failed to write data", hal_ret); + return -EIO; + } + + k_sem_take(&dev_data->sync, K_FOREVER); + + return dev_data->cmd_status; +} + +/* + * Gives a XSPI_RegularCmdTypeDef with all parameters set + * except Instruction, Address, DummyCycles, NbData + */ +static XSPI_RegularCmdTypeDef xspi_prepare_cmd(const uint8_t transfer_mode, + const uint8_t transfer_rate) +{ + XSPI_RegularCmdTypeDef cmd_tmp = { + .OperationType = HAL_XSPI_OPTYPE_COMMON_CFG, + .InstructionWidth = ((transfer_mode == XSPI_OCTO_MODE) + ? HAL_XSPI_INSTRUCTION_16_BITS + : HAL_XSPI_INSTRUCTION_8_BITS), + .InstructionDTRMode = ((transfer_rate == XSPI_DTR_TRANSFER) + ? HAL_XSPI_INSTRUCTION_DTR_ENABLE + : HAL_XSPI_INSTRUCTION_DTR_DISABLE), + .AddressDTRMode = ((transfer_rate == XSPI_DTR_TRANSFER) + ? HAL_XSPI_ADDRESS_DTR_ENABLE + : HAL_XSPI_ADDRESS_DTR_DISABLE), + /* AddressWidth must be set to 32bits for init and mem config phase */ + .AddressWidth = HAL_XSPI_ADDRESS_32_BITS, + .AlternateBytesMode = HAL_XSPI_ALT_BYTES_NONE, + .DataDTRMode = ((transfer_rate == XSPI_DTR_TRANSFER) + ? HAL_XSPI_DATA_DTR_ENABLE + : HAL_XSPI_DATA_DTR_DISABLE), + .DQSMode = (transfer_rate == XSPI_DTR_TRANSFER) + ? HAL_XSPI_DQS_ENABLE + : HAL_XSPI_DQS_DISABLE, + .SIOOMode = HAL_XSPI_SIOO_INST_EVERY_CMD, + }; + + switch (transfer_mode) { + case XSPI_OCTO_MODE: { + cmd_tmp.InstructionMode = HAL_XSPI_INSTRUCTION_8_LINES; + cmd_tmp.AddressMode = HAL_XSPI_ADDRESS_8_LINES; + cmd_tmp.DataMode = HAL_XSPI_DATA_8_LINES; + break; + } + case XSPI_QUAD_MODE: { + cmd_tmp.InstructionMode = HAL_XSPI_INSTRUCTION_4_LINES; + cmd_tmp.AddressMode = HAL_XSPI_ADDRESS_4_LINES; + cmd_tmp.DataMode = HAL_XSPI_DATA_4_LINES; + break; + } + case XSPI_DUAL_MODE: { + cmd_tmp.InstructionMode = HAL_XSPI_INSTRUCTION_2_LINES; + cmd_tmp.AddressMode = HAL_XSPI_ADDRESS_2_LINES; + cmd_tmp.DataMode = HAL_XSPI_DATA_2_LINES; + break; + } + default: { + cmd_tmp.InstructionMode = HAL_XSPI_INSTRUCTION_1_LINE; + cmd_tmp.AddressMode = HAL_XSPI_ADDRESS_1_LINE; + cmd_tmp.DataMode = HAL_XSPI_DATA_1_LINE; + break; + } + } + + return cmd_tmp; +} + +static uint32_t stm32_xspi_hal_address_size(const struct device *dev) +{ + struct flash_stm32_xspi_data *dev_data = dev->data; + + if (dev_data->address_width == 4U) { + return HAL_XSPI_ADDRESS_32_BITS; + } + + return HAL_XSPI_ADDRESS_24_BITS; +} + +#if defined(CONFIG_FLASH_JESD216_API) +/* + * Read the JEDEC ID data from the external Flash at init + * and store in the jedec_id Table of the flash_stm32_xspi_data + * The JEDEC ID is not given by a DTS property + */ +static int stm32_xspi_read_jedec_id(const struct device *dev) +{ + struct flash_stm32_xspi_data *dev_data = dev->data; + + /* This is a SPI/STR command to issue to the external Flash device */ + XSPI_RegularCmdTypeDef cmd = xspi_prepare_cmd(XSPI_SPI_MODE, XSPI_STR_TRANSFER); + + cmd.Instruction = JESD216_CMD_READ_ID; + cmd.AddressWidth = stm32_xspi_hal_address_size(dev); + cmd.AddressMode = HAL_XSPI_ADDRESS_NONE; + cmd.DataLength = JESD216_READ_ID_LEN; /* 3 bytes in the READ ID */ + + HAL_StatusTypeDef hal_ret; + + hal_ret = HAL_XSPI_Command(&dev_data->hxspi, &cmd, + HAL_XSPI_TIMEOUT_DEFAULT_VALUE); + + if (hal_ret != HAL_OK) { + LOG_ERR("%d: Failed to send XSPI instruction", hal_ret); + return -EIO; + } + + /* Place the received data directly into the jedec Table */ + hal_ret = HAL_XSPI_Receive(&dev_data->hxspi, dev_data->jedec_id, + HAL_XSPI_TIMEOUT_DEFAULT_VALUE); + if (hal_ret != HAL_OK) { + LOG_ERR("%d: Failed to read data", hal_ret); + return -EIO; + } + + LOG_DBG("Jedec ID = [%02x %02x %02x]", + dev_data->jedec_id[0], dev_data->jedec_id[1], dev_data->jedec_id[2]); + + dev_data->cmd_status = 0; + + return 0; +} + +/* + * Read Serial Flash ID : + * just gives the values received by the external Flash + */ +static int xspi_read_jedec_id(const struct device *dev, uint8_t *id) +{ + struct flash_stm32_xspi_data *dev_data = dev->data; + + /* Take jedec Id values from the table (issued from the octoFlash) */ + memcpy(id, dev_data->jedec_id, JESD216_READ_ID_LEN); + + LOG_INF("Manuf ID = %02x Memory Type = %02x Memory Density = %02x", + id[0], id[1], id[2]); + + return 0; +} +#endif /* CONFIG_FLASH_JESD216_API */ + +/* + * Read Serial Flash Discovery Parameter from the external Flash at init : + * perform a read access over SPI bus for SDFP (DataMode is already set) + * The SFDP table is not given by a DTS property + */ +static int stm32_xspi_read_sfdp(const struct device *dev, off_t addr, + void *data, + size_t size) +{ + const struct flash_stm32_xspi_config *dev_cfg = dev->config; + struct flash_stm32_xspi_data *dev_data = dev->data; + + XSPI_RegularCmdTypeDef cmd = xspi_prepare_cmd(dev_cfg->data_mode, + dev_cfg->data_rate); + if (dev_cfg->data_mode == XSPI_OCTO_MODE) { + cmd.Instruction = JESD216_OCMD_READ_SFDP; + cmd.DummyCycles = 20U; + cmd.AddressWidth = HAL_XSPI_ADDRESS_32_BITS; + } else { + cmd.Instruction = JESD216_CMD_READ_SFDP; + cmd.InstructionMode = HAL_XSPI_INSTRUCTION_1_LINE; + cmd.DataMode = HAL_XSPI_DATA_1_LINE; + cmd.AddressMode = HAL_XSPI_ADDRESS_1_LINE; + cmd.DummyCycles = 8U; + cmd.AddressWidth = HAL_XSPI_ADDRESS_24_BITS; + } + cmd.Address = addr; + cmd.DataLength = size; + + HAL_StatusTypeDef hal_ret; + + hal_ret = HAL_XSPI_Command(&dev_data->hxspi, &cmd, HAL_XSPI_TIMEOUT_DEFAULT_VALUE); + if (hal_ret != HAL_OK) { + LOG_ERR("%d: Failed to send XSPI instruction", hal_ret); + return -EIO; + } + + hal_ret = HAL_XSPI_Receive(&dev_data->hxspi, (uint8_t *)data, + HAL_XSPI_TIMEOUT_DEFAULT_VALUE); + if (hal_ret != HAL_OK) { + LOG_ERR("%d: Failed to read data", hal_ret); + return -EIO; + } + + dev_data->cmd_status = 0; + + return 0; +} + +/* + * Read Serial Flash Discovery Parameter : + * perform a read access over SPI bus for SDFP (DataMode is already set) + */ +static int xspi_read_sfdp(const struct device *dev, off_t addr, void *data, + size_t size) +{ + LOG_INF("Read SFDP from externalFlash"); + /* Get the SFDP from the external Flash (no sfdp-bfp table in the DeviceTree) */ + if (stm32_xspi_read_sfdp(dev, addr, data, size) == 0) { + /* If valid, then ignore any table from the DTS */ + return 0; + } + LOG_INF("Error reading SFDP from external Flash and none in the DTS"); + return -EINVAL; +} + +static bool xspi_address_is_valid(const struct device *dev, off_t addr, + size_t size) +{ + const struct flash_stm32_xspi_config *dev_cfg = dev->config; + size_t flash_size = dev_cfg->flash_size; + + return (addr >= 0) && ((uint64_t)addr + (uint64_t)size <= flash_size); +} + +static int stm32_xspi_wait_auto_polling(const struct device *dev, + XSPI_AutoPollingTypeDef *s_config, uint32_t timeout_ms) +{ + struct flash_stm32_xspi_data *dev_data = dev->data; + + dev_data->cmd_status = 0; + + if (HAL_XSPI_AutoPolling_IT(&dev_data->hxspi, s_config) != HAL_OK) { + LOG_ERR("XSPI AutoPoll failed"); + return -EIO; + } + + if (k_sem_take(&dev_data->sync, K_MSEC(timeout_ms)) != 0) { + LOG_ERR("XSPI AutoPoll wait failed"); + HAL_XSPI_Abort(&dev_data->hxspi); + k_sem_reset(&dev_data->sync); + return -EIO; + } + + /* HAL_XSPI_AutoPolling_IT enables transfer error interrupt which sets + * cmd_status. + */ + return dev_data->cmd_status; +} + +/* + * This function Polls the WEL (write enable latch) bit to become to 0 + * When the Chip Erase Cycle is completed, the Write Enable Latch (WEL) bit is cleared. + * in nor_mode SPI/OPI XSPI_SPI_MODE or XSPI_OCTO_MODE + * and nor_rate transfer STR/DTR XSPI_STR_TRANSFER or XSPI_DTR_TRANSFER + */ +static int stm32_xspi_mem_erased(const struct device *dev) +{ + const struct flash_stm32_xspi_config *dev_cfg = dev->config; + struct flash_stm32_xspi_data *dev_data = dev->data; + uint8_t nor_mode = dev_cfg->data_mode; + uint8_t nor_rate = dev_cfg->data_rate; + + XSPI_AutoPollingTypeDef s_config = {0}; + XSPI_RegularCmdTypeDef s_command = xspi_prepare_cmd(nor_mode, nor_rate); + + /* Configure automatic polling mode command to wait for memory ready */ + if (nor_mode == XSPI_OCTO_MODE) { + s_command.Instruction = SPI_NOR_OCMD_RDSR; + s_command.DummyCycles = (nor_rate == XSPI_DTR_TRANSFER) + ? SPI_NOR_DUMMY_REG_OCTAL_DTR + : SPI_NOR_DUMMY_REG_OCTAL; + } else { + s_command.Instruction = SPI_NOR_CMD_RDSR; + /* force 1-line InstructionMode for any non-OSPI transfer */ + s_command.InstructionMode = HAL_XSPI_INSTRUCTION_1_LINE; + s_command.AddressMode = HAL_XSPI_ADDRESS_NONE; + /* force 1-line DataMode for any non-OSPI transfer */ + s_command.DataMode = HAL_XSPI_DATA_1_LINE; + s_command.DummyCycles = 0; + } + s_command.DataLength = ((nor_rate == XSPI_DTR_TRANSFER) ? 2U : 1U); + s_command.Address = 0U; + + /* Set the mask to 0x02 to mask all Status REG bits except WEL */ + /* Set the match to 0x00 to check if the WEL bit is Reset */ + s_config.MatchValue = SPI_NOR_WEL_MATCH; + s_config.MatchMask = SPI_NOR_WEL_MASK; /* Write Enable Latch */ + + s_config.MatchMode = HAL_XSPI_MATCH_MODE_AND; + s_config.IntervalTime = SPI_NOR_AUTO_POLLING_INTERVAL; + s_config.AutomaticStop = HAL_XSPI_AUTOMATIC_STOP_ENABLE; + + if (HAL_XSPI_Command(&dev_data->hxspi, &s_command, + HAL_XSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { + LOG_ERR("XSPI AutoPoll command (WEL) failed"); + return -EIO; + } + + /* Start Automatic-Polling mode to wait until the memory is totally erased */ + return stm32_xspi_wait_auto_polling(dev, + &s_config, STM32_XSPI_BULK_ERASE_MAX_TIME); +} + +/* + * This function Polls the WIP(Write In Progress) bit to become to 0 + * in nor_mode SPI/OPI XSPI_SPI_MODE or XSPI_OCTO_MODE + * and nor_rate transfer STR/DTR XSPI_STR_TRANSFER or XSPI_DTR_TRANSFER + */ +static int stm32_xspi_mem_ready(const struct device *dev, uint8_t nor_mode, + uint8_t nor_rate) +{ + struct flash_stm32_xspi_data *dev_data = dev->data; + + XSPI_AutoPollingTypeDef s_config = {0}; + XSPI_RegularCmdTypeDef s_command = xspi_prepare_cmd(nor_mode, nor_rate); + + /* Configure automatic polling mode command to wait for memory ready */ + if (nor_mode == XSPI_OCTO_MODE) { + s_command.Instruction = SPI_NOR_OCMD_RDSR; + s_command.DummyCycles = (nor_rate == XSPI_DTR_TRANSFER) + ? SPI_NOR_DUMMY_REG_OCTAL_DTR + : SPI_NOR_DUMMY_REG_OCTAL; + } else { + s_command.Instruction = SPI_NOR_CMD_RDSR; + /* force 1-line InstructionMode for any non-OSPI transfer */ + s_command.InstructionMode = HAL_XSPI_INSTRUCTION_1_LINE; + s_command.AddressMode = HAL_XSPI_ADDRESS_NONE; + /* force 1-line DataMode for any non-OSPI transfer */ + s_command.DataMode = HAL_XSPI_DATA_1_LINE; + s_command.DummyCycles = 0; + } + s_command.DataLength = ((nor_rate == XSPI_DTR_TRANSFER) ? 2U : 1U); + s_command.Address = 0U; + + /* Set the mask to 0x01 to mask all Status REG bits except WIP */ + /* Set the match to 0x00 to check if the WIP bit is Reset */ + s_config.MatchValue = SPI_NOR_MEM_RDY_MATCH; + s_config.MatchMask = SPI_NOR_MEM_RDY_MASK; /* Write in progress */ + s_config.MatchMode = HAL_XSPI_MATCH_MODE_AND; + s_config.IntervalTime = SPI_NOR_AUTO_POLLING_INTERVAL; + s_config.AutomaticStop = HAL_XSPI_AUTOMATIC_STOP_ENABLE; + + if (HAL_XSPI_Command(&dev_data->hxspi, &s_command, + HAL_XSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { + LOG_ERR("XSPI AutoPoll command failed"); + return -EIO; + } + + /* Start Automatic-Polling mode to wait until the memory is ready WIP=0 */ + return stm32_xspi_wait_auto_polling(dev, &s_config, HAL_XSPI_TIMEOUT_DEFAULT_VALUE); +} + +/* Enables writing to the memory sending a Write Enable and wait it is effective */ +static int stm32_xspi_write_enable(const struct device *dev, + uint8_t nor_mode, uint8_t nor_rate) +{ + struct flash_stm32_xspi_data *dev_data = dev->data; + + XSPI_AutoPollingTypeDef s_config = {0}; + XSPI_RegularCmdTypeDef s_command = xspi_prepare_cmd(nor_mode, nor_rate); + + /* Initialize the write enable command */ + if (nor_mode == XSPI_OCTO_MODE) { + s_command.Instruction = SPI_NOR_OCMD_WREN; + } else { + s_command.Instruction = SPI_NOR_CMD_WREN; + /* force 1-line InstructionMode for any non-OSPI transfer */ + s_command.InstructionMode = HAL_XSPI_INSTRUCTION_1_LINE; + } + s_command.AddressMode = HAL_XSPI_ADDRESS_NONE; + s_command.DataMode = HAL_XSPI_DATA_NONE; + s_command.DummyCycles = 0U; + + if (HAL_XSPI_Command(&dev_data->hxspi, &s_command, + HAL_XSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { + LOG_ERR("XSPI flash write enable cmd failed"); + return -EIO; + } + + /* New command to Configure automatic polling mode to wait for write enabling */ + if (nor_mode == XSPI_OCTO_MODE) { + s_command.Instruction = SPI_NOR_OCMD_RDSR; + s_command.AddressMode = HAL_XSPI_ADDRESS_8_LINES; + s_command.DataMode = HAL_XSPI_DATA_8_LINES; + s_command.DummyCycles = (nor_rate == XSPI_DTR_TRANSFER) + ? SPI_NOR_DUMMY_REG_OCTAL_DTR + : SPI_NOR_DUMMY_REG_OCTAL; + } else { + s_command.Instruction = SPI_NOR_CMD_RDSR; + /* force 1-line DataMode for any non-OSPI transfer */ + s_command.InstructionMode = HAL_XSPI_INSTRUCTION_1_LINE; + s_command.AddressMode = HAL_XSPI_ADDRESS_1_LINE; + s_command.DataMode = HAL_XSPI_DATA_1_LINE; + s_command.DummyCycles = 0; + + /* DummyCycles remains 0 */ + } + s_command.DataLength = (nor_rate == XSPI_DTR_TRANSFER) ? 2U : 1U; + s_command.Address = 0U; + + if (HAL_XSPI_Command(&dev_data->hxspi, &s_command, + HAL_XSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { + LOG_ERR("XSPI config auto polling cmd failed"); + return -EIO; + } + + s_config.MatchValue = SPI_NOR_WREN_MATCH; + s_config.MatchMask = SPI_NOR_WREN_MASK; + s_config.MatchMode = HAL_XSPI_MATCH_MODE_AND; + s_config.IntervalTime = SPI_NOR_AUTO_POLLING_INTERVAL; + s_config.AutomaticStop = HAL_XSPI_AUTOMATIC_STOP_ENABLE; + + return stm32_xspi_wait_auto_polling(dev, &s_config, HAL_XSPI_TIMEOUT_DEFAULT_VALUE); +} + +/* Write Flash configuration register 2 with new dummy cycles */ +static int stm32_xspi_write_cfg2reg_dummy(XSPI_HandleTypeDef *hxspi, + uint8_t nor_mode, uint8_t nor_rate) +{ + uint8_t transmit_data = SPI_NOR_CR2_DUMMY_CYCLES_66MHZ; + XSPI_RegularCmdTypeDef s_command = xspi_prepare_cmd(nor_mode, nor_rate); + + /* Initialize the writing of configuration register 2 */ + s_command.Instruction = (nor_mode == XSPI_SPI_MODE) + ? SPI_NOR_CMD_WR_CFGREG2 + : SPI_NOR_OCMD_WR_CFGREG2; + s_command.Address = SPI_NOR_REG2_ADDR3; + s_command.DummyCycles = 0U; + s_command.DataLength = (nor_mode == XSPI_SPI_MODE) ? 1U + : ((nor_rate == XSPI_DTR_TRANSFER) ? 2U : 1U); + + if (HAL_XSPI_Command(hxspi, &s_command, + HAL_XSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { + LOG_ERR("XSPI transmit cmd"); + return -EIO; + } + + if (HAL_XSPI_Transmit(hxspi, &transmit_data, + HAL_XSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { + LOG_ERR("XSPI transmit "); + return -EIO; + } + + return 0; +} + +/* Write Flash configuration register 2 with new single or octal SPI protocol */ +static int stm32_xspi_write_cfg2reg_io(XSPI_HandleTypeDef *hxspi, + uint8_t nor_mode, uint8_t nor_rate, uint8_t op_enable) +{ + XSPI_RegularCmdTypeDef s_command = xspi_prepare_cmd(nor_mode, nor_rate); + + /* Initialize the writing of configuration register 2 */ + s_command.Instruction = (nor_mode == XSPI_SPI_MODE) + ? SPI_NOR_CMD_WR_CFGREG2 + : SPI_NOR_OCMD_WR_CFGREG2; + s_command.Address = SPI_NOR_REG2_ADDR1; + s_command.DummyCycles = 0U; + s_command.DataLength = (nor_mode == XSPI_SPI_MODE) ? 1U + : ((nor_rate == XSPI_DTR_TRANSFER) ? 2U : 1U); + + if (HAL_XSPI_Command(hxspi, &s_command, + HAL_XSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { + LOG_ERR("Write Flash configuration reg2 failed"); + return -EIO; + } + + if (HAL_XSPI_Transmit(hxspi, &op_enable, + HAL_XSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { + LOG_ERR("Write Flash configuration reg2 failed"); + return -EIO; + } + + return 0; +} + +/* Read Flash configuration register 2 with new single or octal SPI protocol */ +static int stm32_xspi_read_cfg2reg(XSPI_HandleTypeDef *hxspi, + uint8_t nor_mode, uint8_t nor_rate, uint8_t *value) +{ + XSPI_RegularCmdTypeDef s_command = xspi_prepare_cmd(nor_mode, nor_rate); + + /* Initialize the writing of configuration register 2 */ + s_command.Instruction = (nor_mode == XSPI_SPI_MODE) + ? SPI_NOR_CMD_RD_CFGREG2 + : SPI_NOR_OCMD_RD_CFGREG2; + s_command.Address = SPI_NOR_REG2_ADDR1; + s_command.DummyCycles = (nor_mode == XSPI_SPI_MODE) + ? 0U + : ((nor_rate == XSPI_DTR_TRANSFER) + ? SPI_NOR_DUMMY_REG_OCTAL_DTR + : SPI_NOR_DUMMY_REG_OCTAL); + s_command.DataLength = (nor_rate == XSPI_DTR_TRANSFER) ? 2U : 1U; + + if (HAL_XSPI_Command(hxspi, &s_command, HAL_XSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { + LOG_ERR("Write Flash configuration reg2 failed"); + return -EIO; + } + + if (HAL_XSPI_Receive(hxspi, value, HAL_XSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { + LOG_ERR("Write Flash configuration reg2 failed"); + return -EIO; + } + + return 0; +} + +/* Set the NOR Flash to desired Interface mode : SPI/OSPI and STR/DTR according to the DTS */ +static int stm32_xspi_config_mem(const struct device *dev) +{ + const struct flash_stm32_xspi_config *dev_cfg = dev->config; + struct flash_stm32_xspi_data *dev_data = dev->data; + uint8_t reg[2]; + + /* Going to set the SPI mode and STR transfer rate : done */ + if ((dev_cfg->data_mode != XSPI_OCTO_MODE) + && (dev_cfg->data_rate == XSPI_STR_TRANSFER)) { + LOG_INF("OSPI flash config is SPI|DUAL|QUAD / STR"); + return 0; + } + + /* Going to set the XPI mode (STR or DTR transfer rate) */ + LOG_DBG("XSPI configuring Octo SPI mode"); + + if (stm32_xspi_write_enable(dev, + XSPI_SPI_MODE, XSPI_STR_TRANSFER) != 0) { + LOG_ERR("OSPI write Enable failed"); + return -EIO; + } + + /* Write Configuration register 2 (with new dummy cycles) */ + if (stm32_xspi_write_cfg2reg_dummy(&dev_data->hxspi, + XSPI_SPI_MODE, XSPI_STR_TRANSFER) != 0) { + LOG_ERR("XSPI write CFGR2 failed"); + return -EIO; + } + if (stm32_xspi_mem_ready(dev, + XSPI_SPI_MODE, XSPI_STR_TRANSFER) != 0) { + LOG_ERR("XSPI autopolling failed"); + return -EIO; + } + if (stm32_xspi_write_enable(dev, + XSPI_SPI_MODE, XSPI_STR_TRANSFER) != 0) { + LOG_ERR("XSPI write Enable 2 failed"); + return -EIO; + } + + /* Write Configuration register 2 (with Octal I/O SPI protocol : choose STR or DTR) */ + uint8_t mode_enable = ((dev_cfg->data_rate == XSPI_DTR_TRANSFER) + ? SPI_NOR_CR2_DTR_OPI_EN + : SPI_NOR_CR2_STR_OPI_EN); + if (stm32_xspi_write_cfg2reg_io(&dev_data->hxspi, + XSPI_SPI_MODE, XSPI_STR_TRANSFER, mode_enable) != 0) { + LOG_ERR("XSPI write CFGR2 failed"); + return -EIO; + } + + /* Wait that the configuration is effective and check that memory is ready */ + k_busy_wait(STM32_XSPI_WRITE_REG_MAX_TIME * USEC_PER_MSEC); + + /* Reconfigure the memory type of the peripheral */ + dev_data->hxspi.Init.MemoryType = HAL_XSPI_MEMTYPE_MACRONIX; + dev_data->hxspi.Init.DelayHoldQuarterCycle = HAL_XSPI_DHQC_ENABLE; + if (HAL_XSPI_Init(&dev_data->hxspi) != HAL_OK) { + LOG_ERR("XSPI mem type MACRONIX failed"); + return -EIO; + } + + if (dev_cfg->data_rate == XSPI_STR_TRANSFER) { + if (stm32_xspi_mem_ready(dev, + XSPI_OCTO_MODE, XSPI_STR_TRANSFER) != 0) { + /* Check Flash busy ? */ + LOG_ERR("XSPI flash busy failed"); + return -EIO; + } + + if (stm32_xspi_read_cfg2reg(&dev_data->hxspi, + XSPI_OCTO_MODE, XSPI_STR_TRANSFER, reg) != 0) { + /* Check the configuration has been correctly done on SPI_NOR_REG2_ADDR1 */ + LOG_ERR("XSPI flash config read failed"); + return -EIO; + } + + LOG_INF("XSPI flash config is OCTO / STR"); + } + + if (dev_cfg->data_rate == XSPI_DTR_TRANSFER) { + if (stm32_xspi_mem_ready(dev, + XSPI_OCTO_MODE, XSPI_DTR_TRANSFER) != 0) { + /* Check Flash busy ? */ + LOG_ERR("XSPI flash busy failed"); + return -EIO; + } + + LOG_INF("XSPI flash config is OCTO / DTR"); + } + + return 0; +} + +/* gpio or send the different reset command to the NOR flash in SPI/OSPI and STR/DTR */ +static int stm32_xspi_mem_reset(const struct device *dev) +{ + struct flash_stm32_xspi_data *dev_data = dev->data; + +#if STM32_XSPI_RESET_GPIO + /* Generate RESETn pulse for the flash memory */ + gpio_pin_configure_dt(&dev_cfg->reset, GPIO_OUTPUT_ACTIVE); + k_msleep(DT_INST_PROP(0, reset_gpios_duration)); + gpio_pin_set_dt(&dev_cfg->reset, 0); +#else + + /* Reset command sent sucessively for each mode SPI/OPS & STR/DTR */ + XSPI_RegularCmdTypeDef s_command = { + .OperationType = HAL_XSPI_OPTYPE_COMMON_CFG, + .AddressMode = HAL_XSPI_ADDRESS_NONE, + .InstructionMode = HAL_XSPI_INSTRUCTION_1_LINE, + .InstructionDTRMode = HAL_XSPI_INSTRUCTION_DTR_DISABLE, + .Instruction = SPI_NOR_CMD_RESET_EN, + .InstructionWidth = HAL_XSPI_INSTRUCTION_8_BITS, + .AlternateBytesMode = HAL_XSPI_ALT_BYTES_NONE, + .DataLength = HAL_XSPI_DATA_NONE, + .DummyCycles = 0U, + .DQSMode = HAL_XSPI_DQS_DISABLE, + .SIOOMode = HAL_XSPI_SIOO_INST_EVERY_CMD, + }; + + /* Reset enable in SPI mode and STR transfer mode */ + if (HAL_XSPI_Command(&dev_data->hxspi, + &s_command, HAL_XSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { + LOG_ERR("XSPI reset enable (SPI/STR) failed"); + return -EIO; + } + + /* Reset memory in SPI mode and STR transfer mode */ + s_command.Instruction = SPI_NOR_CMD_RESET_MEM; + if (HAL_XSPI_Command(&dev_data->hxspi, + &s_command, HAL_XSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { + LOG_ERR("XSPI reset memory (SPI/STR) failed"); + return -EIO; + } + + /* Reset enable in OPI mode and STR transfer mode */ + s_command.InstructionMode = HAL_XSPI_INSTRUCTION_8_LINES; + s_command.InstructionDTRMode = HAL_XSPI_INSTRUCTION_DTR_DISABLE; + s_command.Instruction = SPI_NOR_OCMD_RESET_EN; + s_command.InstructionWidth = HAL_XSPI_INSTRUCTION_16_BITS; + if (HAL_XSPI_Command(&dev_data->hxspi, + &s_command, HAL_XSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { + LOG_ERR("XSPI reset enable (OCTO/STR) failed"); + return -EIO; + } + + /* Reset memory in OPI mode and STR transfer mode */ + s_command.Instruction = SPI_NOR_OCMD_RESET_MEM; + if (HAL_XSPI_Command(&dev_data->hxspi, + &s_command, HAL_XSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { + LOG_ERR("XSPI reset memory (OCTO/STR) failed"); + return -EIO; + } + + /* Reset enable in OPI mode and DTR transfer mode */ + s_command.InstructionDTRMode = HAL_XSPI_INSTRUCTION_DTR_ENABLE; + s_command.Instruction = SPI_NOR_OCMD_RESET_EN; + if (HAL_XSPI_Command(&dev_data->hxspi, + &s_command, HAL_XSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { + LOG_ERR("XSPI reset enable (OCTO/DTR) failed"); + return -EIO; + } + + /* Reset memory in OPI mode and DTR transfer mode */ + s_command.Instruction = SPI_NOR_OCMD_RESET_MEM; + if (HAL_XSPI_Command(&dev_data->hxspi, + &s_command, HAL_XSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { + LOG_ERR("XSPI reset memory (OCTO/DTR) failed"); + return -EIO; + } + +#endif /* STM32_XSPI_RESET_GPIO */ + /* Wait after SWreset CMD, in case SWReset occurred during erase operation */ + k_busy_wait(STM32_XSPI_RESET_MAX_TIME * USEC_PER_MSEC); + + return 0; +} + +/* + * Function to erase the flash : chip or sector with possible OCTO/SPI and STR/DTR + * to erase the complete chip (using dedicated command) : + * set size >= flash size + * set addr = 0 + */ +static int flash_stm32_xspi_erase(const struct device *dev, off_t addr, + size_t size) +{ + const struct flash_stm32_xspi_config *dev_cfg = dev->config; + struct flash_stm32_xspi_data *dev_data = dev->data; + int ret = 0; + + /* Ignore zero size erase */ + if (size == 0) { + return 0; + } + + /* Maximise erase size : means the complete chip */ + if (size > dev_cfg->flash_size) { + size = dev_cfg->flash_size; + } + + if (!xspi_address_is_valid(dev, addr, size)) { + LOG_ERR("Error: address or size exceeds expected values: " + "addr 0x%lx, size %zu", (long)addr, size); + return -EINVAL; + } + + if (((size % SPI_NOR_SECTOR_SIZE) != 0) && (size < dev_cfg->flash_size)) { + LOG_ERR("Error: wrong sector size 0x%x", size); + return -ENOTSUP; + } + + XSPI_RegularCmdTypeDef cmd_erase = { + .OperationType = HAL_XSPI_OPTYPE_COMMON_CFG, + .AlternateBytesMode = HAL_XSPI_ALT_BYTES_NONE, + .DataMode = HAL_XSPI_DATA_NONE, + .DummyCycles = 0U, + .DQSMode = HAL_XSPI_DQS_DISABLE, + .SIOOMode = HAL_XSPI_SIOO_INST_EVERY_CMD, + }; + + xspi_lock_thread(dev); + + if (stm32_xspi_mem_ready(dev, + dev_cfg->data_mode, dev_cfg->data_rate) != 0) { + xspi_unlock_thread(dev); + LOG_ERR("Erase failed : flash busy"); + return -EBUSY; + } + + cmd_erase.InstructionMode = (dev_cfg->data_mode == XSPI_OCTO_MODE) + ? HAL_XSPI_INSTRUCTION_8_LINES + : HAL_XSPI_INSTRUCTION_1_LINE; + cmd_erase.InstructionDTRMode = (dev_cfg->data_rate == XSPI_DTR_TRANSFER) + ? HAL_XSPI_INSTRUCTION_DTR_ENABLE + : HAL_XSPI_INSTRUCTION_DTR_DISABLE; + cmd_erase.InstructionWidth = (dev_cfg->data_mode == XSPI_OCTO_MODE) + ? HAL_XSPI_INSTRUCTION_16_BITS + : HAL_XSPI_INSTRUCTION_8_BITS; + + while ((size > 0) && (ret == 0)) { + + ret = stm32_xspi_write_enable(dev, + dev_cfg->data_mode, dev_cfg->data_rate); + if (ret != 0) { + LOG_ERR("Erase failed : write enable"); + break; + } + + if (size == dev_cfg->flash_size) { + /* Chip erase */ + LOG_DBG("Chip Erase"); + + cmd_erase.Address = 0; + cmd_erase.Instruction = (dev_cfg->data_mode == XSPI_OCTO_MODE) + ? SPI_NOR_OCMD_BULKE + : SPI_NOR_CMD_BULKE; + cmd_erase.AddressMode = HAL_XSPI_ADDRESS_NONE; + /* Full chip erase (Bulk) command */ + xspi_send_cmd(dev, &cmd_erase); + + size -= dev_cfg->flash_size; + /* Chip (Bulk) erase started, wait until WEL becomes 0 */ + ret = stm32_xspi_mem_erased(dev); + if (ret != 0) { + LOG_ERR("Chip Erase failed"); + break; + } + } else { + /* Sector or Block erase depending on the size */ + LOG_DBG("Sector/Block Erase"); + + cmd_erase.AddressMode = + (dev_cfg->data_mode == XSPI_OCTO_MODE) + ? HAL_XSPI_ADDRESS_8_LINES + : HAL_XSPI_ADDRESS_1_LINE; + cmd_erase.AddressDTRMode = + (dev_cfg->data_rate == XSPI_DTR_TRANSFER) + ? HAL_XSPI_ADDRESS_DTR_ENABLE + : HAL_XSPI_ADDRESS_DTR_DISABLE; + cmd_erase.AddressWidth = stm32_xspi_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; + + for (uint8_t ei = 0; + ei < JESD216_NUM_ERASE_TYPES; ++ei) { + const struct jesd216_erase_type *etp = + &erase_types[ei]; + + if ((etp->exp != 0) + && SPI_NOR_IS_ALIGNED(addr, etp->exp) + && (size >= BIT(etp->exp)) + && ((bet == NULL) + || (etp->exp > bet->exp))) { + bet = etp; + cmd_erase.Instruction = bet->cmd; + } else if (bet == NULL) { + /* Use the default sector erase cmd */ + if (dev_cfg->data_mode == XSPI_OCTO_MODE) { + cmd_erase.Instruction = SPI_NOR_OCMD_SE; + } else { + cmd_erase.Instruction = + (stm32_xspi_hal_address_size(dev) == + HAL_XSPI_ADDRESS_32_BITS) + ? SPI_NOR_CMD_SE_4B + : SPI_NOR_CMD_SE; + } + } + /* Avoid using wrong erase type, + * if zero entries are found in erase_types + */ + bet = NULL; + } + LOG_DBG("Sector/Block Erase addr 0x%x, asize 0x%x amode 0x%x instr 0x%x", + cmd_erase.Address, cmd_erase.AddressWidth, + cmd_erase.AddressMode, cmd_erase.Instruction); + + xspi_send_cmd(dev, &cmd_erase); + + if (bet != NULL) { + addr += BIT(bet->exp); + size -= BIT(bet->exp); + } else { + addr += SPI_NOR_SECTOR_SIZE; + size -= SPI_NOR_SECTOR_SIZE; + } + + ret = stm32_xspi_mem_ready(dev, dev_cfg->data_mode, + dev_cfg->data_rate); + } + + } + + xspi_unlock_thread(dev); + + return ret; +} + +/* Function to read the flash with possible OCTO/SPI and STR/DTR */ +static int flash_stm32_xspi_read(const struct device *dev, off_t addr, + void *data, size_t size) +{ + const struct flash_stm32_xspi_config *dev_cfg = dev->config; + struct flash_stm32_xspi_data *dev_data = dev->data; + int ret; + + if (!xspi_address_is_valid(dev, addr, size)) { + LOG_ERR("Error: address or size exceeds expected values: " + "addr 0x%lx, size %zu", (long)addr, size); + return -EINVAL; + } + + /* Ignore zero size read */ + if (size == 0) { + return 0; + } + + XSPI_RegularCmdTypeDef cmd = xspi_prepare_cmd(dev_cfg->data_mode, dev_cfg->data_rate); + + if (dev_cfg->data_mode != XSPI_OCTO_MODE) { + switch (dev_data->read_mode) { + case JESD216_MODE_112: { + cmd.InstructionMode = HAL_XSPI_INSTRUCTION_1_LINE; + cmd.AddressMode = HAL_XSPI_ADDRESS_1_LINE; + cmd.DataMode = HAL_XSPI_DATA_2_LINES; + break; + } + case JESD216_MODE_122: { + cmd.InstructionMode = HAL_XSPI_INSTRUCTION_1_LINE; + cmd.AddressMode = HAL_XSPI_ADDRESS_2_LINES; + cmd.DataMode = HAL_XSPI_DATA_2_LINES; + break; + } + case JESD216_MODE_114: { + cmd.InstructionMode = HAL_XSPI_INSTRUCTION_1_LINE; + cmd.AddressMode = HAL_XSPI_ADDRESS_1_LINE; + cmd.DataMode = HAL_XSPI_DATA_4_LINES; + break; + } + case JESD216_MODE_144: { + cmd.InstructionMode = HAL_XSPI_INSTRUCTION_1_LINE; + cmd.AddressMode = HAL_XSPI_ADDRESS_4_LINES; + cmd.DataMode = HAL_XSPI_DATA_4_LINES; + break; + } + default: + /* use the mode from ospi_prepare_cmd */ + break; + } + } + + /* Instruction and DummyCycles are set below */ + cmd.Address = addr; /* AddressSize is 32bits in OPSI mode */ + cmd.AddressWidth = stm32_xspi_hal_address_size(dev); + /* DataSize is set by the read cmd */ + + /* Configure other parameters */ + if (dev_cfg->data_rate == XSPI_DTR_TRANSFER) { + /* DTR transfer rate (==> Octal mode) */ + cmd.Instruction = SPI_NOR_OCMD_DTR_RD; + cmd.DummyCycles = SPI_NOR_DUMMY_RD_OCTAL_DTR; + } else { + /* STR transfer rate */ + if (dev_cfg->data_mode == XSPI_OCTO_MODE) { + /* OPI and STR */ + cmd.Instruction = SPI_NOR_OCMD_RD; + cmd.DummyCycles = SPI_NOR_DUMMY_RD_OCTAL; + } else { + /* use SFDP:BFP read instruction */ + cmd.Instruction = dev_data->read_opcode; + cmd.DummyCycles = dev_data->read_dummy; + /* in SPI and STR : expecting SPI_NOR_CMD_READ_FAST_4B */ + } + } + + LOG_DBG("XSPI: read %zu data", size); + xspi_lock_thread(dev); + + ret = xspi_read_access(dev, &cmd, data, size); + + xspi_unlock_thread(dev); + + return ret; +} + +/* Function to write the flash (page program) : with possible OCTO/SPI and STR/DTR */ +static int flash_stm32_xspi_write(const struct device *dev, off_t addr, + const void *data, size_t size) +{ + const struct flash_stm32_xspi_config *dev_cfg = dev->config; + struct flash_stm32_xspi_data *dev_data = dev->data; + size_t to_write; + int ret = 0; + + if (!xspi_address_is_valid(dev, addr, size)) { + LOG_ERR("Error: address or size exceeds expected values: " + "addr 0x%lx, size %zu", (long)addr, size); + return -EINVAL; + } + + /* Ignore zero size write */ + if (size == 0) { + return 0; + } + + /* page program for STR or DTR mode */ + XSPI_RegularCmdTypeDef cmd_pp = xspi_prepare_cmd(dev_cfg->data_mode, dev_cfg->data_rate); + + /* using 32bits address also in SPI/STR mode */ + cmd_pp.Instruction = dev_data->write_opcode; + + if (dev_cfg->data_mode != XSPI_OCTO_MODE) { + switch (cmd_pp.Instruction) { + case SPI_NOR_CMD_PP_4B: + __fallthrough; + case SPI_NOR_CMD_PP: { + cmd_pp.InstructionMode = HAL_XSPI_INSTRUCTION_1_LINE; + cmd_pp.AddressMode = HAL_XSPI_ADDRESS_1_LINE; + cmd_pp.DataMode = HAL_XSPI_DATA_1_LINE; + break; + } + case SPI_NOR_CMD_PP_1_1_4_4B: + __fallthrough; + case SPI_NOR_CMD_PP_1_1_4: { + cmd_pp.InstructionMode = HAL_XSPI_INSTRUCTION_1_LINE; + cmd_pp.AddressMode = HAL_XSPI_ADDRESS_1_LINE; + cmd_pp.DataMode = HAL_XSPI_DATA_4_LINES; + break; + } + case SPI_NOR_CMD_PP_1_4_4_4B: + __fallthrough; + case SPI_NOR_CMD_PP_1_4_4: { + cmd_pp.InstructionMode = HAL_XSPI_INSTRUCTION_1_LINE; + cmd_pp.AddressMode = HAL_XSPI_ADDRESS_4_LINES; + cmd_pp.DataMode = HAL_XSPI_DATA_4_LINES; + break; + } + default: + /* use the mode from ospi_prepare_cmd */ + break; + } + } + + cmd_pp.Address = addr; + cmd_pp.AddressWidth = stm32_xspi_hal_address_size(dev); + cmd_pp.DummyCycles = 0U; + + LOG_DBG("XSPI: write %zu data", size); + xspi_lock_thread(dev); + + ret = stm32_xspi_mem_ready(dev, + dev_cfg->data_mode, dev_cfg->data_rate); + if (ret != 0) { + xspi_unlock_thread(dev); + LOG_ERR("XSPI: write not ready"); + return -EIO; + } + + while ((size > 0) && (ret == 0)) { + to_write = size; + ret = stm32_xspi_write_enable(dev, + dev_cfg->data_mode, dev_cfg->data_rate); + if (ret != 0) { + LOG_ERR("XSPI: write not enabled"); + break; + } + /* Don't write more than a page. */ + if (to_write >= SPI_NOR_PAGE_SIZE) { + to_write = SPI_NOR_PAGE_SIZE; + } + + /* Don't write across a page boundary */ + if (((addr + to_write - 1U) / SPI_NOR_PAGE_SIZE) + != (addr / SPI_NOR_PAGE_SIZE)) { + to_write = SPI_NOR_PAGE_SIZE - + (addr % SPI_NOR_PAGE_SIZE); + } + cmd_pp.Address = addr; + + ret = xspi_write_access(dev, &cmd_pp, data, to_write); + if (ret != 0) { + LOG_ERR("XSPI: write not access"); + break; + } + + size -= to_write; + data = (const uint8_t *)data + to_write; + addr += to_write; + + /* Configure automatic polling mode to wait for end of program */ + ret = stm32_xspi_mem_ready(dev, + dev_cfg->data_mode, dev_cfg->data_rate); + if (ret != 0) { + LOG_ERR("XSPI: write PP not ready"); + break; + } + } + + xspi_unlock_thread(dev); + + return ret; +} + +static const struct flash_parameters flash_stm32_xspi_parameters = { + .write_block_size = 1, + .erase_value = 0xff +}; + +static const struct flash_parameters * +flash_stm32_xspi_get_parameters(const struct device *dev) +{ + ARG_UNUSED(dev); + + return &flash_stm32_xspi_parameters; +} + +static void flash_stm32_xspi_isr(const struct device *dev) +{ + struct flash_stm32_xspi_data *dev_data = dev->data; + + HAL_XSPI_IRQHandler(&dev_data->hxspi); +} + +#if !defined(CONFIG_SOC_SERIES_STM32H7X) +/* weak function required for HAL compilation */ +__weak HAL_StatusTypeDef HAL_DMA_Abort_IT(DMA_HandleTypeDef *hdma) +{ + return HAL_OK; +} + +/* weak function required for HAL compilation */ +__weak HAL_StatusTypeDef HAL_DMA_Abort(DMA_HandleTypeDef *hdma) +{ + return HAL_OK; +} +#endif /* !CONFIG_SOC_SERIES_STM32H7X */ + +/* + * Transfer Error callback. + */ +void HAL_XSPI_ErrorCallback(XSPI_HandleTypeDef *hxspi) +{ + struct flash_stm32_xspi_data *dev_data = + CONTAINER_OF(hxspi, struct flash_stm32_xspi_data, hxspi); + + LOG_DBG("Error cb"); + + dev_data->cmd_status = -EIO; + + k_sem_give(&dev_data->sync); +} + +/* + * Command completed callback. + */ +void HAL_XSPI_CmdCpltCallback(XSPI_HandleTypeDef *hxspi) +{ + struct flash_stm32_xspi_data *dev_data = + CONTAINER_OF(hxspi, struct flash_stm32_xspi_data, hxspi); + + LOG_DBG("Cmd Cplt cb"); + + k_sem_give(&dev_data->sync); +} + +/* + * Rx Transfer completed callback. + */ +void HAL_XSPI_RxCpltCallback(XSPI_HandleTypeDef *hxspi) +{ + struct flash_stm32_xspi_data *dev_data = + CONTAINER_OF(hxspi, struct flash_stm32_xspi_data, hxspi); + + LOG_DBG("Rx Cplt cb"); + + k_sem_give(&dev_data->sync); +} + +/* + * Tx Transfer completed callback. + */ +void HAL_XSPI_TxCpltCallback(XSPI_HandleTypeDef *hxspi) +{ + struct flash_stm32_xspi_data *dev_data = + CONTAINER_OF(hxspi, struct flash_stm32_xspi_data, hxspi); + + LOG_DBG("Tx Cplt cb"); + + k_sem_give(&dev_data->sync); +} + +/* + * Status Match callback. + */ +void HAL_XSPI_StatusMatchCallback(XSPI_HandleTypeDef *hxspi) +{ + struct flash_stm32_xspi_data *dev_data = + CONTAINER_OF(hxspi, struct flash_stm32_xspi_data, hxspi); + + LOG_DBG("Status Match cb"); + + k_sem_give(&dev_data->sync); +} + +/* + * Timeout callback. + */ +void HAL_XSPI_TimeOutCallback(XSPI_HandleTypeDef *hxspi) +{ + struct flash_stm32_xspi_data *dev_data = + CONTAINER_OF(hxspi, struct flash_stm32_xspi_data, hxspi); + + LOG_DBG("Timeout cb"); + + dev_data->cmd_status = -EIO; + + k_sem_give(&dev_data->sync); +} + +#if defined(CONFIG_FLASH_PAGE_LAYOUT) +static void flash_stm32_xspi_pages_layout(const struct device *dev, + const struct flash_pages_layout **layout, + size_t *layout_size) +{ + struct flash_stm32_xspi_data *dev_data = dev->data; + + *layout = &dev_data->layout; + *layout_size = 1; +} +#endif + +static const struct flash_driver_api flash_stm32_xspi_driver_api = { + .read = flash_stm32_xspi_read, + .write = flash_stm32_xspi_write, + .erase = flash_stm32_xspi_erase, + .get_parameters = flash_stm32_xspi_get_parameters, +#if defined(CONFIG_FLASH_PAGE_LAYOUT) + .page_layout = flash_stm32_xspi_pages_layout, +#endif +#if defined(CONFIG_FLASH_JESD216_API) + .sfdp_read = xspi_read_sfdp, + .read_jedec_id = xspi_read_jedec_id, +#endif /* CONFIG_FLASH_JESD216_API */ +}; + +#if defined(CONFIG_FLASH_PAGE_LAYOUT) +static int setup_pages_layout(const struct device *dev) +{ + const struct flash_stm32_xspi_config *dev_cfg = dev->config; + struct flash_stm32_xspi_data *data = dev->data; + const size_t flash_size = dev_cfg->flash_size; + uint32_t layout_page_size = data->page_size; + uint8_t value = 0; + int rv = 0; + + /* Find the smallest erase size. */ + for (size_t i = 0; i < ARRAY_SIZE(data->erase_types); ++i) { + const struct jesd216_erase_type *etp = &data->erase_types[i]; + + if ((etp->cmd != 0) + && ((value == 0) || (etp->exp < value))) { + value = etp->exp; + } + } + + uint32_t erase_size = BIT(value); + + if (erase_size == 0) { + erase_size = SPI_NOR_SECTOR_SIZE; + } + + /* We need layout page size to be compatible with erase size */ + if ((layout_page_size % erase_size) != 0) { + LOG_DBG("layout page %u not compatible with erase size %u", + layout_page_size, erase_size); + LOG_DBG("erase size will be used as layout page size"); + layout_page_size = erase_size; + } + + /* Warn but accept layout page sizes that leave inaccessible + * space. + */ + if ((flash_size % layout_page_size) != 0) { + LOG_DBG("layout page %u wastes space with device size %zu", + layout_page_size, flash_size); + } + + data->layout.pages_size = layout_page_size; + data->layout.pages_count = flash_size / layout_page_size; + LOG_DBG("layout %u x %u By pages", data->layout.pages_count, + data->layout.pages_size); + + return rv; +} +#endif /* CONFIG_FLASH_PAGE_LAYOUT */ + +static int stm32_xspi_read_status_register(const struct device *dev, uint8_t reg_num, uint8_t *reg) +{ + XSPI_RegularCmdTypeDef s_command = { + .InstructionMode = HAL_XSPI_INSTRUCTION_1_LINE, + .DataMode = HAL_XSPI_DATA_1_LINE, + }; + + switch (reg_num) { + case 1U: + s_command.Instruction = SPI_NOR_CMD_RDSR; + break; + case 2U: + s_command.Instruction = SPI_NOR_CMD_RDSR2; + break; + case 3U: + s_command.Instruction = SPI_NOR_CMD_RDSR3; + break; + default: + return -EINVAL; + } + + return xspi_read_access(dev, &s_command, reg, sizeof(*reg)); +} + +static int stm32_xspi_write_status_register(const struct device *dev, uint8_t reg_num, uint8_t reg) +{ + struct flash_stm32_xspi_data *data = dev->data; + XSPI_RegularCmdTypeDef s_command = { + .Instruction = SPI_NOR_CMD_WRSR, + .InstructionMode = HAL_XSPI_INSTRUCTION_1_LINE, + .DataMode = HAL_XSPI_DATA_1_LINE + }; + size_t size; + uint8_t regs[4] = { 0 }; + uint8_t *regs_p; + int ret; + + if (reg_num == 1U) { + size = 1U; + regs[0] = reg; + regs_p = ®s[0]; + /* 1 byte write clears SR2, write SR2 as well */ + if (data->qer_type == JESD216_DW15_QER_S2B1v1) { + ret = stm32_xspi_read_status_register(dev, 2, ®s[1]); + if (ret < 0) { + return ret; + } + size = 2U; + } + } else if (reg_num == 2U) { + s_command.Instruction = SPI_NOR_CMD_WRSR2; + size = 1U; + regs[1] = reg; + regs_p = ®s[1]; + /* if SR2 write needs SR1 */ + if ((data->qer_type == JESD216_DW15_QER_VAL_S2B1v1) || + (data->qer_type == JESD216_DW15_QER_VAL_S2B1v4) || + (data->qer_type == JESD216_DW15_QER_VAL_S2B1v5)) { + ret = stm32_xspi_read_status_register(dev, 1, ®s[0]); + if (ret < 0) { + return ret; + } + s_command.Instruction = SPI_NOR_CMD_WRSR; + size = 2U; + regs_p = ®s[0]; + } + } else if (reg_num == 3U) { + s_command.Instruction = SPI_NOR_CMD_WRSR3; + size = 1U; + regs[2] = reg; + regs_p = ®s[2]; + } else { + return -EINVAL; + } + + return xspi_write_access(dev, &s_command, regs_p, size); +} + +static int stm32_xspi_enable_qe(const struct device *dev) +{ + struct flash_stm32_xspi_data *data = dev->data; + uint8_t qe_reg_num; + uint8_t qe_bit; + uint8_t reg; + int ret; + + switch (data->qer_type) { + case JESD216_DW15_QER_NONE: + /* no QE bit, device detects reads based on opcode */ + return 0; + case JESD216_DW15_QER_S1B6: + qe_reg_num = 1U; + qe_bit = BIT(6U); + break; + case JESD216_DW15_QER_S2B7: + qe_reg_num = 2U; + qe_bit = BIT(7U); + break; + case JESD216_DW15_QER_S2B1v1: + __fallthrough; + case JESD216_DW15_QER_S2B1v4: + __fallthrough; + case JESD216_DW15_QER_S2B1v5: + __fallthrough; + case JESD216_DW15_QER_S2B1v6: + qe_reg_num = 2U; + qe_bit = BIT(1U); + break; + default: + return -ENOTSUP; + } + + ret = stm32_xspi_read_status_register(dev, qe_reg_num, ®); + if (ret < 0) { + return ret; + } + + /* exit early if QE bit is already set */ + if ((reg & qe_bit) != 0U) { + return 0; + } + + ret = stm32_xspi_write_enable(dev, XSPI_SPI_MODE, XSPI_STR_TRANSFER); + if (ret < 0) { + return ret; + } + + reg |= qe_bit; + + ret = stm32_xspi_write_status_register(dev, qe_reg_num, reg); + if (ret < 0) { + return ret; + } + + ret = stm32_xspi_mem_ready(dev, XSPI_SPI_MODE, XSPI_STR_TRANSFER); + if (ret < 0) { + return ret; + } + + /* validate that QE bit is set */ + ret = stm32_xspi_read_status_register(dev, qe_reg_num, ®); + if (ret < 0) { + return ret; + } + + if ((reg & qe_bit) == 0U) { + LOG_ERR("Status Register %u [0x%02x] not set", qe_reg_num, reg); + ret = -EIO; + } + + return ret; +} + +static void spi_nor_process_bfp_addrbytes(const struct device *dev, + const uint8_t jesd216_bfp_addrbytes) +{ + struct flash_stm32_xspi_data *data = dev->data; + + if ((jesd216_bfp_addrbytes == JESD216_SFDP_BFP_DW1_ADDRBYTES_VAL_4B) || + (jesd216_bfp_addrbytes == JESD216_SFDP_BFP_DW1_ADDRBYTES_VAL_3B4B)) { + data->address_width = 4U; + } else { + data->address_width = 3U; + } +} + +static inline uint8_t spi_nor_convert_read_to_4b(const uint8_t opcode) +{ + switch (opcode) { + case SPI_NOR_CMD_READ: + return SPI_NOR_CMD_READ_4B; + case SPI_NOR_CMD_DREAD: + return SPI_NOR_CMD_DREAD_4B; + case SPI_NOR_CMD_2READ: + return SPI_NOR_CMD_2READ_4B; + case SPI_NOR_CMD_QREAD: + return SPI_NOR_CMD_QREAD_4B; + case SPI_NOR_CMD_4READ: + return SPI_NOR_CMD_4READ_4B; + default: + /* use provided */ + return opcode; + } +} + +static inline uint8_t spi_nor_convert_write_to_4b(const uint8_t opcode) +{ + switch (opcode) { + case SPI_NOR_CMD_PP: + return SPI_NOR_CMD_PP_4B; + case SPI_NOR_CMD_PP_1_1_4: + return SPI_NOR_CMD_PP_1_1_4_4B; + case SPI_NOR_CMD_PP_1_4_4: + return SPI_NOR_CMD_PP_1_4_4_4B; + default: + /* use provided */ + return opcode; + } +} + +static int spi_nor_process_bfp(const struct device *dev, + const struct jesd216_param_header *php, + const struct jesd216_bfp *bfp) +{ + const struct flash_stm32_xspi_config *dev_cfg = dev->config; + struct flash_stm32_xspi_data *data = dev->data; + /* must be kept in data mode order, ignore 1-1-1 (always supported) */ + const enum jesd216_mode_type supported_read_modes[] = { JESD216_MODE_112, JESD216_MODE_122, + JESD216_MODE_114, + JESD216_MODE_144 }; + size_t supported_read_modes_max_idx; + struct jesd216_erase_type *etp = data->erase_types; + size_t idx; + const size_t flash_size = jesd216_bfp_density(bfp) / 8U; + struct jesd216_instr read_instr = { 0 }; + struct jesd216_bfp_dw15 dw15; + + if (flash_size != dev_cfg->flash_size) { + LOG_DBG("Unexpected flash size: %u", flash_size); + } + + LOG_DBG("%s: %u MiBy flash", dev->name, (uint32_t)(flash_size >> 20)); + + /* Copy over the erase types, preserving their order. (The + * Sector Map Parameter table references them by index.) + */ + memset(data->erase_types, 0, sizeof(data->erase_types)); + for (idx = 1U; idx <= ARRAY_SIZE(data->erase_types); ++idx) { + if (jesd216_bfp_erase(bfp, idx, etp) == 0) { + LOG_DBG("Erase %u with %02x", + (uint32_t)BIT(etp->exp), etp->cmd); + } + ++etp; + } + + spi_nor_process_bfp_addrbytes(dev, jesd216_bfp_addrbytes(bfp)); + LOG_DBG("Address width: %u Bytes", data->address_width); + + /* use PP opcode based on configured data mode if nothing is set in DTS */ + if (data->write_opcode == SPI_NOR_WRITEOC_NONE) { + switch (dev_cfg->data_mode) { + case XSPI_OCTO_MODE: + data->write_opcode = SPI_NOR_OCMD_PAGE_PRG; + break; + case XSPI_QUAD_MODE: + data->write_opcode = SPI_NOR_CMD_PP_1_4_4; + break; + case XSPI_DUAL_MODE: + data->write_opcode = SPI_NOR_CMD_PP_1_1_2; + break; + default: + data->write_opcode = SPI_NOR_CMD_PP; + break; + } + } + + if (dev_cfg->data_mode != XSPI_OCTO_MODE) { + /* determine supported read modes, begin from the slowest */ + data->read_mode = JESD216_MODE_111; + data->read_opcode = SPI_NOR_CMD_READ; + data->read_dummy = 0U; + + if (dev_cfg->data_mode != XSPI_SPI_MODE) { + if (dev_cfg->data_mode == XSPI_DUAL_MODE) { + /* the index of JESD216_MODE_114 in supported_read_modes */ + supported_read_modes_max_idx = 2U; + } else { + supported_read_modes_max_idx = ARRAY_SIZE(supported_read_modes); + } + + for (idx = 0U; idx < supported_read_modes_max_idx; ++idx) { + if (jesd216_bfp_read_support(php, bfp, supported_read_modes[idx], + &read_instr) < 0) { + /* not supported */ + continue; + } + + LOG_DBG("Supports read mode: %d, instr: 0x%X", + supported_read_modes[idx], read_instr.instr); + data->read_mode = supported_read_modes[idx]; + data->read_opcode = read_instr.instr; + data->read_dummy = + (read_instr.wait_states + read_instr.mode_clocks); + } + } + + /* convert 3-Byte opcodes to 4-Byte (if required) */ + if (IS_ENABLED(DT_INST_PROP(0, four_byte_opcodes))) { + if (data->address_width != 4U) { + LOG_DBG("4-Byte opcodes require 4-Byte address width"); + return -ENOTSUP; + } + data->read_opcode = spi_nor_convert_read_to_4b(data->read_opcode); + data->write_opcode = spi_nor_convert_write_to_4b(data->write_opcode); + } + + /* enable quad mode (if required) */ + if (dev_cfg->data_mode == XSPI_QUAD_MODE) { + if (jesd216_bfp_decode_dw15(php, bfp, &dw15) < 0) { + /* will use QER from DTS or default (refer to device data) */ + LOG_WRN("Unable to decode QE requirement [DW15]"); + } else { + /* bypass DTS QER value */ + data->qer_type = dw15.qer; + } + + LOG_DBG("QE requirement mode: %x", data->qer_type); + + if (stm32_xspi_enable_qe(dev) < 0) { + LOG_ERR("Failed to enable QUAD mode"); + return -EIO; + } + + LOG_DBG("QUAD mode enabled"); + } + } + + data->page_size = jesd216_bfp_page_size(php, bfp); + + LOG_DBG("Page size %u bytes", data->page_size); + LOG_DBG("Flash size %zu bytes", flash_size); + LOG_DBG("Using read mode: %d, instr: 0x%X, dummy cycles: %u", + data->read_mode, data->read_opcode, data->read_dummy); + LOG_DBG("Using write instr: 0x%X", data->write_opcode); + + return 0; +} + +static int flash_stm32_xspi_init(const struct device *dev) +{ + const struct flash_stm32_xspi_config *dev_cfg = dev->config; + struct flash_stm32_xspi_data *dev_data = dev->data; + uint32_t ahb_clock_freq; + uint32_t prescaler = STM32_XSPI_CLOCK_PRESCALER_MIN; + int ret; + + /* The SPI/DTR is not a valid config of data_mode/data_rate according to the DTS */ + if ((dev_cfg->data_mode != XSPI_OCTO_MODE) + && (dev_cfg->data_rate == XSPI_DTR_TRANSFER)) { + /* already the right config, continue */ + LOG_ERR("XSPI mode SPI|DUAL|QUAD/DTR is not valid"); + return -ENOTSUP; + } + + /* Signals configuration */ + ret = pinctrl_apply_state(dev_cfg->pcfg, PINCTRL_STATE_DEFAULT); + if (ret < 0) { + LOG_ERR("XSPI pinctrl setup failed (%d)", ret); + return ret; + } + + if (!device_is_ready(DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE))) { + LOG_ERR("clock control device not ready"); + return -ENODEV; + } + + /* Clock configuration */ + if (clock_control_on(DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE), + (clock_control_subsys_t) &dev_cfg->pclken) != 0) { + LOG_ERR("Could not enable XSPI clock"); + return -EIO; + } + /* Alternate clock config for peripheral if any */ +#if DT_CLOCKS_HAS_NAME(STM32_XSPI_NODE, xspi_ker) + if (clock_control_configure(DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE), + (clock_control_subsys_t) &dev_cfg->pclken_ker, + NULL) != 0) { + LOG_ERR("Could not select XSPI domain clock"); + return -EIO; + } + if (clock_control_get_rate(DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE), + (clock_control_subsys_t) &dev_cfg->pclken_ker, + &ahb_clock_freq) < 0) { + LOG_ERR("Failed call clock_control_get_rate(pclken_ker)"); + return -EIO; + } +#else + if (clock_control_get_rate(DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE), + (clock_control_subsys_t) &dev_cfg->pclken, + &ahb_clock_freq) < 0) { + LOG_ERR("Failed call clock_control_get_rate(pclken)"); + return -EIO; + } +#endif +#if DT_CLOCKS_HAS_NAME(STM32_XSPI_NODE, xspi_mgr) + if (clock_control_on(DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE), + (clock_control_subsys_t) &dev_cfg->pclken_mgr) != 0) { + LOG_ERR("Could not enable XSPI Manager clock"); + return -EIO; + } +#endif + + for (; prescaler <= STM32_XSPI_CLOCK_PRESCALER_MAX; prescaler++) { + uint32_t clk = STM32_XSPI_CLOCK_COMPUTE(ahb_clock_freq, prescaler); + + if (clk <= dev_cfg->max_frequency) { + break; + } + } + __ASSERT_NO_MSG(prescaler >= STM32_XSPI_CLOCK_PRESCALER_MIN && + prescaler <= STM32_XSPI_CLOCK_PRESCALER_MAX); + + /* Initialize XSPI HAL structure completely */ + dev_data->hxspi.Init.ClockPrescaler = prescaler; + /* The stm32 hal_xspi driver does not reduce DEVSIZE before writing the DCR1 */ + dev_data->hxspi.Init.MemorySize = find_lsb_set(dev_cfg->flash_size) - 2; +#if defined(XSPI_DCR2_WRAPSIZE) + dev_data->hxspi.Init.WrapSize = HAL_XSPI_WRAP_NOT_SUPPORTED; +#endif /* XSPI_DCR2_WRAPSIZE */ + /* STR mode else Macronix for DTR mode */ + if (dev_cfg->data_rate == XSPI_DTR_TRANSFER) { + dev_data->hxspi.Init.MemoryType = HAL_XSPI_MEMTYPE_MACRONIX; + dev_data->hxspi.Init.DelayHoldQuarterCycle = HAL_XSPI_DHQC_ENABLE; + } else { + + } +#if STM32_XSPI_DLYB_BYPASSED + dev_data->hxspi.Init.DelayBlockBypass = HAL_XSPI_DELAY_BLOCK_BYPASS; +#else + dev_data->hxspi.Init.DelayBlockBypass = HAL_XSPI_DELAY_BLOCK_ON; +#endif /* STM32_XSPI_DLYB_BYPASSED */ + + + if (HAL_XSPI_Init(&dev_data->hxspi) != HAL_OK) { + LOG_ERR("XSPI Init failed"); + return -EIO; + } + + LOG_DBG("XSPI Init'd"); + +#if defined(HAL_XSPIM_IOPORT_1) || defined(HAL_XSPIM_IOPORT_2) + /* XSPI I/O manager init Function */ + XSPIM_CfgTypeDef xspi_mgr_cfg; + + if (dev_data->hxspi.Instance == XSPI1) { + xspi_mgr_cfg.IOPort = HAL_XSPIM_IOPORT_1; + xspi_mgr_cfg.nCSOverride = HAL_XSPI_CSSEL_OVR_NCS1; + } else if (dev_data->hxspi.Instance == XSPI2) { + ospi_mgr_cfg.IOPort = HAL_XSPIM_IOPORT_2; + ospi_mgr_cfg.nCSOverride = HAL_XSPI_CSSEL_OVR_NCS2; + } + ospi_mgr_cfg.Req2AckTime = 1; + + if (HAL_XSPIM_Config(&dev_data->hxspi, &xspi_mgr_cfg, + HAL_XSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { + LOG_ERR("XSPI M config failed"); + return -EIO; + } + +#endif /* XSPIM */ + +#if defined(DLYB_XSPI1) || defined(DLYB_XSPI2) || defined(DLYB_OCTOSPI1) || defined(DLYB_OCTOSPI2) + /* XSPI delay block init Function */ + HAL_XSPI_DLYB_CfgTypeDef xspi_delay_block_cfg = {0}; + + (void)HAL_XSPI_DLYB_GetClockPeriod(&dev_data->hxspi, &xspi_delay_block_cfg); + /* with DTR, set the PhaseSel/4 (empiric value from stm32Cube) */ + xspi_delay_block_cfg.PhaseSel /= 4; + + if (HAL_XSPI_DLYB_SetConfig(&dev_data->hxspi, &xspi_delay_block_cfg) != HAL_OK) { + LOG_ERR("XSPI DelayBlock failed"); + return -EIO; + } + + LOG_DBG("Delay Block Init"); + +#endif /* DLYB_ */ + + /* Initialize semaphores */ + k_sem_init(&dev_data->sem, 1, 1); + k_sem_init(&dev_data->sync, 0, 1); + + /* Run IRQ init */ + dev_cfg->irq_config(dev); + + /* Reset NOR flash memory : still with the SPI/STR config for the NOR */ + if (stm32_xspi_mem_reset(dev) != 0) { + LOG_ERR("XSPI reset failed"); + return -EIO; + } + + LOG_DBG("Reset Mem (SPI/STR)"); + + /* Check if memory is ready in the SPI/STR mode */ + if (stm32_xspi_mem_ready(dev, + XSPI_SPI_MODE, XSPI_STR_TRANSFER) != 0) { + LOG_ERR("XSPI memory not ready"); + return -EIO; + } + + LOG_DBG("Mem Ready (SPI/STR)"); + +#if defined(CONFIG_FLASH_JESD216_API) + /* Process with the RDID (jedec read ID) instruction at init and fill jedec_id Table */ + ret = stm32_xspi_read_jedec_id(dev); + if (ret != 0) { + LOG_ERR("Read ID failed: %d", ret); + return ret; + } +#endif /* CONFIG_FLASH_JESD216_API */ + + if (stm32_xspi_config_mem(dev) != 0) { + LOG_ERR("OSPI mode not config'd (%u rate %u)", + dev_cfg->data_mode, dev_cfg->data_rate); + return -EIO; + } + + /* Send the instruction to read the SFDP */ + const uint8_t decl_nph = 2; + union { + /* 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; + + ret = xspi_read_sfdp(dev, 0, u.raw, sizeof(u.raw)); + if (ret != 0) { + LOG_ERR("SFDP read failed: %d", ret); + return ret; + } + + uint32_t magic = jesd216_sfdp_magic(hp); + + if (magic != JESD216_SFDP_MAGIC) { + LOG_ERR("SFDP magic %08x invalid", magic); + return -EINVAL; + } + + LOG_DBG("%s: SFDP v %u.%u AP %x with %u PH", dev->name, + hp->rev_major, hp->rev_minor, hp->access, 1 + hp->nph); + + const struct jesd216_param_header *php = hp->phdr; + const struct jesd216_param_header *phpe = php + + MIN(decl_nph, 1 + hp->nph); + + while (php != phpe) { + uint16_t id = jesd216_param_id(php); + + LOG_DBG("PH%u: %04x rev %u.%u: %u DW @ %x", + (php - hp->phdr), id, php->rev_major, php->rev_minor, + php->len_dw, jesd216_param_addr(php)); + + if (id == JESD216_SFDP_PARAM_ID_BFP) { + union { + uint32_t dw[20]; + struct jesd216_bfp bfp; + } u2; + const struct jesd216_bfp *bfp = &u2.bfp; + + ret = xspi_read_sfdp(dev, jesd216_param_addr(php), + (uint8_t *)u2.dw, + MIN(sizeof(uint32_t) * php->len_dw, sizeof(u2.dw))); + if (ret == 0) { + ret = spi_nor_process_bfp(dev, php, bfp); + } + + if (ret != 0) { + LOG_ERR("SFDP BFP failed: %d", ret); + break; + } + } + if (id == JESD216_SFDP_PARAM_ID_4B_ADDR_INSTR) { + + if (dev_data->address_width == 4U) { + /* + * Check table 4 byte address instruction table to get supported + * erase opcodes when running in 4 byte address mode + */ + union { + uint32_t dw[2]; + struct { + uint32_t dummy; + uint8_t type[4]; + } types; + } u2; + ret = xspi_read_sfdp(dev, jesd216_param_addr(php), + (uint8_t *)u2.dw, + MIN(sizeof(uint32_t) * php->len_dw, sizeof(u2.dw))); + if (ret != 0) { + break; + } + for (uint8_t ei = 0; ei < JESD216_NUM_ERASE_TYPES; ++ei) { + struct jesd216_erase_type *etp = &dev_data->erase_types[ei]; + const uint8_t cmd = u2.types.type[ei]; + /* 0xff means not supported */ + if (cmd == 0xff) { + etp->exp = 0; + etp->cmd = 0; + } else { + etp->cmd = cmd; + }; + } + } + } + ++php; + } + +#if defined(CONFIG_FLASH_PAGE_LAYOUT) + ret = setup_pages_layout(dev); + if (ret != 0) { + LOG_ERR("layout setup failed: %d", ret); + return -ENODEV; + } +#endif /* CONFIG_FLASH_PAGE_LAYOUT */ + + LOG_INF("NOR external-flash at 0x%lx (0x%x bytes)", + (long)(STM32_XSPI_BASE_ADDRESS), + dev_cfg->flash_size); + + return 0; +} + +#define XSPI_FLASH_MODULE(drv_id, flash_id) \ + (DT_DRV_INST(drv_id), xspi_nor_flash_##flash_id) + +#define DT_WRITEOC_PROP_OR(inst, default_value) \ + COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, writeoc), \ + (_CONCAT(SPI_NOR_CMD_, DT_STRING_TOKEN(DT_DRV_INST(inst), writeoc))), \ + ((default_value))) + +#define DT_QER_PROP_OR(inst, default_value) \ + COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, quad_enable_requirements), \ + (_CONCAT(JESD216_DW15_QER_VAL_, \ + DT_STRING_TOKEN(DT_DRV_INST(inst), quad_enable_requirements))), \ + ((default_value))) + +static void flash_stm32_xspi_irq_config_func(const struct device *dev); + +PINCTRL_DT_DEFINE(STM32_XSPI_NODE); + +static const struct flash_stm32_xspi_config flash_stm32_xspi_cfg = { + .pclken = {.bus = DT_CLOCKS_CELL_BY_NAME(STM32_XSPI_NODE, xspix, bus), + .enr = DT_CLOCKS_CELL_BY_NAME(STM32_XSPI_NODE, xspix, bits)}, +#if DT_CLOCKS_HAS_NAME(STM32_XSPI_NODE, xspi_ker) + .pclken_ker = {.bus = DT_CLOCKS_CELL_BY_NAME(STM32_XSPI_NODE, xspi_ker, bus), + .enr = DT_CLOCKS_CELL_BY_NAME(STM32_XSPI_NODE, xspi_ker, bits)}, +#endif +#if DT_CLOCKS_HAS_NAME(STM32_XSPI_NODE, xspi_mgr) + .pclken_mgr = {.bus = DT_CLOCKS_CELL_BY_NAME(STM32_XSPI_NODE, xspi_mgr, bus), + .enr = DT_CLOCKS_CELL_BY_NAME(STM32_XSPI_NODE, xspi_mgr, bits)}, +#endif + .irq_config = flash_stm32_xspi_irq_config_func, + .flash_size = DT_INST_REG_ADDR_BY_IDX(0, 1), + .max_frequency = DT_INST_PROP(0, ospi_max_frequency), + .data_mode = DT_INST_PROP(0, spi_bus_width), /* SPI or OPI */ + .data_rate = DT_INST_PROP(0, data_rate), /* DTR or STR */ + .pcfg = PINCTRL_DT_DEV_CONFIG_GET(STM32_XSPI_NODE), +#if STM32_XSPI_RESET_GPIO + .reset = GPIO_DT_SPEC_INST_GET(0, reset_gpios), +#endif /* STM32_XSPI_RESET_GPIO */ +#if DT_NODE_HAS_PROP(DT_INST(0, st_stm32_ospi_nor), sfdp_bfp) + .sfdp_bfp = DT_INST_PROP(0, sfdp_bfp), +#endif /* sfdp_bfp */ +}; + +static struct flash_stm32_xspi_data flash_stm32_xspi_dev_data = { + .hxspi = { + .Instance = (XSPI_TypeDef *)DT_REG_ADDR(STM32_XSPI_NODE), + .Init = { + .FifoThresholdByte = STM32_XSPI_FIFO_THRESHOLD, + .SampleShifting = (DT_PROP(STM32_XSPI_NODE, ssht_enable) + ? HAL_XSPI_SAMPLE_SHIFT_HALFCYCLE + : HAL_XSPI_SAMPLE_SHIFT_NONE), + .ChipSelectHighTimeCycle = 1, + .ClockMode = HAL_XSPI_CLOCK_MODE_0, + .ChipSelectBoundary = 0, + .MemoryMode = HAL_XSPI_SINGLE_MEM, + .FreeRunningClock = HAL_XSPI_FREERUNCLK_DISABLE, +#if defined(OCTOSPI_DCR4_REFRESH) + .Refresh = 0, +#endif /* OCTOSPI_DCR4_REFRESH */ + }, + }, + .qer_type = DT_QER_PROP_OR(0, JESD216_DW15_QER_VAL_S1B6), + .write_opcode = DT_WRITEOC_PROP_OR(0, SPI_NOR_WRITEOC_NONE), + .page_size = SPI_NOR_PAGE_SIZE, /* by default, to be updated by sfdp */ +#if DT_NODE_HAS_PROP(DT_INST(0, st_stm32_ospi_nor), jedec_id) + .jedec_id = DT_INST_PROP(0, jedec_id), +#endif /* jedec_id */ +}; + +DEVICE_DT_INST_DEFINE(0, &flash_stm32_xspi_init, NULL, + &flash_stm32_xspi_dev_data, &flash_stm32_xspi_cfg, + POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, + &flash_stm32_xspi_driver_api); + +static void flash_stm32_xspi_irq_config_func(const struct device *dev) +{ + IRQ_CONNECT(DT_IRQN(STM32_XSPI_NODE), DT_IRQ(STM32_XSPI_NODE, priority), + flash_stm32_xspi_isr, DEVICE_DT_INST_GET(0), 0); + irq_enable(DT_IRQN(STM32_XSPI_NODE)); +} diff --git a/drivers/flash/flash_stm32_xspi.h b/drivers/flash/flash_stm32_xspi.h new file mode 100644 index 00000000000..d940cc93343 --- /dev/null +++ b/drivers/flash/flash_stm32_xspi.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_FLASH_XSPI_STM32_H_ +#define ZEPHYR_DRIVERS_FLASH_XSPI_STM32_H_ + +#define STM32_XSPI_FIFO_THRESHOLD 4U + +/* Valid range is [0, 255] */ +#define STM32_XSPI_CLOCK_PRESCALER_MIN 0U +#define STM32_XSPI_CLOCK_PRESCALER_MAX 255U +#define STM32_XSPI_CLOCK_COMPUTE(bus_freq, prescaler) ((bus_freq) / ((prescaler) + 1U)) + +/* Max Time value during reset or erase operation */ +#define STM32_XSPI_RESET_MAX_TIME 100U +#define STM32_XSPI_BULK_ERASE_MAX_TIME 460000U +#define STM32_XSPI_SECTOR_ERASE_MAX_TIME 1000U +#define STM32_XSPI_SUBSECTOR_4K_ERASE_MAX_TIME 400U +#define STM32_XSPI_WRITE_REG_MAX_TIME 40U + +/* used as default value for DTS writeoc */ +#define SPI_NOR_WRITEOC_NONE 0xFF + +typedef void (*irq_config_func_t)(const struct device *dev); + +struct flash_stm32_xspi_config { + const struct stm32_pclken pclken; /* clock subsystem */ + const struct stm32_pclken pclken_ker; /* clock subsystem */ + const struct stm32_pclken pclken_mgr; /* clock subsystem */ + irq_config_func_t irq_config; + size_t flash_size; + uint32_t max_frequency; + int data_mode; /* SPI or QSPI or OSPI */ + int data_rate; /* DTR or STR */ + const struct pinctrl_dev_config *pcfg; +#if STM32_XSPI_RESET_GPIO + const struct gpio_dt_spec reset; +#endif /* STM32_XSPI_RESET_GPIO */ +}; + +struct flash_stm32_xspi_data { + /* XSPI handle is modifiable ; so part of data struct */ + XSPI_HandleTypeDef hxspi; + struct k_sem sem; + struct k_sem sync; +#if defined(CONFIG_FLASH_PAGE_LAYOUT) + struct flash_pages_layout layout; +#endif + struct jesd216_erase_type erase_types[JESD216_NUM_ERASE_TYPES]; + /* Number of bytes per page */ + uint16_t page_size; + /* Address width in bytes */ + uint8_t address_width; + /* Read operation dummy cycles */ + uint8_t read_dummy; + uint32_t read_opcode; + uint32_t write_opcode; + enum jesd216_mode_type read_mode; + enum jesd216_dw15_qer_type qer_type; +#if defined(CONFIG_FLASH_JESD216_API) + /* Table to hold the jedec Read ID given by the octoFlash const */ + uint8_t jedec_id[JESD216_READ_ID_LEN]; +#endif /* CONFIG_FLASH_JESD216_API */ + int cmd_status; +}; + +#endif /* ZEPHYR_DRIVERS_FLASH_XSPI_STM32_H_ */ diff --git a/drivers/flash/soc_flash_nrf_rram.c b/drivers/flash/soc_flash_nrf_rram.c index b8ab3afa8fe..9e5e652ca5e 100644 --- a/drivers/flash/soc_flash_nrf_rram.c +++ b/drivers/flash/soc_flash_nrf_rram.c @@ -41,7 +41,11 @@ LOG_MODULE_REGISTER(flash_nrf_rram, CONFIG_FLASH_LOG_LEVEL); #define RRAM DT_INST(0, soc_nv_flash) +#if defined(CONFIG_SOC_SERIES_BSIM_NRFXX) +#define RRAM_START NRF_RRAM_BASE_ADDR +#else #define RRAM_START DT_REG_ADDR(RRAM) +#endif #define RRAM_SIZE DT_REG_SIZE(RRAM) #define PAGE_SIZE DT_PROP(RRAM, erase_block_size) diff --git a/drivers/flash/spi_nor.c b/drivers/flash/spi_nor.c index 0b4ab8fba0d..2dd805d3797 100644 --- a/drivers/flash/spi_nor.c +++ b/drivers/flash/spi_nor.c @@ -503,7 +503,6 @@ static int enter_dpd(const struct device *const dev) int ret = 0; const struct spi_nor_config *cfg = dev->config; - ARG_UNUSED(cfg); if (cfg->dpd_exist) { ret = spi_nor_cmd_write(dev, SPI_NOR_CMD_DPD); if (ret == 0) { @@ -819,7 +818,7 @@ static int spi_nor_write(const struct device *dev, off_t addr, { const size_t flash_size = dev_flash_size(dev); const uint16_t page_size = dev_page_size(dev); - int ret = 0; + int ret; /* should be between 0 and flash size */ if ((addr < 0) || ((size + addr) > flash_size)) { @@ -871,7 +870,7 @@ static int spi_nor_write(const struct device *dev, off_t addr, static int spi_nor_erase(const struct device *dev, off_t addr, size_t size) { const size_t flash_size = dev_flash_size(dev); - int ret = 0; + int ret; /* erase area must be subregion of device */ if ((addr < 0) || ((size + addr) > flash_size)) { @@ -965,7 +964,6 @@ static int spi_nor_write_protection_set(const struct device *dev, } #endif - ARG_UNUSED(cfg); ret = spi_nor_cmd_write(dev, (write_protect) ? SPI_NOR_CMD_WRDI : SPI_NOR_CMD_WREN); @@ -1211,8 +1209,6 @@ static int spi_nor_process_sfdp(const struct device *dev) #if defined(CONFIG_FLASH_PAGE_LAYOUT) static int setup_pages_layout(const struct device *dev) { - int rv = 0; - #if defined(CONFIG_SPI_NOR_SFDP_RUNTIME) struct spi_nor_data *data = dev->data; const size_t flash_size = dev_flash_size(dev); @@ -1270,7 +1266,7 @@ static int setup_pages_layout(const struct device *dev) #error Unhandled SFDP choice #endif /* CONFIG_SPI_NOR_SFDP_RUNTIME */ - return rv; + return 0; } #endif /* CONFIG_FLASH_PAGE_LAYOUT */ #endif /* CONFIG_SPI_NOR_SFDP_MINIMAL */ @@ -1663,7 +1659,7 @@ static const struct flash_driver_api spi_nor_api = { .dpd_wakeup_sequence_exist = DT_INST_NODE_HAS_PROP(idx, dpd_wakeup_sequence), \ .mxicy_mx25r_power_mode_exist = DT_INST_NODE_HAS_PROP(idx, mxicy_mx25r_power_mode), \ .reset_gpios_exist = DT_INST_NODE_HAS_PROP(idx, reset_gpios), \ - .requires_ulbpr_exist = DT_INST_PROP(idx, requires_ulbpr), \ + .requires_ulbpr_exist = DT_INST_PROP(idx, requires_ulbpr), \ .wp_gpios_exist = DT_INST_NODE_HAS_PROP(idx, wp_gpios), \ .hold_gpios_exist = DT_INST_NODE_HAS_PROP(idx, hold_gpios), \ IF_ENABLED(INST_HAS_LOCK(idx), (.has_lock = DT_INST_PROP(idx, has_lock),)) \ diff --git a/drivers/fpga/CMakeLists.txt b/drivers/fpga/CMakeLists.txt index e7a16193c4c..8a8f17d1fe9 100644 --- a/drivers/fpga/CMakeLists.txt +++ b/drivers/fpga/CMakeLists.txt @@ -4,6 +4,7 @@ zephyr_library() zephyr_library_sources_ifdef(CONFIG_FPGA_SHELL fpga_shell.c) +zephyr_library_sources_ifdef(CONFIG_ALTERA_AGILEX_BRIDGE_FPGA fpga_altera_agilex_bridge.c) zephyr_library_sources_ifdef(CONFIG_EOS_S3_FPGA fpga_eos_s3.c) zephyr_library_sources_ifdef(CONFIG_ICE40_FPGA fpga_ice40.c) zephyr_library_sources_ifdef(CONFIG_MPFS_FPGA fpga_mpfs.c) diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig index 6041a164f18..2a6a2885c32 100644 --- a/drivers/fpga/Kconfig +++ b/drivers/fpga/Kconfig @@ -26,6 +26,7 @@ config FPGA_SHELL help Enable FPGA Shell support. +source "drivers/fpga/Kconfig.altera_agilex_bridge" source "drivers/fpga/Kconfig.eos_s3" source "drivers/fpga/Kconfig.ice40" source "drivers/fpga/Kconfig.mpfs" diff --git a/drivers/fpga/Kconfig.altera_agilex_bridge b/drivers/fpga/Kconfig.altera_agilex_bridge new file mode 100644 index 00000000000..a9265aab3f6 --- /dev/null +++ b/drivers/fpga/Kconfig.altera_agilex_bridge @@ -0,0 +1,10 @@ +# FPGA ALTERA driver configuration options + +# Copyright (c) 2024, Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +config ALTERA_AGILEX_BRIDGE_FPGA + bool "ALTERA fpga driver" + depends on ARM_SIP_SVC_SUBSYS + help + Enable ALTERA FPGA driver. diff --git a/drivers/fpga/fpga_altera_agilex_bridge.c b/drivers/fpga/fpga_altera_agilex_bridge.c new file mode 100644 index 00000000000..b593cc1a5d3 --- /dev/null +++ b/drivers/fpga/fpga_altera_agilex_bridge.c @@ -0,0 +1,479 @@ +/* + * Copyright (c) 2024, Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT altr_socfpga_agilex_bridge + +#include +#include +#include +#include +#include +#include +#include "fpga_altera_agilex_bridge.h" + +LOG_MODULE_REGISTER(fpga_altera); + +struct fpga_bridge_dev_data { + /* SiP SVC controller */ + struct sip_svc_controller *mailbox_smc_dev; + /* SiP SVC client token id */ + uint32_t mailbox_client_token; +}; + +#define MAX_TIMEOUT_MSECS (1 * 1000UL) + +/** + * @brief Open SiP SVC client session + * + * @return 0 on success or negative value on failure + */ +static int32_t svc_client_open(const struct device *dev) +{ + if (!dev) { + LOG_ERR("No such device found"); + return -ENODEV; + } + + struct fpga_bridge_dev_data *const data = (struct fpga_bridge_dev_data *const)(dev->data); + + if ((!data->mailbox_smc_dev) || (data->mailbox_client_token == 0)) { + LOG_ERR("Mailbox client is not registered"); + return -ENODEV; + } + + if (sip_svc_open(data->mailbox_smc_dev, data->mailbox_client_token, + K_MSEC(MAX_TIMEOUT_MSECS))) { + LOG_ERR("Mailbox client open fail"); + return -ENODEV; + } + + return 0; +} + +/** + * @brief Close the svc client + * + * @return 0 on success or negative value on fail + */ +static int32_t svc_client_close(const struct device *dev) +{ + int32_t err; + uint32_t cmd_size = sizeof(uint32_t); + struct sip_svc_request request; + + if (!dev) { + LOG_ERR("No such device found"); + return -ENODEV; + } + + struct fpga_bridge_dev_data *const data = (struct fpga_bridge_dev_data *const)(dev->data); + + uint32_t *cmd_addr = (uint32_t *)k_malloc(cmd_size); + + if (!cmd_addr) { + return -ENOMEM; + } + + /* Fill the SiP SVC buffer with CANCEL request */ + *cmd_addr = MAILBOX_CANCEL_COMMAND; + + request.header = SIP_SVC_PROTO_HEADER(SIP_SVC_PROTO_CMD_ASYNC, 0); + request.a0 = SMC_FUNC_ID_MAILBOX_SEND_COMMAND; + request.a1 = 0; + request.a2 = (uint64_t)cmd_addr; + request.a3 = (uint64_t)cmd_size; + request.a4 = 0; + request.a5 = 0; + request.a6 = 0; + request.a7 = 0; + request.resp_data_addr = (uint64_t)NULL; + request.resp_data_size = 0; + request.priv_data = NULL; + + err = sip_svc_close(data->mailbox_smc_dev, data->mailbox_client_token, &request); + if (err) { + k_free(cmd_addr); + LOG_ERR("Mailbox client close fail (%d)", err); + } + + return err; +} + +/** + * @brief Call back function which we receive when we send the data + * based on the current stage it will collect the data + * + * @param[in] c_token Token id for our svc services + * @param[in] response Buffer will contain the response + * + * @return void + */ +static void smc_callback(uint32_t c_token, struct sip_svc_response *response) +{ + if (response == NULL) { + return; + } + + uint32_t *resp_data = NULL; + uint32_t resp_len = 0; + uint32_t mbox_idx = 0; + + struct sip_svc_private_data *private_data = + (struct sip_svc_private_data *)response->priv_data; + union mailbox_response_header response_header; + + LOG_DBG("SiP SVC callback"); + + LOG_DBG("\tresponse data below:"); + LOG_DBG("\theader=%08x", response->header); + LOG_DBG("\ta0=%016lx", response->a0); + LOG_DBG("\ta1=%016lx", response->a1); + LOG_DBG("\ta2=%016lx", response->a2); + LOG_DBG("\ta3=%016lx", response->a3); + + private_data->response.header = response->header; + private_data->response.a0 = response->a0; + private_data->response.a1 = response->a1; + private_data->response.a2 = response->a2; + private_data->response.a3 = response->a3; + private_data->response.resp_data_size = response->resp_data_size; + + /* Condition to check only for the mailbox command not for the non-mailbox command */ + if (response->resp_data_size) { + resp_data = (uint32_t *)response->resp_data_addr; + resp_len = response->resp_data_size / 4; + private_data->mbox_response_len = resp_len; + if (resp_data && resp_len) { + response_header = (union mailbox_response_header)resp_data[0]; + private_data->mbox_response_data = + (uint32_t *)k_malloc(sizeof(uint32_t) * resp_len); + for (mbox_idx = 0; mbox_idx < resp_len; mbox_idx++) { + LOG_DBG("\t\t[%4d] %08x", mbox_idx, resp_data[mbox_idx]); + private_data->mbox_response_data[mbox_idx] = resp_data[mbox_idx]; + } + } else { + LOG_ERR("\t\tInvalid addr (%p) or len (%d)", resp_data, resp_len); + } + } + /* Condition for non-mailbox command*/ + else { + LOG_DBG("Response Data size is zero !!"); + } + + /* Client only responsible to free the response data memory space, + * the command data memory space had been freed by SiP SVC service. + */ + if (response->resp_data_addr) { + LOG_DBG("\tFree response memory %p", (char *)response->resp_data_addr); + k_free((char *)response->resp_data_addr); + } + + k_sem_give(&(private_data->smc_sem)); +} + +/** + * @brief Send the data to SiP SVC service layer + * based on the command type further data will be send to SDM using mailbox + * + * @param[in] cmd_type Command type (Mailbox or Non-Mailbox) + * @param[in] function_identifier Function identifier for each command type + * @param[in] cmd_request + * @param[in] private_data + * + * @return 0 on success or negative value on fail + */ +static int32_t smc_send(const struct device *dev, uint32_t cmd_type, uint64_t function_identifier, + uint32_t *cmd_request, struct sip_svc_private_data *private_data) +{ + int32_t trans_id = 0; + uint32_t *cmd_addr = NULL; + uint32_t *resp_addr = NULL; + struct sip_svc_request request; + + if (!dev) { + LOG_ERR("No such device found"); + return -ENODEV; + } + + struct fpga_bridge_dev_data *const data = (struct fpga_bridge_dev_data *const)(dev->data); + + if (!data->mailbox_smc_dev) { + LOG_ERR("Mailbox client is not registered"); + return -ENODEV; + } + + if (cmd_type == SIP_SVC_PROTO_CMD_ASYNC) { + cmd_addr = (uint32_t *)k_malloc(FPGA_MB_CMD_ADDR_MEM_SIZE); + if (!cmd_addr) { + LOG_ERR("Failed to allocate command memory"); + return -ENOMEM; + } + cmd_addr[MBOX_CMD_HEADER_INDEX] = + MBOX_REQUEST_HEADER(cmd_request[SMC_REQUEST_A2_INDEX], 0, 0); + resp_addr = (uint32_t *)k_malloc(FPGA_MB_RESPONSE_MEM_SIZE); + if (!resp_addr) { + k_free(cmd_addr); + return -ENOMEM; + } + + request.a2 = (uint64_t)cmd_addr; + request.a3 = sizeof(uint32_t); + request.resp_data_addr = (uint64_t)resp_addr; + request.resp_data_size = FPGA_MB_RESPONSE_MEM_SIZE; + +#if defined(CONFIG_LOG) + for (int32_t mbox_idx = 0; mbox_idx < request.a3 / 4; mbox_idx++) { + LOG_DBG("\t [%d ] %08x", mbox_idx, cmd_addr[mbox_idx]); + } +#endif + + } else { + request.a2 = cmd_request[SMC_REQUEST_A2_INDEX]; + request.a3 = cmd_request[SMC_REQUEST_A3_INDEX]; + request.resp_data_addr = 0; + request.resp_data_size = 0; + } + + /* Fill SiP SVC request buffer */ + request.header = SIP_SVC_PROTO_HEADER(cmd_type, 0); + request.a0 = function_identifier; + request.a1 = 0; + request.a4 = 0; + request.a5 = 0; + request.a6 = 0; + request.a7 = 0; + request.priv_data = (void *)private_data; + + /* Send SiP SVC request */ + trans_id = sip_svc_send(data->mailbox_smc_dev, data->mailbox_client_token, &request, + smc_callback); + + if (trans_id == SIP_SVC_ID_INVALID) { + LOG_ERR("SiP SVC send request fail"); + return -EBUSY; + } + + return 0; +} + +/* Validate the Reconfig status response */ +static int32_t fpga_reconfig_status_validate(struct fpga_config_status *reconfig_status_resp) +{ + uint32_t ret = 0; + + /* Check for any error */ + ret = reconfig_status_resp->state; + if (ret == MBOX_CFGSTAT_VAB_BS_PREAUTH) { + return MBOX_CONFIG_STATUS_STATE_CONFIG; + } + + if (ret && ret != MBOX_CONFIG_STATUS_STATE_CONFIG) + return ret; + + /* Make sure nStatus is not 0 */ + ret = reconfig_status_resp->pin_status.pin_status; + if (!(ret & RECONFIG_PIN_STATUS_NSTATUS)) + return MBOX_CFGSTAT_STATE_ERROR_HARDWARE; + + ret = reconfig_status_resp->soft_function_status; + if ((ret & RECONFIG_SOFTFUNC_STATUS_CONF_DONE) && + (ret & RECONFIG_SOFTFUNC_STATUS_INIT_DONE) && !reconfig_status_resp->state) + return 0; /* Configuration success */ + + return MBOX_CONFIG_STATUS_STATE_CONFIG; +} + +/* Will send the SMC command to check the status of the FPGA */ +static int32_t fpga_config_ready_check(const struct device *dev) +{ + uint32_t smc_cmd[2] = {0}; + int32_t ret = 0; + struct sip_svc_private_data priv_data; + + /* Initialize the semaphore */ + k_sem_init(&(priv_data.smc_sem), 0, 1); + + smc_cmd[SMC_REQUEST_A2_INDEX] = FPGA_CONFIG_STATUS; + smc_cmd[SMC_REQUEST_A3_INDEX] = 0; + + /* Sending the FPGA config status mailbox command */ + ret = smc_send(dev, SIP_SVC_PROTO_CMD_ASYNC, SMC_FUNC_ID_MAILBOX_SEND_COMMAND, smc_cmd, + &priv_data); + if (ret) { + LOG_ERR("Failed to Send the Mailbox Command !!"); + return -ECANCELED; + } + + k_sem_take(&(priv_data.smc_sem), K_FOREVER); + + /* Verify the SMC response */ + if (!priv_data.response.resp_data_size && + priv_data.mbox_response_len != FPGA_CONFIG_STATUS_RESPONSE_LEN) { + return -EINVAL; + } + + /* Verify the FPGA config status response */ + ret = fpga_reconfig_status_validate( + (struct fpga_config_status *)priv_data.mbox_response_data); + + k_free(priv_data.mbox_response_data); + + return ret; +} + +static int32_t socfpga_bridges_reset(const struct device *dev, uint32_t enable) +{ + uint32_t smc_cmd[2] = {0}; + int ret = 0; + struct sip_svc_private_data priv_data; + + if (!dev) { + LOG_ERR("No such device found"); + return -ENODEV; + } + + /* Initialize the semaphore */ + k_sem_init(&(priv_data.smc_sem), 0, 1); + + smc_cmd[SMC_REQUEST_A2_INDEX] = FIELD_GET(BIT(0), enable); + + smc_cmd[SMC_REQUEST_A2_INDEX] |= BIT(1); + smc_cmd[SMC_REQUEST_A3_INDEX] = BRIDGE_MASK; + + ret = smc_send(dev, SIP_SVC_PROTO_CMD_SYNC, SMC_FUNC_ID_SET_HPS_BRIDGES, smc_cmd, + &priv_data); + if (ret) { + LOG_ERR("Failed to send the smc Command !!"); + return ret; + } + + /* Wait for the SiP SVC callback */ + k_sem_take(&(priv_data.smc_sem), K_FOREVER); + + /* Check error code */ + if (priv_data.response.a0) { + ret = -ENOMSG; + } + + return ret; +} + +static int altera_fpga_on(const struct device *dev) +{ + int32_t ret = 0; + + if (!dev) { + LOG_ERR("No such device found"); + return -ENODEV; + } + + /* Opening SIP SVC session */ + ret = svc_client_open(dev); + if (ret) { + LOG_ERR("Client open Failed!"); + return ret; + } + + /* Check FPGA status before bridge enable/disable */ + ret = fpga_config_ready_check(dev); + if (ret) { + LOG_ERR("FPGA not ready. Bridge reset aborted!"); + svc_client_close(dev); + return -EIO; + } + + /* Bridge reset */ + ret = socfpga_bridges_reset(dev, 0x01); + if (ret) { + LOG_ERR("Bridge reset failed"); + } + + /* Ignoring the return value to return bridge reset status */ + if (svc_client_close(dev)) { + LOG_ERR("Unregistering & Closing failed"); + } + + return ret; +} + +static int altera_fpga_off(const struct device *dev) +{ + int32_t ret = 0; + + if (!dev) { + LOG_ERR("No such device found"); + return -ENODEV; + } + + /* Opening SIP SVC session */ + ret = svc_client_open(dev); + if (ret) { + LOG_ERR("Client open Failed!"); + return ret; + } + + /* Check FPGA status before bridge enable/disable */ + ret = fpga_config_ready_check(dev); + if (ret) { + LOG_ERR("FPGA not ready. Bridge reset aborted!"); + svc_client_close(dev); + return -EIO; + } + + /* Bridge reset */ + ret = socfpga_bridges_reset(dev, 0x00); + if (ret) { + LOG_ERR("Bridge reset failed"); + } + + /* Ignoring the return value to return bridge reset status */ + if (svc_client_close(dev)) { + LOG_ERR("Unregistering & Closing failed"); + } + + return ret; +} + +static int altera_fpga_init(const struct device *dev) +{ + if (!dev) { + LOG_ERR("No such device found"); + return -ENODEV; + } + + struct fpga_bridge_dev_data *const data = (struct fpga_bridge_dev_data *const)(dev->data); + + data->mailbox_smc_dev = sip_svc_get_controller("smc"); + if (!data->mailbox_smc_dev) { + LOG_ERR("Arm SiP service not found"); + return -ENODEV; + } + + data->mailbox_client_token = sip_svc_register(data->mailbox_smc_dev, NULL); + if (data->mailbox_client_token == SIP_SVC_ID_INVALID) { + data->mailbox_smc_dev = NULL; + LOG_ERR("Mailbox client register fail"); + return -EINVAL; + } + + return 0; +} + +static const struct fpga_driver_api altera_fpga_api = { + .on = altera_fpga_on, + .off = altera_fpga_off, +}; + +#define CREATE_ALTERA_FPGA_BRIDGE_DEV(inst) \ + static struct fpga_bridge_dev_data fpga_bridge_data_##inst; \ + DEVICE_DT_INST_DEFINE(inst, \ + altera_fpga_init, \ + NULL, &fpga_bridge_data_##inst, \ + NULL, POST_KERNEL, \ + CONFIG_FPGA_INIT_PRIORITY, \ + &altera_fpga_api); \ + +DT_INST_FOREACH_STATUS_OKAY(CREATE_ALTERA_FPGA_BRIDGE_DEV); diff --git a/drivers/fpga/fpga_altera_agilex_bridge.h b/drivers/fpga/fpga_altera_agilex_bridge.h new file mode 100644 index 00000000000..7ec71c064f8 --- /dev/null +++ b/drivers/fpga/fpga_altera_agilex_bridge.h @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2024, Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_SUBSYS_FPGA_BRIDGE_INTEL_H_ +#define ZEPHYR_SUBSYS_FPGA_BRIDGE_INTEL_H_ + +#include + +/* Mask for FPGA-HPS bridges */ +#define BRIDGE_MASK 0x0F +/* Mailbox command header index */ +#define MBOX_CMD_HEADER_INDEX 0x00 +/* Mailbox command memory size */ +#define FPGA_MB_CMD_ADDR_MEM_SIZE 20 +/* Mailbox command response memory size */ +#define FPGA_MB_RESPONSE_MEM_SIZE 20 +/* Config status response length */ +#define FPGA_CONFIG_STATUS_RESPONSE_LEN 0x07 + +#define MBOX_CMD_CODE_OFFSET 0x00 +#define MBOX_CMD_ID_MASK 0x7FF + +#define MBOX_CMD_MODE_OFFSET 0x0B +#define MBOX_CMD_MODE_MASK 0x800 + +#define MBOX_DATA_LEN_OFFSET 0x0C +#define MBOX_DATA_LEN_MASK 0xFFF000 + +#define RECONFIG_DIRECT_COUNT_OFFSET 0x00 +#define RECONFIG_DIRECT_COUNT_MASK 0xFF + +#define RECONFIG_INDIRECT_ARG_OFFSET 0x08 +#define RECONFIG_INDIRECT_COUNT_MASK 0xFF00 + +#define RECONFIG_INDIRECT_RESPONSE_OFFSET 0x10 +#define RECONFIG_RESPONSE_COUNT_MASK 0xFF0000 + +#define RECONFIG_DATA_MB_CMD_SIZE 0x10 +#define RECONFIG_DATA_MB_CMD_INDIRECT_MODE 0x01 + +#define RECONFIG_DATA_MB_CMD_LENGTH 0x03 + +#define RECONFIG_DATA_MB_CMD_DIRECT_COUNT 0x00 +#define RECONFIG_DATA_MB_CMD_INDIRECT_ARG 0x01 +#define RECONFIG_DATA_MB_CMD_INDIRECT_RESPONSE 0x00 +#define RECONFIG_STATUS_INTERVAL_DELAY_US 1000 +#define RECONFIG_STATUS_RETRY_COUNT 20 + +#define MBOX_CONFIG_STATUS_STATE_CONFIG 0x10000000 +#define MBOX_CFGSTAT_VAB_BS_PREAUTH 0x20000000 + +#define FPGA_NOT_CONFIGURED_ERROR 0x02000004 + +#define MBOX_CFGSTAT_STATE_ERROR_HARDWARE 0xF0000005 +#define RECONFIG_SOFTFUNC_STATUS_CONF_DONE BIT(0) +#define RECONFIG_SOFTFUNC_STATUS_INIT_DONE BIT(1) +#define RECONFIG_SOFTFUNC_STATUS_SEU_ERROR BIT(3) +#define RECONFIG_PIN_STATUS_NSTATUS BIT(31) + +#define MBOX_REQUEST_HEADER(cmd_id, cmd_mode, len) \ + ((cmd_id << MBOX_CMD_CODE_OFFSET) & (MBOX_CMD_ID_MASK)) | \ + ((cmd_mode << MBOX_CMD_MODE_OFFSET) & (MBOX_CMD_MODE_MASK)) | \ + ((len << MBOX_DATA_LEN_OFFSET) & (MBOX_DATA_LEN_MASK)) + +#define MBOX_RECONFIG_REQUEST_DATA_FORMAT(direct_count, indirect_arg_count, response_arg_count) \ + ((direct_count << RECONFIG_DIRECT_COUNT_OFFSET) & (RECONFIG_DIRECT_COUNT_MASK)) | \ + ((indirect_arg_count << RECONFIG_INDIRECT_ARG_OFFSET) & \ + (RECONFIG_INDIRECT_COUNT_MASK)) | \ + ((response_arg_count << RECONFIG_INDIRECT_RESPONSE_OFFSET) & \ + (RECONFIG_RESPONSE_COUNT_MASK)) + +union mailbox_response_header { + /* Header of the config status response */ + uint32_t header; + + struct { + /* error_code ā€“ Field provides a basic description of whether the command + * succeeded or not. A successful response returns an error code of 0x0, + * non-zero values indicate failure + */ + uint32_t error_code : 11; + /* indirect_bit - Field indicates an indirect command */ + uint32_t indirect_bit : 1; + /* data_length - Field counts the number of word arguments which follow the + * response header word. The meaning of these words depends on the command + * code. Units are words + */ + uint32_t data_length : 11; + /* reserve bit */ + uint32_t reserved_bit : 1; + /* id - Field is returned unchanged from the matching command header and is + * useful for matching responses to commands along with the CLIENT + */ + uint32_t id : 4; + /* client_id - Field is returned unchanged from the matching command header and + * is useful for matching responses to commands along with the ID + */ + uint32_t client_id : 4; + } mailbox_resp_header; +}; + +union config_status_version { + /* Version of the config status response */ + uint32_t version; + + struct { + /* update number bits */ + uint32_t update_number : 8; + /* minor acds release number bits */ + uint32_t minor_acds_release_number : 8; + /* major acds release number bits */ + uint32_t major_acds_release_number : 8; + /* qspi flash index bits */ + uint32_t qspi_flash_index : 8; + } response_version_member; +}; + +union config_status_pin_status { + uint32_t pin_status; + + struct { + /* msel bits */ + uint32_t msel : 4; + /* pmf data bits */ + uint32_t pmf_data : 4; + /* reserve bits */ + uint32_t reserved_bit : 22; + /* nconfig bits */ + uint32_t nconfig : 1; + /* nconfig_status bits */ + uint32_t nconfig_status : 1; + } pin_status_member; +}; + +/* Struct to store the fpga_config_status */ +struct fpga_config_status { + /* Response header */ + union mailbox_response_header header; + /* Config state idle or config mode */ + uint32_t state; + /* Version number */ + union config_status_version version; + /* Pin status */ + union config_status_pin_status pin_status; + /* Soft function status details */ + uint32_t soft_function_status; + /* Location in the bitstream where the error occurred */ + uint32_t error_location; + /* Data is non-zero only for certain errors. The contents are highly dependent + * on which error was reported. The meaning of this data will not be made available to + * customers and can only be interpreted by investigating the source code directly + */ + uint32_t error_details; +}; + +enum smc_cmd_code { + /* SMC COMMAND ID to disable all the bridges */ + FPGA_ALL_BRIDGE_DISABLE = 0x00, + /* SMC COMMAND ID to enable all the bridges */ + FPGA_ALL_BRIDGE_ENABLE = 0x01, + /* SMC Cancel Command */ + FPGA_CANCEL = 0x03, + /* SMC COMMAND ID to check Reconfig status to SDM via mailbox */ + FPGA_CONFIG_STATUS = 0x04, + /* SMC COMMAND ID to check Reconfig status to SDM via mailbox */ + FPGA_RECONFIG_STATUS = 0x09 +}; + +enum mbox_reconfig_status_resp { + /* Mailbox reconfig status header */ + MBOX_RECONFIG_STATUS_HEADER, + /* Mailbox reconfig status state */ + MBOX_RECONFIG_STATUS_STATE, + /* Mailbox reconfig status version */ + MBOX_RECONFIG_STATUS_VERSION, + /* Mailbox reconfig status pin status */ + MBOX_RECONFIG_STATUS_PIN_STATUS, + /* Mailbox reconfig status soft function */ + MBOX_RECONFIG_STATUS_SOFT_FUNCTION, + /* Mailbox reconfig status error location */ + MBOX_RECONFIG_STATUS_ERROR_LOCATION, + /* Mailbox reconfig status error details */ + MBOX_RECONFIG_STATUS_ERROR_DETAILS +}; + +enum smc_request { + /* SMC request parameter a2 index*/ + SMC_REQUEST_A2_INDEX = 0x00, + /* SMC request parameter a3 index */ + SMC_REQUEST_A3_INDEX = 0x01 +}; + +/* SIP SVC response private data */ +struct sip_svc_private_data { + struct sip_svc_response response; + uint32_t *mbox_response_data; + uint32_t mbox_response_len; + struct k_sem smc_sem; + struct fpga_config_status config_status; +}; + +#endif diff --git a/drivers/fpga/fpga_shell.c b/drivers/fpga/fpga_shell.c index 7969e231c64..af1a28eb8e1 100644 --- a/drivers/fpga/fpga_shell.c +++ b/drivers/fpga/fpga_shell.c @@ -93,8 +93,11 @@ static int cmd_load(const struct shell *sh, size_t argc, char **argv) shell_print(sh, "%s: loading bitstream", dev->name); - fpga_load(dev, (uint32_t *)strtol(argv[2], NULL, 0), - (uint32_t)atoi(argv[3])); + err = fpga_load(dev, (uint32_t *)strtol(argv[2], NULL, 0), + (uint32_t)atoi(argv[3])); + if (err) { + shell_error(sh, "Error: %d", err); + } return err; } diff --git a/drivers/gnss/CMakeLists.txt b/drivers/gnss/CMakeLists.txt index 32346282c04..05192ca5400 100644 --- a/drivers/gnss/CMakeLists.txt +++ b/drivers/gnss/CMakeLists.txt @@ -4,6 +4,7 @@ zephyr_library() zephyr_library_sources(gnss_publish.c) zephyr_library_sources_ifdef(CONFIG_GNSS_DUMP gnss_dump.c) +zephyr_library_sources_ifdef(CONFIG_GNSS_EMUL gnss_emul.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) @@ -11,3 +12,4 @@ zephyr_library_sources_ifdef(CONFIG_GNSS_NMEA_GENERIC gnss_nmea_generic.c) zephyr_library_sources_ifdef(CONFIG_GNSS_QUECTEL_LCX6G gnss_quectel_lcx6g.c) zephyr_library_sources_ifdef(CONFIG_GNSS_U_BLOX_M10 gnss_u_blox_m10.c) zephyr_library_sources_ifdef(CONFIG_GNSS_U_BLOX_PROTOCOL gnss_u_blox_protocol/gnss_u_blox_protocol.c) +zephyr_library_sources_ifdef(CONFIG_GNSS_LUATOS_AIR530Z gnss_luatos_air530z.c) diff --git a/drivers/gnss/Kconfig b/drivers/gnss/Kconfig index db9762bd87b..94aaf7a02ba 100644 --- a/drivers/gnss/Kconfig +++ b/drivers/gnss/Kconfig @@ -70,8 +70,10 @@ module = GNSS module-str = gnss source "subsys/logging/Kconfig.template.log_config" +rsource "Kconfig.emul" rsource "Kconfig.generic" rsource "Kconfig.quectel_lcx6g" rsource "Kconfig.u_blox_m10" +rsource "Kconfig.luatos_air530z" endif diff --git a/drivers/gnss/Kconfig.emul b/drivers/gnss/Kconfig.emul new file mode 100644 index 00000000000..9ae9a406472 --- /dev/null +++ b/drivers/gnss/Kconfig.emul @@ -0,0 +1,10 @@ +# Copyright (c) 2024 Trackunit Corporation +# SPDX-License-Identifier: Apache-2.0 + +config GNSS_EMUL + bool "Emulated GNSS driver" + default y + depends on DT_HAS_ZEPHYR_GNSS_EMUL_ENABLED + select TIMEOUT_64BIT + help + Enable emulated GNSS driver. diff --git a/drivers/gnss/Kconfig.generic b/drivers/gnss/Kconfig.generic index 47fbd4a7c6c..bbcae309a31 100644 --- a/drivers/gnss/Kconfig.generic +++ b/drivers/gnss/Kconfig.generic @@ -15,6 +15,8 @@ config GNSS_NMEA_GENERIC help Generic NMEA based GNSS device. +if GNSS_NMEA_GENERIC + config GNSS_NMEA_GENERIC_SATELLITES_COUNT int "Maximum satellite count" depends on GNSS_SATELLITES @@ -24,3 +26,5 @@ config GNSS_NMEA_GENERIC_SATELLITES_COUNT 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. + +endif diff --git a/drivers/gnss/Kconfig.luatos_air530z b/drivers/gnss/Kconfig.luatos_air530z new file mode 100644 index 00000000000..958521af1fd --- /dev/null +++ b/drivers/gnss/Kconfig.luatos_air530z @@ -0,0 +1,26 @@ +# Copyright 2024 JerĆ³nimo AgullĆ³ +# SPDX-License-Identifier: Apache-2.0 + +config GNSS_LUATOS_AIR530Z + bool "Luatos Air530z GNSS device" + default y + depends on GNSS + depends on DT_HAS_LUATOS_AIR530Z_ENABLED + select MODEM_MODULES + select MODEM_BACKEND_UART + select MODEM_CHAT + select GNSS_PARSE + select GNSS_NMEA0183 + select GNSS_NMEA0183_MATCH + help + Enable Luatos Air530z GNSS driver. + +config GNSS_LUATOS_AIR530Z_SATELLITES_COUNT + int "Maximum satellite count" + depends on GNSS_SATELLITES + default 24 + help + Maximum number of satellites 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/gnss_emul.c b/drivers/gnss/gnss_emul.c new file mode 100644 index 00000000000..553736f0ba7 --- /dev/null +++ b/drivers/gnss/gnss_emul.c @@ -0,0 +1,510 @@ +/* + * Copyright (c) 2024 Trackunit Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#undef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200809L /* Required for gmtime_r */ + +#include +#include +#include +#include +#include + +#include +#include + +#include +LOG_MODULE_REGISTER(gnss_emul, CONFIG_GNSS_LOG_LEVEL); + +#define DT_DRV_COMPAT zephyr_gnss_emul + +#define GNSS_EMUL_DEFAULT_FIX_INTERVAL_MS 1000 +#define GNSS_EMUL_MIN_FIX_INTERVAL_MS 100 +#define GNSS_EMUL_FIX_ACQUIRE_TIME_MS 5000 +#define GNSS_EMUL_DEFAULT_NAV_MODE GNSS_NAVIGATION_MODE_BALANCED_DYNAMICS +#define GNSS_EMUL_SUPPORTED_SYSTEMS_MASK 0xFF +#define GNSS_EMUL_SUPPORTED_SYSTEMS_COUNT 8 +#define GNSS_EMUL_DEFAULT_ENABLED_SYSTEMS_MASK GNSS_EMUL_SUPPORTED_SYSTEMS_MASK + +struct gnss_emul_data { + const struct device *dev; + struct k_work_delayable data_dwork; + struct k_sem lock; + int64_t resume_timestamp_ms; + int64_t fix_timestamp_ms; + uint32_t fix_interval_ms; + enum gnss_navigation_mode nav_mode; + gnss_systems_t enabled_systems; + struct gnss_data data; + +#ifdef CONFIG_GNSS_SATELLITES + struct gnss_satellite satellites[GNSS_EMUL_SUPPORTED_SYSTEMS_COUNT]; + uint8_t satellites_len; +#endif +}; + +static void gnss_emul_lock_sem(const struct device *dev) +{ + struct gnss_emul_data *data = dev->data; + + (void)k_sem_take(&data->lock, K_FOREVER); +} + +static void gnss_emul_unlock_sem(const struct device *dev) +{ + struct gnss_emul_data *data = dev->data; + + k_sem_give(&data->lock); +} + +static void gnss_emul_update_fix_timestamp(const struct device *dev, bool resuming) +{ + struct gnss_emul_data *data = dev->data; + int64_t uptime_ms; + + uptime_ms = k_uptime_get(); + data->fix_timestamp_ms = ((uptime_ms / data->fix_interval_ms) + 1) * data->fix_interval_ms; + + if (resuming) { + data->resume_timestamp_ms = data->fix_timestamp_ms; + } +} + +static bool gnss_emul_fix_is_acquired(const struct device *dev) +{ + struct gnss_emul_data *data = dev->data; + int64_t time_since_resume; + + time_since_resume = data->fix_timestamp_ms - data->resume_timestamp_ms; + return time_since_resume >= GNSS_EMUL_FIX_ACQUIRE_TIME_MS; +} + +#ifdef CONFIG_PM_DEVICE +static void gnss_emul_clear_fix_timestamp(const struct device *dev) +{ + struct gnss_emul_data *data = dev->data; + + data->fix_timestamp_ms = 0; +} +#endif + +static void gnss_emul_schedule_work(const struct device *dev) +{ + struct gnss_emul_data *data = dev->data; + + k_work_schedule(&data->data_dwork, K_TIMEOUT_ABS_MS(data->fix_timestamp_ms)); +} + +static bool gnss_emul_cancel_work(const struct device *dev) +{ + struct gnss_emul_data *data = dev->data; + struct k_work_sync sync; + + return k_work_cancel_delayable_sync(&data->data_dwork, &sync); +} + +static bool gnss_emul_is_resumed(const struct device *dev) +{ + struct gnss_emul_data *data = dev->data; + + return data->fix_timestamp_ms > 0; +} + +static void gnss_emul_lock(const struct device *dev) +{ + gnss_emul_lock_sem(dev); + gnss_emul_cancel_work(dev); +} + +static void gnss_emul_unlock(const struct device *dev) +{ + if (gnss_emul_is_resumed(dev)) { + gnss_emul_schedule_work(dev); + } + + gnss_emul_unlock_sem(dev); +} + +static int gnss_emul_set_fix_rate(const struct device *dev, uint32_t fix_interval_ms) +{ + struct gnss_emul_data *data = dev->data; + + if (fix_interval_ms < GNSS_EMUL_MIN_FIX_INTERVAL_MS) { + return -EINVAL; + } + + data->fix_interval_ms = fix_interval_ms; + return 0; +} + +static int gnss_emul_get_fix_rate(const struct device *dev, uint32_t *fix_interval_ms) +{ + struct gnss_emul_data *data = dev->data; + + *fix_interval_ms = data->fix_interval_ms; + return 0; +} + +static int gnss_emul_set_navigation_mode(const struct device *dev, + enum gnss_navigation_mode mode) +{ + struct gnss_emul_data *data = dev->data; + + if (mode > GNSS_NAVIGATION_MODE_HIGH_DYNAMICS) { + return -EINVAL; + } + + data->nav_mode = mode; + return 0; +} + +static int gnss_emul_get_navigation_mode(const struct device *dev, + enum gnss_navigation_mode *mode) +{ + struct gnss_emul_data *data = dev->data; + + *mode = data->nav_mode; + return 0; +} + +static int gnss_emul_set_enabled_systems(const struct device *dev, gnss_systems_t systems) +{ + struct gnss_emul_data *data = dev->data; + + if (systems > GNSS_EMUL_SUPPORTED_SYSTEMS_MASK) { + return -EINVAL; + } + + data->enabled_systems = systems; + return 0; +} + +static int gnss_emul_get_enabled_systems(const struct device *dev, gnss_systems_t *systems) +{ + struct gnss_emul_data *data = dev->data; + + *systems = data->enabled_systems; + return 0; +} + +#ifdef CONFIG_PM_DEVICE +static void gnss_emul_resume(const struct device *dev) +{ + gnss_emul_update_fix_timestamp(dev, true); +} + +static void gnss_emul_suspend(const struct device *dev) +{ + gnss_emul_clear_fix_timestamp(dev); +} + +static int gnss_emul_pm_action(const struct device *dev, enum pm_device_action action) +{ + int ret = 0; + + gnss_emul_lock(dev); + + switch (action) { + case PM_DEVICE_ACTION_SUSPEND: + gnss_emul_suspend(dev); + break; + + case PM_DEVICE_ACTION_RESUME: + gnss_emul_resume(dev); + break; + + default: + ret = -ENOTSUP; + break; + } + + gnss_emul_unlock(dev); + return ret; +} +#endif + +static int gnss_emul_api_set_fix_rate(const struct device *dev, uint32_t fix_interval_ms) +{ + int ret = -ENODEV; + + gnss_emul_lock(dev); + + if (!gnss_emul_is_resumed(dev)) { + goto unlock_return; + } + + ret = gnss_emul_set_fix_rate(dev, fix_interval_ms); + +unlock_return: + gnss_emul_unlock(dev); + return ret; +} + +static int gnss_emul_api_get_fix_rate(const struct device *dev, uint32_t *fix_interval_ms) +{ + int ret = -ENODEV; + + gnss_emul_lock(dev); + + if (!gnss_emul_is_resumed(dev)) { + goto unlock_return; + } + + ret = gnss_emul_get_fix_rate(dev, fix_interval_ms); + +unlock_return: + gnss_emul_unlock(dev); + return ret; +} + +static int gnss_emul_api_set_navigation_mode(const struct device *dev, + enum gnss_navigation_mode mode) +{ + int ret = -ENODEV; + + gnss_emul_lock(dev); + + if (!gnss_emul_is_resumed(dev)) { + goto unlock_return; + } + + ret = gnss_emul_set_navigation_mode(dev, mode); + +unlock_return: + gnss_emul_unlock(dev); + return ret; +} + +static int gnss_emul_api_get_navigation_mode(const struct device *dev, + enum gnss_navigation_mode *mode) +{ + int ret = -ENODEV; + + gnss_emul_lock(dev); + + if (!gnss_emul_is_resumed(dev)) { + goto unlock_return; + } + + ret = gnss_emul_get_navigation_mode(dev, mode); + +unlock_return: + gnss_emul_unlock(dev); + return ret; +} + +static int gnss_emul_api_set_enabled_systems(const struct device *dev, gnss_systems_t systems) +{ + int ret = -ENODEV; + + gnss_emul_lock(dev); + + if (!gnss_emul_is_resumed(dev)) { + goto unlock_return; + } + + ret = gnss_emul_set_enabled_systems(dev, systems); + +unlock_return: + gnss_emul_unlock(dev); + return ret; +} + +static int gnss_emul_api_get_enabled_systems(const struct device *dev, gnss_systems_t *systems) +{ + int ret = -ENODEV; + + gnss_emul_lock(dev); + + if (!gnss_emul_is_resumed(dev)) { + goto unlock_return; + } + + ret = gnss_emul_get_enabled_systems(dev, systems); + +unlock_return: + gnss_emul_unlock(dev); + return ret; +} + +static int gnss_emul_api_get_supported_systems(const struct device *dev, gnss_systems_t *systems) +{ + *systems = GNSS_EMUL_SUPPORTED_SYSTEMS_MASK; + return 0; +} + +static struct gnss_driver_api api = { + .set_fix_rate = gnss_emul_api_set_fix_rate, + .get_fix_rate = gnss_emul_api_get_fix_rate, + .set_navigation_mode = gnss_emul_api_set_navigation_mode, + .get_navigation_mode = gnss_emul_api_get_navigation_mode, + .set_enabled_systems = gnss_emul_api_set_enabled_systems, + .get_enabled_systems = gnss_emul_api_get_enabled_systems, + .get_supported_systems = gnss_emul_api_get_supported_systems, +}; + +static void gnss_emul_clear_data(const struct device *dev) +{ + struct gnss_emul_data *data = dev->data; + + memset(&data->data, 0, sizeof(data->data)); +} + +static void gnss_emul_set_fix(const struct device *dev) +{ + struct gnss_emul_data *data = dev->data; + + data->data.info.satellites_cnt = 8; + data->data.info.hdop = 100; + data->data.info.fix_status = GNSS_FIX_STATUS_GNSS_FIX; + data->data.info.fix_quality = GNSS_FIX_QUALITY_GNSS_SPS; +} + +static void gnss_emul_set_utc(const struct device *dev) +{ + struct gnss_emul_data *data = dev->data; + time_t timestamp; + struct tm datetime; + uint16_t millisecond; + + timestamp = (time_t)(data->fix_timestamp_ms / 1000); + gmtime_r(×tamp, &datetime); + + millisecond = (uint16_t)(data->fix_timestamp_ms % 1000) + + (uint16_t)(datetime.tm_sec * 1000); + + data->data.utc.hour = datetime.tm_hour; + data->data.utc.millisecond = millisecond; + data->data.utc.minute = datetime.tm_min; + data->data.utc.month = datetime.tm_mon + 1; + data->data.utc.century_year = datetime.tm_year % 100; +} + +static void gnss_emul_set_nav_data(const struct device *dev) +{ + struct gnss_emul_data *data = dev->data; + + data->data.nav_data.latitude = 10000000000; + data->data.nav_data.longitude = -10000000000; + data->data.nav_data.bearing = 3000; + data->data.nav_data.speed = 0; + data->data.nav_data.altitude = 20000; +} + +#ifdef CONFIG_GNSS_SATELLITES +static void gnss_emul_clear_satellites(const struct device *dev) +{ + struct gnss_emul_data *data = dev->data; + + data->satellites_len = 0; +} + +static bool gnss_emul_system_enabled(const struct device *dev, uint8_t system_bit) +{ + struct gnss_emul_data *data = dev->data; + + return BIT(system_bit) & data->enabled_systems; +} + +static void gnss_emul_add_satellite(const struct device *dev, uint8_t system_bit) +{ + struct gnss_emul_data *data = dev->data; + + /* Unique values synthesized from GNSS system */ + data->satellites[data->satellites_len].prn = system_bit; + data->satellites[data->satellites_len].snr = system_bit + 20; + data->satellites[data->satellites_len].elevation = system_bit + 40; + data->satellites[data->satellites_len].azimuth = system_bit + 60; + data->satellites[data->satellites_len].system = BIT(system_bit); + data->satellites[data->satellites_len].is_tracked = true; + data->satellites_len++; +} + +static void gnss_emul_set_satellites(const struct device *dev) +{ + gnss_emul_clear_satellites(dev); + + for (uint8_t i = 0; i < GNSS_EMUL_SUPPORTED_SYSTEMS_COUNT; i++) { + if (!gnss_emul_system_enabled(dev, i)) { + continue; + } + + gnss_emul_add_satellite(dev, i); + } +} +#endif + +static void gnss_emul_work_handler(struct k_work *work) +{ + struct k_work_delayable *dwork = k_work_delayable_from_work(work); + struct gnss_emul_data *data = CONTAINER_OF(dwork, struct gnss_emul_data, data_dwork); + const struct device *dev = data->dev; + + if (!gnss_emul_fix_is_acquired(dev)) { + gnss_emul_clear_data(dev); + } else { + gnss_emul_set_fix(dev); + gnss_emul_set_utc(dev); + gnss_emul_set_nav_data(dev); + } + + gnss_publish_data(dev, &data->data); + +#ifdef CONFIG_GNSS_SATELLITES + gnss_emul_set_satellites(dev); + gnss_publish_satellites(dev, data->satellites, data->satellites_len); +#endif + + gnss_emul_update_fix_timestamp(dev, false); + gnss_emul_schedule_work(dev); +} + +static void gnss_emul_init_data(const struct device *dev) +{ + struct gnss_emul_data *data = dev->data; + + data->dev = dev; + k_sem_init(&data->lock, 1, 1); + k_work_init_delayable(&data->data_dwork, gnss_emul_work_handler); +} + +static int gnss_emul_init(const struct device *dev) +{ + gnss_emul_init_data(dev); + + if (pm_device_is_powered(dev)) { + gnss_emul_update_fix_timestamp(dev, true); + gnss_emul_schedule_work(dev); + } else { + pm_device_init_off(dev); + } + + return pm_device_runtime_enable(dev); +} + +#define GNSS_EMUL_NAME(inst, name) _CONCAT(name, inst) + +#define GNSS_EMUL_DEVICE(inst) \ + static struct gnss_emul_data GNSS_EMUL_NAME(inst, data) = { \ + .fix_interval_ms = GNSS_EMUL_DEFAULT_FIX_INTERVAL_MS, \ + .nav_mode = GNSS_EMUL_DEFAULT_NAV_MODE, \ + .enabled_systems = GNSS_EMUL_DEFAULT_ENABLED_SYSTEMS_MASK, \ + }; \ + \ + PM_DEVICE_DT_INST_DEFINE(inst, gnss_emul_pm_action); \ + \ + DEVICE_DT_INST_DEFINE( \ + inst, \ + gnss_emul_init, \ + PM_DEVICE_DT_INST_GET(inst), \ + &GNSS_EMUL_NAME(inst, data), \ + NULL, \ + POST_KERNEL, \ + CONFIG_GNSS_INIT_PRIORITY, \ + &api \ + ); + +DT_INST_FOREACH_STATUS_OKAY(GNSS_EMUL_DEVICE) diff --git a/drivers/gnss/gnss_luatos_air530z.c b/drivers/gnss/gnss_luatos_air530z.c new file mode 100644 index 00000000000..a24c8245ac3 --- /dev/null +++ b/drivers/gnss/gnss_luatos_air530z.c @@ -0,0 +1,364 @@ +/* + * Copyright (c) 2024 JerĆ³nimo AgullĆ³ + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#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(luatos_air530z, CONFIG_GNSS_LOG_LEVEL); + +#define DT_DRV_COMPAT luatos_air530z + +#define UART_RECV_BUF_SZ 128 +#define UART_TRANS_BUF_SZ 64 + +#define CHAT_RECV_BUF_SZ 256 +#define CHAT_ARGV_SZ 32 + +MODEM_CHAT_SCRIPT_CMDS_DEFINE(init_script_cmds, +#if CONFIG_GNSS_SATELLITES + /* receive only GGA, RMC and GSV NMEA messages */ + MODEM_CHAT_SCRIPT_CMD_RESP_NONE("$PCAS03,1,0,0,1,1,0,0,0,0,0,0,0,0*1F", 10), +#else + /* receive only GGA and RMC NMEA messages */ + MODEM_CHAT_SCRIPT_CMD_RESP_NONE("$PCAS03,1,0,0,0,1,0,0,0,0,0,0,0,0*1E", 10), +#endif +); + +MODEM_CHAT_SCRIPT_NO_ABORT_DEFINE(init_script, init_script_cmds, NULL, 5); + +struct gnss_luatos_air530z_config { + const struct device *uart; + const struct gpio_dt_spec on_off_gpio; + const int uart_baudrate; +}; + +struct gnss_luatos_air530z_data { + struct gnss_nmea0183_match_data match_data; +#if CONFIG_GNSS_SATELLITES + struct gnss_satellite satellites[CONFIG_GNSS_LUATOS_AIR530Z_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]; + uint8_t uart_backend_transmit_buf[UART_TRANS_BUF_SZ]; + + /* Modem chat */ + struct modem_chat chat; + uint8_t chat_receive_buf[CHAT_RECV_BUF_SZ]; + uint8_t chat_delimiter[2]; + uint8_t *chat_argv[CHAT_ARGV_SZ]; + + /* Dynamic chat script */ + uint8_t dynamic_separators_buf[2]; + uint8_t dynamic_request_buf[32]; + struct modem_chat_script_chat dynamic_script_chat; + struct modem_chat_script dynamic_script; + + struct k_sem 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 void luatos_air530z_lock(const struct device *dev) +{ + struct gnss_luatos_air530z_data *data = dev->data; + + (void)k_sem_take(&data->lock, K_FOREVER); +} + +static void luatos_air530z_unlock(const struct device *dev) +{ + struct gnss_luatos_air530z_data *data = dev->data; + + k_sem_give(&data->lock); +} + +static int gnss_luatos_air530z_init_nmea0183_match(const struct device *dev) +{ + struct gnss_luatos_air530z_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_luatos_air530z_init_pipe(const struct device *dev) +{ + const struct gnss_luatos_air530z_config *config = dev->config; + struct gnss_luatos_air530z_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 = sizeof(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 gnss_luatos_air530z_init_chat(const struct device *dev) +{ + struct gnss_luatos_air530z_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 = 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 luatos_air530z_init_dynamic_script(const struct device *dev) +{ + struct gnss_luatos_air530z_data *data = dev->data; + + /* Air530z doesn't respond to commands. Thus, response_matches_size = 0; */ + data->dynamic_script_chat.request = data->dynamic_request_buf; + data->dynamic_script_chat.response_matches = NULL; + data->dynamic_script_chat.response_matches_size = 0; + data->dynamic_script_chat.timeout = 0; + + data->dynamic_script.name = "PCAS"; + 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 = 5; +} + +static int gnss_luatos_air530z_init(const struct device *dev) +{ + struct gnss_luatos_air530z_data *data = dev->data; + const struct gnss_luatos_air530z_config *config = dev->config; + int ret; + + k_sem_init(&data->lock, 1, 1); + + ret = gnss_luatos_air530z_init_nmea0183_match(dev); + if (ret < 0) { + return ret; + } + + gnss_luatos_air530z_init_pipe(dev); + + ret = gnss_luatos_air530z_init_chat(dev); + if (ret < 0) { + return ret; + } + + luatos_air530z_init_dynamic_script(dev); + + 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; + } + + ret = modem_chat_run_script(&data->chat, &init_script); + if (ret < 0) { + LOG_ERR("Failed to run init_script"); + modem_pipe_close(data->uart_pipe); + return ret; + } + + /* setup on-off gpio for power management */ + if (!gpio_is_ready_dt(&config->on_off_gpio)) { + LOG_ERR("on-off GPIO device not ready"); + return -ENODEV; + } + + gpio_pin_configure_dt(&config->on_off_gpio, GPIO_OUTPUT_HIGH); + + return 0; +} + +static int luatos_air530z_pm_resume(const struct device *dev) +{ + struct gnss_luatos_air530z_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; + } + + ret = modem_chat_run_script(&data->chat, &init_script); + if (ret < 0) { + modem_pipe_close(data->uart_pipe); + return ret; + } + + return 0; +} + +static int luatos_air530z_pm_action(const struct device *dev, enum pm_device_action action) +{ + struct gnss_luatos_air530z_data *data = dev->data; + const struct gnss_luatos_air530z_config *config = dev->config; + int ret = -ENOTSUP; + + switch (action) { + case PM_DEVICE_ACTION_SUSPEND: + gpio_pin_set_dt(&config->on_off_gpio, 0); + ret = modem_pipe_close(data->uart_pipe); + break; + + case PM_DEVICE_ACTION_RESUME: + gpio_pin_set_dt(&config->on_off_gpio, 1); + ret = luatos_air530z_pm_resume(dev); + break; + + default: + break; + } + + return ret; +} + +static int luatos_air530z_set_fix_rate(const struct device *dev, uint32_t fix_interval_ms) +{ + struct gnss_luatos_air530z_data *data = dev->data; + int ret; + + if (fix_interval_ms < 100 || fix_interval_ms > 1000) { + return -EINVAL; + } + + luatos_air530z_lock(dev); + + ret = gnss_nmea0183_snprintk(data->dynamic_request_buf, sizeof(data->dynamic_request_buf), + "PCAS02,%u", fix_interval_ms); + + data->dynamic_script_chat.request_size = ret; + + ret = modem_chat_run_script(&data->chat, &data->dynamic_script); + if (ret < 0) { + goto unlock_return; + } + +unlock_return: + luatos_air530z_unlock(dev); + return ret; +} + +static int luatos_air530z_set_enabled_systems(const struct device *dev, gnss_systems_t systems) +{ + struct gnss_luatos_air530z_data *data = dev->data; + gnss_systems_t supported_systems; + uint8_t encoded_systems = 0; + int ret; + + supported_systems = (GNSS_SYSTEM_GPS | GNSS_SYSTEM_GLONASS | GNSS_SYSTEM_BEIDOU); + + if ((~supported_systems) & systems) { + return -EINVAL; + } + + luatos_air530z_lock(dev); + + WRITE_BIT(encoded_systems, 0, systems & GNSS_SYSTEM_GPS); + WRITE_BIT(encoded_systems, 1, systems & GNSS_SYSTEM_GLONASS); + WRITE_BIT(encoded_systems, 2, systems & GNSS_SYSTEM_BEIDOU); + + ret = gnss_nmea0183_snprintk(data->dynamic_request_buf, sizeof(data->dynamic_request_buf), + "PCAS04,%u", encoded_systems); + if (ret < 0) { + goto unlock_return; + } + + data->dynamic_script_chat.request_size = ret; + + ret = modem_chat_run_script(&data->chat, &data->dynamic_script); + if (ret < 0) { + goto unlock_return; + } + +unlock_return: + luatos_air530z_unlock(dev); + return ret; + +} + +static int luatos_air530z_get_supported_systems(const struct device *dev, gnss_systems_t *systems) +{ + *systems = (GNSS_SYSTEM_GPS | GNSS_SYSTEM_GLONASS | GNSS_SYSTEM_BEIDOU); + return 0; +} + +static struct gnss_driver_api gnss_api = { + .set_fix_rate = luatos_air530z_set_fix_rate, + .set_enabled_systems = luatos_air530z_set_enabled_systems, + .get_supported_systems = luatos_air530z_get_supported_systems, +}; + +#define LUATOS_AIR530Z(inst) \ + static struct gnss_luatos_air530z_config gnss_luatos_air530z_cfg_##inst = { \ + .uart = DEVICE_DT_GET(DT_INST_BUS(inst)), \ + .on_off_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, on_off_gpios, { 0 }), \ + }; \ + \ + static struct gnss_luatos_air530z_data gnss_luatos_air530z_data_##inst = { \ + .chat_delimiter = {'\r', '\n'}, \ + .dynamic_separators_buf = {',', '*'}, \ + }; \ + \ + PM_DEVICE_DT_INST_DEFINE(inst, luatos_air530z_pm_action); \ + \ + DEVICE_DT_INST_DEFINE(inst, gnss_luatos_air530z_init, \ + PM_DEVICE_DT_INST_GET(inst), \ + &gnss_luatos_air530z_data_##inst, \ + &gnss_luatos_air530z_cfg_##inst, \ + POST_KERNEL, CONFIG_GNSS_INIT_PRIORITY, &gnss_api); + +DT_INST_FOREACH_STATUS_OKAY(LUATOS_AIR530Z) diff --git a/drivers/gnss/gnss_nmea0183.c b/drivers/gnss/gnss_nmea0183.c index 9bce7a443a2..515606fbefe 100644 --- a/drivers/gnss/gnss_nmea0183.c +++ b/drivers/gnss/gnss_nmea0183.c @@ -538,7 +538,7 @@ int gnss_nmea0183_parse_gga(const char **argv, uint16_t argc, struct gnss_data * data->info.hdop = (uint16_t)tmp64; /* Parse altitude */ - if ((gnss_parse_dec_to_milli(argv[11], &tmp64) < 0) || + if ((gnss_parse_dec_to_milli(argv[9], &tmp64) < 0) || (tmp64 > INT32_MAX) || (tmp64 < INT32_MIN)) { return -EINVAL; diff --git a/drivers/gnss/gnss_nmea_generic.c b/drivers/gnss/gnss_nmea_generic.c index 2f23f4d7353..2c92ce480ba 100644 --- a/drivers/gnss/gnss_nmea_generic.c +++ b/drivers/gnss/gnss_nmea_generic.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include "gnss_nmea0183.h" @@ -21,14 +22,14 @@ #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 UART_RX_BUF_SZ (256 + IS_ENABLED(CONFIG_GNSS_SATELLITES) * 512) +#define UART_TX_BUF_SZ 64 #define CHAT_RECV_BUF_SZ 256 #define CHAT_ARGV_SZ 32 struct gnss_nmea_generic_config { const struct device *uart; + const struct modem_chat_script *const init_chat_script; }; struct gnss_nmea_generic_data { @@ -40,14 +41,13 @@ struct gnss_nmea_generic_data { /* UART backend */ struct modem_pipe *uart_pipe; struct modem_backend_uart uart_backend; - uint8_t uart_backend_receive_buf[UART_RECV_BUF_SZ]; + uint8_t uart_backend_receive_buf[UART_RX_BUF_SZ]; + uint8_t uart_backend_transmit_buf[UART_TX_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, @@ -60,6 +60,7 @@ MODEM_CHAT_MATCHES_DEFINE(unsol_matches, static int gnss_nmea_generic_resume(const struct device *dev) { + const struct gnss_nmea_generic_config *cfg = dev->config; struct gnss_nmea_generic_data *data = dev->data; int ret; @@ -69,11 +70,14 @@ static int gnss_nmea_generic_resume(const struct device *dev) } ret = modem_chat_attach(&data->chat, data->uart_pipe); + + if (ret == 0) { + ret = modem_chat_run_script(&data->chat, cfg->init_chat_script); + } + if (ret < 0) { modem_pipe_close(data->uart_pipe); - return ret; } - return ret; } @@ -104,6 +108,8 @@ static void gnss_nmea_generic_init_pipe(const struct device *dev) .uart = cfg->uart, .receive_buf = data->uart_backend_receive_buf, .receive_buf_size = sizeof(data->uart_backend_receive_buf), + .transmit_buf = data->uart_backend_transmit_buf, + .transmit_buf_size = sizeof(data->uart_backend_transmit_buf), }; data->uart_pipe = modem_backend_uart_init(&data->uart_backend, &uart_backend_config); @@ -148,24 +154,49 @@ static int gnss_nmea_generic_init(const struct device *dev) return ret; } +#if CONFIG_PM_DEVICE + pm_device_init_suspended(dev); +#else ret = gnss_nmea_generic_resume(dev); if (ret < 0) { return ret; } +#endif return 0; } +#if CONFIG_PM_DEVICE +static int gnss_nmea_generic_pm_action(const struct device *dev, enum pm_device_action action) +{ + switch (action) { + case PM_DEVICE_ACTION_RESUME: + return gnss_nmea_generic_resume(dev); + default: + return -ENOTSUP; + } +} +#endif + +#if DT_HAS_COMPAT_STATUS_OKAY(gnss_nmea_generic) +MODEM_CHAT_SCRIPT_EMPTY_DEFINE(gnss_nmea_generic_init_chat_script); +#endif + #define GNSS_NMEA_GENERIC(inst) \ static struct gnss_nmea_generic_config gnss_nmea_generic_cfg_##inst = { \ .uart = DEVICE_DT_GET(DT_INST_BUS(inst)), \ + .init_chat_script = &_CONCAT(DT_DRV_COMPAT, _init_chat_script), \ }; \ \ static struct gnss_nmea_generic_data gnss_nmea_generic_data_##inst; \ \ - DEVICE_DT_INST_DEFINE(inst, gnss_nmea_generic_init, NULL, \ + PM_DEVICE_DT_INST_DEFINE(inst, gnss_nmea_generic_pm_action); \ + \ + DEVICE_DT_INST_DEFINE(inst, gnss_nmea_generic_init, PM_DEVICE_DT_INST_GET(inst),\ &gnss_nmea_generic_data_##inst, \ &gnss_nmea_generic_cfg_##inst, \ POST_KERNEL, CONFIG_GNSS_INIT_PRIORITY, &gnss_api); +#define DT_DRV_COMPAT gnss_nmea_generic DT_INST_FOREACH_STATUS_OKAY(GNSS_NMEA_GENERIC) +#undef DT_DRV_COMPAT diff --git a/drivers/gnss/gnss_publish.c b/drivers/gnss/gnss_publish.c index 7ddfa5e09fe..309c8560dd1 100644 --- a/drivers/gnss/gnss_publish.c +++ b/drivers/gnss/gnss_publish.c @@ -8,29 +8,33 @@ #include #include -static struct k_spinlock lock; +static K_SEM_DEFINE(semlock, 1, 1); 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); - } + (void)k_sem_take(&semlock, K_FOREVER); + + STRUCT_SECTION_FOREACH(gnss_data_callback, callback) { + if (callback->dev == NULL || callback->dev == dev) { + callback->callback(dev, data); } } + + k_sem_give(&semlock); } #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); - } + (void)k_sem_take(&semlock, K_FOREVER); + + STRUCT_SECTION_FOREACH(gnss_satellites_callback, callback) { + if (callback->dev == NULL || callback->dev == dev) { + callback->callback(dev, satellites, size); } } + + k_sem_give(&semlock); } #endif diff --git a/drivers/gnss/gnss_quectel_lcx6g.c b/drivers/gnss/gnss_quectel_lcx6g.c index 09fa8fd8e4a..d3ac854ae96 100644 --- a/drivers/gnss/gnss_quectel_lcx6g.c +++ b/drivers/gnss/gnss_quectel_lcx6g.c @@ -74,21 +74,10 @@ struct quectel_lcx6g_data { enum gnss_navigation_mode navigation_mode_response; }; - struct k_spinlock lock; + struct k_sem 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( @@ -100,11 +89,10 @@ 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("$PAIR002*38", modem_chat_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), @@ -172,6 +160,20 @@ static int quectel_lcx6g_configure_pps(const struct device *dev) return modem_chat_run_script(&data->chat, &data->dynamic_script); } +static void quectel_lcx6g_lock(const struct device *dev) +{ + struct quectel_lcx6g_data *data = dev->data; + + (void)k_sem_take(&data->lock, K_FOREVER); +} + +static void quectel_lcx6g_unlock(const struct device *dev) +{ + struct quectel_lcx6g_data *data = dev->data; + + k_sem_give(&data->lock); +} + static void quectel_lcx6g_pm_changed(const struct device *dev) { struct quectel_lcx6g_data *data = dev->data; @@ -266,11 +268,9 @@ static int quectel_lcx6g_turn_off(const struct device *dev) 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); + quectel_lcx6g_lock(dev); switch (action) { case PM_DEVICE_ACTION_SUSPEND: @@ -296,7 +296,7 @@ static int quectel_lcx6g_pm_action(const struct device *dev, enum pm_device_acti quectel_lcx6g_pm_changed(dev); - k_spin_unlock(&data->lock, key); + quectel_lcx6g_unlock(dev); return ret; } #endif /* CONFIG_PM_DEVICE */ @@ -304,14 +304,13 @@ static int quectel_lcx6g_pm_action(const struct device *dev, enum pm_device_acti 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); + quectel_lcx6g_lock(dev); ret = gnss_nmea0183_snprintk(data->dynamic_request_buf, sizeof(data->dynamic_request_buf), "PAIR050,%u", fix_interval_ms); @@ -335,7 +334,7 @@ static int quectel_lcx6g_set_fix_rate(const struct device *dev, uint32_t fix_int } unlock_return: - k_spin_unlock(&data->lock, key); + quectel_lcx6g_unlock(dev); return ret; } @@ -359,10 +358,9 @@ static void quectel_lcx6g_get_fix_rate_callback(struct modem_chat *chat, char ** 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); + quectel_lcx6g_lock(dev); ret = gnss_nmea0183_snprintk(data->dynamic_request_buf, sizeof(data->dynamic_request_buf), "PAIR051"); @@ -385,7 +383,7 @@ static int quectel_lcx6g_get_fix_rate(const struct device *dev, uint32_t *fix_in *fix_interval_ms = data->fix_rate_response; unlock_return: - k_spin_unlock(&data->lock, key); + quectel_lcx6g_unlock(dev); return 0; } @@ -393,7 +391,6 @@ 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; @@ -415,7 +412,7 @@ static int quectel_lcx6g_set_navigation_mode(const struct device *dev, break; } - key = k_spin_lock(&data->lock); + quectel_lcx6g_lock(dev); ret = gnss_nmea0183_snprintk(data->dynamic_request_buf, sizeof(data->dynamic_request_buf), "PAIR080,%u", navigation_mode); @@ -439,7 +436,7 @@ static int quectel_lcx6g_set_navigation_mode(const struct device *dev, } unlock_return: - k_spin_unlock(&data->lock, key); + quectel_lcx6g_unlock(dev); return ret; } @@ -480,10 +477,9 @@ 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); + quectel_lcx6g_lock(dev); ret = gnss_nmea0183_snprintk(data->dynamic_request_buf, sizeof(data->dynamic_request_buf), "PAIR081"); @@ -506,7 +502,7 @@ static int quectel_lcx6g_get_navigation_mode(const struct device *dev, *mode = data->navigation_mode_response; unlock_return: - k_spin_unlock(&data->lock, key); + quectel_lcx6g_unlock(dev); return ret; } @@ -514,7 +510,6 @@ static int quectel_lcx6g_set_enabled_systems(const struct device *dev, gnss_syst { 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 | @@ -524,7 +519,7 @@ static int quectel_lcx6g_set_enabled_systems(const struct device *dev, gnss_syst return -EINVAL; } - key = k_spin_lock(&data->lock); + quectel_lcx6g_lock(dev); ret = gnss_nmea0183_snprintk(data->dynamic_request_buf, sizeof(data->dynamic_request_buf), "PAIR066,%u,%u,%u,%u,%u,0", @@ -574,7 +569,7 @@ static int quectel_lcx6g_set_enabled_systems(const struct device *dev, gnss_syst } unlock_return: - k_spin_unlock(&data->lock, key); + quectel_lcx6g_unlock(dev); return ret; } @@ -615,10 +610,9 @@ static void quectel_lcx6g_get_sbas_status_callback(struct modem_chat *chat, char 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); + quectel_lcx6g_lock(dev); ret = gnss_nmea0183_snprintk(data->dynamic_request_buf, sizeof(data->dynamic_request_buf), "PAIR067"); @@ -659,7 +653,7 @@ static int quectel_lcx6g_get_enabled_systems(const struct device *dev, gnss_syst *systems = data->enabled_systems_response; unlock_return: - k_spin_unlock(&data->lock, key); + quectel_lcx6g_unlock(dev); return ret; } @@ -758,8 +752,11 @@ static void quectel_lcx6g_init_dynamic_script(const struct device *dev) static int quectel_lcx6g_init(const struct device *dev) { + struct quectel_lcx6g_data *data = dev->data; int ret; + k_sem_init(&data->lock, 1, 1); + ret = quectel_lcx6g_init_nmea0183_match(dev); if (ret < 0) { return ret; diff --git a/drivers/gpio/CMakeLists.txt b/drivers/gpio/CMakeLists.txt index 2143d019cb7..787a10d7dd5 100644 --- a/drivers/gpio/CMakeLists.txt +++ b/drivers/gpio/CMakeLists.txt @@ -4,94 +4,101 @@ zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/gpio.h) zephyr_library() +# zephyr-keep-sorted-start zephyr_library_sources_ifdef(CONFIG_GPIO_AD559X gpio_ad559x.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_ADP5585 gpio_adp5585.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_ADS114S0X gpio_ads114s0x.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_ALTERA_PIO gpio_altera_pio.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_AMBIQ gpio_ambiq.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_ANDES_ATCGPIO100 gpio_andes_atcgpio100.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) +zephyr_library_sources_ifdef(CONFIG_GPIO_BCM2711 gpio_bcm2711.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_BD8LB600FS gpio_bd8lb600fs.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_BRCMSTB gpio_brcmstb.c) zephyr_library_sources_ifdef(CONFIG_GPIO_CC13XX_CC26XX gpio_cc13xx_cc26xx.c) zephyr_library_sources_ifdef(CONFIG_GPIO_CC32XX gpio_cc32xx.c) zephyr_library_sources_ifdef(CONFIG_GPIO_CMSDK_AHB gpio_cmsdk_ahb.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_CY8C95XX gpio_cy8c95xx.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_DAVINCI gpio_davinci.c) zephyr_library_sources_ifdef(CONFIG_GPIO_DW gpio_dw.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_EFINIX_SAPPHIRE gpio_efinix_sapphire.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_EMUL gpio_emul.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_ENE_KB1200 gpio_ene_kb1200.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_EOS_S3 gpio_eos_s3.c) zephyr_library_sources_ifdef(CONFIG_GPIO_ESP32 gpio_esp32.c) -zephyr_library_sources_ifdef(CONFIG_GPIO_SIFIVE gpio_sifive.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_FXL6408 gpio_fxl6408.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_GD32 gpio_gd32.c) zephyr_library_sources_ifdef(CONFIG_GPIO_GECKO gpio_gecko.c) zephyr_library_sources_ifdef(CONFIG_GPIO_IMX gpio_imx.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_INFINEON_CAT1 gpio_ifx_cat1.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_INTEL gpio_intel.c) zephyr_library_sources_ifdef(CONFIG_GPIO_ITE_IT8XXX2 gpio_ite_it8xxx2.c) zephyr_library_sources_ifdef(CONFIG_GPIO_ITE_IT8XXX2_V2 gpio_ite_it8xxx2_v2.c) zephyr_library_sources_ifdef(CONFIG_GPIO_KSCAN_ITE_IT8XXX2 gpio_kscan_ite_it8xxx2.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_LITEX gpio_litex.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_LMP90XXX gpio_lmp90xxx.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_LPC11U6X gpio_lpc11u6x.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_MCHP_MSS gpio_mchp_mss.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_MCP230XX gpio_mcp230xx.c) zephyr_library_sources_ifdef(CONFIG_GPIO_MCP23S17 gpio_mcp23s17.c) -zephyr_library_sources_ifdef(CONFIG_GPIO_MCP23XXX gpio_mcp23xxx.c) zephyr_library_sources_ifdef(CONFIG_GPIO_MCP23SXX gpio_mcp23sxx.c) -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_MCP23XXX gpio_mcp23xxx.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_MCUX_RGPIO gpio_mcux_rgpio.c) zephyr_library_sources_ifdef(CONFIG_GPIO_MMIO32 gpio_mmio32.c) -zephyr_library_sources_ifdef(CONFIG_GPIO_XEC gpio_mchp_xec.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_NCT38XX gpio_nct38xx.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_NCT38XX gpio_nct38xx_port.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_NCT38XX_ALERT gpio_nct38xx_alert.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_NEORV32 gpio_neorv32.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_NPCX gpio_npcx.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_NPM1300 gpio_npm1300.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_NPM6001 gpio_npm6001.c) zephyr_library_sources_ifdef(CONFIG_GPIO_NRFX gpio_nrfx.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_NUMAKER gpio_numaker.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_NUMICRO gpio_numicro.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_NXP_S32 gpio_nxp_s32.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_PCA953X gpio_pca953x.c) zephyr_library_sources_ifdef(CONFIG_GPIO_PCA95XX gpio_pca95xx.c) -zephyr_library_sources_ifdef(CONFIG_GPIO_STM32 gpio_stm32.c) -zephyr_library_sources_ifdef(CONFIG_GPIO_SAM0 gpio_sam0.c) -zephyr_library_sources_ifdef(CONFIG_GPIO_SAM gpio_sam.c) -zephyr_library_sources_ifdef(CONFIG_GPIO_SAM4L gpio_sam4l.c) -zephyr_library_sources_ifdef(CONFIG_GPIO_SX1509B gpio_sx1509b.c) -zephyr_library_sources_ifdef(CONFIG_GPIO_INTEL gpio_intel.c) -zephyr_library_sources_ifdef(CONFIG_GPIO_STELLARIS gpio_stellaris.c) -zephyr_library_sources_ifdef(CONFIG_GPIO_RPI_PICO gpio_rpi_pico.c) -zephyr_library_sources_ifdef(CONFIG_GPIO_RV32M1 gpio_rv32m1.c) -zephyr_library_sources_ifdef(CONFIG_GPIO_LMP90XXX gpio_lmp90xxx.c) -zephyr_library_sources_ifdef(CONFIG_GPIO_ADS114S0X gpio_ads114s0x.c) -zephyr_library_sources_ifdef(CONFIG_GPIO_LITEX gpio_litex.c) -zephyr_library_sources_ifdef(CONFIG_GPIO_LPC11U6X gpio_lpc11u6x.c) -zephyr_library_sources_ifdef(CONFIG_GPIO_XLNX_AXI gpio_xlnx_axi.c) -zephyr_library_sources_ifdef(CONFIG_GPIO_NPCX gpio_npcx.c) -zephyr_library_sources_ifdef(CONFIG_GPIO_EMUL gpio_emul.c) -zephyr_library_sources_ifdef(CONFIG_GPIO_PSOC6 gpio_psoc6.c) zephyr_library_sources_ifdef(CONFIG_GPIO_PCAL64XXA gpio_pcal64xxa.c) -zephyr_library_sources_ifdef(CONFIG_GPIO_EOS_S3 gpio_eos_s3.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_PCF857X gpio_pcf857x.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_PSOC6 gpio_psoc6.c) zephyr_library_sources_ifdef(CONFIG_GPIO_RCAR gpio_rcar.c) -zephyr_library_sources_ifdef(CONFIG_GPIO_CY8C95XX gpio_cy8c95xx.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_RENESAS_RA gpio_renesas_ra.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_RPI_PICO gpio_rpi_pico.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_RT1718S gpio_rt1718s.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_RT1718S gpio_rt1718s_port.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_RV32M1 gpio_rv32m1.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_RZT2M gpio_rzt2m.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_SAM gpio_sam.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_SAM0 gpio_sam0.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_SAM4L gpio_sam4l.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_SEDI gpio_sedi.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_SIFIVE gpio_sifive.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_SMARTBOND gpio_smartbond.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_SN74HC595 gpio_sn74hc595.c) zephyr_library_sources_ifdef(CONFIG_GPIO_SNPS_CREG gpio_creg_gpio.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_STELLARIS gpio_stellaris.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_STM32 gpio_stm32.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_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) -zephyr_library_sources_ifdef(CONFIG_GPIO_NCT38XX gpio_nct38xx.c) -zephyr_library_sources_ifdef(CONFIG_GPIO_NCT38XX gpio_nct38xx_port.c) -zephyr_library_sources_ifdef(CONFIG_GPIO_NCT38XX_ALERT gpio_nct38xx_alert.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_SX1509B gpio_sx1509b.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_TCA6424A gpio_tca6424a.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_TELINK_B91 gpio_b91.c) zephyr_library_sources_ifdef(CONFIG_GPIO_TEST gpio_test.c) -zephyr_library_sources_ifdef(CONFIG_GPIO_GD32 gpio_gd32.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_TLE9104 gpio_tle9104.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_XEC gpio_mchp_xec.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_XEC_V2 gpio_mchp_xec_v2.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_XLNX_AXI gpio_xlnx_axi.c) zephyr_library_sources_ifdef(CONFIG_GPIO_XLNX_PS gpio_xlnx_ps.c gpio_xlnx_ps_bank.c) -zephyr_library_sources_ifdef(CONFIG_GPIO_SN74HC595 gpio_sn74hc595.c) -zephyr_library_sources_ifdef(CONFIG_GPIO_MCHP_MSS gpio_mchp_mss.c) -zephyr_library_sources_ifdef(CONFIG_GPIO_SMARTBOND gpio_smartbond.c) -zephyr_library_sources_ifdef(CONFIG_GPIO_NXP_S32 gpio_nxp_s32.c) -zephyr_library_sources_ifdef(CONFIG_GPIO_TCA6424A gpio_tca6424a.c) -zephyr_library_sources_ifdef(CONFIG_GPIO_SHELL gpio_shell.c) -zephyr_library_sources_ifdef(CONFIG_USERSPACE gpio_handlers.c) zephyr_library_sources_ifdef(CONFIG_GPIO_XMC4XXX gpio_xmc4xxx.c) -zephyr_library_sources_ifdef(CONFIG_GPIO_NPM1300 gpio_npm1300.c) -zephyr_library_sources_ifdef(CONFIG_GPIO_NPM6001 gpio_npm6001.c) -zephyr_library_sources_ifdef(CONFIG_GPIO_RT1718S gpio_rt1718s.c) -zephyr_library_sources_ifdef(CONFIG_GPIO_RT1718S gpio_rt1718s_port.c) -zephyr_library_sources_ifdef(CONFIG_GPIO_NUMICRO gpio_numicro.c) +# zephyr-keep-sorted-stop + +# zephyr-keep-sorted-start zephyr_library_sources_ifdef(CONFIG_GPIO_HOGS gpio_hogs.c) -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_ENE_KB1200 gpio_ene_kb1200.c) -zephyr_library_sources_ifdef(CONFIG_GPIO_RZT2M gpio_rzt2m.c) -zephyr_library_sources_ifdef(CONFIG_GPIO_AMBIQ gpio_ambiq.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_SHELL gpio_shell.c) +zephyr_library_sources_ifdef(CONFIG_USERSPACE gpio_handlers.c) +# zephyr-keep-sorted-stop if (CONFIG_GPIO_EMUL_SDL) zephyr_library_sources(gpio_emul_sdl.c) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 2ca6da678c3..9ce2b7f5859 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -29,6 +29,13 @@ config GPIO_SHELL_INFO_CMD This command provides a shell user extra information about gpio controller reserved pins and line names. +config GPIO_SHELL_TOGGLE_CMD + bool "GPIO Shell toggle command" + default y + depends on GPIO_SHELL + help + Enable GPIO Shell toggle command. + config GPIO_SHELL_BLINK_CMD bool "GPIO Shell blink command" default y @@ -86,160 +93,87 @@ config GPIO_ENABLE_DISABLE_INTERRUPT on/off the interrupt signal without changing other registers, such as pending register, etc. The driver must implement it to work. - +# zephyr-keep-sorted-start source "drivers/gpio/Kconfig.ad559x" - +source "drivers/gpio/Kconfig.adp5585" +source "drivers/gpio/Kconfig.ads114s0x" +source "drivers/gpio/Kconfig.altera" +source "drivers/gpio/Kconfig.ambiq" +source "drivers/gpio/Kconfig.andes_atcgpio100" source "drivers/gpio/Kconfig.axp192" - source "drivers/gpio/Kconfig.b91" - -source "drivers/gpio/Kconfig.dw" - -source "drivers/gpio/Kconfig.pca95xx" - -source "drivers/gpio/Kconfig.mcp23s17" - -source "drivers/gpio/Kconfig.mcp23xxx" - -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" - -source "drivers/gpio/Kconfig.stm32" - -source "drivers/gpio/Kconfig.nrfx" - -source "drivers/gpio/Kconfig.cmsdk_ahb" - +source "drivers/gpio/Kconfig.bcm2711" +source "drivers/gpio/Kconfig.bd8lb600fs" +source "drivers/gpio/Kconfig.brcmstb" source "drivers/gpio/Kconfig.cc13xx_cc26xx" - source "drivers/gpio/Kconfig.cc32xx" - -source "drivers/gpio/Kconfig.sifive" - +source "drivers/gpio/Kconfig.cmsdk_ahb" +source "drivers/gpio/Kconfig.creg_gpio" +source "drivers/gpio/Kconfig.cy8c95xx" +source "drivers/gpio/Kconfig.davinci" +source "drivers/gpio/Kconfig.dw" +source "drivers/gpio/Kconfig.efinix_sapphire" +source "drivers/gpio/Kconfig.emul" +source "drivers/gpio/Kconfig.emul_sdl" +source "drivers/gpio/Kconfig.ene" +source "drivers/gpio/Kconfig.eos_s3" source "drivers/gpio/Kconfig.esp32" - +source "drivers/gpio/Kconfig.fxl6408" +source "drivers/gpio/Kconfig.gd32" source "drivers/gpio/Kconfig.gecko" - -source "drivers/gpio/Kconfig.sam0" - -source "drivers/gpio/Kconfig.sam" - -source "drivers/gpio/Kconfig.sx1509b" - -source "drivers/gpio/Kconfig.imx" - -source "drivers/gpio/Kconfig.it8xxx2" - source "drivers/gpio/Kconfig.ifx_cat1" - +source "drivers/gpio/Kconfig.imx" source "drivers/gpio/Kconfig.intel" - -source "drivers/gpio/Kconfig.xec" - -source "drivers/gpio/Kconfig.stellaris" - -source "drivers/gpio/Kconfig.rpi_pico" - -source "drivers/gpio/Kconfig.rv32m1" - -source "drivers/gpio/Kconfig.lmp90xxx" - -source "drivers/gpio/Kconfig.ads114s0x" - +source "drivers/gpio/Kconfig.it8xxx2" source "drivers/gpio/Kconfig.litex" - +source "drivers/gpio/Kconfig.lmp90xxx" source "drivers/gpio/Kconfig.lpc11u6x" - -source "drivers/gpio/Kconfig.xlnx" - -source "drivers/gpio/Kconfig.npcx" - -source "drivers/gpio/Kconfig.emul" - -source "drivers/gpio/Kconfig.emul_sdl" - -source "drivers/gpio/Kconfig.psoc6" - -source "drivers/gpio/Kconfig.pcal64xxa" - -source "drivers/gpio/Kconfig.eos_s3" - -source "drivers/gpio/Kconfig.rcar" - -source "drivers/gpio/Kconfig.cy8c95xx" - -source "drivers/gpio/Kconfig.creg_gpio" - -source "drivers/gpio/Kconfig.stmpe1600" - -source "drivers/gpio/Kconfig.pca953x" - -source "drivers/gpio/Kconfig.pcf857x" - -source "drivers/gpio/Kconfig.fxl6408" - -source "drivers/gpio/Kconfig.andes_atcgpio100" - -source "drivers/gpio/Kconfig.neorv32" - -source "drivers/gpio/Kconfig.nct38xx" - -source "drivers/gpio/Kconfig.test" - -source "drivers/gpio/Kconfig.gd32" - -source "drivers/gpio/Kconfig.xlnx_ps" - -source "drivers/gpio/Kconfig.sn74hc595" - source "drivers/gpio/Kconfig.mchp_mss" - -source "drivers/gpio/Kconfig.xmc4xxx" - -source "drivers/gpio/Kconfig.smartbond" - -source "drivers/gpio/Kconfig.nxp_s32" - -source "drivers/gpio/Kconfig.tca6424a" - +source "drivers/gpio/Kconfig.mcp23s17" +source "drivers/gpio/Kconfig.mcp23xxx" +source "drivers/gpio/Kconfig.mcux" +source "drivers/gpio/Kconfig.mcux_igpio" +source "drivers/gpio/Kconfig.mcux_lpc" +source "drivers/gpio/Kconfig.mcux_rgpio" +source "drivers/gpio/Kconfig.mmio32" +source "drivers/gpio/Kconfig.nct38xx" +source "drivers/gpio/Kconfig.neorv32" +source "drivers/gpio/Kconfig.npcx" source "drivers/gpio/Kconfig.npm1300" - source "drivers/gpio/Kconfig.npm6001" - -source "drivers/gpio/Kconfig.rt1718s" - +source "drivers/gpio/Kconfig.nrfx" +source "drivers/gpio/Kconfig.numaker" source "drivers/gpio/Kconfig.numicro" - -source "drivers/gpio/Kconfig.bd8lb600fs" - +source "drivers/gpio/Kconfig.nxp_s32" +source "drivers/gpio/Kconfig.pca953x" +source "drivers/gpio/Kconfig.pca95xx" +source "drivers/gpio/Kconfig.pcal64xxa" +source "drivers/gpio/Kconfig.pcf857x" +source "drivers/gpio/Kconfig.psoc6" +source "drivers/gpio/Kconfig.rcar" +source "drivers/gpio/Kconfig.renesas_ra" +source "drivers/gpio/Kconfig.rpi_pico" +source "drivers/gpio/Kconfig.rt1718s" +source "drivers/gpio/Kconfig.rv32m1" +source "drivers/gpio/Kconfig.rzt2m" +source "drivers/gpio/Kconfig.sam" +source "drivers/gpio/Kconfig.sam0" source "drivers/gpio/Kconfig.sc18im704" - -source "drivers/gpio/Kconfig.numaker" - -source "drivers/gpio/Kconfig.efinix_sapphire" - -source "drivers/gpio/Kconfig.davinci" source "drivers/gpio/Kconfig.sedi" - +source "drivers/gpio/Kconfig.sifive" +source "drivers/gpio/Kconfig.smartbond" +source "drivers/gpio/Kconfig.sn74hc595" +source "drivers/gpio/Kconfig.stellaris" +source "drivers/gpio/Kconfig.stm32" +source "drivers/gpio/Kconfig.stmpe1600" +source "drivers/gpio/Kconfig.sx1509b" +source "drivers/gpio/Kconfig.tca6424a" +source "drivers/gpio/Kconfig.test" 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.ene" - -source "drivers/gpio/Kconfig.rzt2m" - -source "drivers/gpio/Kconfig.ambiq" +source "drivers/gpio/Kconfig.xec" +source "drivers/gpio/Kconfig.xlnx" +source "drivers/gpio/Kconfig.xlnx_ps" +source "drivers/gpio/Kconfig.xmc4xxx" +# zephyr-keep-sorted-stop endif # GPIO diff --git a/drivers/gpio/Kconfig.adp5585 b/drivers/gpio/Kconfig.adp5585 new file mode 100644 index 00000000000..d531f858f1d --- /dev/null +++ b/drivers/gpio/Kconfig.adp5585 @@ -0,0 +1,18 @@ +# Copyright 2024 NXP +# SPDX-License-Identifier: Apache-2.0 + +menuconfig GPIO_ADP5585 + bool "ADP5585_GPIO I2C GPIO chip" + default y + depends on DT_HAS_ADI_ADP5585_GPIO_ENABLED + select MFD + select I2C + help + Enable the ADP5585 GPIO driver. + +config GPIO_ADP5585_INIT_PRIORITY + int "Init priority" + default 70 + depends on GPIO_ADP5585 + help + Device driver initialization priority. diff --git a/drivers/gpio/Kconfig.brcmstb b/drivers/gpio/Kconfig.brcmstb new file mode 100644 index 00000000000..0974f05239e --- /dev/null +++ b/drivers/gpio/Kconfig.brcmstb @@ -0,0 +1,9 @@ +# Copyright (c) 2024 Junho Lee +# SPDX-License-Identifier: Apache-2.0 + +config GPIO_BRCMSTB + bool "Broadcom Set-top box SoC GPIO Driver" + default y + depends on DT_HAS_BRCM_BRCMSTB_GPIO_ENABLED + help + Enable Driver for Broadcom Set-top box SoC GPIO Banks. diff --git a/drivers/gpio/gpio_adp5585.c b/drivers/gpio/gpio_adp5585.c new file mode 100644 index 00000000000..0a1da5e63f4 --- /dev/null +++ b/drivers/gpio/gpio_adp5585.c @@ -0,0 +1,469 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include + +#define DT_DRV_COMPAT adi_adp5585_gpio + +LOG_MODULE_REGISTER(adp5585_gpio, CONFIG_GPIO_LOG_LEVEL); + +#define ADP5585_BANK(offs) (offs >> 3) +#define ADP5585_BIT(offs) (offs & GENMASK(2, 0)) + +enum adp5585_gpio_pin_direction { + adp5585_pin_input = 0U, + adp5585_pin_output, +}; + +enum adp5585_gpio_pin_drive_mode { + adp5585_pin_drive_pp = 0U, + adp5585_pin_drive_od, +}; + +enum adp5585_gpio_pull_config { + adp5585_pull_up_300k = 0U, + adp5585_pull_dn_300k, + adp5585_pull_up_100k, /* not used */ + adp5585_pull_disable, +}; + +enum adp5585_gpio_int_en { + adp5585_int_disable = 0U, + adp5585_int_enable, +}; + +enum adp5585_gpio_int_level { + adp5585_int_active_low = 0U, + adp5585_int_active_high, +}; + +/** Configuration data */ +struct adp5585_gpio_config { + /* gpio_driver_config needs to be first */ + struct gpio_driver_config common; + const struct device *mfd_dev; + const struct gpio_dt_spec gpio_int; +}; + +/** Runtime driver data */ +struct adp5585_gpio_data { + /* gpio_driver_data needs to be first */ + struct gpio_driver_data common; + uint16_t output; + + sys_slist_t callbacks; +}; + +static int gpio_adp5585_config(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags) +{ + const struct adp5585_gpio_config *cfg = dev->config; + struct adp5585_gpio_data *data = dev->data; + const struct mfd_adp5585_config *parent_cfg = + (struct mfd_adp5585_config *)(cfg->mfd_dev->config); + struct mfd_adp5585_data *parent_data = (struct mfd_adp5585_data *)(cfg->mfd_dev->data); + + int ret = 0; + uint8_t reg_value; + + /* ADP5585 has non-contiguous gpio pin layouts, account for this */ + if ((pin & cfg->common.port_pin_mask) == 0) { + LOG_ERR("pin %d is invalid for this device", pin); + return -ENOTSUP; + } + + uint8_t bank = ADP5585_BANK(pin); + uint8_t bank_pin = ADP5585_BIT(pin); + + /* Can't do I2C bus operations from an ISR */ + if (k_is_in_isr()) { + return -EWOULDBLOCK; + } + + /* Simultaneous PU & PD mode not supported */ + if (((flags & GPIO_PULL_UP) != 0) && ((flags & GPIO_PULL_DOWN) != 0)) { + return -ENOTSUP; + } + + /* Simultaneous input & output mode not supported */ + if (((flags & GPIO_INPUT) != 0) && ((flags & GPIO_OUTPUT) != 0)) { + return -ENOTSUP; + } + + k_sem_take(&parent_data->lock, K_FOREVER); + + if ((flags & GPIO_SINGLE_ENDED) != 0) { + reg_value = adp5585_pin_drive_od << bank_pin; + } else { + reg_value = adp5585_pin_drive_pp << bank_pin; + } + ret = i2c_reg_update_byte_dt(&parent_cfg->i2c_bus, ADP5585_GPO_OUT_MODE_A + bank, + BIT(bank_pin), reg_value); + if (ret != 0) { + goto out; + } + + uint8_t regaddr = ADP5585_RPULL_CONFIG_A + (bank << 1); + uint8_t shift = bank_pin << 1; + + if (bank_pin > 3U) { + regaddr += 1U; + shift = (bank_pin - 3U) << 1; + } + if ((flags & GPIO_PULL_UP) != 0) { + reg_value = adp5585_pull_up_300k << shift; + } else if ((flags & GPIO_PULL_DOWN) != 0) { + reg_value = adp5585_pull_dn_300k << shift; + } else { + reg_value = adp5585_pull_disable << shift; + } + + ret = i2c_reg_update_byte_dt(&parent_cfg->i2c_bus, regaddr, + 0b11U << shift, reg_value); + if (ret != 0) { + goto out; + } + + /* Ensure either Output or Input is specified */ + if ((flags & GPIO_OUTPUT) != 0) { + + /* Set Low or High if specified */ + if ((flags & GPIO_OUTPUT_INIT_LOW) != 0) { + data->output &= ~BIT(pin); + } else if ((flags & GPIO_OUTPUT_INIT_HIGH) != 0) { + data->output |= BIT(pin); + } + if (bank == 0) { + /* reg_value for ADP5585_GPO_OUT_MODE */ + reg_value = (uint8_t)data->output; + } else { + /* reg_value for ADP5585_GPO_OUT_MODE */ + reg_value = (uint8_t)(data->output >> 8); + } + ret = i2c_reg_write_byte_dt(&parent_cfg->i2c_bus, + ADP5585_GPO_OUT_MODE_A + bank, + reg_value); + if (ret != 0) { + goto out; + } + /* reg_value for ADP5585_GPIO_DIRECTION */ + reg_value = adp5585_pin_output << bank_pin; + } else if ((flags & GPIO_INPUT) != 0) { + /* reg_value for ADP5585_GPIO_DIRECTION */ + reg_value = adp5585_pin_output << bank_pin; + } + + ret = i2c_reg_update_byte_dt(&parent_cfg->i2c_bus, + ADP5585_GPIO_DIRECTION_A + bank, + BIT(bank_pin), reg_value); + +out: + k_sem_give(&parent_data->lock); + if (ret != 0) { + LOG_ERR("pin configure error: %d", ret); + } + return ret; +} + +static int gpio_adp5585_port_read(const struct device *dev, gpio_port_value_t *value) +{ + const struct adp5585_gpio_config *cfg = dev->config; + /* struct adp5585_gpio_data *data = dev->data; */ + const struct mfd_adp5585_config *parent_cfg = + (struct mfd_adp5585_config *)(cfg->mfd_dev->config); + struct mfd_adp5585_data *parent_data = (struct mfd_adp5585_data *)(cfg->mfd_dev->data); + + uint16_t input_data = 0; + int ret = 0; + + /* Can't do I2C bus operations from an ISR */ + if (k_is_in_isr()) { + return -EWOULDBLOCK; + } + + k_sem_take(&parent_data->lock, K_FOREVER); + + /** Read Input Register */ + + uint8_t gpi_status_reg; + uint8_t gpi_status_buf[2]; + + ret = i2c_write_read_dt(&parent_cfg->i2c_bus, &gpi_status_reg, 1U, + gpi_status_buf, 2U); + if (ret) { + goto out; + } + input_data = sys_le16_to_cpu(*((uint16_t *)gpi_status_buf)); + *value = input_data; + +out: + k_sem_give(&parent_data->lock); + LOG_DBG("read %x got %d", input_data, ret); + return ret; +} + +static int gpio_adp5585_port_write(const struct device *dev, gpio_port_pins_t mask, + gpio_port_value_t value, gpio_port_value_t toggle) +{ + const struct adp5585_gpio_config *cfg = dev->config; + struct adp5585_gpio_data *data = dev->data; + const struct mfd_adp5585_config *parent_cfg = + (struct mfd_adp5585_config *)(cfg->mfd_dev->config); + struct mfd_adp5585_data *parent_data = (struct mfd_adp5585_data *)(cfg->mfd_dev->data); + + uint16_t orig_out; + uint16_t out; + uint8_t reg_value; + int ret; + + /* Can't do I2C bus operations from an ISR */ + if (k_is_in_isr()) { + return -EWOULDBLOCK; + } + + k_sem_take(&parent_data->lock, K_FOREVER); + + orig_out = data->output; + out = ((orig_out & ~mask) | (value & mask)) ^ toggle; + + reg_value = (uint8_t)out; + uint8_t gpo_data_out_buf[] = { ADP5585_GPO_DATA_OUT_A, + (uint8_t)out, (uint8_t)(out >> 8) }; + + ret = i2c_write_dt(&parent_cfg->i2c_bus, gpo_data_out_buf, sizeof(gpo_data_out_buf)); + if (ret) { + goto out; + } + + data->output = out; + +out: + k_sem_give(&parent_data->lock); + LOG_DBG("write %x msk %08x val %08x => %x: %d", orig_out, mask, value, out, ret); + return ret; +} + +static int gpio_adp5585_port_set_masked(const struct device *dev, gpio_port_pins_t mask, + gpio_port_value_t value) +{ + return gpio_adp5585_port_write(dev, mask, value, 0); +} + +static int gpio_adp5585_port_set_bits(const struct device *dev, gpio_port_pins_t pins) +{ + return gpio_adp5585_port_write(dev, pins, pins, 0); +} + +static int gpio_adp5585_port_clear_bits(const struct device *dev, gpio_port_pins_t pins) +{ + return gpio_adp5585_port_write(dev, pins, 0, 0); +} + +static int gpio_adp5585_port_toggle_bits(const struct device *dev, gpio_port_pins_t pins) +{ + return gpio_adp5585_port_write(dev, 0, 0, pins); +} + +static int gpio_adp5585_pin_interrupt_configure(const struct device *dev, gpio_pin_t pin, + enum gpio_int_mode mode, enum gpio_int_trig trig) +{ + const struct adp5585_gpio_config *cfg = dev->config; + /* struct adp5585_gpio_data *data = dev->data; */ + const struct mfd_adp5585_config *parent_cfg = + (struct mfd_adp5585_config *)(cfg->mfd_dev->config); + struct mfd_adp5585_data *parent_data = (struct mfd_adp5585_data *)(cfg->mfd_dev->data); + int ret = 0; + + if (parent_cfg->nint_gpio.port == NULL) { + return -ENOTSUP; + } + + /* ADP5585 has non-contiguous gpio pin layouts, account for this */ + if ((pin & cfg->common.port_pin_mask) == 0) { + LOG_ERR("pin %d is invalid for this device", pin); + return -ENOTSUP; + } + + /* This device supports only level-triggered interrupts. */ + /* This device does NOT support either-level interrupt. */ + if (mode == GPIO_INT_MODE_EDGE || trig == GPIO_INT_TRIG_BOTH) { + return -ENOTSUP; + } + if (k_is_in_isr()) { + return -EWOULDBLOCK; + } + + uint8_t bank = ADP5585_BANK(pin); + uint8_t bank_pin = ADP5585_BIT(pin); + + k_sem_take(&parent_data->lock, K_FOREVER); + + if (mode == GPIO_INT_MODE_DISABLED) { + ret = i2c_reg_update_byte_dt(&parent_cfg->i2c_bus, + ADP5585_GPI_INTERRUPT_EN_A + bank, BIT(bank_pin), + (adp5585_int_disable << bank_pin)); + } else if ((trig & GPIO_INT_TRIG_BOTH) != 0) { + if (trig == GPIO_INT_TRIG_LOW) { + ret = i2c_reg_update_byte_dt( + &parent_cfg->i2c_bus, ADP5585_GPI_INT_LEVEL_A + bank, + BIT(bank_pin), (adp5585_int_active_low << bank_pin)); + } else { + ret = i2c_reg_update_byte_dt( + &parent_cfg->i2c_bus, ADP5585_GPI_INT_LEVEL_A + bank, + BIT(bank_pin), (adp5585_int_active_high << bank_pin)); + } + + /* make sure GPI_n_EVENT_EN is disabled, otherwise it will generate FIFO event */ + ret = i2c_reg_update_byte_dt(&parent_cfg->i2c_bus, + ADP5585_GPI_EVENT_EN_A + bank, BIT(bank_pin), 0U); + ret = i2c_reg_update_byte_dt(&parent_cfg->i2c_bus, + ADP5585_GPI_INTERRUPT_EN_A + bank, + BIT(bank_pin), (adp5585_int_enable << bank_pin)); + } + + k_sem_give(&parent_data->lock); + return ret; +} + +static int gpio_adp5585_manage_callback(const struct device *dev, struct gpio_callback *callback, + bool set) +{ + struct adp5585_gpio_data *data = dev->data; + + return gpio_manage_callback(&data->callbacks, callback, set); +} + +void gpio_adp5585_irq_handler(const struct device *dev) +{ + const struct adp5585_gpio_config *cfg = dev->config; + struct adp5585_gpio_data *data = dev->data; + const struct mfd_adp5585_config *parent_cfg = + (struct mfd_adp5585_config *)(cfg->mfd_dev->config); + struct mfd_adp5585_data *parent_data = (struct mfd_adp5585_data *)(cfg->mfd_dev->data); + + uint16_t reg_int_status; + int ret = 0; + + k_sem_take(&parent_data->lock, K_FOREVER); + + /* Read Input Register */ + ret = i2c_burst_read_dt(&parent_cfg->i2c_bus, ADP5585_GPI_INT_STAT_A, + (uint8_t *)®_int_status, 2U); + if (ret != 0) { + LOG_WRN("%s failed to read interrupt status %d", dev->name, ret); + goto out; + } + +out: + k_sem_give(&parent_data->lock); + + if (ret == 0 && reg_int_status != 0) { + gpio_fire_callbacks(&data->callbacks, dev, reg_int_status); + } +} + +/** + * @brief Initialization function of ADP5585_GPIO + * + * This sets initial input/ output configuration and output states. + * The interrupt is configured if this is enabled. + * + * @param dev Device struct + * @return 0 if successful, failed otherwise. + */ +static int gpio_adp5585_init(const struct device *dev) +{ + const struct adp5585_gpio_config *cfg = dev->config; + struct adp5585_gpio_data *data = dev->data; + const struct mfd_adp5585_config *parent_cfg = + (struct mfd_adp5585_config *)(cfg->mfd_dev->config); + struct mfd_adp5585_data *parent_data = (struct mfd_adp5585_data *)(cfg->mfd_dev->data); + int ret = 0; + + if (!device_is_ready(cfg->mfd_dev)) { + LOG_ERR("%s: parent dev not ready", dev->name); + ret = -ENODEV; + goto out; + } + + if (!device_is_ready(parent_cfg->i2c_bus.bus)) { + LOG_ERR("I2C bus device not found"); + ret = -EIO; + goto out; + } + + k_sem_take(&parent_data->lock, K_FOREVER); + + /** Read output register */ + uint8_t gpo_data_out_buf[] = { ADP5585_GPO_DATA_OUT_A, + 0x00, 0x00 }; + + ret = i2c_write_read_dt(&parent_cfg->i2c_bus, gpo_data_out_buf, 1U, + gpo_data_out_buf + 1, 2U); + if (ret) { + goto out; + } + data->output = sys_le16_to_cpu(*((uint16_t *)(gpo_data_out_buf + 1))); + + /** Set RPULL to high-z by default */ + uint8_t rpull_config_buf[] = { ADP5585_RPULL_CONFIG_A, + 0xffU, 0x03U, 0xffU, 0x03U }; + + ret = i2c_write_dt(&parent_cfg->i2c_bus, rpull_config_buf, sizeof(rpull_config_buf)); + if (ret) { + goto out; + } + + parent_data->child.gpio_dev = dev; + + /** Enable GPI interrupt */ + if ((ret == 0) && gpio_is_ready_dt(&parent_cfg->nint_gpio)) { + ret = i2c_reg_update_byte_dt(&parent_cfg->i2c_bus, ADP5585_INT_EN, (1U << 1), + (1U << 1)); + } + +out: + k_sem_give(&parent_data->lock); + if (ret) { + LOG_ERR("%s init failed: %d", dev->name, ret); + } else { + LOG_INF("%s init ok", dev->name); + } + return ret; +} + +static const struct gpio_driver_api api_table = { + .pin_configure = gpio_adp5585_config, + .port_get_raw = gpio_adp5585_port_read, + .port_set_masked_raw = gpio_adp5585_port_set_masked, + .port_set_bits_raw = gpio_adp5585_port_set_bits, + .port_clear_bits_raw = gpio_adp5585_port_clear_bits, + .port_toggle_bits = gpio_adp5585_port_toggle_bits, + .pin_interrupt_configure = gpio_adp5585_pin_interrupt_configure, + .manage_callback = gpio_adp5585_manage_callback, +}; + +#define GPIO_ADP5585_INIT(inst) \ + static const struct adp5585_gpio_config adp5585_gpio_cfg_##inst = { \ + .common = { \ + .port_pin_mask = GPIO_DT_INST_PORT_PIN_MASK_NGPIOS_EXC( \ + inst, DT_INST_PROP(inst, ngpios)) \ + }, \ + .mfd_dev = DEVICE_DT_GET(DT_INST_PARENT(inst)), \ + }; \ + static struct adp5585_gpio_data adp5585_gpio_drvdata_##inst; \ + DEVICE_DT_INST_DEFINE(inst, gpio_adp5585_init, NULL, \ + &adp5585_gpio_drvdata_##inst, \ + &adp5585_gpio_cfg_##inst, POST_KERNEL, \ + CONFIG_GPIO_ADP5585_INIT_PRIORITY, &api_table); + +DT_INST_FOREACH_STATUS_OKAY(GPIO_ADP5585_INIT) diff --git a/drivers/gpio/gpio_ambiq.c b/drivers/gpio/gpio_ambiq.c index e264a4096d8..0c0f1db458c 100644 --- a/drivers/gpio/gpio_ambiq.c +++ b/drivers/gpio/gpio_ambiq.c @@ -37,6 +37,41 @@ static int ambiq_gpio_pin_configure(const struct device *dev, gpio_pin_t pin, gp { const struct ambiq_gpio_config *const dev_cfg = dev->config; +#if defined(CONFIG_SOC_SERIES_APOLLO3X) + pin += dev_cfg->offset; + + am_hal_gpio_pincfg_t pincfg = g_AM_HAL_GPIO_DEFAULT; + + if (flags & GPIO_INPUT) { + pincfg = g_AM_HAL_GPIO_INPUT; + if (flags & GPIO_PULL_UP) { + pincfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_1_5K; + } else if (flags & GPIO_PULL_DOWN) { + pincfg.ePullup = AM_HAL_GPIO_PIN_PULLDOWN; + } + } + if (flags & GPIO_OUTPUT) { + if (flags & GPIO_SINGLE_ENDED) { + if (flags & GPIO_LINE_OPEN_DRAIN) { + pincfg.eGPOutcfg = AM_HAL_GPIO_PIN_OUTCFG_OPENDRAIN; + } + } else { + pincfg.eGPOutcfg = AM_HAL_GPIO_PIN_OUTCFG_PUSHPULL; + } + } + if (flags & GPIO_DISCONNECTED) { + pincfg = g_AM_HAL_GPIO_DEFAULT; + } + + if (flags & GPIO_OUTPUT_INIT_HIGH) { + pincfg.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.eCEpol = AM_HAL_GPIO_PIN_CEPOL_ACTIVELOW; + am_hal_gpio_state_write(pin, AM_HAL_GPIO_OUTPUT_CLEAR); + } +#else pin += (dev_cfg->offset >> 2); am_hal_gpio_pincfg_t pincfg = am_hal_gpio_pincfg_default; @@ -70,7 +105,7 @@ static int ambiq_gpio_pin_configure(const struct device *dev, gpio_pin_t pin, gp pincfg.GP.cfg_b.eCEpol = AM_HAL_GPIO_PIN_CEPOL_ACTIVELOW; am_hal_gpio_state_write(pin, AM_HAL_GPIO_OUTPUT_CLEAR); } - +#endif am_hal_gpio_pinconfig(pin, pincfg); return 0; @@ -82,6 +117,40 @@ static int ambiq_gpio_get_config(const struct device *dev, gpio_pin_t pin, gpio_ const struct ambiq_gpio_config *const dev_cfg = dev->config; am_hal_gpio_pincfg_t pincfg; +#if defined(CONFIG_SOC_SERIES_APOLLO3X) + pin += dev_cfg->offset; + + am_hal_gpio_pinconfig_get(pin, &pincfg); + + if (pincfg.eGPOutcfg == AM_HAL_GPIO_PIN_OUTCFG_DISABLE && + pincfg.eGPInput == AM_HAL_GPIO_PIN_INPUT_NONE) { + *out_flags = GPIO_DISCONNECTED; + } + if (pincfg.eGPInput == AM_HAL_GPIO_PIN_INPUT_ENABLE) { + *out_flags = GPIO_INPUT; + if (pincfg.ePullup == AM_HAL_GPIO_PIN_PULLUP_1_5K) { + *out_flags |= GPIO_PULL_UP; + } else if (pincfg.ePullup == AM_HAL_GPIO_PIN_PULLDOWN) { + *out_flags |= GPIO_PULL_DOWN; + } + } + if (pincfg.eGPOutcfg == AM_HAL_GPIO_PIN_OUTCFG_PUSHPULL) { + *out_flags = GPIO_OUTPUT | GPIO_PUSH_PULL; + if (pincfg.eCEpol == AM_HAL_GPIO_PIN_CEPOL_ACTIVEHIGH) { + *out_flags |= GPIO_OUTPUT_HIGH; + } else if (pincfg.eCEpol == AM_HAL_GPIO_PIN_CEPOL_ACTIVELOW) { + *out_flags |= GPIO_OUTPUT_LOW; + } + } + if (pincfg.eGPOutcfg == AM_HAL_GPIO_PIN_OUTCFG_OPENDRAIN) { + *out_flags = GPIO_OUTPUT | GPIO_OPEN_DRAIN; + if (pincfg.eCEpol == AM_HAL_GPIO_PIN_CEPOL_ACTIVEHIGH) { + *out_flags |= GPIO_OUTPUT_HIGH; + } else if (pincfg.eCEpol == AM_HAL_GPIO_PIN_CEPOL_ACTIVELOW) { + *out_flags |= GPIO_OUTPUT_LOW; + } + } +#else pin += (dev_cfg->offset >> 2); am_hal_gpio_pinconfig_get(pin, &pincfg); @@ -114,7 +183,7 @@ static int ambiq_gpio_get_config(const struct device *dev, gpio_pin_t pin, gpio_ *out_flags |= GPIO_OUTPUT_LOW; } } - +#endif return 0; } #endif @@ -127,6 +196,33 @@ static int ambiq_gpio_port_get_direction(const struct device *dev, gpio_port_pin am_hal_gpio_pincfg_t pincfg; gpio_port_pins_t ip = 0; gpio_port_pins_t op = 0; +#if defined(CONFIG_SOC_SERIES_APOLLO3X) + uint32_t pin_offset = dev_cfg->offset; + + 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.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.eGPOutcfg == AM_HAL_GPIO_PIN_OUTCFG_PUSHPULL || + pincfg.eGPOutcfg == AM_HAL_GPIO_PIN_OUTCFG_OPENDRAIN) { + op |= BIT(i); + } + } + } + *outputs = op; + } +#else uint32_t pin_offset = dev_cfg->offset >> 2; if (inputs != NULL) { @@ -152,7 +248,7 @@ static int ambiq_gpio_port_get_direction(const struct device *dev, gpio_port_pin } *outputs = op; } - +#endif return 0; } #endif @@ -161,8 +257,11 @@ static int ambiq_gpio_port_get_raw(const struct device *dev, gpio_port_value_t * { const struct ambiq_gpio_config *const dev_cfg = dev->config; +#if defined(CONFIG_SOC_SERIES_APOLLO3X) + *value = (*AM_HAL_GPIO_RDn(dev_cfg->offset)); +#else *value = (*AM_HAL_GPIO_RDn(dev_cfg->offset >> 2)); - +#endif return 0; } @@ -170,8 +269,11 @@ static int ambiq_gpio_port_set_masked_raw(const struct device *dev, gpio_port_pi gpio_port_value_t value) { const struct ambiq_gpio_config *const dev_cfg = dev->config; +#if defined(CONFIG_SOC_SERIES_APOLLO3X) + uint32_t pin_offset = dev_cfg->offset; +#else uint32_t pin_offset = dev_cfg->offset >> 2; - +#endif for (int i = 0; i < dev_cfg->ngpios; i++) { if ((mask >> i) & 1) { am_hal_gpio_state_write(i + pin_offset, ((value >> i) & 1)); @@ -184,7 +286,11 @@ static int ambiq_gpio_port_set_masked_raw(const struct device *dev, gpio_port_pi 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; +#if defined(CONFIG_SOC_SERIES_APOLLO3X) + uint32_t pin_offset = dev_cfg->offset; +#else uint32_t pin_offset = dev_cfg->offset >> 2; +#endif for (int i = 0; i < dev_cfg->ngpios; i++) { if ((pins >> i) & 1) { @@ -198,7 +304,11 @@ static int ambiq_gpio_port_set_bits_raw(const struct device *dev, gpio_port_pins 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; +#if defined(CONFIG_SOC_SERIES_APOLLO3X) + uint32_t pin_offset = dev_cfg->offset; +#else uint32_t pin_offset = dev_cfg->offset >> 2; +#endif for (int i = 0; i < dev_cfg->ngpios; i++) { if ((pins >> i) & 1) { @@ -212,7 +322,11 @@ static int ambiq_gpio_port_clear_bits_raw(const struct device *dev, gpio_port_pi 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; +#if defined(CONFIG_SOC_SERIES_APOLLO3X) + uint32_t pin_offset = dev_cfg->offset; +#else uint32_t pin_offset = dev_cfg->offset >> 2; +#endif for (int i = 0; i < dev_cfg->ngpios; i++) { if ((pins >> i) & 1) { @@ -223,17 +337,49 @@ static int ambiq_gpio_port_toggle_bits(const struct device *dev, gpio_port_pins_ return 0; } +#define APOLLO3_HANDLE_SHARED_GPIO_IRQ(n) \ + static const struct device *const dev_##n = DEVICE_DT_INST_GET(n); \ + const struct ambiq_gpio_config *cfg_##n = dev_##n->config; \ + struct ambiq_gpio_data *const data_##n = dev_##n->data; \ + uint32_t status_##n = (uint32_t)(ui64Status >> cfg_##n->offset); \ + if (status_##n) { \ + gpio_fire_callbacks(&data_##n->cb, dev_##n, status_##n); \ + } + +#define APOLLO3P_HANDLE_SHARED_GPIO_IRQ(n) \ + static const struct device *const dev_##n = DEVICE_DT_INST_GET(n); \ + struct ambiq_gpio_data *const data_##n = dev_##n->data; \ + if (pGpioIntStatusMask->U.Msk[n]) { \ + gpio_fire_callbacks(&data_##n->cb, dev_##n, pGpioIntStatusMask->U.Msk[n]); \ + } + static void ambiq_gpio_isr(const struct device *dev) { +#if defined(CONFIG_SOC_SERIES_APOLLO3X) + ARG_UNUSED(dev); + +#if defined(CONFIG_SOC_APOLLO3_BLUE) + uint64_t ui64Status; + + am_hal_gpio_interrupt_status_get(false, &ui64Status); + am_hal_gpio_interrupt_clear(ui64Status); + DT_INST_FOREACH_STATUS_OKAY(APOLLO3_HANDLE_SHARED_GPIO_IRQ) +#elif defined(CONFIG_SOC_APOLLO3P_BLUE) + AM_HAL_GPIO_MASKCREATE(GpioIntStatusMask); + am_hal_gpio_interrupt_status_get(false, pGpioIntStatusMask); + am_hal_gpio_interrupt_clear(pGpioIntStatusMask); + DT_INST_FOREACH_STATUS_OKAY(APOLLO3P_HANDLE_SHARED_GPIO_IRQ) +#endif +#else + uint32_t int_status; 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); +#endif } static int ambiq_gpio_pin_interrupt_configure(const struct device *dev, gpio_pin_t pin, @@ -242,10 +388,57 @@ static int ambiq_gpio_pin_interrupt_configure(const struct device *dev, gpio_pin 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 ret; +#if defined(CONFIG_SOC_SERIES_APOLLO3X) + am_hal_gpio_pincfg_t pincfg = g_AM_HAL_GPIO_DEFAULT; + int gpio_pin = pin + dev_cfg->offset; + + ret = am_hal_gpio_pinconfig_get(gpio_pin, &pincfg); + + if (mode == GPIO_INT_MODE_DISABLED) { + pincfg.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); + + AM_HAL_GPIO_MASKCREATE(GpioIntMask); + ret = am_hal_gpio_interrupt_clear(AM_HAL_GPIO_MASKBIT(pGpioIntMask, gpio_pin)); + ret = am_hal_gpio_interrupt_disable(AM_HAL_GPIO_MASKBIT(pGpioIntMask, 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.eIntDir = AM_HAL_GPIO_PIN_INTDIR_HI2LO; + break; + case GPIO_INT_TRIG_HIGH: + pincfg.eIntDir = AM_HAL_GPIO_PIN_INTDIR_LO2HI; + break; + case GPIO_INT_TRIG_BOTH: + pincfg.eIntDir = AM_HAL_GPIO_PIN_INTDIR_BOTH; + break; + default: + pincfg.eIntDir = AM_HAL_GPIO_PIN_INTDIR_NONE; + break; + } + ret = am_hal_gpio_pinconfig(gpio_pin, pincfg); + + irq_enable(dev_cfg->irq_num); + + k_spinlock_key_t key = k_spin_lock(&data->lock); + + AM_HAL_GPIO_MASKCREATE(GpioIntMask); + ret = am_hal_gpio_interrupt_clear(AM_HAL_GPIO_MASKBIT(pGpioIntMask, gpio_pin)); + ret = am_hal_gpio_interrupt_enable(AM_HAL_GPIO_MASKBIT(pGpioIntMask, gpio_pin)); + k_spin_unlock(&data->lock, key); + } +#else + am_hal_gpio_pincfg_t pincfg = am_hal_gpio_pincfg_default; int gpio_pin = pin + (dev_cfg->offset >> 2); uint32_t int_status; - int ret; ret = am_hal_gpio_pinconfig_get(gpio_pin, &pincfg); @@ -295,6 +488,7 @@ static int ambiq_gpio_pin_interrupt_configure(const struct device *dev, gpio_pin (void *)&gpio_pin); k_spin_unlock(&data->lock, key); } +#endif return ret; } @@ -306,14 +500,36 @@ static int ambiq_gpio_manage_callback(const struct device *dev, struct gpio_call return gpio_manage_callback(&data->cb, callback, set); } +#if defined(CONFIG_SOC_SERIES_APOLLO3X) +static void ambiq_gpio_cfg_func(void) +{ + /* Apollo3 GPIO banks share the same irq number, connect to bank0 once when init and handle + * different banks in ambiq_gpio_isr + */ + static bool global_irq_init = true; + + if (!global_irq_init) { + return; + } + + global_irq_init = false; + + /* Shared irq config default to BANK0. */ + IRQ_CONNECT(GPIO_IRQn, DT_INST_IRQ(0, priority), ambiq_gpio_isr, DEVICE_DT_INST_GET(0), 0); +} +#endif + 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); +#if defined(CONFIG_SOC_SERIES_APOLLO3X) + ambiq_gpio_cfg_func(); +#else dev_cfg->cfg_func(); - +#endif return 0; } @@ -334,10 +550,25 @@ static const struct gpio_driver_api ambiq_gpio_drv_api = { #endif }; +#if defined(CONFIG_SOC_SERIES_APOLLO3X) +/* Apollo3 GPIO banks share the same irq number, connect irq here will cause build error, so we + * leave this function blank here and do it in ambiq_gpio_cfg_func + */ +#define AMBIQ_GPIO_CONFIG_FUNC(n) static void ambiq_gpio_cfg_func_##n(void){}; +#else +#define AMBIQ_GPIO_CONFIG_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; \ + }; +#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 = \ { \ @@ -348,15 +579,7 @@ static const struct gpio_driver_api ambiq_gpio_drv_api = { .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; \ - }; \ - \ + AMBIQ_GPIO_CONFIG_FUNC(n) \ 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); diff --git a/drivers/gpio/gpio_brcmstb.c b/drivers/gpio/gpio_brcmstb.c new file mode 100644 index 00000000000..cfec6868f29 --- /dev/null +++ b/drivers/gpio/gpio_brcmstb.c @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2024 Junho Lee + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT brcm_brcmstb_gpio + +#include +#include +#include +#include +#include + +#define GIO_DATA 0x04 +#define GIO_IODIR 0x08 + +#define DEV_CFG(dev) ((const struct gpio_brcmstb_config *)(dev)->config) +#define DEV_DATA(dev) ((struct gpio_brcmstb_data *)(dev)->data) + +struct gpio_brcmstb_config { + struct gpio_driver_config common; + + DEVICE_MMIO_NAMED_ROM(reg_base); + mem_addr_t offset; +}; + +struct gpio_brcmstb_data { + struct gpio_driver_data common; + + DEVICE_MMIO_NAMED_RAM(reg_base); + mem_addr_t base; +}; + +static int gpio_brcmstb_pin_configure(const struct device *port, gpio_pin_t pin, gpio_flags_t flags) +{ + struct gpio_brcmstb_data *data = port->data; + + if (flags & (GPIO_SINGLE_ENDED | GPIO_PULL_UP | GPIO_PULL_DOWN)) { + return -ENOTSUP; + } + + if (flags & GPIO_INPUT) { + sys_set_bit(data->base + GIO_IODIR, pin); + } else if (flags & GPIO_OUTPUT) { + sys_clear_bit(data->base + GIO_IODIR, pin); + + if (flags & GPIO_OUTPUT_INIT_HIGH) { + sys_set_bit(data->base + GIO_DATA, pin); + } else if (flags & GPIO_OUTPUT_INIT_LOW) { + sys_clear_bit(data->base + GIO_DATA, pin); + } + } + + return 0; +} + +static int gpio_brcmstb_port_get_raw(const struct device *port, gpio_port_value_t *value) +{ + struct gpio_brcmstb_data *data = port->data; + + *value = sys_read32(data->base + GIO_DATA); + + return 0; +} + +static int gpio_brcmstb_port_set_masked_raw(const struct device *port, gpio_port_pins_t mask, + gpio_port_value_t value) +{ + struct gpio_brcmstb_data *data = port->data; + + sys_clear_bits(data->base + GIO_DATA, mask); + sys_set_bits(data->base + GIO_DATA, (value & mask)); + + return 0; +} + +static int gpio_brcmstb_port_set_bits_raw(const struct device *port, gpio_port_pins_t pins) +{ + struct gpio_brcmstb_data *data = port->data; + + sys_set_bits(data->base + GIO_DATA, pins); + + return 0; +} + +static int gpio_brcmstb_port_clear_bits_raw(const struct device *port, gpio_port_pins_t pins) +{ + struct gpio_brcmstb_data *data = port->data; + + sys_clear_bits(data->base + GIO_DATA, pins); + + return 0; +} + +static int gpio_brcmstb_port_toggle_bits(const struct device *port, gpio_port_pins_t pins) +{ + struct gpio_brcmstb_data *data = port->data; + uint32_t reg_data; + + reg_data = sys_read32(data->base + GIO_DATA); + reg_data ^= pins; + sys_write32(reg_data, data->base + GIO_DATA); + + return 0; +} + +static const struct gpio_driver_api gpio_brcmstb_api = { + .pin_configure = gpio_brcmstb_pin_configure, + .port_get_raw = gpio_brcmstb_port_get_raw, + .port_set_masked_raw = gpio_brcmstb_port_set_masked_raw, + .port_set_bits_raw = gpio_brcmstb_port_set_bits_raw, + .port_clear_bits_raw = gpio_brcmstb_port_clear_bits_raw, + .port_toggle_bits = gpio_brcmstb_port_toggle_bits, +}; + +int gpio_brcmstb_init(const struct device *port) +{ + const struct gpio_brcmstb_config *config = port->config; + struct gpio_brcmstb_data *data = port->data; + + DEVICE_MMIO_NAMED_MAP(port, reg_base, K_MEM_CACHE_NONE); + data->base = DEVICE_MMIO_NAMED_GET(port, reg_base) + config->offset; + + return 0; +} + +#define GPIO_BRCMSTB_INIT(n) \ + static struct gpio_brcmstb_data gpio_brcmstb_data_##n; \ + \ + static const struct gpio_brcmstb_config gpio_brcmstb_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)), \ + .offset = DT_INST_REG_ADDR(n), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(n, gpio_brcmstb_init, NULL, &gpio_brcmstb_data_##n, \ + &gpio_brcmstb_cfg_##n, PRE_KERNEL_1, CONFIG_GPIO_INIT_PRIORITY, \ + &gpio_brcmstb_api); + +DT_INST_FOREACH_STATUS_OKAY(GPIO_BRCMSTB_INIT) diff --git a/drivers/gpio/gpio_intel.c b/drivers/gpio/gpio_intel.c index ef09121eaf4..cd62d9ce0e4 100644 --- a/drivers/gpio/gpio_intel.c +++ b/drivers/gpio/gpio_intel.c @@ -27,11 +27,10 @@ #include #include #include - +#include +#include #include -BUILD_ASSERT(DT_INST_IRQN(0) == 14); - #define REG_MISCCFG 0x0010 #define MISCCFG_IRQ_ROUTE_POS 3 @@ -99,9 +98,11 @@ struct gpio_intel_config { DEVICE_MMIO_NAMED_ROM(reg_base); - uint8_t pin_offset; +#if !DT_ANY_INST_HAS_PROP_STATUS_OKAY(acpi_hid) + uint8_t pin_offset; uint8_t group_index; - uint8_t num_pins; + uint8_t num_pins; +#endif }; struct gpio_intel_data { @@ -114,17 +115,64 @@ struct gpio_intel_data { uint32_t pad_base; sys_slist_t cb; +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(acpi_hid) + uint32_t num_pins; + uint32_t pad_owner_reg; + uint32_t host_owner_reg; + uint32_t intr_stat_reg; + uint32_t base_num; +#endif }; +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(acpi_hid) +#define GPIO_REG_BASE_GET(dev) DEVICE_MMIO_NAMED_GET(dev, reg_base) + +#define REG_GPI_INT_STS_BASE_GET(data) (data)->intr_stat_reg + +#define REG_GPI_INT_EN_BASE_GET(data) (data)->intr_stat_reg + 0x20 + +#define PIN_OFFSET_GET(dev) (0) + +#define GPIO_PAD_OWNERSHIP_GET(data, pin, offset) (data)->pad_owner_reg + (((pin) / 8) * 0x4) + +#define REG_PAD_HOST_SW_OWNER_GET(data) (data)->host_owner_reg + +#define GPIO_BASE_GET(cdf) (0) + +#define GPIO_INTERRUPT_BASE_GET(cfg) (0) + +#define GPIO_GET_PIN_MAX(dev) ((struct gpio_intel_data *)(dev)->data)->num_pins +#else /* Non-ACPI */ +#define GPIO_REG_BASE_GET(dev) GPIO_REG_BASE(DEVICE_MMIO_NAMED_GET(dev, reg_base)) + +#define REG_GPI_INT_STS_BASE_GET(data) REG_GPI_INT_STS_BASE + +#define REG_GPI_INT_EN_BASE_GET(data) REG_GPI_INT_EN_BASE + +#define PIN_OFFSET_GET(dev) ((const struct gpio_intel_config *)(dev)->config)->pin_offset + +#define GPIO_PAD_OWNERSHIP_GET(data, pin, offset) GPIO_PAD_OWNERSHIP(pin, offset) + +#define REG_PAD_HOST_SW_OWNER_GET(data) REG_PAD_HOST_SW_OWNER + +#define GPIO_BASE_GET(cdf) GPIO_BASE(((const struct gpio_intel_config *)(dev)->config)) + +#define GPIO_INTERRUPT_BASE_GET(cfg) GPIO_INTERRUPT_BASE(cfg) + +#define GPIO_GET_PIN_MAX(dev) ((const struct gpio_intel_config *)(dev)->config)->num_pins +#endif + static inline mm_reg_t regs(const struct device *dev) { - return GPIO_REG_BASE(DEVICE_MMIO_NAMED_GET(dev, reg_base)); + return GPIO_REG_BASE_GET(dev); } +#if !DT_ANY_INST_HAS_PROP_STATUS_OKAY(acpi_hid) static inline mm_reg_t pad_base(const struct device *dev) { return GPIO_PAD_BASE(DEVICE_MMIO_NAMED_GET(dev, reg_base)); } +#endif #ifdef CONFIG_GPIO_INTEL_CHECK_PERMS /** @@ -138,14 +186,14 @@ static inline mm_reg_t pad_base(const struct device *dev) static bool check_perm(const struct device *dev, uint32_t raw_pin) { struct gpio_intel_data *data = dev->data; - const struct gpio_intel_config *cfg = dev->config; uint32_t offset, val, pin_offset; - pin_offset = cfg->pin_offset; + pin_offset = PIN_OFFSET_GET(dev); /* First is to establish that host software owns the pin */ /* read the Pad Ownership register related to the pin */ - offset = GPIO_PAD_OWNERSHIP(raw_pin, pin_offset); + offset = GPIO_PAD_OWNERSHIP_GET(data, raw_pin, pin_offset); + val = sys_read32(regs(dev) + offset); /* get the bits about ownership */ @@ -175,9 +223,7 @@ static bool check_perm(const struct device *dev, uint32_t raw_pin) * to the list of devices to check at ISR time. */ -static int nr_isr_devs; - -static const struct device *isr_devs[GPIO_INTEL_NR_SUBDEVS]; +static bool first_inst = true; static void gpio_intel_isr(const struct device *dev) { @@ -185,36 +231,30 @@ static void gpio_intel_isr(const struct device *dev) struct gpio_intel_data *data; struct gpio_callback *cb, *tmp; uint32_t reg, int_sts, cur_mask, acc_mask; - int isr_dev; - - for (isr_dev = 0; isr_dev < nr_isr_devs; ++isr_dev) { - dev = isr_devs[isr_dev]; - cfg = dev->config; - data = dev->data; - - reg = regs(dev) + REG_GPI_INT_STS_BASE - + GPIO_INTERRUPT_BASE(cfg); - int_sts = sys_read32(reg); - acc_mask = 0U; - - SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&data->cb, cb, tmp, node) { - cur_mask = int_sts & cb->pin_mask; - acc_mask |= cur_mask; - if (cur_mask) { - __ASSERT(cb->handler, "No callback handler!"); - cb->handler(dev, cb, cur_mask); - } - } - /* clear handled interrupt bits */ - sys_write32(acc_mask, reg); + cfg = dev->config; + data = dev->data; + + reg = regs(dev) + REG_GPI_INT_STS_BASE_GET(data) + GPIO_INTERRUPT_BASE_GET(cfg); + int_sts = sys_read32(reg); + acc_mask = 0U; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&data->cb, cb, tmp, node) { + cur_mask = int_sts & cb->pin_mask; + acc_mask |= cur_mask; + if (cur_mask) { + __ASSERT(cb->handler, "No callback handler!"); + cb->handler(dev, cb, cur_mask); + } } + + /* clear handled interrupt bits */ + sys_write32(acc_mask, reg); } static int gpio_intel_config(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags) { - const struct gpio_intel_config *cfg = dev->config; struct gpio_intel_data *data = dev->data; uint32_t raw_pin, reg, cfg0, cfg1; @@ -223,9 +263,9 @@ static int gpio_intel_config(const struct device *dev, return -ENOTSUP; } - pin = k_array_index_sanitize(pin, cfg->num_pins + 1); + pin = k_array_index_sanitize(pin, GPIO_GET_PIN_MAX(dev) + 1); - raw_pin = GPIO_RAW_PIN(pin, cfg->pin_offset); + raw_pin = GPIO_RAW_PIN(pin, PIN_OFFSET_GET(dev)); if (!check_perm(dev, raw_pin)) { return -EINVAL; @@ -290,7 +330,6 @@ static int gpio_intel_pin_interrupt_configure(const struct device *dev, enum gpio_int_mode mode, enum gpio_int_trig trig) { - const struct gpio_intel_config *cfg = dev->config; struct gpio_intel_data *data = dev->data; uint32_t raw_pin, cfg0, cfg1; uint32_t reg, reg_en, reg_sts; @@ -300,30 +339,32 @@ static int gpio_intel_pin_interrupt_configure(const struct device *dev, return -ENOTSUP; } - pin = k_array_index_sanitize(pin, cfg->num_pins + 1); + pin = k_array_index_sanitize(pin, GPIO_GET_PIN_MAX(dev) + 1); - raw_pin = GPIO_RAW_PIN(pin, cfg->pin_offset); + raw_pin = GPIO_RAW_PIN(pin, PIN_OFFSET_GET(dev)); if (!check_perm(dev, raw_pin)) { return -EINVAL; } /* set owner to GPIO driver mode for legacy interrupt mode */ - reg = regs(dev) + REG_PAD_HOST_SW_OWNER + GPIO_BASE(cfg); + reg = regs(dev) + REG_PAD_HOST_SW_OWNER_GET(data) + GPIO_BASE_GET(dev); + sys_bitfield_set_bit(reg, raw_pin); /* read in pad configuration register */ reg = regs(dev) + data->pad_base + (raw_pin * PIN_OFFSET); + cfg0 = sys_read32(reg); cfg1 = sys_read32(reg + 4); - reg_en = regs(dev) + REG_GPI_INT_EN_BASE + GPIO_BASE(cfg); + reg_en = regs(dev) + REG_GPI_INT_EN_BASE_GET(data) + GPIO_BASE_GET(dev); /* disable interrupt bit first before setup */ sys_bitfield_clear_bit(reg_en, raw_pin); /* clear (by setting) interrupt status bit */ - reg_sts = regs(dev) + REG_GPI_INT_STS_BASE + GPIO_BASE(cfg); + reg_sts = regs(dev) + REG_GPI_INT_STS_BASE_GET(data) + GPIO_BASE_GET(dev); sys_bitfield_set_bit(reg_sts, raw_pin); /* clear level/edge configuration bits */ @@ -390,7 +431,6 @@ static int port_get_raw(const struct device *dev, uint32_t mask, uint32_t *value, bool read_tx) { - const struct gpio_intel_config *cfg = dev->config; struct gpio_intel_data *data = dev->data; uint32_t pin, raw_pin, reg_addr, reg_val, cmp; @@ -404,13 +444,13 @@ static int port_get_raw(const struct device *dev, uint32_t mask, while (mask != 0U) { pin = find_lsb_set(mask) - 1; - if (pin >= cfg->num_pins) { + if (pin >= GPIO_GET_PIN_MAX(dev)) { break; } mask &= ~BIT(pin); - raw_pin = GPIO_RAW_PIN(pin, cfg->pin_offset); + raw_pin = GPIO_RAW_PIN(pin, PIN_OFFSET_GET(dev)); if (!check_perm(dev, raw_pin)) { continue; @@ -430,20 +470,19 @@ static int port_get_raw(const struct device *dev, uint32_t mask, static int port_set_raw(const struct device *dev, uint32_t mask, uint32_t value) { - const struct gpio_intel_config *cfg = dev->config; struct gpio_intel_data *data = dev->data; uint32_t pin, raw_pin, reg_addr, reg_val; while (mask != 0) { pin = find_lsb_set(mask) - 1; - if (pin >= cfg->num_pins) { + if (pin >= GPIO_GET_PIN_MAX(dev)) { break; } mask &= ~BIT(pin); - raw_pin = GPIO_RAW_PIN(pin, cfg->pin_offset); + raw_pin = GPIO_RAW_PIN(pin, PIN_OFFSET_GET(dev)); if (!check_perm(dev, raw_pin)) { continue; @@ -522,7 +561,66 @@ static const struct gpio_driver_api gpio_intel_api = { .pin_interrupt_configure = gpio_intel_pin_interrupt_configure, }; -int gpio_intel_init(const struct device *dev) +/* We need support either DTS or ACPI base resource enumeration at time.*/ +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(acpi_hid) + +static int gpio_intel_acpi_enum(const struct device *dev, int bank_idx, char *hid, char *uid) +{ + int ret; + struct gpio_acpi_res res; + struct gpio_intel_data *data = dev->data; + + ret = soc_acpi_gpio_resource_get(bank_idx, hid, uid, &res); + if (ret) { + return ret; + } + + device_map(&data->reg_base, res.reg_base, res.len, K_MEM_CACHE_NONE); + + data->num_pins = res.num_pins; + data->pad_owner_reg = res.pad_owner_reg; + data->host_owner_reg = res.host_owner_reg; + data->intr_stat_reg = res.intr_stat_reg; + data->base_num = res.base_num; + data->pad_base = res.pad_base; + + /* Note that all controllers are using the same IRQ line. + * So we can just use the values from the first instance. + */ + if (first_inst) { + irq_connect_dynamic(res.irq, DT_INST_IRQ(0, priority), + (void (*)(const void *))gpio_intel_isr, dev, res.irq_flags); + irq_enable(res.irq); + first_inst = false; + } + + if (IS_ENABLED(CONFIG_SOC_APOLLO_LAKE)) { + /* route to IRQ 14 */ + sys_bitfield_clear_bit(regs(dev) + REG_MISCCFG, MISCCFG_IRQ_ROUTE_POS); + } + + return 0; +} + +#define GPIO_INIT_FN_DEFINE(n) \ + static int gpio_intel_init##n(const struct device *dev) \ + { \ + return gpio_intel_acpi_enum(dev, DT_INST_PROP(n, group_index), \ + ACPI_DT_HID(DT_DRV_INST(n)), ACPI_DT_UID(DT_DRV_INST(n))); \ + } + +#define GPIO_MMIO_ROM_INIT(n) + +#define GPIO_INIT_CONFIG(n) \ + static const struct gpio_intel_config gpio_intel_cfg_##n = { \ + .common = \ + { \ + .port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(n), \ + }, \ + } +#else + +static int gpio_intel_dts_init(const struct device *dev) { struct gpio_intel_data *data = dev->data; @@ -551,21 +649,19 @@ int gpio_intel_init(const struct device *dev) #endif data->pad_base = pad_base(dev); - __ASSERT(nr_isr_devs < GPIO_INTEL_NR_SUBDEVS, "too many subdevs"); - - if (nr_isr_devs == 0) { + if (first_inst) { /* Note that all controllers are using the same IRQ line. * So we can just use the values from the first instance. */ IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), - gpio_intel_isr, NULL, + gpio_intel_isr, dev, DT_INST_IRQ(0, sense)); irq_enable(DT_INST_IRQN(0)); - } - isr_devs[nr_isr_devs++] = dev; + first_inst = false; + } if (IS_ENABLED(CONFIG_SOC_APOLLO_LAKE)) { /* route to IRQ 14 */ @@ -575,26 +671,34 @@ int gpio_intel_init(const struct device *dev) return 0; } -#define GPIO_INTEL_DEV_CFG_DATA(n) \ - static const struct gpio_intel_config \ - gpio_intel_cfg_##n = { \ - .common = { \ - .port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(n), \ - }, \ - DEVICE_MMIO_NAMED_ROM_INIT(reg_base, DT_DRV_INST(n)), \ - .pin_offset = DT_INST_PROP(n, pin_offset), \ - .group_index = DT_INST_PROP_OR(n, group_index, 0), \ - .num_pins = DT_INST_PROP(n, ngpios), \ - }; \ - \ - static struct gpio_intel_data gpio_intel_data_##n; \ - \ - DEVICE_DT_INST_DEFINE(n, \ - gpio_intel_init, \ - NULL, \ - &gpio_intel_data_##n, \ - &gpio_intel_cfg_##n, \ - POST_KERNEL, CONFIG_GPIO_INIT_PRIORITY, \ +#define GPIO_INIT_FN_DEFINE(n) \ + static int gpio_intel_init##n(const struct device *dev) \ + { \ + return gpio_intel_dts_init(dev); \ + } + +#define GPIO_MMIO_ROM_INIT(n) DEVICE_MMIO_NAMED_ROM_INIT(reg_base, DT_DRV_INST(n)), + +#define GPIO_INIT_CONFIG(n) \ + static const struct gpio_intel_config gpio_intel_cfg_##n = { \ + .common = \ + { \ + .port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(n), \ + }, \ + GPIO_MMIO_ROM_INIT(n).pin_offset = DT_INST_PROP(n, pin_offset), \ + .group_index = DT_INST_PROP_OR(n, group_index, 0), \ + .num_pins = DT_INST_PROP(n, ngpios), \ + } + +#endif + +#define GPIO_INTEL_DEV_CFG_DATA(n) \ + GPIO_INIT_FN_DEFINE(n) \ + GPIO_INIT_CONFIG(n); \ + static struct gpio_intel_data gpio_intel_data_##n; \ + \ + DEVICE_DT_INST_DEFINE(n, gpio_intel_init##n, NULL, &gpio_intel_data_##n, \ + &gpio_intel_cfg_##n, POST_KERNEL, CONFIG_GPIO_INIT_PRIORITY, \ &gpio_intel_api); /* "sub" devices. no more than GPIO_INTEL_NR_SUBDEVS of these! */ diff --git a/drivers/gpio/gpio_mcux.c b/drivers/gpio/gpio_mcux.c index 8fa48abc8c6..f7d15e3cf0c 100644 --- a/drivers/gpio/gpio_mcux.c +++ b/drivers/gpio/gpio_mcux.c @@ -332,6 +332,40 @@ static void gpio_mcux_port_isr(const struct device *dev) gpio_fire_callbacks(&data->callbacks, dev, int_status); } +#define GPIO_HAS_SHARED_IRQ DT_HAS_COMPAT_STATUS_OKAY(nxp_gpio_cluster) + +#if GPIO_HAS_SHARED_IRQ +static void gpio_mcux_shared_cluster_isr(const struct device *ports[]) +{ + const struct device **current_port = &ports[0]; + + while (*current_port != NULL) { + gpio_mcux_port_isr(*current_port); + current_port++; + } +} + +#define CLUSTER_ARRAY_ELEMENT(node_id) DEVICE_DT_GET(node_id), + +#define GPIO_MCUX_CLUSTER_INIT(node_id) \ + const struct device *shared_array##node_id[DT_CHILD_NUM_STATUS_OKAY(node_id) + 1] = \ + {DT_FOREACH_CHILD_STATUS_OKAY(node_id, CLUSTER_ARRAY_ELEMENT) NULL}; \ + \ + static int gpio_mcux_shared_interrupt_init##node_id(void) \ + { \ + IRQ_CONNECT(DT_IRQN(node_id), \ + DT_IRQ(node_id, priority), \ + gpio_mcux_shared_cluster_isr, \ + shared_array##node_id, 0); \ + irq_enable(DT_IRQN(node_id)); \ + \ + return 0; \ + } \ + SYS_INIT(gpio_mcux_shared_interrupt_init##node_id, POST_KERNEL, 0); + +DT_FOREACH_STATUS_OKAY(nxp_gpio_cluster, GPIO_MCUX_CLUSTER_INIT) +#endif + #ifdef CONFIG_GPIO_GET_DIRECTION static int gpio_mcux_port_get_direction(const struct device *dev, gpio_port_pins_t map, gpio_port_pins_t *inputs, gpio_port_pins_t *outputs) @@ -388,7 +422,8 @@ static const struct gpio_driver_api gpio_mcux_driver_api = { }, \ .gpio_base = (GPIO_Type *) DT_INST_REG_ADDR(n), \ .port_base = (PORT_Type *) GPIO_PORT_BASE_ADDR(n), \ - .flags = UTIL_AND(DT_INST_IRQ_HAS_IDX(n, 0), GPIO_INT_ENABLE),\ + .flags = UTIL_AND(UTIL_OR(DT_INST_IRQ_HAS_IDX(n, 0), \ + GPIO_HAS_SHARED_IRQ), GPIO_INT_ENABLE), \ }; \ \ static struct gpio_mcux_data gpio_mcux_port## n ##_data; \ diff --git a/drivers/gpio/gpio_numaker.c b/drivers/gpio/gpio_numaker.c index 2c7515f2981..c88e0d498ce 100644 --- a/drivers/gpio/gpio_numaker.c +++ b/drivers/gpio/gpio_numaker.c @@ -48,25 +48,10 @@ static int gpio_numaker_configure(const struct device *dev, gpio_pin_t pin, gpio ARG_UNUSED(data); /* Check for an invalid pin number */ - if (pin >= 15) { + if (pin > 15) { return -EINVAL; } - SYS_UnlockReg(); - - /* Enable GPIO clock */ - struct numaker_scc_subsys scc_subsys; - - memset(&scc_subsys, 0x00, sizeof(scc_subsys)); - scc_subsys.subsys_id = NUMAKER_SCC_SUBSYS_ID_PCC; - scc_subsys.pcc.clk_modidx = config->clk_modidx; - - /* Equivalent to CLK_EnableModuleClock(config->clk_modidx) */ - err = clock_control_on(config->clk_dev, (clock_control_subsys_t)&scc_subsys); - if (err != 0) { - goto move_exit; - } - /* Configure GPIO direction */ switch (flags & GPIO_DIR_MASK) { case GPIO_INPUT: @@ -114,7 +99,6 @@ static int gpio_numaker_configure(const struct device *dev, gpio_pin_t pin, gpio } move_exit: - SYS_LockReg(); return err; } @@ -265,8 +249,21 @@ static void gpio_numaker_isr(const struct device *dev) \ static int gpio_numaker_init##n(const struct device *dev) \ { \ - IF_ENABLED(DT_INST_IRQ_HAS_IDX(n, 0), (GPIO_NUMAKER_IRQ_INIT(n);)) \ - return 0; \ + const struct gpio_numaker_config *config = dev->config; \ + struct numaker_scc_subsys scc_subsys; \ + int err; \ + \ + 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; \ + err = clock_control_on(config->clk_dev, (clock_control_subsys_t)&scc_subsys); \ + if (err == 0) { \ + IF_ENABLED(DT_INST_IRQ_HAS_IDX(n, 0), (GPIO_NUMAKER_IRQ_INIT(n);)) \ + } \ + \ + SYS_LockReg(); \ + return err; \ } \ DEVICE_DT_INST_DEFINE(n, &gpio_numaker_init##n, NULL, &gpio_numaker_data##n, \ &gpio_numaker_config##n, PRE_KERNEL_1, CONFIG_GPIO_INIT_PRIORITY, \ diff --git a/drivers/gpio/gpio_shell.c b/drivers/gpio/gpio_shell.c index 48d7e95f7a7..7bb6b9c58cd 100644 --- a/drivers/gpio/gpio_shell.c +++ b/drivers/gpio/gpio_shell.c @@ -381,6 +381,26 @@ static int cmd_gpio_set(const struct shell *sh, size_t argc, char **argv) return 0; } +static int cmd_gpio_toggle(const struct shell *sh, size_t argc, char **argv) +{ + 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; + } + + ret = gpio_pin_toggle(gpio.dev, gpio.pin); + if (ret != 0) { + shell_error(sh, "error: %d", ret); + return ret; + } + + return 0; +} + /* 500 msec = 1/2 sec */ #define SLEEP_TIME_MS 500 @@ -595,6 +615,9 @@ SHELL_STATIC_SUBCMD_SET_CREATE(sub_gpio, 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_TOGGLE_CMD, toggle, &sub_gpio_dev, + "Toggle GPIO pin\n" + "Usage: gpio toggle ", cmd_gpio_toggle, 3, 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), diff --git a/drivers/gpio/gpio_smartbond.c b/drivers/gpio/gpio_smartbond.c index 81ce31296f2..06af6ffb621 100644 --- a/drivers/gpio/gpio_smartbond.c +++ b/drivers/gpio/gpio_smartbond.c @@ -11,9 +11,11 @@ #include #include #include +#include #include #include +#include #define GPIO_MODE_RESET 0x200 @@ -60,6 +62,14 @@ struct gpio_smartbond_data { /* Pins that are configured for both edges (handled by software) */ gpio_port_pins_t both_edges_pins; sys_slist_t callbacks; +#if CONFIG_PM_DEVICE + /* + * Saved state consist of: + * 1 word for GPIO output port state + * GPIOx_NGPIOS words for each pin mode + */ + uint32_t *gpio_saved_state; +#endif }; struct gpio_smartbond_config { @@ -71,6 +81,9 @@ struct gpio_smartbond_config { volatile struct gpio_smartbond_wkup_regs *wkup_regs; /* Value of TRIG_SELECT for PDC_CTRLx_REG entry */ uint8_t wkup_trig_select; +#if CONFIG_PM_DEVICE + uint8_t ngpios; +#endif }; static void gpio_smartbond_wkup_init(void) @@ -292,6 +305,78 @@ static void gpio_smartbond_isr(const struct device *dev) gpio_fire_callbacks(&data->callbacks, dev, stat); } +#ifdef CONFIG_PM_DEVICE + +static void gpio_latch_inst(mem_addr_t data_reg, mem_addr_t mode_reg, mem_addr_t latch_reg, + uint8_t ngpios, uint32_t *data, uint32_t *mode) +{ + uint8_t idx; + + *data = sys_read32(data_reg); + for (idx = 0; idx < ngpios; idx++, mode_reg += 4) { + mode[idx] = sys_read32(mode_reg); + } + sys_write32(BIT_MASK(ngpios), latch_reg); + +} + +static void gpio_unlatch_inst(mem_addr_t data_reg, mem_addr_t mode_reg, mem_addr_t latch_reg, + uint8_t ngpios, uint32_t data, uint32_t *mode) +{ + uint8_t idx; + + sys_write32(data, data_reg); + for (idx = 0; idx < ngpios; idx++, mode_reg += 4) { + sys_write32(mode[idx], mode_reg); + } + sys_write32(BIT_MASK(ngpios), latch_reg); +} + +static void gpio_latch(const struct device *dev) +{ + const struct gpio_smartbond_config *config = dev->config; + const struct gpio_smartbond_data *data = dev->data; + + gpio_latch_inst((mem_addr_t)&config->data_regs->data, + (mem_addr_t)config->mode_regs, + (mem_addr_t)&config->latch_regs->reset, + config->ngpios, data->gpio_saved_state, data->gpio_saved_state + 1); +} + +static void gpio_unlatch(const struct device *dev) +{ + const struct gpio_smartbond_config *config = dev->config; + const struct gpio_smartbond_data *data = dev->data; + + gpio_unlatch_inst((mem_addr_t)&config->data_regs->data, + (mem_addr_t)config->mode_regs, + (mem_addr_t)&config->latch_regs->set, + config->ngpios, data->gpio_saved_state[0], data->gpio_saved_state + 1); +} + +static int gpio_smartbond_pm_action(const struct device *dev, + enum pm_device_action action) +{ + int ret = 0; + + switch (action) { + case PM_DEVICE_ACTION_RESUME: + da1469x_pd_acquire(MCU_PD_DOMAIN_COM); + gpio_unlatch(dev); + break; + case PM_DEVICE_ACTION_SUSPEND: + gpio_latch(dev); + da1469x_pd_release(MCU_PD_DOMAIN_COM); + break; + default: + ret = -ENOTSUP; + } + + return ret; +} + +#endif /* CONFIG_PM_DEVICE */ + /* GPIO driver registration */ static const struct gpio_driver_api gpio_smartbond_drv_api_funcs = { .pin_configure = gpio_smartbond_pin_configure, @@ -304,8 +389,15 @@ static const struct gpio_driver_api gpio_smartbond_drv_api_funcs = { .manage_callback = gpio_smartbond_manage_callback, }; +#define GPIO_SAVED_STATE(id) gpio_smartbond_saved_state_##id +#define GPIO_PM_DEVICE_CFG(fld, val) \ + COND_CODE_1(CONFIG_PM_DEVICE, (fld = val,), ()) +#define GPIO_PM_DEVICE_STATE(id, ngpios) \ + COND_CODE_1(CONFIG_PM_DEVICE, (static uint32_t GPIO_SAVED_STATE(id)[1 + ngpios];), ()) + #define GPIO_SMARTBOND_DEVICE(id) \ - static const struct gpio_smartbond_config gpio_smartbond_p##id##_config = { \ + GPIO_PM_DEVICE_STATE(id, DT_INST_PROP(id, ngpios)) \ + static const struct gpio_smartbond_config gpio_smartbond_config_##id = { \ .common = { \ .port_pin_mask = \ GPIO_PORT_PIN_MASK_FROM_DT_INST(id), \ @@ -318,12 +410,16 @@ static const struct gpio_driver_api gpio_smartbond_drv_api_funcs = { .wkup_regs = (volatile struct gpio_smartbond_wkup_regs *) \ DT_INST_REG_ADDR_BY_NAME(id, wkup), \ .wkup_trig_select = id, \ + GPIO_PM_DEVICE_CFG(.ngpios, DT_INST_PROP(id, ngpios)) \ }; \ \ - static struct gpio_smartbond_data gpio_smartbond_p##id##_data; \ + static struct gpio_smartbond_data gpio_smartbond_data_##id = { \ + GPIO_PM_DEVICE_CFG(.gpio_saved_state, GPIO_SAVED_STATE(id)) \ + }; \ \ - static int gpio_smartbond_##id##_init(const struct device *dev) \ + static int gpio_smartbond_init_##id(const struct device *dev) \ { \ + da1469x_pd_acquire(MCU_PD_DOMAIN_COM); \ gpio_smartbond_wkup_init(); \ IRQ_CONNECT(DT_INST_IRQN(id), \ DT_INST_IRQ(id, priority), \ @@ -333,10 +429,11 @@ static const struct gpio_driver_api gpio_smartbond_drv_api_funcs = { return 0; \ } \ \ - DEVICE_DT_INST_DEFINE(id, gpio_smartbond_##id##_init, \ - NULL, \ - &gpio_smartbond_p##id##_data, \ - &gpio_smartbond_p##id##_config, \ + PM_DEVICE_DEFINE(id, gpio_smartbond_pm_action); \ + DEVICE_DT_INST_DEFINE(id, gpio_smartbond_init_##id, \ + PM_DEVICE_GET(id), \ + &gpio_smartbond_data_##id, \ + &gpio_smartbond_config_##id, \ PRE_KERNEL_1, \ CONFIG_GPIO_INIT_PRIORITY, \ &gpio_smartbond_drv_api_funcs); diff --git a/drivers/hwinfo/CMakeLists.txt b/drivers/hwinfo/CMakeLists.txt index 2e7d91141be..60707d59a61 100644 --- a/drivers/hwinfo/CMakeLists.txt +++ b/drivers/hwinfo/CMakeLists.txt @@ -29,3 +29,4 @@ 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) zephyr_library_sources_ifdef(CONFIG_HWINFO_RW61X hwinfo_rw61x.c) +zephyr_library_sources_ifdef(CONFIG_HWINFO_AMBIQ hwinfo_ambiq.c) diff --git a/drivers/hwinfo/Kconfig b/drivers/hwinfo/Kconfig index 467a36ad8af..0d3f6b991f9 100644 --- a/drivers/hwinfo/Kconfig +++ b/drivers/hwinfo/Kconfig @@ -173,7 +173,7 @@ config HWINFO_LITEX config HWINFO_PSOC6 bool "Cypress PSoC-6 unique device ID" default y - depends on SOC_FAMILY_PSOC6 + depends on SOC_FAMILY_PSOC6_LEGACY help Enable Cypress PSoC-6 hwinfo driver. @@ -189,6 +189,7 @@ config HWINFO_ANDES bool "Andes system ID" default y depends on SOC_FAMILY_ANDES_V5 + depends on SYSCON help Enable Andes hwinfo driver @@ -199,4 +200,13 @@ config HWINFO_RW61X help Enable RW61X hwinfo driver +config HWINFO_AMBIQ + bool "AMBIQ hwinfo" + default y + depends on SOC_SERIES_APOLLO4X + select AMBIQ_HAL + select AMBIQ_HAL_USE_HWINFO + help + Enable AMBIQ hwinfo driver + endif diff --git a/drivers/hwinfo/hwinfo_ambiq.c b/drivers/hwinfo/hwinfo_ambiq.c new file mode 100644 index 00000000000..80bcf62763a --- /dev/null +++ b/drivers/hwinfo/hwinfo_ambiq.c @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2024 Ambiq + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +ssize_t z_impl_hwinfo_get_device_id(uint8_t *buffer, size_t length) +{ + + struct ambiq_hwinfo { + /* Ambiq Chip ID0 */ + uint32_t chip_id_0; + /* Ambiq Chip ID1 */ + uint32_t chip_id_1; + /* Ambiq Factory Trim Revision */ + /* Can be used in Ambiq HAL for additional code support */ + uint32_t factory_trim_version; + }; + + struct ambiq_hwinfo dev_hw_info = {0}; + + /* Contains the HAL hardware information about the device. */ + am_hal_mcuctrl_device_t mcu_ctrl_device; + + am_hal_mram_info_read(1, AM_REG_INFO1_TRIM_REV_O / 4, 1, &dev_hw_info.factory_trim_version); + am_hal_mcuctrl_info_get(AM_HAL_MCUCTRL_INFO_DEVICEID, &mcu_ctrl_device); + + dev_hw_info.chip_id_0 = mcu_ctrl_device.ui32ChipID0; + dev_hw_info.chip_id_1 = mcu_ctrl_device.ui32ChipID1; + + if (length > sizeof(dev_hw_info)) { + length = sizeof(dev_hw_info); + } + + dev_hw_info.chip_id_0 = BSWAP_32(dev_hw_info.chip_id_0); + dev_hw_info.chip_id_1 = BSWAP_32(dev_hw_info.chip_id_1); + dev_hw_info.factory_trim_version = BSWAP_32(dev_hw_info.factory_trim_version); + memcpy(buffer, &dev_hw_info, length); + + return length; +} + +int z_impl_hwinfo_get_reset_cause(uint32_t *cause) +{ + uint32_t flags = 0; + uint32_t reset_status = 0; + am_hal_reset_status_t status = {0}; + + /* Print out reset status register upon entry */ + am_hal_reset_status_get(&status); + reset_status = status.eStatus; + + /* EXTERNAL PIN */ + if (reset_status & AM_HAL_RESET_STATUS_EXTERNAL) { + flags |= RESET_PIN; + } + + /* POWER CYCLE */ + if (reset_status & AM_HAL_RESET_STATUS_POR) { + flags |= RESET_POR; + } + + /* BROWNOUT DETECTOR */ + if (reset_status & AM_HAL_RESET_STATUS_BOD) { + flags |= RESET_BROWNOUT; + } + + /* SOFTWARE POR */ + if (reset_status & AM_HAL_RESET_STATUS_SWPOR) { + flags |= RESET_SOFTWARE; + } + + /* SOFTWARE POI */ + if (reset_status & AM_HAL_RESET_STATUS_SWPOI) { + flags |= RESET_SOFTWARE; + } + + /* DEBUGGER */ + if (reset_status & AM_HAL_RESET_STATUS_DEBUGGER) { + flags |= RESET_DEBUG; + } + + /* WATCHDOG */ + if (reset_status & AM_HAL_RESET_STATUS_WDT) { + flags |= RESET_WATCHDOG; + } + + /* BOUNREG */ + if (reset_status & AM_HAL_RESET_STATUS_BOUNREG) { + flags |= RESET_HARDWARE; + } + + /* BOCORE */ + if (reset_status & AM_HAL_RESET_STATUS_BOCORE) { + flags |= RESET_HARDWARE; + } + + /* BOMEM */ + if (reset_status & AM_HAL_RESET_STATUS_BOMEM) { + flags |= RESET_HARDWARE; + } + + /* BOHPMEM */ + if (reset_status & AM_HAL_RESET_STATUS_BOHPMEM) { + flags |= RESET_HARDWARE; + } + + *cause = flags; + return 0; +} + +int z_impl_hwinfo_clear_reset_cause(void) +{ + /* SBL maintains the RSTGEN->STAT register in + * INFO1 space even upon clearing RSTGEN->STAT + * register. + * - INFO1_RESETSTATUS + */ + + return -ENOSYS; +} + +int z_impl_hwinfo_get_supported_reset_cause(uint32_t *supported) +{ + *supported = RESET_PIN + | RESET_SOFTWARE + | RESET_POR + | RESET_WATCHDOG + | RESET_HARDWARE + | RESET_BROWNOUT; + return 0; +} diff --git a/drivers/hwinfo/hwinfo_handlers.c b/drivers/hwinfo/hwinfo_handlers.c index 02058f9b955..a1eb9e2c830 100644 --- a/drivers/hwinfo/hwinfo_handlers.c +++ b/drivers/hwinfo/hwinfo_handlers.c @@ -15,6 +15,14 @@ ssize_t z_vrfy_hwinfo_get_device_id(uint8_t *buffer, size_t length) } #include +ssize_t z_vrfy_hwinfo_get_device_eui64(uint8_t *buffer) +{ + K_OOPS(K_SYSCALL_MEMORY_WRITE(buffer, 8)); + + return z_impl_hwinfo_get_device_eui64((uint8_t *)buffer); +} +#include + int z_vrfy_hwinfo_get_reset_cause(uint32_t *cause) { int ret; diff --git a/drivers/hwinfo/hwinfo_shell.c b/drivers/hwinfo/hwinfo_shell.c index c827b051195..934c5c4283f 100644 --- a/drivers/hwinfo/hwinfo_shell.c +++ b/drivers/hwinfo/hwinfo_shell.c @@ -18,9 +18,9 @@ static int cmd_get_device_id(const struct shell *sh, size_t argc, char **argv) length = hwinfo_get_device_id(dev_id, sizeof(dev_id)); - if (length == -ENOTSUP) { + if (length == -ENOSYS) { shell_error(sh, "Not supported by hardware"); - return -ENOTSUP; + return -ENOSYS; } else if (length < 0) { shell_error(sh, "Error: %zd", length); return length; @@ -38,6 +38,33 @@ static int cmd_get_device_id(const struct shell *sh, size_t argc, char **argv) return 0; } +static int cmd_get_device_eui64(const struct shell *sh, size_t argc, char **argv) +{ + uint8_t dev_eui64[8]; + int ret; + int i; + + ret = hwinfo_get_device_eui64(dev_eui64); + + if (ret == -ENOSYS) { + shell_error(sh, "Not supported by hardware"); + return -ENOSYS; + } else if (ret < 0) { + shell_error(sh, "Error: %d", ret); + return ret; + } + + shell_fprintf(sh, SHELL_NORMAL, "EUI64: 0x"); + + for (i = 0 ; i < 8 ; i++) { + shell_fprintf(sh, SHELL_NORMAL, "%02x", dev_eui64[i]); + } + + shell_fprintf(sh, SHELL_NORMAL, "\n"); + + return 0; +} + static inline const char *cause_to_string(uint32_t cause) { switch (cause) { @@ -111,7 +138,7 @@ static int cmd_show_reset_cause(const struct shell *sh, size_t argc, ARG_UNUSED(argv); res = hwinfo_get_reset_cause(&cause); - if (res == -ENOTSUP) { + if (res == -ENOSYS) { shell_error(sh, "Not supported by hardware"); return res; } else if (res != 0) { @@ -138,7 +165,7 @@ static int cmd_clear_reset_cause(const struct shell *sh, size_t argc, ARG_UNUSED(argv); res = hwinfo_clear_reset_cause(); - if (res == -ENOTSUP) { + if (res == -ENOSYS) { shell_error(sh, "Not supported by hardware"); } else if (res != 0) { shell_error(sh, "Error clearing the reset causes [%d]", res); @@ -158,7 +185,7 @@ static int cmd_supported_reset_cause(const struct shell *sh, size_t argc, ARG_UNUSED(argv); res = hwinfo_get_supported_reset_cause(&cause); - if (res == -ENOTSUP) { + if (res == -ENOSYS) { shell_error(sh, "Not supported by hardware"); } else if (res != 0) { shell_error(sh, "Could not get the supported reset causes [%d]", res); @@ -188,6 +215,7 @@ SHELL_STATIC_SUBCMD_SET_CREATE(sub_reset_cause, SHELL_STATIC_SUBCMD_SET_CREATE(sub_hwinfo, SHELL_CMD_ARG(devid, NULL, "Show device id", cmd_get_device_id, 1, 0), + SHELL_CMD_ARG(deveui64, NULL, "Show device eui64", cmd_get_device_eui64, 1, 0), SHELL_CMD_ARG(reset_cause, &sub_reset_cause, "Reset cause commands", cmd_show_reset_cause, 1, 0), SHELL_SUBCMD_SET_END /* Array terminated. */ diff --git a/drivers/hwinfo/hwinfo_stm32.c b/drivers/hwinfo/hwinfo_stm32.c index e20f0609340..75029d7495c 100644 --- a/drivers/hwinfo/hwinfo_stm32.c +++ b/drivers/hwinfo/hwinfo_stm32.c @@ -44,6 +44,26 @@ ssize_t z_impl_hwinfo_get_device_id(uint8_t *buffer, size_t length) return length; } +#if defined(CONFIG_SOC_SERIES_STM32WBAX) || \ + defined(CONFIG_SOC_SERIES_STM32WBX) || \ + defined(CONFIG_SOC_SERIES_STM32WLX) +struct stm32_eui64 { + uint32_t id[2]; +}; + +int z_impl_hwinfo_get_device_eui64(uint8_t *buffer) +{ + struct stm32_eui64 dev_eui64; + + dev_eui64.id[0] = sys_cpu_to_be32(READ_REG(*((uint32_t *)UID64_BASE + 1U))); + dev_eui64.id[1] = sys_cpu_to_be32(READ_REG(*((uint32_t *)UID64_BASE))); + + memcpy(buffer, dev_eui64.id, sizeof(dev_eui64)); + + return 0; +} +#endif + int z_impl_hwinfo_get_reset_cause(uint32_t *cause) { uint32_t flags = 0; diff --git a/drivers/hwinfo/hwinfo_weak_impl.c b/drivers/hwinfo/hwinfo_weak_impl.c index c951d639ae2..a21745d8928 100644 --- a/drivers/hwinfo/hwinfo_weak_impl.c +++ b/drivers/hwinfo/hwinfo_weak_impl.c @@ -11,6 +11,11 @@ ssize_t __weak z_impl_hwinfo_get_device_id(uint8_t *buffer, size_t length) return -ENOSYS; } +int __weak z_impl_hwinfo_get_device_eui64(uint8_t *buffer) +{ + return -ENOSYS; +} + int __weak z_impl_hwinfo_get_reset_cause(uint32_t *cause) { return -ENOSYS; diff --git a/drivers/i2c/CMakeLists.txt b/drivers/i2c/CMakeLists.txt index 13878b66d3b..cb180ef24e3 100644 --- a/drivers/i2c/CMakeLists.txt +++ b/drivers/i2c/CMakeLists.txt @@ -29,7 +29,19 @@ else() endif() zephyr_library_sources_ifdef(CONFIG_I2C_EMUL i2c_emul.c) -zephyr_library_sources_ifdef(CONFIG_I2C_NRFX_TWI i2c_nrfx_twi.c) + +if(CONFIG_I2C_RTIO) + zephyr_library_sources_ifdef(CONFIG_I2C_NRFX_TWI + i2c_nrfx_twi_rtio.c + i2c_nrfx_twi_common.c + ) +else() + zephyr_library_sources_ifdef(CONFIG_I2C_NRFX_TWI + i2c_nrfx_twi.c + i2c_nrfx_twi_common.c + ) +endif() + zephyr_library_sources_ifdef(CONFIG_I2C_NRFX_TWIM i2c_nrfx_twim.c) zephyr_library_sources_ifdef(CONFIG_I2C_SAM_TWI i2c_sam_twi.c) diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index c0bcda79090..8af4bbbeb8b 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -54,8 +54,15 @@ config I2C_CALLBACK help API and implementations of i2c_transfer_cb. +config HAS_I2C_RTIO + bool + help + This option must be selected by I2C controller drivers that optionally implement the RTIO + interface. + config I2C_RTIO bool "I2C RTIO API" + depends on HAS_I2C_RTIO select RTIO help API and implementations of I2C for RTIO @@ -162,19 +169,12 @@ config I2C_MCUX help Enable the mcux I2C driver. -config I2C_MCUX_FLEXCOMM - bool "MCUX FLEXCOMM I2C driver" - default y - depends on DT_HAS_NXP_LPC_I2C_ENABLED - select PINCTRL - help - Enable the mcux flexcomm i2c driver. - config I2C_MCUX_LPI2C bool "MCUX LPI2C driver" default y depends on DT_HAS_NXP_IMX_LPI2C_ENABLED depends on CLOCK_CONTROL + select HAS_I2C_RTIO select PINCTRL help Enable the mcux LPI2C driver. diff --git a/drivers/i2c/Kconfig.ambiq b/drivers/i2c/Kconfig.ambiq index 040a93866e9..04a80848d9f 100644 --- a/drivers/i2c/Kconfig.ambiq +++ b/drivers/i2c/Kconfig.ambiq @@ -13,3 +13,14 @@ config I2C_AMBIQ select AMBIQ_HAL_USE_I2C help Enable driver for Ambiq I2C. + +config I2C_AMBIQ_DMA + bool "AMBIQ APOLLO I2C DMA Support" + help + Enable DMA for Ambiq I2C. + +config I2C_DMA_TCB_BUFFER_SIZE + int "DMA Transfer Control Buffer size in words." + default 1024 + help + DMA Transfer Control Buffer size in words diff --git a/drivers/i2c/Kconfig.dw b/drivers/i2c/Kconfig.dw index 796cfb643d1..4a063c28255 100644 --- a/drivers/i2c/Kconfig.dw +++ b/drivers/i2c/Kconfig.dw @@ -15,6 +15,7 @@ config I2C_DW_CLOCK_SPEED config I2C_DW_LPSS_DMA bool "Use I2C integrated DMA for asynchronous transfer" + depends on I2C_DW select DMA select DMA_INTEL_LPSS help diff --git a/drivers/i2c/Kconfig.mcux b/drivers/i2c/Kconfig.mcux index 7c519abac3b..f9187639014 100644 --- a/drivers/i2c/Kconfig.mcux +++ b/drivers/i2c/Kconfig.mcux @@ -3,9 +3,19 @@ # Copyright (c) 2024, NXP # SPDX-License-Identifier: Apache-2.0 +menuconfig I2C_MCUX_FLEXCOMM + bool "MCUX FLEXCOMM I2C driver" + default y + depends on DT_HAS_NXP_LPC_I2C_ENABLED + select PINCTRL + select RESET + help + Enable the mcux flexcomm i2c driver. + config I2C_NXP_TRANSFER_TIMEOUT int "Transfer timeout [ms]" default 0 + depends on I2C_MCUX_FLEXCOMM help Timeout in milliseconds used for each I2C transfer. 0 means that the driver should use the K_FOREVER value, diff --git a/drivers/i2c/Kconfig.nrfx b/drivers/i2c/Kconfig.nrfx index 6898d6e42a9..3c0596fc5b9 100644 --- a/drivers/i2c/Kconfig.nrfx +++ b/drivers/i2c/Kconfig.nrfx @@ -17,6 +17,7 @@ if I2C_NRFX config I2C_NRFX_TWI def_bool y depends on DT_HAS_NORDIC_NRF_TWI_ENABLED + select HAS_I2C_RTIO select NRFX_TWI0 if HAS_HW_NRF_TWI0 select NRFX_TWI1 if HAS_HW_NRF_TWI1 diff --git a/drivers/i2c/Kconfig.sam_twihs b/drivers/i2c/Kconfig.sam_twihs index 5f1daa6f4c4..ee3a2948752 100644 --- a/drivers/i2c/Kconfig.sam_twihs +++ b/drivers/i2c/Kconfig.sam_twihs @@ -7,5 +7,6 @@ config I2C_SAM_TWIHS bool "Atmel SAM (TWIHS) I2C driver" default y depends on DT_HAS_ATMEL_SAM_I2C_TWIHS_ENABLED + select HAS_I2C_RTIO help Enable Atmel SAM MCU Family (TWIHS) I2C bus driver. diff --git a/drivers/i2c/i2c_ambiq.c b/drivers/i2c/i2c_ambiq.c index e8b62fb2c45..f3c5b90e900 100644 --- a/drivers/i2c/i2c_ambiq.c +++ b/drivers/i2c/i2c_ambiq.c @@ -19,7 +19,8 @@ LOG_MODULE_REGISTER(ambiq_i2c, CONFIG_I2C_LOG_LEVEL); typedef int (*ambiq_i2c_pwr_func_t)(void); -#define PWRCTRL_MAX_WAIT_US 5 +#define PWRCTRL_MAX_WAIT_US 5 +#define I2C_TRANSFER_TIMEOUT_MSEC 500 /* Transfer timeout period */ #include "i2c-priv.h" @@ -29,13 +30,50 @@ struct i2c_ambiq_config { uint32_t bitrate; const struct pinctrl_dev_config *pcfg; ambiq_i2c_pwr_func_t pwr_func; + void (*irq_config_func)(void); }; +typedef void (*i2c_ambiq_callback_t)(const struct device *dev, int result, void *data); + struct i2c_ambiq_data { am_hal_iom_config_t iom_cfg; - void *IOMHandle; + void *iom_handler; + struct k_sem bus_sem; + struct k_sem transfer_sem; + i2c_ambiq_callback_t callback; + void *callback_data; + int inst_idx; + uint32_t transfer_status; }; +#ifdef CONFIG_I2C_AMBIQ_DMA +static __aligned(32) struct { + __aligned(32) uint32_t buf[CONFIG_I2C_DMA_TCB_BUFFER_SIZE]; +} i2c_dma_tcb_buf[DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT)] __attribute__((__section__(".nocache"))); + +static void i2c_ambiq_callback(void *callback_ctxt, uint32_t status) +{ + const struct device *dev = callback_ctxt; + struct i2c_ambiq_data *data = dev->data; + + if (data->callback) { + data->callback(dev, status, data->callback_data); + } + data->transfer_status = status; + k_sem_give(&data->transfer_sem); +} +#endif + +static void i2c_ambiq_isr(const struct device *dev) +{ + uint32_t ui32Status; + struct i2c_ambiq_data *data = dev->data; + + am_hal_iom_interrupt_status_get(data->iom_handler, false, &ui32Status); + am_hal_iom_interrupt_clear(data->iom_handler, ui32Status); + am_hal_iom_interrupt_service(data->iom_handler, ui32Status); +} + static int i2c_ambiq_read(const struct device *dev, struct i2c_msg *msg, uint16_t addr) { struct i2c_ambiq_data *data = dev->data; @@ -50,9 +88,24 @@ static int i2c_ambiq_read(const struct device *dev, struct i2c_msg *msg, uint16_ trans.ui32NumBytes = msg->len; trans.pui32RxBuffer = (uint32_t *)msg->buf; - ret = am_hal_iom_blocking_transfer(data->IOMHandle, &trans); - - return ret; +#ifdef CONFIG_I2C_AMBIQ_DMA + data->transfer_status = -EFAULT; + ret = am_hal_iom_nonblocking_transfer(data->iom_handler, &trans, i2c_ambiq_callback, + (void *)dev); + if (k_sem_take(&data->transfer_sem, K_MSEC(I2C_TRANSFER_TIMEOUT_MSEC))) { + LOG_ERR("Timeout waiting for transfer complete"); + /* cancel timed out transaction */ + am_hal_iom_disable(data->iom_handler); + /* clean up for next xfer */ + k_sem_reset(&data->transfer_sem); + am_hal_iom_enable(data->iom_handler); + return -ETIMEDOUT; + } + ret = data->transfer_status; +#else + ret = am_hal_iom_blocking_transfer(data->iom_handler, &trans); +#endif + return (ret != AM_HAL_STATUS_SUCCESS) ? -EIO : 0; } static int i2c_ambiq_write(const struct device *dev, struct i2c_msg *msg, uint16_t addr) @@ -69,9 +122,26 @@ static int i2c_ambiq_write(const struct device *dev, struct i2c_msg *msg, uint16 trans.ui32NumBytes = msg->len; trans.pui32TxBuffer = (uint32_t *)msg->buf; - ret = am_hal_iom_blocking_transfer(data->IOMHandle, &trans); +#ifdef CONFIG_I2C_AMBIQ_DMA + data->transfer_status = -EFAULT; + ret = am_hal_iom_nonblocking_transfer(data->iom_handler, &trans, i2c_ambiq_callback, + (void *)dev); + + if (k_sem_take(&data->transfer_sem, K_MSEC(I2C_TRANSFER_TIMEOUT_MSEC))) { + LOG_ERR("Timeout waiting for transfer complete"); + /* cancel timed out transaction */ + am_hal_iom_disable(data->iom_handler); + /* clean up for next xfer */ + k_sem_reset(&data->transfer_sem); + am_hal_iom_enable(data->iom_handler); + return -ETIMEDOUT; + } + ret = data->transfer_status; +#else + ret = am_hal_iom_blocking_transfer(data->iom_handler, &trans); +#endif - return ret; + return (ret != AM_HAL_STATUS_SUCCESS) ? -EIO : 0; } static int i2c_ambiq_configure(const struct device *dev, uint32_t dev_config) @@ -96,7 +166,12 @@ static int i2c_ambiq_configure(const struct device *dev, uint32_t dev_config) return -EINVAL; } - am_hal_iom_configure(data->IOMHandle, &data->iom_cfg); +#ifdef CONFIG_I2C_AMBIQ_DMA + data->iom_cfg.pNBTxnBuf = i2c_dma_tcb_buf[data->inst_idx].buf; + data->iom_cfg.ui32NBTxnBufLength = CONFIG_I2C_DMA_TCB_BUFFER_SIZE; +#endif + + am_hal_iom_configure(data->iom_handler, &data->iom_cfg); return 0; } @@ -104,12 +179,16 @@ static int i2c_ambiq_configure(const struct device *dev, uint32_t dev_config) static int i2c_ambiq_transfer(const struct device *dev, struct i2c_msg *msgs, uint8_t num_msgs, uint16_t addr) { + struct i2c_ambiq_data *data = dev->data; int ret = 0; if (!num_msgs) { return 0; } + /* Send out messages */ + k_sem_take(&data->bus_sem, K_FOREVER); + for (int i = 0; i < num_msgs; i++) { if (msgs[i].flags & I2C_MSG_READ) { ret = i2c_ambiq_read(dev, &(msgs[i]), addr); @@ -122,6 +201,8 @@ static int i2c_ambiq_transfer(const struct device *dev, struct i2c_msg *msgs, ui } } + k_sem_give(&data->bus_sem); + return 0; } @@ -134,21 +215,41 @@ static int i2c_ambiq_init(const struct device *dev) data->iom_cfg.eInterfaceMode = AM_HAL_IOM_I2C_MODE; - ret = am_hal_iom_initialize((config->base - REG_IOM_BASEADDR) / config->size, - &data->IOMHandle); + if (AM_HAL_STATUS_SUCCESS != + am_hal_iom_initialize((config->base - REG_IOM_BASEADDR) / config->size, + &data->iom_handler)) { + LOG_ERR("Fail to initialize I2C\n"); + return -ENXIO; + } ret = config->pwr_func(); - ret = i2c_ambiq_configure(dev, I2C_MODE_CONTROLLER | bitrate_cfg); + ret |= i2c_ambiq_configure(dev, I2C_MODE_CONTROLLER | bitrate_cfg); + if (ret < 0) { + LOG_ERR("Fail to config I2C\n"); + goto end; + } ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); - if (ret < 0) { - return ret; + LOG_ERR("Fail to config I2C pins\n"); + goto end; } - ret = am_hal_iom_enable(data->IOMHandle); +#ifdef CONFIG_I2C_AMBIQ_DMA + am_hal_iom_interrupt_clear(data->iom_handler, AM_HAL_IOM_INT_CQUPD | AM_HAL_IOM_INT_ERR); + am_hal_iom_interrupt_enable(data->iom_handler, AM_HAL_IOM_INT_CQUPD | AM_HAL_IOM_INT_ERR); + config->irq_config_func(); +#endif + if (AM_HAL_STATUS_SUCCESS != am_hal_iom_enable(data->iom_handler)) { + LOG_ERR("Fail to enable I2C\n"); + ret = -EIO; + } +end: + if (ret < 0) { + am_hal_iom_uninitialize(data->iom_handler); + } return ret; } @@ -167,12 +268,23 @@ static const struct i2c_driver_api i2c_ambiq_driver_api = { k_busy_wait(PWRCTRL_MAX_WAIT_US); \ return 0; \ } \ - static struct i2c_ambiq_data i2c_ambiq_data##n; \ + static void i2c_irq_config_func_##n(void) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), i2c_ambiq_isr, \ + DEVICE_DT_INST_GET(n), 0); \ + irq_enable(DT_INST_IRQN(n)); \ + }; \ + static struct i2c_ambiq_data i2c_ambiq_data##n = { \ + .bus_sem = Z_SEM_INITIALIZER(i2c_ambiq_data##n.bus_sem, 1, 1), \ + .transfer_sem = Z_SEM_INITIALIZER(i2c_ambiq_data##n.transfer_sem, 0, 1), \ + .inst_idx = n, \ + }; \ static const struct i2c_ambiq_config i2c_ambiq_config##n = { \ .base = DT_INST_REG_ADDR(n), \ .size = DT_INST_REG_SIZE(n), \ .bitrate = DT_INST_PROP(n, clock_frequency), \ .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + .irq_config_func = i2c_irq_config_func_##n, \ .pwr_func = pwr_on_ambiq_i2c_##n}; \ I2C_DEVICE_DT_INST_DEFINE(n, i2c_ambiq_init, NULL, &i2c_ambiq_data##n, \ &i2c_ambiq_config##n, POST_KERNEL, CONFIG_I2C_INIT_PRIORITY, \ diff --git a/drivers/i2c/i2c_dw.c b/drivers/i2c/i2c_dw.c index b198aa15c1b..6bb2fc5c64d 100644 --- a/drivers/i2c/i2c_dw.c +++ b/drivers/i2c/i2c_dw.c @@ -124,7 +124,7 @@ int32_t i2c_dw_idma_rx_transfer(const struct device *dev) dma_cfg.dma_callback = cb_i2c_idma_transfer; dma_cfg.user_data = (void *)dev; dma_cfg.complete_callback_en = 0U; - dma_cfg.error_callback_en = 1U; + dma_cfg.error_callback_dis = 0U; dma_cfg.block_count = 1U; dma_cfg.head_block = &dma_block_cfg; @@ -172,7 +172,7 @@ int32_t i2c_dw_idma_tx_transfer(const struct device *dev, dma_cfg.dma_callback = cb_i2c_idma_transfer; dma_cfg.user_data = (void *)dev; dma_cfg.complete_callback_en = 0U; - dma_cfg.error_callback_en = 1U; + dma_cfg.error_callback_dis = 0U; dma_cfg.block_count = 1U; dma_cfg.head_block = &dma_block_cfg; @@ -252,7 +252,9 @@ static inline void i2c_dw_data_ask(const struct device *dev) data |= IC_DATA_CMD_STOP; } +#ifdef CONFIG_I2C_TARGET clear_bit_intr_mask_tx_empty(reg_base); +#endif /* CONFIG_I2C_TARGET */ write_cmd_data(data, reg_base); @@ -413,6 +415,7 @@ static void i2c_dw_isr(const struct device *port) i2c_dw_data_read(port); } +#ifdef CONFIG_I2C_TARGET /* Check if the TX FIFO is ready for commands. * TX FIFO also serves as command queue where read requests * are written to TX FIFO. @@ -421,6 +424,7 @@ static void i2c_dw_isr(const struct device *port) == I2C_MSG_READ) { set_bit_intr_mask_tx_empty(reg_base); } +#endif /* CONFIG_I2C_TARGET */ if (intr_stat.bits.tx_empty) { if ((dw->xfr_flags & I2C_MSG_RW_MASK) diff --git a/drivers/i2c/i2c_esp32.c b/drivers/i2c/i2c_esp32.c index fdb78a2c6ed..c6554afa539 100644 --- a/drivers/i2c/i2c_esp32.c +++ b/drivers/i2c/i2c_esp32.c @@ -91,7 +91,6 @@ struct i2c_esp32_config { int irq_source; - const uint32_t default_config; const uint32_t bitrate; const uint32_t scl_timeout; }; @@ -262,14 +261,17 @@ static int i2c_esp32_recover(const struct device *dev) return 0; } -static void IRAM_ATTR i2c_esp32_configure_timeout(const struct device *dev) +static void IRAM_ATTR i2c_esp32_configure_bitrate(const struct device *dev, uint32_t bitrate) { const struct i2c_esp32_config *config = dev->config; struct i2c_esp32_data *data = (struct i2c_esp32_data *const)(dev)->data; + i2c_clock_source_t sclk = i2c_get_clk_src(bitrate); + uint32_t clk_freq_mhz = i2c_get_src_clk_freq(sclk); + + i2c_hal_set_bus_timing(&data->hal, bitrate, sclk, clk_freq_mhz); + if (config->scl_timeout > 0) { - i2c_clock_source_t sclk = i2c_get_clk_src(config->bitrate); - uint32_t clk_freq_mhz = i2c_get_src_clk_freq(sclk); uint32_t timeout_cycles = MIN(I2C_LL_MAX_TIMEOUT, clk_freq_mhz / MHZ(1) * config->scl_timeout); i2c_ll_set_tout(data->hal.dev, timeout_cycles); @@ -281,20 +283,15 @@ static void IRAM_ATTR i2c_esp32_configure_timeout(const struct device *dev) */ i2c_ll_set_tout(data->hal.dev, I2C_LL_MAX_TIMEOUT); } + + i2c_ll_update(data->hal.dev); } -static int i2c_esp32_configure(const struct device *dev, uint32_t dev_config) +static void i2c_esp32_configure_data_mode(const struct device *dev) { const struct i2c_esp32_config *config = dev->config; struct i2c_esp32_data *data = (struct i2c_esp32_data *const)(dev)->data; - if (!(dev_config & I2C_MODE_CONTROLLER)) { - LOG_ERR("Only I2C Master mode supported."); - return -ENOTSUP; - } - - data->dev_config = dev_config; - i2c_trans_mode_t tx_mode = I2C_DATA_MODE_MSB_FIRST; i2c_trans_mode_t rx_mode = I2C_DATA_MODE_MSB_FIRST; @@ -306,21 +303,59 @@ static int i2c_esp32_configure(const struct device *dev, uint32_t dev_config) rx_mode = I2C_DATA_MODE_LSB_FIRST; } - i2c_hal_master_init(&data->hal); i2c_ll_set_data_mode(data->hal.dev, tx_mode, rx_mode); i2c_ll_set_filter(data->hal.dev, I2C_FILTER_CYC_NUM_DEF); i2c_ll_update(data->hal.dev); - if (config->bitrate == 0) { +} + +static int i2c_esp32_configure(const struct device *dev, uint32_t dev_config) +{ + const struct i2c_esp32_config *config = dev->config; + struct i2c_esp32_data *data = (struct i2c_esp32_data *const)(dev)->data; + uint32_t bitrate; + + if (!(dev_config & I2C_MODE_CONTROLLER)) { + LOG_ERR("Only I2C Master mode 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("Error configuring I2C speed."); return -ENOTSUP; } - i2c_clock_source_t sclk = i2c_get_clk_src(config->bitrate); + k_sem_take(&data->transfer_sem, K_FOREVER); - i2c_hal_set_bus_timing(&data->hal, config->bitrate, sclk, i2c_get_src_clk_freq(sclk)); - i2c_esp32_configure_timeout(dev); - i2c_ll_update(data->hal.dev); + data->dev_config = dev_config; + + i2c_esp32_configure_bitrate(dev, bitrate); + + k_sem_give(&data->transfer_sem); + + return 0; +} + +static int i2c_esp32_get_config(const struct device *dev, uint32_t *config) +{ + struct i2c_esp32_data *data = (struct i2c_esp32_data *const)(dev)->data; + + if (data->dev_config == 0) { + LOG_ERR("I2C controller not configured"); + return -EIO; + } + + *config = data->dev_config; return 0; } @@ -694,6 +729,7 @@ static void IRAM_ATTR i2c_esp32_isr(void *arg) static const struct i2c_driver_api i2c_esp32_driver_api = { .configure = i2c_esp32_configure, + .get_config = i2c_esp32_get_config, .transfer = i2c_esp32_transfer, .recover_bus = i2c_esp32_recover }; @@ -701,9 +737,9 @@ static const struct i2c_driver_api i2c_esp32_driver_api = { static int IRAM_ATTR i2c_esp32_init(const struct device *dev) { const struct i2c_esp32_config *config = dev->config; -#ifndef SOC_I2C_SUPPORT_HW_CLR_BUS struct i2c_esp32_data *data = (struct i2c_esp32_data *const)(dev)->data; +#ifndef SOC_I2C_SUPPORT_HW_CLR_BUS if (!gpio_is_ready_dt(&config->scl.gpio)) { LOG_ERR("SCL GPIO device is not ready"); return -EINVAL; @@ -730,7 +766,11 @@ static int IRAM_ATTR i2c_esp32_init(const struct device *dev) esp_intr_alloc(config->irq_source, 0, i2c_esp32_isr, (void *)dev, NULL); - return i2c_esp32_configure(dev, config->default_config); + i2c_hal_master_init(&data->hal); + + i2c_esp32_configure_data_mode(dev); + + return i2c_esp32_configure(dev, I2C_MODE_CONTROLLER | i2c_map_dt_bitrate(config->bitrate)); } #define I2C(idx) DT_NODELABEL(i2c##idx) @@ -788,7 +828,6 @@ static int IRAM_ATTR i2c_esp32_init(const struct device *dev) .irq_source = ETS_I2C_EXT##idx##_INTR_SOURCE, \ .bitrate = I2C_FREQUENCY(idx), \ .scl_timeout = I2C_ESP32_TIMEOUT(idx), \ - .default_config = I2C_MODE_CONTROLLER, \ }; \ I2C_DEVICE_DT_DEFINE(I2C(idx), i2c_esp32_init, NULL, &i2c_esp32_data_##idx, \ &i2c_esp32_config_##idx, POST_KERNEL, CONFIG_I2C_INIT_PRIORITY, \ diff --git a/drivers/i2c/i2c_gecko.c b/drivers/i2c/i2c_gecko.c index 0c537add17a..cf44104104a 100644 --- a/drivers/i2c/i2c_gecko.c +++ b/drivers/i2c/i2c_gecko.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2018 Diego Sueiro + * Copyright (c) 2024 Capgemini * * SPDX-License-Identifier: Apache-2.0 */ @@ -8,6 +9,7 @@ #include #include +#include #include #include #include @@ -24,17 +26,10 @@ LOG_MODULE_REGISTER(i2c_gecko); #define DEV_BASE(dev) ((I2C_TypeDef *)((const struct i2c_gecko_config *const)(dev)->config)->base) struct i2c_gecko_config { + const struct pinctrl_dev_config *pcfg; I2C_TypeDef *base; CMU_Clock_TypeDef clock; uint32_t bitrate; - struct soc_gpio_pin pin_sda; - struct soc_gpio_pin pin_scl; -#ifdef CONFIG_SOC_GECKO_HAS_INDIVIDUAL_PIN_LOCATION - uint8_t loc_sda; - uint8_t loc_scl; -#else - uint8_t loc; -#endif #if defined(CONFIG_I2C_TARGET) void (*irq_config_func)(const struct device *dev); #endif @@ -48,32 +43,6 @@ struct i2c_gecko_data { #endif }; -void i2c_gecko_config_pins(const struct device *dev, const struct soc_gpio_pin *pin_sda, - const struct soc_gpio_pin *pin_scl) -{ - I2C_TypeDef *base = DEV_BASE(dev); - const struct i2c_gecko_config *config = dev->config; - - GPIO_PinModeSet(pin_scl->port, pin_scl->pin, pin_scl->mode, pin_scl->out); - GPIO_PinModeSet(pin_sda->port, pin_sda->pin, pin_sda->mode, pin_sda->out); - -#ifdef CONFIG_SOC_GECKO_HAS_INDIVIDUAL_PIN_LOCATION - base->ROUTEPEN = I2C_ROUTEPEN_SDAPEN | I2C_ROUTEPEN_SCLPEN; - base->ROUTELOC0 = (config->loc_sda << _I2C_ROUTELOC0_SDALOC_SHIFT) | - (config->loc_scl << _I2C_ROUTELOC0_SCLLOC_SHIFT); -#elif defined(GPIO_I2C_ROUTEEN_SCLPEN) && defined(GPIO_I2C_ROUTEEN_SDAPEN) - GPIO->I2CROUTE[I2C_NUM(base)].ROUTEEN = GPIO_I2C_ROUTEEN_SCLPEN | GPIO_I2C_ROUTEEN_SDAPEN; - GPIO->I2CROUTE[I2C_NUM(base)].SCLROUTE = - (config->pin_scl.pin << _GPIO_I2C_SCLROUTE_PIN_SHIFT) | - (config->pin_scl.port << _GPIO_I2C_SCLROUTE_PORT_SHIFT); - GPIO->I2CROUTE[I2C_NUM(base)].SDAROUTE = - (config->pin_sda.pin << _GPIO_I2C_SDAROUTE_PIN_SHIFT) | - (config->pin_sda.port << _GPIO_I2C_SDAROUTE_PORT_SHIFT); -#else - base->ROUTE = I2C_ROUTE_SDAPEN | I2C_ROUTE_SCLPEN | (config->loc << 8); -#endif -} - static int i2c_gecko_configure(const struct device *dev, uint32_t dev_config_raw) { I2C_TypeDef *base = DEV_BASE(dev); @@ -182,7 +151,11 @@ static int i2c_gecko_init(const struct device *dev) CMU_ClockEnable(config->clock, true); - i2c_gecko_config_pins(dev, &config->pin_sda, &config->pin_scl); + error = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); + if (error < 0) { + LOG_ERR("Failed to configure I2C pins err[%d]", error); + return error; + } bitrate_cfg = i2c_map_dt_bitrate(config->bitrate); @@ -296,19 +269,6 @@ void i2c_gecko_isr(const struct device *dev) } #endif -#ifdef CONFIG_SOC_GECKO_HAS_INDIVIDUAL_PIN_LOCATION -#define I2C_LOC_DATA(idx) \ - .loc_sda = DT_INST_PROP_BY_IDX(idx, location_sda, 0), \ - .loc_scl = DT_INST_PROP_BY_IDX(idx, location_scl, 0) -#define I2C_VALIDATE_LOC(idx) BUILD_ASSERT(true, "") -#else -#define I2C_VALIDATE_LOC(idx) \ - BUILD_ASSERT(DT_INST_PROP_BY_IDX(idx, location_sda, 0) == \ - DT_INST_PROP_BY_IDX(idx, location_scl, 0), \ - "DTS location-* properties must be equal") -#define I2C_LOC_DATA(idx) .loc = DT_INST_PROP_BY_IDX(idx, location_scl, 0) -#endif - #if defined(CONFIG_I2C_TARGET) #define GECKO_I2C_IRQ_DEF(idx) static void i2c_gecko_config_func_##idx(const struct device *dev); #define GECKO_I2C_IRQ_DATA(idx) .irq_config_func = i2c_gecko_config_func_##idx, @@ -325,23 +285,23 @@ void i2c_gecko_isr(const struct device *dev) #define GECKO_I2C_IRQ_DATA(idx) #endif -#define I2C_INIT(idx) \ - I2C_VALIDATE_LOC(idx); \ - GECKO_I2C_IRQ_DEF(idx) \ - static const struct i2c_gecko_config i2c_gecko_config_##idx = { \ - .base = (I2C_TypeDef *)DT_INST_REG_ADDR(idx), \ - .clock = cmuClock_I2C##idx, \ - .pin_sda = {DT_INST_PROP_BY_IDX(idx, location_sda, 1), \ - DT_INST_PROP_BY_IDX(idx, location_sda, 2), gpioModeWiredAnd, 1}, \ - .pin_scl = {DT_INST_PROP_BY_IDX(idx, location_scl, 1), \ - DT_INST_PROP_BY_IDX(idx, location_scl, 2), gpioModeWiredAnd, 1}, \ - I2C_LOC_DATA(idx), \ - .bitrate = DT_INST_PROP(idx, clock_frequency), \ - GECKO_I2C_IRQ_DATA(idx)}; \ - static struct i2c_gecko_data i2c_gecko_data_##idx; \ - I2C_DEVICE_DT_INST_DEFINE(idx, i2c_gecko_init, NULL, &i2c_gecko_data_##idx, \ - &i2c_gecko_config_##idx, POST_KERNEL, CONFIG_I2C_INIT_PRIORITY, \ - &i2c_gecko_driver_api); \ +#define I2C_INIT(idx) \ + PINCTRL_DT_INST_DEFINE(idx); \ + GECKO_I2C_IRQ_DEF(idx); \ + \ + static const struct i2c_gecko_config i2c_gecko_config_##idx = { \ + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(idx), \ + .base = (I2C_TypeDef *)DT_INST_REG_ADDR(idx), \ + .clock = cmuClock_I2C##idx, \ + .bitrate = DT_INST_PROP(idx, clock_frequency), \ + GECKO_I2C_IRQ_DATA(idx)}; \ + \ + static struct i2c_gecko_data i2c_gecko_data_##idx; \ + \ + I2C_DEVICE_DT_INST_DEFINE(idx, i2c_gecko_init, NULL, &i2c_gecko_data_##idx, \ + &i2c_gecko_config_##idx, POST_KERNEL, \ + CONFIG_I2C_INIT_PRIORITY, &i2c_gecko_driver_api); \ + \ GECKO_I2C_IRQ_HANDLER(idx) DT_INST_FOREACH_STATUS_OKAY(I2C_INIT) diff --git a/drivers/i2c/i2c_ll_stm32_v1.c b/drivers/i2c/i2c_ll_stm32_v1.c index ff63ee39913..e4346726384 100644 --- a/drivers/i2c/i2c_ll_stm32_v1.c +++ b/drivers/i2c/i2c_ll_stm32_v1.c @@ -359,6 +359,14 @@ static inline void handle_rxne(const struct device *dev) k_sem_give(&data->device_sync_sem); break; case 2: + /* + * 2-byte reception for N > 3 has already set the NACK + * bit, and must not set the POS bit. See pg. 854 in + * the F4 reference manual (RM0090). + */ + if (data->current.msg->len > 2) { + break; + } LL_I2C_AcknowledgeNextData(i2c, LL_I2C_NACK); LL_I2C_EnableBitPOS(i2c); __fallthrough; diff --git a/drivers/i2c/i2c_mcux_flexcomm.c b/drivers/i2c/i2c_mcux_flexcomm.c index 151992ecc9d..f75c65650ec 100644 --- a/drivers/i2c/i2c_mcux_flexcomm.c +++ b/drivers/i2c/i2c_mcux_flexcomm.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -23,6 +24,8 @@ LOG_MODULE_REGISTER(mcux_flexcomm); COND_CODE_0(CONFIG_I2C_NXP_TRANSFER_TIMEOUT, (K_FOREVER), \ (K_MSEC(CONFIG_I2C_NXP_TRANSFER_TIMEOUT))) +#define MCUX_FLEXCOMM_MAX_TARGETS 4 + struct mcux_flexcomm_config { I2C_Type *base; const struct device *clock_dev; @@ -30,20 +33,29 @@ struct mcux_flexcomm_config { void (*irq_config_func)(const struct device *dev); uint32_t bitrate; const struct pinctrl_dev_config *pincfg; + const struct reset_dt_spec reset; }; +#ifdef CONFIG_I2C_TARGET +struct mcux_flexcomm_target_data { + struct i2c_target_config *target_cfg; + bool target_attached; + bool first_read; + bool first_write; + bool is_write; +}; +#endif + struct mcux_flexcomm_data { i2c_master_handle_t handle; struct k_sem device_sync_sem; struct k_sem lock; status_t callback_status; #ifdef CONFIG_I2C_TARGET + uint8_t nr_targets_attached; + i2c_slave_config_t i2c_cfg; i2c_slave_handle_t target_handle; - struct i2c_target_config *target_cfg; - bool target_attached; - bool first_read; - bool first_write; - bool is_write; + struct mcux_flexcomm_target_data target_data[MCUX_FLEXCOMM_MAX_TARGETS]; #endif }; @@ -193,23 +205,108 @@ static int mcux_flexcomm_transfer(const struct device *dev, } #if defined(CONFIG_I2C_TARGET) + +static struct mcux_flexcomm_target_data *mcux_flexcomm_find_free_target( + struct mcux_flexcomm_data *data) +{ + struct mcux_flexcomm_target_data *target; + int i; + + for (i = 0; i < ARRAY_SIZE(data->target_data); i++) { + target = &data->target_data[i]; + if (!target->target_attached) { + return target; + } + } + return NULL; +} + +static struct mcux_flexcomm_target_data *mcux_flexcomm_find_target_by_address( + struct mcux_flexcomm_data *data, uint16_t address) +{ + struct mcux_flexcomm_target_data *target; + int i; + + for (i = 0; i < ARRAY_SIZE(data->target_data); i++) { + target = &data->target_data[i]; + if (target->target_attached && target->target_cfg->address == address) { + return target; + } + } + return NULL; +} + +static int mcux_flexcomm_setup_i2c_config_address(struct mcux_flexcomm_data *data, + struct mcux_flexcomm_target_data *target, bool disabled) +{ + i2c_slave_address_t *addr; + int idx = -1; + int i; + + for (i = 0; i < ARRAY_SIZE(data->target_data); i++) { + if (data->target_data[i].target_attached && &data->target_data[i] == target) { + idx = i; + break; + } + } + + if (idx < 0) { + return -ENODEV; + } + + /* This could be just shifting a pointer in the i2c_cfg struct */ + /* However would be less readable and error prone if the struct changes */ + switch (idx) { + case 0: + addr = &data->i2c_cfg.address0; + break; + case 1: + addr = &data->i2c_cfg.address1; + break; + case 2: + addr = &data->i2c_cfg.address2; + break; + case 3: + addr = &data->i2c_cfg.address3; + break; + default: + return -1; + } + + addr->address = target->target_cfg->address; + addr->addressDisable = disabled; + + return 0; +} + static void i2c_target_transfer_callback(I2C_Type *base, volatile i2c_slave_transfer_t *transfer, void *userData) { + /* Convert 8-bit received address to 7-bit address */ + uint8_t address = transfer->receivedAddress >> 1; struct mcux_flexcomm_data *data = userData; - const struct i2c_target_callbacks *target_cb = data->target_cfg->callbacks; + struct mcux_flexcomm_target_data *target; + const struct i2c_target_callbacks *target_cb; static uint8_t rxVal, txVal; ARG_UNUSED(base); + target = mcux_flexcomm_find_target_by_address(data, address); + if (!target) { + LOG_ERR("No target found for address: 0x%x", address); + return; + } + + target_cb = target->target_cfg->callbacks; + switch (transfer->event) { case kI2C_SlaveTransmitEvent: /* request to provide data to transmit */ - if (data->first_read && target_cb->read_requested) { - data->first_read = false; - target_cb->read_requested(data->target_cfg, &txVal); + if (target->first_read && target_cb->read_requested) { + target->first_read = false; + target_cb->read_requested(target->target_cfg, &txVal); } else if (target_cb->read_processed) { - target_cb->read_processed(data->target_cfg, &txVal); + target_cb->read_processed(target->target_cfg, &txVal); } transfer->txData = &txVal; @@ -218,31 +315,31 @@ static void i2c_target_transfer_callback(I2C_Type *base, case kI2C_SlaveReceiveEvent: /* request to provide a buffer in which to place received data */ - if (data->first_write && target_cb->write_requested) { - target_cb->write_requested(data->target_cfg); - data->first_write = false; + if (target->first_write && target_cb->write_requested) { + target_cb->write_requested(target->target_cfg); + target->first_write = false; } transfer->rxData = &rxVal; transfer->rxSize = 1; - data->is_write = true; + target->is_write = true; break; case kI2C_SlaveCompletionEvent: /* called after every transferred byte */ - if (data->is_write && target_cb->write_received) { - target_cb->write_received(data->target_cfg, rxVal); - data->is_write = false; + if (target->is_write && target_cb->write_received) { + target_cb->write_received(target->target_cfg, rxVal); + target->is_write = false; } break; case kI2C_SlaveDeselectedEvent: if (target_cb->stop) { - target_cb->stop(data->target_cfg); + target_cb->stop(target->target_cfg); } - data->first_read = true; - data->first_write = true; + target->first_read = true; + target->first_write = true; break; default: @@ -251,16 +348,12 @@ static void i2c_target_transfer_callback(I2C_Type *base, } } -int mcux_flexcomm_target_register(const struct device *dev, - struct i2c_target_config *target_config) +static int mcux_flexcomm_setup_slave_config(const struct device *dev) { const struct mcux_flexcomm_config *config = dev->config; struct mcux_flexcomm_data *data = dev->data; I2C_Type *base = config->base; uint32_t clock_freq; - i2c_slave_config_t i2c_cfg; - - I2C_MasterDeinit(base); /* Get the clock frequency */ if (clock_control_get_rate(config->clock_dev, config->clock_subsys, @@ -268,29 +361,53 @@ int mcux_flexcomm_target_register(const struct device *dev, return -EINVAL; } + I2C_SlaveInit(base, &data->i2c_cfg, clock_freq); + I2C_SlaveTransferCreateHandle(base, &data->target_handle, + i2c_target_transfer_callback, data); + I2C_SlaveTransferNonBlocking(base, &data->target_handle, + kI2C_SlaveCompletionEvent | kI2C_SlaveTransmitEvent | + kI2C_SlaveReceiveEvent | kI2C_SlaveDeselectedEvent); + + return 0; +} + +int mcux_flexcomm_target_register(const struct device *dev, + struct i2c_target_config *target_config) +{ + const struct mcux_flexcomm_config *config = dev->config; + struct mcux_flexcomm_data *data = dev->data; + struct mcux_flexcomm_target_data *target; + I2C_Type *base = config->base; + + I2C_MasterDeinit(base); + if (!target_config) { return -EINVAL; } - if (data->target_attached) { + target = mcux_flexcomm_find_free_target(data); + if (!target) { return -EBUSY; } - data->target_cfg = target_config; - data->target_attached = true; - data->first_read = true; - data->first_write = true; + target->target_cfg = target_config; + target->target_attached = true; + target->first_read = true; + target->first_write = true; - I2C_SlaveGetDefaultConfig(&i2c_cfg); - i2c_cfg.address0.address = target_config->address; + if (data->nr_targets_attached == 0) { + I2C_SlaveGetDefaultConfig(&data->i2c_cfg); + } - I2C_SlaveInit(base, &i2c_cfg, clock_freq); - I2C_SlaveTransferCreateHandle(base, &data->target_handle, - i2c_target_transfer_callback, data); - I2C_SlaveTransferNonBlocking(base, &data->target_handle, - kI2C_SlaveCompletionEvent | kI2C_SlaveTransmitEvent | - kI2C_SlaveReceiveEvent | kI2C_SlaveDeselectedEvent); + if (mcux_flexcomm_setup_i2c_config_address(data, target, false) < 0) { + return -EINVAL; + } + + if (mcux_flexcomm_setup_slave_config(dev) < 0) { + return -EINVAL; + } + data->nr_targets_attached++; return 0; } @@ -299,16 +416,32 @@ int mcux_flexcomm_target_unregister(const struct device *dev, { const struct mcux_flexcomm_config *config = dev->config; struct mcux_flexcomm_data *data = dev->data; + struct mcux_flexcomm_target_data *target; I2C_Type *base = config->base; - if (!data->target_attached) { + target = mcux_flexcomm_find_target_by_address(data, target_config->address); + if (!target || !target->target_attached) { return -EINVAL; } - data->target_cfg = NULL; - data->target_attached = false; + if (mcux_flexcomm_setup_i2c_config_address(data, target, true) < 0) { + return -EINVAL; + } - I2C_SlaveDeinit(base); + target->target_cfg = NULL; + target->target_attached = false; + + data->nr_targets_attached--; + + if (data->nr_targets_attached > 0) { + /* still slaves attached, reconfigure the I2C peripheral after address removal */ + if (mcux_flexcomm_setup_slave_config(dev) < 0) { + return -EINVAL; + } + + } else { + I2C_SlaveDeinit(base); + } return 0; } @@ -321,7 +454,7 @@ static void mcux_flexcomm_isr(const struct device *dev) I2C_Type *base = config->base; #if defined(CONFIG_I2C_TARGET) - if (data->target_attached) { + if (data->nr_targets_attached > 0) { I2C_SlaveTransferHandleIRQ(base, &data->target_handle); return; } @@ -339,6 +472,16 @@ static int mcux_flexcomm_init(const struct device *dev) i2c_master_config_t master_config; int error; + if (!device_is_ready(config->reset.dev)) { + LOG_ERR("Reset device not ready"); + return -ENODEV; + } + + error = reset_line_toggle(config->reset.dev, config->reset.id); + if (error) { + return error; + } + error = pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT); if (error) { return error; @@ -396,6 +539,7 @@ static const struct i2c_driver_api mcux_flexcomm_driver_api = { .irq_config_func = mcux_flexcomm_config_func_##id, \ .bitrate = DT_INST_PROP(id, clock_frequency), \ .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(id), \ + .reset = RESET_DT_SPEC_INST_GET(id), \ }; \ static struct mcux_flexcomm_data mcux_flexcomm_data_##id; \ I2C_DEVICE_DT_INST_DEFINE(id, \ diff --git a/drivers/i2c/i2c_nrfx_twi.c b/drivers/i2c/i2c_nrfx_twi.c index 8af5fe4ddee..56d3727e125 100644 --- a/drivers/i2c/i2c_nrfx_twi.c +++ b/drivers/i2c/i2c_nrfx_twi.c @@ -11,6 +11,7 @@ #include #include #include +#include "i2c_nrfx_twi_common.h" #include #include @@ -23,19 +24,19 @@ LOG_MODULE_REGISTER(i2c_nrfx_twi, CONFIG_I2C_LOG_LEVEL); #endif struct i2c_nrfx_twi_data { + uint32_t dev_config; struct k_sem transfer_sync; struct k_sem completion_sync; volatile nrfx_err_t res; - uint32_t dev_config; -}; - -struct i2c_nrfx_twi_config { - nrfx_twi_t twi; - nrfx_twi_config_t config; - const struct pinctrl_dev_config *pcfg; }; -static int i2c_nrfx_twi_recover_bus(const struct device *dev); +/* Enforce dev_config matches the same offset as the common structure, + * otherwise common API won't be compatible with i2c_nrfx_twi. + */ +BUILD_ASSERT( + offsetof(struct i2c_nrfx_twi_data, dev_config) == + offsetof(struct i2c_nrfx_twi_common_data, dev_config) +); static int i2c_nrfx_twi_transfer(const struct device *dev, struct i2c_msg *msgs, @@ -53,60 +54,17 @@ static int i2c_nrfx_twi_transfer(const struct device *dev, nrfx_twi_enable(&config->twi); for (size_t i = 0; i < num_msgs; i++) { - if (I2C_MSG_ADDR_10_BITS & msgs[i].flags) { - ret = -ENOTSUP; + bool more_msgs = ((i < (num_msgs - 1)) && + !(msgs[i + 1].flags & I2C_MSG_RESTART)); + + ret = i2c_nrfx_twi_msg_transfer(dev, msgs[i].flags, + msgs[i].buf, + msgs[i].len, addr, + more_msgs); + if (ret) { break; } - nrfx_twi_xfer_desc_t cur_xfer = { - .p_primary_buf = msgs[i].buf, - .primary_length = msgs[i].len, - .address = addr, - .type = (msgs[i].flags & I2C_MSG_READ) ? - NRFX_TWI_XFER_RX : NRFX_TWI_XFER_TX - }; - uint32_t xfer_flags = 0; - nrfx_err_t res; - - /* In case the STOP condition is not supposed to appear after - * the current message, check what is requested further: - */ - if (!(msgs[i].flags & I2C_MSG_STOP)) { - /* - if the transfer consists of more messages - * and the I2C repeated START is not requested - * to appear before the next message, suspend - * the transfer after the current message, - * so that it can be resumed with the next one, - * resulting in the two messages merged into - * a continuous transfer on the bus - */ - if ((i < (num_msgs - 1)) && - !(msgs[i + 1].flags & I2C_MSG_RESTART)) { - xfer_flags |= NRFX_TWI_FLAG_SUSPEND; - /* - otherwise, just finish the transfer without - * generating the STOP condition, unless the current - * message is an RX request, for which such feature - * is not supported - */ - } else if (msgs[i].flags & I2C_MSG_READ) { - ret = -ENOTSUP; - break; - } else { - xfer_flags |= NRFX_TWI_FLAG_TX_NO_STOP; - } - } - - res = nrfx_twi_xfer(&config->twi, &cur_xfer, xfer_flags); - if (res != NRFX_SUCCESS) { - if (res == NRFX_ERROR_BUSY) { - ret = -EBUSY; - break; - } else { - ret = -EIO; - break; - } - } - ret = k_sem_take(&data->completion_sync, I2C_TRANSFER_TIMEOUT_MSEC); if (ret != 0) { @@ -132,8 +90,7 @@ static int i2c_nrfx_twi_transfer(const struct device *dev, break; } - res = data->res; - if (res != NRFX_SUCCESS) { + if (data->res != NRFX_SUCCESS) { ret = -EIO; break; } @@ -147,7 +104,8 @@ static int i2c_nrfx_twi_transfer(const struct device *dev, static void event_handler(nrfx_twi_evt_t const *p_event, void *p_context) { - struct i2c_nrfx_twi_data *dev_data = p_context; + const struct device *dev = p_context; + struct i2c_nrfx_twi_data *dev_data = (struct i2c_nrfx_twi_data *)dev->data; switch (p_event->type) { case NRFX_TWI_EVT_DONE: @@ -167,115 +125,12 @@ static void event_handler(nrfx_twi_evt_t const *p_event, void *p_context) k_sem_give(&dev_data->completion_sync); } -static int i2c_nrfx_twi_configure(const struct device *dev, - uint32_t dev_config) -{ - const struct i2c_nrfx_twi_config *config = dev->config; - struct i2c_nrfx_twi_data *data = dev->data; - nrfx_twi_t const *inst = &config->twi; - - if (I2C_ADDR_10_BITS & dev_config) { - return -EINVAL; - } - - switch (I2C_SPEED_GET(dev_config)) { - case I2C_SPEED_STANDARD: - nrf_twi_frequency_set(inst->p_twi, NRF_TWI_FREQ_100K); - break; - case I2C_SPEED_FAST: - nrf_twi_frequency_set(inst->p_twi, NRF_TWI_FREQ_400K); - break; - default: - LOG_ERR("unsupported speed"); - return -EINVAL; - } - data->dev_config = dev_config; - - return 0; -} - -static int i2c_nrfx_twi_recover_bus(const struct device *dev) -{ - const struct i2c_nrfx_twi_config *config = dev->config; - uint32_t scl_pin; - uint32_t sda_pin; - nrfx_err_t err; - - scl_pin = nrf_twi_scl_pin_get(config->twi.p_twi); - sda_pin = nrf_twi_sda_pin_get(config->twi.p_twi); - - err = nrfx_twi_bus_recover(scl_pin, sda_pin); - return (err == NRFX_SUCCESS ? 0 : -EBUSY); -} - static const struct i2c_driver_api i2c_nrfx_twi_driver_api = { .configure = i2c_nrfx_twi_configure, .transfer = i2c_nrfx_twi_transfer, .recover_bus = i2c_nrfx_twi_recover_bus, }; -static int init_twi(const struct device *dev) -{ - const struct i2c_nrfx_twi_config *config = dev->config; - struct i2c_nrfx_twi_data *dev_data = dev->data; - nrfx_err_t result = nrfx_twi_init(&config->twi, &config->config, - event_handler, dev_data); - if (result != NRFX_SUCCESS) { - LOG_ERR("Failed to initialize device: %s", - dev->name); - return -EBUSY; - } - - return 0; -} - -#ifdef CONFIG_PM_DEVICE -static int twi_nrfx_pm_action(const struct device *dev, - enum pm_device_action action) -{ - const struct i2c_nrfx_twi_config *config = dev->config; - struct i2c_nrfx_twi_data *data = dev->data; - int ret = 0; - - switch (action) { - case PM_DEVICE_ACTION_RESUME: - ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); - if (ret < 0) { - return ret; - } - init_twi(dev); - if (data->dev_config) { - i2c_nrfx_twi_configure(dev, data->dev_config); - } - break; - - case PM_DEVICE_ACTION_SUSPEND: - nrfx_twi_uninit(&config->twi); - - ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_SLEEP); - if (ret < 0) { - return ret; - } - break; - - default: - ret = -ENOTSUP; - } - - return ret; -} -#endif /* CONFIG_PM_DEVICE */ - -#define I2C_NRFX_TWI_INVALID_FREQUENCY ((nrf_twi_frequency_t)-1) -#define I2C_NRFX_TWI_FREQUENCY(bitrate) \ - (bitrate == I2C_BITRATE_STANDARD ? NRF_TWI_FREQ_100K \ - : bitrate == 250000 ? NRF_TWI_FREQ_250K \ - : bitrate == I2C_BITRATE_FAST ? NRF_TWI_FREQ_400K \ - : I2C_NRFX_TWI_INVALID_FREQUENCY) -#define I2C(idx) DT_NODELABEL(i2c##idx) -#define I2C_FREQUENCY(idx) \ - I2C_NRFX_TWI_FREQUENCY(DT_PROP(I2C(idx), clock_frequency)) - #define I2C_NRFX_TWI_DEVICE(idx) \ NRF_DT_CHECK_NODE_HAS_PINCTRL_SLEEP(I2C(idx)); \ BUILD_ASSERT(I2C_FREQUENCY(idx) != \ @@ -291,7 +146,7 @@ static int twi_nrfx_pm_action(const struct device *dev, if (err < 0) { \ return err; \ } \ - return init_twi(dev); \ + return i2c_nrfx_twi_init(dev); \ } \ static struct i2c_nrfx_twi_data twi_##idx##_data = { \ .transfer_sync = Z_SEM_INITIALIZER( \ @@ -307,6 +162,7 @@ static int twi_nrfx_pm_action(const struct device *dev, .skip_psel_cfg = true, \ .frequency = I2C_FREQUENCY(idx), \ }, \ + .event_handler = event_handler, \ .pcfg = PINCTRL_DT_DEV_CONFIG_GET(I2C(idx)), \ }; \ PM_DEVICE_DT_DEFINE(I2C(idx), twi_nrfx_pm_action); \ diff --git a/drivers/i2c/i2c_nrfx_twi_common.c b/drivers/i2c/i2c_nrfx_twi_common.c new file mode 100644 index 00000000000..0d8bda63425 --- /dev/null +++ b/drivers/i2c/i2c_nrfx_twi_common.c @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2024, Croxel Inc + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include "i2c_nrfx_twi_common.h" + +#include +LOG_MODULE_DECLARE(i2c_nrfx_twi); + +int i2c_nrfx_twi_init(const struct device *dev) +{ + const struct i2c_nrfx_twi_config *config = dev->config; + nrfx_err_t result = nrfx_twi_init(&config->twi, &config->config, + config->event_handler, (void *)dev); + if (result != NRFX_SUCCESS) { + LOG_ERR("Failed to initialize device: %s", + dev->name); + return -EBUSY; + } + + return 0; +} + +int i2c_nrfx_twi_configure(const struct device *dev, uint32_t dev_config) +{ + const struct i2c_nrfx_twi_config *config = dev->config; + struct i2c_nrfx_twi_common_data *data = dev->data; + nrfx_twi_t const *inst = &config->twi; + + if (I2C_ADDR_10_BITS & dev_config) { + return -EINVAL; + } + + switch (I2C_SPEED_GET(dev_config)) { + case I2C_SPEED_STANDARD: + nrf_twi_frequency_set(inst->p_twi, NRF_TWI_FREQ_100K); + break; + case I2C_SPEED_FAST: + nrf_twi_frequency_set(inst->p_twi, NRF_TWI_FREQ_400K); + break; + default: + LOG_ERR("unsupported speed"); + return -EINVAL; + } + data->dev_config = dev_config; + + return 0; +} + +int i2c_nrfx_twi_recover_bus(const struct device *dev) +{ + const struct i2c_nrfx_twi_config *config = dev->config; + uint32_t scl_pin; + uint32_t sda_pin; + nrfx_err_t err; + + scl_pin = nrf_twi_scl_pin_get(config->twi.p_twi); + sda_pin = nrf_twi_sda_pin_get(config->twi.p_twi); + + err = nrfx_twi_bus_recover(scl_pin, sda_pin); + return (err == NRFX_SUCCESS ? 0 : -EBUSY); +} + +int i2c_nrfx_twi_msg_transfer(const struct device *dev, uint8_t flags, + uint8_t *buf, size_t buf_len, + uint16_t i2c_addr, bool more_msgs) +{ + const struct i2c_nrfx_twi_config *config = dev->config; + int ret = 0; + uint32_t xfer_flags = 0; + nrfx_err_t res; + nrfx_twi_xfer_desc_t cur_xfer = { + .p_primary_buf = buf, + .primary_length = buf_len, + .address = i2c_addr, + .type = (flags & I2C_MSG_READ) ? + NRFX_TWI_XFER_RX : NRFX_TWI_XFER_TX, + }; + + if (flags & I2C_MSG_ADDR_10_BITS) { + LOG_ERR("10-bit I2C Addr devices not supported"); + ret = -ENOTSUP; + } else if (!(flags & I2C_MSG_STOP)) { + /* - if the transfer consists of more messages + * and the I2C repeated START is not requested + * to appear before the next message, suspend + * the transfer after the current message, + * so that it can be resumed with the next one, + * resulting in the two messages merged into + * a continuous transfer on the bus + */ + if (more_msgs) { + xfer_flags |= NRFX_TWI_FLAG_SUSPEND; + /* - otherwise, just finish the transfer without + * generating the STOP condition, unless the current + * message is an RX request, for which such feature + * is not supported + */ + } else if (flags & I2C_MSG_READ) { + ret = -ENOTSUP; + } else { + xfer_flags |= NRFX_TWI_FLAG_TX_NO_STOP; + } + } + + if (!ret) { + res = nrfx_twi_xfer(&config->twi, &cur_xfer, xfer_flags); + switch (res) { + case NRFX_SUCCESS: + break; + case NRFX_ERROR_BUSY: + ret = -EBUSY; + break; + default: + ret = -EIO; + break; + } + } + + return ret; +} + +#ifdef CONFIG_PM_DEVICE +int twi_nrfx_pm_action(const struct device *dev, enum pm_device_action action) +{ + const struct i2c_nrfx_twi_config *config = dev->config; + struct i2c_nrfx_twi_common_data *data = dev->data; + int ret = 0; + + switch (action) { + case PM_DEVICE_ACTION_RESUME: + ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); + if (ret < 0) { + return ret; + } + i2c_nrfx_twi_init(dev); + if (data->dev_config) { + i2c_nrfx_twi_configure(dev, data->dev_config); + } + break; + + case PM_DEVICE_ACTION_SUSPEND: + nrfx_twi_uninit(&config->twi); + + ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_SLEEP); + if (ret < 0) { + return ret; + } + break; + + default: + ret = -ENOTSUP; + } + + return ret; +} +#endif /* CONFIG_PM_DEVICE */ diff --git a/drivers/i2c/i2c_nrfx_twi_common.h b/drivers/i2c/i2c_nrfx_twi_common.h new file mode 100644 index 00000000000..a8925d3f75b --- /dev/null +++ b/drivers/i2c/i2c_nrfx_twi_common.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2024, Croxel Inc + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_I2C_I2C_NRFX_TWI_COMMON_H_ +#define ZEPHYR_DRIVERS_I2C_I2C_NRFX_TWI_COMMON_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define I2C_NRFX_TWI_INVALID_FREQUENCY ((nrf_twi_frequency_t)-1) +#define I2C_NRFX_TWI_FREQUENCY(bitrate) \ + (bitrate == I2C_BITRATE_STANDARD ? NRF_TWI_FREQ_100K \ + : bitrate == 250000 ? NRF_TWI_FREQ_250K \ + : bitrate == I2C_BITRATE_FAST ? NRF_TWI_FREQ_400K \ + : I2C_NRFX_TWI_INVALID_FREQUENCY) +#define I2C(idx) DT_NODELABEL(i2c##idx) +#define I2C_FREQUENCY(idx) \ + I2C_NRFX_TWI_FREQUENCY(DT_PROP(I2C(idx), clock_frequency)) + +struct i2c_nrfx_twi_common_data { + uint32_t dev_config; +}; + +struct i2c_nrfx_twi_config { + nrfx_twi_t twi; + nrfx_twi_config_t config; + nrfx_twi_evt_handler_t event_handler; + const struct pinctrl_dev_config *pcfg; +}; + +static inline nrfx_err_t i2c_nrfx_twi_get_evt_result(nrfx_twi_evt_t const *p_event) +{ + switch (p_event->type) { + case NRFX_TWI_EVT_DONE: + return NRFX_SUCCESS; + case NRFX_TWI_EVT_ADDRESS_NACK: + return NRFX_ERROR_DRV_TWI_ERR_ANACK; + case NRFX_TWI_EVT_DATA_NACK: + return NRFX_ERROR_DRV_TWI_ERR_DNACK; + default: + return NRFX_ERROR_INTERNAL; + } +} + +int i2c_nrfx_twi_init(const struct device *dev); +int i2c_nrfx_twi_configure(const struct device *dev, uint32_t dev_config); +int i2c_nrfx_twi_recover_bus(const struct device *dev); +int i2c_nrfx_twi_msg_transfer(const struct device *dev, uint8_t flags, + uint8_t *buf, size_t buf_len, + uint16_t i2c_addr, bool more_msgs); + +#ifdef CONFIG_PM_DEVICE +int twi_nrfx_pm_action(const struct device *dev, enum pm_device_action action); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_DRIVERS_I2C_I2C_NRFX_TWI_COMMON_H_ */ diff --git a/drivers/i2c/i2c_nrfx_twi_rtio.c b/drivers/i2c/i2c_nrfx_twi_rtio.c new file mode 100644 index 00000000000..cf2e4c06312 --- /dev/null +++ b/drivers/i2c/i2c_nrfx_twi_rtio.c @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2018, Nordic Semiconductor ASA + * Copyright (c) 2024, Croxel Inc + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include "i2c_nrfx_twi_common.h" + +#include +#include +LOG_MODULE_REGISTER(i2c_nrfx_twi, CONFIG_I2C_LOG_LEVEL); + +struct i2c_nrfx_twi_rtio_data { + uint32_t dev_config; + bool twi_enabled; + struct i2c_rtio *ctx; +}; + +/* Enforce dev_config matches the same offset as the common structure, + * otherwise common API won't be compatible with i2c_nrfx_twi_rtio. + */ +BUILD_ASSERT( + offsetof(struct i2c_nrfx_twi_rtio_data, dev_config) == + offsetof(struct i2c_nrfx_twi_common_data, dev_config) +); + +static void i2c_nrfx_twi_complete(const struct device *dev, int status); + +static bool i2c_nrfx_twi_msg_start(const struct device *dev, uint8_t flags, + uint8_t *buf, size_t buf_len, uint16_t i2c_addr) +{ + const struct i2c_nrfx_twi_config *config = dev->config; + struct i2c_nrfx_twi_rtio_data *const dev_data = dev->data; + struct i2c_rtio *ctx = dev_data->ctx; + int ret = 0; + + /** Enabling while already enabled ends up in a failed assertion: skip it. */ + if (!dev_data->twi_enabled) { + nrfx_twi_enable(&config->twi); + dev_data->twi_enabled = true; + } + + ret = i2c_nrfx_twi_msg_transfer(dev, flags, buf, buf_len, i2c_addr, false); + if (ret != 0) { + nrfx_twi_disable(&config->twi); + dev_data->twi_enabled = false; + + return i2c_rtio_complete(ctx, ret); + } + + return false; +} + +static bool i2c_nrfx_twi_start(const struct device *dev) +{ + struct i2c_nrfx_twi_rtio_data *const dev_data = dev->data; + struct i2c_rtio *ctx = dev_data->ctx; + struct rtio_sqe *sqe = &ctx->txn_curr->sqe; + struct i2c_dt_spec *dt_spec = sqe->iodev->data; + + switch (sqe->op) { + case RTIO_OP_RX: + return i2c_nrfx_twi_msg_start(dev, I2C_MSG_READ | sqe->iodev_flags, + sqe->buf, sqe->buf_len, dt_spec->addr); + case RTIO_OP_TINY_TX: + return i2c_nrfx_twi_msg_start(dev, I2C_MSG_WRITE | sqe->iodev_flags, + sqe->tiny_buf, sqe->tiny_buf_len, dt_spec->addr); + case RTIO_OP_TX: + return i2c_nrfx_twi_msg_start(dev, I2C_MSG_WRITE | sqe->iodev_flags, + sqe->buf, sqe->buf_len, dt_spec->addr); + case RTIO_OP_I2C_CONFIGURE: + (void)i2c_nrfx_twi_configure(dev, sqe->i2c_config); + return false; + case RTIO_OP_I2C_RECOVER: + (void)i2c_rtio_recover(ctx); + return false; + default: + LOG_ERR("Invalid op code %d for submission %p\n", sqe->op, (void *)sqe); + return i2c_rtio_complete(ctx, -EINVAL); + } +} + +static void i2c_nrfx_twi_complete(const struct device *dev, int status) +{ + /** Finalize if there are no more pending xfers */ + const struct i2c_nrfx_twi_config *config = dev->config; + struct i2c_nrfx_twi_rtio_data *data = dev->data; + struct i2c_rtio *const ctx = data->ctx; + + if (i2c_rtio_complete(ctx, status)) { + (void)i2c_nrfx_twi_start(dev); + } else { + nrfx_twi_disable(&config->twi); + data->twi_enabled = false; + } +} + +static int i2c_nrfx_twi_transfer(const struct device *dev, + struct i2c_msg *msgs, + uint8_t num_msgs, uint16_t addr) +{ + struct i2c_rtio *const ctx = ((struct i2c_nrfx_twi_rtio_data *) + dev->data)->ctx; + + return i2c_rtio_transfer(ctx, msgs, num_msgs, addr); +} + +static void event_handler(nrfx_twi_evt_t const *p_event, void *p_context) +{ + const struct device *dev = p_context; + int status = 0; + + if (i2c_nrfx_twi_get_evt_result(p_event) != NRFX_SUCCESS) { + status = -EIO; + } + + i2c_nrfx_twi_complete(dev, status); +} + +static void i2c_nrfx_twi_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_seq) +{ + struct i2c_nrfx_twi_rtio_data *data = dev->data; + struct i2c_rtio *const ctx = data->ctx; + + if (i2c_rtio_submit(ctx, iodev_seq)) { + (void)i2c_nrfx_twi_start(dev); + } +} + +static const struct i2c_driver_api i2c_nrfx_twi_driver_api = { + .configure = i2c_nrfx_twi_configure, + .transfer = i2c_nrfx_twi_transfer, + .recover_bus = i2c_nrfx_twi_recover_bus, + .iodev_submit = i2c_nrfx_twi_submit, +}; + +#define I2C_NRFX_TWI_RTIO_DEVICE(idx) \ + NRF_DT_CHECK_NODE_HAS_PINCTRL_SLEEP(I2C(idx)); \ + BUILD_ASSERT(I2C_FREQUENCY(idx) != \ + I2C_NRFX_TWI_INVALID_FREQUENCY, \ + "Wrong I2C " #idx " frequency setting in dts"); \ + static int twi_##idx##_init(const struct device *dev) \ + { \ + IRQ_CONNECT(DT_IRQN(I2C(idx)), DT_IRQ(I2C(idx), priority), \ + nrfx_isr, nrfx_twi_##idx##_irq_handler, 0); \ + const struct i2c_nrfx_twi_config *config = dev->config; \ + const struct i2c_nrfx_twi_rtio_data *dev_data = dev->data; \ + int err = pinctrl_apply_state(config->pcfg, \ + PINCTRL_STATE_DEFAULT); \ + if (err < 0) { \ + return err; \ + } \ + i2c_rtio_init(dev_data->ctx, dev); \ + return i2c_nrfx_twi_init(dev); \ + } \ + I2C_RTIO_DEFINE(_i2c##idx##_twi_rtio, \ + DT_INST_PROP_OR(n, sq_size, CONFIG_I2C_RTIO_SQ_SIZE), \ + DT_INST_PROP_OR(n, cq_size, CONFIG_I2C_RTIO_CQ_SIZE)); \ + static struct i2c_nrfx_twi_rtio_data twi_##idx##_data = { \ + .ctx = &_i2c##idx##_twi_rtio, \ + }; \ + PINCTRL_DT_DEFINE(I2C(idx)); \ + static const struct i2c_nrfx_twi_config twi_##idx##z_config = { \ + .twi = NRFX_TWI_INSTANCE(idx), \ + .config = { \ + .skip_gpio_cfg = true, \ + .skip_psel_cfg = true, \ + .frequency = I2C_FREQUENCY(idx), \ + }, \ + .event_handler = event_handler, \ + .pcfg = PINCTRL_DT_DEV_CONFIG_GET(I2C(idx)), \ + }; \ + PM_DEVICE_DT_DEFINE(I2C(idx), twi_nrfx_pm_action); \ + I2C_DEVICE_DT_DEFINE(I2C(idx), \ + twi_##idx##_init, \ + PM_DEVICE_DT_GET(I2C(idx)), \ + &twi_##idx##_data, \ + &twi_##idx##z_config, \ + POST_KERNEL, \ + CONFIG_I2C_INIT_PRIORITY, \ + &i2c_nrfx_twi_driver_api) + +#ifdef CONFIG_HAS_HW_NRF_TWI0 +I2C_NRFX_TWI_RTIO_DEVICE(0); +#endif + +#ifdef CONFIG_HAS_HW_NRF_TWI1 +I2C_NRFX_TWI_RTIO_DEVICE(1); +#endif diff --git a/drivers/i2c/i2c_rtio.c b/drivers/i2c/i2c_rtio.c index 0a43acc4f62..7fd90c3b89d 100644 --- a/drivers/i2c/i2c_rtio.c +++ b/drivers/i2c/i2c_rtio.c @@ -142,8 +142,6 @@ int i2c_rtio_transfer(struct i2c_rtio *ctx, struct i2c_msg *msgs, uint8_t num_ms goto out; } - sqe->flags &= ~RTIO_SQE_TRANSACTION; - rtio_submit(r, 1); cqe = rtio_cqe_consume(r); diff --git a/drivers/i2c/i2c_shell.c b/drivers/i2c/i2c_shell.c index 4bbefcc5734..176a0d46c56 100644 --- a/drivers/i2c/i2c_shell.c +++ b/drivers/i2c/i2c_shell.c @@ -195,9 +195,6 @@ static int i2c_read_to_buffer(const struct shell *shell_ctx, uint8_t *buf, uint8_t buf_length) { const struct device *dev; - uint8_t reg_addr_buf[MAX_BYTES_FOR_REGISTER_INDEX]; - int reg_addr_bytes; - int reg_addr; int dev_addr; int ret; @@ -209,15 +206,23 @@ static int i2c_read_to_buffer(const struct shell *shell_ctx, } dev_addr = strtol(s_dev_addr, NULL, 16); - reg_addr = strtol(s_reg_addr, NULL, 16); - reg_addr_bytes = get_bytes_count_for_hex(s_reg_addr); - sys_put_be32(reg_addr, reg_addr_buf); + if (s_reg_addr != NULL) { + uint8_t reg_addr_buf[MAX_BYTES_FOR_REGISTER_INDEX]; + int reg_addr_bytes; + int reg_addr; + + reg_addr = strtol(s_reg_addr, NULL, 16); + reg_addr_bytes = get_bytes_count_for_hex(s_reg_addr); + sys_put_be32(reg_addr, reg_addr_buf); + + ret = i2c_write_read(dev, dev_addr, + reg_addr_buf + MAX_BYTES_FOR_REGISTER_INDEX - reg_addr_bytes, + reg_addr_bytes, buf, buf_length); + } else { + ret = i2c_read(dev, buf, buf_length, dev_addr); + } - ret = i2c_write_read(dev, dev_addr, - reg_addr_buf + - MAX_BYTES_FOR_REGISTER_INDEX - reg_addr_bytes, - reg_addr_bytes, buf, buf_length); if (ret < 0) { shell_error(shell_ctx, "Failed to read from device: %s", s_dev_addr); @@ -270,6 +275,30 @@ static int cmd_i2c_read(const struct shell *shell_ctx, size_t argc, char **argv) return ret; } +/* i2c direct_read [] */ +static int cmd_i2c_direct_read(const struct shell *shell_ctx, size_t argc, char **argv) +{ + uint8_t buf[MAX_I2C_BYTES]; + int num_bytes; + int ret; + + if (argc > 3) { + num_bytes = strtol(argv[3], NULL, 16); + if (num_bytes > MAX_I2C_BYTES) { + num_bytes = MAX_I2C_BYTES; + } + } else { + num_bytes = MAX_I2C_BYTES; + } + + ret = i2c_read_to_buffer(shell_ctx, argv[ARGV_DEV], argv[ARGV_ADDR], NULL, buf, num_bytes); + if (ret == 0) { + shell_hexdump(shell_ctx, buf, num_bytes); + } + + return ret; +} + /* i2c speed * For: speed see constants like I2C_SPEED_STANDARD */ @@ -336,6 +365,11 @@ SHELL_STATIC_SUBCMD_SET_CREATE(sub_i2c_cmds, "Read a byte from an I2C device\n" "Usage: read_byte ", cmd_i2c_read_byte, 4, 0), + SHELL_CMD_ARG(direct_read, &dsub_device_name, + "Read byte stream directly from an I2C device without " + "writing a register address first\n" + "Usage: direct_read []", + cmd_i2c_direct_read, 3, 1), SHELL_CMD_ARG(write, &dsub_device_name, "Write bytes to an I2C device\n" "Usage: write [, ...]", diff --git a/drivers/i2c/i2c_xilinx_axi.c b/drivers/i2c/i2c_xilinx_axi.c index 88aef5dd099..c940e8dab0a 100644 --- a/drivers/i2c/i2c_xilinx_axi.c +++ b/drivers/i2c/i2c_xilinx_axi.c @@ -39,19 +39,36 @@ struct i2c_xilinx_axi_data { #endif }; +static void i2c_xilinx_axi_reinit(const struct i2c_xilinx_axi_config *config) +{ + LOG_DBG("Controller reinit"); + sys_write32(SOFTR_KEY, config->base + REG_SOFTR); + sys_write32(CR_TX_FIFO_RST, config->base + REG_CR); + sys_write32(CR_EN, config->base + REG_CR); + sys_write32(GIE_ENABLE, config->base + REG_GIE); +} + #if defined(CONFIG_I2C_TARGET) #define I2C_XILINX_AXI_TARGET_INTERRUPTS \ (ISR_ADDR_TARGET | ISR_NOT_ADDR_TARGET | ISR_RX_FIFO_FULL | ISR_TX_FIFO_EMPTY | \ ISR_TX_ERR_TARGET_COMP) +static void i2c_xilinx_axi_target_setup(const struct i2c_xilinx_axi_config *config, + struct i2c_target_config *cfg) +{ + i2c_xilinx_axi_reinit(config); + + sys_write32(ISR_ADDR_TARGET, config->base + REG_IER); + sys_write32(cfg->address << 1, config->base + REG_ADR); + sys_write32(0, config->base + REG_RX_FIFO_PIRQ); +} + static int i2c_xilinx_axi_target_register(const struct device *dev, struct i2c_target_config *cfg) { const struct i2c_xilinx_axi_config *config = dev->config; struct i2c_xilinx_axi_data *data = dev->data; k_spinlock_key_t key; - uint32_t int_enable; - uint32_t int_status; int ret; if (cfg->flags & I2C_TARGET_FLAGS_ADDR_10_BITS) { @@ -68,20 +85,7 @@ static int i2c_xilinx_axi_target_register(const struct device *dev, struct i2c_t } data->target_cfg = cfg; - - int_status = sys_read32(config->base + REG_ISR); - if (int_status & I2C_XILINX_AXI_TARGET_INTERRUPTS) { - sys_write32(int_status & I2C_XILINX_AXI_TARGET_INTERRUPTS, config->base + REG_ISR); - } - - sys_write32(CR_EN, config->base + REG_CR); - int_enable = sys_read32(config->base + REG_IER); - int_enable |= ISR_ADDR_TARGET; - sys_write32(int_enable, config->base + REG_IER); - - sys_write32(cfg->address << 1, config->base + REG_ADR); - sys_write32(0, config->base + REG_RX_FIFO_PIRQ); - + i2c_xilinx_axi_target_setup(config, cfg); ret = 0; out_unlock: @@ -119,7 +123,6 @@ static int i2c_xilinx_axi_target_unregister(const struct device *dev, struct i2c int_enable = sys_read32(config->base + REG_IER); int_enable &= ~I2C_XILINX_AXI_TARGET_INTERRUPTS; sys_write32(int_enable, config->base + REG_IER); - ret = 0; out_unlock: @@ -130,11 +133,12 @@ static int i2c_xilinx_axi_target_unregister(const struct device *dev, struct i2c } static void i2c_xilinx_axi_target_isr(const struct i2c_xilinx_axi_config *config, - struct i2c_xilinx_axi_data *data, uint32_t int_status, + struct i2c_xilinx_axi_data *data, uint32_t *int_status, uint32_t *ints_to_clear, uint32_t *int_enable) { - if (int_status & ISR_ADDR_TARGET) { + if (*int_status & ISR_ADDR_TARGET) { LOG_DBG("Addressed as target"); + *int_status &= ~ISR_ADDR_TARGET; *int_enable &= ~ISR_ADDR_TARGET; *int_enable |= ISR_NOT_ADDR_TARGET; *ints_to_clear |= ISR_NOT_ADDR_TARGET; @@ -163,7 +167,7 @@ static void i2c_xilinx_axi_target_isr(const struct i2c_xilinx_axi_config *config sys_write32(cr, config->base + REG_CR); } } - } else if (int_status & ISR_NOT_ADDR_TARGET) { + } else if (*int_status & ISR_NOT_ADDR_TARGET) { LOG_DBG("Not addressed as target"); (*data->target_cfg->callbacks->stop)(data->target_cfg); data->target_reading = false; @@ -171,10 +175,12 @@ static void i2c_xilinx_axi_target_isr(const struct i2c_xilinx_axi_config *config data->target_writing = false; sys_write32(CR_EN, config->base + REG_CR); + *int_status &= ~ISR_NOT_ADDR_TARGET; *int_enable &= ~I2C_XILINX_AXI_TARGET_INTERRUPTS; *int_enable |= ISR_ADDR_TARGET; *ints_to_clear |= ISR_ADDR_TARGET; - } else if (int_status & ISR_RX_FIFO_FULL) { + } else if (data->target_writing && (*int_status & ISR_RX_FIFO_FULL)) { + *int_status &= ~ISR_RX_FIFO_FULL; const uint8_t written_byte = sys_read32(config->base + REG_RX_FIFO) & RX_FIFO_DATA_MASK; @@ -186,31 +192,25 @@ static void i2c_xilinx_axi_target_isr(const struct i2c_xilinx_axi_config *config cr |= CR_TXAK; sys_write32(cr, config->base + REG_CR); } - } else if (int_status & ISR_TX_ERR_TARGET_COMP) { - if (data->target_reading) { - /* Controller has NAKed the last byte read, so no more to send. - * Ignore TX FIFO empty so we don't write an extra byte. - */ - LOG_DBG("target read completed"); - *int_enable &= ~ISR_TX_FIFO_EMPTY; - *ints_to_clear |= ISR_TX_FIFO_EMPTY; - } else { - LOG_WRN("Unexpected TX complete"); - } - } else if (int_status & ISR_TX_FIFO_EMPTY) { - if (data->target_reading) { - uint8_t read_byte = 0xFF; - - if (!data->target_read_aborted && - (*data->target_cfg->callbacks->read_processed)(data->target_cfg, - &read_byte)) { - LOG_DBG("target read_processed rejected"); - data->target_read_aborted = true; - } - sys_write32(read_byte, config->base + REG_TX_FIFO); - } else { - LOG_WRN("Unexpected TX empty"); + } else if (data->target_reading && (*int_status & ISR_TX_ERR_TARGET_COMP)) { + /* Controller has NAKed the last byte read, so no more to send. + * Ignore TX FIFO empty so we don't write an extra byte. + */ + LOG_DBG("target read completed"); + *int_status &= ~ISR_TX_ERR_TARGET_COMP; + *int_enable &= ~ISR_TX_FIFO_EMPTY; + *ints_to_clear |= ISR_TX_FIFO_EMPTY; + } else if (data->target_reading && (*int_status & ISR_TX_FIFO_EMPTY)) { + *int_status &= ~ISR_TX_FIFO_EMPTY; + uint8_t read_byte = 0xFF; + + if (!data->target_read_aborted && + (*data->target_cfg->callbacks->read_processed)(data->target_cfg, + &read_byte)) { + LOG_DBG("target read_processed rejected"); + data->target_read_aborted = true; } + sys_write32(read_byte, config->base + REG_TX_FIFO); } } #endif @@ -221,9 +221,8 @@ static void i2c_xilinx_axi_isr(const struct device *dev) struct i2c_xilinx_axi_data *data = dev->data; const k_spinlock_key_t key = k_spin_lock(&data->lock); uint32_t int_enable = sys_read32(config->base + REG_IER); - const uint32_t int_status = sys_read32(config->base + REG_ISR) & int_enable; + uint32_t int_status = sys_read32(config->base + REG_ISR) & int_enable; uint32_t ints_to_clear = int_status; - uint32_t ints_to_mask = int_status; LOG_DBG("ISR called for 0x%08" PRIxPTR ", status 0x%02x", config->base, int_status); @@ -237,26 +236,20 @@ static void i2c_xilinx_axi_isr(const struct device *dev) #if defined(CONFIG_I2C_TARGET) if (data->target_cfg && (int_status & I2C_XILINX_AXI_TARGET_INTERRUPTS)) { - ints_to_mask &= ~(int_status & I2C_XILINX_AXI_TARGET_INTERRUPTS); - i2c_xilinx_axi_target_isr(config, data, int_status, &ints_to_clear, &int_enable); + /* This clears events from int_status which are already handled */ + i2c_xilinx_axi_target_isr(config, data, &int_status, &ints_to_clear, &int_enable); } #endif - sys_write32(int_enable & ~ints_to_mask, config->base + REG_IER); + /* Mask any interrupts which have not already been handled separately */ + sys_write32(int_enable & ~int_status, config->base + REG_IER); /* Be careful, writing 1 to a bit that is not currently set in ISR will SET it! */ sys_write32(ints_to_clear & sys_read32(config->base + REG_ISR), config->base + REG_ISR); k_spin_unlock(&data->lock, key); - k_event_post(&data->irq_event, int_status); -} - -static void i2c_xilinx_axi_reinit(const struct i2c_xilinx_axi_config *config) -{ - LOG_DBG("Controller reinit"); - sys_write32(SOFTR_KEY, config->base + REG_SOFTR); - sys_write32(CR_TX_FIFO_RST, config->base + REG_CR); - sys_write32(CR_EN, config->base + REG_CR); - sys_write32(GIE_ENABLE, config->base + REG_GIE); + if (int_status) { + k_event_post(&data->irq_event, int_status); + } } static int i2c_xilinx_axi_configure(const struct device *dev, uint32_t dev_config) @@ -549,12 +542,6 @@ static int i2c_xilinx_axi_transfer(const struct device *dev, struct i2c_msg *msg k_mutex_lock(&data->mutex, K_FOREVER); - /** - * Reinitializing before each transfer shouldn't technically be needed, but - * seems to improve general reliability. The Linux driver also does this. - */ - i2c_xilinx_axi_reinit(config); - ret = i2c_xilinx_axi_wait_not_busy(config, data); if (ret) { goto out_unlock; @@ -564,11 +551,17 @@ static int i2c_xilinx_axi_transfer(const struct device *dev, struct i2c_msg *msg goto out_unlock; } + /** + * Reinitializing before each transfer shouldn't technically be needed, but + * seems to improve general reliability. The Linux driver also does this. + */ + i2c_xilinx_axi_reinit(config); + do { if (msgs->flags & I2C_MSG_ADDR_10_BITS) { /* Optionally supported in core, but not implemented in driver yet */ ret = -EOPNOTSUPP; - goto out_unlock; + goto out_check_target; } if (msgs->flags & I2C_MSG_READ) { if (config->dyn_read_working && msgs->len <= MAX_DYNAMIC_READ_LEN) { @@ -583,12 +576,25 @@ static int i2c_xilinx_axi_transfer(const struct device *dev, struct i2c_msg *msg ret = i2c_xilinx_axi_wait_not_busy(config, data); } if (ret) { - goto out_unlock; + goto out_check_target; } msgs++; num_msgs--; } while (num_msgs); +out_check_target: +#if defined(CONFIG_I2C_TARGET) + /* If a target is registered, then ensure the controller gets put back + * into a suitable state to handle target transfers. + */ + k_spinlock_key_t key = k_spin_lock(&data->lock); + + if (data->target_cfg) { + i2c_xilinx_axi_target_setup(config, data->target_cfg); + } + k_spin_unlock(&data->lock, key); +#endif + out_unlock: k_mutex_unlock(&data->mutex); return ret; @@ -629,7 +635,7 @@ static const struct i2c_driver_api i2c_xilinx_axi_driver_api = { static const struct i2c_xilinx_axi_config i2c_xilinx_axi_config_##compat##_##n = { \ .base = DT_INST_REG_ADDR(n), \ .irq_config_func = i2c_xilinx_axi_config_func_##compat##_##n, \ - .dyn_read_working = DT_NODE_HAS_COMPAT(DT_DRV_INST(n), xlnx_xps_iic_2_1)}; \ + .dyn_read_working = DT_INST_NODE_HAS_COMPAT(n, xlnx_xps_iic_2_1)}; \ \ static struct i2c_xilinx_axi_data i2c_xilinx_axi_data_##compat##_##n; \ \ diff --git a/drivers/i2s/i2s_ll_stm32.c b/drivers/i2s/i2s_ll_stm32.c index bf06d5f4df7..b289ddabe75 100644 --- a/drivers/i2s/i2s_ll_stm32.c +++ b/drivers/i2s/i2s_ll_stm32.c @@ -633,7 +633,7 @@ static void dma_tx_callback(const struct device *dma_dev, void *arg, #else (void *)LL_SPI_DMA_GetRegAddr(cfg->i2s), #endif - stream->cfg.block_size); + mem_block_size); if (ret < 0) { LOG_DBG("Failed to start TX DMA transfer: %d", ret); goto tx_disable; diff --git a/drivers/i2s/i2s_mcux_flexcomm.c b/drivers/i2s/i2s_mcux_flexcomm.c index 6e966edd4a1..f91aa3489a5 100644 --- a/drivers/i2s/i2s_mcux_flexcomm.c +++ b/drivers/i2s/i2s_mcux_flexcomm.c @@ -449,7 +449,7 @@ static void i2s_mcux_config_dma_blocks(const struct device *dev, LOG_DBG("channel_direction is %d", stream->dma_cfg.channel_direction); LOG_DBG("complete_callback_en is %d", stream->dma_cfg.complete_callback_en); - LOG_DBG("error_callback_en is %d", stream->dma_cfg.error_callback_en); + LOG_DBG("error_callback_dis is %d", stream->dma_cfg.error_callback_dis); LOG_DBG("source_handshake is %d", stream->dma_cfg.source_handshake); LOG_DBG("dest_handshake is %d", stream->dma_cfg.dest_handshake); LOG_DBG("channel_priority is %d", stream->dma_cfg.channel_priority); diff --git a/drivers/i2s/i2s_mcux_sai.c b/drivers/i2s/i2s_mcux_sai.c index 1ab1677c46a..89b07cbedca 100644 --- a/drivers/i2s/i2s_mcux_sai.c +++ b/drivers/i2s/i2s_mcux_sai.c @@ -1303,7 +1303,7 @@ static const struct i2s_driver_api i2s_mcux_driver_api = { CONFIG_I2S_EDMA_BURST_SIZE, \ .dma_callback = i2s_dma_tx_callback, \ .complete_callback_en = 1, \ - .error_callback_en = 1, \ + .error_callback_dis = 1, \ .block_count = 1, \ .head_block = \ &i2s_##i2s_id##_data.tx.dma_block, \ @@ -1323,7 +1323,7 @@ static const struct i2s_driver_api i2s_mcux_driver_api = { CONFIG_I2S_EDMA_BURST_SIZE, \ .dma_callback = i2s_dma_rx_callback, \ .complete_callback_en = 1, \ - .error_callback_en = 1, \ + .error_callback_dis = 1, \ .block_count = 1, \ .head_block = \ &i2s_##i2s_id##_data.rx.dma_block, \ diff --git a/drivers/i3c/CMakeLists.txt b/drivers/i3c/CMakeLists.txt index 71a7dc6eb27..0a2ef3a5f5d 100644 --- a/drivers/i3c/CMakeLists.txt +++ b/drivers/i3c/CMakeLists.txt @@ -16,6 +16,11 @@ zephyr_library_sources_ifdef( i3c_handlers.c ) +zephyr_library_sources_ifdef( + CONFIG_I3C_SHELL + i3c_shell.c +) + zephyr_library_sources_ifdef( CONFIG_I3C_IBI_WORKQUEUE i3c_ibi_workq.c @@ -31,6 +36,11 @@ zephyr_library_sources_ifdef( i3c_cdns.c ) +zephyr_library_sources_ifdef( + CONFIG_I3C_NPCX + i3c_npcx.c +) + zephyr_library_sources_ifdef( CONFIG_I3C_TEST i3c_test.c diff --git a/drivers/i3c/Kconfig b/drivers/i3c/Kconfig index 2b524c2bf9d..ca3fde0318a 100644 --- a/drivers/i3c/Kconfig +++ b/drivers/i3c/Kconfig @@ -15,6 +15,15 @@ module = I3C module-str = i3c source "subsys/logging/Kconfig.template.log_config" +config I3C_SHELL + bool "I3C Shell" + depends on SHELL + help + Enable I3C Shell. + + The I3C shell supports info, bus recovery, CCC, I3C read and + write operations. + config I3C_USE_GROUP_ADDR bool "Use Group Addresses" default y @@ -100,6 +109,7 @@ comment "Device Drivers" rsource "Kconfig.nxp" rsource "Kconfig.cdns" +rsource "Kconfig.npcx" rsource "Kconfig.test" endif # I3C diff --git a/drivers/i3c/Kconfig.npcx b/drivers/i3c/Kconfig.npcx new file mode 100644 index 00000000000..b3b317a6fb6 --- /dev/null +++ b/drivers/i3c/Kconfig.npcx @@ -0,0 +1,35 @@ +# NPCX I3C driver configuration options + +# Copyright (c) 2024 Nuvoton Technology Corporation. +# SPDX-License-Identifier: Apache-2.0 + +DT_I3C_NPCX := $(dt_nodelabel_path,i3c0) + +config I3C_NPCX + bool "Nuvoton NPCX embedded controller (EC) I3C driver" + depends on DT_HAS_NUVOTON_NPCX_I3C_ENABLED + select RESET + select I3C_IBI_WORKQUEUE if I3C_USE_IBI + default y + help + This option enables the I3C driver for NPCX family of + processors. + Say y if you wish to use I3C channels on NPCX MCU. + +# Expose this option when the 'reg' property includes the MDMA base address +# as the second group in the phandle-array. +# i.e. I3C node example in dtsi file. +# i3c0: i3c@400f0000 { +# .... +# /* reg[0]: I3C_1 register, reg[1]: MDMA5 register */ +# reg-names = "i3c1", "mdma5"; +# reg = <0x400f0000 0x2000>, +# <0x40011500 0x100>; +# .... +# } +config I3C_NPCX_DMA + bool "Nuvoton NPCX embedded controller (EC) serial driver DMA support" + depends on I3C_NPCX && "$(dt_node_reg_addr_hex,$(DT_I3C_NPCX),1)" != 0 + default y + help + Enable support for npcx I3C DMA mode. diff --git a/drivers/i3c/i3c_ccc.c b/drivers/i3c/i3c_ccc.c index efe65e6756e..7b03b5b9f42 100644 --- a/drivers/i3c/i3c_ccc.c +++ b/drivers/i3c/i3c_ccc.c @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -254,8 +255,7 @@ int i3c_ccc_do_setmwl_all(const struct device *controller, ccc_payload.ccc.data_len = sizeof(data); /* The actual data is MSB first. So order the data. */ - data[0] = (uint8_t)((mwl->len & 0xFF00U) >> 8); - data[1] = (uint8_t)(mwl->len & 0xFFU); + sys_put_be16(mwl->len, data); return i3c_do_ccc(controller, &ccc_payload); } @@ -282,8 +282,7 @@ int i3c_ccc_do_setmwl(const struct i3c_device_desc *target, ccc_payload.targets.num_targets = 1; /* The actual length is MSB first. So order the data. */ - data[0] = (uint8_t)((mwl->len & 0xFF00U) >> 8); - data[1] = (uint8_t)(mwl->len & 0xFFU); + sys_put_be16(mwl->len, data); return i3c_do_ccc(target->bus, &ccc_payload); } @@ -314,7 +313,7 @@ int i3c_ccc_do_getmwl(const struct i3c_device_desc *target, if (ret == 0) { /* The actual length is MSB first. So order the data. */ - mwl->len = (data[0] << 8) | data[1]; + mwl->len = sys_get_be16(data); } return ret; @@ -337,8 +336,7 @@ int i3c_ccc_do_setmrl_all(const struct device *controller, ccc_payload.ccc.data_len = has_ibi_size ? 3 : 2; /* The actual length is MSB first. So order the data. */ - data[0] = (uint8_t)((mrl->len & 0xFF00U) >> 8); - data[1] = (uint8_t)(mrl->len & 0xFFU); + sys_put_be16(mrl->len, data); if (has_ibi_size) { data[2] = mrl->ibi_len; @@ -368,8 +366,7 @@ int i3c_ccc_do_setmrl(const struct i3c_device_desc *target, ccc_payload.targets.num_targets = 1; /* The actual length is MSB first. So order the data. */ - data[0] = (uint8_t)((mrl->len & 0xFF00U) >> 8); - data[1] = (uint8_t)(mrl->len & 0xFFU); + sys_put_be16(mrl->len, data); if ((target->bcr & I3C_BCR_IBI_PAYLOAD_HAS_DATA_BYTE) == I3C_BCR_IBI_PAYLOAD_HAS_DATA_BYTE) { @@ -413,7 +410,7 @@ int i3c_ccc_do_getmrl(const struct i3c_device_desc *target, if (ret == 0) { /* The actual length is MSB first. So order the data. */ - mrl->len = (data[0] << 8) | data[1]; + mrl->len = sys_get_be16(data); if (has_ibi_sz) { mrl->ibi_len = data[2]; @@ -477,13 +474,112 @@ int i3c_ccc_do_getstatus(const struct i3c_device_desc *target, if (ret == 0) { /* Received data is MSB first. So order the data. */ if (fmt == GETSTATUS_FORMAT_1) { - status->fmt1.status = (data[0] << 8) | data[1]; + status->fmt1.status = sys_get_be16(data); } else if (fmt == GETSTATUS_FORMAT_2) { switch (defbyte) { case GETSTATUS_FORMAT_2_TGTSTAT: __fallthrough; case GETSTATUS_FORMAT_2_PRECR: - status->fmt2.raw_u16 = (data[0] << 8) | data[1]; + status->fmt2.raw_u16 = sys_get_be16(data); + break; + default: + break; + } + } + } + +out: + return ret; +} + +int i3c_ccc_do_getcaps(const struct i3c_device_desc *target, + union i3c_ccc_getcaps *caps, + enum i3c_ccc_getcaps_fmt fmt, + enum i3c_ccc_getcaps_defbyte defbyte) +{ + struct i3c_ccc_payload ccc_payload; + struct i3c_ccc_target_payload ccc_tgt_payload; + uint8_t defining_byte; + uint8_t data[4]; + uint8_t len; + int ret; + + __ASSERT_NO_MSG(target != NULL); + __ASSERT_NO_MSG(target->bus != NULL); + __ASSERT_NO_MSG(caps != NULL); + + ccc_tgt_payload.addr = target->dynamic_addr; + ccc_tgt_payload.rnw = 1; + ccc_tgt_payload.data = &data[0]; + + if (fmt == GETCAPS_FORMAT_1) { + /* Could be 1-4 Data Bytes Returned */ + ccc_tgt_payload.data_len = 4; + } else if (fmt == GETCAPS_FORMAT_2) { + switch (defbyte) { + case GETCAPS_FORMAT_2_CRCAPS: + __fallthrough; + case GETCAPS_FORMAT_2_VTCAPS: + /* Could be 1-2 Data Bytes Returned*/ + ccc_tgt_payload.data_len = 2; + break; + case GETCAPS_FORMAT_2_TGTCAPS: + __fallthrough; + case GETCAPS_FORMAT_2_TESTPAT: + /* Could be 1-4 Data Bytes Returned */ + ccc_tgt_payload.data_len = 4; + break; + default: + ret = -EINVAL; + goto out; + } + } else { + ret = -EINVAL; + goto out; + } + + memset(&ccc_payload, 0, sizeof(ccc_payload)); + ccc_payload.ccc.id = I3C_CCC_GETCAPS; + ccc_payload.targets.payloads = &ccc_tgt_payload; + ccc_payload.targets.num_targets = 1; + + if (fmt == GETCAPS_FORMAT_2) { + defining_byte = (uint8_t)defbyte; + + ccc_payload.ccc.data = &defining_byte; + ccc_payload.ccc.data_len = 1; + } + + ret = i3c_do_ccc(target->bus, &ccc_payload); + + if (ret == 0) { + /* GETCAPS will return a variable length */ + len = ccc_tgt_payload.num_xfer; + + if (fmt == GETCAPS_FORMAT_1) { + memcpy(caps->fmt1.getcaps, data, len); + /* for values not received, assume default (1'b0) */ + memset(&caps->fmt1.getcaps[len], 0, sizeof(caps->fmt1.getcaps) - len); + } else if (fmt == GETCAPS_FORMAT_2) { + switch (defbyte) { + case GETCAPS_FORMAT_2_CRCAPS: + memcpy(caps->fmt2.crcaps, data, len); + /* for values not received, assume default (1'b0) */ + memset(&caps->fmt2.crcaps[len], 0, sizeof(caps->fmt2.crcaps) - len); + case GETCAPS_FORMAT_2_VTCAPS: + memcpy(caps->fmt2.vtcaps, data, len); + /* for values not received, assume default (1'b0) */ + memset(&caps->fmt2.vtcaps[len], 0, sizeof(caps->fmt2.vtcaps) - len); + break; + case GETCAPS_FORMAT_2_TGTCAPS: + memcpy(caps->fmt2.tgtcaps, data, len); + /* for values not received, assume default (1'b0) */ + memset(&caps->fmt2.tgtcaps[len], 0, + sizeof(caps->fmt2.tgtcaps) - len); + break; + case GETCAPS_FORMAT_2_TESTPAT: + /* should always be 4 data bytes */ + caps->fmt2.testpat = sys_get_be32(data); break; default: break; diff --git a/drivers/i3c/i3c_cdns.c b/drivers/i3c/i3c_cdns.c index ef361523e4e..fab1df7f4ab 100644 --- a/drivers/i3c/i3c_cdns.c +++ b/drivers/i3c/i3c_cdns.c @@ -1350,9 +1350,42 @@ static void cdns_i3c_complete_transfer(const struct device *dev) } break; + case CMDR_M0_ERROR: { + uint8_t ccc = data->xfer.cmds[i].cmd1 & 0xFF; + /* + * The M0 is an illegally formatted CCC. i.e. the Controller + * receives 1 byte instead of 2 with the GETMWL CCC. This can + * be problematic for CCCs that can have variable length such + * as GETMXDS and GETCAPS. Verify the number of bytes received matches + * what's expected from the specification and ignore the error. The IP will + * still retramsit the same CCC and theres nothing that can be done to + * prevent this. It it still up to the application to read `num_xfer` to + * determine the number of bytes returned. + */ + if (ccc == I3C_CCC_GETMXDS) { + /* + * Whether GETMXDS format 1 and format 2 can't be known ahead of + * time which will be returned. + */ + if ((*data->xfer.cmds[i].num_xfer != + sizeof(((union i3c_ccc_getmxds *)0)->fmt1)) && + (*data->xfer.cmds[i].num_xfer != + sizeof(((union i3c_ccc_getmxds *)0)->fmt2))) { + ret = -EIO; + } + } else if (ccc == I3C_CCC_GETCAPS) { + /* GETCAPS can only return 1-4 bytes */ + if (*data->xfer.cmds[i].num_xfer > sizeof(union i3c_ccc_getcaps)) { + ret = -EIO; + } + } else { + ret = -EIO; + } + 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_NACK_RESP: diff --git a/drivers/i3c/i3c_common.c b/drivers/i3c/i3c_common.c index 6c170edb9e3..f58521bd483 100644 --- a/drivers/i3c/i3c_common.c +++ b/drivers/i3c/i3c_common.c @@ -454,7 +454,7 @@ int i3c_dev_list_daa_addr_helper(struct i3c_addr_slots *addr_slots, goto out; } - if (desc->dynamic_addr != 0U) { + if (desc != NULL && desc->dynamic_addr != 0U) { if (assigned_okay) { /* Return the already assigned address if desired so. */ dyn_addr = desc->dynamic_addr; @@ -477,9 +477,8 @@ int i3c_dev_list_daa_addr_helper(struct i3c_addr_slots *addr_slots, * Use the desired dynamic address as the new dynamic address * if the slot is free. */ - if (desc->init_dynamic_addr != 0U) { - if (i3c_addr_slots_is_free(addr_slots, - desc->init_dynamic_addr)) { + if (desc != NULL && desc->init_dynamic_addr != 0U) { + if (i3c_addr_slots_is_free(addr_slots, desc->init_dynamic_addr)) { dyn_addr = desc->init_dynamic_addr; goto out; } @@ -513,6 +512,7 @@ int i3c_device_basic_info_get(struct i3c_device_desc *target) struct i3c_ccc_getdcr dcr = {0}; struct i3c_ccc_mrl mrl = {0}; struct i3c_ccc_mwl mwl = {0}; + union i3c_ccc_getcaps caps = {0}; /* * Since some CCC functions requires BCR to function @@ -548,6 +548,21 @@ int i3c_device_basic_info_get(struct i3c_device_desc *target) LOG_DBG("No settable limit for GETMWL"); } + /* GETCAPS */ + ret = i3c_ccc_do_getcaps_fmt1(target, &caps); + /* + * GETCAPS (GETHDRCAP) is required to be supported for I3C v1.0 targets that support HDR + * modes and required if the Target's I3C version is v1.1 or later, but which the version it + * supports it can't be known ahead of time. So if the BCR bit for Advanced capabilities is + * set, then it is expected for GETCAPS to always be supported. Otherwise, then it's a I3C + * v1.0 device without any HDR modes so do not treat as an error if no valid response. + */ + if (ret == 0) { + memcpy(&target->getcaps, &caps, sizeof(target->getcaps)); + } else if ((ret != 0) && (target->bcr & I3C_BCR_ADV_CAPABILITIES)) { + goto out; + } + target->dcr = dcr.dcr; target->data_length.mrl = mrl.len; target->data_length.mwl = mwl.len; diff --git a/drivers/i3c/i3c_mcux.c b/drivers/i3c/i3c_mcux.c index 70fd991c4ee..f3c91ea148c 100644 --- a/drivers/i3c/i3c_mcux.c +++ b/drivers/i3c/i3c_mcux.c @@ -63,6 +63,8 @@ LOG_MODULE_REGISTER(i3c_mcux, CONFIG_I3C_MCUX_LOG_LEVEL); #define I3C_MSTATUS_IBITYPE_MR I3C_MSTATUS_IBITYPE(2) #define I3C_MSTATUS_IBITYPE_HJ I3C_MSTATUS_IBITYPE(3) +#define I3C_MAX_STOP_RETRIES 5 + struct mcux_i3c_config { /** Common I3C Driver Config */ struct i3c_driver_config common; @@ -146,38 +148,24 @@ struct mcux_i3c_data { * @param reg Pointer to 32-bit Register. * @param mask Mask to the register value. * @param match Value to match for masked register value. - * @param init_delay_us Initial delay in microsecond before reading register - * (can be 0). - * @param step_delay_us Delay in microsecond between each read of register - * (cannot be 0). - * @param total_delay_us Total delay in microsecond before bailing out. + * @param timeout_us Timeout in microsecond before bailing out. * * @retval 0 If masked register value matches before time out. - * @retval -ETIMEDOUT Exhausted all delays without matching. + * @retval -ETIMEDOUT Timedout without matching. */ static int reg32_poll_timeout(volatile uint32_t *reg, uint32_t mask, uint32_t match, - uint32_t init_delay_us, uint32_t step_delay_us, - uint32_t total_delay_us) + uint32_t timeout_us) { - uint32_t delayed = init_delay_us; - int ret = -ETIMEDOUT; - - if (init_delay_us > 0U) { - k_busy_wait(init_delay_us); - } - - while (delayed <= total_delay_us) { - if ((sys_read32((mm_reg_t)reg) & mask) == match) { - ret = 0; - break; - } - - k_busy_wait(step_delay_us); - delayed += step_delay_us; + /* + * These polling checks are typically satisfied + * quickly (some sub-microseconds) so no extra + * delay between checks. + */ + if (!WAIT_FOR((sys_read32((mm_reg_t)reg) & mask) == match, timeout_us, /*nop*/)) { + return -ETIMEDOUT; } - - return ret; + return 0; } /** @@ -360,22 +348,15 @@ static inline void mcux_i3c_status_wait(I3C_Type *base, uint32_t mask) * * @param base Pointer to controller registers. * @param mask Bits to be tested. - * @param init_delay_us Initial delay in microsecond before reading register - * (can be 0). - * @param step_delay_us Delay in microsecond between each read of register - * (cannot be 0). - * @param total_delay_us Total delay in microsecond before bailing out. + * @param timeout_us Timeout in microsecond before bailing out. * * @retval 0 If bits are set before time out. - * @retval -ETIMEDOUT Exhausted all delays. + * @retval -ETIMEDOUT */ static inline int mcux_i3c_status_wait_timeout(I3C_Type *base, uint32_t mask, - uint32_t init_delay_us, - uint32_t step_delay_us, - uint32_t total_delay_us) + uint32_t timeout_us) { - return reg32_poll_timeout(&base->MSTATUS, mask, mask, - init_delay_us, step_delay_us, total_delay_us); + return reg32_poll_timeout(&base->MSTATUS, mask, mask, timeout_us); } /** @@ -427,37 +408,27 @@ static inline void mcux_i3c_status_clear_all(I3C_Type *base) * * @param base Pointer to controller registers. * @param mask Bits to be cleared. - * @param init_delay_us Initial delay in microsecond before reading register - * (can be 0). - * @param step_delay_us Delay in microsecond between each read of register - * (cannot be 0). - * @param total_delay_us Total delay in microsecond before bailing out. + * @param timeout_us Timeout in microsecond before bailing out. * * @retval 0 If bits are cleared before time out. - * @retval -ETIMEDOUT Exhausted all delays. + * @retval -ETIMEDOUT */ static inline int mcux_i3c_status_clear_timeout(I3C_Type *base, uint32_t mask, - uint32_t init_delay_us, - uint32_t step_delay_us, - uint32_t total_delay_us) + uint32_t timeout_us) { - uint32_t delayed = init_delay_us; - int ret = -ETIMEDOUT; - - /* Try to clear bit until it is cleared */ - while (delayed <= total_delay_us) { - base->MSTATUS = mask; - - if (!mcux_i3c_status_is_set(base, mask)) { - ret = 0; - break; - } + bool result; - k_busy_wait(step_delay_us); - delayed += step_delay_us; + base->MSTATUS = mask; + /* + * Status should clear quickly so no extra delays between + * checks. Use the delay_stmt to retry clearing the + * status by writing to the MSTATUS register. + */ + result = WAIT_FOR(!mcux_i3c_status_is_set(base, mask), timeout_us, base->MSTATUS = mask); + if (!result) { + return -ETIMEDOUT; } - - return ret; + return 0; } /** @@ -486,30 +457,22 @@ static inline void mcux_i3c_status_wait_clear(I3C_Type *base, uint32_t mask) * * @param base Pointer to controller registers. * @param mask Bits to be set and to be cleared. - * @param init_delay_us Initial delay in microsecond before reading register - * (can be 0). - * @param step_delay_us Delay in microsecond between each read of register - * (cannot be 0). - * @param total_delay_us Total delay in microsecond before bailing out. + * @param timeout_us Timeout in microsecond before bailing out. * * @retval 0 If masked register value matches before time out. - * @retval -ETIMEDOUT Exhausted all delays without matching. + * @retval -ETIMEDOUT Timedout without matching. */ static inline int mcux_i3c_status_wait_clear_timeout(I3C_Type *base, uint32_t mask, - uint32_t init_delay_us, - uint32_t step_delay_us, - uint32_t total_delay_us) + uint32_t timeout_us) { int ret; - ret = mcux_i3c_status_wait_timeout(base, mask, init_delay_us, - step_delay_us, total_delay_us); + ret = mcux_i3c_status_wait_timeout(base, mask, timeout_us); if (ret != 0) { goto out; } - ret = mcux_i3c_status_clear_timeout(base, mask, init_delay_us, - step_delay_us, total_delay_us); + ret = mcux_i3c_status_clear_timeout(base, mask, timeout_us); out: return ret; @@ -578,12 +541,10 @@ static inline uint32_t mcux_i3c_state_get(I3C_Type *base) } /** - * @brief Wait for MSTATUS bit to be set, and clear it afterwards with time out. + * @brief Wait for MSTATUS state * * @param base Pointer to controller registers. - * @param mask Bits to be set. - * @param init_delay_us Initial delay in microsecond before reading register - * (can be 0). + * @param state MSTATUS state to wait for. * @param step_delay_us Delay in microsecond between each read of register * (cannot be 0). * @param total_delay_us Total delay in microsecond before bailing out. @@ -592,14 +553,12 @@ static inline uint32_t mcux_i3c_state_get(I3C_Type *base) * @retval -ETIMEDOUT Exhausted all delays without matching. */ static inline int mcux_i3c_state_wait_timeout(I3C_Type *base, uint32_t state, - uint32_t init_delay_us, uint32_t step_delay_us, uint32_t total_delay_us) { - uint32_t delayed = init_delay_us; + uint32_t delayed = 0; int ret = -ETIMEDOUT; - /* Try to clear bit until it is cleared */ while (delayed <= total_delay_us) { if (mcux_i3c_state_get(base) == state) { ret = 0; @@ -662,7 +621,7 @@ static int mcux_i3c_request_emit_start(I3C_Type *base, uint8_t addr, bool is_i2c /* Wait for controller to say the operation is done */ ret = mcux_i3c_status_wait_clear_timeout(base, I3C_MSTATUS_MCTRLDONE_MASK, - 0, 10, 1000); + 1000); if (ret == 0) { /* Check for NACK */ if (mcux_i3c_error_is_nack(base)) { @@ -676,23 +635,18 @@ static int mcux_i3c_request_emit_start(I3C_Type *base, uint8_t addr, bool is_i2c /** * @brief Tell controller to emit STOP. * - * This emits STOP when controller is in NORMACT state as this is - * the only valid state where STOP can be emitted. This also waits - * for the controller to get out of NORMACT before returning. + * This emits STOP and waits for controller to get out of NORMACT, + * checking for errors. * * @param base Pointer to controller registers. * @param wait_stop True if need to wait for controller to be * no longer in NORMACT. */ -static inline void mcux_i3c_request_emit_stop(struct mcux_i3c_data *dev_data, - I3C_Type *base, bool wait_stop) +static inline int mcux_i3c_do_request_emit_stop(I3C_Type *base, bool wait_stop) { - /* Make sure we are in a state where we can emit STOP */ - if (mcux_i3c_state_get(base) == I3C_MSTATUS_STATE_NORMACT) { - reg32_update(&base->MCTRL, - I3C_MCTRL_REQUEST_MASK | I3C_MCTRL_DIR_MASK | I3C_MCTRL_RDTERM_MASK, - I3C_MCTRL_REQUEST_EMIT_STOP); - } + reg32_update(&base->MCTRL, + I3C_MCTRL_REQUEST_MASK | I3C_MCTRL_DIR_MASK | I3C_MCTRL_RDTERM_MASK, + I3C_MCTRL_REQUEST_EMIT_STOP); /* * EMIT_STOP request doesn't result in MCTRLDONE being cleared @@ -709,14 +663,78 @@ static inline void mcux_i3c_request_emit_stop(struct mcux_i3c_data *dev_data, I3C_MSTATUS_STATE_NORMACT)) { if (mcux_i3c_has_error(base)) { /* - * Bail out if there is any error so - * we won't loop forever. + * A timeout error has been observed on + * an EMIT_STOP request. Refman doesn't say + * how that could occur but clear it + * and return the error. */ - return; + if (reg32_test(&base->MERRWARN, + I3C_MERRWARN_TIMEOUT_MASK)) { + mcux_i3c_errwarn_clear_all_nowait(base); + return -ETIMEDOUT; + } + return -EIO; } - k_busy_wait(10); - }; + } + } + return 0; +} + +/** + * @brief Tell controller to emit STOP. + * + * This emits STOP when controller is in NORMACT state as this is + * the only valid state where STOP can be emitted. This also waits + * for the controller to get out of NORMACT before returning and + * retries if any timeout errors occur during the emit STOP. + * + * @param dev_data Pointer to device driver data + * @param base Pointer to controller registers. + * @param wait_stop True if need to wait for controller to be + * no longer in NORMACT. + */ +static inline void mcux_i3c_request_emit_stop(struct mcux_i3c_data *dev_data, + I3C_Type *base, bool wait_stop) +{ + size_t retries; + + /* + * Stop is usually the last part of a transfer. + * Sometimes, an error occurred before. We want to clear + * it so any error as a result of emitting the stop + * itself doesn't get incorrectly mixed together. + */ + if (mcux_i3c_has_error(base)) { + mcux_i3c_errwarn_clear_all_nowait(base); + } + + /* Make sure we are in a state where we can emit STOP */ + if (!reg32_test_match(&base->MSTATUS, I3C_MSTATUS_STATE_MASK, + I3C_MSTATUS_STATE_NORMACT)) { + return; + } + + retries = 0; + while (1) { + int err = mcux_i3c_do_request_emit_stop(base, wait_stop); + + if (err) { + if ((err == -ETIMEDOUT) && (++retries <= I3C_MAX_STOP_RETRIES)) { + LOG_WRN("Timeout on emit stop, retrying"); + continue; + } + LOG_ERR("Error waiting for stop"); + return; + } + /* + * Success. If wait_stop was true, state should now + * be IDLE or possibly SLVREQ. + */ + if (retries) { + LOG_WRN("EMIT_STOP succeeded on %u retries", retries); + } + break; } /* Release any threads that might have been blocked waiting for IDLE */ @@ -857,7 +875,7 @@ static int mcux_i3c_recover_bus(const struct device *dev) mcux_i3c_request_auto_ibi(base); if (mcux_i3c_status_wait_clear_timeout(base, I3C_MSTATUS_COMPLETE_MASK, - 0, 10, 1000) == -ETIMEDOUT) { + 1000) == -ETIMEDOUT) { break; } @@ -873,7 +891,7 @@ static int mcux_i3c_recover_bus(const struct device *dev) } if (reg32_poll_timeout(&base->MSTATUS, I3C_MSTATUS_STATE_MASK, - I3C_MSTATUS_STATE_IDLE, 0, 10, 1000) == -ETIMEDOUT) { + I3C_MSTATUS_STATE_IDLE, 1000) == -ETIMEDOUT) { ret = -EBUSY; } @@ -962,8 +980,7 @@ static int mcux_i3c_do_one_xfer_write(I3C_Type *base, uint8_t *buf, uint8_t buf_ int ret = 0; while (remaining > 0) { - ret = reg32_poll_timeout(&base->MDATACTRL, I3C_MDATACTRL_TXFULL_MASK, 0, - 0, 10, 1000); + ret = reg32_poll_timeout(&base->MDATACTRL, I3C_MDATACTRL_TXFULL_MASK, 0, 1000); if (ret == -ETIMEDOUT) { goto one_xfer_write_out; } @@ -1036,9 +1053,11 @@ static int mcux_i3c_do_one_xfer(I3C_Type *base, struct mcux_i3c_data *data, } if (is_read || !no_ending) { - /* Wait for controller to say the operation is done */ - ret = mcux_i3c_status_wait_clear_timeout(base, I3C_MSTATUS_COMPLETE_MASK, - 0, 10, 1000); + /* + * Wait for controller to say the operation is done. + * Save time by not clearing the bit. + */ + ret = mcux_i3c_status_wait_timeout(base, I3C_MSTATUS_COMPLETE_MASK, 1000); if (ret != 0) { LOG_DBG("%s: timed out addr 0x%02x, buf_sz %u", __func__, addr, buf_sz); @@ -1202,7 +1221,7 @@ static int mcux_i3c_do_daa(const struct device *dev) k_mutex_lock(&data->lock, K_FOREVER); - ret = mcux_i3c_state_wait_timeout(base, I3C_MSTATUS_STATE_IDLE, 0, 100, 100000); + ret = mcux_i3c_state_wait_timeout(base, I3C_MSTATUS_STATE_IDLE, 100, 100000); if (ret == -ETIMEDOUT) { goto out_daa_unlock; } @@ -1398,7 +1417,7 @@ static int mcux_i3c_do_ccc(const struct device *dev, } /* Wait for controller to say the operation is done */ - ret = mcux_i3c_status_wait_clear_timeout(base, I3C_MSTATUS_COMPLETE_MASK, 0, 10, 1000); + ret = mcux_i3c_status_wait_clear_timeout(base, I3C_MSTATUS_COMPLETE_MASK, 1000); if (ret != 0) { goto out_ccc_stop; } @@ -1502,7 +1521,7 @@ static void mcux_i3c_ibi_work(struct k_work *work) case I3C_MSTATUS_IBITYPE_MR: if (mcux_i3c_status_wait_timeout(base, I3C_MSTATUS_COMPLETE_MASK, - 0, 10, 1000) == -ETIMEDOUT) { + 1000) == -ETIMEDOUT) { LOG_ERR("Timeout waiting for COMPLETE"); mcux_i3c_request_emit_stop(data, base, true); diff --git a/drivers/i3c/i3c_npcx.c b/drivers/i3c/i3c_npcx.c new file mode 100644 index 00000000000..9790e593915 --- /dev/null +++ b/drivers/i3c/i3c_npcx.c @@ -0,0 +1,2052 @@ +/* + * Copyright (c) 2024 Nuvoton Technology Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ +/*132*/ +#define DT_DRV_COMPAT nuvoton_npcx_i3c + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(npcx_i3c, CONFIG_I3C_LOG_LEVEL); + +#define NPCX_I3C_CHK_TIMEOUT_US 10000 /* Timeout for checking register status */ +#define I3C_SCL_PP_FREQ_MAX_MHZ 12500000 +#define I3C_SCL_OD_FREQ_MAX_MHZ 4170000 + +#define I3C_BUS_TLOW_PP_MIN_NS 24 /* T_LOW period in push-pull mode */ +#define I3C_BUS_THigh_PP_MIN_NS 24 /* T_High period in push-pull mode */ +#define I3C_BUS_TLOW_OD_MIN_NS 200 /* T_LOW period in open-drain mode */ + +#define PPBAUD_DIV_MAX (BIT(GET_FIELD_SZ(NPCX_I3C_MCONFIG_PPBAUD)) - 1) /* PPBAUD divider max */ + +#define DAA_TGT_INFO_SZ 0x8 /* 8 bytes = PID(6) + BCR(1) + DCR(1) */ +#define BAMATCH_DIV 0x4 /* BAMATCH = APB4_CLK divided by four */ + +/* Default maximum time we allow for an I3C transfer */ +#define I3C_TRANS_TIMEOUT_MS K_MSEC(100) + +#define MCLKD_FREQ_45_MHZ MHZ(45) + +#define I3C_STATUS_CLR_MASK \ + (BIT(NPCX_I3C_MSTATUS_TGTSTART) | BIT(NPCX_I3C_MSTATUS_MCTRLDONE) | \ + BIT(NPCX_I3C_MSTATUS_COMPLETE) | BIT(NPCX_I3C_MSTATUS_IBIWON) | \ + BIT(NPCX_I3C_MSTATUS_NOWCNTLR)) + +/* Supported I3C MCLKD frequency */ +enum npcx_i3c_speed { + NPCX_I3C_BUS_SPEED_45MHZ, +}; + +/* Operation type */ +enum npcx_i3c_oper_state { + NPCX_I3C_IDLE, + NPCX_I3C_WR, + NPCX_I3C_RD, +}; + +/* I3C timing configuration for each i3c speed */ +struct npcx_i3c_timing_cfg { + uint8_t ppbaud; /* Push-Pull high period */ + uint8_t pplow; /* Push-Pull low period */ + uint8_t odhpp; /* Open-Drain high period */ + uint8_t odbaud; /* Open-Drain low period */ +}; + +/* Recommended I3C timing values are based on MCLKD 45 MHz */ +static const struct npcx_i3c_timing_cfg npcx_def_speed_cfg[] = { + /* PP = 12.5 mhz, OD = 4.17 Mhz */ + [NPCX_I3C_BUS_SPEED_45MHZ] = {.ppbaud = 1, .pplow = 0, .odhpp = 1, .odbaud = 4}, +}; + +struct npcx_i3c_config { + /* Common I3C Driver Config */ + struct i3c_driver_config common; + + /* Pointer to controller registers. */ + struct i3c_reg *base; + + /* Pointer to the clock device. */ + const struct device *clock_dev; + + /* Reset controller */ + struct reset_dt_spec reset; + + /* Clock control subsys related struct. */ + struct npcx_clk_cfg clock_subsys; + + /* Reference clock to determine 1 Ī¼s bus available time */ + struct npcx_clk_cfg ref_clk_subsys; + + /* Pointer to pin control device. */ + const struct pinctrl_dev_config *pincfg; + + /* Interrupt configuration function. */ + void (*irq_config_func)(const struct device *dev); + + struct { + uint32_t i3c_pp_scl_hz; /* I3C push pull clock frequency in Hz. */ + uint32_t i3c_od_scl_hz; /* I3C open drain clock frequency in Hz. */ + } clocks; + +#ifdef CONFIG_I3C_NPCX_DMA + struct npcx_clk_cfg mdma_clk_subsys; + struct mdma_reg *mdma_base; +#endif +}; + +struct npcx_i3c_data { + struct i3c_driver_data common; /* Common i3c driver data */ + struct k_mutex lock_mutex; /* Mutex of i3c controller */ + struct k_sem sync_sem; /* Semaphore used for synchronization */ + struct k_sem ibi_lock_sem; /* Semaphore used for ibi */ + enum npcx_i3c_oper_state oper_state; /* controller operation state */ + +#ifdef CONFIG_I3C_USE_IBI + struct { + /* List of addresses used in the MIBIRULES register. */ + uint8_t addr[5]; + + /* Number of valid addresses in MIBIRULES. */ + uint8_t num_addr; + + /* True if all addresses have MSB set. */ + bool msb; + + /* + * True if all target devices require mandatory byte + * for IBI. + */ + bool has_mandatory_byte; + } ibi; +#endif +}; + +static void npcx_i3c_mutex_lock(const struct device *dev) +{ + struct npcx_i3c_data *const data = dev->data; + + k_mutex_lock(&data->lock_mutex, K_FOREVER); +} + +static void npcx_i3c_mutex_unlock(const struct device *dev) +{ + struct npcx_i3c_data *const data = dev->data; + + k_mutex_unlock(&data->lock_mutex); +} + +#ifdef CONFIG_I3C_NPCX_DMA +static void i3c_ctrl_notify(const struct device *dev) +{ + struct npcx_i3c_data *const data = dev->data; + + k_sem_give(&data->sync_sem); +} + +static int i3c_ctrl_wait_completion(const struct device *dev) +{ + struct npcx_i3c_data *const data = dev->data; + + return k_sem_take(&data->sync_sem, I3C_TRANS_TIMEOUT_MS); +} + +static enum npcx_i3c_oper_state get_oper_state(const struct device *dev) +{ + struct npcx_i3c_data *const data = dev->data; + + return data->oper_state; +} +#endif /* CONFIG_I3C_NPCX_DMA */ + +static void set_oper_state(const struct device *dev, enum npcx_i3c_oper_state state) +{ + struct npcx_i3c_data *const data = dev->data; + + data->oper_state = state; +} + +/* + * brief: Wait for status bit done and clear the status + * + * param[in] inst Pointer to I3C register. + * + * return 0, success + * -ETIMEDOUT: check status timeout. + */ +static inline int npcx_i3c_status_wait_clear(struct i3c_reg *inst, uint8_t bit_offset) +{ + if (WAIT_FOR(IS_BIT_SET(inst->MSTATUS, bit_offset), NPCX_I3C_CHK_TIMEOUT_US, NULL) == + false) { + return -ETIMEDOUT; + } + + inst->MSTATUS = BIT(bit_offset); /* W1C */ + + return 0; +} + +static inline uint32_t npcx_i3c_state_get(struct i3c_reg *inst) +{ + return GET_FIELD(inst->MSTATUS, NPCX_I3C_MSTATUS_STATE); +} + +static inline void npcx_i3c_interrupt_all_disable(struct i3c_reg *inst) +{ + uint32_t intmask = inst->MINTSET; + + inst->MINTCLR = intmask; +} + +static inline void npcx_i3c_interrupt_enable(struct i3c_reg *inst, uint32_t mask) +{ + inst->MINTSET = mask; +} + +static bool npcx_i3c_has_error(struct i3c_reg *inst) +{ + if (IS_BIT_SET(inst->MSTATUS, NPCX_I3C_MSTATUS_ERRWARN)) { + LOG_WRN("ERROR: MSTATUS 0x%08x MERRWARN 0x%08x", inst->MSTATUS, inst->MERRWARN); + + return true; + } + + return false; +} + +static inline void npcx_i3c_status_clear_all(struct i3c_reg *inst) +{ + uint32_t mask = I3C_STATUS_CLR_MASK; + + inst->MSTATUS = mask; +} + +static inline void npcx_i3c_errwarn_clear_all(struct i3c_reg *inst) +{ + inst->MERRWARN = inst->MERRWARN; +} + +static inline void npcx_i3c_fifo_flush(struct i3c_reg *inst) +{ + inst->MDATACTRL |= (BIT(NPCX_I3C_MDATACTRL_FLUSHTB) | BIT(NPCX_I3C_MDATACTRL_FLUSHFB)); +} + +/* + * brief: Send request and check the request is valid + * + * param[in] inst Pointer to I3C register. + * + * return 0, success + * -ETIMEDOUT check MCTRLDONE timeout. + * -ENOSYS invalid use of request. + */ +static inline int npcx_i3c_send_request(struct i3c_reg *inst, uint32_t mctrl_val) +{ + inst->MCTRL = mctrl_val; + + if (npcx_i3c_status_wait_clear(inst, NPCX_I3C_MSTATUS_MCTRLDONE) != 0) { + return -ETIMEDOUT; + } + + /* Check invalid use of request */ + if (IS_BIT_SET(inst->MERRWARN, NPCX_I3C_MERRWARN_INVERQ)) { + LOG_ERR("%s: Invalid request, merrwarn: %#x", __func__, inst->MERRWARN); + return -ENOSYS; + } + + return 0; +} + +/* Start DAA procedure and continue the DAA with a Repeated START */ +static inline int npcx_i3c_request_daa(struct i3c_reg *inst) +{ + uint32_t val = 0; + int ret; + + /* Set IBI response NACK while processing DAA */ + SET_FIELD(val, NPCX_I3C_MCTRL_IBIRESP, MCTRL_IBIRESP_NACK); + + /* Send DAA request */ + SET_FIELD(val, NPCX_I3C_MCTRL_REQUEST, MCTRL_REQUEST_PROCESSDAA); + + ret = npcx_i3c_send_request(inst, val); + if (ret != 0) { + LOG_ERR("Request DAA error, %d", ret); + return ret; + } + + return 0; +} + +/* Tell controller to start auto IBI */ +static inline int npcx_i3c_request_auto_ibi(struct i3c_reg *inst) +{ + uint32_t val = 0; + int ret; + + SET_FIELD(val, NPCX_I3C_MCTRL_IBIRESP, MCTRL_IBIRESP_ACK); + SET_FIELD(val, NPCX_I3C_MCTRL_REQUEST, MCTRL_REQUEST_AUTOIBI); + + ret = npcx_i3c_send_request(inst, val); + if (ret != 0) { + LOG_ERR("Request auto ibi error, %d", ret); + return ret; + } + + return 0; +} + +/* + * brief: Controller emit start and send address + * + * param[in] inst Pointer to I3C register. + * param[in] addr Dyamic address for xfer or 0x7E for CCC command. + * param[in] op_type Request type. + * param[in] is_read Read(true) or write(false) operation. + * param[in] read_sz Read size. + * + * return 0, success + * else, error + */ +static int npcx_i3c_request_emit_start(struct i3c_reg *inst, uint8_t addr, + enum npcx_i3c_mctrl_type op_type, bool is_read, + size_t read_sz) +{ + uint32_t mctrl = 0; + int ret; + + /* Set request and target address*/ + SET_FIELD(mctrl, NPCX_I3C_MCTRL_REQUEST, MCTRL_REQUEST_EMITSTARTADDR); + + /* Set operation type */ + SET_FIELD(mctrl, NPCX_I3C_MCTRL_TYPE, op_type); + + /* Set IBI response NACK in emit start */ + SET_FIELD(mctrl, NPCX_I3C_MCTRL_IBIRESP, MCTRL_IBIRESP_NACK); + + /* Set dynamic address */ + SET_FIELD(mctrl, NPCX_I3C_MCTRL_ADDR, addr); + + /* Set read(1) or write(0) */ + if (is_read) { + mctrl |= BIT(NPCX_I3C_MCTRL_DIR); + SET_FIELD(mctrl, NPCX_I3C_MCTRL_RDTERM, read_sz); /* Set read length */ + } else { + mctrl &= ~BIT(NPCX_I3C_MCTRL_DIR); + } + + ret = npcx_i3c_send_request(inst, mctrl); + if (ret != 0) { + LOG_ERR("Request start error, %d", ret); + return ret; + } + + /* Check NACK after MCTRLDONE is get */ + if (IS_BIT_SET(inst->MERRWARN, NPCX_I3C_MERRWARN_NACK)) { + LOG_DBG("%s: nack", __func__); + return -ENODEV; + } + + return 0; +} + +/* + * brief: Controller emit STOP. + * + * This emits STOP when controller is in NORMACT state. + * + * param[in] inst Pointer to I3C register. + * + * return 0 success + * -ECANCELED i3c state not as expected. + * -ETIMEDOUT check MCTRLDONE timeout. + * -ENOSYS invalid use of request. + */ +static inline int npcx_i3c_request_emit_stop(struct i3c_reg *inst) +{ + uint32_t val = 0; + int ret; + uint32_t i3c_state = npcx_i3c_state_get(inst); + + /* Make sure we are in a state where we can emit STOP */ + if ((i3c_state != MSTATUS_STATE_NORMACT) && (i3c_state != MSTATUS_STATE_DAA)) { + LOG_ERR("Request stop state error, state= %#x", i3c_state); + return -ECANCELED; + } + + SET_FIELD(val, NPCX_I3C_MCTRL_REQUEST, MCTRL_REQUEST_EMITSTOP); + + ret = npcx_i3c_send_request(inst, val); + if (ret != 0) { + LOG_ERR("Request stop error, %d", ret); + return ret; + } + + return 0; +} + +static inline int npcx_i3c_ibi_respond_nack(struct i3c_reg *inst) +{ + uint32_t val = 0; + int ret; + + SET_FIELD(val, NPCX_I3C_MCTRL_IBIRESP, MCTRL_IBIRESP_NACK); + SET_FIELD(val, NPCX_I3C_MCTRL_REQUEST, MCTRL_REQUEST_IBIACKNACK); + + ret = npcx_i3c_send_request(inst, val); + if (ret != 0) { + LOG_ERR("Request ibi_rsp nack error, %d", ret); + return ret; + } + + return 0; +} + +static inline int npcx_i3c_ibi_respond_ack(struct i3c_reg *inst) +{ + uint32_t val = 0; + int ret; + + SET_FIELD(val, NPCX_I3C_MCTRL_IBIRESP, MCTRL_IBIRESP_ACK); + SET_FIELD(val, NPCX_I3C_MCTRL_REQUEST, MCTRL_REQUEST_IBIACKNACK); + + ret = npcx_i3c_send_request(inst, val); + if (ret != 0) { + LOG_ERR("Request ibi_rsp ack error %d", ret); + return ret; + } + + return 0; +} + +/* + * brief: Find a registered I3C target device. + * + * This returns the I3C device descriptor of the I3C device + * matching the incoming id. + * + * param[in] dev Pointer to controller device driver instance. + * param[in] id Pointer to I3C device ID. + * + * return see i3c_device_find. + */ +static inline struct i3c_device_desc *npcx_i3c_device_find(const struct device *dev, + const struct i3c_device_id *id) +{ + const struct npcx_i3c_config *config = dev->config; + + return i3c_dev_list_find(&config->common.dev_list, id); +} + +/* + * brief: Perform bus recovery. + * + * param[in] dev Pointer to controller device driver instance. + * + * return 0 success, otherwise error + */ +static int npcx_i3c_recover_bus(const struct device *dev) +{ + const struct npcx_i3c_config *config = dev->config; + struct i3c_reg *inst = config->base; + + /* + * If the controller is in NORMACT state, tells it to emit STOP + * so it can return to IDLE, or is ready to clear any pending + * target initiated IBIs. + */ + if (npcx_i3c_state_get(inst) == MSTATUS_STATE_NORMACT) { + npcx_i3c_request_emit_stop(inst); + }; + + /* Exhaust all target initiated IBI */ + while (IS_BIT_SET(inst->MSTATUS, NPCX_I3C_MSTATUS_TGTSTART)) { + /* Tell the controller to perform auto IBI. */ + npcx_i3c_request_auto_ibi(inst); + + if (WAIT_FOR(IS_BIT_SET(inst->MSTATUS, NPCX_I3C_MSTATUS_COMPLETE), + NPCX_I3C_CHK_TIMEOUT_US, NULL) == false) { + break; + } + + /* Once auto IBI is done, discard bytes in FIFO. */ + while (IS_BIT_SET(inst->MSTATUS, NPCX_I3C_MSTATUS_RXPEND)) { + /* Flush FIFO as long as RXPEND is set. */ + npcx_i3c_fifo_flush(inst); + } + + /* + * There might be other IBIs waiting. + * So pause a bit to let other targets initiates + * their IBIs. + */ + k_busy_wait(100); + } + + /* Check IDLE state */ + if (WAIT_FOR((npcx_i3c_state_get(inst) == MSTATUS_STATE_IDLE), NPCX_I3C_CHK_TIMEOUT_US, + NULL) == false) { + return -EBUSY; + } + + return 0; +} + +static inline void npcx_i3c_xfer_reset(struct i3c_reg *inst) +{ + npcx_i3c_status_clear_all(inst); + npcx_i3c_errwarn_clear_all(inst); + npcx_i3c_fifo_flush(inst); +} + +/* + * brief: Perform one write transaction. + * + * This writes all data in buf to TX FIFO or time out + * waiting for FIFO spaces. + * + * param[in] inst Pointer to controller registers. + * param[in] buf Buffer containing data to be sent. + * param[in] buf_sz Number of bytes in buf to send. + * param[in] no_ending True, not including ending byte in message. + * False, including ending byte in message + * + * return Number of bytes written, or negative if error. + * + */ +static int npcx_i3c_xfer_write_fifo(struct i3c_reg *inst, uint8_t *buf, uint8_t buf_sz, + bool no_ending) +{ + int offset = 0; + int remaining = buf_sz; + + while (remaining > 0) { + /* Check tx fifo not full */ + if (WAIT_FOR(!IS_BIT_SET(inst->MDATACTRL, NPCX_I3C_MDATACTRL_TXFULL), + NPCX_I3C_CHK_TIMEOUT_US, NULL) == false) { + LOG_DBG("%s: Check tx fifo not full timed out", __func__); + return -ETIMEDOUT; + } + + if ((remaining > 1) || no_ending) { + inst->MWDATAB = (uint32_t)buf[offset]; + } else { + inst->MWDATABE = (uint32_t)buf[offset]; /* Set last byte */ + } + + offset += 1; + remaining -= 1; + } + + return offset; +} + +/* + * brief: Perform read transaction. + * + * This reads from RX FIFO until COMPLETE bit is set in MSTATUS + * or time out. + * + * param[in] inst Pointer to controller registers. + * param[in] buf Buffer to store data. + * param[in] buf_sz Number of bytes to read. + * + * return Number of bytes read, or negative if error. + * + */ +static int npcx_i3c_xfer_read_fifo(struct i3c_reg *inst, uint8_t *buf, uint8_t rd_sz) +{ + bool is_done = false; + int offset = 0; + + while (is_done == false) { + /* Check message is terminated */ + if (IS_BIT_SET(inst->MSTATUS, NPCX_I3C_MSTATUS_COMPLETE)) { + is_done = true; + } + + /* Check I3C bus error */ + if (npcx_i3c_has_error(inst)) { + /* Check timeout*/ + if (IS_BIT_SET(inst->MERRWARN, NPCX_I3C_MERRWARN_TIMEOUT)) { + LOG_WRN("%s: ERR: timeout", __func__); + } + + inst->MERRWARN = inst->MERRWARN; + + return -EIO; + } + + /* Check rx not empty */ + if (IS_BIT_SET(inst->MSTATUS, NPCX_I3C_MSTATUS_RXPEND)) { + + /* Receive all the data in this round. + * Read in a tight loop to reduce chance of losing + * FIFO data when the i3c speed is high. + */ + while (offset < rd_sz) { + if (GET_FIELD(inst->MDATACTRL, NPCX_I3C_MDATACTRL_RXCOUNT) == 0) { + break; + } + + buf[offset++] = (uint8_t)inst->MRDATAB; + } + } + } + + return offset; +} + +#ifdef CONFIG_I3C_NPCX_DMA +/* + * brief: Perform DMA write transaction. + * + * For write end, use the interrupt generated by COMPLETE bit in MSTATUS register. + * + * param[in] dev Pointer to controller device driver instance. + * param[in] buf Buffer to store data. + * param[in] buf_sz Number of bytes to read. + * + * return Number of bytes read, or negative if error. + * + */ +static int npcx_i3c_xfer_write_fifo_dma(const struct device *dev, uint8_t *buf, uint8_t buf_sz) +{ + const struct npcx_i3c_config *config = dev->config; + struct i3c_reg *i3c_inst = config->base; + struct mdma_reg *mdma_inst = config->mdma_base; + int ret; + + set_oper_state(dev, NPCX_I3C_WR); + + /* Enable I3C MDMA write for one frame */ + SET_FIELD(i3c_inst->MDMACTRL, NPCX_I3C_MDMACTRL_DMATB, MDMA_DMATB_EN_ONE_FRAME); + i3c_inst->MINTSET |= BIT(NPCX_I3C_MINTCLR_COMPLETE); /* Enable I3C complete interrupt */ + + /* Write Operation (MDMA CH_1) */ + mdma_inst->MDMA_TCNT1 = buf_sz; /* Set MDMA transfer count */ + mdma_inst->MDMA_SRCB1 = (uint32_t)buf; /* Set source address */ + mdma_inst->MDMA_CTL1 |= BIT(NPCX_MDMA_CTL_MDMAEN); /* Start DMA transfer */ + + /* Wait I3C COMPLETE */ + ret = i3c_ctrl_wait_completion(dev); + if (ret < 0) { + LOG_DBG("%s: Check complete time out, buf_size:%d", __func__, buf_sz); + goto out_wr_fifo_dma; + } + + /* Check and clear DMA TC after complete */ + if (!IS_BIT_SET(mdma_inst->MDMA_CTL1, NPCX_MDMA_CTL_TC)) { + LOG_DBG("%s: DMA busy, TC=%d", __func__, + IS_BIT_SET(mdma_inst->MDMA_CTL1, NPCX_MDMA_CTL_TC)); + ret = -EBUSY; + goto out_wr_fifo_dma; + } + + mdma_inst->MDMA_CTL1 &= ~BIT(NPCX_MDMA_CTL_TC); /* Clear TC, W0C */ + ret = buf_sz - mdma_inst->MDMA_CTCNT1; /* Set transferred count */ + LOG_DBG("Write cnt=%d", ret); + +out_wr_fifo_dma: + i3c_inst->MINTCLR |= BIT(NPCX_I3C_MINTCLR_COMPLETE); /* Disable I3C complete interrupt */ + npcx_i3c_fifo_flush(i3c_inst); + set_oper_state(dev, NPCX_I3C_IDLE); + + return ret; +} + +/* + * brief: Perform DMA read transaction. + * + * For read end, use the MDMA end-of-transfer interrupt(SIEN bit) + * instead of using the I3CI interrupt generated by COMPLETE bit in MSTATUS register. + * + * param[in] dev Pointer to controller device driver instance. + * param[in] buf Buffer to store data. + * param[in] buf_sz Number of bytes to read. + * + * return Number of bytes read, or negative if error. + * + */ +static int npcx_i3c_xfer_read_fifo_dma(const struct device *dev, uint8_t *buf, uint8_t buf_sz) +{ + const struct npcx_i3c_config *config = dev->config; + struct i3c_reg *i3c_inst = config->base; + struct mdma_reg *mdma_inst = config->mdma_base; + int ret; + + set_oper_state(dev, NPCX_I3C_RD); + + /* Enable DMA until DMA is disabled by setting DMAFB to 00 */ + SET_FIELD(i3c_inst->MDMACTRL, NPCX_I3C_MDMACTRL_DMAFB, MDMA_DMAFB_EN_MANUAL); + + /* Read Operation (MDMA CH_0) */ + mdma_inst->MDMA_TCNT0 = buf_sz; /* Set MDMA transfer count */ + mdma_inst->MDMA_DSTB0 = (uint32_t)buf; /* Set destination address */ + mdma_inst->MDMA_CTL0 |= BIT(NPCX_MDMA_CTL_SIEN); /* Enable stop interrupt */ + mdma_inst->MDMA_CTL0 |= BIT(NPCX_MDMA_CTL_MDMAEN); /* Start DMA transfer */ + + /* Wait MDMA TC */ + ret = i3c_ctrl_wait_completion(dev); + if (ret < 0) { + LOG_DBG("%s: Check DMA done time out", __func__); + } else { + ret = buf_sz - mdma_inst->MDMA_CTCNT0; /* Set transferred count */ + LOG_DBG("Read cnt=%d", ret); + } + + mdma_inst->MDMA_CTL0 &= ~BIT(NPCX_MDMA_CTL_SIEN); /* Disable stop interrupt */ + /* Disable I3C MDMA read */ + SET_FIELD(i3c_inst->MDMACTRL, NPCX_I3C_MDMACTRL_DMAFB, MDMA_DMAFB_DISABLE); + npcx_i3c_fifo_flush(i3c_inst); + set_oper_state(dev, NPCX_I3C_IDLE); + + return ret; +} + +/* + * brief: Perform one transfer transaction by DMA. + * + * param[in] inst Pointer to controller registers. + * param[in] addr Target address. + * param[in] op_type Request type. + * param[in] buf Buffer for data to be sent or received. + * param[in] buf_sz Buffer size in bytes. + * param[in] is_read True if this is a read transaction, false if write. + * param[in] emit_start True if START is needed before read/write. + * param[in] emit_stop True if STOP is needed after read/write. + * + * return Number of bytes read/written, or negative if error. + */ +static int npcx_i3c_do_one_xfer_dma(const struct device *dev, uint8_t addr, + enum npcx_i3c_mctrl_type op_type, uint8_t *buf, size_t buf_sz, + bool is_read, bool emit_start, bool emit_stop) +{ + const struct npcx_i3c_config *config = dev->config; + struct i3c_reg *inst = config->base; + int ret = 0; + + npcx_i3c_status_clear_all(inst); + npcx_i3c_errwarn_clear_all(inst); + + /* Emit START if needed */ + if (emit_start) { + ret = npcx_i3c_request_emit_start(inst, addr, op_type, is_read, buf_sz); + if (ret != 0) { + LOG_ERR("%s: emit start fail", __func__); + goto out_do_one_xfer_dma; + } + } + + /* No data to be transferred */ + if ((buf == NULL) || (buf_sz == 0)) { + goto out_do_one_xfer_dma; + } + + /* Select read or write operation */ + if (is_read) { + ret = npcx_i3c_xfer_read_fifo_dma(dev, buf, buf_sz); + } else { + ret = npcx_i3c_xfer_write_fifo_dma(dev, buf, buf_sz); + } + + if (ret < 0) { + LOG_ERR("%s: %s fifo fail", __func__, is_read ? "read" : "write"); + goto out_do_one_xfer_dma; + } + + /* Check I3C bus error */ + if (npcx_i3c_has_error(inst)) { + ret = -EIO; + LOG_ERR("%s: I3C bus error", __func__); + } + +out_do_one_xfer_dma: + /* Emit STOP if needed */ + if (emit_stop) { + npcx_i3c_request_emit_stop(inst); + } + + return ret; +} +#endif /* End of CONFIG_I3C_NPCX_DMA */ + +/* + * brief: Perform one transfer transaction. + * + * param[in] inst Pointer to controller registers. + * param[in] addr Target address. + * param[in] op_type Request type. + * param[in] buf Buffer for data to be sent or received. + * param[in] buf_sz Buffer size in bytes. + * param[in] is_read True if this is a read transaction, false if write. + * param[in] emit_start True if START is needed before read/write. + * param[in] emit_stop True if STOP is needed after read/write. + * param[in] no_ending True if not to signal end of write message. + * + * return Number of bytes read/written, or negative if error. + */ +static int npcx_i3c_do_one_xfer(struct i3c_reg *inst, uint8_t addr, + enum npcx_i3c_mctrl_type op_type, uint8_t *buf, size_t buf_sz, + bool is_read, bool emit_start, bool emit_stop, bool no_ending) +{ + int ret = 0; + + npcx_i3c_status_clear_all(inst); + npcx_i3c_errwarn_clear_all(inst); + + /* Emit START if needed */ + if (emit_start) { + ret = npcx_i3c_request_emit_start(inst, addr, op_type, is_read, buf_sz); + if (ret != 0) { + LOG_ERR("%s: emit start fail", __func__); + goto out_do_one_xfer; + } + } + + /* No data to be transferred */ + if ((buf == NULL) || (buf_sz == 0)) { + goto out_do_one_xfer; + } + + /* Select read or write operation */ + if (is_read) { + ret = npcx_i3c_xfer_read_fifo(inst, buf, buf_sz); + } else { + ret = npcx_i3c_xfer_write_fifo(inst, buf, buf_sz, no_ending); + } + + if (ret < 0) { + LOG_ERR("%s: %s fifo fail", __func__, is_read ? "read" : "write"); + goto out_do_one_xfer; + } + + /* Check message complete if is a read transaction or + * ending byte of a write transaction. + */ + if (is_read || !no_ending) { + /* Wait message transfer complete */ + if (WAIT_FOR(IS_BIT_SET(inst->MSTATUS, NPCX_I3C_MSTATUS_COMPLETE), + NPCX_I3C_CHK_TIMEOUT_US, NULL) == false) { + LOG_DBG("%s: timed out addr 0x%02x, buf_sz %u", __func__, addr, buf_sz); + + ret = -ETIMEDOUT; + emit_stop = true; + + goto out_do_one_xfer; + } + + inst->MSTATUS = BIT(NPCX_I3C_MSTATUS_COMPLETE); /* W1C */ + } + + /* Check I3C bus error */ + if (npcx_i3c_has_error(inst)) { + ret = -EIO; + LOG_ERR("%s: I3C bus error", __func__); + } + +out_do_one_xfer: + /* Emit STOP if needed */ + if (emit_stop) { + npcx_i3c_request_emit_stop(inst); + } + + return ret; +} + +/* + * brief: Transfer messages in I3C mode. + * + * see i3c_transfer + * + * param[in] dev Pointer to device driver instance. + * param[in] target Pointer to target device descriptor. + * param[in] msgs Pointer to I3C messages. + * param[in] num_msgs Number of messages to transfers. + * + * return see i3c_transfer + */ +static int npcx_i3c_transfer(const struct device *dev, struct i3c_device_desc *target, + struct i3c_msg *msgs, uint8_t num_msgs) +{ + const struct npcx_i3c_config *config = dev->config; + struct i3c_reg *inst = config->base; + uint32_t intmask; + int xfered_len, ret = 0; + bool send_broadcast = true; + bool is_xfer_done = true; + + if (msgs == NULL) { + return -EINVAL; + } + + if (target->dynamic_addr == 0U) { + return -EINVAL; + } + + npcx_i3c_mutex_lock(dev); + + /* Check bus in idle state */ + if (WAIT_FOR((npcx_i3c_state_get(inst) == MSTATUS_STATE_IDLE), NPCX_I3C_CHK_TIMEOUT_US, + NULL) == false) { + LOG_ERR("%s: xfer state error: %d", __func__, npcx_i3c_state_get(inst)); + npcx_i3c_mutex_unlock(dev); + return -ETIMEDOUT; + } + + /* Disable interrupt */ + intmask = inst->MINTSET; + npcx_i3c_interrupt_all_disable(inst); + + npcx_i3c_xfer_reset(inst); + + /* Iterate over all the messages */ + for (int i = 0; i < num_msgs; i++) { + + /* + * Check message is read or write operaion. + * For write operation, check the last data byte of a transmit message. + */ + bool is_read = (msgs[i].flags & I3C_MSG_RW_MASK) == I3C_MSG_READ; + bool no_ending = false; + + /* + * Emit start if this is the first message or that + * the RESTART flag is set in message. + */ + bool emit_start = + (i == 0) || ((msgs[i].flags & I3C_MSG_RESTART) == I3C_MSG_RESTART); + + bool emit_stop = (msgs[i].flags & I3C_MSG_STOP) == I3C_MSG_STOP; + + /* + * The controller requires special treatment of last byte of + * a write message. Since the API permits having a bunch of + * write messages without RESTART in between, this is just some + * logic to determine whether to treat the last byte of this + * message to be the last byte of a series of write mssages. + * If not, tell the write function not to treat it that way. + */ + if (!is_read && !emit_stop && ((i + 1) != num_msgs)) { + bool next_is_write = (msgs[i + 1].flags & I3C_MSG_RW_MASK) == I3C_MSG_WRITE; + bool next_is_restart = + ((msgs[i + 1].flags & I3C_MSG_RESTART) == I3C_MSG_RESTART); + + /* Check next msg is still write operation and not including Sr */ + if (next_is_write && !next_is_restart) { + no_ending = true; + } + } + +#ifdef CONFIG_I3C_NPCX_DMA + /* Current DMA not support multi-message write */ + if (!is_read && no_ending) { + LOG_ERR("I3C DMA transfer not support multi-message write"); + ret = -EINVAL; + break; + } +#endif + + /* + * Two ways to do read/write transfer . + * 1. [S] + [0x7E] + [address] + [data] + [Sr or P] + * 2. [S] + [address] + [data] + [Sr or P] + * + * Send broadcast header(0x7E) on first transfer or after a STOP, + * unless flag is set not to. + */ + if (!(msgs[i].flags & I3C_MSG_NBCH) && (send_broadcast)) { + ret = npcx_i3c_request_emit_start(inst, I3C_BROADCAST_ADDR, + NPCX_I3C_MCTRL_TYPE_I3C, false, 0); + if (ret < 0) { + LOG_ERR("%s: emit start of broadcast addr failed, error (%d)", + __func__, ret); + break; + } + send_broadcast = false; + } + +#ifdef CONFIG_I3C_NPCX_DMA + /* Do transfer with target device */ + xfered_len = npcx_i3c_do_one_xfer_dma(dev, target->dynamic_addr, + NPCX_I3C_MCTRL_TYPE_I3C, msgs[i].buf, + msgs[i].len, is_read, emit_start, emit_stop); +#else + xfered_len = npcx_i3c_do_one_xfer(inst, target->dynamic_addr, + NPCX_I3C_MCTRL_TYPE_I3C, msgs[i].buf, msgs[i].len, + is_read, emit_start, emit_stop, no_ending); +#endif + if (xfered_len < 0) { + LOG_ERR("%s: do xfer fail", __func__); + ret = xfered_len; /* Set error code to ret */ + break; + } + + /* Write back the total number of bytes transferred */ + msgs[i].num_xfer = xfered_len; + + if (emit_stop) { + /* After a STOP, send broadcast header before next msg */ + send_broadcast = true; + } + + /* Check emit stop flag including in the final msg */ + if ((i == num_msgs - 1) && (emit_stop == false)) { + is_xfer_done = false; + } + } + + /* Emit stop if error occurs or stop flag not in the msg */ + if ((ret != 0) || (is_xfer_done == false)) { + npcx_i3c_request_emit_stop(inst); + } + + npcx_i3c_errwarn_clear_all(inst); + npcx_i3c_status_clear_all(inst); + + npcx_i3c_interrupt_enable(inst, intmask); + + npcx_i3c_mutex_unlock(dev); + + return ret; +} + +/* + * brief: Perform Dynamic Address Assignment. + * + * param[in] dev Pointer to controller device driver instance. + * + * return 0 If successful. + * -EBUSY Bus is busy. + * -EIO General input / output error. + * -ENODEV If a provisioned ID does not match to any target devices + * in the registered device list. + * -ENOSPC No more free addresses can be assigned to target. + * -ENOSYS Dynamic address assignment is not supported by + * the controller driver. + */ +static int npcx_i3c_do_daa(const struct device *dev) +{ + const struct npcx_i3c_config *config = dev->config; + struct npcx_i3c_data *data = dev->data; + struct i3c_reg *inst = config->base; + int ret = 0; + uint8_t rx_buf[8]; + size_t rx_count; + uint32_t intmask; + + npcx_i3c_mutex_lock(dev); + + memset(rx_buf, 0xff, sizeof(rx_buf)); + + /* Check bus in idle state */ + if (WAIT_FOR((npcx_i3c_state_get(inst) == MSTATUS_STATE_IDLE), NPCX_I3C_CHK_TIMEOUT_US, + NULL) == false) { + LOG_ERR("%s: DAA state error: %d", __func__, npcx_i3c_state_get(inst)); + npcx_i3c_mutex_unlock(dev); + return -ETIMEDOUT; + } + + LOG_DBG("DAA: ENTDAA"); + + /* Disable interrupt */ + intmask = inst->MINTSET; + npcx_i3c_interrupt_all_disable(inst); + + npcx_i3c_xfer_reset(inst); + + /* Emit process DAA */ + if (npcx_i3c_request_daa(inst) != 0) { + ret = -ETIMEDOUT; + LOG_ERR("Emit process DAA error"); + goto out_do_daa; + } + + /* Loop until no more responses from devices */ + do { + /* Check ERRWARN bit set */ + if (npcx_i3c_has_error(inst)) { + ret = -EIO; + LOG_ERR("DAA recv error"); + break; + } + + /* Receive Provisioned ID, BCR and DCR (total 8 bytes) */ + rx_count = GET_FIELD(inst->MDATACTRL, NPCX_I3C_MDATACTRL_RXCOUNT); + + if (rx_count == DAA_TGT_INFO_SZ) { + for (int i = 0; i < rx_count; i++) { + rx_buf[i] = (uint8_t)inst->MRDATAB; + } + } else { + /* Data count not as expected, exit DAA */ + ret = -EBADMSG; + LOG_DBG("Rx count not as expected %d, abort DAA", rx_count); + break; + } + + /* Start assign dynamic address */ + if ((npcx_i3c_state_get(inst) == MSTATUS_STATE_DAA) && + IS_BIT_SET(inst->MSTATUS, NPCX_I3C_MSTATUS_BETWEEN)) { + struct i3c_device_desc *target; + uint16_t vendor_id; + uint32_t part_no; + uint64_t pid; + uint8_t dyn_addr = 0; + + /* PID[47:33] = manufacturer ID */ + vendor_id = (((uint16_t)rx_buf[0] << 8U) | (uint16_t)rx_buf[1]) & 0xFFFEU; + + /* PID[31:0] = vendor fixed falue or random value */ + part_no = (uint32_t)rx_buf[2] << 24U | (uint32_t)rx_buf[3] << 16U | + (uint32_t)rx_buf[4] << 8U | (uint32_t)rx_buf[5]; + + /* Combine into one Provisioned ID */ + pid = (uint64_t)vendor_id << 32U | (uint64_t)part_no; + + LOG_DBG("DAA: Rcvd PID 0x%04x%08x", vendor_id, part_no); + + /* Find a usable address during ENTDAA */ + ret = i3c_dev_list_daa_addr_helper(&data->common.attached_dev.addr_slots, + &config->common.dev_list, pid, false, + false, &target, &dyn_addr); + if (ret != 0) { + LOG_ERR("%s: Assign new DA error", __func__); + break; + } + + if (target == NULL) { + LOG_INF("%s: PID 0x%04x%08x is not in registered device " + "list, given dynamic address 0x%02x", + dev->name, vendor_id, part_no, dyn_addr); + } else { + /* Update target descriptor */ + target->dynamic_addr = dyn_addr; + target->bcr = rx_buf[6]; + target->dcr = rx_buf[7]; + } + + /* Mark the address as I3C device */ + i3c_addr_slots_mark_i3c(&data->common.attached_dev.addr_slots, dyn_addr); + + /* + * If the device has static address, after address assignment, + * the device will not respond to the static address anymore. + * So free the static one from address slots if different from + * newly assigned one. + */ + if ((target != NULL) && (target->static_addr != 0U) && + (dyn_addr != target->static_addr)) { + i3c_addr_slots_mark_free(&data->common.attached_dev.addr_slots, + dyn_addr); + } + + /* Emit process DAA again to send the address to the device */ + inst->MWDATAB = dyn_addr; + ret = npcx_i3c_request_daa(inst); + if (ret != 0) { + LOG_ERR("%s: Assign DA timeout", __func__); + break; + } + + LOG_DBG("PID 0x%04x%08x assigned dynamic address 0x%02x", vendor_id, + part_no, dyn_addr); + + /* Target did not accept the assigned DA, exit DAA */ + if (IS_BIT_SET(inst->MSTATUS, NPCX_I3C_MSTATUS_NACKED)) { + ret = -EFAULT; + LOG_DBG("TGT NACK assigned DA %#x", dyn_addr); + + /* Free the reserved DA */ + i3c_addr_slots_mark_free(&data->common.attached_dev.addr_slots, + dyn_addr); + + /* 0 if address has not been assigned */ + if (target != NULL) { + target->dynamic_addr = 0; + } + + break; + } + } + + /* Check all targets have been assigned DA and DAA complete */ + } while ((!IS_BIT_SET(inst->MSTATUS, NPCX_I3C_MSTATUS_COMPLETE)) && + npcx_i3c_state_get(inst) != MSTATUS_STATE_IDLE); + +out_do_daa: + /* Exit DAA mode when error occurs */ + if (ret != 0) { + npcx_i3c_request_emit_stop(inst); + } + + /* Clear all flags. */ + npcx_i3c_errwarn_clear_all(inst); + npcx_i3c_status_clear_all(inst); + + /* Re-Enable I3C IRQ sources. */ + npcx_i3c_interrupt_enable(inst, intmask); + + npcx_i3c_fifo_flush(inst); + npcx_i3c_mutex_unlock(dev); + + return ret; +} + +/* + * brief: Send Common Command Code (CCC). + * + * param[in] dev Pointer to controller device driver instance. + * param[in] payload Pointer to CCC payload. + * + * return: The same as i3c_do_ccc() + * 0 If successful. + * -EBUSY Bus is busy. + * -EIO General Input / output error. + * -EINVAL Invalid valid set in the payload structure. + * -ENOSYS Not implemented. + */ +static int npcx_i3c_do_ccc(const struct device *dev, struct i3c_ccc_payload *payload) +{ + const struct npcx_i3c_config *config = dev->config; + int ret; + struct i3c_reg *inst = config->base; + uint32_t intmask; + int xfered_len; + + if (dev == NULL || payload == NULL) { + return -EINVAL; + } + + npcx_i3c_mutex_lock(dev); + + /* Disable interrupt */ + intmask = inst->MINTSET; + npcx_i3c_interrupt_all_disable(inst); + + /* Clear status and flush fifo */ + npcx_i3c_xfer_reset(inst); + + LOG_DBG("CCC[0x%02x]", payload->ccc.id); + + /* Write emit START and broadcast address (0x7E) */ + ret = npcx_i3c_request_emit_start(inst, I3C_BROADCAST_ADDR, NPCX_I3C_MCTRL_TYPE_I3C, false, + 0); + if (ret < 0) { + LOG_ERR("CCC[0x%02x] %s START error (%d)", payload->ccc.id, + i3c_ccc_is_payload_broadcast(payload) ? "broadcast" : "direct", ret); + + goto out_do_ccc; + } + + /* Write CCC command */ + npcx_i3c_status_clear_all(inst); + npcx_i3c_errwarn_clear_all(inst); + xfered_len = npcx_i3c_xfer_write_fifo(inst, &payload->ccc.id, 1, payload->ccc.data_len > 0); + if (xfered_len < 0) { + LOG_ERR("CCC[0x%02x] %s command error (%d)", payload->ccc.id, + i3c_ccc_is_payload_broadcast(payload) ? "broadcast" : "direct", ret); + ret = xfered_len; + + goto out_do_ccc; + } + + /* Write data (defining byte or data bytes) for CCC if needed */ + if (payload->ccc.data_len > 0) { + npcx_i3c_status_clear_all(inst); + npcx_i3c_errwarn_clear_all(inst); + xfered_len = npcx_i3c_xfer_write_fifo(inst, payload->ccc.data, + payload->ccc.data_len, false); + if (xfered_len < 0) { + LOG_ERR("CCC[0x%02x] %s command payload error (%d)", payload->ccc.id, + i3c_ccc_is_payload_broadcast(payload) ? "broadcast" : "direct", + ret); + ret = xfered_len; + + goto out_do_ccc; + } + + /* Write back the transferred bytes */ + payload->ccc.num_xfer = xfered_len; + } + + /* Wait message transfer complete */ + if (WAIT_FOR(IS_BIT_SET(inst->MSTATUS, NPCX_I3C_MSTATUS_COMPLETE), NPCX_I3C_CHK_TIMEOUT_US, + NULL) == false) { + ret = -ETIMEDOUT; + LOG_DBG("Check complete timeout"); + goto out_do_ccc; + } + + inst->MSTATUS = BIT(NPCX_I3C_MSTATUS_COMPLETE); /* W1C */ + + /* For direct CCC */ + if (!i3c_ccc_is_payload_broadcast(payload)) { + /* + * If there are payload(s) for each target, + * RESTART and then send payload for each target. + */ + for (int idx = 0; idx < payload->targets.num_targets; idx++) { + struct i3c_ccc_target_payload *tgt_payload = + &payload->targets.payloads[idx]; + + bool is_read = (tgt_payload->rnw == 1U); + + xfered_len = npcx_i3c_do_one_xfer( + inst, tgt_payload->addr, NPCX_I3C_MCTRL_TYPE_I3C, tgt_payload->data, + tgt_payload->data_len, is_read, true, false, false); + if (xfered_len < 0) { + LOG_ERR("CCC[0x%02x] target payload error (%d)", payload->ccc.id, + ret); + ret = xfered_len; + + goto out_do_ccc; + } + + /* Write back the total number of bytes transferred */ + tgt_payload->num_xfer = xfered_len; + } + } + +out_do_ccc: + npcx_i3c_request_emit_stop(inst); + + npcx_i3c_interrupt_enable(inst, intmask); + + npcx_i3c_mutex_unlock(dev); + + return ret; +} + +#ifdef CONFIG_I3C_USE_IBI +/* + * brief Callback to service target initiated IBIs in workqueue. + * + * param[in] work Pointer to k_work item. + */ +static void npcx_i3c_ibi_work(struct k_work *work) +{ + uint8_t payload[CONFIG_I3C_IBI_MAX_PAYLOAD_SIZE]; + size_t payload_sz = 0; + + struct i3c_ibi_work *i3c_ibi_work = CONTAINER_OF(work, struct i3c_ibi_work, work); + const struct device *dev = i3c_ibi_work->controller; + const struct npcx_i3c_config *config = dev->config; + struct npcx_i3c_data *data = dev->data; + struct i3c_dev_attached_list *dev_list = &data->common.attached_dev; + struct i3c_reg *inst = config->base; + struct i3c_device_desc *target = NULL; + uint32_t ibitype, ibiaddr; + int ret; + + k_sem_take(&data->ibi_lock_sem, K_FOREVER); + + if (npcx_i3c_state_get(inst) != MSTATUS_STATE_TGTREQ) { + LOG_DBG("IBI work %p running not because of IBI", work); + LOG_ERR("%s: MSTATUS 0x%08x MERRWARN 0x%08x", __func__, inst->MSTATUS, + inst->MERRWARN); + + npcx_i3c_request_emit_stop(inst); + + goto out_ibi_work; + }; + + /* Use auto IBI to service the IBI */ + npcx_i3c_request_auto_ibi(inst); + + /* Wait for target to win address arbitration (ibitype and ibiaddr) */ + if (WAIT_FOR(IS_BIT_SET(inst->MSTATUS, NPCX_I3C_MSTATUS_IBIWON), NPCX_I3C_CHK_TIMEOUT_US, + NULL) == false) { + LOG_ERR("IBI work, IBIWON timeout"); + + goto out_ibi_work; + } + + ibitype = GET_FIELD(inst->MSTATUS, NPCX_I3C_MSTATUS_IBITYPE); + ibiaddr = GET_FIELD(inst->MSTATUS, NPCX_I3C_MSTATUS_IBIADDR); + + switch (ibitype) { + case MSTATUS_IBITYPE_IBI: + target = i3c_dev_list_i3c_addr_find(dev_list, (uint8_t)ibiaddr); + if (target != NULL) { + ret = npcx_i3c_xfer_read_fifo(inst, &payload[0], sizeof(payload)); + if (ret >= 0) { + payload_sz = (size_t)ret; + } else { + LOG_ERR("Error reading IBI payload"); + + npcx_i3c_request_emit_stop(inst); + + goto out_ibi_work; + } + } else { + /* NACK IBI coming from unknown device */ + npcx_i3c_ibi_respond_nack(inst); + } + break; + case MSTATUS_IBITYPE_HJ: + npcx_i3c_ibi_respond_ack(inst); + npcx_i3c_request_emit_stop(inst); + break; + case MSTATUS_IBITYPE_CR: + LOG_DBG("Controller role handoff not supported"); + npcx_i3c_ibi_respond_nack(inst); + break; + default: + break; + } + + if (npcx_i3c_has_error(inst)) { + /* + * If the controller detects any errors, simply + * emit a STOP to abort the IBI. The target will + * raise IBI again if so desired. + */ + npcx_i3c_request_emit_stop(inst); + + goto out_ibi_work; + } + + switch (ibitype) { + case MSTATUS_IBITYPE_IBI: + if (target != NULL) { + if (i3c_ibi_work_enqueue_target_irq(target, &payload[0], payload_sz) != 0) { + LOG_ERR("Error enqueue IBI IRQ work"); + } + } + + /* Finishing the IBI transaction */ + npcx_i3c_request_emit_stop(inst); + break; + case MSTATUS_IBITYPE_HJ: + if (i3c_ibi_work_enqueue_hotjoin(dev) != 0) { + LOG_ERR("Error enqueue IBI HJ work"); + } + break; + case MSTATUS_IBITYPE_CR: + /* Not supported */ + break; + default: + break; + } + +out_ibi_work: + npcx_i3c_xfer_reset(inst); + + k_sem_give(&data->ibi_lock_sem); + + /* Re-enable target initiated IBI interrupt. */ + inst->MINTSET = BIT(NPCX_I3C_MINTSET_TGTSTART); +} + +/* Set local IBI information to IBIRULES register */ +static void npcx_i3c_ibi_rules_setup(struct npcx_i3c_data *data, struct i3c_reg *inst) +{ + uint32_t ibi_rules; + int idx; + + ibi_rules = 0; + + for (idx = 0; idx < ARRAY_SIZE(data->ibi.addr); idx++) { + uint32_t addr_6bit; + + /* Extract the lower 6-bit of target address */ + addr_6bit = (uint32_t)data->ibi.addr[idx] & IBIRULES_ADDR_MSK; + + /* Shift into correct place */ + addr_6bit <<= idx * IBIRULES_ADDR_SHIFT; + + /* Put into the temporary IBI Rules register */ + ibi_rules |= addr_6bit; + } + + if (!data->ibi.msb) { + /* The MSB0 field is 1 if MSB is 0 */ + ibi_rules |= BIT(NPCX_I3C_IBIRULES_MSB0); + } + + if (!data->ibi.has_mandatory_byte) { + /* The NOBYTE field is 1 if there is no mandatory byte */ + ibi_rules |= BIT(NPCX_I3C_IBIRULES_NOBYTE); + } + + /* Update the register */ + inst->IBIRULES = ibi_rules; + + LOG_DBG("MIBIRULES 0x%08x", ibi_rules); +} + +static int npcx_i3c_ibi_enable(const struct device *dev, struct i3c_device_desc *target) +{ + const struct npcx_i3c_config *config = dev->config; + struct npcx_i3c_data *data = dev->data; + struct i3c_reg *inst = config->base; + struct i3c_ccc_events i3c_events; + uint8_t idx; + bool msb, has_mandatory_byte; + int ret; + + /* Check target IBI request capable */ + if (!i3c_device_is_ibi_capable(target)) { + LOG_ERR("%s: device is not ibi capable", __func__); + return -EINVAL; + } + + if (data->ibi.num_addr >= ARRAY_SIZE(data->ibi.addr)) { + /* No more free entries in the IBI Rules table */ + LOG_ERR("%s: no more free space in the IBI rules table", __func__); + return -ENOMEM; + } + + /* Check whether the selected target is already in the list */ + for (idx = 0; idx < ARRAY_SIZE(data->ibi.addr); idx++) { + if (data->ibi.addr[idx] == target->dynamic_addr) { + LOG_ERR("%s: selected target is already in the list", __func__); + return -EINVAL; + } + } + + /* Disable controller interrupt while we configure IBI rules. */ + inst->MINTCLR = BIT(NPCX_I3C_MINTCLR_TGTSTART); + + LOG_DBG("IBI enabling for 0x%02x (BCR 0x%02x)", target->dynamic_addr, target->bcr); + + msb = (target->dynamic_addr & BIT(6)) == BIT(6); /* Check addess(7-bit) MSB enable */ + has_mandatory_byte = i3c_ibi_has_payload(target); + + /* + * If there are already addresses in the table, we must + * check if the incoming entry is compatible with + * the existing ones. + * + * All targets in the list should follow the same IBI rules. + */ + if (data->ibi.num_addr > 0) { + /* + * 1. All devices in the table must all use mandatory + * bytes, or do not. + * + * 2. Each address in entry only captures the lowest 6-bit. + * The MSB (7th bit) is captured separated in another bit + * in the register. So all addresses must have the same MSB. + */ + if ((has_mandatory_byte != data->ibi.has_mandatory_byte) || + (msb != data->ibi.msb)) { + ret = -EINVAL; + LOG_ERR("%s: New IBI does not have same mandatory byte or msb" + " as previous IBI", __func__); + goto out_ibi_enable; + } + + /* Find an empty address slot */ + for (idx = 0; idx < ARRAY_SIZE(data->ibi.addr); idx++) { + if (data->ibi.addr[idx] == 0U) { + break; + } + } + + if (idx >= ARRAY_SIZE(data->ibi.addr)) { + ret = -ENOTSUP; + LOG_ERR("Cannot support more IBIs"); + goto out_ibi_enable; + } + } else { + /* + * If the incoming address is the first in the table, + * it dictates future compatibilities. + */ + data->ibi.has_mandatory_byte = has_mandatory_byte; + data->ibi.msb = msb; + + idx = 0; + } + + data->ibi.addr[idx] = target->dynamic_addr; + data->ibi.num_addr += 1U; + + npcx_i3c_ibi_rules_setup(data, inst); + + /* Enable target IBI event by ENEC command */ + i3c_events.events = I3C_CCC_EVT_INTR; + ret = i3c_ccc_do_events_set(target, true, &i3c_events); + if (ret != 0) { + LOG_ERR("Error sending IBI ENEC for 0x%02x (%d)", target->dynamic_addr, ret); + } + +out_ibi_enable: + if (data->ibi.num_addr > 0U) { + /* + * If there is more than 1 target in the list, + * enable controller to raise interrupt when a target + * initiates IBI. + */ + inst->MINTSET = BIT(NPCX_I3C_MINTSET_TGTSTART); + } + + return ret; +} + +static int npcx_i3c_ibi_disable(const struct device *dev, struct i3c_device_desc *target) +{ + const struct npcx_i3c_config *config = dev->config; + struct npcx_i3c_data *data = dev->data; + struct i3c_reg *inst = config->base; + struct i3c_ccc_events i3c_events; + int ret; + int idx; + + if (!i3c_device_is_ibi_capable(target)) { + LOG_ERR("%s: device is not ibi capable", __func__); + return -EINVAL; + } + + for (idx = 0; idx < ARRAY_SIZE(data->ibi.addr); idx++) { + if (target->dynamic_addr == data->ibi.addr[idx]) { + break; + } + } + + if (idx == ARRAY_SIZE(data->ibi.addr)) { + LOG_ERR("%s: target is not in list of registered addresses", __func__); + return -ENODEV; + } + + /* Disable controller interrupt while we configure IBI rules. */ + inst->MINTCLR = BIT(NPCX_I3C_MINTCLR_TGTSTART); + + /* Clear the ibi rule data */ + data->ibi.addr[idx] = 0U; + data->ibi.num_addr -= 1U; + + /* Disable disable target IBI */ + i3c_events.events = I3C_CCC_EVT_INTR; + ret = i3c_ccc_do_events_set(target, false, &i3c_events); + if (ret != 0) { + LOG_ERR("Error sending IBI DISEC for 0x%02x (%d)", target->dynamic_addr, ret); + } + + npcx_i3c_ibi_rules_setup(data, inst); + + if (data->ibi.num_addr > 0U) { + /* + * Enable controller to raise interrupt when a target + * initiates IBI. + */ + inst->MINTSET = BIT(NPCX_I3C_MINTSET_TGTSTART); + } + + return ret; +} +#endif /* CONFIG_I3C_USE_IBI */ + +static void npcx_i3c_isr(const struct device *dev) +{ + const struct npcx_i3c_config *config = dev->config; + struct i3c_reg *inst = config->base; + +#ifdef CONFIG_I3C_NPCX_DMA + struct mdma_reg *mdma_inst = config->mdma_base; + + if (IS_BIT_SET(inst->MSTATUS, NPCX_I3C_MSTATUS_COMPLETE)) { + inst->MSTATUS = BIT(NPCX_I3C_MSTATUS_COMPLETE); /* W1C */ + + /* MDMA write */ + if (get_oper_state(dev) == NPCX_I3C_WR) { + return i3c_ctrl_notify(dev); + } + } + + if (IS_BIT_SET(mdma_inst->MDMA_CTL0, NPCX_MDMA_CTL_TC)) { + mdma_inst->MDMA_CTL0 &= ~BIT(NPCX_MDMA_CTL_TC); /* W0C */ + + /* MDMA read */ + if (get_oper_state(dev) == NPCX_I3C_RD) { + return i3c_ctrl_notify(dev); + } + + } +#endif /* CONFIG_I3C_NPCX_DMA */ + +#ifdef CONFIG_I3C_USE_IBI + /* Target start detected */ + if (IS_BIT_SET(inst->MSTATUS, NPCX_I3C_MSTATUS_TGTSTART)) { + /* Disable further target initiated IBI interrupt */ + inst->MINTCLR = BIT(NPCX_I3C_MINTCLR_TGTSTART); + + /* Handle IBI in workqueue */ + i3c_ibi_work_enqueue_cb(dev, npcx_i3c_ibi_work); + } +#endif /* CONFIG_I3C_USE_IBI */ + +} + +static int npcx_i3c_get_scl_config(struct npcx_i3c_timing_cfg *cfg, uint32_t i3c_src_clk, + uint32_t pp_baudrate_hz, uint32_t od_baudrate_hz) +{ + uint32_t i3c_div, freq; + uint32_t ppbaud, odbaud; + uint32_t pplow_ns, odlow_ns; + + if (cfg == NULL) { + LOG_ERR("Freq config NULL"); + return -EINVAL; + } + + if ((pp_baudrate_hz == 0) || (pp_baudrate_hz > I3C_SCL_PP_FREQ_MAX_MHZ) || + (od_baudrate_hz == 0) || (od_baudrate_hz > I3C_SCL_OD_FREQ_MAX_MHZ)) { + LOG_ERR("I3C PP_SCL should within 12.5 Mhz, input: %d", pp_baudrate_hz); + LOG_ERR("I3C OD_SCL should within 4.17 Mhz, input: %d", od_baudrate_hz); + return -EINVAL; + } + + /* Fixed PPLOW = 0 to achieve 50% duty cycle */ + /* pp_freq = ((f_mclkd / 2) / (PPBAUD+1)) */ + freq = i3c_src_clk / 2UL; + + i3c_div = freq / pp_baudrate_hz; + i3c_div = (i3c_div == 0UL) ? 1UL : i3c_div; + if (freq / i3c_div > pp_baudrate_hz) { + i3c_div++; + } + + if (i3c_div > PPBAUD_DIV_MAX) { + LOG_ERR("PPBAUD out of range"); + return -EINVAL; + } + + ppbaud = i3c_div - 1UL; + freq /= i3c_div; + + /* Check PP low period in spec (should be the same as PPHIGH) */ + pplow_ns = (uint32_t)(NSEC_PER_SEC / (2UL * freq)); + if (pplow_ns < I3C_BUS_TLOW_PP_MIN_NS) { + LOG_ERR("PPLOW ns out of spec"); + return -EINVAL; + } + + /* Fixed odhpp = 1 configuration */ + /* odFreq = (2*freq) / (ODBAUD + 2), 1 <= ODBAUD <= 255 */ + i3c_div = (2UL * freq) / od_baudrate_hz; + i3c_div = i3c_div < 2UL ? 2UL : i3c_div; + if ((2UL * freq / i3c_div) > od_baudrate_hz) { + i3c_div++; + } + + odbaud = i3c_div - 2UL; + freq = (2UL * freq) / i3c_div; /* For I2C usage in the future */ + + /* Check OD low period in spec */ + odlow_ns = (odbaud + 1UL) * pplow_ns; + if (odlow_ns < I3C_BUS_TLOW_OD_MIN_NS) { + LOG_ERR("ODBAUD ns out of spec"); + return -EINVAL; + } + + cfg->pplow = 0; + cfg->odhpp = 1; + cfg->ppbaud = ppbaud; + cfg->odbaud = odbaud; + + return 0; +} + +static int npcx_i3c_freq_init(const struct device *dev) +{ + const struct npcx_i3c_config *config = dev->config; + struct npcx_i3c_data *data = dev->data; + struct i3c_reg *inst = config->base; + const struct device *const clk_dev = config->clock_dev; + struct i3c_config_controller *ctrl_config = &data->common.ctrl_config; + uint32_t scl_pp = ctrl_config->scl.i3c; + uint32_t scl_od = config->clocks.i3c_od_scl_hz; + struct npcx_i3c_timing_cfg timing_cfg; + uint32_t mclkd; + int ret; + + ret = clock_control_get_rate(clk_dev, (clock_control_subsys_t)&config->clock_subsys, + &mclkd); + if (ret != 0x0) { + LOG_ERR("Get I3C source clock fail %d", ret); + return -EINVAL; + } + + LOG_DBG("MCLKD: %d", mclkd); + LOG_DBG("SCL_PP_FEQ MAX: %d", I3C_SCL_PP_FREQ_MAX_MHZ); + LOG_DBG("SCL_OD_FEQ MAX: %d", I3C_SCL_OD_FREQ_MAX_MHZ); + LOG_DBG("scl_pp: %d", scl_pp); + LOG_DBG("scl_od: %d", scl_od); + LOG_DBG("hdr: %d", ctrl_config->supported_hdr); + + /* MCLKD = MCLK / I3C_DIV(1 or 2) + * MCLKD must between 40 mhz to 50 mhz. + */ + if (mclkd == MCLKD_FREQ_45_MHZ) { + /* Set default I3C_SCL configuration */ + timing_cfg = npcx_def_speed_cfg[NPCX_I3C_BUS_SPEED_45MHZ]; + } else { + LOG_ERR("Unsupported MCLKD freq for %s.", dev->name); + return -EINVAL; + } + + ret = npcx_i3c_get_scl_config(&timing_cfg, mclkd, scl_pp, scl_od); + if (ret != 0x0) { + LOG_ERR("Adjust I3C frequency fail"); + return -EINVAL; + } + + /* Apply SCL_PP and SCL_OD */ + SET_FIELD(inst->MCONFIG, NPCX_I3C_MCONFIG_PPBAUD, timing_cfg.ppbaud); + SET_FIELD(inst->MCONFIG, NPCX_I3C_MCONFIG_PPLOW, timing_cfg.pplow); + SET_FIELD(inst->MCONFIG, NPCX_I3C_MCONFIG_ODBAUD, timing_cfg.odbaud); + if (timing_cfg.odhpp != 0) { + inst->MCONFIG |= BIT(NPCX_I3C_MCONFIG_ODHPP); + } else { + inst->MCONFIG &= ~BIT(NPCX_I3C_MCONFIG_ODHPP); + } + + LOG_DBG("ppbaud: %d", GET_FIELD(inst->MCONFIG, NPCX_I3C_MCONFIG_PPBAUD)); + LOG_DBG("odbaud: %d", GET_FIELD(inst->MCONFIG, NPCX_I3C_MCONFIG_ODBAUD)); + LOG_DBG("pplow: %d", GET_FIELD(inst->MCONFIG, NPCX_I3C_MCONFIG_PPLOW)); + LOG_DBG("odhpp: %d", IS_BIT_SET(inst->MCONFIG, NPCX_I3C_MCONFIG_ODHPP)); + + return 0; +} + +static int npcx_i3c_cntlr_init(const struct device *dev) +{ + const struct npcx_i3c_config *config = dev->config; + struct i3c_reg *inst = config->base; + const struct device *const clk_dev = config->clock_dev; + uint32_t apb4_rate; + uint8_t bamatch; + int ret; + + /* Reset I3C module */ + reset_line_toggle_dt(&config->reset); + + /* Disable all interrupts */ + npcx_i3c_interrupt_all_disable(inst); + + /* Initial baudrate. PPLOW=1, PPBAUD, ODHPP=1, ODBAUD */ + if (npcx_i3c_freq_init(dev) != 0x0) { + return -EINVAL; + } + + /* Enable main controller mode */ + SET_FIELD(inst->MCONFIG, NPCX_I3C_MCONFIG_CTRENA, MCONFIG_CTRENA_ON); + /* Enable external high-keeper */ + SET_FIELD(inst->MCONFIG, NPCX_I3C_MCONFIG_HKEEP, MCONFIG_HKEEP_EXT_SDA_SCL); + /* Enable open-drain stop */ + inst->MCONFIG |= BIT(NPCX_I3C_MCONFIG_ODSTOP); + /* Enable timeout */ + inst->MCONFIG &= ~BIT(NPCX_I3C_MCONFIG_DISTO); + /* Flush tx and tx FIFO buffer */ + npcx_i3c_fifo_flush(inst); + + /* Set bus available match value in target register */ + ret = clock_control_get_rate(clk_dev, (clock_control_subsys_t)&config->ref_clk_subsys, + &apb4_rate); + LOG_DBG("APB4_CLK: %d", apb4_rate); + + if (ret != 0x0) { + LOG_ERR("Get APb4 source clock fail %d", ret); + return -EINVAL; + } + + bamatch = DIV_ROUND_UP(apb4_rate, MHZ(1)); + bamatch = DIV_ROUND_UP(bamatch, BAMATCH_DIV); + LOG_DBG("BAMATCH: %d", bamatch); + + SET_FIELD(inst->CONFIG, NPCX_I3C_CONFIG_BAMATCH, bamatch); + + return 0; +} + +static int npcx_i3c_configure(const struct device *dev, enum i3c_config_type type, void *config) +{ + struct npcx_i3c_data *dev_data = dev->data; + struct i3c_config_controller *cntlr_cfg = config; + + if (type == I3C_CONFIG_CONTROLLER) { + /* + * Check for valid configuration parameters. + * Currently, must be the primary controller. + */ + if ((cntlr_cfg->is_secondary) || (cntlr_cfg->scl.i3c == 0U)) { + return -EINVAL; + } + + /* Save requested config to dev */ + (void)memcpy(&dev_data->common.ctrl_config, cntlr_cfg, sizeof(*cntlr_cfg)); + + /* Controller init */ + return npcx_i3c_cntlr_init(dev); + } + + LOG_ERR("Support controller mode only"); + return -EINVAL; +} + +static int npcx_i3c_config_get(const struct device *dev, enum i3c_config_type type, void *config) +{ + struct npcx_i3c_data *data = dev->data; + + if ((type != I3C_CONFIG_CONTROLLER) || (config == NULL)) { + return -EINVAL; + } + + (void)memcpy(config, &data->common.ctrl_config, sizeof(data->common.ctrl_config)); + + return 0; +} + +static int npcx_i3c_init(const struct device *dev) +{ + const struct npcx_i3c_config *config = dev->config; + struct npcx_i3c_data *data = dev->data; + struct i3c_config_controller *ctrl_config = &data->common.ctrl_config; + const struct device *const clk_dev = config->clock_dev; + int ret; + + /* Check clock device ready */ + if (!device_is_ready(clk_dev)) { + LOG_ERR("%s Clk device not ready", clk_dev->name); + return -ENODEV; + } + + /* Set I3C_PD operational */ + ret = clock_control_on(clk_dev, (clock_control_subsys_t)&config->clock_subsys); + if (ret < 0) { + LOG_ERR("Turn on I3C clock fail %d", ret); + return ret; + } + +#ifdef CONFIG_I3C_NPCX_DMA + ret = clock_control_on(clk_dev, (clock_control_subsys_t)&config->mdma_clk_subsys); + if (ret < 0) { + LOG_ERR("Turn on I3C MDMA clock fail %d", ret); + return ret; + } +#endif + + /* Apply pin-muxing */ + ret = pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT); + if (ret != 0) { + LOG_ERR("Apply pinctrl fail %d", ret); + return ret; + } + + k_mutex_init(&data->lock_mutex); + k_sem_init(&data->sync_sem, 0, 1); + k_sem_init(&data->ibi_lock_sem, 1, 1); + + ret = i3c_addr_slots_init(dev); + if (ret != 0) { + LOG_ERR("Addr slots init fail %d", ret); + return ret; + } + + ctrl_config->is_secondary = false; /* Currently can only act as primary controller. */ + ctrl_config->supported_hdr = 0U; /* HDR mode not supported at the moment. */ + ctrl_config->scl.i3c = config->clocks.i3c_pp_scl_hz; /* Set I3C frequency */ + + ret = npcx_i3c_configure(dev, I3C_CONFIG_CONTROLLER, ctrl_config); + if (ret != 0) { + LOG_ERR("Apply i3c_configure() fail %d", ret); + return ret; + } + + /* Just in case the bus is not in idle. */ + ret = npcx_i3c_recover_bus(dev); + if (ret != 0) { + LOG_ERR("Apply i3c_recover_bus() fail %d", ret); + return ret; + } + + /* Configure interrupt */ + config->irq_config_func(dev); + + /* Initialize driver status machine */ + set_oper_state(dev, NPCX_I3C_IDLE); + + /* Check I3C target device exist in device tree */ + if (config->common.dev_list.num_i3c > 0) { + /* Perform bus initialization */ + ret = i3c_bus_init(dev, &config->common.dev_list); + if (ret != 0) { + LOG_ERR("Apply i3c_bus_init() fail %d", ret); + return ret; + } + } + + return 0; +} + +static const struct i3c_driver_api npcx_i3c_driver_api = { + .configure = npcx_i3c_configure, + .config_get = npcx_i3c_config_get, + + .recover_bus = npcx_i3c_recover_bus, + + .do_daa = npcx_i3c_do_daa, + .do_ccc = npcx_i3c_do_ccc, + + .i3c_device_find = npcx_i3c_device_find, + + .i3c_xfers = npcx_i3c_transfer, + +#ifdef CONFIG_I3C_USE_IBI + .ibi_enable = npcx_i3c_ibi_enable, + .ibi_disable = npcx_i3c_ibi_disable, +#endif +}; + +#define I3C_NPCX_DEVICE(id) \ + PINCTRL_DT_INST_DEFINE(id); \ + static void npcx_i3c_config_func_##id(const struct device *dev) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(id), DT_INST_IRQ(id, priority), npcx_i3c_isr, \ + DEVICE_DT_INST_GET(id), 0); \ + irq_enable(DT_INST_IRQN(id)); \ + }; \ + static struct i3c_device_desc npcx_i3c_device_array_##id[] = I3C_DEVICE_ARRAY_DT_INST(id); \ + static struct i3c_i2c_device_desc npcx_i3c_i2c_device_array_##id[] = \ + I3C_I2C_DEVICE_ARRAY_DT_INST(id); \ + static const struct npcx_i3c_config npcx_i3c_config_##id = { \ + .base = (struct i3c_reg *)DT_INST_REG_ADDR(id), \ + .clock_dev = DEVICE_DT_GET(NPCX_CLK_CTRL_NODE), \ + .reset = RESET_DT_SPEC_INST_GET(id), \ + .clock_subsys = NPCX_DT_CLK_CFG_ITEM_BY_NAME(id, mclkd), \ + .ref_clk_subsys = NPCX_DT_CLK_CFG_ITEM_BY_NAME(id, apb4), \ + .irq_config_func = npcx_i3c_config_func_##id, \ + .common.dev_list.i3c = npcx_i3c_device_array_##id, \ + .common.dev_list.num_i3c = ARRAY_SIZE(npcx_i3c_device_array_##id), \ + .common.dev_list.i2c = npcx_i3c_i2c_device_array_##id, \ + .common.dev_list.num_i2c = ARRAY_SIZE(npcx_i3c_i2c_device_array_##id), \ + .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(id), \ + .clocks.i3c_pp_scl_hz = DT_INST_PROP_OR(id, i3c_scl_hz, 0), \ + .clocks.i3c_od_scl_hz = DT_INST_PROP_OR(id, i3c_od_scl_hz, 0), \ + IF_ENABLED(CONFIG_I3C_NPCX_DMA, ( \ + .mdma_clk_subsys = NPCX_DT_CLK_CFG_ITEM_BY_IDX(id, 2), \ + )) \ + IF_ENABLED(CONFIG_I3C_NPCX_DMA, ( \ + .mdma_base = (struct mdma_reg *)DT_INST_REG_ADDR_BY_IDX(id, 1), \ + )) \ + }; \ + static struct npcx_i3c_data npcx_i3c_data_##id; \ + DEVICE_DT_INST_DEFINE(id, npcx_i3c_init, NULL, &npcx_i3c_data_##id, &npcx_i3c_config_##id, \ + POST_KERNEL, CONFIG_I3C_CONTROLLER_INIT_PRIORITY, \ + &npcx_i3c_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(I3C_NPCX_DEVICE) diff --git a/drivers/i3c/i3c_shell.c b/drivers/i3c/i3c_shell.c new file mode 100644 index 00000000000..8cd2c2b57e5 --- /dev/null +++ b/drivers/i3c/i3c_shell.c @@ -0,0 +1,1528 @@ +/* + * Copyright (c) 2024 Meta Platforms + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(i3c_shell, CONFIG_LOG_DEFAULT_LEVEL); + +#define MAX_BYTES_FOR_REGISTER_INDEX 4 +#define ARGV_DEV 1 +#define ARGV_TDEV 2 +#define ARGV_REG 3 + +/* Maximum bytes we can write or read at once */ +#define MAX_I3C_BYTES 16 + +struct i3c_ctrl { + const struct device *dev; + const union shell_cmd_entry *i3c_attached_dev_subcmd; + const union shell_cmd_entry *i3c_list_dev_subcmd; +}; + +#define I3C_ATTACHED_DEV_GET_FN(node_id) \ + static void node_id##cmd_i3c_attached_get(size_t idx, struct shell_static_entry *entry); \ + \ + SHELL_DYNAMIC_CMD_CREATE(node_id##sub_i3c_attached, node_id##cmd_i3c_attached_get); \ + \ + static void node_id##cmd_i3c_attached_get(size_t idx, struct shell_static_entry *entry) \ + { \ + const struct device *dev = DEVICE_DT_GET(node_id); \ + struct i3c_driver_data *data; \ + sys_snode_t *node; \ + size_t cnt = 0; \ + \ + entry->syntax = NULL; \ + entry->handler = NULL; \ + entry->subcmd = NULL; \ + entry->help = NULL; \ + \ + data = (struct i3c_driver_data *)dev->data; \ + if (!sys_slist_is_empty(&data->attached_dev.devices.i3c)) { \ + SYS_SLIST_FOR_EACH_NODE(&data->attached_dev.devices.i3c, node) { \ + if (cnt == idx) { \ + struct i3c_device_desc *desc = \ + CONTAINER_OF(node, struct i3c_device_desc, node); \ + entry->syntax = desc->dev->name; \ + return; \ + } \ + cnt++; \ + } \ + } \ + } + +#define I3C_LIST_DEV_GET_FN(node_id) \ + static void node_id##cmd_i3c_list_get(size_t idx, struct shell_static_entry *entry); \ + \ + SHELL_DYNAMIC_CMD_CREATE(node_id##sub_i3c_list, node_id##cmd_i3c_list_get); \ + \ + static void node_id##cmd_i3c_list_get(size_t idx, struct shell_static_entry *entry) \ + { \ + const struct device *dev = DEVICE_DT_GET(node_id); \ + struct i3c_driver_config *config; \ + \ + entry->syntax = NULL; \ + entry->handler = NULL; \ + entry->subcmd = NULL; \ + entry->help = NULL; \ + \ + config = (struct i3c_driver_config *)dev->config; \ + if (idx < config->dev_list.num_i3c) { \ + entry->syntax = config->dev_list.i3c[idx].dev->name; \ + } \ + } + +#define I3C_CTRL_FN(node_id) \ + I3C_ATTACHED_DEV_GET_FN(node_id) \ + I3C_LIST_DEV_GET_FN(node_id) + +/* zephyr-keep-sorted-start */ +DT_FOREACH_STATUS_OKAY(cdns_i3c, I3C_CTRL_FN) +DT_FOREACH_STATUS_OKAY(nuvoton_npcx_i3c, I3C_CTRL_FN) +DT_FOREACH_STATUS_OKAY(nxp_mcux_i3c, I3C_CTRL_FN) +/* zephyr-keep-sorted-stop */ + +#define I3C_CTRL_LIST_ENTRY(node_id) \ + { \ + .dev = DEVICE_DT_GET(node_id), \ + .i3c_attached_dev_subcmd = &node_id##sub_i3c_attached, \ + .i3c_list_dev_subcmd = &node_id##sub_i3c_list, \ + }, + +const struct i3c_ctrl i3c_list[] = { + /* zephyr-keep-sorted-start */ + DT_FOREACH_STATUS_OKAY(cdns_i3c, I3C_CTRL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(nuvoton_npcx_i3c, I3C_CTRL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(nxp_mcux_i3c, I3C_CTRL_LIST_ENTRY) + /* zephyr-keep-sorted-stop */ +}; + +static int get_bytes_count_for_hex(char *arg) +{ + int length = (strlen(arg) + 1) / 2; + + if (length > 1 && arg[0] == '0' && (arg[1] == 'x' || arg[1] == 'X')) { + length -= 1; + } + + return MIN(MAX_BYTES_FOR_REGISTER_INDEX, length); +} + +static struct i3c_i2c_device_desc *get_i3c_i2c_list_desc_from_addr(const struct device *dev, + uint16_t addr) +{ + struct i3c_driver_config *config; + uint8_t i; + + config = (struct i3c_driver_config *)dev->config; + for (i = 0; i < config->dev_list.num_i2c; i++) { + if (config->dev_list.i2c[i].addr == addr) { + /* only look for a device with the addr */ + return &config->dev_list.i2c[i]; + } + } + + return NULL; +} + +static struct i3c_device_desc *get_i3c_list_desc_from_dev_name(const struct device *dev, + const char *tdev_name) +{ + struct i3c_driver_config *config; + uint8_t i; + + config = (struct i3c_driver_config *)dev->config; + for (i = 0; i < config->dev_list.num_i3c; i++) { + if (strcmp(config->dev_list.i3c[i].dev->name, tdev_name) == 0) { + /* only look for a device with the same name */ + return &config->dev_list.i3c[i]; + } + } + + return NULL; +} + +static struct i3c_device_desc *get_i3c_attached_desc_from_dev_name(const struct device *dev, + const char *tdev_name) +{ + struct i3c_driver_data *data; + sys_snode_t *node; + + data = (struct i3c_driver_data *)dev->data; + if (!sys_slist_is_empty(&data->attached_dev.devices.i3c)) { + SYS_SLIST_FOR_EACH_NODE(&data->attached_dev.devices.i3c, node) { + struct i3c_device_desc *desc = + CONTAINER_OF(node, struct i3c_device_desc, node); + /* only look for a device with the same name */ + if (strcmp(desc->dev->name, tdev_name) == 0) { + return desc; + } + } + } + + return NULL; +} + +/* i3c info [] */ +static int cmd_i3c_info(const struct shell *shell_ctx, size_t argc, char **argv) +{ + const struct device *dev, *tdev; + struct i3c_driver_data *data; + sys_snode_t *node; + bool found = false; + + dev = device_get_binding(argv[ARGV_DEV]); + + if (!dev) { + shell_error(shell_ctx, "I3C: Device driver %s not found.", argv[ARGV_DEV]); + return -ENODEV; + } + data = (struct i3c_driver_data *)dev->data; + + if (argc == 3) { + /* TODO: is this needed? */ + tdev = device_get_binding(argv[ARGV_TDEV]); + if (!tdev) { + shell_error(shell_ctx, "I3C: Target Device driver %s not found.", + argv[ARGV_DEV]); + return -ENODEV; + } + + if (!sys_slist_is_empty(&data->attached_dev.devices.i3c)) { + SYS_SLIST_FOR_EACH_NODE(&data->attached_dev.devices.i3c, node) { + struct i3c_device_desc *desc = + CONTAINER_OF(node, struct i3c_device_desc, node); + /* only look for a device with the same name */ + if (strcmp(desc->dev->name, tdev->name) == 0) { + shell_print(shell_ctx, + "name: %s\n" + "\tpid: 0x%012llx\n" + "\tstatic_addr: 0x%02x\n" + "\tdynamic_addr: 0x%02x\n" +#if defined(CONFIG_I3C_USE_GROUP_ADDR) + "\tgroup_addr: 0x%02x\n" +#endif + "\tbcr: 0x%02x\n" + "\tdcr: 0x%02x\n" + "\tmaxrd: 0x%02x\n" + "\tmaxwr: 0x%02x\n" + "\tmax_read_turnaround: 0x%08x\n" + "\tmrl: 0x%04x\n" + "\tmwl: 0x%04x\n" + "\tmax_ibi: 0x%02x\n" + "\tgetcaps: 0x%02x; 0x%02x; 0x%02x; 0x%02x", + desc->dev->name, (uint64_t)desc->pid, + desc->static_addr, desc->dynamic_addr, +#if defined(CONFIG_I3C_USE_GROUP_ADDR) + desc->group_addr, +#endif + desc->bcr, desc->dcr, desc->data_speed.maxrd, + desc->data_speed.maxwr, + desc->data_speed.max_read_turnaround, + desc->data_length.mrl, desc->data_length.mwl, + desc->data_length.max_ibi, + desc->getcaps.getcap1, desc->getcaps.getcap2, + desc->getcaps.getcap3, desc->getcaps.getcap4); + found = true; + break; + } + } + } else { + shell_print(shell_ctx, "I3C: No devices found."); + return -ENODEV; + } + if (found == false) { + shell_error(shell_ctx, "I3C: Target device not found."); + return -ENODEV; + } + } else if (argc == 2) { + /* This gets all "currently attached" I3C and I2C devices */ + if (!sys_slist_is_empty(&data->attached_dev.devices.i3c)) { + shell_print(shell_ctx, "I3C: Devices found:"); + SYS_SLIST_FOR_EACH_NODE(&data->attached_dev.devices.i3c, node) { + struct i3c_device_desc *desc = + CONTAINER_OF(node, struct i3c_device_desc, node); + shell_print(shell_ctx, + "name: %s\n" + "\tpid: 0x%012llx\n" + "\tstatic_addr: 0x%02x\n" + "\tdynamic_addr: 0x%02x\n" +#if defined(CONFIG_I3C_USE_GROUP_ADDR) + "\tgroup_addr: 0x%02x\n" +#endif + "\tbcr: 0x%02x\n" + "\tdcr: 0x%02x\n" + "\tmaxrd: 0x%02x\n" + "\tmaxwr: 0x%02x\n" + "\tmax_read_turnaround: 0x%08x\n" + "\tmrl: 0x%04x\n" + "\tmwl: 0x%04x\n" + "\tmax_ibi: 0x%02x\n" + "\tgetcaps: 0x%02x; 0x%02x; 0x%02x; 0x%02x", + desc->dev->name, (uint64_t)desc->pid, desc->static_addr, + desc->dynamic_addr, +#if defined(CONFIG_I3C_USE_GROUP_ADDR) + desc->group_addr, +#endif + desc->bcr, desc->dcr, desc->data_speed.maxrd, + desc->data_speed.maxwr, + desc->data_speed.max_read_turnaround, + desc->data_length.mrl, desc->data_length.mwl, + desc->data_length.max_ibi, desc->getcaps.getcap1, + desc->getcaps.getcap2, desc->getcaps.getcap3, + desc->getcaps.getcap4); + } + } else { + shell_print(shell_ctx, "I3C: No devices found."); + } + if (!sys_slist_is_empty(&data->attached_dev.devices.i2c)) { + shell_print(shell_ctx, "I2C: Devices found:"); + SYS_SLIST_FOR_EACH_NODE(&data->attached_dev.devices.i2c, node) { + struct i3c_i2c_device_desc *desc = + CONTAINER_OF(node, struct i3c_i2c_device_desc, node); + shell_print(shell_ctx, + "addr: 0x%02x\n" + "\tlvr: 0x%02x", + desc->addr, desc->lvr); + } + } else { + shell_print(shell_ctx, "I2C: No devices found."); + } + } else { + shell_error(shell_ctx, "Invalid number of arguments."); + } + + return 0; +} + +/* i3c recover */ +static int cmd_i3c_recover(const struct shell *shell_ctx, size_t argc, char **argv) +{ + const struct device *dev; + int err; + + dev = device_get_binding(argv[ARGV_DEV]); + if (!dev) { + shell_error(shell_ctx, "I3C: Device driver %s not found.", argv[1]); + return -ENODEV; + } + + err = i3c_recover_bus(dev); + if (err) { + shell_error(shell_ctx, "I3C: Bus recovery failed (err %d)", err); + return err; + } + + return 0; +} + +static int i3c_write_from_buffer(const struct shell *shell_ctx, char *s_dev_name, char *s_tdev_name, + char *s_reg_addr, char **data, uint8_t data_length) +{ + /* This buffer must preserve 4 bytes for register address, as it is + * filled using put_be32 function and we don't want to lower available + * space when using 1 byte address. + */ + uint8_t buf[MAX_I3C_BYTES + MAX_BYTES_FOR_REGISTER_INDEX - 1]; + const struct device *dev, *tdev; + struct i3c_device_desc *desc; + int reg_addr_bytes; + int reg_addr; + int ret; + int i; + + dev = device_get_binding(s_dev_name); + if (!dev) { + shell_error(shell_ctx, "I3C: Device driver %s not found.", s_dev_name); + return -ENODEV; + } + tdev = device_get_binding(s_tdev_name); + if (!tdev) { + shell_error(shell_ctx, "I3C: Device driver %s not found.", s_tdev_name); + return -ENODEV; + } + desc = get_i3c_attached_desc_from_dev_name(dev, tdev->name); + if (!desc) { + shell_error(shell_ctx, "I3C: Device %s not attached to bus.", tdev->name); + return -ENODEV; + } + + reg_addr = strtol(s_reg_addr, NULL, 16); + + reg_addr_bytes = get_bytes_count_for_hex(s_reg_addr); + sys_put_be32(reg_addr, buf); + + if (data_length + reg_addr_bytes > MAX_I3C_BYTES) { + data_length = MAX_I3C_BYTES - reg_addr_bytes; + shell_info(shell_ctx, "Too many bytes provided, limit is %d", + MAX_I3C_BYTES - reg_addr_bytes); + } + + for (i = 0; i < data_length; i++) { + buf[MAX_BYTES_FOR_REGISTER_INDEX + i] = (uint8_t)strtol(data[i], NULL, 16); + } + + ret = i3c_write(desc, buf + MAX_BYTES_FOR_REGISTER_INDEX - reg_addr_bytes, + reg_addr_bytes + data_length); + if (ret < 0) { + shell_error(shell_ctx, "Failed to write to device: %s", tdev->name); + return -EIO; + } + + return 0; +} + +/* i3c write [, ...] */ +static int cmd_i3c_write(const struct shell *shell_ctx, size_t argc, char **argv) +{ + return i3c_write_from_buffer(shell_ctx, argv[ARGV_DEV], argv[ARGV_TDEV], argv[ARGV_REG], + &argv[4], argc - 4); +} + +/* i3c write_byte */ +static int cmd_i3c_write_byte(const struct shell *shell_ctx, size_t argc, char **argv) +{ + return i3c_write_from_buffer(shell_ctx, argv[ARGV_DEV], argv[ARGV_TDEV], argv[ARGV_REG], + &argv[4], 1); +} + +static int i3c_read_to_buffer(const struct shell *shell_ctx, char *s_dev_name, char *s_tdev_name, + char *s_reg_addr, uint8_t *buf, uint8_t buf_length) +{ + const struct device *dev, *tdev; + struct i3c_device_desc *desc; + uint8_t reg_addr_buf[MAX_BYTES_FOR_REGISTER_INDEX]; + int reg_addr_bytes; + int reg_addr; + int ret; + + dev = device_get_binding(s_dev_name); + if (!dev) { + shell_error(shell_ctx, "I3C: Device driver %s not found.", s_dev_name); + return -ENODEV; + } + tdev = device_get_binding(s_tdev_name); + if (!tdev) { + shell_error(shell_ctx, "I3C: Device driver %s not found.", s_dev_name); + return -ENODEV; + } + desc = get_i3c_attached_desc_from_dev_name(dev, tdev->name); + if (!desc) { + shell_error(shell_ctx, "I3C: Device %s not attached to bus.", tdev->name); + return -ENODEV; + } + + reg_addr = strtol(s_reg_addr, NULL, 16); + + reg_addr_bytes = get_bytes_count_for_hex(s_reg_addr); + sys_put_be32(reg_addr, reg_addr_buf); + + ret = i3c_write_read(desc, reg_addr_buf + MAX_BYTES_FOR_REGISTER_INDEX - reg_addr_bytes, + reg_addr_bytes, buf, buf_length); + if (ret < 0) { + shell_error(shell_ctx, "Failed to read from device: %s", tdev->name); + return -EIO; + } + + return 0; +} + +/* i3c read_byte */ +static int cmd_i3c_read_byte(const struct shell *shell_ctx, size_t argc, char **argv) +{ + uint8_t out; + int ret; + + ret = i3c_read_to_buffer(shell_ctx, argv[ARGV_DEV], argv[ARGV_TDEV], argv[ARGV_REG], &out, + 1); + if (ret == 0) { + shell_print(shell_ctx, "Output: 0x%x", out); + } + + return ret; +} + +/* i3c read [] */ +static int cmd_i3c_read(const struct shell *shell_ctx, size_t argc, char **argv) +{ + uint8_t buf[MAX_I3C_BYTES]; + int num_bytes; + int ret; + + if (argc > 4) { + num_bytes = strtol(argv[4], NULL, 16); + if (num_bytes > MAX_I3C_BYTES) { + num_bytes = MAX_I3C_BYTES; + } + } else { + num_bytes = MAX_I3C_BYTES; + } + + ret = i3c_read_to_buffer(shell_ctx, argv[ARGV_DEV], argv[ARGV_TDEV], argv[ARGV_REG], buf, + num_bytes); + if (ret == 0) { + shell_hexdump(shell_ctx, buf, num_bytes); + } + + return ret; +} + +/* i3c ccc rstdaa */ +static int cmd_i3c_ccc_rstdaa(const struct shell *shell_ctx, size_t argc, char **argv) +{ + const struct device *dev; + struct i3c_driver_data *data; + sys_snode_t *node; + int ret; + + dev = device_get_binding(argv[ARGV_DEV]); + if (!dev) { + shell_error(shell_ctx, "I3C: Device driver %s not found.", argv[ARGV_DEV]); + return -ENODEV; + } + data = (struct i3c_driver_data *)dev->data; + + ret = i3c_ccc_do_rstdaa_all(dev); + if (ret < 0) { + shell_error(shell_ctx, "I3C: unable to send CCC RSTDAA."); + return ret; + } + + /* reset all devices DA */ + if (!sys_slist_is_empty(&data->attached_dev.devices.i3c)) { + SYS_SLIST_FOR_EACH_NODE(&data->attached_dev.devices.i3c, node) { + struct i3c_device_desc *desc = + CONTAINER_OF(node, struct i3c_device_desc, node); + desc->dynamic_addr = 0; + shell_print(shell_ctx, "Reset dynamic address for device %s", + desc->dev->name); + } + } + + return ret; +} + +/* i3c ccc entdaa */ +static int cmd_i3c_ccc_entdaa(const struct shell *shell_ctx, size_t argc, char **argv) +{ + const struct device *dev; + + dev = device_get_binding(argv[ARGV_DEV]); + if (!dev) { + shell_error(shell_ctx, "I3C: Device driver %s not found.", argv[ARGV_DEV]); + return -ENODEV; + } + + return i3c_do_daa(dev); +} + +/* i3c ccc setdasa */ +static int cmd_i3c_ccc_setdasa(const struct shell *shell_ctx, size_t argc, char **argv) +{ + const struct device *dev, *tdev; + struct i3c_device_desc *desc; + int ret; + + dev = device_get_binding(argv[ARGV_DEV]); + if (!dev) { + shell_error(shell_ctx, "I3C: Device driver %s not found.", argv[ARGV_DEV]); + return -ENODEV; + } + tdev = device_get_binding(argv[ARGV_TDEV]); + if (!tdev) { + shell_error(shell_ctx, "I3C: Device driver %s not found.", argv[ARGV_TDEV]); + return -ENODEV; + } + desc = get_i3c_attached_desc_from_dev_name(dev, tdev->name); + if (!desc) { + shell_error(shell_ctx, "I3C: Device %s not attached to bus.", tdev->name); + return -ENODEV; + } + + ret = i3c_ccc_do_setdasa(desc); + if (ret < 0) { + shell_error(shell_ctx, "I3C: unable to send CCC SETDASA."); + return ret; + } + + /* update the target's dynamic address */ + desc->dynamic_addr = desc->init_dynamic_addr ? desc->init_dynamic_addr : desc->static_addr; + + return ret; +} + +/* i3c ccc setnewda */ +static int cmd_i3c_ccc_setnewda(const struct shell *shell_ctx, size_t argc, char **argv) +{ + const struct device *dev, *tdev; + struct i3c_device_desc *desc; + struct i3c_driver_data *data; + struct i3c_ccc_address new_da; + uint8_t old_da; + int ret; + + dev = device_get_binding(argv[ARGV_DEV]); + if (!dev) { + shell_error(shell_ctx, "I3C: Device driver %s not found.", argv[ARGV_DEV]); + return -ENODEV; + } + tdev = device_get_binding(argv[ARGV_TDEV]); + if (!tdev) { + shell_error(shell_ctx, "I3C: Device driver %s not found.", argv[ARGV_TDEV]); + return -ENODEV; + } + desc = get_i3c_attached_desc_from_dev_name(dev, tdev->name); + if (!desc) { + shell_error(shell_ctx, "I3C: Device %s not attached to bus.", tdev->name); + return -ENODEV; + } + + data = (struct i3c_driver_data *)dev->data; + new_da.addr = strtol(argv[3], NULL, 16); + /* check if the addressed is free */ + if (!i3c_addr_slots_is_free(&data->attached_dev.addr_slots, new_da.addr)) { + shell_error(shell_ctx, "I3C: Address 0x%02x is already in use.", new_da.addr); + return -EINVAL; + } + + ret = i3c_ccc_do_setnewda(desc, new_da); + if (ret < 0) { + shell_error(shell_ctx, "I3C: unable to send CCC SETDASA."); + return ret; + } + + /* reattach device address */ + old_da = desc->dynamic_addr; + desc->dynamic_addr = new_da.addr; + ret = i3c_reattach_i3c_device(desc, old_da); + if (ret < 0) { + shell_error(shell_ctx, "I3C: unable to reattach device"); + return ret; + } + + return ret; +} + +/* i3c ccc getbcr */ +static int cmd_i3c_ccc_getbcr(const struct shell *shell_ctx, size_t argc, char **argv) +{ + const struct device *dev, *tdev; + struct i3c_device_desc *desc; + struct i3c_ccc_getbcr bcr; + int ret; + + dev = device_get_binding(argv[ARGV_DEV]); + if (!dev) { + shell_error(shell_ctx, "I3C: Device driver %s not found.", argv[ARGV_DEV]); + return -ENODEV; + } + tdev = device_get_binding(argv[ARGV_TDEV]); + if (!tdev) { + shell_error(shell_ctx, "I3C: Device driver %s not found.", argv[ARGV_TDEV]); + return -ENODEV; + } + desc = get_i3c_attached_desc_from_dev_name(dev, tdev->name); + if (!desc) { + shell_error(shell_ctx, "I3C: Device %s not attached to bus.", tdev->name); + return -ENODEV; + } + + ret = i3c_ccc_do_getbcr(desc, &bcr); + if (ret < 0) { + shell_error(shell_ctx, "I3C: unable to send CCC GETBCR."); + return ret; + } + + shell_print(shell_ctx, "BCR: 0x%02x", bcr.bcr); + + return ret; +} + +/* i3c ccc getdcr */ +static int cmd_i3c_ccc_getdcr(const struct shell *shell_ctx, size_t argc, char **argv) +{ + const struct device *dev, *tdev; + struct i3c_device_desc *desc; + struct i3c_ccc_getdcr dcr; + int ret; + + dev = device_get_binding(argv[ARGV_DEV]); + if (!dev) { + shell_error(shell_ctx, "I3C: Device driver %s not found.", argv[ARGV_DEV]); + return -ENODEV; + } + tdev = device_get_binding(argv[ARGV_TDEV]); + if (!tdev) { + shell_error(shell_ctx, "I3C: Device driver %s not found.", argv[ARGV_TDEV]); + return -ENODEV; + } + desc = get_i3c_attached_desc_from_dev_name(dev, tdev->name); + if (!desc) { + shell_error(shell_ctx, "I3C: Device %s not attached to bus.", tdev->name); + return -ENODEV; + } + + ret = i3c_ccc_do_getdcr(desc, &dcr); + if (ret < 0) { + shell_error(shell_ctx, "I3C: unable to send CCC GETDCR."); + return ret; + } + + shell_print(shell_ctx, "DCR: 0x%02x", dcr.dcr); + + return ret; +} + +/* i3c ccc getpid */ +static int cmd_i3c_ccc_getpid(const struct shell *shell_ctx, size_t argc, char **argv) +{ + const struct device *dev, *tdev; + struct i3c_device_desc *desc; + struct i3c_ccc_getpid pid; + int ret; + + dev = device_get_binding(argv[ARGV_DEV]); + if (!dev) { + shell_error(shell_ctx, "I3C: Device driver %s not found.", argv[ARGV_DEV]); + return -ENODEV; + } + tdev = device_get_binding(argv[ARGV_TDEV]); + if (!tdev) { + shell_error(shell_ctx, "I3C: Device driver %s not found.", argv[ARGV_TDEV]); + return -ENODEV; + } + desc = get_i3c_attached_desc_from_dev_name(dev, tdev->name); + if (!desc) { + shell_error(shell_ctx, "I3C: Device %s not attached to bus.", tdev->name); + return -ENODEV; + } + + ret = i3c_ccc_do_getpid(desc, &pid); + if (ret < 0) { + shell_error(shell_ctx, "I3C: unable to send CCC GETPID."); + return ret; + } + + shell_print(shell_ctx, "PID: 0x%012llx", sys_get_be48(pid.pid)); + + return ret; +} + +/* i3c ccc getmrl */ +static int cmd_i3c_ccc_getmrl(const struct shell *shell_ctx, size_t argc, char **argv) +{ + const struct device *dev, *tdev; + struct i3c_device_desc *desc; + struct i3c_ccc_mrl mrl; + int ret; + + dev = device_get_binding(argv[ARGV_DEV]); + if (!dev) { + shell_error(shell_ctx, "I3C: Device driver %s not found.", argv[ARGV_DEV]); + return -ENODEV; + } + tdev = device_get_binding(argv[ARGV_TDEV]); + if (!tdev) { + shell_error(shell_ctx, "I3C: Device driver %s not found.", argv[ARGV_TDEV]); + return -ENODEV; + } + desc = get_i3c_attached_desc_from_dev_name(dev, tdev->name); + if (!desc) { + shell_error(shell_ctx, "I3C: Device %s not attached to bus.", tdev->name); + return -ENODEV; + } + + ret = i3c_ccc_do_getmrl(desc, &mrl); + if (ret < 0) { + shell_error(shell_ctx, "I3C: unable to send CCC GETMRL."); + return ret; + } + + if (desc->bcr & I3C_BCR_IBI_PAYLOAD_HAS_DATA_BYTE) { + shell_print(shell_ctx, "MRL: 0x%04x; IBI Length:0x%02x", mrl.len, mrl.ibi_len); + } else { + shell_print(shell_ctx, "MRL: 0x%04x", mrl.len); + } + + return ret; +} + +/* i3c ccc getmwl */ +static int cmd_i3c_ccc_getmwl(const struct shell *shell_ctx, size_t argc, char **argv) +{ + const struct device *dev, *tdev; + struct i3c_device_desc *desc; + struct i3c_ccc_mwl mwl; + int ret; + + dev = device_get_binding(argv[ARGV_DEV]); + if (!dev) { + shell_error(shell_ctx, "I3C: Device driver %s not found.", argv[ARGV_DEV]); + return -ENODEV; + } + tdev = device_get_binding(argv[ARGV_TDEV]); + if (!tdev) { + shell_error(shell_ctx, "I3C: Device driver %s not found.", argv[ARGV_TDEV]); + return -ENODEV; + } + desc = get_i3c_attached_desc_from_dev_name(dev, tdev->name); + if (!desc) { + shell_error(shell_ctx, "I3C: Device %s not attached to bus.", tdev->name); + return -ENODEV; + } + + ret = i3c_ccc_do_getmwl(desc, &mwl); + if (ret < 0) { + shell_error(shell_ctx, "I3C: unable to send CCC GETMWL."); + return ret; + } + + shell_print(shell_ctx, "MWL: 0x%04x", mwl.len); + + return ret; +} + +/* i3c ccc setmrl [] */ +static int cmd_i3c_ccc_setmrl(const struct shell *shell_ctx, size_t argc, char **argv) +{ + const struct device *dev, *tdev; + struct i3c_device_desc *desc; + struct i3c_ccc_mrl mrl; + int ret; + + dev = device_get_binding(argv[ARGV_DEV]); + if (!dev) { + shell_error(shell_ctx, "I3C: Device driver %s not found.", argv[ARGV_DEV]); + return -ENODEV; + } + tdev = device_get_binding(argv[ARGV_TDEV]); + if (!tdev) { + shell_error(shell_ctx, "I3C: Device driver %s not found.", argv[ARGV_TDEV]); + return -ENODEV; + } + desc = get_i3c_attached_desc_from_dev_name(dev, tdev->name); + if (!desc) { + shell_error(shell_ctx, "I3C: Device %s not attached to bus.", tdev->name); + return -ENODEV; + } + + /* IBI length is required if the ibi payload bit is set */ + if ((desc->bcr & I3C_BCR_IBI_PAYLOAD_HAS_DATA_BYTE) && (argc < 4)) { + shell_error(shell_ctx, "I3C: Missing IBI length."); + return -EINVAL; + } + + mrl.len = strtol(argv[3], NULL, 16); + if (argc > 3) { + mrl.ibi_len = strtol(argv[4], NULL, 16); + } + + ret = i3c_ccc_do_setmrl(desc, &mrl); + if (ret < 0) { + shell_error(shell_ctx, "I3C: unable to send CCC SETMRL."); + return ret; + } + + return ret; +} + +/* i3c ccc setmwl */ +static int cmd_i3c_ccc_setmwl(const struct shell *shell_ctx, size_t argc, char **argv) +{ + const struct device *dev, *tdev; + struct i3c_device_desc *desc; + struct i3c_ccc_mwl mwl; + int ret; + + dev = device_get_binding(argv[ARGV_DEV]); + if (!dev) { + shell_error(shell_ctx, "I3C: Device driver %s not found.", argv[ARGV_DEV]); + return -ENODEV; + } + tdev = device_get_binding(argv[ARGV_TDEV]); + if (!tdev) { + shell_error(shell_ctx, "I3C: Device driver %s not found.", argv[ARGV_TDEV]); + return -ENODEV; + } + desc = get_i3c_attached_desc_from_dev_name(dev, tdev->name); + if (!desc) { + shell_error(shell_ctx, "I3C: Device %s not attached to bus.", tdev->name); + return -ENODEV; + } + + mwl.len = strtol(argv[3], NULL, 16); + + ret = i3c_ccc_do_setmwl(desc, &mwl); + if (ret < 0) { + shell_error(shell_ctx, "I3C: unable to send CCC SETMWL."); + return ret; + } + + return ret; +} + +/* i3c ccc setmrl_bc [] */ +static int cmd_i3c_ccc_setmrl_bc(const struct shell *shell_ctx, size_t argc, char **argv) +{ + const struct device *dev; + struct i3c_ccc_mrl mrl; + int ret; + + dev = device_get_binding(argv[ARGV_DEV]); + if (!dev) { + shell_error(shell_ctx, "I3C: Device driver %s not found.", argv[ARGV_DEV]); + return -ENODEV; + } + + mrl.len = strtol(argv[2], NULL, 16); + if (argc > 3) { + mrl.ibi_len = strtol(argv[3], NULL, 16); + } + + ret = i3c_ccc_do_setmrl_all(dev, &mrl, argc > 3); + if (ret < 0) { + shell_error(shell_ctx, "I3C: unable to send CCC SETMRL BC."); + return ret; + } + + return ret; +} + +/* i3c ccc setmwl_bc */ +static int cmd_i3c_ccc_setmwl_bc(const struct shell *shell_ctx, size_t argc, char **argv) +{ + const struct device *dev; + struct i3c_ccc_mwl mwl; + int ret; + + dev = device_get_binding(argv[ARGV_DEV]); + if (!dev) { + shell_error(shell_ctx, "I3C: Device driver %s not found.", argv[ARGV_DEV]); + return -ENODEV; + } + + mwl.len = strtol(argv[3], NULL, 16); + + ret = i3c_ccc_do_setmwl_all(dev, &mwl); + if (ret < 0) { + shell_error(shell_ctx, "I3C: unable to send CCC SETMWL BC."); + return ret; + } + + return ret; +} + +/* i3c ccc rstact_bc */ +static int cmd_i3c_ccc_rstact_bc(const struct shell *shell_ctx, size_t argc, char **argv) +{ + const struct device *dev; + enum i3c_ccc_rstact_defining_byte action; + int ret; + + dev = device_get_binding(argv[ARGV_DEV]); + if (!dev) { + shell_error(shell_ctx, "I3C: Device driver %s not found.", argv[ARGV_DEV]); + return -ENODEV; + } + + action = strtol(argv[2], NULL, 16); + + ret = i3c_ccc_do_rstact_all(dev, action); + if (ret < 0) { + shell_error(shell_ctx, "I3C: unable to send CCC RSTACT BC."); + return ret; + } + + return ret; +} + +/* i3c ccc enec_bc */ +static int cmd_i3c_ccc_enec_bc(const struct shell *shell_ctx, size_t argc, char **argv) +{ + const struct device *dev; + struct i3c_ccc_events events; + int ret; + + dev = device_get_binding(argv[ARGV_DEV]); + if (!dev) { + shell_error(shell_ctx, "I3C: Device driver %s not found.", argv[ARGV_DEV]); + return -ENODEV; + } + + events.events = strtol(argv[2], NULL, 16); + + ret = i3c_ccc_do_events_all_set(dev, true, &events); + if (ret < 0) { + shell_error(shell_ctx, "I3C: unable to send CCC ENEC BC."); + return ret; + } + + return ret; +} + +/* i3c ccc disec_bc */ +static int cmd_i3c_ccc_disec_bc(const struct shell *shell_ctx, size_t argc, char **argv) +{ + const struct device *dev; + struct i3c_ccc_events events; + int ret; + + dev = device_get_binding(argv[ARGV_DEV]); + if (!dev) { + shell_error(shell_ctx, "I3C: Device driver %s not found.", argv[ARGV_DEV]); + return -ENODEV; + } + + events.events = strtol(argv[2], NULL, 16); + + ret = i3c_ccc_do_events_all_set(dev, false, &events); + if (ret < 0) { + shell_error(shell_ctx, "I3C: unable to send CCC ENEC BC."); + return ret; + } + + return ret; +} + +/* i3c ccc enec */ +static int cmd_i3c_ccc_enec(const struct shell *shell_ctx, size_t argc, char **argv) +{ + const struct device *dev, *tdev; + struct i3c_device_desc *desc; + struct i3c_ccc_events events; + int ret; + + dev = device_get_binding(argv[ARGV_DEV]); + if (!dev) { + shell_error(shell_ctx, "I3C: Device driver %s not found.", argv[ARGV_DEV]); + return -ENODEV; + } + tdev = device_get_binding(argv[ARGV_TDEV]); + if (!tdev) { + shell_error(shell_ctx, "I3C: Device driver %s not found.", argv[ARGV_TDEV]); + return -ENODEV; + } + desc = get_i3c_attached_desc_from_dev_name(dev, tdev->name); + if (!desc) { + shell_error(shell_ctx, "I3C: Device %s not attached to bus.", tdev->name); + return -ENODEV; + } + + events.events = strtol(argv[3], NULL, 16); + + ret = i3c_ccc_do_events_set(desc, true, &events); + if (ret < 0) { + shell_error(shell_ctx, "I3C: unable to send CCC ENEC BC."); + return ret; + } + + return ret; +} + +/* i3c ccc disec */ +static int cmd_i3c_ccc_disec(const struct shell *shell_ctx, size_t argc, char **argv) +{ + const struct device *dev, *tdev; + struct i3c_device_desc *desc; + struct i3c_ccc_events events; + int ret; + + dev = device_get_binding(argv[ARGV_DEV]); + if (!dev) { + shell_error(shell_ctx, "I3C: Device driver %s not found.", argv[ARGV_DEV]); + return -ENODEV; + } + tdev = device_get_binding(argv[ARGV_TDEV]); + if (!tdev) { + shell_error(shell_ctx, "I3C: Device driver %s not found.", argv[ARGV_TDEV]); + return -ENODEV; + } + desc = get_i3c_attached_desc_from_dev_name(dev, tdev->name); + if (!desc) { + shell_error(shell_ctx, "I3C: Device %s not attached to bus.", tdev->name); + return -ENODEV; + } + + events.events = strtol(argv[3], NULL, 16); + + ret = i3c_ccc_do_events_set(desc, false, &events); + if (ret < 0) { + shell_error(shell_ctx, "I3C: unable to send CCC ENEC BC."); + return ret; + } + + return ret; +} + +/* i3c ccc getstatus [] */ +static int cmd_i3c_ccc_getstatus(const struct shell *shell_ctx, size_t argc, char **argv) +{ + const struct device *dev, *tdev; + struct i3c_device_desc *desc; + union i3c_ccc_getstatus status; + enum i3c_ccc_getstatus_fmt fmt; + enum i3c_ccc_getstatus_defbyte defbyte = GETSTATUS_FORMAT_2_INVALID; + int ret; + + dev = device_get_binding(argv[ARGV_DEV]); + if (!dev) { + shell_error(shell_ctx, "I3C: Device driver %s not found.", argv[ARGV_DEV]); + return -ENODEV; + } + tdev = device_get_binding(argv[ARGV_TDEV]); + if (!tdev) { + shell_error(shell_ctx, "I3C: Device driver %s not found.", argv[ARGV_TDEV]); + return -ENODEV; + } + desc = get_i3c_attached_desc_from_dev_name(dev, tdev->name); + if (!desc) { + shell_error(shell_ctx, "I3C: Device %s not attached to bus.", tdev->name); + return -ENODEV; + } + + /* If there is a defining byte, then it is assumed to be Format 2*/ + if (argc > 3) { + fmt = GETSTATUS_FORMAT_2; + defbyte = strtol(argv[3], NULL, 16); + if (defbyte != GETSTATUS_FORMAT_2_TGTSTAT || defbyte != GETSTATUS_FORMAT_2_PRECR) { + shell_error(shell_ctx, "Invalid defining byte."); + return -EINVAL; + } + } else { + fmt = GETSTATUS_FORMAT_1; + } + + ret = i3c_ccc_do_getstatus(desc, &status, fmt, defbyte); + if (ret < 0) { + shell_error(shell_ctx, "I3C: unable to send CCC GETSTATUS."); + return ret; + } + + if (fmt == GETSTATUS_FORMAT_2) { + if (defbyte == GETSTATUS_FORMAT_2_TGTSTAT) { + shell_print(shell_ctx, "TGTSTAT: 0x%04x", status.fmt2.tgtstat); + } else if (defbyte == GETSTATUS_FORMAT_2_PRECR) { + shell_print(shell_ctx, "PRECR: 0x%04x", status.fmt2.precr); + } + } else { + shell_print(shell_ctx, "Status: 0x%04x", status.fmt1.status); + } + + return ret; +} + +/* i3c ccc getcaps [] */ +static int cmd_i3c_ccc_getcaps(const struct shell *shell_ctx, size_t argc, char **argv) +{ + const struct device *dev, *tdev; + struct i3c_device_desc *desc; + union i3c_ccc_getcaps caps; + enum i3c_ccc_getcaps_fmt fmt; + enum i3c_ccc_getcaps_defbyte defbyte = GETCAPS_FORMAT_2_INVALID; + int ret; + + dev = device_get_binding(argv[ARGV_DEV]); + if (!dev) { + shell_error(shell_ctx, "I3C: Device driver %s not found.", argv[ARGV_DEV]); + return -ENODEV; + } + tdev = device_get_binding(argv[ARGV_TDEV]); + if (!tdev) { + shell_error(shell_ctx, "I3C: Device driver %s not found.", argv[ARGV_TDEV]); + return -ENODEV; + } + desc = get_i3c_attached_desc_from_dev_name(dev, tdev->name); + if (!desc) { + shell_error(shell_ctx, "I3C: Device %s not attached to bus.", tdev->name); + return -ENODEV; + } + + if (!(desc->bcr & I3C_BCR_ADV_CAPABILITIES)) { + shell_error(shell_ctx, "I3C: Device %s does not support advanced capabilities", + desc->dev->name); + return -ENOTSUP; + } + + /* If there is a defining byte, then it is assumed to be Format 2 */ + if (argc > 3) { + fmt = GETCAPS_FORMAT_2; + defbyte = strtol(argv[3], NULL, 16); + if (defbyte != GETCAPS_FORMAT_2_TGTCAPS || defbyte != GETCAPS_FORMAT_2_TESTPAT || + defbyte != GETCAPS_FORMAT_2_CRCAPS || defbyte != GETCAPS_FORMAT_2_VTCAPS || + defbyte != GETCAPS_FORMAT_2_DBGCAPS) { + shell_error(shell_ctx, "Invalid defining byte."); + return -EINVAL; + } + } else { + fmt = GETCAPS_FORMAT_1; + } + + ret = i3c_ccc_do_getcaps(desc, &caps, fmt, defbyte); + if (ret < 0) { + shell_error(shell_ctx, "I3C: unable to send CCC GETCAPS."); + return ret; + } + + if (fmt == GETCAPS_FORMAT_2) { + if (defbyte == GETCAPS_FORMAT_2_TGTCAPS) { + shell_print(shell_ctx, "TGTCAPS: 0x%02x; 0x%02x; 0x%02x; 0x%02x", + caps.fmt2.tgtcaps[0], caps.fmt2.tgtcaps[1], + caps.fmt2.tgtcaps[2], caps.fmt2.tgtcaps[3]); + } else if (defbyte == GETCAPS_FORMAT_2_TESTPAT) { + shell_print(shell_ctx, "TESTPAT: 0x%08x", caps.fmt2.testpat); + } else if (defbyte == GETCAPS_FORMAT_2_CRCAPS) { + shell_print(shell_ctx, "CRCAPS: 0x%02x; 0x%02x", caps.fmt2.crcaps[0], + caps.fmt2.crcaps[1]); + } else if (defbyte == GETCAPS_FORMAT_2_VTCAPS) { + shell_print(shell_ctx, "VTCAPS: 0x%02x; 0x%02x", caps.fmt2.vtcaps[0], + caps.fmt2.vtcaps[1]); + } + } else { + shell_print(shell_ctx, "GETCAPS: 0x%02x; 0x%02x; 0x%02x; 0x%02x", + caps.fmt1.getcaps[0], caps.fmt1.getcaps[1], caps.fmt1.getcaps[2], + caps.fmt1.getcaps[3]); + } + + return ret; +} + +static int cmd_i3c_attach(const struct shell *shell_ctx, size_t argc, char **argv) +{ + const struct device *dev, *tdev; + struct i3c_device_desc *desc; + int ret; + + dev = device_get_binding(argv[ARGV_DEV]); + if (!dev) { + shell_error(shell_ctx, "I3C: Device driver %s not found.", argv[ARGV_DEV]); + return -ENODEV; + } + tdev = device_get_binding(argv[ARGV_TDEV]); + if (!tdev) { + shell_error(shell_ctx, "I3C: Device driver %s not found.", argv[ARGV_TDEV]); + return -ENODEV; + } + desc = get_i3c_list_desc_from_dev_name(dev, tdev->name); + if (!desc) { + shell_error(shell_ctx, "I3C: Device %s not attached to bus.", tdev->name); + return -ENODEV; + } + + ret = i3c_attach_i3c_device(desc); + if (ret < 0) { + shell_error(shell_ctx, "I3C: unable to attach device %s.", tdev->name); + } + + return ret; +} + +static int cmd_i3c_reattach(const struct shell *shell_ctx, size_t argc, char **argv) +{ + const struct device *dev, *tdev; + struct i3c_device_desc *desc; + uint8_t old_dyn_addr = 0; + int ret; + + dev = device_get_binding(argv[ARGV_DEV]); + if (!dev) { + shell_error(shell_ctx, "I3C: Device driver %s not found.", argv[ARGV_DEV]); + return -ENODEV; + } + tdev = device_get_binding(argv[ARGV_TDEV]); + if (!tdev) { + shell_error(shell_ctx, "I3C: Device driver %s not found.", argv[ARGV_TDEV]); + return -ENODEV; + } + desc = get_i3c_attached_desc_from_dev_name(dev, tdev->name); + if (!desc) { + shell_error(shell_ctx, "I3C: Device %s not attached to bus.", tdev->name); + return -ENODEV; + } + + if (argc > 2) { + old_dyn_addr = strtol(argv[2], NULL, 16); + } + + ret = i3c_reattach_i3c_device(desc, old_dyn_addr); + if (ret < 0) { + shell_error(shell_ctx, "I3C: unable to reattach device %s.", tdev->name); + } + + return ret; +} + +static int cmd_i3c_detach(const struct shell *shell_ctx, size_t argc, char **argv) +{ + const struct device *dev, *tdev; + struct i3c_device_desc *desc; + int ret; + + dev = device_get_binding(argv[ARGV_DEV]); + if (!dev) { + shell_error(shell_ctx, "I3C: Device driver %s not found.", argv[ARGV_DEV]); + return -ENODEV; + } + tdev = device_get_binding(argv[ARGV_TDEV]); + if (!tdev) { + shell_error(shell_ctx, "I3C: Device driver %s not found.", argv[ARGV_TDEV]); + return -ENODEV; + } + desc = get_i3c_attached_desc_from_dev_name(dev, tdev->name); + if (!desc) { + shell_error(shell_ctx, "I3C: Device %s not attached to bus.", tdev->name); + return -ENODEV; + } + + ret = i3c_detach_i3c_device(desc); + if (ret < 0) { + shell_error(shell_ctx, "I3C: unable to detach device %s.", tdev->name); + } + + return ret; +} + +static int cmd_i3c_i2c_attach(const struct shell *shell_ctx, size_t argc, char **argv) +{ + const struct device *dev; + struct i3c_i2c_device_desc *desc; + uint16_t addr = 0; + int ret; + + dev = device_get_binding(argv[ARGV_DEV]); + if (!dev) { + shell_error(shell_ctx, "I3C: Device driver %s not found.", argv[ARGV_DEV]); + return -ENODEV; + } + addr = strtol(argv[2], NULL, 16); + desc = get_i3c_i2c_list_desc_from_addr(dev, addr); + if (!desc) { + shell_error(shell_ctx, "I3C: I2C addr 0x%02x not listed with the bus.", addr); + return -ENODEV; + } + + ret = i3c_attach_i2c_device(desc); + if (ret < 0) { + shell_error(shell_ctx, "I3C: unable to attach I2C addr 0x%02x.", addr); + } + + return ret; +} + +static int cmd_i3c_i2c_detach(const struct shell *shell_ctx, size_t argc, char **argv) +{ + const struct device *dev; + struct i3c_i2c_device_desc *desc; + uint16_t addr = 0; + int ret; + + dev = device_get_binding(argv[ARGV_DEV]); + if (!dev) { + shell_error(shell_ctx, "I3C: Device driver %s not found.", argv[ARGV_DEV]); + return -ENODEV; + } + addr = strtol(argv[2], NULL, 16); + desc = get_i3c_i2c_list_desc_from_addr(dev, addr); + if (!desc) { + shell_error(shell_ctx, "I3C: I2C addr 0x%02x not listed with the bus.", addr); + return -ENODEV; + } + + ret = i3c_detach_i2c_device(desc); + if (ret < 0) { + shell_error(shell_ctx, "I3C: unable to detach I2C addr 0x%02x.", addr); + } + + return ret; +} + +static void i3c_device_list_target_name_get(size_t idx, struct shell_static_entry *entry) +{ + if (idx < ARRAY_SIZE(i3c_list)) { + entry->syntax = i3c_list[idx].dev->name; + entry->handler = NULL; + entry->help = NULL; + entry->subcmd = i3c_list[idx].i3c_list_dev_subcmd; + } else { + entry->syntax = NULL; + } +} + +SHELL_DYNAMIC_CMD_CREATE(dsub_i3c_device_list_name, i3c_device_list_target_name_get); + +static void i3c_device_attached_target_name_get(size_t idx, struct shell_static_entry *entry) +{ + if (idx < ARRAY_SIZE(i3c_list)) { + entry->syntax = i3c_list[idx].dev->name; + entry->handler = NULL; + entry->help = NULL; + entry->subcmd = i3c_list[idx].i3c_attached_dev_subcmd; + } else { + entry->syntax = NULL; + } +} + +SHELL_DYNAMIC_CMD_CREATE(dsub_i3c_device_attached_name, i3c_device_attached_target_name_get); + +static void i3c_device_name_get(size_t idx, struct shell_static_entry *entry) +{ + if (idx < ARRAY_SIZE(i3c_list)) { + entry->syntax = i3c_list[idx].dev->name; + entry->handler = NULL; + entry->help = NULL; + entry->subcmd = NULL; + } else { + entry->syntax = NULL; + } +} + +SHELL_DYNAMIC_CMD_CREATE(dsub_i3c_device_name, i3c_device_name_get); + +/* L2 I3C CCC Shell Commands*/ +SHELL_STATIC_SUBCMD_SET_CREATE( + sub_i3c_ccc_cmds, + SHELL_CMD_ARG(rstdaa, &dsub_i3c_device_name, + "Send CCC RSTDAA\n" + "Usage: ccc rstdaa ", + cmd_i3c_ccc_rstdaa, 2, 0), + SHELL_CMD_ARG(entdaa, &dsub_i3c_device_name, + "Send CCC ENTDAA\n" + "Usage: ccc entdaa ", + cmd_i3c_ccc_entdaa, 2, 0), + SHELL_CMD_ARG(setdasa, &dsub_i3c_device_attached_name, + "Send CCC SETDASA\n" + "Usage: ccc setdasa ", + cmd_i3c_ccc_setdasa, 3, 0), + SHELL_CMD_ARG(setnewda, &dsub_i3c_device_attached_name, + "Send CCC SETNEWDA\n" + "Usage: ccc setnewda ", + cmd_i3c_ccc_setnewda, 4, 0), + SHELL_CMD_ARG(getbcr, &dsub_i3c_device_attached_name, + "Send CCC GETBCR\n" + "Usage: ccc getbcr ", + cmd_i3c_ccc_getbcr, 3, 0), + SHELL_CMD_ARG(getdcr, &dsub_i3c_device_attached_name, + "Send CCC GETDCR\n" + "Usage: ccc getdcr ", + cmd_i3c_ccc_getdcr, 3, 0), + SHELL_CMD_ARG(getpid, &dsub_i3c_device_attached_name, + "Send CCC GETPID\n" + "Usage: ccc getpid ", + cmd_i3c_ccc_getpid, 3, 0), + SHELL_CMD_ARG(getmrl, &dsub_i3c_device_attached_name, + "Send CCC GETMRL\n" + "Usage: ccc getmrl ", + cmd_i3c_ccc_getmrl, 3, 0), + SHELL_CMD_ARG(getmwl, &dsub_i3c_device_attached_name, + "Send CCC GETMWL\n" + "Usage: ccc getmwl ", + cmd_i3c_ccc_getmwl, 3, 0), + SHELL_CMD_ARG(setmrl, &dsub_i3c_device_attached_name, + "Send CCC SETMRL\n" + "Usage: ccc setmrl []", + cmd_i3c_ccc_setmrl, 4, 1), + SHELL_CMD_ARG(setmwl, &dsub_i3c_device_attached_name, + "Send CCC SETMWL\n" + "Usage: ccc setmwl ", + cmd_i3c_ccc_setmwl, 4, 0), + SHELL_CMD_ARG(setmrl_bc, &dsub_i3c_device_name, + "Send CCC SETMRL BC\n" + "Usage: ccc setmrl_bc []", + cmd_i3c_ccc_setmrl_bc, 3, 1), + SHELL_CMD_ARG(setmwl_bc, &dsub_i3c_device_name, + "Send CCC SETMWL BC\n" + "Usage: ccc setmwl_bc ", + cmd_i3c_ccc_setmwl_bc, 3, 0), + SHELL_CMD_ARG(rstact_bc, &dsub_i3c_device_name, + "Send CCC RSTACT BC\n" + "Usage: ccc rstact_bc ", + cmd_i3c_ccc_rstact_bc, 3, 0), + SHELL_CMD_ARG(enec_bc, &dsub_i3c_device_name, + "Send CCC ENEC BC\n" + "Usage: ccc enec_bc ", + cmd_i3c_ccc_enec_bc, 3, 0), + SHELL_CMD_ARG(disec_bc, &dsub_i3c_device_name, + "Send CCC DISEC BC\n" + "Usage: ccc disec_bc ", + cmd_i3c_ccc_disec_bc, 3, 0), + SHELL_CMD_ARG(enec, &dsub_i3c_device_attached_name, + "Send CCC ENEC\n" + "Usage: ccc enec ", + cmd_i3c_ccc_enec, 4, 0), + SHELL_CMD_ARG(disec, &dsub_i3c_device_attached_name, + "Send CCC DISEC\n" + "Usage: ccc disec ", + cmd_i3c_ccc_disec, 4, 0), + SHELL_CMD_ARG(getstatus, &dsub_i3c_device_attached_name, + "Send CCC GETSTATUS\n" + "Usage: ccc getstatus []", + cmd_i3c_ccc_getstatus, 3, 1), + SHELL_CMD_ARG(getcaps, &dsub_i3c_device_attached_name, + "Send CCC GETCAPS\n" + "Usage: ccc getcaps []", + cmd_i3c_ccc_getcaps, 3, 1), + SHELL_SUBCMD_SET_END /* Array terminated. */ +); + +/* L1 I3C Shell Commands*/ +SHELL_STATIC_SUBCMD_SET_CREATE( + sub_i3c_cmds, + SHELL_CMD_ARG(info, &dsub_i3c_device_attached_name, + "Get I3C device info\n" + "Usage: info []", + cmd_i3c_info, 2, 1), + SHELL_CMD_ARG(recover, &dsub_i3c_device_name, + "Recover I3C bus\n" + "Usage: recover ", + cmd_i3c_recover, 2, 0), + SHELL_CMD_ARG(read, &dsub_i3c_device_attached_name, + "Read bytes from an I3C device\n" + "Usage: read []", + cmd_i3c_read, 4, 1), + SHELL_CMD_ARG(read_byte, &dsub_i3c_device_attached_name, + "Read a byte from an I3C device\n" + "Usage: read_byte ", + cmd_i3c_read_byte, 4, 0), + SHELL_CMD_ARG(write, &dsub_i3c_device_attached_name, + "Write bytes to an I3C device\n" + "Usage: write [, ...]", + cmd_i3c_write, 4, MAX_I3C_BYTES), + SHELL_CMD_ARG(write_byte, &dsub_i3c_device_attached_name, + "Write a byte to an I3C device\n" + "Usage: write_byte ", + cmd_i3c_write_byte, 5, 0), + SHELL_CMD_ARG(i3c_attach, &dsub_i3c_device_list_name, + "Attach I3C device from the bus\n" + "Usage: i3c_attach ", + cmd_i3c_attach, 3, 0), + SHELL_CMD_ARG(i3c_reattach, &dsub_i3c_device_attached_name, + "Reattach I3C device from the bus\n" + "Usage: i3c_reattach []", + cmd_i3c_reattach, 3, 1), + SHELL_CMD_ARG(i3c_detach, &dsub_i3c_device_attached_name, + "Detach I3C device from the bus\n" + "Usage: i3c_detach ", + cmd_i3c_detach, 3, 0), + SHELL_CMD_ARG(i2c_attach, &dsub_i3c_device_name, + "Attach I2C device from the bus\n" + "Usage: i2c_attach ", + cmd_i3c_i2c_attach, 3, 0), + SHELL_CMD_ARG(i2c_detach, &dsub_i3c_device_name, + "Detach I2C device from the bus\n" + "Usage: i2c_detach ", + cmd_i3c_i2c_detach, 3, 0), + SHELL_CMD_ARG(ccc, &sub_i3c_ccc_cmds, + "Send I3C CCC\n" + "Usage: ccc ", + NULL, 3, 0), + SHELL_SUBCMD_SET_END /* Array terminated. */ +); + +SHELL_CMD_REGISTER(i3c, &sub_i3c_cmds, "I3C commands", NULL); diff --git a/drivers/ieee802154/Kconfig.nrf5 b/drivers/ieee802154/Kconfig.nrf5 index 9acb811e6b6..43217f8d37a 100644 --- a/drivers/ieee802154/Kconfig.nrf5 +++ b/drivers/ieee802154/Kconfig.nrf5 @@ -72,7 +72,7 @@ config IEEE802154_NRF5_FCS_IN_LENGTH config IEEE802154_NRF5_DELAY_TRX_ACC int "Clock accuracy for delayed operations" - default CLOCK_CONTROL_NRF_ACCURACY if CLOCK_CONTROL_NRF_ACCURACY < 255 + default CLOCK_CONTROL_NRF_ACCURACY if (CLOCK_CONTROL_NRF && (CLOCK_CONTROL_NRF_ACCURACY < 255)) default 255 help Accuracy of the clock used for scheduling radio delayed operations (delayed transmission diff --git a/drivers/ieee802154/ieee802154_nrf5.c b/drivers/ieee802154/ieee802154_nrf5.c index 4cbdd9eb607..77993ac9fbb 100644 --- a/drivers/ieee802154/ieee802154_nrf5.c +++ b/drivers/ieee802154/ieee802154_nrf5.c @@ -126,7 +126,11 @@ static void nrf5_get_eui64(uint8_t *mac) mac[index++] = (IEEE802154_NRF5_VENDOR_OUI >> 8) & 0xff; mac[index++] = IEEE802154_NRF5_VENDOR_OUI & 0xff; -#if defined(CONFIG_TRUSTED_EXECUTION_NONSECURE) && defined(NRF_FICR_S) +#if defined(NRF54H_SERIES) + /* Can't access SICR with device id on a radio core. Use BLE.ADDR. */ + deviceid[0] = NRF_FICR->BLE.ADDR[0]; + deviceid[1] = NRF_FICR->BLE.ADDR[1]; +#elif defined(CONFIG_TRUSTED_EXECUTION_NONSECURE) && defined(NRF_FICR_S) soc_secure_read_deviceid(deviceid); #else deviceid[0] = nrf_ficr_deviceid_get(NRF_FICR, 0); diff --git a/drivers/input/CMakeLists.txt b/drivers/input/CMakeLists.txt index 4131cca963f..bab58e5c6d3 100644 --- a/drivers/input/CMakeLists.txt +++ b/drivers/input/CMakeLists.txt @@ -21,6 +21,7 @@ zephyr_library_sources_ifdef(CONFIG_INPUT_ITE_IT8XXX2_KBD input_ite_it8xxx2_kbd. 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_PAT912X input_pat912x.c) +zephyr_library_sources_ifdef(CONFIG_INPUT_PAW32XX input_paw32xx.c) zephyr_library_sources_ifdef(CONFIG_INPUT_PINNACLE input_pinnacle.c) zephyr_library_sources_ifdef(CONFIG_INPUT_PMW3610 input_pmw3610.c) zephyr_library_sources_ifdef(CONFIG_INPUT_STMPE811 input_stmpe811.c) diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index 2312767cea9..e810b5b0914 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -23,6 +23,7 @@ source "drivers/input/Kconfig.it8xxx2" source "drivers/input/Kconfig.kbd_matrix" source "drivers/input/Kconfig.npcx" source "drivers/input/Kconfig.pat912x" +source "drivers/input/Kconfig.paw32xx" source "drivers/input/Kconfig.pinnacle" source "drivers/input/Kconfig.pmw3610" source "drivers/input/Kconfig.sdl" diff --git a/drivers/input/Kconfig.analog_axis b/drivers/input/Kconfig.analog_axis index 472b611acea..47f90e9fcb4 100644 --- a/drivers/input/Kconfig.analog_axis +++ b/drivers/input/Kconfig.analog_axis @@ -5,8 +5,8 @@ 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 + select ADC help ADC based analog axis input driver diff --git a/drivers/input/Kconfig.paw32xx b/drivers/input/Kconfig.paw32xx new file mode 100644 index 00000000000..652f3e773fb --- /dev/null +++ b/drivers/input/Kconfig.paw32xx @@ -0,0 +1,10 @@ +# Copyright 2024 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +config INPUT_PAW32XX + bool "PAW32xx ultra low power wireless mouse chip" + default y + depends on DT_HAS_PIXART_PAW32XX_ENABLED + select SPI + help + PAW32XX low power laser mouse sensor input driver diff --git a/drivers/input/input_analog_axis.c b/drivers/input/input_analog_axis.c index 832bd970fba..4217fdc7650 100644 --- a/drivers/input/input_analog_axis.c +++ b/drivers/input/input_analog_axis.c @@ -38,7 +38,7 @@ struct analog_axis_config { }; struct analog_axis_data { - struct k_mutex cal_lock; + struct k_sem cal_lock; analog_axis_raw_data_t raw_data_cb; struct k_timer timer; struct k_thread thread; @@ -66,9 +66,9 @@ int analog_axis_calibration_get(const struct device *dev, return -EINVAL; } - k_mutex_lock(&data->cal_lock, K_FOREVER); + k_sem_take(&data->cal_lock, K_FOREVER); memcpy(out_cal, cal, sizeof(struct analog_axis_calibration)); - k_mutex_unlock(&data->cal_lock); + k_sem_give(&data->cal_lock); return 0; } @@ -77,9 +77,9 @@ void analog_axis_set_raw_data_cb(const struct device *dev, analog_axis_raw_data_ { struct analog_axis_data *data = dev->data; - k_mutex_lock(&data->cal_lock, K_FOREVER); + k_sem_take(&data->cal_lock, K_FOREVER); data->raw_data_cb = cb; - k_mutex_unlock(&data->cal_lock); + k_sem_give(&data->cal_lock); } int analog_axis_calibration_set(const struct device *dev, @@ -94,9 +94,9 @@ int analog_axis_calibration_set(const struct device *dev, return -EINVAL; } - k_mutex_lock(&data->cal_lock, K_FOREVER); + k_sem_take(&data->cal_lock, K_FOREVER); memcpy(cal, new_cal, sizeof(struct analog_axis_calibration)); - k_mutex_unlock(&data->cal_lock); + k_sem_give(&data->cal_lock); return 0; } @@ -171,7 +171,7 @@ static void analog_axis_loop(const struct device *dev) return; } - k_mutex_lock(&data->cal_lock, K_FOREVER); + k_sem_take(&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]; @@ -203,7 +203,7 @@ static void analog_axis_loop(const struct device *dev) axis_data->last_out = out; } - k_mutex_unlock(&data->cal_lock); + k_sem_give(&data->cal_lock); } static void analog_axis_thread(void *arg1, void *arg2, void *arg3) @@ -244,7 +244,7 @@ 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); + k_sem_init(&data->cal_lock, 1, 1); tid = k_thread_create(&data->thread, data->thread_stack, K_KERNEL_STACK_SIZEOF(data->thread_stack), diff --git a/drivers/input/input_gpio_keys.c b/drivers/input/input_gpio_keys.c index 7fca24a55ed..fa27ca5bd64 100644 --- a/drivers/input/input_gpio_keys.c +++ b/drivers/input/input_gpio_keys.c @@ -106,6 +106,14 @@ static __maybe_unused void gpio_keys_change_deferred(struct k_work *work) const struct gpio_keys_config *cfg = dev->config; int key_index = pin_data - (struct gpio_keys_pin_data *)cfg->pin_data; +#ifdef CONFIG_PM_DEVICE + struct gpio_keys_data *data = dev->data; + + if (atomic_get(&data->suspended) == 1) { + return; + } +#endif + gpio_keys_poll_pin(dev, key_index); } diff --git a/drivers/input/input_ite_it8xxx2_kbd.c b/drivers/input/input_ite_it8xxx2_kbd.c index 5e62e6ee32e..5681b331833 100644 --- a/drivers/input/input_ite_it8xxx2_kbd.c +++ b/drivers/input/input_ite_it8xxx2_kbd.c @@ -16,6 +16,7 @@ #include #include #include +#include #include LOG_MODULE_REGISTER(input_ite_it8xxx2_kbd); @@ -58,24 +59,27 @@ 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; + const uint32_t kso_mask = BIT_MASK(common->col_size); + const uint8_t ksol_mask = kso_mask & 0xff; + const uint8_t ksoh1_mask = (kso_mask >> 8) & 0xff; + uint32_t kso_val; /* Tri-state all outputs */ if (col == INPUT_KBD_MATRIX_COLUMN_DRIVE_NONE) { - mask = 0x3ffff; + kso_val = kso_mask; /* Assert all outputs */ } else if (col == INPUT_KBD_MATRIX_COLUMN_DRIVE_ALL) { - mask = 0; + kso_val = 0; /* Assert a single output */ } else { - mask = 0x3ffff ^ BIT(col); + kso_val = kso_mask ^ BIT(col); } /* Set KSO[17:0] output data */ - inst->KBS_KSOL = (uint8_t) (mask & 0xff); - inst->KBS_KSOH1 = (uint8_t) ((mask >> 8) & 0xff); + inst->KBS_KSOL = (inst->KBS_KSOL & ~ksol_mask) | (kso_val & ksol_mask); + inst->KBS_KSOH1 = (inst->KBS_KSOH1 & ~ksoh1_mask) | ((kso_val >> 8) & ksoh1_mask); if (common->col_size > 16) { - inst->KBS_KSOH2 = (uint8_t) ((mask >> 16) & 0xff); + inst->KBS_KSOH2 = (kso_val >> 16) & 0xff; } } @@ -138,6 +142,9 @@ static int it8xxx2_kbd_init(const struct device *dev) 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; + const uint32_t kso_mask = BIT_MASK(common->col_size); + const uint8_t ksol_mask = kso_mask & 0xff; + const uint8_t ksoh1_mask = (kso_mask >> 8) & 0xff; int status; /* Disable wakeup and interrupt of KSI pins before configuring */ @@ -171,8 +178,8 @@ static int it8xxx2_kbd_init(const struct device *dev) } /* KSO[17:0] pins output low */ - inst->KBS_KSOL = 0x00; - inst->KBS_KSOH1 = 0x00; + inst->KBS_KSOL = inst->KBS_KSOL & ~ksol_mask; + inst->KBS_KSOH1 = inst->KBS_KSOH1 & ~ksoh1_mask; if (common->col_size > 16) { inst->KBS_KSOH2 = 0x00; } @@ -241,4 +248,4 @@ DEVICE_DT_INST_DEFINE(0, &it8xxx2_kbd_init, 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"); +BUILD_ASSERT(IN_RANGE(DT_INST_PROP(0, col_size), 1, 18), "invalid col-size"); diff --git a/drivers/input/input_paw32xx.c b/drivers/input/input_paw32xx.c new file mode 100644 index 00000000000..277da93bd52 --- /dev/null +++ b/drivers/input/input_paw32xx.c @@ -0,0 +1,467 @@ +/* + * Copyright 2024 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT pixart_paw32xx + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(input_paw32xx, CONFIG_INPUT_LOG_LEVEL); + +#define PAW32XX_PRODUCT_ID1 0x00 +#define PAW32XX_PRODUCT_ID2 0x01 +#define PAW32XX_MOTION 0x02 +#define PAW32XX_DELTA_X 0x03 +#define PAW32XX_DELTA_Y 0x04 +#define PAW32XX_OPERATION_MODE 0x05 +#define PAW32XX_CONFIGURATION 0x06 +#define PAW32XX_WRITE_PROTECT 0x09 +#define PAW32XX_SLEEP1 0x0a +#define PAW32XX_SLEEP2 0x0b +#define PAW32XX_SLEEP3 0x0c +#define PAW32XX_CPI_X 0x0d +#define PAW32XX_CPI_Y 0x0e +#define PAW32XX_DELTA_XY_HI 0x12 +#define PAW32XX_MOUSE_OPTION 0x19 + +#define PRODUCT_ID_PAW32XX 0x30 +#define SPI_WRITE BIT(7) + +#define MOTION_STATUS_MOTION BIT(7) +#define OPERATION_MODE_SLP_ENH BIT(4) +#define OPERATION_MODE_SLP2_ENH BIT(3) +#define OPERATION_MODE_SLP_MASK (OPERATION_MODE_SLP_ENH | OPERATION_MODE_SLP2_ENH) +#define CONFIGURATION_PD_ENH BIT(3) +#define CONFIGURATION_RESET BIT(7) +#define WRITE_PROTECT_ENABLE 0x00 +#define WRITE_PROTECT_DISABLE 0x5a +#define MOUSE_OPTION_MOVX_INV_BIT 3 +#define MOUSE_OPTION_MOVY_INV_BIT 4 + +#define PAW32XX_DATA_SIZE_BITS 12 + +#define RESET_DELAY_MS 2 + +#define RES_STEP 38 +#define RES_MIN (16 * RES_STEP) +#define RES_MAX (127 * RES_STEP) + +struct paw32xx_config { + struct spi_dt_spec spi; + struct gpio_dt_spec motion_gpio; + uint16_t axis_x; + uint16_t axis_y; + int16_t res_cpi; + bool invert_x; + bool invert_y; + bool force_awake; +}; + +struct paw32xx_data { + const struct device *dev; + struct k_work motion_work; + struct gpio_callback motion_cb; +}; + +static int paw32xx_read_reg(const struct device *dev, uint8_t addr, uint8_t *value) +{ + const struct paw32xx_config *cfg = dev->config; + + const struct spi_buf tx_buf = { + .buf = &addr, + .len = sizeof(addr), + }; + const struct spi_buf_set tx = { + .buffers = &tx_buf, + .count = 1, + }; + + struct spi_buf rx_buf[] = { + { + .buf = NULL, + .len = sizeof(addr), + }, + { + .buf = value, + .len = 1, + }, + }; + const struct spi_buf_set rx = { + .buffers = rx_buf, + .count = ARRAY_SIZE(rx_buf), + }; + + return spi_transceive_dt(&cfg->spi, &tx, &rx); +} + +static int paw32xx_write_reg(const struct device *dev, uint8_t addr, uint8_t value) +{ + const struct paw32xx_config *cfg = dev->config; + + uint8_t write_buf[] = {addr | SPI_WRITE, value}; + const struct spi_buf tx_buf = { + .buf = write_buf, + .len = sizeof(write_buf), + }; + const struct spi_buf_set tx = { + .buffers = &tx_buf, + .count = 1, + }; + + return spi_write_dt(&cfg->spi, &tx); +} + +static int paw32xx_update_reg(const struct device *dev, uint8_t addr, uint8_t mask, uint8_t value) +{ + uint8_t val; + int ret; + + ret = paw32xx_read_reg(dev, addr, &val); + if (ret < 0) { + return ret; + } + + val = (val & ~mask) | (value & mask); + + ret = paw32xx_write_reg(dev, addr, val); + if (ret < 0) { + return ret; + } + + return 0; +} + +static int paw32xx_read_xy(const struct device *dev, int16_t *x, int16_t *y) +{ + const struct paw32xx_config *cfg = dev->config; + int ret; + + uint8_t tx_data[] = { + PAW32XX_DELTA_X, + 0xff, + PAW32XX_DELTA_Y, + 0xff, + PAW32XX_DELTA_XY_HI, + 0xff, + }; + uint8_t rx_data[sizeof(tx_data)]; + + const struct spi_buf tx_buf = { + .buf = tx_data, + .len = sizeof(tx_data), + }; + const struct spi_buf_set tx = { + .buffers = &tx_buf, + .count = 1, + }; + + struct spi_buf rx_buf = { + .buf = rx_data, + .len = sizeof(rx_data), + }; + const struct spi_buf_set rx = { + .buffers = &rx_buf, + .count = 1, + }; + + ret = spi_transceive_dt(&cfg->spi, &tx, &rx); + if (ret < 0) { + return ret; + } + + *x = ((rx_data[5] << 4) & 0xf00) | rx_data[1]; + *y = ((rx_data[5] << 8) & 0xf00) | rx_data[3]; + + *x = sign_extend(*x, PAW32XX_DATA_SIZE_BITS - 1); + *y = sign_extend(*y, PAW32XX_DATA_SIZE_BITS - 1); + + return 0; +} + +static void paw32xx_motion_work_handler(struct k_work *work) +{ + struct paw32xx_data *data = CONTAINER_OF( + work, struct paw32xx_data, motion_work); + const struct device *dev = data->dev; + const struct paw32xx_config *cfg = dev->config; + uint8_t val; + int16_t x, y; + int ret; + + ret = paw32xx_read_reg(dev, PAW32XX_MOTION, &val); + if (ret < 0) { + return; + } + + if ((val & MOTION_STATUS_MOTION) == 0x00) { + return; + } + + ret = paw32xx_read_xy(dev, &x, &y); + if (ret < 0) { + return; + } + + LOG_DBG("x=%4d y=%4d", x, y); + + input_report_rel(data->dev, cfg->axis_x, x, false, K_FOREVER); + input_report_rel(data->dev, cfg->axis_y, y, true, K_FOREVER); + + /* Trigger one more scan in case more data is available. */ + k_work_submit(&data->motion_work); +} + +static void paw32xx_motion_handler(const struct device *gpio_dev, + struct gpio_callback *cb, + uint32_t pins) +{ + struct paw32xx_data *data = CONTAINER_OF( + cb, struct paw32xx_data, motion_cb); + + k_work_submit(&data->motion_work); +} + +int paw32xx_set_resolution(const struct device *dev, uint16_t res_cpi) +{ + uint8_t val; + int ret; + + if (!IN_RANGE(res_cpi, RES_MIN, RES_MAX)) { + LOG_ERR("res_cpi out of range: %d", res_cpi); + return -EINVAL; + } + + val = res_cpi / RES_STEP; + + ret = paw32xx_write_reg(dev, PAW32XX_WRITE_PROTECT, WRITE_PROTECT_DISABLE); + if (ret < 0) { + return ret; + } + + ret = paw32xx_write_reg(dev, PAW32XX_CPI_X, val); + if (ret < 0) { + return ret; + } + + ret = paw32xx_write_reg(dev, PAW32XX_CPI_Y, val); + if (ret < 0) { + return ret; + } + + ret = paw32xx_write_reg(dev, PAW32XX_WRITE_PROTECT, WRITE_PROTECT_ENABLE); + if (ret < 0) { + return ret; + } + + return 0; +} + +int paw32xx_force_awake(const struct device *dev, bool enable) +{ + uint8_t val = enable ? 0 : OPERATION_MODE_SLP_MASK; + int ret; + + ret = paw32xx_write_reg(dev, PAW32XX_WRITE_PROTECT, WRITE_PROTECT_DISABLE); + if (ret < 0) { + return ret; + } + + ret = paw32xx_update_reg(dev, PAW32XX_OPERATION_MODE, + OPERATION_MODE_SLP_MASK, val); + if (ret < 0) { + return ret; + } + + ret = paw32xx_write_reg(dev, PAW32XX_WRITE_PROTECT, WRITE_PROTECT_ENABLE); + if (ret < 0) { + return ret; + } + + return 0; +} + +static int paw32xx_configure(const struct device *dev) +{ + const struct paw32xx_config *cfg = dev->config; + uint8_t val; + int ret; + + ret = paw32xx_read_reg(dev, PAW32XX_PRODUCT_ID1, &val); + if (ret < 0) { + return ret; + } + + if (val != PRODUCT_ID_PAW32XX) { + LOG_ERR("Invalid product id: %02x", val); + return -ENOTSUP; + } + + ret = paw32xx_update_reg(dev, PAW32XX_CONFIGURATION, + CONFIGURATION_RESET, CONFIGURATION_RESET); + if (ret < 0) { + return ret; + } + + k_sleep(K_MSEC(RESET_DELAY_MS)); + + if (cfg->invert_x || cfg->invert_y) { + ret = paw32xx_write_reg(dev, PAW32XX_WRITE_PROTECT, WRITE_PROTECT_DISABLE); + if (ret < 0) { + return ret; + } + + ret = paw32xx_read_reg(dev, PAW32XX_MOUSE_OPTION, &val); + if (ret < 0) { + return ret; + } + + WRITE_BIT(val, MOUSE_OPTION_MOVX_INV_BIT, cfg->invert_x); + WRITE_BIT(val, MOUSE_OPTION_MOVY_INV_BIT, cfg->invert_y); + + ret = paw32xx_write_reg(dev, PAW32XX_MOUSE_OPTION, val); + if (ret < 0) { + return ret; + } + + ret = paw32xx_write_reg(dev, PAW32XX_WRITE_PROTECT, WRITE_PROTECT_ENABLE); + if (ret < 0) { + return ret; + } + } + + if (cfg->res_cpi > 0) { + paw32xx_set_resolution(dev, cfg->res_cpi); + } + + paw32xx_force_awake(dev, cfg->force_awake); + + return 0; +} + +static int paw32xx_init(const struct device *dev) +{ + const struct paw32xx_config *cfg = dev->config; + struct paw32xx_data *data = dev->data; + int ret; + + if (!spi_is_ready_dt(&cfg->spi)) { + LOG_ERR("%s is not ready", cfg->spi.bus->name); + return -ENODEV; + } + + data->dev = dev; + + k_work_init(&data->motion_work, paw32xx_motion_work_handler); + + if (!gpio_is_ready_dt(&cfg->motion_gpio)) { + LOG_ERR("%s is not ready", cfg->motion_gpio.port->name); + return -ENODEV; + } + + ret = gpio_pin_configure_dt(&cfg->motion_gpio, GPIO_INPUT); + if (ret != 0) { + LOG_ERR("Motion pin configuration failed: %d", ret); + return ret; + } + + gpio_init_callback(&data->motion_cb, paw32xx_motion_handler, + BIT(cfg->motion_gpio.pin)); + + ret = gpio_add_callback_dt(&cfg->motion_gpio, &data->motion_cb); + if (ret < 0) { + LOG_ERR("Could not set motion callback: %d", ret); + return ret; + } + + ret = paw32xx_configure(dev); + if (ret != 0) { + LOG_ERR("Device configuration failed: %d", ret); + return ret; + } + + ret = gpio_pin_interrupt_configure_dt(&cfg->motion_gpio, + GPIO_INT_EDGE_TO_ACTIVE); + if (ret != 0) { + LOG_ERR("Motion interrupt configuration failed: %d", ret); + return ret; + } + + ret = pm_device_runtime_enable(dev); + if (ret < 0) { + LOG_ERR("Failed to enable runtime power management: %d", ret); + return ret; + } + + return 0; +} + +#ifdef CONFIG_PM_DEVICE +static int paw32xx_pm_action(const struct device *dev, + enum pm_device_action action) +{ + int ret; + uint8_t val; + + switch (action) { + case PM_DEVICE_ACTION_SUSPEND: + val = CONFIGURATION_PD_ENH; + break; + case PM_DEVICE_ACTION_RESUME: + val = 0; + break; + default: + return -ENOTSUP; + } + + ret = paw32xx_update_reg(dev, PAW32XX_CONFIGURATION, + CONFIGURATION_PD_ENH, val); + if (ret < 0) { + return ret; + } + + return 0; +} +#endif + +#define PAW32XX_SPI_MODE (SPI_OP_MODE_MASTER | SPI_WORD_SET(8) | \ + SPI_MODE_CPOL | SPI_MODE_CPHA | SPI_TRANSFER_MSB) + +#define PAW32XX_INIT(n) \ + BUILD_ASSERT(IN_RANGE(DT_INST_PROP_OR(n, res_cpi, RES_MIN), \ + RES_MIN, RES_MAX), "invalid res-cpi"); \ + \ + static const struct paw32xx_config paw32xx_cfg_##n = { \ + .spi = SPI_DT_SPEC_INST_GET(n, PAW32XX_SPI_MODE, 0), \ + .motion_gpio = GPIO_DT_SPEC_INST_GET(n, motion_gpios), \ + .axis_x = DT_INST_PROP(n, zephyr_axis_x), \ + .axis_y = DT_INST_PROP(n, zephyr_axis_y), \ + .res_cpi = DT_INST_PROP_OR(n, res_cpi, -1), \ + .invert_x = DT_INST_PROP(n, invert_x), \ + .invert_y = DT_INST_PROP(n, invert_y), \ + .force_awake = DT_INST_PROP(n, force_awake), \ + }; \ + \ + static struct paw32xx_data paw32xx_data_##n; \ + \ + PM_DEVICE_DT_INST_DEFINE(n, paw32xx_pm_action); \ + \ + DEVICE_DT_INST_DEFINE(n, paw32xx_init, PM_DEVICE_DT_INST_GET(n), \ + &paw32xx_data_##n, &paw32xx_cfg_##n, \ + POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY, \ + NULL); + +DT_INST_FOREACH_STATUS_OKAY(PAW32XX_INIT) diff --git a/drivers/interrupt_controller/CMakeLists.txt b/drivers/interrupt_controller/CMakeLists.txt index 0df052e6045..9e07386e59e 100644 --- a/drivers/interrupt_controller/CMakeLists.txt +++ b/drivers/interrupt_controller/CMakeLists.txt @@ -33,6 +33,8 @@ zephyr_library_sources_ifdef(CONFIG_VEXRISCV_LITEX_IRQ intc_vexriscv_litex. 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_NRFX_CLIC intc_nrfx_clic.c) +zephyr_library_sources_ifdef(CONFIG_NRFX_CLIC intc_nrfx_clic.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) diff --git a/drivers/interrupt_controller/Kconfig.clic b/drivers/interrupt_controller/Kconfig.clic index a047a832331..fff8d1dffad 100644 --- a/drivers/interrupt_controller/Kconfig.clic +++ b/drivers/interrupt_controller/Kconfig.clic @@ -10,9 +10,20 @@ config NUCLEI_ECLIC help Interrupt controller for Nuclei SoC core. +config NRFX_CLIC + bool "VPR Core Local Interrpt Controller (CLIC)" + default y + depends on DT_HAS_NORDIC_NRF_CLIC_ENABLED + help + Interrupt controller for Nordic VPR cores. + +if NUCLEI_ECLIC + 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. + +endif # NUCLEI_ECLIC diff --git a/drivers/interrupt_controller/intc_nrfx_clic.S b/drivers/interrupt_controller/intc_nrfx_clic.S new file mode 100644 index 00000000000..05b2d4a1912 --- /dev/null +++ b/drivers/interrupt_controller/intc_nrfx_clic.S @@ -0,0 +1,15 @@ +/* + * Copyright (C) 2024 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/* Exports */ +GTEXT(__soc_handle_irq) + +/* + * No need to clear anything, pending bit is cleared by HW. + */ +SECTION_FUNC(exception.other, __soc_handle_irq) + ret diff --git a/drivers/interrupt_controller/intc_nrfx_clic.c b/drivers/interrupt_controller/intc_nrfx_clic.c new file mode 100644 index 00000000000..7d6629e3769 --- /dev/null +++ b/drivers/interrupt_controller/intc_nrfx_clic.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2024, Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +void riscv_clic_irq_enable(uint32_t irq) +{ + nrf_vpr_clic_int_enable_set(NRF_VPRCLIC, irq, true); +} + +void riscv_clic_irq_disable(uint32_t irq) +{ + nrf_vpr_clic_int_enable_set(NRF_VPRCLIC, irq, false); +} + +int riscv_clic_irq_is_enabled(uint32_t irq) +{ + return nrf_vpr_clic_int_enable_check(NRF_VPRCLIC, irq); +} + +void riscv_clic_irq_priority_set(uint32_t irq, uint32_t pri, uint32_t flags) +{ + nrf_vpr_clic_int_priority_set(NRF_VPRCLIC, irq, NRF_VPR_CLIC_INT_TO_PRIO(pri)); +} + +void riscv_clic_irq_set_pending(uint32_t irq) +{ + nrf_vpr_clic_int_pending_set(NRF_VPRCLIC, irq); +} diff --git a/drivers/interrupt_controller/intc_nxp_pint.c b/drivers/interrupt_controller/intc_nxp_pint.c index 80a20abe4bd..2a11fd7ad45 100644 --- a/drivers/interrupt_controller/intc_nxp_pint.c +++ b/drivers/interrupt_controller/intc_nxp_pint.c @@ -99,6 +99,7 @@ int nxp_pint_pin_enable(uint8_t pin, enum nxp_pint_trigger trigger, bool wake) EnableDeepSleepIRQ(pint_irq_cfg[slot].irq); } else { DisableDeepSleepIRQ(pint_irq_cfg[slot].irq); + irq_enable(pint_irq_cfg[slot].irq); } #endif return 0; diff --git a/drivers/interrupt_controller/intc_system_apic.c b/drivers/interrupt_controller/intc_system_apic.c index b9ad0b70bbf..6089e453405 100644 --- a/drivers/interrupt_controller/intc_system_apic.c +++ b/drivers/interrupt_controller/intc_system_apic.c @@ -19,7 +19,7 @@ #include #include -#define IS_IOAPIC_IRQ(irq) (irq < z_loapic_irq_base()) +#define IS_IOAPIC_IRQ(irq) ((irq) < z_loapic_irq_base()) #define HARDWARE_IRQ_LIMIT ((z_loapic_irq_base() + LOAPIC_IRQ_COUNT) - 1) /** diff --git a/drivers/ipm/Kconfig.imx b/drivers/ipm/Kconfig.imx index 67fbc370ac8..743c7d9c6a5 100644 --- a/drivers/ipm/Kconfig.imx +++ b/drivers/ipm/Kconfig.imx @@ -5,6 +5,7 @@ config IPM_MCUX bool "MCUX IPM driver" default y depends on DT_HAS_NXP_LPC_MAILBOX_ENABLED + select RESET help Driver for MCUX mailbox diff --git a/drivers/ipm/ipm_mcux.c b/drivers/ipm/ipm_mcux.c index 2365f58aacc..e323dc9ec78 100644 --- a/drivers/ipm/ipm_mcux.c +++ b/drivers/ipm/ipm_mcux.c @@ -14,6 +14,8 @@ #include #include #include +#include +#include #define MCUX_IPM_DATA_REGS 1 #define MCUX_IPM_MAX_ID_VAL 0 @@ -36,9 +38,12 @@ #endif #endif +#define MAILBOX_USES_RESET COND_CODE_1(DT_ANY_INST_HAS_PROP_STATUS_OKAY(resets), (true), (false)) + struct mcux_mailbox_config { MAILBOX_Type *base; void (*irq_config_func)(const struct device *dev); + const struct reset_dt_spec reset; }; struct mcux_mailbox_data { @@ -143,10 +148,34 @@ static int mcux_mailbox_ipm_set_enabled(const struct device *d, int enable) return 0; } +static inline int mcux_mailbox_reset(const struct device *dev) +{ + const struct mcux_mailbox_config *config = dev->config; + int ret = 0; + + /* on some platforms, explicit reset is not needed or possible for the mailbox */ + if (!MAILBOX_USES_RESET) { + return 0; + } + + if (!device_is_ready(config->reset.dev)) { + ret = -ENODEV; + } else { + ret = reset_line_toggle(config->reset.dev, config->reset.id); + } + + return ret; +} static int mcux_mailbox_init(const struct device *dev) { const struct mcux_mailbox_config *config = dev->config; + int ret = 0; + + ret = mcux_mailbox_reset(dev); + if (ret) { + return ret; + } MAILBOX_Init(config->base); config->irq_config_func(dev); @@ -169,6 +198,7 @@ static void mcux_mailbox_config_func_0(const struct device *dev); static const struct mcux_mailbox_config mcux_mailbox_0_config = { .base = (MAILBOX_Type *)DT_INST_REG_ADDR(0), .irq_config_func = mcux_mailbox_config_func_0, + .reset = RESET_DT_SPEC_INST_GET_OR(0, {0}), }; static struct mcux_mailbox_data mcux_mailbox_0_data; diff --git a/drivers/kscan/CMakeLists.txt b/drivers/kscan/CMakeLists.txt index 5e846edcb36..1108cd61629 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_HT16K33 kscan_ht16k33.c) zephyr_library_sources_ifdef(CONFIG_KSCAN_INPUT kscan_input.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE kscan_handlers.c) diff --git a/drivers/kscan/Kconfig b/drivers/kscan/Kconfig index de9b79255ea..ed0910bbd27 100644 --- a/drivers/kscan/Kconfig +++ b/drivers/kscan/Kconfig @@ -10,7 +10,6 @@ menuconfig KSCAN if KSCAN -source "drivers/kscan/Kconfig.ht16k33" source "drivers/kscan/Kconfig.input" module = KSCAN diff --git a/drivers/kscan/Kconfig.ht16k33 b/drivers/kscan/Kconfig.ht16k33 deleted file mode 100644 index ef16347ede2..00000000000 --- a/drivers/kscan/Kconfig.ht16k33 +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) 2019 - 2021 Henrik Brix Andersen -# SPDX-License-Identifier: Apache-2.0 - -config KSCAN_HT16K33 - bool "HT16K33 keyscan driver" - default y - depends on DT_HAS_HOLTEK_HT16K33_KEYSCAN_ENABLED - help - Enable keyscan driver for HT16K33. - - The HT16K33 is a memory mapping, multifunction LED - controller driver. The controller supports matrix key scan - circuit of up to 13x3 keys. diff --git a/drivers/kscan/kscan_ht16k33.c b/drivers/kscan/kscan_ht16k33.c deleted file mode 100644 index 9595874e908..00000000000 --- a/drivers/kscan/kscan_ht16k33.c +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2019 - 2021 Henrik Brix Andersen - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#define DT_DRV_COMPAT holtek_ht16k33_keyscan - -/** - * @file - * @brief Keyscan driver for the HT16K33 I2C LED driver - */ - -#include -#include -#include -#include - -LOG_MODULE_REGISTER(kscan_ht16k33, CONFIG_KSCAN_LOG_LEVEL); - -BUILD_ASSERT(CONFIG_KSCAN_INIT_PRIORITY > CONFIG_LED_INIT_PRIORITY, - "HT16K33 keyscan driver must be initialized after HT16K33 LED driver"); - -struct kscan_ht16k33_cfg { - const struct device *parent; -}; - -static int kscan_ht16k33_config(const struct device *dev, - kscan_callback_t callback) -{ - const struct kscan_ht16k33_cfg *config = dev->config; - - return ht16k33_register_keyscan_callback(config->parent, dev, callback); -} - -static int kscan_ht16k33_init(const struct device *dev) -{ - const struct kscan_ht16k33_cfg *config = dev->config; - - if (!device_is_ready(config->parent)) { - LOG_ERR("HT16K33 parent device not ready"); - return -EINVAL; - } - - return 0; -} - -static const struct kscan_driver_api kscan_ht16k33_api = { - .config = kscan_ht16k33_config, -}; - -#define KSCAN_HT16K33_DEVICE(id) \ - static const struct kscan_ht16k33_cfg kscan_ht16k33_##id##_cfg = { \ - .parent = DEVICE_DT_GET(DT_INST_BUS(id)), \ - }; \ - \ - DEVICE_DT_INST_DEFINE(id, &kscan_ht16k33_init, \ - NULL, NULL, \ - &kscan_ht16k33_##id##_cfg, POST_KERNEL, \ - CONFIG_KSCAN_INIT_PRIORITY, \ - &kscan_ht16k33_api); - -DT_INST_FOREACH_STATUS_OKAY(KSCAN_HT16K33_DEVICE) diff --git a/drivers/led/Kconfig.ht16k33 b/drivers/led/Kconfig.ht16k33 index 6fd72d53837..1addae0436b 100644 --- a/drivers/led/Kconfig.ht16k33 +++ b/drivers/led/Kconfig.ht16k33 @@ -15,8 +15,7 @@ menuconfig HT16K33 config HT16K33_KEYSCAN bool "Keyscan support" - depends on (HT16K33 && KSCAN) - select KSCAN_HT16K33 + depends on (HT16K33 && INPUT) help Enable keyscan child device support in the HT16K33 LED driver. diff --git a/drivers/led/ht16k33.c b/drivers/led/ht16k33.c index 8df5b7553f6..07a1ae56ca1 100644 --- a/drivers/led/ht16k33.c +++ b/drivers/led/ht16k33.c @@ -13,9 +13,9 @@ #include #include +#include #include #include -#include #include #include @@ -77,7 +77,6 @@ struct ht16k33_data { #ifdef CONFIG_HT16K33_KEYSCAN struct k_mutex lock; const struct device *child; - kscan_callback_t kscan_cb; struct gpio_callback irq_cb; struct k_thread irq_thread; struct k_sem irq_sem; @@ -230,15 +229,13 @@ static bool ht16k33_process_keyscan_data(const struct device *dev) pressed = true; } - if (data->kscan_cb == NULL) { - continue; - } - for (col = 0; col < HT16K33_KEYSCAN_COLS; col++) { - if (changed & BIT(col)) { - data->kscan_cb(data->child, row, col, - state & BIT(col)); + if ((changed & BIT(col)) == 0) { + continue; } + input_report_abs(dev, INPUT_ABS_X, col, false, K_FOREVER); + input_report_abs(dev, INPUT_ABS_Y, row, false, K_FOREVER); + input_report_key(dev, INPUT_BTN_TOUCH, state & BIT(col), true, K_FOREVER); } } @@ -285,20 +282,6 @@ static void ht16k33_timer_callback(struct k_timer *timer) data = CONTAINER_OF(timer, struct ht16k33_data, timer); k_sem_give(&data->irq_sem); } - -int ht16k33_register_keyscan_callback(const struct device *parent, - const struct device *child, - kscan_callback_t callback) -{ - struct ht16k33_data *data = parent->data; - - k_mutex_lock(&data->lock, K_FOREVER); - data->child = child; - data->kscan_cb = callback; - k_mutex_unlock(&data->lock); - - return 0; -} #endif /* CONFIG_HT16K33_KEYSCAN */ static int ht16k33_init(const struct device *dev) diff --git a/drivers/led/led_shell.c b/drivers/led/led_shell.c index 10364b43a59..3e26c915c3c 100644 --- a/drivers/led/led_shell.c +++ b/drivers/led/led_shell.c @@ -307,21 +307,32 @@ cmd_write_channels(const struct shell *sh, size_t argc, char **argv) return err; } -SHELL_STATIC_SUBCMD_SET_CREATE(sub_led, - SHELL_CMD_ARG(off, NULL, " ", cmd_off, 3, 0), - SHELL_CMD_ARG(on, NULL, " ", cmd_on, 3, 0), - SHELL_CMD_ARG(get_info, NULL, " ", cmd_get_info, 3, 0), - SHELL_CMD_ARG(set_brightness, NULL, " ", +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( + sub_led, SHELL_CMD_ARG(off, &dsub_device_name, " ", cmd_off, 3, 0), + SHELL_CMD_ARG(on, &dsub_device_name, " ", cmd_on, 3, 0), + SHELL_CMD_ARG(get_info, &dsub_device_name, " ", cmd_get_info, 3, 0), + SHELL_CMD_ARG(set_brightness, &dsub_device_name, " ", cmd_set_brightness, 4, 0), - SHELL_CMD_ARG(set_color, NULL, - " ... ", - cmd_set_color, 4, MAX_CHANNEL_ARGS - 1), - SHELL_CMD_ARG(set_channel, NULL, " ", + SHELL_CMD_ARG(set_color, &dsub_device_name, + " ... ", cmd_set_color, 4, + MAX_CHANNEL_ARGS - 1), + SHELL_CMD_ARG(set_channel, &dsub_device_name, " ", cmd_set_channel, 4, 0), - SHELL_CMD_ARG(write_channels, NULL, - " ... ", - cmd_write_channels, 4, MAX_CHANNEL_ARGS - 1), - SHELL_SUBCMD_SET_END -); + SHELL_CMD_ARG(write_channels, &dsub_device_name, + " ... ", cmd_write_channels, 4, + MAX_CHANNEL_ARGS - 1), + SHELL_SUBCMD_SET_END); SHELL_CMD_REGISTER(led, &sub_led, "LED commands", NULL); diff --git a/drivers/led/ncp5623.c b/drivers/led/ncp5623.c index 0fd0f128d37..b197ab89842 100644 --- a/drivers/led/ncp5623.c +++ b/drivers/led/ncp5623.c @@ -156,7 +156,7 @@ static int ncp5623_led_init(const struct device *dev) } } else if (config->num_leds <= 3) { /* three single-channel LEDs */ for (i = 0; i < config->num_leds; i++) { - led_info = ncp5623_led_to_info(config, 0); + led_info = ncp5623_led_to_info(config, i); if (!led_info) { return -ENODEV; diff --git a/drivers/led_strip/CMakeLists.txt b/drivers/led_strip/CMakeLists.txt index aa4e95722a7..b293782e620 100644 --- a/drivers/led_strip/CMakeLists.txt +++ b/drivers/led_strip/CMakeLists.txt @@ -9,3 +9,4 @@ 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) +zephyr_library_sources_ifdef(CONFIG_TLC59731_STRIP tlc59731.c) diff --git a/drivers/led_strip/Kconfig b/drivers/led_strip/Kconfig index 269657dd0b8..3be80de4729 100644 --- a/drivers/led_strip/Kconfig +++ b/drivers/led_strip/Kconfig @@ -35,4 +35,6 @@ source "drivers/led_strip/Kconfig.apa102" source "drivers/led_strip/Kconfig.tlc5971" +source "drivers/led_strip/Kconfig.tlc59731" + endif # LED_STRIP diff --git a/drivers/led_strip/Kconfig.tlc59731 b/drivers/led_strip/Kconfig.tlc59731 new file mode 100644 index 00000000000..3857c08dc5f --- /dev/null +++ b/drivers/led_strip/Kconfig.tlc59731 @@ -0,0 +1,11 @@ +# Copyright (c) 2024 Javad Rahimipetroudi +# SPDX-License-Identifier: Apache-2.0 + +config TLC59731_STRIP + bool "TLC59731 LED controller" + default y + depends on DT_HAS_TI_TLC59731_ENABLED + select GPIO + help + Enable driver for the Texas Instruments TLC59731 EasySet LED + controllers. diff --git a/drivers/led_strip/apa102.c b/drivers/led_strip/apa102.c index cea394d7901..9f7de642358 100644 --- a/drivers/led_strip/apa102.c +++ b/drivers/led_strip/apa102.c @@ -14,6 +14,7 @@ struct apa102_config { struct spi_dt_spec bus; + size_t length; }; static int apa102_update(const struct device *dev, void *buf, size_t size) @@ -73,11 +74,11 @@ static int apa102_update_rgb(const struct device *dev, struct led_rgb *pixels, return apa102_update(dev, pixels, sizeof(struct led_rgb) * count); } -static int apa102_update_channels(const struct device *dev, uint8_t *channels, - size_t num_channels) +static size_t apa102_length(const struct device *dev) { - /* Not implemented */ - return -EINVAL; + const struct apa102_config *config = dev->config; + + return config->length; } static int apa102_init(const struct device *dev) @@ -93,7 +94,7 @@ static int apa102_init(const struct device *dev) static const struct led_strip_driver_api apa102_api = { .update_rgb = apa102_update_rgb, - .update_channels = apa102_update_channels, + .length = apa102_length, }; #define APA102_DEVICE(idx) \ @@ -102,6 +103,7 @@ static const struct led_strip_driver_api apa102_api = { idx, \ SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB | SPI_WORD_SET(8), \ 0), \ + .length = DT_INST_PROP(idx, chain_length), \ }; \ \ DEVICE_DT_INST_DEFINE(idx, \ diff --git a/drivers/led_strip/lpd880x.c b/drivers/led_strip/lpd880x.c index a1fa90e6415..991e2e3fb57 100644 --- a/drivers/led_strip/lpd880x.c +++ b/drivers/led_strip/lpd880x.c @@ -36,6 +36,7 @@ LOG_MODULE_REGISTER(lpd880x); struct lpd880x_config { struct spi_dt_spec bus; + size_t length; }; static int lpd880x_update(const struct device *dev, void *data, size_t size) @@ -125,6 +126,13 @@ static int lpd880x_strip_update_channels(const struct device *dev, return lpd880x_update(dev, channels, num_channels); } +static size_t lpd880x_strip_length(const struct device *dev) +{ + const struct lpd880x_config *config = dev->config; + + return config->length; +} + static int lpd880x_strip_init(const struct device *dev) { const struct lpd880x_config *config = dev->config; @@ -138,12 +146,14 @@ static int lpd880x_strip_init(const struct device *dev) } static const struct lpd880x_config lpd880x_config = { - .bus = SPI_DT_SPEC_INST_GET(0, LPD880X_SPI_OPERATION, 0) + .bus = SPI_DT_SPEC_INST_GET(0, LPD880X_SPI_OPERATION, 0), + .length = DT_INST_PROP(0, chain_length), }; static const struct led_strip_driver_api lpd880x_strip_api = { .update_rgb = lpd880x_strip_update_rgb, .update_channels = lpd880x_strip_update_channels, + .length = lpd880x_strip_length, }; DEVICE_DT_INST_DEFINE(0, lpd880x_strip_init, NULL, diff --git a/drivers/led_strip/tlc5971.c b/drivers/led_strip/tlc5971.c index 06d36455d58..ace45414fbf 100644 --- a/drivers/led_strip/tlc5971.c +++ b/drivers/led_strip/tlc5971.c @@ -248,25 +248,16 @@ static int tlc5971_transmit_data(const struct device *dev, size_t num_pixels) static int tlc5971_update_rgb(const struct device *dev, struct led_rgb *pixels, size_t num_pixels) { - const struct tlc5971_config *cfg = dev->config; - - if (num_pixels > cfg->num_pixels) { - LOG_ERR("invalid number of pixels, %zu vs actual %i", num_pixels, cfg->num_pixels); - return -EINVAL; - } - tlc5971_fill_data_buffer(dev, pixels, num_pixels); return tlc5971_transmit_data(dev, num_pixels); } -static int tlc5971_update_channels(const struct device *dev, uint8_t *channels, size_t num_channels) +static size_t tlc5971_length(const struct device *dev) { - ARG_UNUSED(dev); - ARG_UNUSED(channels); - ARG_UNUSED(num_channels); + const struct tlc5971_config *cfg = dev->config; - return -ENOTSUP; + return (size_t)cfg->num_pixels; } int tlc5971_set_global_brightness(const struct device *dev, struct led_rgb pixel) @@ -333,7 +324,7 @@ static int tlc5971_init(const struct device *dev) static const struct led_strip_driver_api tlc5971_api = { .update_rgb = tlc5971_update_rgb, - .update_channels = tlc5971_update_channels, + .length = tlc5971_length, }; #define TLC5971_DATA_BUFFER_LENGTH(inst) \ diff --git a/drivers/led_strip/tlc59731.c b/drivers/led_strip/tlc59731.c new file mode 100644 index 00000000000..c8501156e81 --- /dev/null +++ b/drivers/led_strip/tlc59731.c @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2024 Javad Rahimipetroudi + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT ti_tlc59731 + +/** + * @file + * @brief LED driver for the TLC59731 LED driver. + * + * TLC59731 is a 3-Channel, 8-Bit, PWM LED Driver + * With Single-Wire Interface (EasySet) + * + * The EasySet protocol is based on short pulses and the time between + * them. At least one pulse must be sent every T_CYCLE, which can be + * between 1.67us and 50us. We want to go as fast as possible, but + * delays under 1us don't work very well, so we settle on 5us for the + * cycle time. + * A pulse must be high for at least 14ns. In practice, turning a GPIO on + * and immediately off again already takes longer than that, so no delay + * is needed there. + * A zero is represented by no additional pulses within a cycle. + * A one is represented by an additional pulse between 275ns and 2.5us + * (half a cycle) after the first one. We need at least some delay to get to + * 275ns, but because of the limited granularity of k_busy_wait we use a + * full 1us. After the pulse, we wait an additional T_CYCLE_1 to complete + * the cycle. This time can be slightly shorter because the second pulse + * already closes the cycle. + * Finally we need to keep the line low for T_H0 to complete the address + * for a single chip, and T_H1 to complete the write for all chips. + */ + +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(tlc59731, CONFIG_LED_STRIP_LOG_LEVEL); + +/* Pulse timing */ +#define TLC59731_DELAY 0x01 /* us */ +#define TLC59731_T_CYCLE_0 0x04 /* us */ +#define TLC59731_T_CYCLE_1 0x01 /* us */ +#define TLC59731_T_H0 (4 * TLC59731_T_CYCLE_0) +#define TLC59731_T_H1 (8 * TLC59731_T_CYCLE_0) +/* Threshould levels */ +#define TLC59731_HIGH 0x01 +#define TLC59731_LOW 0x00 + +/* Write command */ +#define TLC59731_WR 0x3A + +struct tlc59731_cfg { + struct gpio_dt_spec sdi_gpio; + size_t length; +}; + +static inline int rgb_pulse(const struct gpio_dt_spec *led_dev) +{ + int fret = 0; + + fret = gpio_pin_set_dt(led_dev, TLC59731_HIGH); + if (fret != 0) { + return fret; + } + + fret = gpio_pin_set_dt(led_dev, TLC59731_LOW); + if (fret != 0) { + return fret; + } + + return fret; +} + +static int rgb_write_bit(const struct gpio_dt_spec *led_dev, uint8_t data) +{ + rgb_pulse(led_dev); + + k_busy_wait(TLC59731_DELAY); + + if (data) { + rgb_pulse(led_dev); + k_busy_wait(TLC59731_T_CYCLE_1); + } else { + k_busy_wait(TLC59731_T_CYCLE_0); + } + + return 0; +} + +static int rgb_write_data(const struct gpio_dt_spec *led_dev, uint8_t data) +{ + int8_t idx = 7; + + while (idx >= 0) { + rgb_write_bit(led_dev, data & BIT((idx--))); + } + + return 0; +} + +static int tlc59731_led_set_color(const struct device *dev, struct led_rgb *pixel) +{ + + const struct tlc59731_cfg *tlc_conf = dev->config; + const struct gpio_dt_spec *led_gpio = &tlc_conf->sdi_gpio; + + rgb_write_data(led_gpio, TLC59731_WR); + rgb_write_data(led_gpio, pixel->r); + rgb_write_data(led_gpio, pixel->g); + rgb_write_data(led_gpio, pixel->b); + + return 0; +} + +static int tlc59731_gpio_update_rgb(const struct device *dev, struct led_rgb *pixels, + size_t num_pixels) +{ + size_t i; + int err = 0; + + for (i = 0; i < num_pixels; i++) { + err = tlc59731_led_set_color(dev, &pixels[i]); + if (err) { + break; + } + } + + return err; +} + +static size_t tlc59731_length(const struct device *dev) +{ + const struct tlc59731_cfg *config = dev->config; + + return config->length; +} + +static const struct led_strip_driver_api tlc59731_gpio_api = { + .update_rgb = tlc59731_gpio_update_rgb, + .length = tlc59731_length, +}; + +static int tlc59731_gpio_init(const struct device *dev) +{ + const struct tlc59731_cfg *tlc_conf = dev->config; + const struct gpio_dt_spec *led = &tlc_conf->sdi_gpio; + int err = 0; + + if (!device_is_ready(led->port)) { + LOG_ERR("%s: no LEDs found (DT child nodes missing)", dev->name); + err = -ENODEV; + goto scape; + } + + err = gpio_pin_configure_dt(led, GPIO_OUTPUT_ACTIVE); + if (err < 0) { + LOG_ERR("%s: Unable to setup SDI port", dev->name); + err = -EIO; + goto scape; + } + + err = gpio_pin_set_dt(led, TLC59731_LOW); + if (err < 0) { + LOG_ERR("%s: Unable to set the SDI-GPIO)", dev->name); + err = -EIO; + goto scape; + } + + gpio_pin_set_dt(led, TLC59731_HIGH); + gpio_pin_set_dt(led, TLC59731_LOW); + + k_busy_wait((TLC59731_DELAY + TLC59731_T_CYCLE_0)); +scape: + return err; +} + +#define TLC59731_DEVICE(i) \ + static struct tlc59731_cfg tlc59731_cfg_##i = { \ + .sdi_gpio = GPIO_DT_SPEC_INST_GET(i, gpios), \ + .length = DT_INST_PROP(i, chain_length), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(i, tlc59731_gpio_init, NULL, NULL, &tlc59731_cfg_##i, POST_KERNEL, \ + CONFIG_LED_STRIP_INIT_PRIORITY, &tlc59731_gpio_api); +DT_INST_FOREACH_STATUS_OKAY(TLC59731_DEVICE) diff --git a/drivers/led_strip/ws2812_gpio.c b/drivers/led_strip/ws2812_gpio.c index bba534f1bbe..9c0d47d3afb 100644 --- a/drivers/led_strip/ws2812_gpio.c +++ b/drivers/led_strip/ws2812_gpio.c @@ -28,6 +28,7 @@ struct ws2812_gpio_cfg { struct gpio_dt_spec gpio; uint8_t num_colors; const uint8_t *color_mapping; + size_t length; }; /* @@ -179,17 +180,16 @@ static int ws2812_gpio_update_rgb(const struct device *dev, return send_buf(dev, (uint8_t *)pixels, num_pixels * config->num_colors); } -static int ws2812_gpio_update_channels(const struct device *dev, - uint8_t *channels, - size_t num_channels) +static size_t ws2812_gpio_length(const struct device *dev) { - LOG_ERR("update_channels not implemented"); - return -ENOTSUP; + const struct ws2812_gpio_cfg *config = dev->config; + + return config->length; } static const struct led_strip_driver_api ws2812_gpio_api = { .update_rgb = ws2812_gpio_update_rgb, - .update_channels = ws2812_gpio_update_channels, + .length = ws2812_gpio_length, }; /* @@ -245,6 +245,7 @@ static const uint8_t ws2812_gpio_##idx##_color_mapping[] = \ .gpio = GPIO_DT_SPEC_INST_GET(idx, gpios), \ .num_colors = WS2812_NUM_COLORS(idx), \ .color_mapping = ws2812_gpio_##idx##_color_mapping, \ + .length = DT_INST_PROP(idx, chain_length), \ }; \ \ DEVICE_DT_INST_DEFINE(idx, \ diff --git a/drivers/led_strip/ws2812_i2s.c b/drivers/led_strip/ws2812_i2s.c index 19baefff8e2..b1b95121628 100644 --- a/drivers/led_strip/ws2812_i2s.c +++ b/drivers/led_strip/ws2812_i2s.c @@ -38,6 +38,7 @@ struct ws2812_i2s_cfg { size_t tx_buf_bytes; struct k_mem_slab *mem_slab; uint8_t num_colors; + size_t length; const uint8_t *color_mapping; uint16_t reset_words; uint32_t lrck_period; @@ -163,11 +164,11 @@ static int ws2812_strip_update_rgb(const struct device *dev, struct led_rgb *pix return ret; } -static int ws2812_strip_update_channels(const struct device *dev, uint8_t *channels, - size_t num_channels) +static size_t ws2812_strip_length(const struct device *dev) { - LOG_ERR("update_channels not implemented"); - return -ENOTSUP; + const struct ws2812_i2s_cfg *cfg = dev->config; + + return cfg->length; } static int ws2812_i2s_init(const struct device *dev) @@ -217,7 +218,7 @@ static int ws2812_i2s_init(const struct device *dev) static const struct led_strip_driver_api ws2812_i2s_api = { .update_rgb = ws2812_strip_update_rgb, - .update_channels = ws2812_strip_update_channels, + .length = ws2812_strip_length, }; /* Integer division, but always rounds up: e.g. 10/3 = 4 */ @@ -250,6 +251,7 @@ static const struct led_strip_driver_api ws2812_i2s_api = { .tx_buf_bytes = WS2812_I2S_BUFSIZE(idx), \ .mem_slab = &ws2812_i2s_##idx##_slab, \ .num_colors = WS2812_NUM_COLORS(idx), \ + .length = DT_INST_PROP(idx, chain_length), \ .color_mapping = ws2812_i2s_##idx##_color_mapping, \ .lrck_period = WS2812_I2S_LRCK_PERIOD_US(idx), \ .extra_wait_time_us = DT_INST_PROP(idx, extra_wait_time), \ diff --git a/drivers/led_strip/ws2812_rpi_pico_pio.c b/drivers/led_strip/ws2812_rpi_pico_pio.c index 5da5cc05f59..45b19da8f84 100644 --- a/drivers/led_strip/ws2812_rpi_pico_pio.c +++ b/drivers/led_strip/ws2812_rpi_pico_pio.c @@ -24,6 +24,7 @@ struct ws2812_led_strip_config { const struct device *piodev; const uint8_t gpio_pin; uint8_t num_colors; + size_t length; uint32_t frequency; const uint8_t *const color_mapping; uint16_t reset_delay; @@ -108,16 +109,16 @@ static int ws2812_led_strip_update_rgb(const struct device *dev, struct led_rgb return 0; } -static int ws2812_led_strip_update_channels(const struct device *dev, uint8_t *channels, - size_t num_channels) +static size_t ws2812_led_strip_length(const struct device *dev) { - LOG_DBG("update_channels not implemented"); - return -ENOTSUP; + const struct ws2812_led_strip_config *config = dev->config; + + return config->length; } 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, + .length = ws2812_led_strip_length, }; /* @@ -190,6 +191,7 @@ static int ws2812_rpi_pico_pio_init(const struct device *dev) .piodev = DEVICE_DT_GET(DT_PARENT(DT_PARENT(node))), \ .gpio_pin = DT_GPIO_PIN_BY_IDX(node, gpios, 0), \ .num_colors = DT_PROP_LEN(node, color_mapping), \ + .length = DT_PROP(node, chain_length), \ .color_mapping = ws2812_led_strip_##node##_color_mapping, \ .reset_delay = DT_PROP(node, reset_delay), \ .frequency = DT_PROP(node, frequency), \ diff --git a/drivers/led_strip/ws2812_spi.c b/drivers/led_strip/ws2812_spi.c index 44cfecebc9e..536da5463c9 100644 --- a/drivers/led_strip/ws2812_spi.c +++ b/drivers/led_strip/ws2812_spi.c @@ -39,11 +39,11 @@ LOG_MODULE_REGISTER(ws2812_spi); struct ws2812_spi_cfg { struct spi_dt_spec bus; uint8_t *px_buf; - size_t px_buf_size; uint8_t one_frame; uint8_t zero_frame; uint8_t num_colors; const uint8_t *color_mapping; + size_t length; uint16_t reset_delay; }; @@ -67,20 +67,6 @@ static inline void ws2812_spi_ser(uint8_t buf[8], uint8_t color, } } -/* - * Returns true if and only if cfg->px_buf is big enough to convert - * num_pixels RGB color values into SPI frames. - */ -static inline bool num_pixels_ok(const struct ws2812_spi_cfg *cfg, - size_t num_pixels) -{ - size_t nbytes; - bool overflow; - - overflow = size_mul_overflow(num_pixels, cfg->num_colors * 8, &nbytes); - return !overflow && (nbytes <= cfg->px_buf_size); -} - /* * Latch current color values on strip and reset its state machines. */ @@ -97,7 +83,7 @@ static int ws2812_strip_update_rgb(const struct device *dev, const uint8_t one = cfg->one_frame, zero = cfg->zero_frame; struct spi_buf buf = { .buf = cfg->px_buf, - .len = cfg->px_buf_size, + .len = (cfg->length * 8 * cfg->num_colors), }; const struct spi_buf_set tx = { .buffers = &buf, @@ -107,10 +93,6 @@ static int ws2812_strip_update_rgb(const struct device *dev, size_t i; int rc; - if (!num_pixels_ok(cfg, num_pixels)) { - return -ENOMEM; - } - /* * Convert pixel data into SPI frames. Each frame has pixel data * in color mapping on-wire format (e.g. GRB, GRBW, RGB, etc). @@ -152,12 +134,11 @@ static int ws2812_strip_update_rgb(const struct device *dev, return rc; } -static int ws2812_strip_update_channels(const struct device *dev, - uint8_t *channels, - size_t num_channels) +static size_t ws2812_strip_length(const struct device *dev) { - LOG_ERR("update_channels not implemented"); - return -ENOTSUP; + const struct ws2812_spi_cfg *cfg = dev_cfg(dev); + + return cfg->length; } static int ws2812_spi_init(const struct device *dev) @@ -190,7 +171,7 @@ static int ws2812_spi_init(const struct device *dev) static const struct led_strip_driver_api ws2812_spi_api = { .update_rgb = ws2812_strip_update_rgb, - .update_channels = ws2812_strip_update_channels, + .length = ws2812_strip_length, }; #define WS2812_SPI_NUM_PIXELS(idx) \ @@ -226,11 +207,11 @@ static const struct led_strip_driver_api ws2812_spi_api = { static const struct ws2812_spi_cfg ws2812_spi_##idx##_cfg = { \ .bus = SPI_DT_SPEC_INST_GET(idx, SPI_OPER(idx), 0), \ .px_buf = ws2812_spi_##idx##_px_buf, \ - .px_buf_size = WS2812_SPI_BUFSZ(idx), \ .one_frame = WS2812_SPI_ONE_FRAME(idx), \ .zero_frame = WS2812_SPI_ZERO_FRAME(idx), \ .num_colors = WS2812_NUM_COLORS(idx), \ .color_mapping = ws2812_spi_##idx##_color_mapping, \ + .length = DT_INST_PROP(idx, chain_length), \ .reset_delay = WS2812_RESET_DELAY(idx), \ }; \ \ diff --git a/drivers/mbox/mbox_nrf_vevif_local.c b/drivers/mbox/mbox_nrf_vevif_local.c index 31b89e1e6fb..56cb5cc49d9 100644 --- a/drivers/mbox/mbox_nrf_vevif_local.c +++ b/drivers/mbox/mbox_nrf_vevif_local.c @@ -111,7 +111,6 @@ static const struct mbox_driver_api vevif_local_driver_api = { static int vevif_local_init(const struct device *dev) { - nrf_vpr_csr_rtperiph_enable_set(true); nrf_vpr_csr_vevif_tasks_clear(NRF_VPR_TASK_TRIGGER_ALL_MASK); LISTIFY(DT_NUM_IRQS(DT_DRV_INST(0)), VEVIF_IRQ_CONNECT, (;)); diff --git a/drivers/mdio/CMakeLists.txt b/drivers/mdio/CMakeLists.txt index ad63d34f4ad..63e43e5936b 100644 --- a/drivers/mdio/CMakeLists.txt +++ b/drivers/mdio/CMakeLists.txt @@ -10,5 +10,6 @@ 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_ST_STM32_HAL mdio_stm32_hal.c) zephyr_library_sources_ifdef(CONFIG_MDIO_INFINEON_XMC4XXX mdio_xmc4xxx.c) zephyr_library_sources_ifdef(CONFIG_MDIO_NXP_ENET_QOS mdio_nxp_enet_qos.c) diff --git a/drivers/mdio/Kconfig b/drivers/mdio/Kconfig index 4af6827e8b7..dbd1ae9a038 100644 --- a/drivers/mdio/Kconfig +++ b/drivers/mdio/Kconfig @@ -31,6 +31,7 @@ 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.stm32_hal" source "drivers/mdio/Kconfig.xmc4xxx" source "drivers/mdio/Kconfig.nxp_enet_qos" diff --git a/drivers/mdio/Kconfig.stm32_hal b/drivers/mdio/Kconfig.stm32_hal new file mode 100644 index 00000000000..28268ab1486 --- /dev/null +++ b/drivers/mdio/Kconfig.stm32_hal @@ -0,0 +1,11 @@ +# Copyright (c) 2024 BayLibre, SAS +# Copyright (c) 2024 Analog Devices Inc. +# SPDX-License-Identifier: Apache-2.0 + +config MDIO_ST_STM32_HAL + bool "STM32 MDIO controller driver" + default y + depends on ETH_STM32_HAL_API_V2 + depends on DT_HAS_ST_STM32_MDIO_ENABLED + help + Enable STM32 MDIO support. diff --git a/drivers/mdio/mdio_esp32.c b/drivers/mdio/mdio_esp32.c index 871380c9a0a..8e3e073bba0 100644 --- a/drivers/mdio/mdio_esp32.c +++ b/drivers/mdio/mdio_esp32.c @@ -86,16 +86,6 @@ static int mdio_esp32_write(const struct device *dev, uint8_t prtad, return mdio_transfer(dev, prtad, regad, true, data, NULL); } -static void mdio_esp32_bus_enable(const struct device *dev) -{ - ARG_UNUSED(dev); -} - -static void mdio_esp32_bus_disable(const struct device *dev) -{ - ARG_UNUSED(dev); -} - static int mdio_esp32_initialize(const struct device *dev) { const struct mdio_esp32_dev_config *const cfg = dev->config; @@ -134,8 +124,6 @@ static int mdio_esp32_initialize(const struct device *dev) static const struct mdio_driver_api mdio_esp32_driver_api = { .read = mdio_esp32_read, .write = mdio_esp32_write, - .bus_enable = mdio_esp32_bus_enable, - .bus_disable = mdio_esp32_bus_disable, }; #define MDIO_ESP32_CONFIG(n) \ diff --git a/drivers/mdio/mdio_gpio.c b/drivers/mdio/mdio_gpio.c index 25f67cd41b1..f097004900b 100644 --- a/drivers/mdio/mdio_gpio.c +++ b/drivers/mdio/mdio_gpio.c @@ -157,21 +157,9 @@ static int mdio_gpio_initialize(const struct device *dev) return 0; } -static void mdio_gpio_bus_enable(const struct device *dev) -{ - ARG_UNUSED(dev); -} - -static void mdio_gpio_bus_disable(const struct device *dev) -{ - ARG_UNUSED(dev); -} - static const struct mdio_driver_api mdio_gpio_driver_api = { .read = mdio_gpio_read_mmi, .write = mdio_gpio_write_mmi, - .bus_enable = mdio_gpio_bus_enable, - .bus_disable = mdio_gpio_bus_disable, }; #define MDIO_GPIO_CONFIG(inst) \ diff --git a/drivers/mdio/mdio_nxp_enet.c b/drivers/mdio/mdio_nxp_enet.c index 6b5c128e075..f91158ed505 100644 --- a/drivers/mdio/mdio_nxp_enet.c +++ b/drivers/mdio/mdio_nxp_enet.c @@ -179,21 +179,9 @@ static int nxp_enet_mdio_write(const struct device *dev, 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) diff --git a/drivers/mdio/mdio_nxp_enet_qos.c b/drivers/mdio/mdio_nxp_enet_qos.c index e853d16b15f..61de09d2bd5 100644 --- a/drivers/mdio/mdio_nxp_enet_qos.c +++ b/drivers/mdio/mdio_nxp_enet_qos.c @@ -144,17 +144,9 @@ static int nxp_enet_qos_mdio_write(const struct device *dev, return do_transaction(&mdio_write); } -static void nxp_enet_qos_mdio_bus_fn(const struct device *dev) -{ - /* Intentionally empty. IP does not support this functionality. */ - ARG_UNUSED(dev); -} - static const struct mdio_driver_api nxp_enet_qos_mdio_api = { .read = nxp_enet_qos_mdio_read, .write = nxp_enet_qos_mdio_write, - .bus_enable = nxp_enet_qos_mdio_bus_fn, - .bus_disable = nxp_enet_qos_mdio_bus_fn, }; static int nxp_enet_qos_mdio_init(const struct device *dev) diff --git a/drivers/mdio/mdio_nxp_s32_gmac.c b/drivers/mdio/mdio_nxp_s32_gmac.c index afd7c8ccedb..4e8cc2942b4 100644 --- a/drivers/mdio/mdio_nxp_s32_gmac.c +++ b/drivers/mdio/mdio_nxp_s32_gmac.c @@ -141,19 +141,11 @@ static int mdio_nxp_s32_init(const struct device *dev) 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) \ diff --git a/drivers/mdio/mdio_nxp_s32_netc.c b/drivers/mdio/mdio_nxp_s32_netc.c index ff8a561d974..6f2acea2caf 100644 --- a/drivers/mdio/mdio_nxp_s32_netc.c +++ b/drivers/mdio/mdio_nxp_s32_netc.c @@ -67,17 +67,9 @@ static int nxp_s32_mdio_initialize(const struct device *dev) return 0; } -static void nxp_s32_mdio_noop(const struct device *dev) -{ - /* intentionally left empty */ -} - static const struct mdio_driver_api nxp_s32_mdio_api = { .read = nxp_s32_mdio_read, .write = nxp_s32_mdio_write, - /* NETC does not support enabling/disabling EMDIO controller independently */ - .bus_enable = nxp_s32_mdio_noop, - .bus_disable = nxp_s32_mdio_noop, }; #define NXP_S32_MDIO_HW_INSTANCE_CHECK(i, n) \ diff --git a/drivers/mdio/mdio_stm32_hal.c b/drivers/mdio/mdio_stm32_hal.c new file mode 100644 index 00000000000..3e788027fae --- /dev/null +++ b/drivers/mdio/mdio_stm32_hal.c @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2024 BayLibre, SAS + * Copyright (c) 2024 Analog Devices Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(mdio_stm32_hal, CONFIG_MDIO_LOG_LEVEL); + +#define DT_DRV_COMPAT st_stm32_mdio + +#define ADIN1100_REG_VALUE_MASK GENMASK(15, 0) + +struct mdio_stm32_data { + struct k_sem sem; + ETH_HandleTypeDef heth; +}; + +struct mdio_stm32_config { + const struct pinctrl_dev_config *pincfg; +}; + +static int mdio_stm32_read(const struct device *dev, uint8_t prtad, + uint8_t regad, uint16_t *data) +{ + struct mdio_stm32_data *const dev_data = dev->data; + ETH_HandleTypeDef *heth = &dev_data->heth; + uint32_t read; + int ret; + + k_sem_take(&dev_data->sem, K_FOREVER); + + ret = HAL_ETH_ReadPHYRegister(heth, prtad, regad, &read); + + k_sem_give(&dev_data->sem); + + if (ret != HAL_OK) { + return -EIO; + } + + *data = read & ADIN1100_REG_VALUE_MASK; + + return ret; +} + +static int mdio_stm32_write(const struct device *dev, uint8_t prtad, + uint8_t regad, uint16_t data) +{ + struct mdio_stm32_data *const dev_data = dev->data; + ETH_HandleTypeDef *heth = &dev_data->heth; + int ret; + + k_sem_take(&dev_data->sem, K_FOREVER); + + ret = HAL_ETH_WritePHYRegister(heth, prtad, regad, data); + + k_sem_give(&dev_data->sem); + + if (ret != HAL_OK) { + return -EIO; + } + + return ret; +} + +static void mdio_stm32_bus_enable(const struct device *dev) +{ + ARG_UNUSED(dev); +} + +static void mdio_stm32_bus_disable(const struct device *dev) +{ + ARG_UNUSED(dev); +} + +static int mdio_stm32_init(const struct device *dev) +{ + struct mdio_stm32_data *const dev_data = dev->data; + const struct mdio_stm32_config *const config = dev->config; + int ret; + + ret = pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT); + if (ret < 0) { + return ret; + } + + k_sem_init(&dev_data->sem, 1, 1); + + return 0; +} + +static const struct mdio_driver_api mdio_stm32_api = { + .read = mdio_stm32_read, + .write = mdio_stm32_write, + .bus_enable = mdio_stm32_bus_enable, + .bus_disable = mdio_stm32_bus_disable, +}; + +#define MDIO_STM32_HAL_DEVICE(inst) \ + PINCTRL_DT_INST_DEFINE(inst); \ + \ + static struct mdio_stm32_data mdio_stm32_data_##inst = { \ + .heth = {.Instance = (ETH_TypeDef *)DT_REG_ADDR(DT_INST_PARENT(inst))}, \ + }; \ + static struct mdio_stm32_config mdio_stm32_config_##inst = { \ + .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \ + }; \ + DEVICE_DT_INST_DEFINE(inst, &mdio_stm32_init, NULL, \ + &mdio_stm32_data_##inst, &mdio_stm32_config_##inst, \ + POST_KERNEL, CONFIG_ETH_INIT_PRIORITY, \ + &mdio_stm32_api); + +DT_INST_FOREACH_STATUS_OKAY(MDIO_STM32_HAL_DEVICE) diff --git a/drivers/memc/CMakeLists.txt b/drivers/memc/CMakeLists.txt index 8aaedc22073..1648343c18f 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_MCUX_FLEXSPI_IS66WVQ8M4 memc_mcux_flexspi_is66wvq8m4.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) @@ -22,3 +23,4 @@ if((DEFINED CONFIG_FLASH_MCUX_FLEXSPI_XIP) AND (DEFINED CONFIG_FLASH)) endif() zephyr_library_sources_ifdef(CONFIG_MEMC_NXP_S32_QSPI memc_nxp_s32_qspi.c) +zephyr_library_sources_ifdef(CONFIG_MEMC_SMARTBOND memc_smartbond_nor_psram.c) diff --git a/drivers/memc/Kconfig b/drivers/memc/Kconfig index f6416557355..afab61994af 100644 --- a/drivers/memc/Kconfig +++ b/drivers/memc/Kconfig @@ -31,4 +31,6 @@ source "drivers/memc/Kconfig.sifive" source "drivers/memc/Kconfig.nxp_s32" +source "drivers/memc/Kconfig.smartbond" + endif diff --git a/drivers/memc/Kconfig.mcux b/drivers/memc/Kconfig.mcux index e801e7577ae..dd6c2da48f4 100644 --- a/drivers/memc/Kconfig.mcux +++ b/drivers/memc/Kconfig.mcux @@ -24,6 +24,32 @@ config MEMC_MCUX_FLEXSPI_APS6408L depends on DT_HAS_NXP_IMX_FLEXSPI_APS6408L_ENABLED select MEMC_MCUX_FLEXSPI +config MEMC_MCUX_FLEXSPI_IS66WVQ8M4 + bool "MCUX FlexSPI ISSI IS66WVQ8M4 pSRAM driver" + default y + depends on DT_HAS_NXP_IMX_FLEXSPI_IS66WVQ8M4_ENABLED + select MEMC_MCUX_FLEXSPI + +config MEMC_MCUX_FLEXSPI_INIT_PRIORITY + int "MCUX FLEXSPI MEMC driver initialization priority" + default MEMC_INIT_PRIORITY + help + Initialization priority for FlexSPI MEMC driver. In cases where the + flash driver must initialize before the MEMC RAM driver, + initialization priorities can be set such that + MEMC_MCUX_FLEXSPI_INIT_PRIORITY < FLASH_INIT_PRIORITY < + MEMC_INIT_PRIORITY + +config MEMC_MCUX_FLEXSPI_INIT_XIP + bool "Initialize FLEXSPI when using device for XIP" + help + Initialize the FLEXSPI device even when using it for XIP. If this + Kconfig is enabled, the user must ensure that the pin control + state used does not reconfigure the pins used to interface with + the flash device used for XIP, and that the configuration settings + used for the FLEXSPI are compatible with those needed for XIP from + the flash device. + config MEMC_MCUX_FLEXSPI bool select PINCTRL diff --git a/drivers/memc/Kconfig.smartbond b/drivers/memc/Kconfig.smartbond new file mode 100644 index 00000000000..32cb8c94f46 --- /dev/null +++ b/drivers/memc/Kconfig.smartbond @@ -0,0 +1,11 @@ +# Smartbond Cryptographic Accelerator configuration options + +# Copyright (c) 2023 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +config MEMC_SMARTBOND + bool "Smartbond NOR/PSRAM memory controller" + depends on DT_HAS_RENESAS_SMARTBOND_NOR_PSRAM_ENABLED + default y + help + Enable Smartbond NOR/PSRAM memory controller. diff --git a/drivers/memc/memc_mcux_flexspi.c b/drivers/memc/memc_mcux_flexspi.c index e0c8f6faf96..c3ad20aab4b 100644 --- a/drivers/memc/memc_mcux_flexspi.c +++ b/drivers/memc/memc_mcux_flexspi.c @@ -56,6 +56,10 @@ struct memc_flexspi_data { bool combination_mode; bool sck_differential_clock; flexspi_read_sample_clock_t rx_sample_clock; +#if defined(FSL_FEATURE_FLEXSPI_SUPPORT_SEPERATE_RXCLKSRC_PORTB) && \ +FSL_FEATURE_FLEXSPI_SUPPORT_SEPERATE_RXCLKSRC_PORTB + flexspi_read_sample_clock_t rx_sample_clock_b; +#endif const struct pinctrl_dev_config *pincfg; size_t size[kFLEXSPI_PortCount]; struct port_lut port_luts[kFLEXSPI_PortCount]; @@ -184,9 +188,12 @@ int memc_flexspi_set_device_config(const struct device *dev, /* 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; + /* LUTs should only be installed on sequence boundaries, every + * 4 entries. Round LUT usage up to nearest sequence + */ + data->port_luts[port].lut_used = ROUND_UP(lut_count, 4); + tmp_config.ARDSeqIndex += data->port_luts[port].lut_offset / MEMC_FLEXSPI_CMD_PER_SEQ; + tmp_config.AWRSeqIndex += data->port_luts[port].lut_offset / MEMC_FLEXSPI_CMD_PER_SEQ; /* Lock IRQs before reconfiguring FlexSPI, to prevent XIP */ key = irq_lock(); @@ -211,12 +218,29 @@ int memc_flexspi_reset(const struct device *dev) int memc_flexspi_transfer(const struct device *dev, flexspi_transfer_t *transfer) { + flexspi_transfer_t tmp; struct memc_flexspi_data *data = dev->data; status_t status; + uint32_t seq_off, addr_offset = 0U; + int i; + + /* Calculate sequence offset and address offset based on port */ + seq_off = data->port_luts[transfer->port].lut_offset / + MEMC_FLEXSPI_CMD_PER_SEQ; + for (i = 0; i < transfer->port; i++) { + addr_offset += data->size[i]; + } - /* Adjust transfer LUT index based on port */ - transfer->seqIndex += data->port_luts[transfer->port].lut_offset; - status = FLEXSPI_TransferBlocking(data->base, transfer); + if ((seq_off != 0) || (addr_offset != 0)) { + /* Adjust device address and sequence index for transfer */ + memcpy(&tmp, transfer, sizeof(tmp)); + tmp.seqIndex += seq_off; + tmp.deviceAddress += addr_offset; + status = FLEXSPI_TransferBlocking(data->base, &tmp); + } else { + /* Transfer does not need adjustment */ + status = FLEXSPI_TransferBlocking(data->base, transfer); + } if (status != kStatus_Success) { LOG_ERR("Transfer error: %d", status); @@ -241,6 +265,14 @@ void *memc_flexspi_get_ahb_address(const struct device *dev, offset += data->size[i]; } +#if defined(FSL_FEATURE_FLEXSPI_SUPPORT_ADDRESS_SHIFT) && \ + (FSL_FEATURE_FLEXSPI_SUPPORT_ADDRESS_SHIFT) + if (data->base->FLSHCR0[port] & FLEXSPI_FLSHCR0_ADDRSHIFT_MASK) { + /* Address shift is set, add 0x1000_0000 to AHB address */ + offset += 0x10000000; + } +#endif + return data->ahb_base + offset; } @@ -248,19 +280,21 @@ static int memc_flexspi_init(const struct device *dev) { struct memc_flexspi_data *data = dev->data; flexspi_config_t flexspi_config; + uint32_t flash_sizes[kFLEXSPI_PortCount]; + int ret; + uint8_t i; /* we should not configure the device we are running on */ if (memc_flexspi_is_running_xip(dev)) { - LOG_DBG("XIP active on %s, skipping init", dev->name); - return 0; + if (!IS_ENABLED(CONFIG_MEMC_MCUX_FLEXSPI_INIT_XIP)) { + LOG_DBG("XIP active on %s, skipping init", dev->name); + return 0; + } } - /* * SOCs such as the RT1064 and RT1024 have internal flash, and no pinmux * settings, continue if no pinctrl state found. */ - int ret; - ret = pinctrl_apply_state(data->pincfg, PINCTRL_STATE_DEFAULT); if (ret < 0 && ret != -ENOENT) { return ret; @@ -282,11 +316,21 @@ static int memc_flexspi_init(const struct device *dev) flexspi_config.enableSckBDiffOpt = data->sck_differential_clock; #endif flexspi_config.rxSampleClock = data->rx_sample_clock; +#if defined(FSL_FEATURE_FLEXSPI_SUPPORT_SEPERATE_RXCLKSRC_PORTB) && \ +FSL_FEATURE_FLEXSPI_SUPPORT_SEPERATE_RXCLKSRC_PORTB + flexspi_config.rxSampleClockPortB = data->rx_sample_clock_b; +#if defined(FSL_FEATURE_FLEXSPI_SUPPORT_RXCLKSRC_DIFF) && \ + FSL_FEATURE_FLEXSPI_SUPPORT_RXCLKSRC_DIFF + if (flexspi_config.rxSampleClock != flexspi_config.rxSampleClockPortB) { + flexspi_config.rxSampleClockDiff = true; + } +#endif +#endif /* Configure AHB RX buffers, if any configuration settings are present */ __ASSERT(data->buf_cfg_cnt < FSL_FEATURE_FLEXSPI_AHB_BUFFER_COUNT, "Maximum RX buffer configuration count exceeded"); - for (uint8_t i = 0; i < data->buf_cfg_cnt; i++) { + for (i = 0; i < data->buf_cfg_cnt; i++) { /* Should AHB prefetch up to buffer size? */ flexspi_config.ahbConfig.buffer[i].enablePrefetch = data->buf_cfg[i].prefetch; /* AHB access priority (used for suspending control of AHB prefetching )*/ @@ -297,8 +341,25 @@ static int memc_flexspi_init(const struct device *dev) flexspi_config.ahbConfig.buffer[i].bufferSize = data->buf_cfg[i].buf_size; } + if (memc_flexspi_is_running_xip(dev)) { + /* Save flash sizes- FlexSPI init will reset them */ + for (i = 0; i < kFLEXSPI_PortCount; i++) { + flash_sizes[i] = data->base->FLSHCR0[i]; + } + } + FLEXSPI_Init(data->base, &flexspi_config); + if (memc_flexspi_is_running_xip(dev)) { + /* Restore flash sizes */ + for (i = 0; i < kFLEXSPI_PortCount; i++) { + data->base->FLSHCR0[i] = flash_sizes[i]; + } + + /* Reenable FLEXSPI module */ + data->base->MCR0 &= ~FLEXSPI_MCR0_MDIS_MASK; + } + return 0; } @@ -329,6 +390,13 @@ static int memc_flexspi_pm_action(const struct device *dev, enum pm_device_actio } #endif +#if defined(FSL_FEATURE_FLEXSPI_SUPPORT_SEPERATE_RXCLKSRC_PORTB) && \ + FSL_FEATURE_FLEXSPI_SUPPORT_SEPERATE_RXCLKSRC_PORTB +#define MEMC_FLEXSPI_RXCLK_B(inst) .rx_sample_clock_b = DT_INST_PROP(inst, rx_clock_source_b), +#else +#define MEMC_FLEXSPI_RXCLK_B(inst) +#endif + #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) \ @@ -357,6 +425,7 @@ static int memc_flexspi_pm_action(const struct device *dev, enum pm_device_actio .combination_mode = DT_INST_PROP(n, combination_mode), \ .sck_differential_clock = DT_INST_PROP(n, sck_differential_clock), \ .rx_sample_clock = DT_INST_PROP(n, rx_clock_source), \ + MEMC_FLEXSPI_RXCLK_B(n) \ .buf_cfg = (struct memc_flexspi_buf_cfg *)buf_cfg_##n, \ .buf_cfg_cnt = sizeof(buf_cfg_##n) / \ sizeof(struct memc_flexspi_buf_cfg), \ @@ -374,7 +443,7 @@ static int memc_flexspi_pm_action(const struct device *dev, enum pm_device_actio &memc_flexspi_data_##n, \ NULL, \ POST_KERNEL, \ - CONFIG_MEMC_INIT_PRIORITY, \ + CONFIG_MEMC_MCUX_FLEXSPI_INIT_PRIORITY, \ NULL); DT_INST_FOREACH_STATUS_OKAY(MEMC_FLEXSPI) diff --git a/drivers/memc/memc_mcux_flexspi.h b/drivers/memc/memc_mcux_flexspi.h index 707d9f088cc..6863649bc94 100644 --- a/drivers/memc/memc_mcux_flexspi.h +++ b/drivers/memc/memc_mcux_flexspi.h @@ -57,7 +57,7 @@ int memc_flexspi_update_clock(const struct device *dev, * @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 lut_count: number of LUT entries (4 bytes each) in lut array * @param port: FlexSPI port to use for this external device * @return 0 on success, negative value on failure */ diff --git a/drivers/memc/memc_mcux_flexspi_is66wvq8m4.c b/drivers/memc/memc_mcux_flexspi_is66wvq8m4.c new file mode 100644 index 00000000000..7ce698b3dd6 --- /dev/null +++ b/drivers/memc/memc_mcux_flexspi_is66wvq8m4.c @@ -0,0 +1,247 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + + #define DT_DRV_COMPAT nxp_imx_flexspi_is66wvq8m4 + + #include + #include + #include + + #include "memc_mcux_flexspi.h" + +LOG_MODULE_REGISTER(memc_flexspi_is66wvq8m4, CONFIG_MEMC_LOG_LEVEL); + +/* Vendor ID for ISSI device */ +#define ISSI_VENDOR_ID 0x3 + +enum { + READ_DATA = 0, + WRITE_DATA, + READ_REG, + WRITE_REG, + READ_ID, +}; + +struct memc_flexspi_is66wvq8m4_config { + flexspi_port_t port; + flexspi_device_config_t config; +}; + +/* Device variables used in critical sections should be in this structure */ +struct memc_flexspi_is66wvq8m4_data { + const struct device *controller; +}; + +/* IS66WVQ8M4 configuration register constants */ +#define IS66WVQ8M4_LATENCY_MASK BIT(3) +#define IS66WVQ8M4_LATENCY_FIXED BIT(3) + +static const uint32_t memc_flexspi_is66wvq8m4_lut[][4] = { + /* Read Data (continuous burst) */ + [READ_DATA] = { + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_4PAD, 0xAA, + kFLEXSPI_Command_DDR, kFLEXSPI_4PAD, 0x00), + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_4PAD, 16, + kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_4PAD, 16), + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DUMMY_DDR, kFLEXSPI_4PAD, 28, + kFLEXSPI_Command_READ_DDR, kFLEXSPI_4PAD, 0x01), + }, + /* Write Data (continuous burst) */ + [WRITE_DATA] = { + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_4PAD, 0x22, + kFLEXSPI_Command_DDR, kFLEXSPI_4PAD, 0x00), + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_4PAD, 16, + kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_4PAD, 16), + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DUMMY_DDR, kFLEXSPI_4PAD, 28, + kFLEXSPI_Command_WRITE_DDR, kFLEXSPI_4PAD, 0x01), + }, + /* Read Register */ + [READ_REG] = { + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_4PAD, 0xCC, + kFLEXSPI_Command_DDR, kFLEXSPI_4PAD, 0x00), + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_4PAD, 16, + kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_4PAD, 16), + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DUMMY_DDR, kFLEXSPI_4PAD, 12, + kFLEXSPI_Command_READ_DDR, kFLEXSPI_4PAD, 0x01), + }, + /* Write Register */ + [WRITE_REG] = { + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_4PAD, 0x66, + kFLEXSPI_Command_DDR, kFLEXSPI_4PAD, 0x00), + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_4PAD, 16, + kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_4PAD, 16), + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_WRITE_DDR, kFLEXSPI_4PAD, 0x01, + kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x00), + }, + /* Read Identification register */ + [READ_ID] = { + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_4PAD, 0xE0, + kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_4PAD, 16), + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_4PAD, 16, + kFLEXSPI_Command_DUMMY_RWDS_DDR, kFLEXSPI_4PAD, 0x08), + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_DDR, kFLEXSPI_4PAD, 0x01, + kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x00), + } +}; + + +/* Read vendor ID from identification register */ +static int memc_flexspi_is66wvq8m4_get_vendor_id(const struct device *dev, + uint8_t *vendor_id) +{ + const struct memc_flexspi_is66wvq8m4_config *config = dev->config; + struct memc_flexspi_is66wvq8m4_data *data = dev->data; + uint32_t buffer = 0; + int ret; + + flexspi_transfer_t transfer = { + .deviceAddress = 0x00, /* Not used by this command */ + .port = config->port, + .cmdType = kFLEXSPI_Read, + .SeqNumber = 1, + .seqIndex = READ_ID, + .data = &buffer, + .dataSize = 2, + }; + + ret = memc_flexspi_transfer(data->controller, &transfer); + *vendor_id = buffer & 0x7; + + return ret; +} + +/* Update configuration register */ +static int memc_flexspi_is66wvq8m4_update_cfg(const struct device *dev, + uint16_t mask, uint16_t set_val) +{ + const struct memc_flexspi_is66wvq8m4_config *config = dev->config; + struct memc_flexspi_is66wvq8m4_data *data = dev->data; + uint32_t buffer = 0; + int ret; + + flexspi_transfer_t transfer = { + /* Results in 0x4 being written on clock 4 */ + .deviceAddress = (0x4 << 9), + .port = config->port, + .cmdType = kFLEXSPI_Read, + .SeqNumber = 1, + .seqIndex = READ_REG, + .data = &buffer, + .dataSize = 2, + }; + + ret = memc_flexspi_transfer(data->controller, &transfer); + if (ret < 0) { + return ret; + } + + buffer &= (~mask & GENMASK(15, 0)); + buffer |= set_val; + + LOG_DBG("Setting cfg reg to 0x%0x", buffer); + + transfer.cmdType = kFLEXSPI_Write, + transfer.seqIndex = WRITE_REG; + + ret = memc_flexspi_transfer(data->controller, &transfer); + return ret; +} + +static int memc_flexspi_is66wvq8m4_init(const struct device *dev) +{ + const struct memc_flexspi_is66wvq8m4_config *config = dev->config; + struct memc_flexspi_is66wvq8m4_data *data = dev->data; + uint8_t vendor_id; + + if (!device_is_ready(data->controller)) { + LOG_ERR("Controller device not ready"); + return -ENODEV; + } + + if (memc_flexspi_set_device_config(data->controller, &config->config, + (const uint32_t *) memc_flexspi_is66wvq8m4_lut, + sizeof(memc_flexspi_is66wvq8m4_lut) / MEMC_FLEXSPI_CMD_SIZE, + config->port)) { + LOG_ERR("Could not set device configuration"); + return -EINVAL; + } + + if (memc_flexspi_is66wvq8m4_get_vendor_id(dev, &vendor_id)) { + LOG_ERR("Could not read vendor id"); + return -EIO; + } + LOG_DBG("Vendor id: 0x%0x", vendor_id); + if (vendor_id != ISSI_VENDOR_ID) { + LOG_WRN("Vendor ID does not match expected value of 0x%0x", + ISSI_VENDOR_ID); + } + + if (memc_flexspi_is66wvq8m4_update_cfg(dev, IS66WVQ8M4_LATENCY_MASK, + IS66WVQ8M4_LATENCY_FIXED)) { + LOG_ERR("Could not set fixed latency mode"); + return -EIO; + } + + return 0; +} + +#define CONCAT3(x, y, z) x ## y ## z + +#define CS_INTERVAL_UNIT(unit) \ + CONCAT3(kFLEXSPI_CsIntervalUnit, unit, SckCycle) + +#define AHB_WRITE_WAIT_UNIT(unit) \ + CONCAT3(kFLEXSPI_AhbWriteWaitUnit, unit, AhbCycle) + +#define MEMC_FLEXSPI_DEVICE_CONFIG(n) \ + { \ + .flexspiRootClk = DT_INST_PROP(n, spi_max_frequency), \ + .isSck2Enabled = false, \ + .flashSize = DT_INST_PROP(n, size) / 8 / KB(1), \ + .addressShift = DT_INST_REG_ADDR(n) != 0, \ + .CSIntervalUnit = \ + CS_INTERVAL_UNIT( \ + DT_INST_PROP(n, cs_interval_unit)), \ + .CSInterval = DT_INST_PROP(n, cs_interval), \ + .CSHoldTime = DT_INST_PROP(n, cs_hold_time), \ + .CSSetupTime = DT_INST_PROP(n, cs_setup_time), \ + .dataValidTime = DT_INST_PROP(n, data_valid_time), \ + .columnspace = DT_INST_PROP(n, column_space), \ + .enableWordAddress = DT_INST_PROP(n, word_addressable), \ + .AWRSeqIndex = WRITE_DATA, \ + .AWRSeqNumber = 1, \ + .ARDSeqIndex = READ_DATA, \ + .ARDSeqNumber = 1, \ + .AHBWriteWaitUnit = \ + AHB_WRITE_WAIT_UNIT( \ + DT_INST_PROP(n, ahb_write_wait_unit)), \ + .AHBWriteWaitInterval = \ + DT_INST_PROP(n, ahb_write_wait_interval), \ + .enableWriteMask = true, \ + } + +#define MEMC_FLEXSPI_IS66WVQ8M4(n) \ + static const struct memc_flexspi_is66wvq8m4_config \ + memc_flexspi_is66wvq8m4_config_##n = { \ + .port = DT_INST_REG_ADDR(n), \ + .config = MEMC_FLEXSPI_DEVICE_CONFIG(n), \ + }; \ + \ + static struct memc_flexspi_is66wvq8m4_data \ + memc_flexspi_is66wvq8m4_data_##n = { \ + .controller = DEVICE_DT_GET(DT_INST_BUS(n)), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(n, \ + memc_flexspi_is66wvq8m4_init, \ + NULL, \ + &memc_flexspi_is66wvq8m4_data_##n, \ + &memc_flexspi_is66wvq8m4_config_##n,\ + POST_KERNEL, \ + CONFIG_MEMC_INIT_PRIORITY, \ + NULL); + +DT_INST_FOREACH_STATUS_OKAY(MEMC_FLEXSPI_IS66WVQ8M4) diff --git a/drivers/memc/memc_smartbond_nor_psram.c b/drivers/memc/memc_smartbond_nor_psram.c new file mode 100644 index 00000000000..37584f99dcc --- /dev/null +++ b/drivers/memc/memc_smartbond_nor_psram.c @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2023 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT renesas_smartbond_nor_psram + +#include +#include +#include +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(smartbond_nor_psram, CONFIG_MEMC_LOG_LEVEL); + +#define CLK_AMBA_REG_SET_FIELD(_field, _var, _val) \ + ((_var)) = \ + ((_var) & ~(CRG_TOP_CLK_AMBA_REG_ ## _field ## _Msk)) | \ + (((_val) << CRG_TOP_CLK_AMBA_REG_ ## _field ## _Pos) & \ + CRG_TOP_CLK_AMBA_REG_ ## _field ## _Msk) + +#define QSPIC2_CTRLMODE_REG_SET_FIELD(_field, _var, _val) \ + ((_var)) = \ + ((_var) & ~(QSPIC2_QSPIC2_CTRLMODE_REG_ ## _field ## _Msk)) | \ + (((_val) << QSPIC2_QSPIC2_CTRLMODE_REG_ ## _field ## _Pos) & \ + QSPIC2_QSPIC2_CTRLMODE_REG_ ## _field ## _Msk) + +#define QSPIC2_BURSTCMDA_REG_SET_FIELD(_field, _var, _val) \ + ((_var)) = \ + ((_var) & ~(QSPIC2_QSPIC2_BURSTCMDA_REG_ ## _field ## _Msk)) | \ + (((_val) << QSPIC2_QSPIC2_BURSTCMDA_REG_ ## _field ## _Pos) & \ + QSPIC2_QSPIC2_BURSTCMDA_REG_ ## _field ## _Msk) + +#define QSPIC2_BURSTCMDB_REG_SET_FIELD(_field, _var, _val) \ + ((_var)) = \ + ((_var) & ~(QSPIC2_QSPIC2_BURSTCMDB_REG_ ## _field ## _Msk)) | \ + (((_val) << QSPIC2_QSPIC2_BURSTCMDB_REG_ ## _field ## _Pos) & \ + QSPIC2_QSPIC2_BURSTCMDB_REG_ ## _field ## _Msk) + +#define QSPIC2_AWRITECMD_REG_SET_FIELD(_field, _var, _val) \ + ((_var)) = \ + ((_var) & ~(QSPIC2_QSPIC2_AWRITECMD_REG_ ## _field ## _Msk)) | \ + (((_val) << QSPIC2_QSPIC2_AWRITECMD_REG_ ## _field ## _Pos) & \ + QSPIC2_QSPIC2_AWRITECMD_REG_ ## _field ## _Msk) + +static void memc_set_status(bool status, int clk_div) +{ + unsigned int key; + uint32_t clk_amba_reg; + + /* Clock AMBA register might be accessed by multiple driver classes */ + key = irq_lock(); + clk_amba_reg = CRG_TOP->CLK_AMBA_REG; + + if (status) { + CLK_AMBA_REG_SET_FIELD(QSPI2_ENABLE, clk_amba_reg, 1); + CLK_AMBA_REG_SET_FIELD(QSPI2_DIV, clk_amba_reg, clk_div); + } else { + CLK_AMBA_REG_SET_FIELD(QSPI2_ENABLE, clk_amba_reg, 0); + } + + CRG_TOP->CLK_AMBA_REG = clk_amba_reg; + irq_unlock(key); +} + +static void memc_automode_configure(void) +{ + uint32_t reg; + + reg = QSPIC2->QSPIC2_CTRLMODE_REG; + QSPIC2_CTRLMODE_REG_SET_FIELD(QSPIC_SRAM_EN, reg, + DT_INST_PROP(0, is_ram)); + QSPIC2_CTRLMODE_REG_SET_FIELD(QSPIC_USE_32BA, reg, + DT_INST_ENUM_IDX(0, addr_range)); + QSPIC2_CTRLMODE_REG_SET_FIELD(QSPIC_CLK_MD, reg, + DT_INST_ENUM_IDX(0, clock_mode)); + QSPIC2_CTRLMODE_REG_SET_FIELD(QSPIC_AUTO_MD, reg, 1); + QSPIC2->QSPIC2_CTRLMODE_REG = reg; + + reg = QSPIC2->QSPIC2_BURSTCMDA_REG; + QSPIC2_BURSTCMDA_REG_SET_FIELD(QSPIC_DMY_TX_MD, reg, + DT_INST_ENUM_IDX(0, rx_dummy_mode)); + QSPIC2_BURSTCMDA_REG_SET_FIELD(QSPIC_ADR_TX_MD, reg, + DT_INST_ENUM_IDX(0, rx_addr_mode)); + QSPIC2_BURSTCMDA_REG_SET_FIELD(QSPIC_INST_TX_MD, reg, + DT_INST_ENUM_IDX(0, rx_inst_mode)); + #if DT_INST_PROP(0, extra_byte_enable) + QSPIC2_BURSTCMDA_REG_SET_FIELD(QSPIC_EXT_TX_MD, reg, + DT_INST_ENUM_IDX(0, rx_extra_mode)); + #endif + QSPIC2_BURSTCMDA_REG_SET_FIELD(QSPIC_INST, reg, + DT_INST_PROP(0, read_cmd)); + #if DT_INST_PROP(0, extra_byte_enable) + QSPIC2_BURSTCMDA_REG_SET_FIELD(QSPIC_EXT_BYTE, reg, + DT_INST_PROP(0, extra_byte)); + #endif + QSPIC2->QSPIC2_BURSTCMDA_REG = reg; + + reg = QSPIC2->QSPIC2_BURSTCMDB_REG; + QSPIC2_BURSTCMDB_REG_SET_FIELD(QSPIC_DMY_NUM, reg, + DT_INST_ENUM_IDX(0, dummy_bytes_count)); + QSPIC2_BURSTCMDB_REG_SET_FIELD(QSPIC_DAT_RX_MD, reg, + DT_INST_ENUM_IDX(0, rx_data_mode)); + QSPIC2_BURSTCMDB_REG_SET_FIELD(QSPIC_INST_MD, reg, 0); + QSPIC2_BURSTCMDB_REG_SET_FIELD(QSPIC_EXT_BYTE_EN, reg, + DT_INST_PROP(0, extra_byte_enable)); + QSPIC2->QSPIC2_BURSTCMDB_REG = reg; + + reg = QSPIC2->QSPIC2_AWRITECMD_REG; + QSPIC2_AWRITECMD_REG_SET_FIELD(QSPIC_WR_DAT_TX_MD, reg, + DT_INST_ENUM_IDX(0, tx_data_mode)); + QSPIC2_AWRITECMD_REG_SET_FIELD(QSPIC_WR_ADR_TX_MD, reg, + DT_INST_ENUM_IDX(0, tx_addr_mode)); + QSPIC2_AWRITECMD_REG_SET_FIELD(QSPIC_WR_INST_TX_MD, reg, + DT_INST_ENUM_IDX(0, tx_inst_mode)); + QSPIC2_AWRITECMD_REG_SET_FIELD(QSPIC_WR_INST, reg, + DT_INST_PROP(0, write_cmd)); + QSPIC2->QSPIC2_AWRITECMD_REG = reg; +} + +/* Read PSRAM/NOR device ID using JEDEC commands. */ +static bool memc_jedec_read_and_verify_id(QSPIC_TYPE qspi_id) +{ + uint16_t device_density; + bool ret = 0; + qspi_memory_id_t memory_id; + + da1469x_qspi_memory_jedec_read_id(qspi_id, &memory_id); + + device_density = DT_INST_PROP(0, dev_density); + ret |= !(memory_id.id == DT_INST_PROP(0, dev_id)); + ret |= !(memory_id.type == DT_INST_PROP(0, dev_type)); + ret |= !((memory_id.density & (device_density >> 8)) == (device_density & 0xFF)); + + return ret; +} + +static int memc_smartbond_init(const struct device *dev) +{ + uint32_t qspic_ctrlmode_reg; + + /* First QSPI controller is enabled so registers can be accessed */ + memc_set_status(true, DT_INST_PROP_OR(0, clock_div, 0)); + + /* Apply the min. required settings before performing any transaction in manual mode. */ + qspic_ctrlmode_reg = QSPIC2->QSPIC2_CTRLMODE_REG; + QSPIC2_CTRLMODE_REG_SET_FIELD(QSPIC_CLK_MD, qspic_ctrlmode_reg, + DT_INST_ENUM_IDX(0, clock_mode)); + QSPIC2_CTRLMODE_REG_SET_FIELD(QSPIC_AUTO_MD, qspic_ctrlmode_reg, 0); + QSPIC2->QSPIC2_CTRLMODE_REG = qspic_ctrlmode_reg; + + /* Reset PSRAM/NOR device using JDEC commands */ + da1469x_qspi_memory_jedec_reset(QSPIC2_ID); + + /* Wait till reset is completed */ + k_usleep(DT_INST_PROP(0, reset_delay_us)); + + if (memc_jedec_read_and_verify_id(QSPIC2_ID)) { + LOG_ERR("Device detection failed"); + memc_set_status(false, 0); + + return -EINVAL; + } + +#if DT_INST_PROP(0, enter_qpi_mode) + da1469x_qspi_enter_exit_qpi_mode(QSPIC2_ID, true, DT_INST_PROP(0, enter_qpi_cmd)); +#endif + + /* Should be called prior to switching to auto mode and when the quad bus is selected! */ + da1469x_qspi_set_bus_mode(QSPIC2_ID, QSPI_BUS_MODE_QUAD); + +#if CONFIG_PM_DEVICE_RUNTIME + /* + * Turn off the controller to minimize power consumption. Application is responsible to + * configure/de-configure the controller before interacting with the memory. + */ + memc_set_status(false, 0); + + /* Make sure device is marked as suspended */ + pm_device_init_suspended(dev); + + return pm_device_runtime_enable(dev); +#else + da1469x_pd_acquire(MCU_PD_DOMAIN_SYS); + + /* From this point onwards memory device should be seen as memory mapped device. */ + memc_automode_configure(); +#endif + + return 0; +} + +#ifdef CONFIG_PM_DEVICE +static int memc_smartbond_pm_action(const struct device *dev, enum pm_device_action action) +{ + switch (action) { + case PM_DEVICE_ACTION_SUSPEND: + /* + * CLK_AMBA_REG, that controlls QSPIC2, is retained during sleep + * (resides in PD_AON). However, unused blocks should be disabled + * to minimize power consumption at sleep. + */ + memc_set_status(false, 0); + + da1469x_pd_release(MCU_PD_DOMAIN_SYS); + break; + case PM_DEVICE_ACTION_RESUME: + + /* + * Mainly, required when in PM runtime mode. When in PM static mode, + * the device will block till an ongoing/pending AMBA bus transfer + * completes. + */ + da1469x_pd_acquire(MCU_PD_DOMAIN_SYS); + + /* + * QSPIC2 is powered by PD_SYS which is turned off during sleep and + * so QSPIC2 auto mode re-initialization is required. + * + * XXX: It's assumed that memory device's power rail, that should + * be 1V8P, is not turned off and so the device itsef does not + * require re-initialization. Revisit this part if power settings + * are changed in the future, that should include: + * + * 1. Powering off the memory device by turning off 1V8P + * (valid for FLASH/PSRAM). + * 2. Powering down the memory device so it enters the suspend/low-power + * state during sleep (valid for FLASH/NOR devices). + */ + memc_set_status(true, DT_INST_PROP_OR(0, clock_div, 0)); + memc_automode_configure(); + default: + return -ENOTSUP; + } + + return 0; +} +#endif + +#define SMARTBOND_MEMC_INIT(inst) \ + BUILD_ASSERT(inst == 0, "multiple instances are not permitted"); \ + BUILD_ASSERT(DT_INST_PROP(inst, is_ram), \ + "current driver version suports only PSRAM devices"); \ + \ + PM_DEVICE_DT_INST_DEFINE(inst, memc_smartbond_pm_action); \ + \ + DEVICE_DT_INST_DEFINE(inst, memc_smartbond_init, PM_DEVICE_DT_INST_GET(inst), \ + NULL, NULL, \ + POST_KERNEL, CONFIG_MEMC_INIT_PRIORITY, NULL); + +DT_INST_FOREACH_STATUS_OKAY(SMARTBOND_MEMC_INIT) diff --git a/drivers/mfd/CMakeLists.txt b/drivers/mfd/CMakeLists.txt index bcd9b190e15..fa6ab5ddced 100644 --- a/drivers/mfd/CMakeLists.txt +++ b/drivers/mfd/CMakeLists.txt @@ -3,6 +3,7 @@ zephyr_library() +zephyr_library_sources_ifdef(CONFIG_MFD_ADP5585 mfd_adp5585.c) 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) diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index b487c3556b0..c384249daed 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -19,6 +19,7 @@ config MFD_INIT_PRIORITY Multi-function devices initialization priority. source "drivers/mfd/Kconfig.ad559x" +source "drivers/mfd/Kconfig.adp5585" source "drivers/mfd/Kconfig.axp192" source "drivers/mfd/Kconfig.bd8lb600fs" source "drivers/mfd/Kconfig.max20335" diff --git a/drivers/mfd/Kconfig.ad559x b/drivers/mfd/Kconfig.ad559x index 1597f60e3b2..ff0a4954942 100644 --- a/drivers/mfd/Kconfig.ad559x +++ b/drivers/mfd/Kconfig.ad559x @@ -1,5 +1,5 @@ # Copyright (c) 2023 Grinn -# SPDX -License-Identifier: Apache-2.0 +# SPDX-License-Identifier: Apache-2.0 menuconfig MFD_AD559X bool "Analog AD559x I2C/SPI configurable ADC/DAC/GPIO chip" diff --git a/drivers/mfd/Kconfig.adp5585 b/drivers/mfd/Kconfig.adp5585 new file mode 100644 index 00000000000..e08f119a72c --- /dev/null +++ b/drivers/mfd/Kconfig.adp5585 @@ -0,0 +1,17 @@ +# Copyright 2024 NXP +# SPDX-License-Identifier: Apache-2.0 + +menuconfig MFD_ADP5585 + bool "Analog ADP5585 I2C configurable GPIO/PWM/KeyScan chip" + default y + depends on DT_HAS_ADI_ADP5585_ENABLED + depends on I2C + help + Enable driver for Analog ADP5585. + +config MFD_ADP5585_INIT_PRIORITY + int "Init priority" + default 65 + depends on MFD_ADP5585 + help + Device driver initialization priority. diff --git a/drivers/mfd/Kconfig.axp192 b/drivers/mfd/Kconfig.axp192 index fed776d3656..da76c4cc615 100644 --- a/drivers/mfd/Kconfig.axp192 +++ b/drivers/mfd/Kconfig.axp192 @@ -1,5 +1,5 @@ # Copyright (c) 2023 Martin Kiepfer -# SPDX -License-Identifier: Apache-2.0 +# SPDX-License-Identifier: Apache-2.0 config MFD_AXP192 bool "AXP192 PMIC multi-function device driver" diff --git a/drivers/mfd/Kconfig.bd8lb600fs b/drivers/mfd/Kconfig.bd8lb600fs index 4029f1f2e85..752eb942fe4 100644 --- a/drivers/mfd/Kconfig.bd8lb600fs +++ b/drivers/mfd/Kconfig.bd8lb600fs @@ -1,5 +1,5 @@ # Copyright (c) 2024 SILA Embedded Solutions GmbH -# SPDX -License-Identifier: Apache-2.0 +# SPDX-License-Identifier: Apache-2.0 config MFD_BD8LB600FS bool "BD8LB600FS low side switch multi-function device driver" diff --git a/drivers/mfd/Kconfig.max20335 b/drivers/mfd/Kconfig.max20335 index 3d146de17f0..bc9ee006edc 100644 --- a/drivers/mfd/Kconfig.max20335 +++ b/drivers/mfd/Kconfig.max20335 @@ -1,5 +1,5 @@ # Copyright (c) 2023 Grinn -# SPDX -License-Identifier: Apache-2.0 +# SPDX-License-Identifier: Apache-2.0 config MFD_MAX20335 bool "MAX20335 PMIC multi-function device driver" diff --git a/drivers/mfd/Kconfig.max31790 b/drivers/mfd/Kconfig.max31790 index 2c542982d9f..1e2e9ac4e11 100644 --- a/drivers/mfd/Kconfig.max31790 +++ b/drivers/mfd/Kconfig.max31790 @@ -1,5 +1,5 @@ # Copyright (c) 2024 SILA Embedded Solutions GmbH -# SPDX -License-Identifier: Apache-2.0 +# SPDX-License-Identifier: Apache-2.0 config MFD_MAX31790 bool "Maxim Integrated MAX31790 I2C configurable PWM controller" diff --git a/drivers/mfd/Kconfig.nct38xx b/drivers/mfd/Kconfig.nct38xx index aa852d974bb..743e07689b6 100644 --- a/drivers/mfd/Kconfig.nct38xx +++ b/drivers/mfd/Kconfig.nct38xx @@ -1,5 +1,5 @@ # Copyright (c) 2023 Google, LLC -# SPDX -License-Identifier: Apache-2.0 +# SPDX-License-Identifier: Apache-2.0 config MFD_NCT38XX bool "Nuvton NCT38xx multi-function device driver" diff --git a/drivers/mfd/Kconfig.npm1300 b/drivers/mfd/Kconfig.npm1300 index 506508bd902..56a54f3005a 100644 --- a/drivers/mfd/Kconfig.npm1300 +++ b/drivers/mfd/Kconfig.npm1300 @@ -1,5 +1,5 @@ # Copyright (c) 2023 Nordic Semiconductor ASA -# SPDX -License-Identifier: Apache-2.0 +# SPDX-License-Identifier: Apache-2.0 config MFD_NPM1300 bool "nPM1300 PMIC multi-function device driver" diff --git a/drivers/mfd/Kconfig.npm6001 b/drivers/mfd/Kconfig.npm6001 index b81c942f2d6..46c0bc0d9c5 100644 --- a/drivers/mfd/Kconfig.npm6001 +++ b/drivers/mfd/Kconfig.npm6001 @@ -1,5 +1,5 @@ # Copyright (c) 2023 Nordic Semiconductor ASA -# SPDX -License-Identifier: Apache-2.0 +# SPDX-License-Identifier: Apache-2.0 config MFD_NPM6001 bool "nPM6001 PMIC multi-function device driver" diff --git a/drivers/mfd/Kconfig.tle9104 b/drivers/mfd/Kconfig.tle9104 index 8432e067adb..e102eec013b 100644 --- a/drivers/mfd/Kconfig.tle9104 +++ b/drivers/mfd/Kconfig.tle9104 @@ -1,5 +1,5 @@ # Copyright (c) 2024 SILA Embedded Solutions GmbH -# SPDX -License-Identifier: Apache-2.0 +# SPDX-License-Identifier: Apache-2.0 config MFD_TLE9104 bool "Infineon TLE9104 SPI powertrain switch" diff --git a/drivers/mfd/mfd_adp5585.c b/drivers/mfd/mfd_adp5585.c new file mode 100644 index 00000000000..d57b82035dc --- /dev/null +++ b/drivers/mfd/mfd_adp5585.c @@ -0,0 +1,145 @@ +/* + * Copyright 2024 NXP + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT adi_adp5585 + +#include +#include +#include +#include +#include +#include + +#include + +LOG_MODULE_REGISTER(adp5585, CONFIG_GPIO_LOG_LEVEL); + +static int mfd_adp5585_software_reset(const struct device *dev) +{ + const struct mfd_adp5585_config *config = dev->config; + int ret = 0; + + /** Set CONFIG to gpio by default */ + uint8_t pin_config_buf[] = { ADP5585_PIN_CONFIG_A, 0x00U, 0x00U }; + + ret = i2c_write_dt(&config->i2c_bus, pin_config_buf, sizeof(pin_config_buf)); + if (ret) { + goto out; + } + +out: + if (ret) { + LOG_ERR("%s: software reset failed: %d", dev->name, ret); + } + return ret; +} + +static void mfd_adp5585_int_gpio_handler(const struct device *dev, struct gpio_callback *gpio_cb, + uint32_t pins) +{ + ARG_UNUSED(dev); + ARG_UNUSED(pins); + + struct mfd_adp5585_data *data = CONTAINER_OF(gpio_cb, struct mfd_adp5585_data, int_gpio_cb); + + k_work_submit(&data->work); +} + +static void mfd_adp5585_work_handler(struct k_work *work) +{ + struct mfd_adp5585_data *data = CONTAINER_OF(work, struct mfd_adp5585_data, work); + const struct mfd_adp5585_config *config = data->dev->config; + uint8_t reg_int_status; + int ret = 0; + + k_sem_take(&data->lock, K_FOREVER); + /* Read Interrput Flag */ + if (ret == 0) { + ret = i2c_reg_read_byte_dt(&config->i2c_bus, ADP5585_INT_STATUS, ®_int_status); + } + /* Clear Interrput Flag */ + if (ret == 0) { + ret = i2c_reg_write_byte_dt(&config->i2c_bus, ADP5585_INT_STATUS, reg_int_status); + } + + k_sem_give(&data->lock); + +#ifdef CONFIG_GPIO_ADP5585 + if ((reg_int_status & ADP5585_INT_GPI) && device_is_ready(data->child.gpio_dev)) { + (void)gpio_adp5585_irq_handler(data->child.gpio_dev); + } +#endif /* CONFIG_GPIO_ADP5585 */ +} + +static int mfd_adp5585_init(const struct device *dev) +{ + const struct mfd_adp5585_config *config = dev->config; + struct mfd_adp5585_data *data = dev->data; + int ret; + + if (!i2c_is_ready_dt(&config->i2c_bus)) { + return -ENODEV; + } + + /* reset gpio can be left float */ + if (gpio_is_ready_dt(&config->reset_gpio)) { + ret = gpio_pin_configure_dt(&config->reset_gpio, GPIO_OUTPUT_INACTIVE); + if (ret) { + LOG_ERR("%s: configure reset pin failed: %d", dev->name, ret); + return ret; + } + } else { + LOG_WRN("%s: reset pin not configured", dev->name); + } + + ret = mfd_adp5585_software_reset(dev); + if (ret) { + return ret; + } + + if (gpio_is_ready_dt(&config->nint_gpio)) { + ret = gpio_pin_configure_dt(&config->nint_gpio, GPIO_INPUT); + if (ret < 0) { + return ret; + } + ret = gpio_pin_interrupt_configure_dt(&config->nint_gpio, GPIO_INT_EDGE_TO_ACTIVE); + if (ret != 0) { + LOG_ERR("%s: failed to configure INT interrupt: %d", dev->name, ret); + return ret; + } + + gpio_init_callback(&data->int_gpio_cb, mfd_adp5585_int_gpio_handler, + BIT(config->nint_gpio.pin)); + ret = gpio_add_callback_dt(&config->nint_gpio, &data->int_gpio_cb); + if (ret != 0) { + LOG_ERR("%s: failed to add INT callback: %d", dev->name, ret); + return ret; + } + } else { + LOG_WRN("%s: nint pin not configured", dev->name); + } + + LOG_DBG("%s: init ok\r\n", dev->name); + + return 0; +} + +#define MFD_ADP5585_DEFINE(inst) \ + static const struct mfd_adp5585_config mfd_adp5585_config_##inst = { \ + .reset_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, reset_gpios, {0}), \ + .nint_gpio = GPIO_DT_SPEC_INST_GET_OR(n, nint_gpios, {0}), \ + .i2c_bus = I2C_DT_SPEC_INST_GET(inst), \ + }; \ + static struct mfd_adp5585_data mfd_adp5585_data_##inst = { \ + .work = Z_WORK_INITIALIZER(mfd_adp5585_work_handler), \ + .lock = Z_SEM_INITIALIZER(mfd_adp5585_data_##inst.lock, 1, 1), \ + .dev = DEVICE_DT_INST_GET(inst), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(inst, mfd_adp5585_init, NULL, &mfd_adp5585_data_##inst, \ + &mfd_adp5585_config_##inst, POST_KERNEL, \ + CONFIG_MFD_ADP5585_INIT_PRIORITY, NULL); + +DT_INST_FOREACH_STATUS_OKAY(MFD_ADP5585_DEFINE); diff --git a/drivers/mfd/mfd_npm1300.c b/drivers/mfd/mfd_npm1300.c index a8cc16c15a5..2ea0818faee 100644 --- a/drivers/mfd/mfd_npm1300.c +++ b/drivers/mfd/mfd_npm1300.c @@ -29,6 +29,7 @@ #define MAIN_OFFSET_INTENCLR 0x03U #define SHIP_OFFSET_HIBERNATE 0x00U +#define SHIP_OFFSET_CFGSTROBE 0x01U #define SHIP_OFFSET_CONFIG 0x04U #define SHIP_OFFSET_LPCONFIG 0x06U @@ -175,7 +176,12 @@ static int mfd_npm1300_init(const struct device *dev) return ret; } - return mfd_npm1300_reg_write(dev, SHIP_BASE, SHIP_OFFSET_LPCONFIG, config->lp_reset); + ret = mfd_npm1300_reg_write(dev, SHIP_BASE, SHIP_OFFSET_LPCONFIG, config->lp_reset); + if (ret < 0) { + return ret; + } + + return mfd_npm1300_reg_write(dev, SHIP_BASE, SHIP_OFFSET_CFGSTROBE, 1U); } int mfd_npm1300_reg_read_burst(const struct device *dev, uint8_t base, uint8_t offset, void *data, diff --git a/drivers/mipi_dbi/mipi_dbi_smartbond.c b/drivers/mipi_dbi/mipi_dbi_smartbond.c index 6187d38d16e..480ee2158b2 100644 --- a/drivers/mipi_dbi/mipi_dbi_smartbond.c +++ b/drivers/mipi_dbi/mipi_dbi_smartbond.c @@ -62,6 +62,10 @@ struct mipi_dbi_smartbond_data { struct k_sem sync_sem; /* Flag indicating whether or not an underflow took place */ volatile bool underflow_flag; +#if defined(CONFIG_PM_DEVICE) || defined(CONFIG_PM_DEVICE_RUNTIME) + /* Flag to designate whether or not a frame update is in progress */ + bool is_active; +#endif /* Layer settings */ lcdc_smartbond_layer_cfg layer; }; @@ -80,44 +84,20 @@ struct mipi_dbi_smartbond_config { /* Mark the device is is progress and so it's not allowed to enter the sleep state. */ static void mipi_dbi_pm_get(const struct device *dev) { -#if CONFIG_PM_DEVICE - /* - * By marking the device as busy, PM will not communicate PM events - * to the device via mipi_dbi_smartbond_pm_action. It's OK if PM is - * not used at all. Executing a single frame requires waiting for - * the frame to be completed. As such, the system might enter the idle - * state if no other tasks are pending and for as long as the frame is - * being sent. - * - * XXX: Another option would be to use a flag and mark when the controller - * is in progress so a negative value other than -ENOSYS, -ENOTSUP or - * -EALREADY is returned in mipi_dbi_smartbond_pm_action. Sideffect - * of this approach is that the sleep state will be aborted at all, - * though the system could enter a low-power state, instead (see comment - * below on how to achieve a low-power state). - */ - pm_device_busy_set(dev); -#endif -#if CONFIG_PM - /* - * LCDC controller resides in PD_SYS which is turned off when the system enters - * the extended sleep state. By calling this API, a reference counter is - * incremented, designating that the specific power domain should not be turned off. - * As a result, a low-power state (i.e. ARM WFI) will be selected, instead (when the - * system is idle). - */ - (void)da1469x_pd_acquire_noconf(MCU_PD_DOMAIN_SYS); +#ifdef CONFIG_PM_DEVICE + struct mipi_dbi_smartbond_data *data = dev->data; + + data->is_active = true; #endif } /* Mark that device is inactive and so it's allowed to enter the sleep state */ static void mipi_dbi_pm_put(const struct device *dev) { -#if CONFIG_PM_DEVICE - (void)pm_device_busy_clear(dev); -#endif -#if CONFIG_PM - (void)da1469x_pd_release_nowait(MCU_PD_DOMAIN_SYS); +#ifdef CONFIG_PM_DEVICE + struct mipi_dbi_smartbond_data *data = dev->data; + + data->is_active = false; #endif } @@ -488,7 +468,7 @@ static int mipi_dbi_smartbond_resume(const struct device *dev) return mipi_dbi_smartbond_configure(dev); } -#ifdef CONFIG_PM_DEVICE +#if defined(CONFIG_PM_DEVICE) || defined(CONFIG_PM_DEVICE_RUNTIME) static int mipi_dbi_smartbond_suspend(const struct device *dev) { const struct mipi_dbi_smartbond_config *config = dev->config; @@ -508,31 +488,39 @@ static int mipi_dbi_smartbond_suspend(const struct device *dev) static int mipi_dbi_smartbond_pm_action(const struct device *dev, enum pm_device_action action) { - int ret = 0; + /* Initialize with an error code that should abort sleeping */ + int ret = -EBUSY; + struct mipi_dbi_smartbond_data *data = dev->data; switch (action) { case PM_DEVICE_ACTION_SUSPEND: - (void)mipi_dbi_smartbond_suspend(dev); - -#if CONFIG_PM_DEVICE_RUNTIME && CONFIG_PM - da1469x_pd_release_nowait(MCU_PD_DOMAIN_SYS); -#endif - break; + /* Sleep is only allowed when there are no active LCDC operations */ + if (!data->is_active) { + (void)mipi_dbi_smartbond_suspend(dev); + /* + * Once the display block is turned off, its power domain + * can be released as well. + */ + da1469x_pd_release_nowait(MCU_PD_DOMAIN_SYS); + ret = 0; + } + break; case PM_DEVICE_ACTION_RESUME: - ret = mipi_dbi_smartbond_resume(dev); + __ASSERT_NO_MSG(!data->is_active); -#if CONFIG_PM_DEVICE_RUNTIME && CONFIG_PM /* - * If resume succeeded, prevent the system from entering the - * extended sleep state (Instead, use __WFI). If not, do not - * as users should not suspend the device and thus releasing - * PD_SYS. + * Although PD_SYS should already be turned on, make sure LCD controller's + * power domain is up and running before accessing the display block. + * Acquiring PD_SYS is mandatory when in PM runtime mode. */ - if (ret == 0) { - da1469x_pd_acquire_noconf(MCU_PD_DOMAIN_SYS); - } -#endif - break; + da1469x_pd_acquire(MCU_PD_DOMAIN_SYS); + + /* + * The resume error code should not be taken into consideration + * by the PM subsystem. + */ + ret = mipi_dbi_smartbond_resume(dev); + break; default: return -ENOTSUP; } @@ -570,18 +558,13 @@ static int mipi_dbi_smartbond_init(const struct device *dev) pm_device_init_suspended(dev); ret = pm_device_runtime_enable(dev); - if ((ret < 0) && (ret != -ENOSYS)) { - return ret; - } #else + da1469x_pd_acquire(MCU_PD_DOMAIN_SYS); /* Resme if either PM is not used at all or if PM without runtime is used. */ ret = mipi_dbi_smartbond_resume(dev); - if (ret < 0) { - return ret; - } #endif - return 0; + return ret; } static struct mipi_dbi_driver_api mipi_dbi_smartbond_driver_api = { diff --git a/drivers/mipi_dbi/mipi_dbi_spi.c b/drivers/mipi_dbi/mipi_dbi_spi.c index 846158efee6..e2b3aefe53b 100644 --- a/drivers/mipi_dbi/mipi_dbi_spi.c +++ b/drivers/mipi_dbi/mipi_dbi_spi.c @@ -66,21 +66,21 @@ static int mipi_dbi_spi_write_helper(const struct device *dev, if (dbi_config->mode == MIPI_DBI_MODE_SPI_3WIRE && IS_ENABLED(CONFIG_MIPI_DBI_SPI_3WIRE)) { - struct spi_config tmp_cfg; - /* We have to emulate 3 wire mode by packing the data/command - * bit into the upper bit of the SPI transfer. - * switch SPI to 9 bit mode, and write the transfer + /* 9 bit word mode must be used, as the command/data bit + * is stored before the data word. */ - memcpy(&tmp_cfg, &dbi_config->config, sizeof(tmp_cfg)); - tmp_cfg.operation &= ~SPI_WORD_SIZE_MASK; - tmp_cfg.operation |= SPI_WORD_SET(9); + if ((dbi_config->config.operation & SPI_WORD_SIZE_MASK) + != SPI_WORD_SET(9)) { + return -ENOTSUP; + } buffer.buf = &data->spi_byte; - buffer.len = 1; + buffer.len = 2; /* Send command */ if (cmd_present) { data->spi_byte = cmd; - ret = spi_write(config->spi_dev, &tmp_cfg, &buf_set); + ret = spi_write(config->spi_dev, &dbi_config->config, + &buf_set); if (ret < 0) { goto out; } @@ -88,7 +88,8 @@ static int mipi_dbi_spi_write_helper(const struct device *dev, /* Write data, byte by byte */ for (size_t i = 0; i < len; i++) { data->spi_byte = MIPI_DBI_DC_BIT | data_buf[i]; - ret = spi_write(config->spi_dev, &tmp_cfg, &buf_set); + ret = spi_write(config->spi_dev, &dbi_config->config, + &buf_set); if (ret < 0) { goto out; } @@ -266,6 +267,14 @@ static int mipi_dbi_spi_reset(const struct device *dev, uint32_t delay) return gpio_pin_set_dt(&config->reset, 0); } +static int mipi_dbi_spi_release(const struct device *dev, + const struct mipi_dbi_config *dbi_config) +{ + const struct mipi_dbi_spi_config *config = dev->config; + + return spi_release(config->spi_dev, &dbi_config->config); +} + static int mipi_dbi_spi_init(const struct device *dev) { const struct mipi_dbi_spi_config *config = dev->config; @@ -308,6 +317,7 @@ static struct mipi_dbi_driver_api mipi_dbi_spi_driver_api = { .reset = mipi_dbi_spi_reset, .command_write = mipi_dbi_spi_command_write, .write_display = mipi_dbi_spi_write_display, + .release = mipi_dbi_spi_release, #if MIPI_DBI_SPI_READ_REQUIRED .command_read = mipi_dbi_spi_command_read, #endif diff --git a/drivers/misc/grove_lcd_rgb/Kconfig b/drivers/misc/grove_lcd_rgb/Kconfig index b6c0533c6e3..90f30fe0508 100644 --- a/drivers/misc/grove_lcd_rgb/Kconfig +++ b/drivers/misc/grove_lcd_rgb/Kconfig @@ -3,8 +3,10 @@ config GROVE_LCD_RGB bool "Seeed Grove LCD RGB Backlight" + default y + depends on DT_HAS_SEEED_GROVE_LCD_RGB_ENABLED help - Setting this value will enable driver support for the Groove-LCD RGB + Setting this value will enable driver support for the Grove-LCD RGB Backlight. if GROVE_LCD_RGB diff --git a/drivers/misc/nordic_vpr_launcher/nordic_vpr_launcher.c b/drivers/misc/nordic_vpr_launcher/nordic_vpr_launcher.c index 11b75a2c0e5..4a2f185468b 100644 --- a/drivers/misc/nordic_vpr_launcher/nordic_vpr_launcher.c +++ b/drivers/misc/nordic_vpr_launcher/nordic_vpr_launcher.c @@ -14,6 +14,9 @@ #include #include +#if defined(CONFIG_SOC_NRF54L15_ENGA_CPUAPP) && !defined(CONFIG_TRUSTED_EXECUTION_NONSECURE) +#include +#endif LOG_MODULE_REGISTER(nordic_vpr_launcher, CONFIG_NORDIC_VPR_LAUNCHER_LOG_LEVEL); @@ -38,6 +41,10 @@ static int nordic_vpr_launcher_init(const struct device *dev) } #endif +#if defined(CONFIG_SOC_NRF54L15_ENGA_CPUAPP) && !defined(CONFIG_TRUSTED_EXECUTION_NONSECURE) + nrf_spu_periph_perm_secattr_set(NRF_SPU00, nrf_address_slave_get((uint32_t)config->vpr), + true); +#endif LOG_DBG("Launching VPR (%p) from %p", config->vpr, (void *)config->exec_addr); nrf_vpr_initpc_set(config->vpr, config->exec_addr); nrf_vpr_cpurun_set(config->vpr, true); diff --git a/drivers/modem/Kconfig.cellular b/drivers/modem/Kconfig.cellular index aacf4449d28..23446c62b72 100644 --- a/drivers/modem/Kconfig.cellular +++ b/drivers/modem/Kconfig.cellular @@ -16,7 +16,7 @@ config MODEM_CELLULAR DT_HAS_SIMCOM_SIM7080_ENABLED || DT_HAS_U_BLOX_SARA_R4_ENABLED || \ DT_HAS_U_BLOX_SARA_R5_ENABLED || DT_HAS_SWIR_HL7800_ENABLED || \ DT_HAS_TELIT_ME910G1_ENABLED || DT_HAS_QUECTEL_EG25_G_ENABLED || \ - DT_HAS_NORDIC_NRF91_SLM_ENABLED) + DT_HAS_NORDIC_NRF91_SLM_ENABLED || DT_HAS_SQN_GM02S_ENABLED) help This driver uses the generic 3gpp AT commands, along with the standard protocols CMUX and PPP, to configure diff --git a/drivers/modem/modem_cellular.c b/drivers/modem/modem_cellular.c index c66264d349f..ca48f140b86 100644 --- a/drivers/modem/modem_cellular.c +++ b/drivers/modem/modem_cellular.c @@ -134,13 +134,13 @@ struct modem_cellular_data { struct modem_cellular_config { const struct device *uart; - const struct gpio_dt_spec power_gpio; - const struct gpio_dt_spec reset_gpio; - const uint16_t power_pulse_duration_ms; - const uint16_t reset_pulse_duration_ms; - const uint16_t startup_time_ms; - const uint16_t shutdown_time_ms; - const bool autostarts; + struct gpio_dt_spec power_gpio; + struct gpio_dt_spec reset_gpio; + uint16_t power_pulse_duration_ms; + uint16_t reset_pulse_duration_ms; + uint16_t startup_time_ms; + uint16_t shutdown_time_ms; + 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; @@ -408,7 +408,7 @@ static void modem_cellular_chat_on_cxreg(struct modem_chat *chat, char **argv, u if (argc == 2) { registration_status = atoi(argv[1]); - } else if (argc == 3) { + } else if (argc == 3 || argc == 6) { registration_status = atoi(argv[2]); } else { return; @@ -458,7 +458,7 @@ MODEM_CHAT_MATCHES_DEFINE(dial_abort_matches, MODEM_CHAT_MATCH("NO CARRIER", "", NULL), MODEM_CHAT_MATCH("NO DIALTONE", "", NULL)); -#if DT_HAS_COMPAT_STATUS_OKAY(swir_hl7800) +#if DT_HAS_COMPAT_STATUS_OKAY(swir_hl7800) || DT_HAS_COMPAT_STATUS_OKAY(sqn_gm02s) MODEM_CHAT_MATCH_DEFINE(connect_match, "CONNECT", "", NULL); #endif @@ -2038,6 +2038,45 @@ MODEM_CHAT_SCRIPT_DEFINE(nordic_nrf91_slm_periodic_chat_script, modem_cellular_chat_callback_handler, 4); #endif +#if DT_HAS_COMPAT_STATUS_OKAY(sqn_gm02s) +MODEM_CHAT_SCRIPT_CMDS_DEFINE(sqn_gm02s_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+CEREG=1", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CEREG?", 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+CMUX=0,0,5,127", ok_match)); + +MODEM_CHAT_SCRIPT_DEFINE(sqn_gm02s_init_chat_script, sqn_gm02s_init_chat_script_cmds, + abort_matches, modem_cellular_chat_callback_handler, 10); + +MODEM_CHAT_SCRIPT_CMDS_DEFINE(sqn_gm02s_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_NONE("AT+CFUN=1", 10000), + MODEM_CHAT_SCRIPT_CMD_RESP("ATD*99***1#", connect_match)); + +MODEM_CHAT_SCRIPT_DEFINE(sqn_gm02s_dial_chat_script, sqn_gm02s_dial_chat_script_cmds, + dial_abort_matches, modem_cellular_chat_callback_handler, 15); + +MODEM_CHAT_SCRIPT_CMDS_DEFINE(sqn_gm02s_periodic_chat_script_cmds, + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CEREG?", ok_match)); + +MODEM_CHAT_SCRIPT_DEFINE(sqn_gm02s_periodic_chat_script, + sqn_gm02s_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) @@ -2050,7 +2089,7 @@ MODEM_CHAT_SCRIPT_DEFINE(nordic_nrf91_slm_periodic_chat_script, .ppp = &MODEM_CELLULAR_INST_NAME(ppp, inst), \ }; \ \ - static struct modem_cellular_config MODEM_CELLULAR_INST_NAME(config, inst) = { \ + static const 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, {}), \ @@ -2079,7 +2118,7 @@ MODEM_CHAT_SCRIPT_DEFINE(nordic_nrf91_slm_periodic_chat_script, .ppp = &MODEM_CELLULAR_INST_NAME(ppp, inst), \ }; \ \ - static struct modem_cellular_config MODEM_CELLULAR_INST_NAME(config, inst) = { \ + static const 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, {}), \ @@ -2108,7 +2147,7 @@ MODEM_CHAT_SCRIPT_DEFINE(nordic_nrf91_slm_periodic_chat_script, .ppp = &MODEM_CELLULAR_INST_NAME(ppp, inst), \ }; \ \ - static struct modem_cellular_config MODEM_CELLULAR_INST_NAME(config, inst) = { \ + static const 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, {}), \ @@ -2137,7 +2176,7 @@ MODEM_CHAT_SCRIPT_DEFINE(nordic_nrf91_slm_periodic_chat_script, .ppp = &MODEM_CELLULAR_INST_NAME(ppp, inst), \ }; \ \ - static struct modem_cellular_config MODEM_CELLULAR_INST_NAME(config, inst) = { \ + static const 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, {}), \ @@ -2166,7 +2205,7 @@ MODEM_CHAT_SCRIPT_DEFINE(nordic_nrf91_slm_periodic_chat_script, .ppp = &MODEM_CELLULAR_INST_NAME(ppp, inst), \ }; \ \ - static struct modem_cellular_config MODEM_CELLULAR_INST_NAME(config, inst) = { \ + static const 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, {}), \ @@ -2195,7 +2234,7 @@ MODEM_CHAT_SCRIPT_DEFINE(nordic_nrf91_slm_periodic_chat_script, .ppp = &MODEM_CELLULAR_INST_NAME(ppp, inst), \ }; \ \ - static struct modem_cellular_config MODEM_CELLULAR_INST_NAME(config, inst) = { \ + static const 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, {}), \ @@ -2225,7 +2264,7 @@ MODEM_CHAT_SCRIPT_DEFINE(nordic_nrf91_slm_periodic_chat_script, .ppp = &MODEM_CELLULAR_INST_NAME(ppp, inst), \ }; \ \ - static struct modem_cellular_config MODEM_CELLULAR_INST_NAME(config, inst) = { \ + static const 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, {}), \ @@ -2254,7 +2293,7 @@ MODEM_CHAT_SCRIPT_DEFINE(nordic_nrf91_slm_periodic_chat_script, .ppp = &MODEM_CELLULAR_INST_NAME(ppp, inst), \ }; \ \ - static struct modem_cellular_config MODEM_CELLULAR_INST_NAME(config, inst) = { \ + static const 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, {}), \ @@ -2282,7 +2321,7 @@ MODEM_CHAT_SCRIPT_DEFINE(nordic_nrf91_slm_periodic_chat_script, .ppp = &MODEM_CELLULAR_INST_NAME(ppp, inst), \ }; \ \ - static struct modem_cellular_config MODEM_CELLULAR_INST_NAME(config, inst) = { \ + static const 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, {}), \ @@ -2302,6 +2341,36 @@ MODEM_CHAT_SCRIPT_DEFINE(nordic_nrf91_slm_periodic_chat_script, &MODEM_CELLULAR_INST_NAME(config, inst), POST_KERNEL, 99, \ &modem_cellular_api); +#define MODEM_CELLULAR_DEVICE_SQN_GM02S(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 const 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 = 2000, \ + .shutdown_time_ms = 5000, \ + .init_chat_script = &sqn_gm02s_init_chat_script, \ + .dial_chat_script = &sqn_gm02s_dial_chat_script, \ + .periodic_chat_script = &sqn_gm02s_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_QUECTEL_BG95) #undef DT_DRV_COMPAT @@ -2337,3 +2406,7 @@ DT_INST_FOREACH_STATUS_OKAY(MODEM_CELLULAR_DEVICE_TELIT_ME910G1) #define DT_DRV_COMPAT nordic_nrf91_slm DT_INST_FOREACH_STATUS_OKAY(MODEM_CELLULAR_DEVICE_NORDIC_NRF91_SLM) #undef DT_DRV_COMPAT + +#define DT_DRV_COMPAT sqn_gm02s +DT_INST_FOREACH_STATUS_OKAY(MODEM_CELLULAR_DEVICE_SQN_GM02S) +#undef DT_DRV_COMPAT diff --git a/drivers/net/nsos.h b/drivers/net/nsos.h index e7ece3ded7e..911e49dff2c 100644 --- a/drivers/net/nsos.h +++ b/drivers/net/nsos.h @@ -89,6 +89,21 @@ struct nsos_mid_addrinfo { struct nsos_mid_addrinfo *ai_next; }; +struct nsos_mid_iovec { + void *iov_base; + size_t iov_len; +}; + +struct nsos_mid_msghdr { + void *msg_name; /* optional socket address, big endian */ + size_t msg_namelen; /* size of socket address */ + struct nsos_mid_iovec *msg_iov; /* scatter/gather array */ + size_t msg_iovlen; /* number of elements in msg_iov */ + void *msg_control; /* ancillary data */ + size_t msg_controllen; /* ancillary data buffer len */ + int msg_flags; /* flags on received message */ +}; + static inline void nsos_socket_flag_convert(int *flags_a, int flag_a, int *flags_b, int flag_b) { @@ -108,8 +123,13 @@ int nsos_adapt_listen(int fd, int backlog); int nsos_adapt_accept(int fd, struct nsos_mid_sockaddr *addr, size_t *addrlen); int nsos_adapt_sendto(int fd, const void *buf, size_t len, int flags, const struct nsos_mid_sockaddr *addr, size_t addrlen); +int nsos_adapt_sendmsg(int fd, const struct nsos_mid_msghdr *msg_mid, int flags); int nsos_adapt_recvfrom(int fd, void *buf, size_t len, int flags, struct nsos_mid_sockaddr *addr, size_t *addrlen); +int nsos_adapt_getsockopt(int fd, int level, int optname, + void *optval, size_t *optlen); +int nsos_adapt_setsockopt(int fd, int level, int optname, + const void *optval, size_t optlen); void nsos_adapt_poll_add(struct nsos_mid_pollfd *pollfd); void nsos_adapt_poll_remove(struct nsos_mid_pollfd *pollfd); @@ -118,6 +138,8 @@ void nsos_adapt_poll_update(struct nsos_mid_pollfd *pollfd); int nsos_adapt_fcntl_getfl(int fd); int nsos_adapt_fcntl_setfl(int fd, int flags); +int nsos_adapt_fionread(int fd, int *avail); + int nsos_adapt_getaddrinfo(const char *node, const char *service, const struct nsos_mid_addrinfo *hints, struct nsos_mid_addrinfo **res, diff --git a/drivers/net/nsos_adapt.c b/drivers/net/nsos_adapt.c index 5f44b332f60..af9acd1e40e 100644 --- a/drivers/net/nsos_adapt.c +++ b/drivers/net/nsos_adapt.c @@ -10,14 +10,18 @@ * Linux (bottom) side of NSOS (Native Simulator Offloaded Sockets). */ +#define _DEFAULT_SOURCE + #include #include #include #include +#include #include #include #include #include +#include #include #include @@ -25,6 +29,7 @@ #include "nsos_errno.h" #include "nsos_fcntl.h" #include "nsos_netdb.h" +#include "nsos_socket.h" #include "board_soc.h" #include "irq_ctrl.h" @@ -445,6 +450,49 @@ int nsos_adapt_sendto(int fd, const void *buf, size_t len, int flags, return ret; } +int nsos_adapt_sendmsg(int fd, const struct nsos_mid_msghdr *msg_mid, int flags) +{ + struct sockaddr_storage addr_storage; + struct sockaddr *addr = (struct sockaddr *)&addr_storage; + struct msghdr msg; + struct iovec *msg_iov; + socklen_t addrlen; + int ret; + + ret = sockaddr_from_nsos_mid(&addr, &addrlen, msg_mid->msg_name, msg_mid->msg_namelen); + if (ret < 0) { + return ret; + } + + msg_iov = calloc(msg_mid->msg_iovlen, sizeof(*msg_iov)); + if (!msg_iov) { + ret = -ENOMEM; + return ret; + } + + for (size_t i = 0; i < msg_mid->msg_iovlen; i++) { + msg_iov[i].iov_base = msg_mid->msg_iov[i].iov_base; + msg_iov[i].iov_len = msg_mid->msg_iov[i].iov_len; + } + + msg.msg_name = addr; + msg.msg_namelen = addrlen; + msg.msg_iov = msg_iov; + msg.msg_iovlen = msg_mid->msg_iovlen; + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_flags = 0; + + ret = sendmsg(fd, &msg, socket_flags_from_nsos_mid(flags) | MSG_NOSIGNAL); + if (ret < 0) { + ret = -errno_to_nsos_mid(errno); + } + + free(msg_iov); + + return ret; +} + int nsos_adapt_recvfrom(int fd, void *buf, size_t len, int flags, struct nsos_mid_sockaddr *addr_mid, size_t *addrlen_mid) { @@ -468,6 +516,229 @@ int nsos_adapt_recvfrom(int fd, void *buf, size_t len, int flags, return ret; } +static int nsos_adapt_getsockopt_int(int fd, int level, int optname, + void *optval, size_t *nsos_mid_optlen) +{ + socklen_t optlen = *nsos_mid_optlen; + int ret; + + ret = getsockopt(fd, level, optname, optval, &optlen); + if (ret < 0) { + return -errno_to_nsos_mid(errno); + } + + *nsos_mid_optlen = optlen; + + return 0; +} + +int nsos_adapt_getsockopt(int fd, int nsos_mid_level, int nsos_mid_optname, + void *nsos_mid_optval, size_t *nsos_mid_optlen) +{ + switch (nsos_mid_level) { + case NSOS_MID_SOL_SOCKET: + switch (nsos_mid_optname) { + case NSOS_MID_SO_ERROR: { + int err; + socklen_t optlen = sizeof(err); + int ret; + + ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &optlen); + if (ret < 0) { + return -errno_to_nsos_mid(errno); + } + + *(int *)nsos_mid_optval = errno_to_nsos_mid(err); + + return 0; + } + case NSOS_MID_SO_TYPE: { + int type; + socklen_t optlen = sizeof(type); + int ret; + int err; + + ret = getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &optlen); + if (ret < 0) { + return -errno_to_nsos_mid(errno); + } + + err = socket_type_to_nsos_mid(type, nsos_mid_optval); + if (err) { + return err; + } + + return 0; + } + case NSOS_MID_SO_PROTOCOL: { + int proto; + socklen_t optlen = sizeof(proto); + int ret; + int err; + + ret = getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &proto, &optlen); + if (ret < 0) { + return -errno_to_nsos_mid(errno); + } + + err = socket_proto_to_nsos_mid(proto, nsos_mid_optval); + if (err) { + return err; + } + + return 0; + } + case NSOS_MID_SO_DOMAIN: { + int family; + socklen_t optlen = sizeof(family); + int ret; + int err; + + ret = getsockopt(fd, SOL_SOCKET, SO_DOMAIN, &family, &optlen); + if (ret < 0) { + return -errno_to_nsos_mid(errno); + } + + err = socket_family_to_nsos_mid(family, nsos_mid_optval); + if (err) { + return err; + } + + return 0; + } + case NSOS_MID_SO_RCVBUF: + return nsos_adapt_getsockopt_int(fd, SOL_SOCKET, SO_RCVBUF, + nsos_mid_optval, nsos_mid_optlen); + case NSOS_MID_SO_SNDBUF: + return nsos_adapt_getsockopt_int(fd, SOL_SOCKET, SO_SNDBUF, + nsos_mid_optval, nsos_mid_optlen); + case NSOS_MID_SO_REUSEADDR: + return nsos_adapt_getsockopt_int(fd, SOL_SOCKET, SO_REUSEADDR, + nsos_mid_optval, nsos_mid_optlen); + case NSOS_MID_SO_REUSEPORT: + return nsos_adapt_getsockopt_int(fd, SOL_SOCKET, SO_REUSEPORT, + nsos_mid_optval, nsos_mid_optlen); + case NSOS_MID_SO_LINGER: + return nsos_adapt_getsockopt_int(fd, SOL_SOCKET, SO_LINGER, + nsos_mid_optval, nsos_mid_optlen); + case NSOS_MID_SO_KEEPALIVE: + return nsos_adapt_getsockopt_int(fd, SOL_SOCKET, SO_KEEPALIVE, + nsos_mid_optval, nsos_mid_optlen); + } + + case NSOS_MID_IPPROTO_TCP: + switch (nsos_mid_optname) { + case NSOS_MID_TCP_NODELAY: + return nsos_adapt_getsockopt_int(fd, IPPROTO_TCP, TCP_NODELAY, + nsos_mid_optval, nsos_mid_optlen); + case NSOS_MID_TCP_KEEPIDLE: + return nsos_adapt_getsockopt_int(fd, IPPROTO_TCP, TCP_KEEPIDLE, + nsos_mid_optval, nsos_mid_optlen); + case NSOS_MID_TCP_KEEPINTVL: + return nsos_adapt_getsockopt_int(fd, IPPROTO_TCP, TCP_KEEPINTVL, + nsos_mid_optval, nsos_mid_optlen); + case NSOS_MID_TCP_KEEPCNT: + return nsos_adapt_getsockopt_int(fd, IPPROTO_TCP, TCP_KEEPCNT, + nsos_mid_optval, nsos_mid_optlen); + } + + case NSOS_MID_IPPROTO_IPV6: + switch (nsos_mid_optname) { + case NSOS_MID_IPV6_V6ONLY: + return nsos_adapt_getsockopt_int(fd, IPPROTO_IPV6, IPV6_V6ONLY, + nsos_mid_optval, nsos_mid_optlen); + } + } + + return -NSOS_MID_EOPNOTSUPP; +} + +static int nsos_adapt_setsockopt_int(int fd, int level, int optname, + const void *optval, size_t optlen) +{ + int ret; + + ret = setsockopt(fd, level, optname, optval, optlen); + if (ret < 0) { + return -errno_to_nsos_mid(errno); + } + + return 0; +} + +int nsos_adapt_setsockopt(int fd, int nsos_mid_level, int nsos_mid_optname, + const void *nsos_mid_optval, size_t nsos_mid_optlen) +{ + switch (nsos_mid_level) { + case NSOS_MID_SOL_SOCKET: + switch (nsos_mid_optname) { + case NSOS_MID_SO_PRIORITY: + return nsos_adapt_setsockopt_int(fd, SOL_SOCKET, SO_PRIORITY, + nsos_mid_optval, nsos_mid_optlen); + + case NSOS_MID_SO_RCVTIMEO: { + const struct nsos_mid_timeval *nsos_mid_tv = nsos_mid_optval; + struct timeval tv = { + .tv_sec = nsos_mid_tv->tv_sec, + .tv_usec = nsos_mid_tv->tv_usec, + }; + int ret; + + ret = setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, + &tv, sizeof(tv)); + if (ret < 0) { + return -errno_to_nsos_mid(errno); + } + + return 0; + } + case NSOS_MID_SO_RCVBUF: + return nsos_adapt_setsockopt_int(fd, SOL_SOCKET, SO_RCVBUF, + nsos_mid_optval, nsos_mid_optlen); + case NSOS_MID_SO_SNDBUF: + return nsos_adapt_setsockopt_int(fd, SOL_SOCKET, SO_SNDBUF, + nsos_mid_optval, nsos_mid_optlen); + case NSOS_MID_SO_REUSEADDR: + return nsos_adapt_setsockopt_int(fd, SOL_SOCKET, SO_REUSEADDR, + nsos_mid_optval, nsos_mid_optlen); + case NSOS_MID_SO_REUSEPORT: + return nsos_adapt_setsockopt_int(fd, SOL_SOCKET, SO_REUSEPORT, + nsos_mid_optval, nsos_mid_optlen); + case NSOS_MID_SO_LINGER: + return nsos_adapt_setsockopt_int(fd, SOL_SOCKET, SO_LINGER, + nsos_mid_optval, nsos_mid_optlen); + case NSOS_MID_SO_KEEPALIVE: + return nsos_adapt_setsockopt_int(fd, SOL_SOCKET, SO_KEEPALIVE, + nsos_mid_optval, nsos_mid_optlen); + } + + case NSOS_MID_IPPROTO_TCP: + switch (nsos_mid_optname) { + case NSOS_MID_TCP_NODELAY: + return nsos_adapt_setsockopt_int(fd, IPPROTO_TCP, TCP_NODELAY, + nsos_mid_optval, nsos_mid_optlen); + case NSOS_MID_TCP_KEEPIDLE: + return nsos_adapt_setsockopt_int(fd, IPPROTO_TCP, TCP_KEEPIDLE, + nsos_mid_optval, nsos_mid_optlen); + case NSOS_MID_TCP_KEEPINTVL: + return nsos_adapt_setsockopt_int(fd, IPPROTO_TCP, TCP_KEEPINTVL, + nsos_mid_optval, nsos_mid_optlen); + case NSOS_MID_TCP_KEEPCNT: + return nsos_adapt_setsockopt_int(fd, IPPROTO_TCP, TCP_KEEPCNT, + nsos_mid_optval, nsos_mid_optlen); + } + + case NSOS_MID_IPPROTO_IPV6: + switch (nsos_mid_optname) { + case NSOS_MID_IPV6_V6ONLY: + return nsos_adapt_setsockopt_int(fd, IPPROTO_IPV6, IPV6_V6ONLY, + nsos_mid_optval, nsos_mid_optlen); + } + } + + return -NSOS_MID_EOPNOTSUPP; +} + #define MAP_POLL_EPOLL(_event_from, _event_to) \ if (events_from & (_event_from)) { \ events_from &= ~(_event_from); \ @@ -481,6 +752,7 @@ static int nsos_poll_to_epoll_events(int events_from) MAP_POLL_EPOLL(POLLIN, EPOLLIN); MAP_POLL_EPOLL(POLLOUT, EPOLLOUT); MAP_POLL_EPOLL(POLLERR, EPOLLERR); + MAP_POLL_EPOLL(POLLHUP, EPOLLHUP); return events_to; } @@ -492,6 +764,7 @@ static int nsos_epoll_to_poll_events(int events_from) MAP_POLL_EPOLL(EPOLLIN, POLLIN); MAP_POLL_EPOLL(EPOLLOUT, POLLOUT); MAP_POLL_EPOLL(EPOLLERR, POLLERR); + MAP_POLL_EPOLL(EPOLLHUP, POLLHUP); return events_to; } @@ -716,6 +989,18 @@ int nsos_adapt_fcntl_setfl(int fd, int flags) return 0; } +int nsos_adapt_fionread(int fd, int *avail) +{ + int ret; + + ret = ioctl(fd, FIONREAD, avail); + if (ret < 0) { + return -errno_to_nsos_mid(errno); + } + + return 0; +} + static void nsos_adapt_init(void) { nsos_epoll_fd = epoll_create(1); diff --git a/drivers/net/nsos_fcntl.c b/drivers/net/nsos_fcntl.c index be49d3ec63e..ab4d22ce51a 100644 --- a/drivers/net/nsos_fcntl.c +++ b/drivers/net/nsos_fcntl.c @@ -16,7 +16,14 @@ * symbols. */ +/* + * When building for Zephyr, use Zephyr specific fcntl definitions. + */ +#ifdef __ZEPHYR__ +#include +#else #include +#endif #include "nsos_errno.h" #include "nsos_fcntl.h" diff --git a/drivers/net/nsos_socket.h b/drivers/net/nsos_socket.h new file mode 100644 index 00000000000..66f54130d17 --- /dev/null +++ b/drivers/net/nsos_socket.h @@ -0,0 +1,134 @@ +/** + * Copyright (c) 2024 Marcin Niestroj + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __DRIVERS_NET_NSOS_SOCKET_H__ +#define __DRIVERS_NET_NSOS_SOCKET_H__ + +#include + +/** + * @name Socket level options (NSOS_MID_SOL_SOCKET) + * @{ + */ +/** Socket-level option */ +#define NSOS_MID_SOL_SOCKET 1 + +/* Socket options for NSOS_MID_SOL_SOCKET level */ + +/** Recording debugging information (ignored, for compatibility) */ +#define NSOS_MID_SO_DEBUG 1 +/** address reuse */ +#define NSOS_MID_SO_REUSEADDR 2 +/** Type of the socket */ +#define NSOS_MID_SO_TYPE 3 +/** Async error */ +#define NSOS_MID_SO_ERROR 4 +/** Bypass normal routing and send directly to host (ignored, for compatibility) */ +#define NSOS_MID_SO_DONTROUTE 5 +/** Transmission of broadcast messages is supported (ignored, for compatibility) */ +#define NSOS_MID_SO_BROADCAST 6 + +/** Size of socket send buffer */ +#define NSOS_MID_SO_SNDBUF 7 +/** Size of socket recv buffer */ +#define NSOS_MID_SO_RCVBUF 8 + +/** Enable sending keep-alive messages on connections */ +#define NSOS_MID_SO_KEEPALIVE 9 +/** Place out-of-band data into receive stream (ignored, for compatibility) */ +#define NSOS_MID_SO_OOBINLINE 10 +/** Socket priority */ +#define NSOS_MID_SO_PRIORITY 12 +/** Socket lingers on close (ignored, for compatibility) */ +#define NSOS_MID_SO_LINGER 13 +/** Allow multiple sockets to reuse a single port */ +#define NSOS_MID_SO_REUSEPORT 15 + +/** Receive low watermark (ignored, for compatibility) */ +#define NSOS_MID_SO_RCVLOWAT 18 +/** Send low watermark (ignored, for compatibility) */ +#define NSOS_MID_SO_SNDLOWAT 19 + +/** + * Receive timeout + * Applies to receive functions like recv(), but not to connect() + */ +#define NSOS_MID_SO_RCVTIMEO 20 +/** Send timeout */ +#define NSOS_MID_SO_SNDTIMEO 21 + +/** Bind a socket to an interface */ +#define NSOS_MID_SO_BINDTODEVICE 25 + +/** Socket accepts incoming connections (ignored, for compatibility) */ +#define NSOS_MID_SO_ACCEPTCONN 30 + +/** Timestamp TX packets */ +#define NSOS_MID_SO_TIMESTAMPING 37 +/** Protocol used with the socket */ +#define NSOS_MID_SO_PROTOCOL 38 + +/** Domain used with SOCKET */ +#define NSOS_MID_SO_DOMAIN 39 + +/** Enable SOCKS5 for Socket */ +#define NSOS_MID_SO_SOCKS5 60 + +/** Socket TX time (when the data should be sent) */ +#define NSOS_MID_SO_TXTIME 61 + +struct nsos_mid_timeval { + int64_t tv_sec; + int64_t tv_usec; +}; + +/** @} */ + +/** + * @name TCP level options (NSOS_MID_IPPROTO_TCP) + * @{ + */ +/* Socket options for NSOS_MID_IPPROTO_TCP level */ +/** Disable TCP buffering (ignored, for compatibility) */ +#define NSOS_MID_TCP_NODELAY 1 +/** Start keepalives after this period (seconds) */ +#define NSOS_MID_TCP_KEEPIDLE 2 +/** Interval between keepalives (seconds) */ +#define NSOS_MID_TCP_KEEPINTVL 3 +/** Number of keepalives before dropping connection */ +#define NSOS_MID_TCP_KEEPCNT 4 + +/** @} */ + +/** + * @name IPv6 level options (NSOS_MID_IPPROTO_IPV6) + * @{ + */ +/* Socket options for NSOS_MID_IPPROTO_IPV6 level */ +/** Set the unicast hop limit for the socket. */ +#define NSOS_MID_IPV6_UNICAST_HOPS 16 + +/** Set the multicast hop limit for the socket. */ +#define NSOS_MID_IPV6_MULTICAST_HOPS 18 + +/** Join IPv6 multicast group. */ +#define NSOS_MID_IPV6_ADD_MEMBERSHIP 20 + +/** Leave IPv6 multicast group. */ +#define NSOS_MID_IPV6_DROP_MEMBERSHIP 21 + +/** Don't support IPv4 access */ +#define NSOS_MID_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 NSOS_MID_IPV6_RECVPKTINFO 49 + +/** @} */ + +#endif /* __DRIVERS_NET_NSOS_SOCKET_H__ */ diff --git a/drivers/net/nsos_sockets.c b/drivers/net/nsos_sockets.c index 2e1ff4589d1..1c7df2af830 100644 --- a/drivers/net/nsos_sockets.c +++ b/drivers/net/nsos_sockets.c @@ -28,6 +28,7 @@ #include "nsos_errno.h" #include "nsos_fcntl.h" #include "nsos_netdb.h" +#include "nsos_socket.h" #include "nsi_host_trampolines.h" @@ -41,6 +42,8 @@ struct nsos_socket { struct nsos_mid_pollfd pollfd; struct k_poll_signal poll; + k_timeout_t recv_timeout; + sys_dnode_t node; }; @@ -179,6 +182,7 @@ static int nsos_socket_create(int family, int type, int proto) } sock->fd = fd; + sock->recv_timeout = K_FOREVER; sock->pollfd.fd = nsos_adapt_socket(family_mid, type_mid, proto_mid); if (sock->pollfd.fd < 0) { @@ -261,8 +265,7 @@ static int nsos_poll_prepare(struct nsos_socket *sock, struct zsock_pollfd *pfd, sock->pollfd.cb = pollcb; if (*pev == pev_end) { - errno = ENOMEM; - return -1; + return -ENOMEM; } k_poll_signal_init(&sock->poll); @@ -367,12 +370,21 @@ static int nsos_ioctl(void *obj, unsigned int request, va_list args) return -errno_from_nsos_mid(-ret); } + + case ZFD_IOCTL_FIONREAD: { + int *avail = va_arg(args, int *); + int ret; + + ret = nsos_adapt_fionread(sock->pollfd.fd, avail); + + return -errno_from_nsos_mid(-ret); + } } return -EINVAL; } -static int sockaddr_to_nsos_mid(const struct sockaddr *addr, socklen_t *addrlen, +static int sockaddr_to_nsos_mid(const struct sockaddr *addr, socklen_t addrlen, struct nsos_mid_sockaddr **addr_mid, size_t *addrlen_mid) { if (!addr || !addrlen) { @@ -389,7 +401,7 @@ static int sockaddr_to_nsos_mid(const struct sockaddr *addr, socklen_t *addrlen, struct nsos_mid_sockaddr_in *addr_in_mid = (struct nsos_mid_sockaddr_in *)*addr_mid; - if (*addrlen < sizeof(*addr_in)) { + if (addrlen < sizeof(*addr_in)) { return -NSOS_MID_EINVAL; } @@ -407,7 +419,7 @@ static int sockaddr_to_nsos_mid(const struct sockaddr *addr, socklen_t *addrlen, struct nsos_mid_sockaddr_in6 *addr_in_mid = (struct nsos_mid_sockaddr_in6 *)*addr_mid; - if (*addrlen < sizeof(*addr_in)) { + if (addrlen < sizeof(*addr_in)) { return -NSOS_MID_EINVAL; } @@ -477,7 +489,7 @@ static int nsos_bind(void *obj, const struct sockaddr *addr, socklen_t addrlen) size_t addrlen_mid; int ret; - ret = sockaddr_to_nsos_mid(addr, &addrlen, &addr_mid, &addrlen_mid); + ret = sockaddr_to_nsos_mid(addr, addrlen, &addr_mid, &addrlen_mid); if (ret < 0) { goto return_ret; } @@ -501,7 +513,7 @@ static int nsos_connect(void *obj, const struct sockaddr *addr, socklen_t addrle size_t addrlen_mid; int ret; - ret = sockaddr_to_nsos_mid(addr, &addrlen, &addr_mid, &addrlen_mid); + ret = sockaddr_to_nsos_mid(addr, addrlen, &addr_mid, &addrlen_mid); if (ret < 0) { goto return_ret; } @@ -549,7 +561,7 @@ static int nsos_wait_for_pollin(struct nsos_socket *sock) return ret; } - ret = k_poll(poll_events, ARRAY_SIZE(poll_events), K_FOREVER); + ret = k_poll(poll_events, ARRAY_SIZE(poll_events), sock->recv_timeout); if (ret != 0 && ret != -EAGAIN && ret != -EINTR) { return ret; } @@ -611,6 +623,7 @@ static int nsos_accept(void *obj, struct sockaddr *addr, socklen_t *addrlen) zephyr_fd = z_reserve_fd(); if (zephyr_fd < 0) { + errno = -zephyr_fd; goto close_adapt_fd; } @@ -653,7 +666,7 @@ static ssize_t nsos_sendto(void *obj, const void *buf, size_t len, int flags, flags_mid = ret; - ret = sockaddr_to_nsos_mid(addr, &addrlen, &addr_mid, &addrlen_mid); + ret = sockaddr_to_nsos_mid(addr, addrlen, &addr_mid, &addrlen_mid); if (ret < 0) { goto return_ret; } @@ -672,8 +685,57 @@ static ssize_t nsos_sendto(void *obj, const void *buf, size_t len, int flags, static ssize_t nsos_sendmsg(void *obj, const struct msghdr *msg, int flags) { - errno = ENOTSUP; - return -1; + struct nsos_socket *sock = obj; + struct nsos_mid_sockaddr_storage addr_storage_mid; + struct nsos_mid_sockaddr *addr_mid = (struct nsos_mid_sockaddr *)&addr_storage_mid; + size_t addrlen_mid = sizeof(addr_storage_mid); + struct nsos_mid_msghdr msg_mid; + struct nsos_mid_iovec *msg_iov; + int flags_mid; + int ret; + + ret = socket_flags_to_nsos_mid(flags); + if (ret < 0) { + goto return_ret; + } + + flags_mid = ret; + + ret = sockaddr_to_nsos_mid(msg->msg_name, msg->msg_namelen, &addr_mid, &addrlen_mid); + if (ret < 0) { + goto return_ret; + } + + msg_iov = k_calloc(msg->msg_iovlen, sizeof(*msg_iov)); + if (!msg_iov) { + ret = -NSOS_MID_ENOMEM; + goto return_ret; + } + + for (size_t i = 0; i < msg->msg_iovlen; i++) { + msg_iov[i].iov_base = msg->msg_iov[i].iov_base; + msg_iov[i].iov_len = msg->msg_iov[i].iov_len; + } + + msg_mid.msg_name = addr_mid; + msg_mid.msg_namelen = addrlen_mid; + msg_mid.msg_iov = msg_iov; + msg_mid.msg_iovlen = msg->msg_iovlen; + msg_mid.msg_control = NULL; + msg_mid.msg_controllen = 0; + msg_mid.msg_flags = 0; + + ret = nsos_adapt_sendmsg(sock->pollfd.fd, &msg_mid, flags_mid); + + k_free(msg_iov); + +return_ret: + if (ret < 0) { + errno = errno_from_nsos_mid(-ret); + return -1; + } + + return ret; } static int nsos_recvfrom_with_poll(struct nsos_socket *sock, void *buf, size_t len, int flags, @@ -746,6 +808,393 @@ static ssize_t nsos_recvmsg(void *obj, struct msghdr *msg, int flags) return -1; } +static int socket_type_from_nsos_mid(int type_mid, int *type) +{ + switch (type_mid) { + case NSOS_MID_SOCK_STREAM: + *type = SOCK_STREAM; + break; + case NSOS_MID_SOCK_DGRAM: + *type = SOCK_DGRAM; + break; + case NSOS_MID_SOCK_RAW: + *type = SOCK_RAW; + break; + default: + return -NSOS_MID_ESOCKTNOSUPPORT; + } + + return 0; +} + +static int socket_proto_from_nsos_mid(int proto_mid, int *proto) +{ + switch (proto_mid) { + case NSOS_MID_IPPROTO_IP: + *proto = IPPROTO_IP; + break; + case NSOS_MID_IPPROTO_ICMP: + *proto = IPPROTO_ICMP; + break; + case NSOS_MID_IPPROTO_IGMP: + *proto = IPPROTO_IGMP; + break; + case NSOS_MID_IPPROTO_IPIP: + *proto = IPPROTO_IPIP; + break; + case NSOS_MID_IPPROTO_TCP: + *proto = IPPROTO_TCP; + break; + case NSOS_MID_IPPROTO_UDP: + *proto = IPPROTO_UDP; + break; + case NSOS_MID_IPPROTO_IPV6: + *proto = IPPROTO_IPV6; + break; + case NSOS_MID_IPPROTO_RAW: + *proto = IPPROTO_RAW; + break; + default: + return -NSOS_MID_EPROTONOSUPPORT; + } + + return 0; +} + +static int socket_family_from_nsos_mid(int family_mid, int *family) +{ + switch (family_mid) { + case NSOS_MID_AF_UNSPEC: + *family = AF_UNSPEC; + break; + case NSOS_MID_AF_INET: + *family = AF_INET; + break; + case NSOS_MID_AF_INET6: + *family = AF_INET6; + break; + default: + return -NSOS_MID_EAFNOSUPPORT; + } + + return 0; +} + +static int nsos_getsockopt_int(struct nsos_socket *sock, int nsos_mid_level, int nsos_mid_optname, + void *optval, socklen_t *optlen) +{ + size_t nsos_mid_optlen = sizeof(int); + int err; + + if (*optlen != sizeof(int)) { + errno = EINVAL; + return -1; + } + + err = nsos_adapt_getsockopt(sock->pollfd.fd, NSOS_MID_SOL_SOCKET, + NSOS_MID_SO_KEEPALIVE, optval, &nsos_mid_optlen); + if (err) { + errno = errno_from_nsos_mid(-err); + return -1; + } + + *optlen = nsos_mid_optlen; + + return 0; +} + +static int nsos_getsockopt(void *obj, int level, int optname, + void *optval, socklen_t *optlen) +{ + struct nsos_socket *sock = obj; + + switch (level) { + case SOL_SOCKET: + switch (optname) { + case SO_ERROR: { + int nsos_mid_err; + int err; + + if (*optlen != sizeof(int)) { + errno = EINVAL; + return -1; + } + + err = nsos_adapt_getsockopt(sock->pollfd.fd, NSOS_MID_SOL_SOCKET, + NSOS_MID_SO_ERROR, &nsos_mid_err, NULL); + if (err) { + errno = errno_from_nsos_mid(-err); + return -1; + } + + *(int *)optval = errno_from_nsos_mid(nsos_mid_err); + + return 0; + } + case SO_TYPE: { + int nsos_mid_type; + int err; + + if (*optlen != sizeof(nsos_mid_type)) { + errno = EINVAL; + return -1; + } + + err = nsos_adapt_getsockopt(sock->pollfd.fd, NSOS_MID_SOL_SOCKET, + NSOS_MID_SO_TYPE, &nsos_mid_type, NULL); + if (err) { + errno = errno_from_nsos_mid(-err); + return -1; + } + + err = socket_type_from_nsos_mid(nsos_mid_type, optval); + if (err) { + errno = errno_from_nsos_mid(-err); + return -1; + } + + return 0; + } + case SO_PROTOCOL: { + int nsos_mid_proto; + int err; + + if (*optlen != sizeof(nsos_mid_proto)) { + errno = EINVAL; + return -1; + } + + err = nsos_adapt_getsockopt(sock->pollfd.fd, NSOS_MID_SOL_SOCKET, + NSOS_MID_SO_PROTOCOL, &nsos_mid_proto, NULL); + if (err) { + errno = errno_from_nsos_mid(-err); + return -1; + } + + err = socket_proto_from_nsos_mid(nsos_mid_proto, optval); + if (err) { + errno = errno_from_nsos_mid(-err); + return -1; + } + + return 0; + } + case SO_DOMAIN: { + int nsos_mid_family; + int err; + + if (*optlen != sizeof(nsos_mid_family)) { + errno = EINVAL; + return -1; + } + + err = nsos_adapt_getsockopt(sock->pollfd.fd, NSOS_MID_SOL_SOCKET, + NSOS_MID_SO_DOMAIN, &nsos_mid_family, NULL); + if (err) { + errno = errno_from_nsos_mid(-err); + return -1; + } + + err = socket_family_from_nsos_mid(nsos_mid_family, optval); + if (err) { + errno = errno_from_nsos_mid(-err); + return -1; + } + + return 0; + } + case SO_RCVBUF: + return nsos_getsockopt_int(sock, + NSOS_MID_SOL_SOCKET, NSOS_MID_SO_RCVBUF, + optval, optlen); + case SO_SNDBUF: + return nsos_getsockopt_int(sock, + NSOS_MID_SOL_SOCKET, NSOS_MID_SO_SNDBUF, + optval, optlen); + case SO_REUSEADDR: + return nsos_getsockopt_int(sock, + NSOS_MID_SOL_SOCKET, NSOS_MID_SO_REUSEADDR, + optval, optlen); + case SO_REUSEPORT: + return nsos_getsockopt_int(sock, + NSOS_MID_SOL_SOCKET, NSOS_MID_SO_REUSEPORT, + optval, optlen); + case SO_KEEPALIVE: + return nsos_getsockopt_int(sock, + NSOS_MID_SOL_SOCKET, NSOS_MID_SO_KEEPALIVE, + optval, optlen); + } + + case IPPROTO_TCP: + switch (optname) { + case TCP_NODELAY: + return nsos_getsockopt_int(sock, + NSOS_MID_IPPROTO_TCP, NSOS_MID_TCP_NODELAY, + optval, optlen); + case TCP_KEEPIDLE: + return nsos_getsockopt_int(sock, + NSOS_MID_IPPROTO_TCP, NSOS_MID_TCP_KEEPIDLE, + optval, optlen); + case TCP_KEEPINTVL: + return nsos_getsockopt_int(sock, + NSOS_MID_IPPROTO_TCP, NSOS_MID_TCP_KEEPINTVL, + optval, optlen); + case TCP_KEEPCNT: + return nsos_getsockopt_int(sock, + NSOS_MID_IPPROTO_TCP, NSOS_MID_TCP_KEEPCNT, + optval, optlen); + } + + case IPPROTO_IPV6: + switch (optname) { + case IPV6_V6ONLY: + return nsos_getsockopt_int(sock, + NSOS_MID_IPPROTO_IPV6, NSOS_MID_IPV6_V6ONLY, + optval, optlen); + } + } + + errno = EOPNOTSUPP; + return -1; +} + +static int nsos_setsockopt_int(struct nsos_socket *sock, int nsos_mid_level, int nsos_mid_optname, + const void *optval, socklen_t optlen) +{ + int err; + + if (optlen != sizeof(int)) { + errno = EINVAL; + return -1; + } + + err = nsos_adapt_setsockopt(sock->pollfd.fd, nsos_mid_level, nsos_mid_optname, + optval, optlen); + if (err) { + errno = errno_from_nsos_mid(-err); + return -1; + } + + return 0; +} + +static int nsos_setsockopt(void *obj, int level, int optname, + const void *optval, socklen_t optlen) +{ + struct nsos_socket *sock = obj; + + switch (level) { + case SOL_SOCKET: + switch (optname) { + case SO_PRIORITY: { + int nsos_mid_priority; + int err; + + if (optlen != sizeof(uint8_t)) { + errno = EINVAL; + return -1; + } + + nsos_mid_priority = *(uint8_t *)optval; + + err = nsos_adapt_setsockopt(sock->pollfd.fd, NSOS_MID_SOL_SOCKET, + NSOS_MID_SO_PRIORITY, &nsos_mid_priority, + sizeof(nsos_mid_priority)); + if (err) { + errno = errno_from_nsos_mid(-err); + return -1; + } + + return 0; + } + case SO_RCVTIMEO: { + const struct zsock_timeval *tv = optval; + struct nsos_mid_timeval nsos_mid_tv; + int err; + + if (optlen != sizeof(struct zsock_timeval)) { + errno = EINVAL; + return -1; + } + + nsos_mid_tv.tv_sec = tv->tv_sec; + nsos_mid_tv.tv_usec = tv->tv_usec; + + err = nsos_adapt_setsockopt(sock->pollfd.fd, NSOS_MID_SOL_SOCKET, + NSOS_MID_SO_RCVTIMEO, &nsos_mid_tv, + sizeof(nsos_mid_tv)); + if (err) { + errno = errno_from_nsos_mid(-err); + return -1; + } + + if (tv->tv_sec == 0 && tv->tv_usec == 0) { + sock->recv_timeout = K_FOREVER; + } else { + sock->recv_timeout = K_USEC(tv->tv_sec * 1000000LL + tv->tv_usec); + } + + return 0; + } + case SO_RCVBUF: + return nsos_setsockopt_int(sock, + NSOS_MID_SOL_SOCKET, NSOS_MID_SO_RCVBUF, + optval, optlen); + case SO_SNDBUF: + return nsos_setsockopt_int(sock, + NSOS_MID_SOL_SOCKET, NSOS_MID_SO_SNDBUF, + optval, optlen); + case SO_REUSEADDR: + return nsos_setsockopt_int(sock, + NSOS_MID_SOL_SOCKET, NSOS_MID_SO_REUSEADDR, + optval, optlen); + case SO_REUSEPORT: + return nsos_setsockopt_int(sock, + NSOS_MID_SOL_SOCKET, NSOS_MID_SO_REUSEPORT, + optval, optlen); + case SO_LINGER: + return nsos_setsockopt_int(sock, + NSOS_MID_SOL_SOCKET, NSOS_MID_SO_LINGER, + optval, optlen); + case SO_KEEPALIVE: + return nsos_setsockopt_int(sock, + NSOS_MID_SOL_SOCKET, NSOS_MID_SO_KEEPALIVE, + optval, optlen); + } + + case IPPROTO_TCP: + switch (optname) { + case TCP_NODELAY: + return nsos_setsockopt_int(sock, + NSOS_MID_IPPROTO_TCP, NSOS_MID_TCP_NODELAY, + optval, optlen); + case TCP_KEEPIDLE: + return nsos_setsockopt_int(sock, + NSOS_MID_IPPROTO_TCP, NSOS_MID_TCP_KEEPIDLE, + optval, optlen); + case TCP_KEEPINTVL: + return nsos_setsockopt_int(sock, + NSOS_MID_IPPROTO_TCP, NSOS_MID_TCP_KEEPINTVL, + optval, optlen); + case TCP_KEEPCNT: + return nsos_setsockopt_int(sock, + NSOS_MID_IPPROTO_TCP, NSOS_MID_TCP_KEEPCNT, + optval, optlen); + } + + case IPPROTO_IPV6: + switch (optname) { + case IPV6_V6ONLY: + return nsos_setsockopt_int(sock, + NSOS_MID_IPPROTO_IPV6, NSOS_MID_IPV6_V6ONLY, + optval, optlen); + } + } + + errno = EOPNOTSUPP; + return -1; +} + static const struct socket_op_vtable nsos_socket_fd_op_vtable = { .fd_vtable = { .read = nsos_read, @@ -761,6 +1210,8 @@ static const struct socket_op_vtable nsos_socket_fd_op_vtable = { .sendmsg = nsos_sendmsg, .recvfrom = nsos_recvfrom, .recvmsg = nsos_recvmsg, + .getsockopt = nsos_getsockopt, + .setsockopt = nsos_setsockopt, }; static bool nsos_is_supported(int family, int type, int proto) diff --git a/drivers/pcie/host/pcie.c b/drivers/pcie/host/pcie.c index 0a98d8e8e06..c2261af5de4 100644 --- a/drivers/pcie/host/pcie.c +++ b/drivers/pcie/host/pcie.c @@ -37,23 +37,6 @@ static bool prt_en; /* functions documented in drivers/pcie/pcie.h */ -bool pcie_probe(pcie_bdf_t bdf, pcie_id_t id) -{ - uint32_t data; - - data = pcie_conf_read(bdf, PCIE_CONF_ID); - - if (!PCIE_ID_IS_VALID(data)) { - return false; - } - - if (id == PCIE_ID_NONE) { - return true; - } - - return (id == data); -} - void pcie_set_cmd(pcie_bdf_t bdf, uint32_t bits, bool on) { uint32_t cmdstat; @@ -179,8 +162,8 @@ static bool pcie_get_bar(pcie_bdf_t bdf, reg++; phys_addr |= ((uint64_t)pcie_conf_read(bdf, reg)) << 32; - if (PCIE_CONF_BAR_ADDR(phys_addr) == PCIE_CONF_BAR_INVAL64 || - PCIE_CONF_BAR_ADDR(phys_addr) == PCIE_CONF_BAR_NONE) { + 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 */ goto err_exit; } @@ -188,8 +171,8 @@ static bool pcie_get_bar(pcie_bdf_t bdf, pcie_conf_write(bdf, reg, 0xFFFFFFFFU); size |= ((uint64_t)pcie_conf_read(bdf, reg)) << 32; pcie_conf_write(bdf, reg, (uint32_t)((uint64_t)phys_addr >> 32)); - } else if (PCIE_CONF_BAR_ADDR(phys_addr) == PCIE_CONF_BAR_INVAL || - PCIE_CONF_BAR_ADDR(phys_addr) == PCIE_CONF_BAR_NONE) { + } 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 */ goto err_exit; } @@ -253,7 +236,7 @@ static bool pcie_probe_bar(pcie_bdf_t bdf, uint32_t reg; for (reg = PCIE_CONF_BAR0; - index > 0 && reg <= PCIE_CONF_BAR5; reg++, index--) { + (index > 0) && (reg <= PCIE_CONF_BAR5); reg++, index--) { uintptr_t addr = pcie_conf_read(bdf, reg); if (PCIE_CONF_BAR_MEM(addr) && PCIE_CONF_BAR_64(addr)) { @@ -306,8 +289,8 @@ unsigned int pcie_alloc_irq(pcie_bdf_t bdf) data = pcie_conf_read(bdf, PCIE_CONF_INTR); irq = PCIE_CONF_INTR_IRQ(data); - if (irq == PCIE_CONF_INTR_IRQ_NONE || - irq >= CONFIG_MAX_IRQ_LINES || + if ((irq == PCIE_CONF_INTR_IRQ_NONE) || + (irq >= CONFIG_MAX_IRQ_LINES) || arch_irq_is_used(irq)) { /* In some platforms, PCI interrupts are hardwired to specific interrupt inputs @@ -385,40 +368,6 @@ void pcie_irq_enable(pcie_bdf_t bdf, unsigned int irq) irq_enable(irq); } -struct lookup_data { - pcie_bdf_t bdf; - pcie_id_t id; -}; - -static bool lookup_cb(pcie_bdf_t bdf, pcie_id_t id, void *cb_data) -{ - struct lookup_data *data = cb_data; - - if (id == data->id) { - data->bdf = bdf; - return false; - } - - return true; -} - -pcie_bdf_t pcie_bdf_lookup(pcie_id_t id) -{ - struct lookup_data data = { - .bdf = PCIE_BDF_NONE, - .id = id, - }; - struct pcie_scan_opt opt = { - .cb = lookup_cb, - .cb_data = &data, - .flags = (PCIE_SCAN_RECURSIVE | PCIE_SCAN_CB_ALL), - }; - - pcie_scan(&opt); - - return data.bdf; -} - static bool scan_flag(const struct pcie_scan_opt *opt, uint32_t flag) { return ((opt->flags & flag) != 0U); diff --git a/drivers/pinctrl/CMakeLists.txt b/drivers/pinctrl/CMakeLists.txt index c285e7d6f7f..91bbb8b3d51 100644 --- a/drivers/pinctrl/CMakeLists.txt +++ b/drivers/pinctrl/CMakeLists.txt @@ -4,7 +4,7 @@ zephyr_library() zephyr_library_sources(common.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_TELINK_B91 pinctrl_b91.c) -zephyr_library_sources_ifdef(CONFIG_PINCTRL_AMBIQ_APOLLO4 pinctrl_ambiq_apollo4.c) +zephyr_library_sources_ifdef(CONFIG_PINCTRL_AMBIQ pinctrl_ambiq.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_GD32_AF pinctrl_gd32_af.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_GD32_AFIO pinctrl_gd32_afio.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_ITE_IT8XXX2 pinctrl_ite_it8xxx2.c) diff --git a/drivers/pinctrl/Kconfig.ambiq b/drivers/pinctrl/Kconfig.ambiq index 14d5f76ca89..336dce05dec 100644 --- a/drivers/pinctrl/Kconfig.ambiq +++ b/drivers/pinctrl/Kconfig.ambiq @@ -2,11 +2,11 @@ # # Copyright (c) 2023 Antmicro -config PINCTRL_AMBIQ_APOLLO4 - bool "Ambiq Apollo4 pin controller driver" +config PINCTRL_AMBIQ + bool "Ambiq Apollo pin controller driver" default y - depends on DT_HAS_AMBIQ_APOLLO4_PINCTRL_ENABLED + depends on DT_HAS_AMBIQ_APOLLO4_PINCTRL_ENABLED || DT_HAS_AMBIQ_APOLLO3_PINCTRL_ENABLED select AMBIQ_HAL select AMBIQ_HAL_USE_GPIO help - Ambiq Apollo4 pinctrl driver + Ambiq Apollo pinctrl driver diff --git a/drivers/pinctrl/Kconfig.xlnx b/drivers/pinctrl/Kconfig.xlnx index bd61e09cadd..dbee12050f3 100644 --- a/drivers/pinctrl/Kconfig.xlnx +++ b/drivers/pinctrl/Kconfig.xlnx @@ -5,6 +5,6 @@ config PINCTRL_XLNX_ZYNQ bool "Xilinx Zynq 7000 processor system MIO pin controller driver" default y depends on DT_HAS_XLNX_PINCTRL_ZYNQ_ENABLED - select SYSCON + depends on SYSCON help Enable the Xilinx Zynq 7000 processor system MIO pin controller driver. diff --git a/drivers/pinctrl/pinctrl_ambiq.c b/drivers/pinctrl/pinctrl_ambiq.c new file mode 100644 index 00000000000..395f0101f4c --- /dev/null +++ b/drivers/pinctrl/pinctrl_ambiq.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2023 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/* ambiq-sdk includes */ +#include + +static void pinctrl_configure_pin(const pinctrl_soc_pin_t *pin) +{ + am_hal_gpio_pincfg_t pin_config = {0}; + +#if defined(CONFIG_SOC_SERIES_APOLLO3X) + pin_config.uFuncSel = pin->alt_func; + pin_config.eGPInput = + pin->input_enable ? AM_HAL_GPIO_PIN_INPUT_ENABLE : AM_HAL_GPIO_PIN_INPUT_NONE; + pin_config.eGPOutcfg = pin->push_pull ? AM_HAL_GPIO_PIN_OUTCFG_PUSHPULL + : pin->open_drain ? AM_HAL_GPIO_PIN_OUTCFG_OPENDRAIN + : pin->tristate ? AM_HAL_GPIO_PIN_OUTCFG_TRISTATE + : AM_HAL_GPIO_PIN_OUTCFG_DISABLE; + pin_config.eDriveStrength = pin->drive_strength; + pin_config.uNCE = pin->iom_nce; +#if defined(CONFIG_SOC_APOLLO3P_BLUE) + pin_config.bIomMSPIn = pin->iom_mspi; +#endif + pin_config.uIOMnum = pin->iom_num; + + if (pin->bias_pull_up) { + pin_config.ePullup = pin->ambiq_pull_up_ohms + AM_HAL_GPIO_PIN_PULLUP_1_5K; + } else if (pin->bias_pull_down) { + pin_config.ePullup = AM_HAL_GPIO_PIN_PULLDOWN; + } +#else + pin_config.GP.cfg_b.uFuncSel = pin->alt_func; + pin_config.GP.cfg_b.eGPInput = + pin->input_enable ? AM_HAL_GPIO_PIN_INPUT_ENABLE : AM_HAL_GPIO_PIN_INPUT_NONE; + pin_config.GP.cfg_b.eGPOutCfg = pin->push_pull ? AM_HAL_GPIO_PIN_OUTCFG_PUSHPULL + : pin->open_drain ? AM_HAL_GPIO_PIN_OUTCFG_OPENDRAIN + : pin->tristate ? AM_HAL_GPIO_PIN_OUTCFG_TRISTATE + : AM_HAL_GPIO_PIN_OUTCFG_DISABLE; + pin_config.GP.cfg_b.eDriveStrength = pin->drive_strength; + pin_config.GP.cfg_b.uSlewRate = pin->slew_rate; + pin_config.GP.cfg_b.uNCE = pin->iom_nce; + + if (pin->bias_pull_up) { + pin_config.GP.cfg_b.ePullup = pin->ambiq_pull_up_ohms + AM_HAL_GPIO_PIN_PULLUP_1_5K; + } else if (pin->bias_pull_down) { + pin_config.GP.cfg_b.ePullup = AM_HAL_GPIO_PIN_PULLDOWN_50K; + } +#endif + am_hal_gpio_pinconfig(pin->pin_num, pin_config); +} + +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_ambiq_apollo4.c b/drivers/pinctrl/pinctrl_ambiq_apollo4.c deleted file mode 100644 index 6247838738e..00000000000 --- a/drivers/pinctrl/pinctrl_ambiq_apollo4.c +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2023 Antmicro - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include - -/* ambiq-sdk includes */ -#include - -static void pinctrl_configure_pin(const pinctrl_soc_pin_t *pin) -{ - am_hal_gpio_pincfg_t pin_config = {0}; - - pin_config.GP.cfg_b.uFuncSel = pin->alt_func; - pin_config.GP.cfg_b.eGPInput = pin->input_enable ? AM_HAL_GPIO_PIN_INPUT_ENABLE - : AM_HAL_GPIO_PIN_INPUT_NONE; - pin_config.GP.cfg_b.eGPOutCfg = pin->push_pull ? AM_HAL_GPIO_PIN_OUTCFG_PUSHPULL - : pin->open_drain ? AM_HAL_GPIO_PIN_OUTCFG_OPENDRAIN - : pin->tristate ? AM_HAL_GPIO_PIN_OUTCFG_TRISTATE - : AM_HAL_GPIO_PIN_OUTCFG_DISABLE; - pin_config.GP.cfg_b.eDriveStrength = pin->drive_strength; - pin_config.GP.cfg_b.uSlewRate = pin->slew_rate; - pin_config.GP.cfg_b.uNCE = pin->iom_nce; - - if (pin->bias_pull_up) { - pin_config.GP.cfg_b.ePullup = pin->ambiq_pull_up_ohms + AM_HAL_GPIO_PIN_PULLUP_1_5K; - } else if (pin->bias_pull_down) { - pin_config.GP.cfg_b.ePullup = AM_HAL_GPIO_PIN_PULLDOWN_50K; - } - - am_hal_gpio_pinconfig(pin->pin_num, pin_config); -} - -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_gecko.c b/drivers/pinctrl/pinctrl_gecko.c index 0573ef3a40c..37f2f14338a 100644 --- a/drivers/pinctrl/pinctrl_gecko.c +++ b/drivers/pinctrl/pinctrl_gecko.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2023 Silicon Labs + * Copyright (c) 2024 Capgemini * * SPDX-License-Identifier: Apache-2.0 */ @@ -18,6 +19,10 @@ int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, uintp int usart_num = USART_NUM(base); #endif +#ifdef CONFIG_I2C_GECKO + I2C_TypeDef *i2c_base = (I2C_TypeDef *)reg; +#endif + #ifdef CONFIG_UART_GECKO struct soc_gpio_pin rxpin = {0, 0, 0, 0}; struct soc_gpio_pin txpin = {0, 0, 0, 0}; @@ -277,6 +282,54 @@ int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, uintp #endif /* CONFIG_SOC_FAMILY_SILABS_S1 */ #endif /* CONFIG_SPI_GECKO */ +#ifdef CONFIG_I2C_GECKO + case GECKO_FUN_I2C_SDA: + pin_config.mode = gpioModeWiredAnd; + pin_config.out = 1; + GPIO_PinModeSet(pin_config.port, pin_config.pin, pin_config.mode, + pin_config.out); + + break; + + case GECKO_FUN_I2C_SCL: + pin_config.mode = gpioModeWiredAnd; + pin_config.out = 1; + GPIO_PinModeSet(pin_config.port, pin_config.pin, pin_config.mode, + pin_config.out); + break; + + case GECKO_FUN_I2C_SDA_LOC: +#ifdef CONFIG_SOC_GECKO_HAS_INDIVIDUAL_PIN_LOCATION + i2c_base->ROUTEPEN |= I2C_ROUTEPEN_SDAPEN; + i2c_base->ROUTELOC0 &= ~_I2C_ROUTELOC0_SDALOC_MASK; + i2c_base->ROUTELOC0 |= (loc << _I2C_ROUTELOC0_SDALOC_SHIFT); +#elif defined(GPIO_I2C_ROUTEEN_SCLPEN) && defined(GPIO_I2C_ROUTEEN_SDAPEN) + GPIO->I2CROUTE[I2C_NUM(i2c_base)].ROUTEEN |= GPIO_I2C_ROUTEEN_SDAPEN; + GPIO->I2CROUTE[I2C_NUM(i2c_base)].SDAROUTE = + (pin_config.pin << _GPIO_I2C_SDAROUTE_PIN_SHIFT) | + (pin_config.port << _GPIO_I2C_SDAROUTE_PORT_SHIFT); +#else + i2c_base->ROUTE = I2C_ROUTE_SDAPEN | I2C_ROUTE_SCLPEN | (loc << 8); +#endif + break; + + case GECKO_FUN_I2C_SCL_LOC: +#ifdef CONFIG_SOC_GECKO_HAS_INDIVIDUAL_PIN_LOCATION + i2c_base->ROUTEPEN |= I2C_ROUTEPEN_SCLPEN; + i2c_base->ROUTELOC0 &= ~_I2C_ROUTEPEN_SCLPEN_MASK; + i2c_base->ROUTELOC0 |= (loc << _I2C_ROUTELOC0_SCLLOC_SHIFT); +#elif defined(GPIO_I2C_ROUTEEN_SCLPEN) && defined(GPIO_I2C_ROUTEEN_SDAPEN) + GPIO->I2CROUTE[I2C_NUM(i2c_base)].ROUTEEN |= GPIO_I2C_ROUTEEN_SCLPEN; + GPIO->I2CROUTE[I2C_NUM(i2c_base)].SCLROUTE = + (pin_config.pin << _GPIO_I2C_SCLROUTE_PIN_SHIFT) | + (pin_config.port << _GPIO_I2C_SCLROUTE_PORT_SHIFT); +#else + i2c_base->ROUTE = I2C_ROUTE_SDAPEN | I2C_ROUTE_SCLPEN | (loc << 8); +#endif + break; + +#endif /* CONFIG_I2C_GECKO */ + default: return -ENOTSUP; } diff --git a/drivers/pinctrl/pinctrl_numaker.c b/drivers/pinctrl/pinctrl_numaker.c index a443f705edf..e29f214a183 100644 --- a/drivers/pinctrl/pinctrl_numaker.c +++ b/drivers/pinctrl/pinctrl_numaker.c @@ -16,7 +16,9 @@ #define GPIO_SIZE DT_REG_SIZE(DT_NODELABEL(gpioa)) #define SLEWCTL_PIN_SHIFT(pin_idx) ((pin_idx) * 2) -#define SLEWCTL_MASK(pin_idx) (3 << SLEWCTL_PIN_SHIFT(pin_idx)) +#define SLEWCTL_MASK(pin_idx) (3 << SLEWCTL_PIN_SHIFT(pin_idx)) +#define DINOFF_PIN_SHIFT(pin_idx) (pin_idx + GPIO_DINOFF_DINOFF0_Pos) +#define DINOFF_MASK(pin_idx) (1 << DINOFF_PIN_SHIFT(pin_idx)) static void gpio_configure(const pinctrl_soc_pin_t *pin, uint8_t port_idx, uint8_t pin_idx) { @@ -28,7 +30,8 @@ static void gpio_configure(const pinctrl_soc_pin_t *pin, uint8_t port_idx, uint8 ((pin->schmitt_enable ? 1 : 0) << pin_idx); port->SLEWCTL = (port->SLEWCTL & ~SLEWCTL_MASK(pin_idx)) | (pin->slew_rate << SLEWCTL_PIN_SHIFT(pin_idx)); - + port->DINOFF = (port->DINOFF & ~DINOFF_MASK(pin_idx)) | + ((pin->digital_disable ? 1 : 0) << DINOFF_PIN_SHIFT(pin_idx)); } /** * Configure pin multi-function diff --git a/drivers/pinctrl/pinctrl_stm32.c b/drivers/pinctrl/pinctrl_stm32.c index 53c8f2b193c..b6a1b550e8b 100644 --- a/drivers/pinctrl/pinctrl_stm32.c +++ b/drivers/pinctrl/pinctrl_stm32.c @@ -80,8 +80,8 @@ int stm32_pinmux_init_remap(void) #if REMAP_PA11 || REMAP_PA12 -#if !defined(CONFIG_SOC_SERIES_STM32G0X) -#error "Pin remap property available only on STM32G0 SoC series" +#if !defined(CONFIG_SOC_SERIES_STM32G0X) && !defined(CONFIG_SOC_SERIES_STM32C0X) +#error "Pin remap property available only on STM32G0 and STM32C0 SoC series" #endif LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SYSCFG); diff --git a/drivers/pinctrl/renesas/rcar/CMakeLists.txt b/drivers/pinctrl/renesas/rcar/CMakeLists.txt index 6d0f8e70a72..dcfc3605634 100644 --- a/drivers/pinctrl/renesas/rcar/CMakeLists.txt +++ b/drivers/pinctrl/renesas/rcar/CMakeLists.txt @@ -5,7 +5,8 @@ zephyr_library_sources(pfc_rcar.c) if (CONFIG_SOC_R8A77951_R7 OR CONFIG_SOC_R8A77951_A57) zephyr_library_sources(pfc_r8a77951.c) +elseif (CONFIG_SOC_R8A779F0_R52 OR CONFIG_SOC_R8A779F0_A55) + zephyr_library_sources(pfc_r8a779f0.c) endif() zephyr_library_sources_ifdef(CONFIG_SOC_R8A77961 pfc_r8a77961.c) -zephyr_library_sources_ifdef(CONFIG_SOC_R8A779F0 pfc_r8a779f0.c) diff --git a/drivers/ptp_clock/Kconfig.nxp_enet b/drivers/ptp_clock/Kconfig.nxp_enet index aa9c8d5e41b..2952466cad6 100644 --- a/drivers/ptp_clock/Kconfig.nxp_enet +++ b/drivers/ptp_clock/Kconfig.nxp_enet @@ -3,7 +3,8 @@ 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) + default y + depends on DT_HAS_NXP_ENET_PTP_CLOCK_ENABLED && NET_L2_PTP + depends on ETH_NXP_ENET help Enable NXP ENET PTP clock support. diff --git a/drivers/ptp_clock/ptp_clock_nxp_enet.c b/drivers/ptp_clock/ptp_clock_nxp_enet.c index 943ff6ca4ea..286c6c91d57 100644 --- a/drivers/ptp_clock/ptp_clock_nxp_enet.c +++ b/drivers/ptp_clock/ptp_clock_nxp_enet.c @@ -16,7 +16,7 @@ #include #include -#include "fsl_enet.h" +#include struct ptp_clock_nxp_enet_config { ENET_Type *base; diff --git a/drivers/pwm/pwm_mcux.c b/drivers/pwm/pwm_mcux.c index d753682f46e..617ac3e4b7f 100644 --- a/drivers/pwm/pwm_mcux.c +++ b/drivers/pwm/pwm_mcux.c @@ -12,6 +12,7 @@ #include #include #include +#include #include @@ -35,9 +36,10 @@ struct pwm_mcux_config { struct pwm_mcux_data { uint32_t period_cycles[CHANNEL_COUNT]; pwm_signal_param_t channel[CHANNEL_COUNT]; + struct k_mutex lock; }; -static int mcux_pwm_set_cycles(const struct device *dev, uint32_t channel, +static int mcux_pwm_set_cycles_internal(const struct device *dev, uint32_t channel, uint32_t period_cycles, uint32_t pulse_cycles, pwm_flags_t flags) { @@ -45,24 +47,6 @@ static int mcux_pwm_set_cycles(const struct device *dev, uint32_t channel, struct pwm_mcux_data *data = dev->data; pwm_level_select_t level; - if (channel >= CHANNEL_COUNT) { - LOG_ERR("Invalid channel"); - return -EINVAL; - } - - if (period_cycles == 0) { - LOG_ERR("Channel can not be set to inactive level"); - return -ENOTSUP; - } - - if (period_cycles > UINT16_MAX) { - /* 16-bit resolution */ - LOG_ERR("Too long period (%u), adjust pwm prescaler!", - period_cycles); - /* TODO: dynamically adjust prescaler */ - return -EINVAL; - } - if (flags & PWM_POLARITY_INVERTED) { level = kPWM_LowTrue; } else { @@ -158,6 +142,36 @@ static int mcux_pwm_set_cycles(const struct device *dev, uint32_t channel, return 0; } +static int mcux_pwm_set_cycles(const struct device *dev, uint32_t channel, + uint32_t period_cycles, uint32_t pulse_cycles, + pwm_flags_t flags) +{ + struct pwm_mcux_data *data = dev->data; + int result; + + if (channel >= CHANNEL_COUNT) { + LOG_ERR("Invalid channel"); + return -EINVAL; + } + + if (period_cycles == 0) { + LOG_ERR("Channel can not be set to inactive level"); + return -ENOTSUP; + } + + if (period_cycles > UINT16_MAX) { + /* 16-bit resolution */ + LOG_ERR("Too long period (%u), adjust pwm prescaler!", + period_cycles); + /* TODO: dynamically adjust prescaler */ + return -EINVAL; + } + k_mutex_lock(&data->lock, K_FOREVER); + result = mcux_pwm_set_cycles_internal(dev, channel, period_cycles, pulse_cycles, flags); + k_mutex_unlock(&data->lock); + return result; +} + static int mcux_pwm_get_cycles_per_sec(const struct device *dev, uint32_t channel, uint64_t *cycles) { @@ -181,6 +195,8 @@ static int pwm_mcux_init(const struct device *dev) status_t status; int i, err; + k_mutex_init(&data->lock); + if (!device_is_ready(config->clock_dev)) { LOG_ERR("clock control device not ready"); return -ENODEV; diff --git a/drivers/pwm/pwm_mcux_ftm.c b/drivers/pwm/pwm_mcux_ftm.c index 9f57be2dd71..4774fad4f80 100644 --- a/drivers/pwm/pwm_mcux_ftm.c +++ b/drivers/pwm/pwm_mcux_ftm.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, NXP + * Copyright 2017, 2024 NXP * Copyright (c) 2020-2021 Vestas Wind Systems A/S * * SPDX-License-Identifier: Apache-2.0 @@ -578,7 +578,7 @@ static const struct mcux_ftm_config mcux_ftm_config_##n = { \ .clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)), \ .clock_subsys = (clock_control_subsys_t) \ DT_INST_CLOCKS_CELL(n, name), \ - .ftm_clock_source = kFTM_FixedClock, \ + .ftm_clock_source = (ftm_clock_source_t)(DT_INST_ENUM_IDX(n, clock_source) + 1U), \ .prescale = TO_FTM_PRESCALE_DIVIDE(DT_INST_PROP(n, prescaler)),\ .channel_count = FSL_FEATURE_FTM_CHANNEL_COUNTn((FTM_Type *) \ DT_INST_REG_ADDR(n)), \ diff --git a/drivers/pwm/pwm_stm32.c b/drivers/pwm/pwm_stm32.c index c8e44633ad5..70006e377b1 100644 --- a/drivers/pwm/pwm_stm32.c +++ b/drivers/pwm/pwm_stm32.c @@ -141,9 +141,7 @@ static void (*const set_timer_compare[TIMER_MAX_CH])(TIM_TypeDef *, }; /** Channel to capture get function mapping. */ -#if !defined(CONFIG_SOC_SERIES_STM32F4X) && \ - !defined(CONFIG_SOC_SERIES_STM32G4X) && \ - !defined(CONFIG_SOC_SERIES_STM32MP1X) +#if !defined(CONFIG_SOC_SERIES_STM32MP1X) static uint32_t __maybe_unused (*const get_channel_capture[])(const TIM_TypeDef *) = { #else static uint32_t __maybe_unused (*const get_channel_capture[])(TIM_TypeDef *) = { @@ -166,9 +164,7 @@ static void __maybe_unused (*const disable_capture_interrupt[])(TIM_TypeDef *) = }; /** Channel to is capture active flag mapping. */ -#if !defined(CONFIG_SOC_SERIES_STM32F4X) && \ - !defined(CONFIG_SOC_SERIES_STM32G4X) && \ - !defined(CONFIG_SOC_SERIES_STM32MP1X) +#if !defined(CONFIG_SOC_SERIES_STM32MP1X) static uint32_t __maybe_unused (*const is_capture_active[])(const TIM_TypeDef *) = { #else static uint32_t __maybe_unused (*const is_capture_active[])(TIM_TypeDef *) = { diff --git a/drivers/regulator/Kconfig.adp5360 b/drivers/regulator/Kconfig.adp5360 index 0785ba54abf..f93df2ef163 100644 --- a/drivers/regulator/Kconfig.adp5360 +++ b/drivers/regulator/Kconfig.adp5360 @@ -1,5 +1,5 @@ # Copyright (c) 2023 Nordic Semiconductor ASA -# SPDX -License-Identifier: Apache-2.0 +# SPDX-License-Identifier: Apache-2.0 config REGULATOR_ADP5360 bool "ADP5360 PMIC regulator driver" diff --git a/drivers/regulator/Kconfig.axp192 b/drivers/regulator/Kconfig.axp192 index 8c8fad5cdb4..b56868ccdb7 100644 --- a/drivers/regulator/Kconfig.axp192 +++ b/drivers/regulator/Kconfig.axp192 @@ -1,5 +1,5 @@ # Copyright (c) 2023 Martin Kiepfer -# SPDX -License-Identifier: Apache-2.0 +# SPDX-License-Identifier: Apache-2.0 config REGULATOR_AXP192 bool "X-Power AXP192 PMIC regulator driver" diff --git a/drivers/regulator/Kconfig.max20335 b/drivers/regulator/Kconfig.max20335 index a92743afdb5..df0eafe5158 100644 --- a/drivers/regulator/Kconfig.max20335 +++ b/drivers/regulator/Kconfig.max20335 @@ -1,5 +1,5 @@ # Copyright (c) 2023 Grinn -# SPDX -License-Identifier: Apache-2.0 +# SPDX-License-Identifier: Apache-2.0 config REGULATOR_MAX20335 bool "MAX20335 PMIC regulator driver" diff --git a/drivers/regulator/Kconfig.npm1100 b/drivers/regulator/Kconfig.npm1100 index 56301a7beca..97c7cbefc35 100644 --- a/drivers/regulator/Kconfig.npm1100 +++ b/drivers/regulator/Kconfig.npm1100 @@ -1,5 +1,5 @@ # Copyright (c) 2023 Nordic Semiconductor ASA -# SPDX -License-Identifier: Apache-2.0 +# SPDX-License-Identifier: Apache-2.0 config REGULATOR_NPM1100 bool "nPM1100 PMIC regulator driver" diff --git a/drivers/regulator/Kconfig.npm1300 b/drivers/regulator/Kconfig.npm1300 index 997934cabb7..19adee0ebab 100644 --- a/drivers/regulator/Kconfig.npm1300 +++ b/drivers/regulator/Kconfig.npm1300 @@ -1,5 +1,5 @@ # Copyright (c) 2023 Nordic Semiconductor ASA -# SPDX -License-Identifier: Apache-2.0 +# SPDX-License-Identifier: Apache-2.0 config REGULATOR_NPM1300 bool "nPM1300 PMIC regulator driver" diff --git a/drivers/regulator/Kconfig.npm6001 b/drivers/regulator/Kconfig.npm6001 index a9c290475de..d171a4bdd6f 100644 --- a/drivers/regulator/Kconfig.npm6001 +++ b/drivers/regulator/Kconfig.npm6001 @@ -1,5 +1,5 @@ # Copyright (c) 2022 Nordic Semiconductor ASA -# SPDX -License-Identifier: Apache-2.0 +# SPDX-License-Identifier: Apache-2.0 config REGULATOR_NPM6001 bool "nPM6001 PMIC regulator driver" diff --git a/drivers/regulator/Kconfig.nxp_vref b/drivers/regulator/Kconfig.nxp_vref index 4c9bc54fd13..b26614b75da 100644 --- a/drivers/regulator/Kconfig.nxp_vref +++ b/drivers/regulator/Kconfig.nxp_vref @@ -1,14 +1,16 @@ # Copyright 2023 NXP -# SPDX -License-Identifier: Apache-2.0 +# SPDX-License-Identifier: Apache-2.0 config REGULATOR_NXP_VREF bool "NXP VREF peripheral driver" - default y if DT_HAS_NXP_VREF_ENABLED + default y + depends on DT_HAS_NXP_VREF_ENABLED help Enable the NXP VREF driver config REGULATOR_NXP_VREF_INIT_PRIORITY int "NXP VREF peripheral driver init priority" default 45 + depends on DT_HAS_NXP_VREF_ENABLED help Init priority for the NXP VREF peripheral. diff --git a/drivers/regulator/Kconfig.pca9420 b/drivers/regulator/Kconfig.pca9420 index 9a2d2377c61..bf87ed50d23 100644 --- a/drivers/regulator/Kconfig.pca9420 +++ b/drivers/regulator/Kconfig.pca9420 @@ -1,5 +1,5 @@ # Copyright (c) 2021, NXP -# SPDX -License-Identifier: Apache-2.0 +# SPDX-License-Identifier: Apache-2.0 config REGULATOR_PCA9420 bool "NXP PCA9420 PMIC regulator driver" diff --git a/drivers/regulator/regulator_common.c b/drivers/regulator/regulator_common.c index c539e1169ee..104c66e19cc 100644 --- a/drivers/regulator/regulator_common.c +++ b/drivers/regulator/regulator_common.c @@ -10,11 +10,7 @@ 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 } } diff --git a/drivers/regulator/regulator_cp9314.c b/drivers/regulator/regulator_cp9314.c index 2ba137a50ce..0e155b17247 100644 --- a/drivers/regulator/regulator_cp9314.c +++ b/drivers/regulator/regulator_cp9314.c @@ -66,6 +66,16 @@ LOG_MODULE_REGISTER(CP9314, CONFIG_REGULATOR_LOG_LEVEL); #define CP9314_MODE_2TO1 1 #define CP9314_MODE_3TO1 2 +#define CP9314_REG_FLT_FLAG 0x12 +#define CP9314_VIN_OVP_FLAG BIT(1) +#define CP9314_VOUT_OVP_FLAG BIT(0) + +#define CP9314_REG_COMP_FLAG0 0x2A +#define CP9314_IIN_OCP_FLAG BIT(4) + +#define CP9314_REG_COMP_FLAG1 0x2C +#define CP9314_VIN2OUT_OVP_FLAG BIT(0) + #define CP9314_REG_LION_CFG_1 0x31 #define CP9314_LB2_DELTA_CFG_1 GENMASK(7, 5) @@ -156,6 +166,7 @@ LOG_MODULE_REGISTER(CP9314, CONFIG_REGULATOR_LOG_LEVEL); #define CP9314_SOFT_RESET_DELAY_MSEC 200 #define CP9314_EN_DEBOUNCE_USEC 3000 +#define CP9314_T_STARTUP_MSEC 120 #define CP9314_DEVICE_MODE_HOST_4GANG_0x78 0x0 #define CP9314_DEVICE_MODE_HOST_4GANG_0x72 0x1 @@ -184,6 +195,7 @@ struct regulator_cp9314_config { struct regulator_common_config common; struct i2c_dt_spec i2c; struct gpio_dt_spec en_pin; + struct gpio_dt_spec pgood_pin; uint8_t initial_op_mode_idx; }; @@ -230,6 +242,47 @@ static struct cp9314_reg_patch otp_1_patch[3] = { {CP9314_REG_TSBAT_CTRL, CP9314_LB1_STOP_PHASE_SEL, CP9314_LB1_STOP_PHASE_SEL}, }; +static int regulator_cp9314_get_error_flags(const struct device *dev, + regulator_error_flags_t *flags) +{ + const struct regulator_cp9314_config *config = dev->config; + uint8_t val[3]; + int ret; + + *flags = 0U; + + ret = i2c_reg_read_byte_dt(&config->i2c, CP9314_REG_FLT_FLAG, &val[0]); + if (ret < 0) { + return ret; + } + + if (FIELD_GET(CP9314_VIN_OVP_FLAG, val[0]) || FIELD_GET(CP9314_VOUT_OVP_FLAG, val[0])) { + *flags |= REGULATOR_ERROR_OVER_VOLTAGE; + } + + ret = i2c_reg_read_byte_dt(&config->i2c, CP9314_REG_COMP_FLAG0, &val[1]); + if (ret < 0) { + return ret; + } + + if (FIELD_GET(CP9314_IIN_OCP_FLAG, val[1])) { + *flags |= REGULATOR_ERROR_OVER_CURRENT; + } + + ret = i2c_reg_read_byte_dt(&config->i2c, CP9314_REG_COMP_FLAG1, &val[2]); + if (ret < 0) { + return ret; + } + + if (FIELD_GET(CP9314_VIN2OUT_OVP_FLAG, val[2])) { + *flags |= REGULATOR_ERROR_OVER_VOLTAGE; + } + + LOG_DBG("FLT_FLAG = 0x%x, COMP_FLAG0 = 0x%x, COMP_FLAG1 = 0x%x", val[0], val[1], val[2]); + + return 0; +} + static int regulator_cp9314_disable(const struct device *dev) { const struct regulator_cp9314_config *config = dev->config; @@ -268,13 +321,35 @@ static int regulator_cp9314_enable(const struct device *dev) } if (config->en_pin.port != NULL) { - return gpio_pin_set_dt(&config->en_pin, 1); + ret = gpio_pin_set_dt(&config->en_pin, 1); + if (ret < 0) { + return ret; + } + } else { + ret = i2c_reg_update_byte_dt(&config->i2c, CP9314_REG_CTRL1, CP9314_CP_EN, + CP9314_CP_EN); + if (ret < 0) { + LOG_ERR("Unable to set CP_EN"); + return ret; + } } - ret = i2c_reg_update_byte_dt(&config->i2c, CP9314_REG_CTRL1, CP9314_CP_EN, CP9314_CP_EN); - if (ret < 0) { - LOG_ERR("Unable to set CP_EN"); - return ret; + k_msleep(CP9314_T_STARTUP_MSEC); + + if (config->pgood_pin.port != NULL) { + ret = gpio_pin_get_dt(&config->pgood_pin); + if (ret < 0) { + return ret; + } else if (ret == 0) { + return -EINVAL; + } + } else { + ret = i2c_reg_read_byte_dt(&config->i2c, CP9314_REG_CONVERTER, &value); + if (ret < 0) { + return ret; + } else if (FIELD_GET(CP9314_PGOOD_PIN_STS, value) == 0U) { + return -EINVAL; + } } return 0; @@ -338,11 +413,7 @@ static int cp9314_do_soft_reset(const struct device *dev) return ret; } -#ifdef CONFIG_MULTITHREADING k_msleep(CP9314_SOFT_RESET_DELAY_MSEC); -#else - k_busy_wait(CP9314_SOFT_RESET_DELAY_MSEC * USEC_PER_MSEC); -#endif return 0; } @@ -411,6 +482,17 @@ static int regulator_cp9314_init(const struct device *dev) return -ENOTSUP; } + if (config->pgood_pin.port != NULL) { + if (!gpio_is_ready_dt(&config->pgood_pin)) { + return -ENODEV; + } + + ret = gpio_pin_configure_dt(&config->pgood_pin, GPIO_INPUT); + if (ret < 0) { + return ret; + } + } + if (config->en_pin.port != NULL) { if (!gpio_is_ready_dt(&config->en_pin)) { return -ENODEV; @@ -421,11 +503,7 @@ static int regulator_cp9314_init(const struct device *dev) return ret; } -#ifdef CONFIG_MULTITHREADING k_usleep(CP9314_EN_DEBOUNCE_USEC); -#else - k_busy_wait(CP9314_EN_DEBOUNCE_USEC); -#endif } ret = cp9314_do_soft_reset(dev); @@ -523,6 +601,7 @@ static int regulator_cp9314_init(const struct device *dev) static const struct regulator_driver_api api = { .enable = regulator_cp9314_enable, .disable = regulator_cp9314_disable, + .get_error_flags = regulator_cp9314_get_error_flags, }; #define REGULATOR_CP9314_DEFINE(inst) \ @@ -532,6 +611,7 @@ static const struct regulator_driver_api api = { .common = REGULATOR_DT_INST_COMMON_CONFIG_INIT(inst), \ .i2c = I2C_DT_SPEC_INST_GET(inst), \ .en_pin = GPIO_DT_SPEC_INST_GET_OR(inst, cirrus_en_gpios, {}), \ + .pgood_pin = GPIO_DT_SPEC_INST_GET_OR(inst, cirrus_pgood_gpios, {}), \ .initial_op_mode_idx = \ DT_INST_ENUM_IDX_OR(inst, cirrus_initial_switched_capacitor_mode, -1) + 1, \ }; \ diff --git a/drivers/regulator/regulator_da1469x.c b/drivers/regulator/regulator_da1469x.c index 36d8fe1d35f..ad3db8f9952 100644 --- a/drivers/regulator/regulator_da1469x.c +++ b/drivers/regulator/regulator_da1469x.c @@ -10,6 +10,8 @@ #include #include #include +#include +#include #include LOG_MODULE_REGISTER(regulator_da1469x, CONFIG_REGULATOR_LOG_LEVEL); @@ -77,6 +79,16 @@ enum da1469x_rail { V30, }; +struct dcdc_regs { + uint32_t v18; + uint32_t v18p; + uint32_t vdd; + uint32_t v14; + uint32_t ctrl1; +}; + +static struct dcdc_regs dcdc_state; + struct regulator_da1469x_desc { const struct linear_range *voltage_ranges; const struct linear_range *current_ranges; @@ -85,6 +97,7 @@ struct regulator_da1469x_desc { uint32_t enable_mask; uint32_t voltage_idx_mask; volatile uint32_t *dcdc_register; + uint32_t *dcdc_register_shadow; }; static const struct regulator_da1469x_desc vdd_desc = { @@ -94,6 +107,7 @@ static const struct regulator_da1469x_desc vdd_desc = { .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, + .dcdc_register_shadow = &dcdc_state.vdd, }; static const struct regulator_da1469x_desc vdd_sleep_desc = { @@ -117,6 +131,7 @@ static const struct regulator_da1469x_desc v14_desc = { .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, + .dcdc_register_shadow = &dcdc_state.v14, }; static const struct regulator_da1469x_desc v18_desc = { @@ -127,6 +142,7 @@ static const struct regulator_da1469x_desc v18_desc = { 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, + .dcdc_register_shadow = &dcdc_state.v18, }; static const struct regulator_da1469x_desc v18p_desc = { @@ -137,6 +153,7 @@ static const struct regulator_da1469x_desc v18p_desc = { CRG_TOP_POWER_CTRL_REG_LDO_1V8P_RET_ENABLE_SLEEP_Msk, .voltage_idx_mask = 0, .dcdc_register = &DCDC->DCDC_V18P_REG, + .dcdc_register_shadow = &dcdc_state.v18p, }; static const struct regulator_da1469x_desc v30_desc = { @@ -183,6 +200,7 @@ static int regulator_da1469x_enable(const struct device *dev) ~(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_shadow = reg_val; *config->desc->dcdc_register = reg_val; } @@ -196,6 +214,7 @@ static int regulator_da1469x_enable(const struct device *dev) (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; + dcdc_state.ctrl1 = DCDC->DCDC_CTRL1_REG; } return 0; @@ -214,6 +233,7 @@ static int regulator_da1469x_disable(const struct device *dev) 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_shadow = reg_val; *config->desc->dcdc_register = reg_val; } @@ -224,6 +244,7 @@ static int regulator_da1469x_disable(const struct device *dev) (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; + dcdc_state.ctrl1 = DCDC->DCDC_CTRL1_REG; } return 0; @@ -286,7 +307,7 @@ static int regulator_da1469x_get_voltage(const struct device *dev, uint16_t idx; if (config->desc->voltage_idx_mask) { - idx = FIELD_GET(CRG_TOP->POWER_CTRL_REG, config->desc->voltage_idx_mask); + idx = FIELD_GET(config->desc->voltage_idx_mask, CRG_TOP->POWER_CTRL_REG); } else { idx = 0; } @@ -321,7 +342,7 @@ static int regulator_da1469x_set_current_limit(const struct device *dev, 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_shadow = reg_val; *config->desc->dcdc_register = reg_val; return ret; @@ -337,8 +358,8 @@ static int regulator_da1469x_get_current_limit(const struct device *dev, 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); + idx = FIELD_GET(DCDC_DCDC_V14_REG_DCDC_V14_CUR_LIM_MAX_HV_Msk, + *config->desc->dcdc_register); ret = linear_range_group_get_value(config->desc->current_ranges, 1, idx, curr_ua); return ret; @@ -369,6 +390,37 @@ static int regulator_da1469x_init(const struct device *dev) return regulator_common_init(dev, 0); } +#if IS_ENABLED(CONFIG_PM_DEVICE) +static int regulator_da1469x_pm_action(const struct device *dev, + enum pm_device_action action) +{ + const struct regulator_da1469x_config *config = dev->config; + int ret = 0; + + switch (action) { + case PM_DEVICE_ACTION_RESUME: + if (config->desc->dcdc_register) { + *config->desc->dcdc_register = *config->desc->dcdc_register_shadow; + if ((CRG_TOP->ANA_STATUS_REG & CRG_TOP_ANA_STATUS_REG_COMP_VBAT_HIGH_Msk) && + (*config->desc->dcdc_register_shadow & DCDC_REQUESTED)) { + DCDC->DCDC_CTRL1_REG = dcdc_state.ctrl1; + } + } + break; + case PM_DEVICE_ACTION_SUSPEND: + /* + * Shadow register is saved on each regulator API call, there is no need + * to save it here. + */ + break; + default: + ret = -ENOTSUP; + } + + return ret; +} +#endif + #define REGULATOR_DA1469X_DEFINE(node, id, rail_id) \ static struct regulator_da1469x_data data_##id; \ \ @@ -392,7 +444,10 @@ static int regulator_da1469x_init(const struct device *dev) (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, \ + PM_DEVICE_DT_DEFINE(node, regulator_da1469x_pm_action); \ + DEVICE_DT_DEFINE(node, regulator_da1469x_init, \ + PM_DEVICE_DT_GET(node), \ + &data_##id, \ &config_##id, PRE_KERNEL_1, \ CONFIG_REGULATOR_DA1469X_INIT_PRIORITY, \ ®ulator_da1469x_api); diff --git a/drivers/regulator/regulator_gpio.c b/drivers/regulator/regulator_gpio.c index 49d373897b3..d888a5fd6dc 100644 --- a/drivers/regulator/regulator_gpio.c +++ b/drivers/regulator/regulator_gpio.c @@ -167,8 +167,6 @@ static int regulator_gpio_init(const struct device *dev) regulator_common_data_init(dev); for (unsigned int gpio_idx = 0; gpio_idx < cfg->num_gpios; gpio_idx++) { - int ret; - if (!gpio_is_ready_dt(&cfg->gpios[gpio_idx])) { LOG_ERR("%s: gpio pin: %s not ready", dev->name, cfg->gpios[gpio_idx].port ? cfg->gpios[gpio_idx].port->name diff --git a/drivers/regulator/regulator_npm6001.c b/drivers/regulator/regulator_npm6001.c index 1b854cbf830..2ade708271a 100644 --- a/drivers/regulator/regulator_npm6001.c +++ b/drivers/regulator/regulator_npm6001.c @@ -211,7 +211,7 @@ static int regulator_npm6001_ldo0_set_voltage(const struct device *dev, int32_t int32_t max_uv) { const struct regulator_npm6001_config *config = dev->config; - uint8_t val; + uint8_t val = 0U; size_t i; for (i = 0U; i < ARRAY_SIZE(ldo0_voltages); i++) { diff --git a/drivers/regulator/regulator_nxp_vref.c b/drivers/regulator/regulator_nxp_vref.c index 3d2ba23010e..d3aa0f48a15 100644 --- a/drivers/regulator/regulator_nxp_vref.c +++ b/drivers/regulator/regulator_nxp_vref.c @@ -1,5 +1,5 @@ /* - * Copyright 2023 NXP + * Copyright 2023-2024 NXP * SPDX-License-Identifier: Apache-2.0 */ @@ -24,7 +24,6 @@ struct regulator_nxp_vref_data { struct regulator_nxp_vref_config { struct regulator_common_config common; VREF_Type *base; - uint8_t gnd_sel; uint16_t buf_start_delay; uint16_t bg_start_time; }; @@ -165,7 +164,7 @@ static int regulator_nxp_vref_get_voltage(const struct device *dev, /* Linear range index is the register value */ idx = (base->UTRIM & VREF_UTRIM_TRIM2V1_MASK) >> VREF_UTRIM_TRIM2V1_SHIFT; - ret = linear_range_get_value(&utrim_range, base->UTRIM, volt_uv); + ret = linear_range_get_value(&utrim_range, idx, volt_uv); return ret; } @@ -183,16 +182,10 @@ static const struct regulator_driver_api api = { static int regulator_nxp_vref_init(const struct device *dev) { - const struct regulator_nxp_vref_config *config = dev->config; - VREF_Type *base = config->base; int ret; regulator_common_data_init(dev); - /* Select ground */ - base->CSR &= ~VREF_CSR_REFL_GRD_SEL_MASK; - base->CSR |= config->gnd_sel; - ret = regulator_nxp_vref_disable(dev); if (ret < 0) { return ret; @@ -207,7 +200,6 @@ static int regulator_nxp_vref_init(const struct device *dev) static const struct regulator_nxp_vref_config config_##inst = { \ .common = REGULATOR_DT_INST_COMMON_CONFIG_INIT(inst), \ .base = (VREF_Type *) DT_INST_REG_ADDR(inst), \ - .gnd_sel = DT_INST_ENUM_IDX_OR(inst, nxp_ground_select, 0), \ .buf_start_delay = DT_INST_PROP(inst, \ nxp_buffer_startup_delay_us), \ .bg_start_time = DT_INST_PROP(inst, \ diff --git a/drivers/regulator/regulator_shell.c b/drivers/regulator/regulator_shell.c index c1a24f61a61..ba0c29e34b8 100644 --- a/drivers/regulator/regulator_shell.c +++ b/drivers/regulator/regulator_shell.c @@ -74,8 +74,7 @@ static int strtomicro(char *inp, char units, int32_t *val) static void microtoshell(const struct shell *sh, char unit, int32_t val) { if (val > 100000) { - shell_print(sh, "%d.%03d %c", val / 1000000, - (val % 1000000) / 1000, unit); + shell_print(sh, "%d.%06d %c", val / 1000000, val % 1000000, unit); } else if (val > 1000) { shell_print(sh, "%d.%03d m%c", val / 1000, val % 1000, unit); } else { @@ -127,6 +126,27 @@ static int cmd_disable(const struct shell *sh, size_t argc, char **argv) return 0; } +static int cmd_is_enabled(const struct shell *sh, size_t argc, char **argv) +{ + const struct device *dev; + + 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 (regulator_is_enabled(dev)) { + shell_print(sh, "Regulator is enabled"); + } else { + shell_print(sh, "Regulator is disabled"); + } + + return 0; +} + static int cmd_vlist(const struct shell *sh, size_t argc, char **argv) { const struct device *dev; @@ -378,9 +398,9 @@ static int cmd_adset(const struct shell *sh, size_t argc, char **argv) return -ENODEV; } - if (strcmp(argv[2], "enable")) { + if (strcmp(argv[2], "enable") == 0) { ad = true; - } else if (strcmp(argv[2], "disable")) { + } else if (strcmp(argv[2], "disable") == 0) { ad = false; } else { shell_error(sh, "Invalid parameter"); @@ -524,6 +544,10 @@ SHELL_STATIC_SUBCMD_SET_CREATE( "Disable regulator\n" "Usage: disable ", cmd_disable, 2, 0), + SHELL_CMD_ARG(is_enabled, &dsub_device_name, + "Report whether regulator is enabled or disabled\n" + "Usage: is_enabled ", + cmd_is_enabled, 2, 0), SHELL_CMD_ARG(vlist, &dsub_device_name, "List all supported voltages\n" "Usage: vlist ", diff --git a/drivers/reset/CMakeLists.txt b/drivers/reset/CMakeLists.txt index 36c68367d39..84f0443cabb 100644 --- a/drivers/reset/CMakeLists.txt +++ b/drivers/reset/CMakeLists.txt @@ -9,3 +9,6 @@ zephyr_library_sources_ifdef(CONFIG_RESET_AST10X0 reset_ast10x0.c) zephyr_library_sources_ifdef(CONFIG_RESET_STM32 reset_stm32.c) zephyr_library_sources_ifdef(CONFIG_RESET_NUMAKER reset_numaker.c) zephyr_library_sources_ifdef(CONFIG_RESET_INTEL_SOCFPGA reset_intel_socfpga.c) +zephyr_library_sources_ifdef(CONFIG_RESET_NPCX reset_npcx.c) +zephyr_library_sources_ifdef(CONFIG_RESET_NXP_SYSCON reset_lpc_syscon.c) +zephyr_library_sources_ifdef(CONFIG_RESET_NXP_RSTCTL reset_nxp_rstctl.c) diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index f940583c974..87ba9c7576c 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -33,5 +33,8 @@ rsource "Kconfig.aspeed" rsource "Kconfig.stm32" rsource "Kconfig.numaker" rsource "Kconfig.intel_socfpga" +rsource "Kconfig.npcx" +rsource "Kconfig.lpc_syscon" +rsource "Kconfig.nxp_rstctl" endif # RESET diff --git a/drivers/reset/Kconfig.lpc_syscon b/drivers/reset/Kconfig.lpc_syscon new file mode 100644 index 00000000000..cfa6bcdd558 --- /dev/null +++ b/drivers/reset/Kconfig.lpc_syscon @@ -0,0 +1,10 @@ +# Copyright 2024 NXP +# SPDX-License-Identifier: Apache-2.0 + +config RESET_NXP_SYSCON + bool "NXP Syscon Reset controller driver" + default y + depends on DT_HAS_NXP_LPC_SYSCON_RESET_ENABLED + help + Enable the NXP syscon reset controller driver. + Syscon is found on LPC parts and LPC heritage parts. diff --git a/drivers/reset/Kconfig.npcx b/drivers/reset/Kconfig.npcx new file mode 100644 index 00000000000..1ce6d27fec0 --- /dev/null +++ b/drivers/reset/Kconfig.npcx @@ -0,0 +1,11 @@ +# NPCX reset controller driver configuration options + +# Copyright (c) 2024 Nuvoton Technology Corporation. +# SPDX-License-Identifier: Apache-2.0 + +config RESET_NPCX + bool "Nuvoton NPCX embedded controller (EC) reset controller driver" + default y + depends on DT_HAS_NUVOTON_NPCX_RST_ENABLED + help + This option enables the reset controller driver for Nuvoton NPCX MCUs. diff --git a/drivers/reset/Kconfig.nxp_rstctl b/drivers/reset/Kconfig.nxp_rstctl new file mode 100644 index 00000000000..6e604b96643 --- /dev/null +++ b/drivers/reset/Kconfig.nxp_rstctl @@ -0,0 +1,10 @@ +# Copyright 2024 NXP +# SPDX-License-Identifier: Apache-2.0 + +config RESET_NXP_RSTCTL + bool "NXP RSTCTL driver" + default y + depends on DT_HAS_NXP_RSTCTL_ENABLED + help + Enable the driver for the NXP RSTCTL, + a peripheral reset controller. diff --git a/drivers/reset/reset_lpc_syscon.c b/drivers/reset/reset_lpc_syscon.c new file mode 100644 index 00000000000..9effda66518 --- /dev/null +++ b/drivers/reset/reset_lpc_syscon.c @@ -0,0 +1,65 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nxp_lpc_syscon_reset + +#include +#include +#include + +#include + +#define LPC_RESET_OFFSET(id) (id >> 16) +#define LPC_RESET_BIT(id) (BIT(id & 0xFFFF)) + +static int reset_nxp_syscon_status(const struct device *dev, uint32_t id, uint8_t *status) +{ + const volatile uint32_t *ctrl_reg = ((uint32_t *)dev->config)+(LPC_RESET_OFFSET(id)); + *status = (uint8_t)FIELD_GET((uint32_t)LPC_RESET_BIT(id), *ctrl_reg); + + return 0; +} + +static int reset_nxp_syscon_line_assert(const struct device *dev, uint32_t id) +{ + SYSCON->PRESETCTRLSET[LPC_RESET_OFFSET(id)] = FIELD_PREP(LPC_RESET_BIT(id), 0b1); + + return 0; +} + +static int reset_nxp_syscon_line_deassert(const struct device *dev, uint32_t id) +{ + SYSCON->PRESETCTRLCLR[LPC_RESET_OFFSET(id)] = FIELD_PREP(LPC_RESET_BIT(id), 0b1); + + return 0; +} + +static int reset_nxp_syscon_line_toggle(const struct device *dev, uint32_t id) +{ + uint8_t status = 0; + + reset_nxp_syscon_line_assert(dev, id); + + do { + reset_nxp_syscon_status(dev, id, &status); + } while (status != 0b1); + + reset_nxp_syscon_line_deassert(dev, id); + + return 0; +} + +static const struct reset_driver_api reset_nxp_syscon_driver_api = { + .status = reset_nxp_syscon_status, + .line_assert = reset_nxp_syscon_line_assert, + .line_deassert = reset_nxp_syscon_line_deassert, + .line_toggle = reset_nxp_syscon_line_toggle, +}; + +DEVICE_DT_INST_DEFINE(0, NULL, NULL, NULL, + (void *)(DT_REG_ADDR(DT_INST_PARENT(0)) + 0x100), + PRE_KERNEL_1, CONFIG_RESET_INIT_PRIORITY, + &reset_nxp_syscon_driver_api); diff --git a/drivers/reset/reset_npcx.c b/drivers/reset/reset_npcx.c new file mode 100644 index 00000000000..af9cac37f06 --- /dev/null +++ b/drivers/reset/reset_npcx.c @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2024 Nuvoton Technology Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nuvoton_npcx_rst + +#include +#include + +#if defined(CONFIG_SOC_SERIES_NPCX7) +#include +#elif defined(CONFIG_SOC_SERIES_NPCX9) +#include +#elif defined(CONFIG_SOC_SERIES_NPCX4) +#include +#endif + +#include +LOG_MODULE_REGISTER(rst_npcx); + +#define NPCX_RESET_CTL_REG_BYTE_SIZE 4 +#define NPCX_RESET_CTL_REG_OFFSET(id) ((id) >> (NPCX_RESET_CTL_REG_BYTE_SIZE + 1)) +#define NPCX_RESET_CTL_REG_BIT(id) (((id) & ((1 << (NPCX_RESET_CTL_REG_BYTE_SIZE + 1)) - 1))) + +#define NPCX_SWRST_TRG_WORD_START 0xC183 +#define NPCX_SWRST_TRG_WORD_CLEAR 0x0 +#define NPCX_SWRST_TRG_WORD_DONE 0xFFFF +#define NPCX_SWRST_DONE_TIMEOUT_US 100 + +struct reset_npcx_dev_config { + struct swrst_reg *reg_base; +}; + +static int reset_npcx_line_toggle(const struct device *dev, uint32_t id) +{ + const struct reset_npcx_dev_config *const config = dev->config; + struct swrst_reg *const reg = config->reg_base; + unsigned int key; + uint8_t reg_offset; + uint8_t reg_bit; + int ret = 0; + + if (!IN_RANGE(id, NPCX_RESET_ID_START, NPCX_RESET_ID_END)) { + LOG_ERR("Invalid Reset ID"); + return -EINVAL; + } + reg_offset = NPCX_RESET_CTL_REG_OFFSET(id); + reg_bit = NPCX_RESET_CTL_REG_BIT(id); + + key = irq_lock(); + + reg->SWRST_CTL[reg_offset] |= BIT(reg_bit); + reg->SWRST_TRG = NPCX_SWRST_TRG_WORD_CLEAR; + reg->SWRST_TRG = NPCX_SWRST_TRG_WORD_START; + + if (!WAIT_FOR((reg->SWRST_TRG == NPCX_SWRST_TRG_WORD_DONE), NPCX_SWRST_DONE_TIMEOUT_US, + NULL)) { + LOG_ERR("Reset trig timeout"); + ret = -EBUSY; + } + + irq_unlock(key); + + return ret; +} + +static const struct reset_driver_api reset_npcx_driver_api = { + .line_toggle = reset_npcx_line_toggle, +}; + +static const struct reset_npcx_dev_config reset_npcx_config = { + .reg_base = (struct swrst_reg *)DT_INST_REG_ADDR(0), +}; + +DEVICE_DT_INST_DEFINE(0, NULL, NULL, NULL, &reset_npcx_config, PRE_KERNEL_1, + CONFIG_RESET_INIT_PRIORITY, &reset_npcx_driver_api); diff --git a/drivers/reset/reset_nxp_rstctl.c b/drivers/reset/reset_nxp_rstctl.c new file mode 100644 index 00000000000..22d7cfa0650 --- /dev/null +++ b/drivers/reset/reset_nxp_rstctl.c @@ -0,0 +1,80 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nxp_rstctl + +#include +#include +#include + +#include + +#define NXP_RSTCTL_OFFSET(id) ((id >> 16) * sizeof(uint32_t)) +#define NXP_RSTCTL_BIT(id) (BIT(id & 0xFFFF)) +#define NXP_RSTCTL_CTL(id) (NXP_RSTCTL_OFFSET(id) + 0x10) +#define NXP_RSTCTL_SET(id) (NXP_RSTCTL_OFFSET(id) + 0x40) +#define NXP_RSTCTL_CLR(id) (NXP_RSTCTL_OFFSET(id) + 0x70) + +static int reset_nxp_rstctl_status(const struct device *dev, uint32_t id, uint8_t *status) +{ + const uint32_t *base = dev->config; + volatile const uint32_t *ctl_reg = base+(NXP_RSTCTL_CTL(id)/sizeof(uint32_t)); + uint32_t val = *ctl_reg; + + *status = (uint8_t)FIELD_GET(NXP_RSTCTL_BIT(id), val); + + return 0; +} + +static int reset_nxp_rstctl_line_assert(const struct device *dev, uint32_t id) +{ + const uint32_t *base = dev->config; + volatile uint32_t *set_reg = (uint32_t *)base+(NXP_RSTCTL_SET(id)/sizeof(uint32_t)); + + *set_reg = FIELD_PREP(NXP_RSTCTL_BIT(id), 0b1); + + return 0; +} + +static int reset_nxp_rstctl_line_deassert(const struct device *dev, uint32_t id) +{ + const uint32_t *base = dev->config; + volatile uint32_t *clr_reg = (uint32_t *)base+(NXP_RSTCTL_CLR(id)/sizeof(uint32_t)); + + *clr_reg = FIELD_PREP(NXP_RSTCTL_BIT(id), 0b1); + + return 0; +} + +static int reset_nxp_rstctl_line_toggle(const struct device *dev, uint32_t id) +{ + uint8_t status = 0; + + reset_nxp_rstctl_line_assert(dev, id); + + do { + reset_nxp_rstctl_status(dev, id, &status); + } while (status != 0b1); + + reset_nxp_rstctl_line_deassert(dev, id); + + return 0; +} + +static const struct reset_driver_api reset_nxp_rstctl_driver_api = { + .status = reset_nxp_rstctl_status, + .line_assert = reset_nxp_rstctl_line_assert, + .line_deassert = reset_nxp_rstctl_line_deassert, + .line_toggle = reset_nxp_rstctl_line_toggle, +}; + +#define NXP_RSTCTL_INIT(n) \ + DEVICE_DT_INST_DEFINE(n, NULL, NULL, NULL, \ + (void *)DT_INST_REG_ADDR(n), \ + PRE_KERNEL_1, CONFIG_RESET_INIT_PRIORITY, \ + &reset_nxp_rstctl_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(NXP_RSTCTL_INIT) diff --git a/drivers/rtc/CMakeLists.txt b/drivers/rtc/CMakeLists.txt index 26ea1a56567..85ff98320dd 100644 --- a/drivers/rtc/CMakeLists.txt +++ b/drivers/rtc/CMakeLists.txt @@ -20,3 +20,4 @@ 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) zephyr_library_sources_ifdef(CONFIG_RTC_RPI_PICO rtc_rpi_pico.c) +zephyr_library_sources_ifdef(CONFIG_RTC_NUMAKER rtc_numaker.c) diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 3b44235b75c..46bd2562dd9 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -52,5 +52,6 @@ source "drivers/rtc/Kconfig.rpi_pico" source "drivers/rtc/Kconfig.sam" source "drivers/rtc/Kconfig.smartbond" source "drivers/rtc/Kconfig.stm32" +source "drivers/rtc/Kconfig.numaker" endif # RTC diff --git a/drivers/rtc/Kconfig.numaker b/drivers/rtc/Kconfig.numaker new file mode 100644 index 00000000000..5e55f6a1086 --- /dev/null +++ b/drivers/rtc/Kconfig.numaker @@ -0,0 +1,14 @@ +# NUMAKER RTC Driver configuration options + +# Copyright (c) 2024 Nuvoton Technology Corporation. +# SPDX-License-Identifier: Apache-2.0 + +config RTC_NUMAKER + bool "Nuvoton NuMaker MCU RTC driver" + default y + select HAS_NUMAKER_RTC + depends on DT_HAS_NUVOTON_NUMAKER_RTC_ENABLED + help + This option enables the RTC driver for Nuvoton NuMaker family of + processors. + Say y if you wish to enable NuMaker RTC. diff --git a/drivers/rtc/rtc_ll_stm32.c b/drivers/rtc/rtc_ll_stm32.c index 1051c8fc0d1..2cdda0158f3 100644 --- a/drivers/rtc/rtc_ll_stm32.c +++ b/drivers/rtc/rtc_ll_stm32.c @@ -1,6 +1,7 @@ /* * Copyright (c) 2023 Prevas A/S * Copyright (c) 2023 Syslinbit + * Copyright (c) 2024 STMicroelectronics * * SPDX-License-Identifier: Apache-2.0 * @@ -22,15 +23,25 @@ #include #include #include +#ifdef CONFIG_RTC_ALARM +#include +#endif /* CONFIG_RTC_ALARM */ #include +#ifdef CONFIG_RTC_ALARM +#include +#endif /* CONFIG_RTC_ALARM */ #include +#include "rtc_utils.h" + +#include "rtc_ll_stm32.h" LOG_MODULE_REGISTER(rtc_stm32, CONFIG_RTC_LOG_LEVEL); -#if defined(CONFIG_SOC_SERIES_STM32L1X) && !defined(RTC_SUBSECOND_SUPPORT) -/* subsecond counting is not supported by some STM32L1x MCUs */ +#if (defined(CONFIG_SOC_SERIES_STM32L1X) && !defined(RTC_SUBSECOND_SUPPORT)) \ + || defined(CONFIG_SOC_SERIES_STM32F2X) +/* subsecond counting is not supported by some STM32L1x MCUs (Cat.1) & by STM32F2x SoC series */ #define HW_SUBSECOND_SUPPORT (0) #else #define HW_SUBSECOND_SUPPORT (1) @@ -67,6 +78,36 @@ LOG_MODULE_REGISTER(rtc_stm32, CONFIG_RTC_LOG_LEVEL); /* Timeout in microseconds used to wait for flags */ #define RTC_TIMEOUT 1000000 +#ifdef CONFIG_RTC_ALARM +#define RTC_STM32_ALARMS_COUNT DT_INST_PROP(0, alarms_count) + +#define RTC_STM32_ALRM_A 0U +#define RTC_STM32_ALRM_B 1U + +/* Zephyr mask supported by RTC device, values from RTC_ALARM_TIME_MASK */ +#define RTC_STM32_SUPPORTED_ALARM_FIELDS \ + (RTC_ALARM_TIME_MASK_SECOND | RTC_ALARM_TIME_MASK_MINUTE \ + | RTC_ALARM_TIME_MASK_HOUR | RTC_ALARM_TIME_MASK_WEEKDAY \ + | RTC_ALARM_TIME_MASK_MONTHDAY) + +#if DT_INST_NODE_HAS_PROP(0, alrm_exti_line) +#define RTC_STM32_EXTI_LINE CONCAT(LL_EXTI_LINE_, DT_INST_PROP(0, alrm_exti_line)) +#else +#define RTC_STM32_EXTI_LINE 0 +#endif /* DT_INST_NODE_HAS_PROP(0, alrm_exti_line) */ +#endif /* CONFIG_RTC_ALARM */ + +#if defined(PWR_CR_DBP) || defined(PWR_CR1_DBP) || defined(PWR_DBPCR_DBP) || defined(PWR_DBPR_DBP) +/* + * After system reset, the RTC registers are protected against parasitic write access by the + * DBP bit in the power control peripheral (PWR). + * Hence, DBP bit must be set in order to enable RTC registers write access. + */ +#define RTC_STM32_BACKUP_DOMAIN_WRITE_PROTECTION (1) +#else +#define RTC_STM32_BACKUP_DOMAIN_WRITE_PROTECTION (0) +#endif /* PWR_CR_DBP || PWR_CR1_DBP || PWR_DBPCR_DBP || PWR_DBPR_DBP */ + struct rtc_stm32_config { uint32_t async_prescaler; uint32_t sync_prescaler; @@ -76,8 +117,23 @@ struct rtc_stm32_config { #endif }; +#ifdef CONFIG_RTC_ALARM +struct rtc_stm32_alrm { + LL_RTC_AlarmTypeDef ll_rtc_alrm; + /* user-defined alarm mask, values from RTC_ALARM_TIME_MASK */ + uint16_t user_mask; + rtc_alarm_callback user_callback; + void *user_data; + bool is_pending; +}; +#endif /* CONFIG_RTC_ALARM */ + struct rtc_stm32_data { struct k_mutex lock; +#ifdef CONFIG_RTC_ALARM + struct rtc_stm32_alrm rtc_alrm_a; + struct rtc_stm32_alrm rtc_alrm_b; +#endif /* CONFIG_RTC_ALARM */ }; static int rtc_stm32_configure(const struct device *dev) @@ -126,6 +182,149 @@ static int rtc_stm32_configure(const struct device *dev) return err; } +#ifdef CONFIG_RTC_ALARM +static inline ErrorStatus rtc_stm32_init_alarm(RTC_TypeDef *rtc, uint32_t format, + LL_RTC_AlarmTypeDef *ll_alarm_struct, uint16_t id) +{ + ll_alarm_struct->AlarmDateWeekDaySel = RTC_STM32_ALRM_DATEWEEKDAYSEL_DATE; + /* RTC write protection is disabled & enabled again inside LL_RTC_ALMx_Init functions */ + if (id == RTC_STM32_ALRM_A) { + return LL_RTC_ALMA_Init(rtc, format, ll_alarm_struct); + } +#if RTC_STM32_ALARMS_COUNT > 1 + if (id == RTC_STM32_ALRM_B) { + return LL_RTC_ALMB_Init(rtc, format, ll_alarm_struct); + } +#endif /* RTC_STM32_ALARMS_COUNT > 1 */ + + return 0; +} + +static inline void rtc_stm32_clear_alarm_flag(RTC_TypeDef *rtc, uint16_t id) +{ + if (id == RTC_STM32_ALRM_A) { + LL_RTC_ClearFlag_ALRA(rtc); + return; + } +#if RTC_STM32_ALARMS_COUNT > 1 + if (id == RTC_STM32_ALRM_B) { + LL_RTC_ClearFlag_ALRB(rtc); + } +#endif /* RTC_STM32_ALARMS_COUNT > 1 */ +} + +static inline uint32_t rtc_stm32_is_active_alarm(RTC_TypeDef *rtc, uint16_t id) +{ + if (id == RTC_STM32_ALRM_A) { + return LL_RTC_IsActiveFlag_ALRA(rtc); + } +#if RTC_STM32_ALARMS_COUNT > 1 + if (id == RTC_STM32_ALRM_B) { + return LL_RTC_IsActiveFlag_ALRB(rtc); + } +#endif /* RTC_STM32_ALARMS_COUNT > 1 */ + + return 0; +} + +static inline void rtc_stm32_enable_interrupt_alarm(RTC_TypeDef *rtc, uint16_t id) +{ + if (id == RTC_STM32_ALRM_A) { + LL_RTC_EnableIT_ALRA(rtc); + return; + } +#if RTC_STM32_ALARMS_COUNT > 1 + if (id == RTC_STM32_ALRM_B) { + LL_RTC_EnableIT_ALRB(rtc); + } +#endif /* RTC_STM32_ALARMS_COUNT > 1 */ +} + +static inline void rtc_stm32_disable_interrupt_alarm(RTC_TypeDef *rtc, uint16_t id) +{ + if (id == RTC_STM32_ALRM_A) { + LL_RTC_DisableIT_ALRA(rtc); + return; + } +#if RTC_STM32_ALARMS_COUNT > 1 + if (id == RTC_STM32_ALRM_B) { + LL_RTC_DisableIT_ALRB(rtc); + } +#endif /* RTC_STM32_ALARMS_COUNT > 1 */ +} + +static inline void rtc_stm32_enable_alarm(RTC_TypeDef *rtc, uint16_t id) +{ + if (id == RTC_STM32_ALRM_A) { + LL_RTC_ALMA_Enable(rtc); + return; + } +#if RTC_STM32_ALARMS_COUNT > 1 + if (id == RTC_STM32_ALRM_B) { + LL_RTC_ALMB_Enable(rtc); + } +#endif /* RTC_STM32_ALARMS_COUNT > 1 */ +} + +static inline void rtc_stm32_disable_alarm(RTC_TypeDef *rtc, uint16_t id) +{ + if (id == RTC_STM32_ALRM_A) { + LL_RTC_ALMA_Disable(rtc); + return; + } +#if RTC_STM32_ALARMS_COUNT > 1 + if (id == RTC_STM32_ALRM_B) { + LL_RTC_ALMB_Disable(rtc); + } +#endif /* RTC_STM32_ALARMS_COUNT > 1 */ +} + +void rtc_stm32_isr(const struct device *dev) +{ + struct rtc_stm32_data *data = dev->data; + struct rtc_stm32_alrm *p_rtc_alrm; + int id = 0; + +#if RTC_STM32_BACKUP_DOMAIN_WRITE_PROTECTION + LL_PWR_EnableBkUpAccess(); +#endif /* RTC_STM32_BACKUP_DOMAIN_WRITE_PROTECTION */ + + for (id = 0; id < RTC_STM32_ALARMS_COUNT; id++) { + if (rtc_stm32_is_active_alarm(RTC, (uint16_t)id) != 0) { + LL_RTC_DisableWriteProtection(RTC); + rtc_stm32_clear_alarm_flag(RTC, (uint16_t)id); + LL_RTC_EnableWriteProtection(RTC); + + if (id == RTC_STM32_ALRM_A) { + p_rtc_alrm = &(data->rtc_alrm_a); + } else { + p_rtc_alrm = &(data->rtc_alrm_b); + } + + p_rtc_alrm->is_pending = true; + + if (p_rtc_alrm->user_callback != NULL) { + p_rtc_alrm->user_callback(dev, (uint16_t)id, p_rtc_alrm->user_data); + } + } + } + +#if RTC_STM32_BACKUP_DOMAIN_WRITE_PROTECTION + LL_PWR_DisableBkUpAccess(); +#endif /* RTC_STM32_BACKUP_DOMAIN_WRITE_PROTECTION */ + + ll_func_exti_clear_rtc_alarm_flag(RTC_STM32_EXTI_LINE); +} + +static void rtc_stm32_irq_config(const struct device *dev) +{ + IRQ_CONNECT(DT_INST_IRQN(0), + DT_INST_IRQ(0, priority), + rtc_stm32_isr, DEVICE_DT_INST_GET(0), 0); + irq_enable(DT_INST_IRQN(0)); +} +#endif /* CONFIG_RTC_ALARM */ + static int rtc_stm32_init(const struct device *dev) { const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE); @@ -148,9 +347,9 @@ static int rtc_stm32_init(const struct device *dev) k_mutex_init(&data->lock); /* Enable Backup access */ -#if defined(PWR_CR_DBP) || defined(PWR_CR1_DBP) || defined(PWR_DBPCR_DBP) || defined(PWR_DBPR_DBP) +#if RTC_STM32_BACKUP_DOMAIN_WRITE_PROTECTION LL_PWR_EnableBkUpAccess(); -#endif /* PWR_CR_DBP || PWR_CR1_DBP || PWR_DBPR_DBP */ +#endif /* RTC_STM32_BACKUP_DOMAIN_WRITE_PROTECTION */ /* Enable RTC clock source */ if (clock_control_configure(clk, (clock_control_subsys_t)&cfg->pclken[1], NULL) != 0) { @@ -158,17 +357,34 @@ static int rtc_stm32_init(const struct device *dev) return -EIO; } +/* + * On STM32WBAX series, there is no bit in BCDR register to enable RTC. + * Enabling RTC is done directly via the RCC APB register bit. + */ +#ifndef CONFIG_SOC_SERIES_STM32WBAX z_stm32_hsem_lock(CFG_HW_RCC_SEMID, HSEM_LOCK_DEFAULT_RETRY); LL_RCC_EnableRTC(); z_stm32_hsem_unlock(CFG_HW_RCC_SEMID); +#endif /* CONFIG_SOC_SERIES_STM32WBAX */ err = rtc_stm32_configure(dev); -#if defined(PWR_CR_DBP) || defined(PWR_CR1_DBP) || defined(PWR_DBPCR_DBP) || defined(PWR_DBPR_DBP) +#if RTC_STM32_BACKUP_DOMAIN_WRITE_PROTECTION LL_PWR_DisableBkUpAccess(); -#endif /* PWR_CR_DBP || PWR_CR1_DBP || PWR_DBPR_DBP */ +#endif /* RTC_STM32_BACKUP_DOMAIN_WRITE_PROTECTION */ + +#ifdef CONFIG_RTC_ALARM + rtc_stm32_irq_config(dev); + + ll_func_exti_enable_rtc_alarm_it(RTC_STM32_EXTI_LINE); + + k_mutex_lock(&data->lock, K_FOREVER); + memset(&(data->rtc_alrm_a), 0, sizeof(struct rtc_stm32_alrm)); + memset(&(data->rtc_alrm_b), 0, sizeof(struct rtc_stm32_alrm)); + k_mutex_unlock(&data->lock); +#endif /* CONFIG_RTC_ALARM */ return err; } @@ -176,9 +392,7 @@ static int rtc_stm32_init(const struct device *dev) static int rtc_stm32_set_time(const struct device *dev, const struct rtc_time *timeptr) { struct rtc_stm32_data *data = dev->data; - uint32_t real_year = timeptr->tm_year + TM_YEAR_REF; - int err = 0; if (real_year < RTC_YEAR_REF) { @@ -196,22 +410,19 @@ static int rtc_stm32_set_time(const struct device *dev, const struct rtc_time *t return err; } - LOG_INF("Setting clock"); + LOG_DBG("Setting clock"); -#if defined(PWR_CR_DBP) || defined(PWR_CR1_DBP) || defined(PWR_DBPCR_DBP) || defined(PWR_DBPR_DBP) +#if RTC_STM32_BACKUP_DOMAIN_WRITE_PROTECTION LL_PWR_EnableBkUpAccess(); -#endif /* PWR_CR_DBP || PWR_CR1_DBP || PWR_DBPR_DBP */ +#endif /* RTC_STM32_BACKUP_DOMAIN_WRITE_PROTECTION */ LL_RTC_DisableWriteProtection(RTC); 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 -EIO; + err = -EIO; + goto protect_unlock_return; } LL_RTC_DATE_SetYear(RTC, bin2bcd(real_year - RTC_YEAR_REF)); @@ -226,18 +437,18 @@ static int rtc_stm32_set_time(const struct device *dev, const struct rtc_time *t LL_RTC_DATE_SetWeekDay(RTC, timeptr->tm_wday); } - LL_RTC_TIME_SetHour(RTC, bin2bcd(timeptr->tm_hour)); LL_RTC_TIME_SetMinute(RTC, bin2bcd(timeptr->tm_min)); LL_RTC_TIME_SetSecond(RTC, bin2bcd(timeptr->tm_sec)); LL_RTC_DisableInitMode(RTC); +protect_unlock_return: LL_RTC_EnableWriteProtection(RTC); -#if defined(PWR_CR_DBP) || defined(PWR_CR1_DBP) || defined(PWR_DBPCR_DBP) || defined(PWR_DBPR_DBP) +#if RTC_STM32_BACKUP_DOMAIN_WRITE_PROTECTION LL_PWR_DisableBkUpAccess(); -#endif /* PWR_CR_DBP || PWR_CR1_DBP || PWR_DBPR_DBP */ +#endif /* RTC_STM32_BACKUP_DOMAIN_WRITE_PROTECTION */ k_mutex_unlock(&data->lock); @@ -253,7 +464,12 @@ static int rtc_stm32_get_time(const struct device *dev, struct rtc_time *timeptr #if HW_SUBSECOND_SUPPORT const struct rtc_stm32_config *cfg = dev->config; uint32_t rtc_subsecond; -#endif +#endif /* HW_SUBSECOND_SUPPORT */ + + if (timeptr == NULL) { + LOG_ERR("NULL rtc_time pointer"); + return -EINVAL; + } int err = k_mutex_lock(&data->lock, K_NO_WAIT); @@ -282,7 +498,7 @@ static int rtc_stm32_get_time(const struct device *dev, struct rtc_time *timeptr rtc_time = LL_RTC_TIME_Get(RTC); #if HW_SUBSECOND_SUPPORT rtc_subsecond = LL_RTC_TIME_GetSubSecond(RTC); -#endif +#endif /* HW_SUBSECOND_SUPPORT */ } while (rtc_time != LL_RTC_TIME_Get(RTC)); } while (rtc_date != LL_RTC_DATE_Get(RTC)); @@ -322,6 +538,387 @@ static int rtc_stm32_get_time(const struct device *dev, struct rtc_time *timeptr return 0; } +#ifdef CONFIG_RTC_ALARM +static void rtc_stm32_init_ll_alrm_struct(LL_RTC_AlarmTypeDef *p_rtc_alarm, + const struct rtc_time *timeptr, uint16_t mask) +{ + LL_RTC_TimeTypeDef *p_rtc_alrm_time = &(p_rtc_alarm->AlarmTime); + uint32_t ll_mask = 0; + + /* + * STM32 RTC Alarm LL mask should be set for all fields beyond the broadest one + * that's being matched with RTC calendar to trigger alarm periodically, + * the opposite of Zephyr RTC Alarm mask which is set for active fields. + */ + ll_mask = RTC_STM32_ALRM_MASK_ALL; + + if (mask & RTC_ALARM_TIME_MASK_SECOND) { + ll_mask &= ~RTC_STM32_ALRM_MASK_SECONDS; + p_rtc_alrm_time->Seconds = bin2bcd(timeptr->tm_sec); + } + + if (mask & RTC_ALARM_TIME_MASK_MINUTE) { + ll_mask &= ~RTC_STM32_ALRM_MASK_MINUTES; + p_rtc_alrm_time->Minutes = bin2bcd(timeptr->tm_min); + } + + if (mask & RTC_ALARM_TIME_MASK_HOUR) { + ll_mask &= ~RTC_STM32_ALRM_MASK_HOURS; + p_rtc_alrm_time->Hours = bin2bcd(timeptr->tm_hour); + } + + if (mask & RTC_ALARM_TIME_MASK_WEEKDAY) { + /* the Alarm Mask field compares with the day of the week */ + ll_mask &= ~RTC_STM32_ALRM_MASK_DATEWEEKDAY; + p_rtc_alarm->AlarmDateWeekDaySel = RTC_STM32_ALRM_DATEWEEKDAYSEL_WEEKDAY; + + if (timeptr->tm_wday == 0) { + /* sunday (tm_wday = 0) is not represented by the same value in hardware */ + p_rtc_alarm->AlarmDateWeekDay = LL_RTC_WEEKDAY_SUNDAY; + } else { + /* all the other values are consistent with what is expected by hardware */ + p_rtc_alarm->AlarmDateWeekDay = bin2bcd(timeptr->tm_wday); + } + + } else if (mask & RTC_ALARM_TIME_MASK_MONTHDAY) { + /* the Alarm compares with the day number & ignores the day of the week */ + ll_mask &= ~RTC_STM32_ALRM_MASK_DATEWEEKDAY; + p_rtc_alarm->AlarmDateWeekDaySel = RTC_STM32_ALRM_DATEWEEKDAYSEL_DATE; + p_rtc_alarm->AlarmDateWeekDay = bin2bcd(timeptr->tm_mday); + } + + p_rtc_alrm_time->TimeFormat = LL_RTC_TIME_FORMAT_AM_OR_24; + + p_rtc_alarm->AlarmMask = ll_mask; +} + +static inline void rtc_stm32_get_ll_alrm_time(uint16_t id, struct rtc_time *timeptr) +{ + if (id == RTC_STM32_ALRM_A) { + timeptr->tm_sec = bcd2bin(LL_RTC_ALMA_GetSecond(RTC)); + timeptr->tm_min = bcd2bin(LL_RTC_ALMA_GetMinute(RTC)); + timeptr->tm_hour = bcd2bin(LL_RTC_ALMA_GetHour(RTC)); + timeptr->tm_wday = bcd2bin(LL_RTC_ALMA_GetWeekDay(RTC)); + timeptr->tm_mday = bcd2bin(LL_RTC_ALMA_GetDay(RTC)); + return; + } +#if RTC_STM32_ALARMS_COUNT > 1 + if (id == RTC_STM32_ALRM_B) { + timeptr->tm_sec = bcd2bin(LL_RTC_ALMB_GetSecond(RTC)); + timeptr->tm_min = bcd2bin(LL_RTC_ALMB_GetMinute(RTC)); + timeptr->tm_hour = bcd2bin(LL_RTC_ALMB_GetHour(RTC)); + timeptr->tm_wday = bcd2bin(LL_RTC_ALMB_GetWeekDay(RTC)); + timeptr->tm_mday = bcd2bin(LL_RTC_ALMB_GetDay(RTC)); + } +#endif /* RTC_STM32_ALARMS_COUNT > 1 */ +} + +static inline uint16_t rtc_stm32_get_ll_alrm_mask(uint16_t id) +{ + uint32_t ll_alarm_mask = 0; + uint16_t zephyr_alarm_mask = 0; + uint32_t week_day = 0; + + /* + * STM32 RTC Alarm LL mask is set for all fields beyond the broadest one + * that's being matched with RTC calendar to trigger alarm periodically, + * the opposite of Zephyr RTC Alarm mask which is set for active fields. + */ + + if (id == RTC_STM32_ALRM_A) { + ll_alarm_mask = LL_RTC_ALMA_GetMask(RTC); + } + +#if RTC_STM32_ALARMS_COUNT > 1 + if (id == RTC_STM32_ALRM_B) { + ll_alarm_mask = LL_RTC_ALMB_GetMask(RTC); + } +#endif /* RTC_STM32_ALARMS_COUNT > 1 */ + + if ((ll_alarm_mask & RTC_STM32_ALRM_MASK_SECONDS) == 0x0) { + zephyr_alarm_mask = RTC_ALARM_TIME_MASK_SECOND; + } + if ((ll_alarm_mask & RTC_STM32_ALRM_MASK_MINUTES) == 0x0) { + zephyr_alarm_mask |= RTC_ALARM_TIME_MASK_MINUTE; + } + if ((ll_alarm_mask & RTC_STM32_ALRM_MASK_HOURS) == 0x0) { + zephyr_alarm_mask |= RTC_ALARM_TIME_MASK_HOUR; + } + if ((ll_alarm_mask & RTC_STM32_ALRM_MASK_DATEWEEKDAY) == 0x0) { + if (id == RTC_STM32_ALRM_A) { + week_day = LL_RTC_ALMA_GetWeekDay(RTC); + } +#if RTC_STM32_ALARMS_COUNT > 1 + if (id == RTC_STM32_ALRM_B) { + week_day = LL_RTC_ALMB_GetWeekDay(RTC); + } +#endif /* RTC_STM32_ALARMS_COUNT > 1 */ + if (week_day) { + zephyr_alarm_mask |= RTC_ALARM_TIME_MASK_WEEKDAY; + } else { + zephyr_alarm_mask |= RTC_ALARM_TIME_MASK_MONTHDAY; + } + } + + return zephyr_alarm_mask; +} + +static int rtc_stm32_alarm_get_supported_fields(const struct device *dev, uint16_t id, + uint16_t *mask) +{ + if (mask == NULL) { + LOG_ERR("NULL mask pointer"); + return -EINVAL; + } + + if ((id != RTC_STM32_ALRM_A) && (id != RTC_STM32_ALRM_B)) { + LOG_ERR("invalid alarm ID %d", id); + return -EINVAL; + } + + *mask = (uint16_t)RTC_STM32_SUPPORTED_ALARM_FIELDS; + + return 0; +} + +static int rtc_stm32_alarm_get_time(const struct device *dev, uint16_t id, uint16_t *mask, + struct rtc_time *timeptr) +{ + struct rtc_stm32_data *data = dev->data; + struct rtc_stm32_alrm *p_rtc_alrm; + LL_RTC_AlarmTypeDef *p_ll_rtc_alarm; + LL_RTC_TimeTypeDef *p_ll_rtc_alrm_time; + int err = 0; + + if ((mask == NULL) || (timeptr == NULL)) { + LOG_ERR("NULL pointer"); + return -EINVAL; + } + + k_mutex_lock(&data->lock, K_FOREVER); + + if (id == RTC_STM32_ALRM_A) { + p_rtc_alrm = &(data->rtc_alrm_a); + } else if (id == RTC_STM32_ALRM_B) { + p_rtc_alrm = &(data->rtc_alrm_b); + } else { + LOG_ERR("invalid alarm ID %d", id); + err = -EINVAL; + goto unlock; + } + + p_ll_rtc_alarm = &(p_rtc_alrm->ll_rtc_alrm); + p_ll_rtc_alrm_time = &(p_ll_rtc_alarm->AlarmTime); + + memset(timeptr, -1, sizeof(struct rtc_time)); + + rtc_stm32_get_ll_alrm_time(id, timeptr); + + p_rtc_alrm->user_mask = rtc_stm32_get_ll_alrm_mask(id); + + *mask = p_rtc_alrm->user_mask; + + LOG_DBG("get alarm: mday = %d, wday = %d, hour = %d, min = %d, sec = %d, " + "mask = 0x%04x", timeptr->tm_mday, timeptr->tm_wday, timeptr->tm_hour, + timeptr->tm_min, timeptr->tm_sec, *mask); + +unlock: + k_mutex_unlock(&data->lock); + + return err; +} + +static int rtc_stm32_alarm_set_time(const struct device *dev, uint16_t id, uint16_t mask, + const struct rtc_time *timeptr) +{ + struct rtc_stm32_data *data = dev->data; + struct rtc_stm32_alrm *p_rtc_alrm; + LL_RTC_AlarmTypeDef *p_ll_rtc_alarm; + LL_RTC_TimeTypeDef *p_ll_rtc_alrm_time; + int err = 0; + + k_mutex_lock(&data->lock, K_FOREVER); + + if (id == RTC_STM32_ALRM_A) { + p_rtc_alrm = &(data->rtc_alrm_a); + } else if (id == RTC_STM32_ALRM_B) { + p_rtc_alrm = &(data->rtc_alrm_b); + } else { + LOG_ERR("invalid alarm ID %d", id); + err = -EINVAL; + goto unlock; + } + + if ((mask == 0) && (timeptr == NULL)) { + memset(&(p_rtc_alrm->ll_rtc_alrm), 0, sizeof(LL_RTC_AlarmTypeDef)); + p_rtc_alrm->user_callback = NULL; + p_rtc_alrm->user_data = NULL; + p_rtc_alrm->is_pending = false; +#if RTC_STM32_BACKUP_DOMAIN_WRITE_PROTECTION + LL_PWR_EnableBkUpAccess(); +#endif /* RTC_STM32_BACKUP_DOMAIN_WRITE_PROTECTION */ + if (rtc_stm32_is_active_alarm(RTC, id)) { + LL_RTC_DisableWriteProtection(RTC); + rtc_stm32_disable_alarm(RTC, id); + LL_RTC_EnableWriteProtection(RTC); + } + LOG_DBG("Alarm %d has been disabled", id); + goto disable_bkup_access; + } + + if ((mask & ~RTC_STM32_SUPPORTED_ALARM_FIELDS) != 0) { + LOG_ERR("unsupported alarm %d field mask 0x%04x", id, mask); + err = -EINVAL; + goto unlock; + } + + if (timeptr == NULL) { + LOG_ERR("timeptr is invalid"); + err = -EINVAL; + goto unlock; + } + + if (!rtc_utils_validate_rtc_time(timeptr, mask)) { + LOG_DBG("One or multiple time values are invalid"); + err = -EINVAL; + goto unlock; + } + + p_ll_rtc_alarm = &(p_rtc_alrm->ll_rtc_alrm); + p_ll_rtc_alrm_time = &(p_ll_rtc_alarm->AlarmTime); + + memset(p_ll_rtc_alrm_time, 0, sizeof(LL_RTC_TimeTypeDef)); + rtc_stm32_init_ll_alrm_struct(p_ll_rtc_alarm, timeptr, mask); + + p_rtc_alrm->user_mask = mask; + + LOG_DBG("set alarm: second = %d, min = %d, hour = %d," + "wday = %d, mday = %d, mask = 0x%04x", + timeptr->tm_sec, timeptr->tm_min, timeptr->tm_hour, + timeptr->tm_wday, timeptr->tm_mday, mask); + +#if RTC_STM32_BACKUP_DOMAIN_WRITE_PROTECTION + LL_PWR_EnableBkUpAccess(); +#endif /* RTC_STM32_BACKUP_DOMAIN_WRITE_PROTECTION */ + + /* Disable the write protection for RTC registers */ + LL_RTC_DisableWriteProtection(RTC); + + if (rtc_stm32_is_active_alarm(RTC, id)) { + /* Disable Alarm if already active */ + rtc_stm32_disable_alarm(RTC, id); + } + +#ifdef RTC_ISR_ALRAWF + if (id == RTC_STM32_ALRM_A) { + /* Wait till RTC ALRAWF flag is set before writing to RTC registers */ + while ((LL_RTC_ReadReg(RTC, ISR) & RTC_ISR_ALRAWF) == 0U) { + ; + } + } +#endif /* RTC_ISR_ALRAWF */ + +#ifdef RTC_ISR_ALRBWF + if (id == RTC_STM32_ALRM_B) { + /* Wait till RTC ALRBWF flag is set before writing to RTC registers */ + while ((LL_RTC_ReadReg(RTC, ISR) & RTC_ISR_ALRBWF) == 0U) { + ; + } + } +#endif /* RTC_ISR_ALRBWF */ + + /* init Alarm */ + /* write protection is disabled & enabled again inside the LL_RTC_ALMx_Init function */ + if (rtc_stm32_init_alarm(RTC, LL_RTC_FORMAT_BCD, p_ll_rtc_alarm, id) != SUCCESS) { + LOG_ERR("Could not initialize Alarm %d", id); + err = -ECANCELED; + goto disable_bkup_access; + } + + /* Disable the write protection for RTC registers */ + LL_RTC_DisableWriteProtection(RTC); + + /* Enable Alarm */ + rtc_stm32_enable_alarm(RTC, id); + /* Clear Alarm flag */ + rtc_stm32_clear_alarm_flag(RTC, id); + /* Enable Alarm IT */ + rtc_stm32_enable_interrupt_alarm(RTC, id); + + ll_func_exti_enable_rtc_alarm_it(RTC_STM32_EXTI_LINE); + + /* Enable the write protection for RTC registers */ + LL_RTC_EnableWriteProtection(RTC); + +disable_bkup_access: +#if RTC_STM32_BACKUP_DOMAIN_WRITE_PROTECTION + LL_PWR_DisableBkUpAccess(); +#endif /* RTC_STM32_BACKUP_DOMAIN_WRITE_PROTECTION */ + +unlock: + k_mutex_unlock(&data->lock); + + return err; +} + +static int rtc_stm32_alarm_set_callback(const struct device *dev, uint16_t id, + rtc_alarm_callback callback, void *user_data) +{ + struct rtc_stm32_data *data = dev->data; + struct rtc_stm32_alrm *p_rtc_alrm; + int err = 0; + + k_mutex_lock(&data->lock, K_FOREVER); + + if (id == RTC_STM32_ALRM_A) { + p_rtc_alrm = &(data->rtc_alrm_a); + } else if (id == RTC_STM32_ALRM_B) { + p_rtc_alrm = &(data->rtc_alrm_b); + } else { + LOG_ERR("invalid alarm ID %d", id); + err = -EINVAL; + goto unlock; + } + + /* Passing the callback function and userdata filled by the user */ + p_rtc_alrm->user_callback = callback; + p_rtc_alrm->user_data = user_data; + +unlock: + k_mutex_unlock(&data->lock); + + return err; +} + +static int rtc_stm32_alarm_is_pending(const struct device *dev, uint16_t id) +{ + struct rtc_stm32_data *data = dev->data; + struct rtc_stm32_alrm *p_rtc_alrm; + int ret = 0; + + k_mutex_lock(&data->lock, K_FOREVER); + + if (id == RTC_STM32_ALRM_A) { + p_rtc_alrm = &(data->rtc_alrm_a); + } else if (id == RTC_STM32_ALRM_B) { + p_rtc_alrm = &(data->rtc_alrm_b); + } else { + LOG_ERR("invalid alarm ID %d", id); + ret = -EINVAL; + goto unlock; + } + + __disable_irq(); + ret = p_rtc_alrm->is_pending ? 1 : 0; + p_rtc_alrm->is_pending = false; + __enable_irq(); + +unlock: + k_mutex_unlock(&data->lock); + return ret; +} +#endif /* CONFIG_RTC_ALARM */ + #ifdef CONFIG_RTC_CALIBRATION #if !defined(CONFIG_SOC_SERIES_STM32F2X) && \ !(defined(CONFIG_SOC_SERIES_STM32L1X) && !defined(RTC_SMOOTHCALIB_SUPPORT)) @@ -361,9 +958,9 @@ 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) +#if RTC_STM32_BACKUP_DOMAIN_WRITE_PROTECTION LL_PWR_EnableBkUpAccess(); -#endif /* PWR_CR_DBP || PWR_CR1_DBP || PWR_DBPR_DBP */ +#endif /* RTC_STM32_BACKUP_DOMAIN_WRITE_PROTECTION */ LL_RTC_DisableWriteProtection(RTC); @@ -371,9 +968,9 @@ static int rtc_stm32_set_calibration(const struct device *dev, int32_t calibrati LL_RTC_EnableWriteProtection(RTC); -#if defined(PWR_CR_DBP) || defined(PWR_CR1_DBP) || defined(PWR_DBPCR_DBP) || defined(PWR_DBPR_DBP) +#if RTC_STM32_BACKUP_DOMAIN_WRITE_PROTECTION LL_PWR_DisableBkUpAccess(); -#endif /* PWR_CR_DBP || PWR_CR1_DBP || PWR_DBPR_DBP */ +#endif /* RTC_STM32_BACKUP_DOMAIN_WRITE_PROTECTION */ return 0; } @@ -403,8 +1000,13 @@ static int rtc_stm32_get_calibration(const struct device *dev, int32_t *calibrat 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 */ - /* RTC_UPDATE not supported */ +#ifdef CONFIG_RTC_ALARM + .alarm_get_supported_fields = rtc_stm32_alarm_get_supported_fields, + .alarm_set_time = rtc_stm32_alarm_set_time, + .alarm_get_time = rtc_stm32_alarm_get_time, + .alarm_set_callback = rtc_stm32_alarm_set_callback, + .alarm_is_pending = rtc_stm32_alarm_is_pending, +#endif /* CONFIG_RTC_ALARM */ #ifdef CONFIG_RTC_CALIBRATION #if !defined(CONFIG_SOC_SERIES_STM32F2X) && \ !(defined(CONFIG_SOC_SERIES_STM32L1X) && !defined(RTC_SMOOTHCALIB_SUPPORT)) diff --git a/drivers/rtc/rtc_ll_stm32.h b/drivers/rtc/rtc_ll_stm32.h new file mode 100644 index 00000000000..16f381081c1 --- /dev/null +++ b/drivers/rtc/rtc_ll_stm32.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_RTC_RTC_LL_STM32_H_ +#define ZEPHYR_DRIVERS_RTC_RTC_LL_STM32_H_ + +#ifdef CONFIG_RTC_ALARM + +/* STM32 RTC alarms, A & B, LL masks are equal */ +#define RTC_STM32_ALRM_MASK_ALL LL_RTC_ALMA_MASK_ALL +#define RTC_STM32_ALRM_MASK_SECONDS LL_RTC_ALMA_MASK_SECONDS +#define RTC_STM32_ALRM_MASK_MINUTES LL_RTC_ALMA_MASK_MINUTES +#define RTC_STM32_ALRM_MASK_HOURS LL_RTC_ALMA_MASK_HOURS +#define RTC_STM32_ALRM_MASK_DATEWEEKDAY LL_RTC_ALMA_MASK_DATEWEEKDAY + +#define RTC_STM32_ALRM_DATEWEEKDAYSEL_WEEKDAY LL_RTC_ALMA_DATEWEEKDAYSEL_WEEKDAY +#define RTC_STM32_ALRM_DATEWEEKDAYSEL_DATE LL_RTC_ALMA_DATEWEEKDAYSEL_DATE + +static inline void ll_func_exti_enable_rtc_alarm_it(uint32_t exti_line) +{ +#if defined(CONFIG_SOC_SERIES_STM32H7X) && defined(CONFIG_CPU_CORTEX_M4) + LL_C2_EXTI_EnableIT_0_31(exti_line); + LL_EXTI_EnableRisingTrig_0_31(exti_line); +#elif defined(CONFIG_SOC_SERIES_STM32U5X) || defined(CONFIG_SOC_SERIES_STM32WBAX) + /* in STM32U5 & STM32WBAX series, RTC Alarm event is not routed to EXTI */ +#else + LL_EXTI_EnableIT_0_31(exti_line); + LL_EXTI_EnableRisingTrig_0_31(exti_line); +#endif /* CONFIG_SOC_SERIES_STM32H7X and CONFIG_CPU_CORTEX_M4 */ +} + +static inline void ll_func_exti_clear_rtc_alarm_flag(uint32_t exti_line) +{ +#if defined(CONFIG_SOC_SERIES_STM32H7X) && defined(CONFIG_CPU_CORTEX_M4) + LL_C2_EXTI_ClearFlag_0_31(exti_line); +#elif defined(CONFIG_SOC_SERIES_STM32U5X) || defined(CONFIG_SOC_SERIES_STM32WBAX) + /* in STM32U5 & STM32WBAX series, RTC Alarm event is not routed to EXTI */ +#elif DT_HAS_COMPAT_STATUS_OKAY(st_stm32g0_exti) + LL_EXTI_ClearRisingFlag_0_31(exti_line); +#else + LL_EXTI_ClearFlag_0_31(exti_line); +#endif /* CONFIG_SOC_SERIES_STM32H7X and CONFIG_CPU_CORTEX_M4 */ +} +#endif /* CONFIG_RTC_ALARM */ + +#endif /* ZEPHYR_DRIVERS_RTC_RTC_LL_STM32_H_ */ diff --git a/drivers/rtc/rtc_numaker.c b/drivers/rtc/rtc_numaker.c new file mode 100644 index 00000000000..4356a76eef7 --- /dev/null +++ b/drivers/rtc/rtc_numaker.c @@ -0,0 +1,426 @@ +/* + * Copyright (c) 2024 Nuvoton Technology Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nuvoton_numaker_rtc + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "rtc_utils.h" + +LOG_MODULE_REGISTER(rtc_numaker, CONFIG_RTC_LOG_LEVEL); + +/* RTC support 2000 ~ 2099 */ +#define NVT_RTC_YEAR_MIN 2000U +#define NVT_RTC_YEAR_MAX 2099U +/* struct tm start time: 1st, Jan, 1900 */ +#define TM_YEAR_REF 1900U + +#define NVT_TIME_SCALE RTC_CLOCK_24 +#define NVT_ALARM_MSK 0x3fU +#define NVT_ALARM_UNIT_MSK 0x03U + +struct rtc_numaker_config { + RTC_T *rtc_base; + uint32_t clk_modidx; + const struct device *clk_dev; + uint32_t oscillator; +}; + +struct rtc_numaker_data { + struct k_spinlock lock; +#ifdef CONFIG_RTC_ALARM + rtc_alarm_callback alarm_callback; + void *alarm_user_data; + bool alarm_pending; +#endif /* CONFIG_RTC_ALARM */ +}; + +struct rtc_numaker_time { + uint32_t year; /* Year value */ + uint32_t month; /* Month value */ + uint32_t day; /* Day value */ + uint32_t day_of_week; /* Day of week value */ + uint32_t hour; /* Hour value */ + uint32_t minute; /* Minute value */ + uint32_t second; /* Second value */ + uint32_t time_scale; /* 12-Hour, 24-Hour */ + uint32_t am_pm; /* Only Time Scale select 12-hr used */ +}; + +static int rtc_numaker_set_time(const struct device *dev, const struct rtc_time *timeptr) +{ + struct rtc_numaker_time curr_time; + struct rtc_numaker_data *data = dev->data; + uint32_t real_year = timeptr->tm_year + TM_YEAR_REF; +#ifdef CONFIG_RTC_ALARM + const struct rtc_numaker_config *config = dev->config; + RTC_T *rtc_base = config->rtc_base; +#endif + + if (real_year < NVT_RTC_YEAR_MIN || real_year > NVT_RTC_YEAR_MAX) { + /* RTC can't support years out of 2000 ~ 2099 */ + return -EINVAL; + } + + if (timeptr->tm_wday == -1) { + return -EINVAL; + } + + curr_time.year = real_year; + curr_time.month = timeptr->tm_mon + 1; + curr_time.day = timeptr->tm_mday; + curr_time.hour = timeptr->tm_hour; + curr_time.minute = timeptr->tm_min; + curr_time.second = timeptr->tm_sec; + curr_time.day_of_week = timeptr->tm_wday; + curr_time.time_scale = NVT_TIME_SCALE; + + k_spinlock_key_t key = k_spin_lock(&data->lock); + + RTC_SetDateAndTime((S_RTC_TIME_DATA_T *)&curr_time); + +#ifdef CONFIG_RTC_ALARM + /* Restore RTC alarm mask */ + rtc_base->CAMSK = rtc_base->SPR[1]; + rtc_base->TAMSK = rtc_base->SPR[2]; +#endif + k_spin_unlock(&data->lock, key); + + return 0; +} + +static int rtc_numaker_get_time(const struct device *dev, struct rtc_time *timeptr) +{ + struct rtc_numaker_data *data = dev->data; + struct rtc_numaker_time curr_time; + + curr_time.time_scale = NVT_TIME_SCALE; + k_spinlock_key_t key = k_spin_lock(&data->lock); + + RTC_GetDateAndTime((S_RTC_TIME_DATA_T *)&curr_time); + k_spin_unlock(&data->lock, key); + + timeptr->tm_year = curr_time.year - TM_YEAR_REF; + timeptr->tm_mon = curr_time.month - 1; + timeptr->tm_mday = curr_time.day; + timeptr->tm_wday = curr_time.day_of_week; + + timeptr->tm_hour = curr_time.hour; + timeptr->tm_min = curr_time.minute; + timeptr->tm_sec = curr_time.second; + timeptr->tm_nsec = 0; + + /* unknown values */ + timeptr->tm_yday = -1; + timeptr->tm_isdst = -1; + + return 0; +} + +static void rtc_numaker_isr(const struct device *dev) +{ + const struct rtc_numaker_config *config = dev->config; + RTC_T *rtc_base = config->rtc_base; + uint32_t int_status; +#ifdef CONFIG_RTC_ALARM + struct rtc_numaker_data *data = dev->data; +#endif + + int_status = rtc_base->INTSTS; + if (int_status & RTC_INTSTS_TICKIF_Msk) { + /* Clear RTC Tick interrupt flag */ + rtc_base->INTSTS = RTC_INTSTS_TICKIF_Msk; + } + +#ifdef CONFIG_RTC_ALARM + if (int_status & RTC_INTSTS_ALMIF_Msk) { + rtc_alarm_callback callback; + void *user_data; + + /* Clear RTC Alarm interrupt flag */ + rtc_base->INTSTS = RTC_INTSTS_ALMIF_Msk; + rtc_base->CAMSK = 0x00; + rtc_base->TAMSK = 0x00; + callback = data->alarm_callback; + user_data = data->alarm_user_data; + data->alarm_pending = callback ? false : true; + + if (callback != NULL) { + callback(dev, 0, user_data); + } + } +#endif /* CONFIG_RTC_ALARM */ +} + +#ifdef CONFIG_RTC_ALARM +static int rtc_numaker_alarm_get_supported_fields(const struct device *dev, uint16_t id, + uint16_t *mask) +{ + ARG_UNUSED(dev); + ARG_UNUSED(id); + + *mask = 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 + | RTC_ALARM_TIME_MASK_YEAR; + + return 0; +} + +static int rtc_numaker_alarm_set_time(const struct device *dev, uint16_t id, uint16_t mask, + const struct rtc_time *timeptr) +{ + struct rtc_numaker_data *data = dev->data; + const struct rtc_numaker_config *config = dev->config; + RTC_T *rtc_base = config->rtc_base; + uint16_t mask_capable; + struct rtc_numaker_time alarm_time; + + rtc_numaker_alarm_get_supported_fields(dev, 0, &mask_capable); + + if ((id != 0)) { + return -EINVAL; + } + + if ((mask != 0) && (timeptr == NULL)) { + return -EINVAL; + } + + if (mask & ~mask_capable) { + return -EINVAL; + } + + if (rtc_utils_validate_rtc_time(timeptr, mask) == false) { + return -EINVAL; + } + + k_spinlock_key_t key = k_spin_lock(&data->lock); + + irq_disable(DT_INST_IRQN(0)); + if ((mask == 0) || (timeptr == NULL)) { + /* Disable the alarm */ + rtc_base->SPR[0] = mask; + rtc_base->SPR[1] = 0x00; + rtc_base->SPR[2] = 0x00; + irq_enable(DT_INST_IRQN(0)); + k_spin_unlock(&data->lock, key); + rtc_base->CAMSK = rtc_base->SPR[1]; + rtc_base->TAMSK = rtc_base->SPR[2]; + /* Disable RTC Alarm Interrupt */ + RTC_DisableInt(RTC_INTEN_ALMIEN_Msk); + return 0; + } + + alarm_time.time_scale = NVT_TIME_SCALE; + RTC_GetDateAndTime((S_RTC_TIME_DATA_T *)&alarm_time); + + /* Reset RTC alarm mask of camsk & tamsk */ + uint32_t camsk = NVT_ALARM_MSK; + uint32_t tamsk = NVT_ALARM_MSK; + + /* Set H/W care to match bits */ + if (mask & RTC_ALARM_TIME_MASK_YEAR) { + alarm_time.year = timeptr->tm_year + TM_YEAR_REF; + camsk &= ~(NVT_ALARM_UNIT_MSK << RTC_CAMSK_MYEAR_Pos); + } + if (mask & RTC_ALARM_TIME_MASK_MONTH) { + alarm_time.month = timeptr->tm_mon + 1; + camsk &= ~(NVT_ALARM_UNIT_MSK << RTC_CAMSK_MMON_Pos); + } + if (mask & RTC_ALARM_TIME_MASK_MONTHDAY) { + alarm_time.day = timeptr->tm_mday; + camsk &= ~(NVT_ALARM_UNIT_MSK << RTC_CAMSK_MDAY_Pos); + } + if (mask & RTC_ALARM_TIME_MASK_HOUR) { + alarm_time.hour = timeptr->tm_hour; + tamsk &= ~(NVT_ALARM_UNIT_MSK << RTC_TAMSK_MHR_Pos); + } + if (mask & RTC_ALARM_TIME_MASK_MINUTE) { + alarm_time.minute = timeptr->tm_min; + tamsk &= ~(NVT_ALARM_UNIT_MSK << RTC_TAMSK_MMIN_Pos); + } + if (mask & RTC_ALARM_TIME_MASK_SECOND) { + alarm_time.second = timeptr->tm_sec; + tamsk &= ~(NVT_ALARM_UNIT_MSK << RTC_TAMSK_MSEC_Pos); + } + + /* Disable RTC Alarm Interrupt */ + RTC_DisableInt(RTC_INTEN_ALMIEN_Msk); + + /* Set the alarm time */ + RTC_SetAlarmDateAndTime((S_RTC_TIME_DATA_T *)&alarm_time); + + /* Clear RTC alarm interrupt flag */ + RTC_CLEAR_ALARM_INT_FLAG(); + + rtc_base->SPR[0] = mask; + rtc_base->SPR[1] = camsk; + rtc_base->SPR[2] = tamsk; + + rtc_base->CAMSK = rtc_base->SPR[1]; + rtc_base->TAMSK = rtc_base->SPR[2]; + + k_spin_unlock(&data->lock, key); + irq_enable(DT_INST_IRQN(0)); + + /* Enable RTC Alarm Interrupt */ + RTC_EnableInt(RTC_INTEN_ALMIEN_Msk); + + return 0; +} + +static int rtc_numaker_alarm_get_time(const struct device *dev, uint16_t id, uint16_t *mask, + struct rtc_time *timeptr) +{ + struct rtc_numaker_data *data = dev->data; + const struct rtc_numaker_config *config = dev->config; + RTC_T *rtc_base = config->rtc_base; + struct rtc_numaker_time alarm_time; + + if ((id != 0) || (mask == NULL) || (timeptr == NULL)) { + return -EINVAL; + } + + alarm_time.time_scale = NVT_TIME_SCALE; + + K_SPINLOCK(&data->lock) { + RTC_GetAlarmDateAndTime((S_RTC_TIME_DATA_T *)&alarm_time); + } + + *mask = rtc_base->SPR[0]; + if (*mask & RTC_ALARM_TIME_MASK_YEAR) { + timeptr->tm_year = alarm_time.year - TM_YEAR_REF; + } + if (*mask & RTC_ALARM_TIME_MASK_MONTH) { + timeptr->tm_mon = alarm_time.month - 1; + } + if (*mask & RTC_ALARM_TIME_MASK_MONTHDAY) { + timeptr->tm_mday = alarm_time.day; + } + if (*mask & RTC_ALARM_TIME_MASK_HOUR) { + timeptr->tm_hour = alarm_time.hour; + } + if (*mask & RTC_ALARM_TIME_MASK_MINUTE) { + timeptr->tm_min = alarm_time.minute; + } + if (*mask & RTC_ALARM_TIME_MASK_SECOND) { + timeptr->tm_sec = alarm_time.second; + } + + return 0; +} + +static int rtc_numaker_alarm_is_pending(const struct device *dev, uint16_t id) +{ + struct rtc_numaker_data *data = dev->data; + int ret; + + if (id != 0) { + return -EINVAL; + } + + K_SPINLOCK(&data->lock) { + ret = data->alarm_pending ? 1 : 0; + data->alarm_pending = false; + } + + return ret; +} + +static int rtc_numaker_alarm_set_callback(const struct device *dev, uint16_t id, + rtc_alarm_callback callback, void *user_data) +{ + struct rtc_numaker_data *data = dev->data; + + if (id != 0) { + return -EINVAL; + } + + K_SPINLOCK(&data->lock) { + irq_disable(DT_INST_IRQN(0)); + data->alarm_callback = callback; + data->alarm_user_data = user_data; + if ((callback == NULL) && (user_data == NULL)) { + /* Disable RTC Alarm Interrupt */ + RTC_DisableInt(RTC_INTEN_ALMIEN_Msk); + } + irq_enable(DT_INST_IRQN(0)); + } + + return 0; +} +#endif /* CONFIG_RTC_ALARM */ + +static const struct rtc_driver_api rtc_numaker_driver_api = { + .set_time = rtc_numaker_set_time, + .get_time = rtc_numaker_get_time, +#ifdef CONFIG_RTC_ALARM + .alarm_get_supported_fields = rtc_numaker_alarm_get_supported_fields, + .alarm_set_time = rtc_numaker_alarm_set_time, + .alarm_get_time = rtc_numaker_alarm_get_time, + .alarm_is_pending = rtc_numaker_alarm_is_pending, + .alarm_set_callback = rtc_numaker_alarm_set_callback, +#endif /* CONFIG_RTC_ALARM */ +}; + +static int rtc_numaker_init(const struct device *dev) +{ + const struct rtc_numaker_config *cfg = dev->config; + struct numaker_scc_subsys scc_subsys; + RTC_T *rtc_base = cfg->rtc_base; + int err; + + /* 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; + + SYS_UnlockReg(); + + /* CLK_EnableModuleClock */ + err = clock_control_on(cfg->clk_dev, (clock_control_subsys_t)&scc_subsys); + if (err != 0) { + goto done; + } + + RTC_SetClockSource(cfg->oscillator); + /* Enable spare registers */ + rtc_base->SPRCTL = RTC_SPRCTL_SPRRWEN_Msk; + + irq_disable(DT_INST_IRQN(0)); + + IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), rtc_numaker_isr, + DEVICE_DT_INST_GET(0), 0); + + irq_enable(DT_INST_IRQN(0)); + err = RTC_Open(0); + +done: + SYS_LockReg(); + return err; +} + +static struct rtc_numaker_data rtc_data; + +/* Set config based on DTS */ +static const struct rtc_numaker_config rtc_config = { + .rtc_base = (RTC_T *)DT_INST_REG_ADDR(0), + .clk_modidx = DT_INST_CLOCKS_CELL(0, clock_module_index), + .clk_dev = DEVICE_DT_GET(DT_PARENT(DT_INST_CLOCKS_CTLR(0))), + .oscillator = DT_ENUM_IDX(DT_NODELABEL(rtc), oscillator), +}; + +DEVICE_DT_INST_DEFINE(0, &rtc_numaker_init, NULL, &rtc_data, &rtc_config, PRE_KERNEL_1, + CONFIG_RTC_INIT_PRIORITY, &rtc_numaker_driver_api); diff --git a/drivers/rtc/rtc_smartbond.c b/drivers/rtc/rtc_smartbond.c index bfac974e874..7aa0d461d27 100644 --- a/drivers/rtc/rtc_smartbond.c +++ b/drivers/rtc/rtc_smartbond.c @@ -16,6 +16,7 @@ #include #include #include +#include "rtc_utils.h" #include LOG_MODULE_REGISTER(rtc_smartbond, CONFIG_RTC_LOG_LEVEL); @@ -266,8 +267,7 @@ static int rtc_smartbond_get_time(const struct device *dev, struct rtc_time *tim } if (!data->is_rtc_configured) { - LOG_ERR("RTC is not initialized yet"); - return -ENODATA; + LOG_WRN("RTC is not initialized yet"); } k_mutex_lock(&data->lock, K_FOREVER); @@ -286,7 +286,10 @@ static int rtc_smartbond_get_time(const struct device *dev, struct rtc_time *tim #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 */ +/* + * Parse only the alarm fields indicated by the mask. Default valid values should be assigned + * to unused fields as it might happen that application has provided with invalid values. + */ static uint32_t alarm_calendar_to_bcd(const struct rtc_time *timeptr, uint16_t mask) { uint32_t rtc_calendar_alarm_reg = 0x0108; @@ -304,14 +307,28 @@ static uint32_t alarm_calendar_to_bcd(const struct rtc_time *timeptr, uint16_t m 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) +/* + * Parse only the alarm fields indicated by the mask. Default valid values should be assigned + * to unused fields as it might happen that application has provided with invalid values. + */ +static inline uint32_t alarm_time_to_bcd(const struct rtc_time *timeptr, uint16_t mask) { 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]*/ + if (mask & RTC_ALARM_TIME_MASK_SECOND) { + /*[0, 59]*/ + RTC_TIME_ALARM_REG_SET_FIELD(S, rtc_time_alarm_reg, bin2bcd(timeptr->tm_sec)); + } + + if (mask & RTC_ALARM_TIME_MASK_MINUTE) { + /*[0, 59]*/ + RTC_TIME_ALARM_REG_SET_FIELD(M, rtc_time_alarm_reg, bin2bcd(timeptr->tm_min)); + } + + if (mask & RTC_ALARM_TIME_MASK_HOUR) { + /*[0, 23]*/ + RTC_TIME_ALARM_REG_SET_FIELD(HR, rtc_time_alarm_reg, bin2bcd(timeptr->tm_hour)); + } return rtc_time_alarm_reg; } @@ -408,6 +425,11 @@ static int rtc_smartbond_alarm_set_time(const struct device *dev, uint16_t id, u return -EINVAL; } + if (!rtc_utils_validate_rtc_time(timeptr, mask)) { + LOG_ERR("Invalid alarm fields values"); + return -EINVAL; + } + if (!data->is_rtc_configured) { LOG_WRN("RTC is not initialized yet"); } @@ -425,7 +447,7 @@ static int rtc_smartbond_alarm_set_time(const struct device *dev, uint16_t id, u 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_TIME_ALARM_REG = alarm_time_to_bcd(timeptr, mask); RTC->RTC_CALENDAR_ALARM_REG = alarm_calendar_to_bcd(timeptr, mask); rtc_status_reg = RTC->RTC_STATUS_REG; diff --git a/drivers/sdhc/CMakeLists.txt b/drivers/sdhc/CMakeLists.txt index 2675589bfc9..42985f873f1 100644 --- a/drivers/sdhc/CMakeLists.txt +++ b/drivers/sdhc/CMakeLists.txt @@ -6,8 +6,10 @@ zephyr_library() zephyr_library_sources_ifdef(CONFIG_IMX_USDHC imx_usdhc.c) 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_RCAR_MMC rcar_mmc.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) +zephyr_library_sources_ifdef(CONFIG_SDHC_ESP32 sdhc_esp32.c) endif() diff --git a/drivers/sdhc/Kconfig b/drivers/sdhc/Kconfig index 13b63cfcc9c..b6b1276207b 100644 --- a/drivers/sdhc/Kconfig +++ b/drivers/sdhc/Kconfig @@ -12,9 +12,11 @@ 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.rcar" source "drivers/sdhc/Kconfig.sam_hsmci" source "drivers/sdhc/Kconfig.intel" source "drivers/sdhc/Kconfig.sdhc_cdns" +source "drivers/sdhc/Kconfig.esp32" config SDHC_INIT_PRIORITY int "SDHC driver init priority" diff --git a/drivers/sdhc/Kconfig.esp32 b/drivers/sdhc/Kconfig.esp32 new file mode 100644 index 00000000000..cf95a4317a0 --- /dev/null +++ b/drivers/sdhc/Kconfig.esp32 @@ -0,0 +1,19 @@ +# Copyright (c) 2024 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +config SDHC_ESP32 + bool "ESP32 SDHC Driver" + default y + depends on DT_HAS_ESPRESSIF_ESP32_SDHC_SLOT_ENABLED + select SDHC_SUPPORTS_NATIVE_MODE + select PINCTRL + help + Enables the ESP32 SD Host controller driver + +if SDHC_ESP32 + +# ESP32 DMA needs 32 bit aligned buffers +config SDHC_BUFFER_ALIGNMENT + default 4 + +endif diff --git a/drivers/sdhc/Kconfig.imx b/drivers/sdhc/Kconfig.imx index 48e47a12621..47bb84db553 100644 --- a/drivers/sdhc/Kconfig.imx +++ b/drivers/sdhc/Kconfig.imx @@ -1,5 +1,5 @@ # Copyright (c) 2022, NXP -# SPDX -License-Identifier: Apache-2.0 +# SPDX-License-Identifier: Apache-2.0 config IMX_USDHC bool "NXP IMX USDHC Driver" diff --git a/drivers/sdhc/Kconfig.mcux_sdif b/drivers/sdhc/Kconfig.mcux_sdif index 528df6de763..2b66a42e564 100644 --- a/drivers/sdhc/Kconfig.mcux_sdif +++ b/drivers/sdhc/Kconfig.mcux_sdif @@ -1,5 +1,5 @@ # Copyright 2022, NXP -# SPDX -License-Identifier: Apache-2.0 +# SPDX-License-Identifier: Apache-2.0 config MCUX_SDIF bool "NXP MCUX SDIF Driver" diff --git a/drivers/sdhc/Kconfig.rcar b/drivers/sdhc/Kconfig.rcar new file mode 100644 index 00000000000..f5d57a4bb03 --- /dev/null +++ b/drivers/sdhc/Kconfig.rcar @@ -0,0 +1,42 @@ +# Copyright (c) 2023 EPAM Systems +# SPDX-License-Identifier: Apache-2.0 + +config RCAR_MMC + bool "Renesas Rcar MMC driver" + default y + depends on DT_HAS_RENESAS_RCAR_MMC_ENABLED + select SDHC_SUPPORTS_NATIVE_MODE + select REGULATOR + select GPIO + select SDHC_SUPPORTS_UHS if SDMMC_STACK + help + Renesas Rcar MMC driver. + +if RCAR_MMC + +config RCAR_MMC_DMA_SUPPORT + bool "Internal DMA support for Renesas Rcar MMC driver" + select CACHE_MANAGEMENT + select DCACHE + default y + help + Internal DMA support for Renesas Rcar MMC driver. + +config RCAR_MMC_SCC_SUPPORT + bool "Support of SCC" + default y + help + Enable support of Sampling Clock Controller for Renesas Rcar MMC driver. + +if RCAR_MMC_DMA_SUPPORT + +config SDHC_BUFFER_ALIGNMENT + default 128 + +config RCAR_MMC_DMA_IRQ_DRIVEN_SUPPORT + bool "Internal DMA IRQ driven support for Renesas Rcar MMC driver" + default y + +endif # RCAR_MMC_DMA_SUPPORT + +endif # RCAR_MMC diff --git a/drivers/sdhc/Kconfig.sam_hsmci b/drivers/sdhc/Kconfig.sam_hsmci index 68265dcabed..fca9bafdaff 100644 --- a/drivers/sdhc/Kconfig.sam_hsmci +++ b/drivers/sdhc/Kconfig.sam_hsmci @@ -1,5 +1,5 @@ # Copyright 2023 Nikhef -# SPDX -License-Identifier: Apache-2.0 +# SPDX-License-Identifier: Apache-2.0 config SAM_HSMCI bool "ATMEL SAM HSMCI driver" diff --git a/drivers/sdhc/Kconfig.spi b/drivers/sdhc/Kconfig.spi index 555f11619b0..ce861f1d02d 100644 --- a/drivers/sdhc/Kconfig.spi +++ b/drivers/sdhc/Kconfig.spi @@ -1,5 +1,5 @@ # Copyright (c) 2022, NXP -# SPDX -License-Identifier: Apache-2.0 +# SPDX-License-Identifier: Apache-2.0 config SPI_SDHC bool "SD protocol over SPI bus" diff --git a/drivers/sdhc/imx_usdhc.c b/drivers/sdhc/imx_usdhc.c index 84f8f2aee3b..2909ea104b1 100644 --- a/drivers/sdhc/imx_usdhc.c +++ b/drivers/sdhc/imx_usdhc.c @@ -159,6 +159,14 @@ static void card_detect_gpio_cb(const struct device *port, } } +static void imx_usdhc_select_1_8v(USDHC_Type *base, bool enable_1_8v) +{ +#if !(defined(FSL_FEATURE_USDHC_HAS_NO_VOLTAGE_SELECT) && \ + (FSL_FEATURE_USDHC_HAS_NO_VOLTAGE_SELECT)) + UDSHC_SelectVoltage(base, enable_1_8v); +#endif +} + static int imx_usdhc_dat3_pull(const struct usdhc_config *cfg, bool pullup) { @@ -256,7 +264,7 @@ static int imx_usdhc_reset(const struct device *dev) { const struct usdhc_config *cfg = dev->config; /* Switch to default I/O voltage of 3.3V */ - UDSHC_SelectVoltage(cfg->base, false); + imx_usdhc_select_1_8v(cfg->base, false); USDHC_EnableDDRMode(cfg->base, false, 0U); #if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE) USDHC_EnableStandardTuning(cfg->base, 0, 0, false); @@ -271,22 +279,7 @@ static int imx_usdhc_reset(const struct device *dev) #endif /* Reset data/command/tuning circuit */ - return USDHC_Reset(cfg->base, kUSDHC_ResetAll, 100U) == true ? 0 : -ETIMEDOUT; -} - -/* Wait for USDHC to gate clock when it is disabled */ -static inline void imx_usdhc_wait_clock_gate(USDHC_Type *base) -{ - uint32_t timeout = 1000; - - while (timeout--) { - if (base->PRES_STATE & USDHC_PRES_STATE_SDOFF_MASK) { - break; - } - } - if (timeout == 0) { - LOG_WRN("SD clock did not gate in time"); - } + return USDHC_Reset(cfg->base, kUSDHC_ResetAll, 1000U) == true ? 0 : -ETIMEDOUT; } /* @@ -353,7 +346,7 @@ static int imx_usdhc_set_io(const struct device *dev, struct sdhc_io *ios) switch (ios->signal_voltage) { case SD_VOL_3_3_V: case SD_VOL_3_0_V: - UDSHC_SelectVoltage(cfg->base, false); + imx_usdhc_select_1_8v(cfg->base, false); break; case SD_VOL_1_8_V: /** @@ -367,7 +360,7 @@ static int imx_usdhc_set_io(const struct device *dev, struct sdhc_io *ios) * 10 ms, then allow it to be gated again. */ /* Switch to 1.8V */ - UDSHC_SelectVoltage(cfg->base, true); + imx_usdhc_select_1_8v(cfg->base, true); /* Wait 10 ms- clock will be gated during this period */ k_msleep(10); /* Force the clock on */ diff --git a/drivers/sdhc/rcar_mmc.c b/drivers/sdhc/rcar_mmc.c new file mode 100644 index 00000000000..8d637f0fd57 --- /dev/null +++ b/drivers/sdhc/rcar_mmc.c @@ -0,0 +1,2214 @@ +/* + * Copyright (c) 2023 EPAM Systems + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT renesas_rcar_mmc + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rcar_mmc_registers.h" + +#define PINCTRL_STATE_UHS PINCTRL_STATE_PRIV_START + +/** + * @note we don't need any locks here, because SDHC subsystem cares about it + */ + +LOG_MODULE_REGISTER(rcar_mmc, CONFIG_LOG_DEFAULT_LEVEL); + +#define MMC_POLL_FLAGS_TIMEOUT_US 100000 +#define MMC_POLL_FLAGS_ONE_CYCLE_TIMEOUT_US 1 +#define MMC_BUS_CLOCK_FREQ 800000000 + +#ifdef CONFIG_RCAR_MMC_DMA_SUPPORT +#define ALIGN_BUF_DMA __aligned(CONFIG_SDHC_BUFFER_ALIGNMENT) +#else +#define ALIGN_BUF_DMA +#endif + +/** + * @brief Renesas MMC host controller driver data + * + */ +struct mmc_rcar_data { + DEVICE_MMIO_RAM; /* Must be first */ + struct sdhc_io host_io; + struct sdhc_host_props props; +#ifdef CONFIG_RCAR_MMC_DMA_IRQ_DRIVEN_SUPPORT + struct k_sem irq_xref_fin; +#endif + + uint8_t ver; + /* in bytes, possible values are 2, 4 or 8 */ + uint8_t width_access_sd_buf0; + uint8_t ddr_mode; + uint8_t restore_cfg_after_reset; + uint8_t is_last_cmd_app_cmd; /* ACMD55 */ + +#ifdef CONFIG_RCAR_MMC_SCC_SUPPORT + uint8_t manual_retuning; + uint8_t tuning_buf[128] ALIGN_BUF_DMA; +#endif /* CONFIG_RCAR_MMC_SCC_SUPPORT */ + uint8_t can_retune; +}; + +/** + * @brief Renesas MMC host controller driver configuration + */ +struct mmc_rcar_cfg { + DEVICE_MMIO_ROM; /* Must be first */ + struct rcar_cpg_clk cpg_clk; + struct rcar_cpg_clk bus_clk; + const struct device *cpg_dev; + const struct pinctrl_dev_config *pcfg; + const struct device *regulator_vqmmc; + const struct device *regulator_vmmc; + + uint32_t max_frequency; + +#ifdef CONFIG_RCAR_MMC_DMA_IRQ_DRIVEN_SUPPORT + void (*irq_config_func)(const struct device *dev); +#endif + + uint8_t non_removable; + uint8_t uhs_support; + uint8_t mmc_hs200_1_8v; + uint8_t mmc_hs400_1_8v; + uint8_t bus_width; + uint8_t mmc_sdr104_support; +}; + +#ifdef CONFIG_RCAR_MMC_SCC_SUPPORT +static int rcar_mmc_execute_tuning(const struct device *dev); +static int rcar_mmc_retune_if_needed(const struct device *dev, bool request_retune); +#endif +static int rcar_mmc_disable_scc(const struct device *dev); + +static uint32_t rcar_mmc_read_reg32(const struct device *dev, uint32_t reg) +{ + return sys_read32(DEVICE_MMIO_GET(dev) + reg); +} + +static void rcar_mmc_write_reg32(const struct device *dev, uint32_t reg, uint32_t val) +{ + sys_write32(val, DEVICE_MMIO_GET(dev) + reg); +} + +/* cleanup SD card interrupt flag register and mask their interrupts */ +static inline void rcar_mmc_reset_and_mask_irqs(const struct device *dev) +{ + struct mmc_rcar_data *data = dev->data; + + rcar_mmc_write_reg32(dev, RCAR_MMC_INFO1, 0); + rcar_mmc_write_reg32(dev, RCAR_MMC_INFO1_MASK, ~0); + + rcar_mmc_write_reg32(dev, RCAR_MMC_INFO2, RCAR_MMC_INFO2_CLEAR); + rcar_mmc_write_reg32(dev, RCAR_MMC_INFO2_MASK, ~0); + +#ifdef CONFIG_RCAR_MMC_DMA_SUPPORT + /* default value of Seq suspend should be 0 */ + rcar_mmc_write_reg32(dev, RCAR_MMC_DMA_INFO1_MASK, 0xfffffeff); + rcar_mmc_write_reg32(dev, RCAR_MMC_DMA_INFO1, 0x0); + rcar_mmc_write_reg32(dev, RCAR_MMC_DMA_INFO2_MASK, 0xffffffff); + rcar_mmc_write_reg32(dev, RCAR_MMC_DMA_INFO2, 0x0); +#ifdef CONFIG_RCAR_MMC_DMA_IRQ_DRIVEN_SUPPORT + k_sem_reset(&data->irq_xref_fin); +#endif +#endif /* CONFIG_RCAR_MMC_DMA_SUPPORT */ +} + +/** + * @brief check if MMC is busy + * + * This check should generally be implemented as checking the controller + * state. No MMC commands need to be sent. + * + * @param dev MMC device + * @retval 0 card is not busy + * @retval 1 card is busy + * @retval -EINVAL: the dev pointer is NULL + */ +static int rcar_mmc_card_busy(const struct device *dev) +{ + uint32_t reg; + + if (!dev) { + return -EINVAL; + } + + reg = rcar_mmc_read_reg32(dev, RCAR_MMC_INFO2); + return (reg & RCAR_MMC_INFO2_DAT0) ? 0 : 1; +} + +/** + * @brief Check error flags inside INFO2 MMC register + * + * @note in/out parameters should be checked by a caller function + * + * @param dev MMC device + * + * @retval 0 INFO2 register hasn't errors + * @retval -ETIMEDOUT: timed out while tx/rx + * @retval -EIO: I/O error + * @retval -EILSEQ: communication out of sync + */ +static int rcar_mmc_check_errors(const struct device *dev) +{ + uint32_t info2 = rcar_mmc_read_reg32(dev, RCAR_MMC_INFO2); + + if (info2 & (RCAR_MMC_INFO2_ERR_TO | RCAR_MMC_INFO2_ERR_RTO)) { + LOG_DBG("timeout error 0x%08x", info2); + return -ETIMEDOUT; + } + + if (info2 & (RCAR_MMC_INFO2_ERR_END | RCAR_MMC_INFO2_ERR_CRC | RCAR_MMC_INFO2_ERR_IDX)) { + LOG_DBG("communication out of sync 0x%08x", info2); + return -EILSEQ; + } + + if (info2 & (RCAR_MMC_INFO2_ERR_ILA | RCAR_MMC_INFO2_ERR_ILR | RCAR_MMC_INFO2_ERR_ILW)) { + LOG_DBG("illegal access 0x%08x", info2); + return -EIO; + } + + return 0; +} + +/** + * @brief Poll flag(s) in MMC register and check errors + * + * @note in/out parameters should be checked by a caller function + * + * @param dev MMC device + * @param reg register offset relative to the base address + * @param flag polling flag(s) + * @param state state of flag(s) when we should stop polling + * @param check_errors call @ref rcar_mmc_check_errors function or not + * @param check_dma_errors check if there are DMA errors inside info2 + * @param timeout_us timeout in microseconds how long we should poll flag(s) + * + * @retval 0 poll of flag(s) was successful + * @retval -ETIMEDOUT: timed out while tx/rx + * @retval -EIO: I/O error + * @retval -EILSEQ: communication out of sync + */ +static int rcar_mmc_poll_reg_flags_check_err(const struct device *dev, unsigned int reg, + uint32_t flag, uint32_t state, bool check_errors, + bool check_dma_errors, int64_t timeout_us) +{ + int ret; + + while ((rcar_mmc_read_reg32(dev, reg) & flag) != state) { + if (timeout_us < 0) { + LOG_DBG("timeout error during polling flag(s) 0x%08x in reg 0x%08x", flag, + reg); + return -ETIMEDOUT; + } + + if (check_errors) { + ret = rcar_mmc_check_errors(dev); + if (ret) { + return ret; + } + } + + if (check_dma_errors && rcar_mmc_read_reg32(dev, RCAR_MMC_DMA_INFO2)) { + LOG_DBG("%s: an error occurs on the DMAC channel #%u", dev->name, + (reg & RCAR_MMC_DMA_INFO2_ERR_RD) ? 1U : 0U); + return -EIO; + } + + k_usleep(MMC_POLL_FLAGS_ONE_CYCLE_TIMEOUT_US); + timeout_us -= MMC_POLL_FLAGS_ONE_CYCLE_TIMEOUT_US; + } + + return 0; +} + +/* reset DMA MMC controller */ +static inline void rcar_mmc_reset_dma(const struct device *dev) +{ + uint32_t reg = RCAR_MMC_DMA_RST_DTRAN0 | RCAR_MMC_DMA_RST_DTRAN1; + + rcar_mmc_write_reg32(dev, RCAR_MMC_EXTMODE, 0); + rcar_mmc_write_reg32(dev, RCAR_MMC_DMA_RST, ~reg); + rcar_mmc_write_reg32(dev, RCAR_MMC_DMA_RST, ~0); + rcar_mmc_write_reg32(dev, RCAR_MMC_EXTMODE, 1); +} + +/** + * @brief reset MMC controller state + * + * Used when the MMC has encountered an error. Resetting the MMC controller + * should clear all errors on the MMC, but does not necessarily reset I/O + * settings to boot (this can be done with @ref sdhc_set_io) + * + * @note during reset the clock input is disabled, also this call changes rate + * + * @param dev MMC controller device + * @retval 0 reset succeeded + * @retval -ETIMEDOUT: controller reset timed out + * @retval -EINVAL: the dev pointer is NULL + * @retval -EILSEQ: communication out of sync + * @retval -ENOTSUP: controller does not support I/O + * + * @details List of affected registers and their bits during the soft reset trigger: + * * RCAR_MMC_STOP all bits reset to default (0x0); + * * RCAR_MMC_INFO1 affected bits: + * * RCAR_MMC_INFO1_CMP default state 0; + * * RCAR_MMC_INFO1_RSP default state 0; + * * HPIRES Response Reception Completion (16), default state 0; + * * RCAR_MMC_INFO2 all bits reset 0, except the next: + * * RCAR_MMC_INFO2_DAT0 state unknown after reset; + * * RCAR_MMC_INFO2_SCLKDIVEN default state 1; + * * RCAR_MMC_CLKCTL affected bit(s): + * * RCAR_MMC_CLKCTL_SCLKEN default state 0; + * * RCAR_MMC_OPTION affected bits: + * * WIDTH (15) and WIDTH8 (13) set to 0, which equal to 4-bits bus; + * * Timeout Mode Select (EXTOP - 9) is set to 0; + * * Timeout Mask (TOUTMASK - 8) is set to 0; + * * Timeout Counter (TOP27-TOP24 bits 7-4) is equal to 0b1110; + * * Card Detect Time Counter (CTOP24-CTOP21 bits 3-0) is equal to 0b1110; + * * RCAR_MMC_ERR_STS1 all bits after reset 0, except the next: + * * E13 default state 1 (E12-E14 it is CRC status 0b010); + * * RCAR_MMC_ERR_STS2 all bits after reset 0; + * * IO_INFO1 all bits after reset 0; + * * RCAR_MMC_IF_MODE all bits after reset 0. + */ +static int rcar_mmc_reset(const struct device *dev) +{ + int ret = 0; + uint32_t reg; + struct mmc_rcar_data *data; + uint8_t can_retune; + + if (!dev) { + return -EINVAL; + } + + data = dev->data; + + /* + * soft reset of the host + */ + reg = rcar_mmc_read_reg32(dev, RCAR_MMC_SOFT_RST); + reg &= ~RCAR_MMC_SOFT_RST_RSTX; + rcar_mmc_write_reg32(dev, RCAR_MMC_SOFT_RST, reg); + reg |= RCAR_MMC_SOFT_RST_RSTX; + rcar_mmc_write_reg32(dev, RCAR_MMC_SOFT_RST, reg); + + rcar_mmc_reset_and_mask_irqs(dev); + + /* + * note: DMA reset can be triggered only in case of error in + * DMA Info2 otherwise the SDIP will not accurately operate + */ +#ifdef CONFIG_RCAR_MMC_DMA_SUPPORT + rcar_mmc_reset_dma(dev); +#endif + + can_retune = data->can_retune; + if (can_retune) { + rcar_mmc_disable_scc(dev); + } + + /* note: be careful soft reset stops SDCLK */ + if (data->restore_cfg_after_reset) { + struct sdhc_io ios; + + memcpy(&ios, &data->host_io, sizeof(ios)); + memset(&data->host_io, 0, sizeof(ios)); + + data->host_io.power_mode = ios.power_mode; + + ret = sdhc_set_io(dev, &ios); + + rcar_mmc_write_reg32(dev, RCAR_MMC_STOP, RCAR_MMC_STOP_SEC); + +#ifdef CONFIG_RCAR_MMC_SCC_SUPPORT + /* tune if this reset isn't invoked during tuning */ + if (can_retune && (ios.timing == SDHC_TIMING_SDR50 || + ios.timing == SDHC_TIMING_SDR104 || + ios.timing == SDHC_TIMING_HS200)) { + ret = rcar_mmc_execute_tuning(dev); + } +#endif + + return ret; + } + + data->ddr_mode = 0; + data->host_io.bus_width = SDHC_BUS_WIDTH4BIT; + data->host_io.timing = SDHC_TIMING_LEGACY; + data->is_last_cmd_app_cmd = 0; + + return 0; +} + +/** + * @brief SD Clock (SD_CLK) Output Control Enable + * + * @note in/out parameters should be checked by a caller function. + * + * @param dev MMC device + * @param enable + * false: SD_CLK output is disabled. The SD_CLK signal is fixed 0. + * true: SD_CLK output is enabled. + * + * @retval 0 I/O was configured correctly + * @retval -ETIMEDOUT: card busy flag is set during long time + */ +static int rcar_mmc_enable_clock(const struct device *dev, bool enable) +{ + int ret; + uint32_t mmc_clk_ctl = rcar_mmc_read_reg32(dev, RCAR_MMC_CLKCTL); + + if (enable == true) { + mmc_clk_ctl &= ~RCAR_MMC_CLKCTL_OFFEN; + mmc_clk_ctl |= RCAR_MMC_CLKCTL_SCLKEN; + } else { + mmc_clk_ctl |= RCAR_MMC_CLKCTL_OFFEN; + mmc_clk_ctl &= ~RCAR_MMC_CLKCTL_SCLKEN; + } + + /* + * Do not change the values of these bits + * when the CBSY bit in SD_INFO2 is 1 + */ + ret = rcar_mmc_poll_reg_flags_check_err(dev, RCAR_MMC_INFO2, RCAR_MMC_INFO2_CBSY, 0, false, + false, MMC_POLL_FLAGS_TIMEOUT_US); + if (ret) { + return -ETIMEDOUT; + } + rcar_mmc_write_reg32(dev, RCAR_MMC_CLKCTL, mmc_clk_ctl); + + /* SD spec recommends at least 1 ms of delay */ + k_msleep(1); + + return 0; +} + +/** + * @brief Convert SDHC response to Renesas MMC response + * + * Function performs a conversion from SDHC response to Renesas MMC + * CMD register response. + * + * @note in/out parameters should be checked by a caller function. + * + * @param response_type SDHC response type without SPI flags + * + * @retval positiv number (partial configuration of CMD register) on + * success, negative errno code otherwise + */ +static int32_t rcar_mmc_convert_sd_to_mmc_resp(uint32_t response_type) +{ + uint32_t mmc_resp = 0U; + + switch (response_type) { + case SD_RSP_TYPE_NONE: + mmc_resp = RCAR_MMC_CMD_RSP_NONE; + break; + case SD_RSP_TYPE_R1: + case SD_RSP_TYPE_R5: + case SD_RSP_TYPE_R6: + case SD_RSP_TYPE_R7: + mmc_resp = RCAR_MMC_CMD_RSP_R1; + break; + case SD_RSP_TYPE_R1b: + case SD_RSP_TYPE_R5b: + mmc_resp = RCAR_MMC_CMD_RSP_R1B; + break; + case SD_RSP_TYPE_R2: + mmc_resp = RCAR_MMC_CMD_RSP_R2; + break; + case SD_RSP_TYPE_R3: + case SD_RSP_TYPE_R4: + mmc_resp = RCAR_MMC_CMD_RSP_R3; + break; + default: + LOG_ERR("unknown response type 0x%08x", response_type); + return -EINVAL; + } + + __ASSERT((int32_t)mmc_resp >= 0, "%s: converted response shouldn't be negative", __func__); + + return mmc_resp; +} + +/** + * @brief Convert response from Renesas MMC to SDHC + * + * Function writes a response to response array of @ref sdhc_command structure + * + * @note in/out parameters should be checked by a caller function. + * + * @param dev MMC device + * @param cmd MMC command + * @param response_type SDHC response type without SPI flags + * + * @retval none + */ +static void rcar_mmc_extract_resp(const struct device *dev, struct sdhc_command *cmd, + uint32_t response_type) +{ + if (response_type == SD_RSP_TYPE_R2) { + uint32_t rsp_127_104 = rcar_mmc_read_reg32(dev, RCAR_MMC_RSP76); + uint32_t rsp_103_72 = rcar_mmc_read_reg32(dev, RCAR_MMC_RSP54); + uint32_t rsp_71_40 = rcar_mmc_read_reg32(dev, RCAR_MMC_RSP32); + uint32_t rsp_39_8 = rcar_mmc_read_reg32(dev, RCAR_MMC_RSP10); + + cmd->response[0] = (rsp_39_8 & 0xffffff) << 8; + cmd->response[1] = + ((rsp_71_40 & 0x00ffffff) << 8) | ((rsp_39_8 & 0xff000000) >> 24); + cmd->response[2] = + ((rsp_103_72 & 0x00ffffff) << 8) | ((rsp_71_40 & 0xff000000) >> 24); + cmd->response[3] = + ((rsp_127_104 & 0x00ffffff) << 8) | ((rsp_103_72 & 0xff000000) >> 24); + + LOG_DBG("Response 2\n\t[0]: 0x%08x\n\t[1]: 0x%08x" + "\n\t[2]: 0x%08x\n\t[3]: 0x%08x", + cmd->response[0], cmd->response[1], cmd->response[2], cmd->response[3]); + } else { + cmd->response[0] = rcar_mmc_read_reg32(dev, RCAR_MMC_RSP10); + LOG_DBG("Response %u\n\t[0]: 0x%08x", response_type, cmd->response[0]); + } +} + +/* configure CMD register for tx/rx data */ +static uint32_t rcar_mmc_gen_data_cmd(struct sdhc_command *cmd, struct sdhc_data *data) +{ + uint32_t cmd_reg = RCAR_MMC_CMD_DATA; + + switch (cmd->opcode) { + case MMC_SEND_EXT_CSD: + case SD_READ_SINGLE_BLOCK: + case MMC_SEND_TUNING_BLOCK: + case SD_SEND_TUNING_BLOCK: + case SD_SWITCH: + case SD_APP_SEND_NUM_WRITTEN_BLK: + case SD_APP_SEND_SCR: + cmd_reg |= RCAR_MMC_CMD_RD; + break; + case SD_READ_MULTIPLE_BLOCK: + cmd_reg |= RCAR_MMC_CMD_RD; + cmd_reg |= RCAR_MMC_CMD_MULTI; + break; + case SD_WRITE_MULTIPLE_BLOCK: + cmd_reg |= RCAR_MMC_CMD_MULTI; + break; + case SD_WRITE_SINGLE_BLOCK: + /* fall through */ + default: + break; + } + + if (data->blocks > 1) { + cmd_reg |= RCAR_MMC_CMD_MULTI; + } + + return cmd_reg; +} + +/** + * @brief Transmit/Receive data to/from MMC using DMA + * + * Sends/Receives data to/from the MMC controller. + * + * @note in/out parameters should be checked by a caller function. + * + * @param dev MMC device + * @param data MMC data buffer for tx/rx + * @param is_read it is read or write operation + * + * @retval 0 tx/rx was successful + * @retval -ENOTSUP: cache flush/invalidate aren't supported + * @retval -ETIMEDOUT: timed out while tx/rx + * @retval -EIO: I/O error + * @retval -EILSEQ: communication out of sync + */ +static int rcar_mmc_dma_rx_tx_data(const struct device *dev, struct sdhc_data *data, bool is_read) +{ + uintptr_t dma_addr; + uint32_t reg; + int ret = 0; + uint32_t dma_info1_poll_flag; +#ifdef CONFIG_RCAR_MMC_DMA_IRQ_DRIVEN_SUPPORT + struct mmc_rcar_data *dev_data = dev->data; +#endif + + ret = sys_cache_data_flush_range(data->data, data->blocks * data->block_size); + if (ret < 0) { + LOG_ERR("%s: can't invalidate data cache before write", dev->name); + return ret; + } + + reg = rcar_mmc_read_reg32(dev, RCAR_MMC_DMA_MODE); + if (is_read) { + dma_info1_poll_flag = RCAR_MMC_DMA_INFO1_END_RD2; + reg |= RCAR_MMC_DMA_MODE_DIR_RD; + } else { + dma_info1_poll_flag = RCAR_MMC_DMA_INFO1_END_WR; + reg &= ~RCAR_MMC_DMA_MODE_DIR_RD; + } + rcar_mmc_write_reg32(dev, RCAR_MMC_DMA_MODE, reg); + + reg = rcar_mmc_read_reg32(dev, RCAR_MMC_EXTMODE); + reg |= RCAR_MMC_EXTMODE_DMA_EN; + rcar_mmc_write_reg32(dev, RCAR_MMC_EXTMODE, reg); + + dma_addr = z_mem_phys_addr(data->data); + + rcar_mmc_write_reg32(dev, RCAR_MMC_DMA_ADDR_L, dma_addr); + rcar_mmc_write_reg32(dev, RCAR_MMC_DMA_ADDR_H, 0); + +#ifdef CONFIG_RCAR_MMC_DMA_IRQ_DRIVEN_SUPPORT + rcar_mmc_write_reg32( + dev, RCAR_MMC_DMA_INFO2_MASK, + (uint32_t)(is_read ? (~RCAR_MMC_DMA_INFO2_ERR_RD) : (~RCAR_MMC_DMA_INFO2_ERR_WR))); + + reg = rcar_mmc_read_reg32(dev, RCAR_MMC_DMA_INFO1_MASK); + reg &= ~dma_info1_poll_flag; + rcar_mmc_write_reg32(dev, RCAR_MMC_DMA_INFO1_MASK, reg); + rcar_mmc_write_reg32(dev, RCAR_MMC_DMA_CTL, RCAR_MMC_DMA_CTL_START); + + ret = k_sem_take(&dev_data->irq_xref_fin, K_MSEC(data->timeout_ms)); + if (ret < 0) { + LOG_ERR("%s: interrupt signal timeout error %d", dev->name, ret); + } + + reg = rcar_mmc_read_reg32(dev, RCAR_MMC_DMA_INFO2); + if (reg) { + LOG_ERR("%s: an error occurs on the DMAC channel #%u", dev->name, + (reg & RCAR_MMC_DMA_INFO2_ERR_RD) ? 1U : 0U); + ret = -EIO; + } +#else + rcar_mmc_write_reg32(dev, RCAR_MMC_DMA_CTL, RCAR_MMC_DMA_CTL_START); + ret = rcar_mmc_poll_reg_flags_check_err(dev, RCAR_MMC_DMA_INFO1, dma_info1_poll_flag, + dma_info1_poll_flag, false, true, + data->timeout_ms * 1000LL); +#endif + + if (is_read) { + if (sys_cache_data_invd_range(data->data, data->blocks * data->block_size) < 0) { + LOG_ERR("%s: can't invalidate data cache after read", dev->name); + } + } + + /* in case when we get to here and there wasn't IRQ trigger */ + rcar_mmc_write_reg32(dev, RCAR_MMC_DMA_INFO1_MASK, 0xfffffeff); + rcar_mmc_write_reg32(dev, RCAR_MMC_DMA_INFO2_MASK, ~0); + + if (ret == -EIO) { + rcar_mmc_reset_dma(dev); + } + + reg = rcar_mmc_read_reg32(dev, RCAR_MMC_EXTMODE); + reg &= ~RCAR_MMC_EXTMODE_DMA_EN; + rcar_mmc_write_reg32(dev, RCAR_MMC_EXTMODE, reg); + + return ret; +} + +/* read from SD/MMC controller buf0 register */ +static inline uint64_t rcar_mmc_read_buf0(const struct device *dev) +{ + uint64_t buf0 = 0ULL; + struct mmc_rcar_data *dev_data = dev->data; + uint8_t sd_buf0_size = dev_data->width_access_sd_buf0; + mm_reg_t buf0_addr = DEVICE_MMIO_GET(dev) + RCAR_MMC_BUF0; + + switch (sd_buf0_size) { + case 8: + buf0 = sys_read64(buf0_addr); + break; + case 4: + buf0 = sys_read32(buf0_addr); + break; + case 2: + buf0 = sys_read16(buf0_addr); + break; + default: + k_panic(); + break; + } + + return buf0; +} + +/* write to SD/MMC controller buf0 register */ +static inline void rcar_mmc_write_buf0(const struct device *dev, uint64_t val) +{ + struct mmc_rcar_data *dev_data = dev->data; + uint8_t sd_buf0_size = dev_data->width_access_sd_buf0; + mm_reg_t buf0_addr = DEVICE_MMIO_GET(dev) + RCAR_MMC_BUF0; + + switch (sd_buf0_size) { + case 8: + sys_write64(val, buf0_addr); + break; + case 4: + sys_write32(val, buf0_addr); + break; + case 2: + sys_write16(val, buf0_addr); + break; + default: + k_panic(); + break; + } +} + +/** + * @brief Transmit/Receive data to/from MMC without DMA + * + * Sends/Receives data to/from the MMC controller. + * + * @note in/out parameters should be checked by a caller function. + * + * @param dev MMC device + * @param data MMC data buffer for tx/rx + * @param is_read it is read or write operation + * + * @retval 0 tx/rx was successful + * @retval -EINVAL: invalid block size + * @retval -ETIMEDOUT: timed out while tx/rx + * @retval -EIO: I/O error + * @retval -EILSEQ: communication out of sync + */ +static int rcar_mmc_sd_buf_rx_tx_data(const struct device *dev, struct sdhc_data *data, + bool is_read) +{ + struct mmc_rcar_data *dev_data = dev->data; + uint32_t block; + int ret = 0; + uint32_t info2_poll_flag = is_read ? RCAR_MMC_INFO2_BRE : RCAR_MMC_INFO2_BWE; + uint8_t sd_buf0_size = dev_data->width_access_sd_buf0; + uint16_t aligned_block_size = ROUND_UP(data->block_size, sd_buf0_size); + uint32_t cmd_reg = 0; + int64_t remaining_timeout_us = data->timeout_ms * 1000LL; + + /* + * note: below code should work for all possible block sizes, but + * we need below check, because code isn't tested with smaller + * block sizes. + */ + if ((data->block_size % dev_data->width_access_sd_buf0) || + (data->block_size < dev_data->width_access_sd_buf0)) { + LOG_ERR("%s: block size (%u) less or not align on SD BUF0 access width (%hhu)", + dev->name, data->block_size, dev_data->width_access_sd_buf0); + return -EINVAL; + } + + /* + * JEDEC Standard No. 84-B51 + * 6.6.24 Dual Data Rate mode operation: + * Therefore, all single or multiple block data transfer read or write will operate on + * a fixed block size of 512 bytes while the Device remains in dual data rate. + * + * Physical Layer Specification Version 3.01 + * 4.12.6 Timing Changes in DDR50 Mode + * 4.12.6.2 Protocol Principles + * * Read and Write data block length size is always 512 bytes (same as SDHC). + */ + if (dev_data->ddr_mode && data->block_size != 512) { + LOG_ERR("%s: block size (%u) isn't equal to 512 in DDR mode", dev->name, + data->block_size); + return -EINVAL; + } + + /* + * note: the next restrictions we have according to description of + * transfer data length register from R-Car S4 series User's Manual + */ + if (data->block_size > 512 || data->block_size == 0) { + LOG_ERR("%s: block size (%u) must not be bigger than 512 bytes and equal to zero", + dev->name, data->block_size); + return -EINVAL; + } + + cmd_reg = rcar_mmc_read_reg32(dev, RCAR_MMC_CMD); + if (cmd_reg & RCAR_MMC_CMD_MULTI) { + /* CMD12 is automatically issued at multiple block transfer */ + if (!(cmd_reg & RCAR_MMC_CMD_NOSTOP) && data->block_size != 512) { + LOG_ERR("%s: illegal block size (%u) for multi-block xref with CMD12", + dev->name, data->block_size); + return -EINVAL; + } + + switch (data->block_size) { + case 32: + case 64: + case 128: + case 256: + case 512: + break; + default: + LOG_ERR("%s: illegal block size (%u) for multi-block xref without CMD12", + dev->name, data->block_size); + return -EINVAL; + } + } + + if (data->block_size == 1 && dev_data->host_io.bus_width == SDHC_BUS_WIDTH8BIT) { + LOG_ERR("%s: block size can't be equal to 1 with 8-bits bus width", dev->name); + return -EINVAL; + } + + for (block = 0; block < data->blocks; block++) { + uint8_t *buf = (uint8_t *)data->data + (block * data->block_size); + uint32_t info2_reg; + uint16_t w_off; /* word offset in a block */ + uint64_t start_block_xref_us = k_ticks_to_us_ceil64(k_uptime_ticks()); + + /* wait until the buffer is filled with data */ + ret = rcar_mmc_poll_reg_flags_check_err(dev, RCAR_MMC_INFO2, info2_poll_flag, + info2_poll_flag, true, false, + remaining_timeout_us); + if (ret) { + return ret; + } + + /* clear write/read buffer ready flag */ + info2_reg = rcar_mmc_read_reg32(dev, RCAR_MMC_INFO2); + info2_reg &= ~info2_poll_flag; + rcar_mmc_write_reg32(dev, RCAR_MMC_INFO2, info2_reg); + + for (w_off = 0; w_off < aligned_block_size; w_off += sd_buf0_size) { + uint64_t buf0 = 0ULL; + uint8_t copy_size = MIN(sd_buf0_size, data->block_size - w_off); + + if (is_read) { + buf0 = rcar_mmc_read_buf0(dev); + memcpy(buf + w_off, &buf0, copy_size); + } else { + memcpy(&buf0, buf + w_off, copy_size); + rcar_mmc_write_buf0(dev, buf0); + } + } + + remaining_timeout_us -= + k_ticks_to_us_ceil64(k_uptime_ticks()) - start_block_xref_us; + if (remaining_timeout_us < 0) { + return -ETIMEDOUT; + } + } + + return ret; +} + +/** + * @brief Transmit/Receive data to/from MMC + * + * Sends/Receives data to/from the MMC controller. + * + * @note in/out parameters should be checked by a caller function. + * + * @param dev MMC device + * @param data MMC data buffer for tx/rx + * @param is_read it is read or write operation + * + * @retval 0 tx/rx was successful + * @retval -EINVAL: invalid block size + * @retval -ETIMEDOUT: timed out while tx/rx + * @retval -EIO: I/O error + * @retval -EILSEQ: communication out of sync + */ +static int rcar_mmc_rx_tx_data(const struct device *dev, struct sdhc_data *data, bool is_read) +{ + uint32_t info1_reg; + int ret = 0; + +#ifdef CONFIG_RCAR_MMC_DMA_SUPPORT + if (!(z_mem_phys_addr(data->data) >> 32)) { + ret = rcar_mmc_dma_rx_tx_data(dev, data, is_read); + } else +#endif + { + ret = rcar_mmc_sd_buf_rx_tx_data(dev, data, is_read); + } + + if (ret < 0) { + return ret; + } + + ret = rcar_mmc_poll_reg_flags_check_err(dev, RCAR_MMC_INFO1, RCAR_MMC_INFO1_CMP, + RCAR_MMC_INFO1_CMP, true, false, + MMC_POLL_FLAGS_TIMEOUT_US); + if (ret) { + return ret; + } + + /* clear access end flag */ + info1_reg = rcar_mmc_read_reg32(dev, RCAR_MMC_INFO1); + info1_reg &= ~RCAR_MMC_INFO1_CMP; + rcar_mmc_write_reg32(dev, RCAR_MMC_INFO1, info1_reg); + + return ret; +} + +/** + * @brief Send command to MMC + * + * Sends a command to the MMC controller. + * + * @param dev MMC device + * @param cmd MMC command + * @param data MMC data. Leave NULL to send SD command without data. + * + * @retval 0 command was sent successfully + * @retval -ETIMEDOUT: command timed out while sending + * @retval -ENOTSUP: host controller does not support command + * @retval -EIO: I/O error + * @retval -EILSEQ: communication out of sync + */ +static int rcar_mmc_request(const struct device *dev, struct sdhc_command *cmd, + struct sdhc_data *data) +{ + int ret = -ENOTSUP; + uint32_t reg; + uint32_t response_type; + bool is_read = true; + int attempts; + struct mmc_rcar_data *dev_data; + + if (!dev || !cmd) { + return -EINVAL; + } + + dev_data = dev->data; + response_type = cmd->response_type & SDHC_NATIVE_RESPONSE_MASK; + attempts = cmd->retries + 1; + + while (ret && attempts-- > 0) { + if (ret != -ENOTSUP) { + rcar_mmc_reset(dev); +#ifdef CONFIG_RCAR_MMC_SCC_SUPPORT + rcar_mmc_retune_if_needed(dev, true); +#endif + } + + ret = rcar_mmc_poll_reg_flags_check_err(dev, RCAR_MMC_INFO2, RCAR_MMC_INFO2_CBSY, 0, + false, false, MMC_POLL_FLAGS_TIMEOUT_US); + if (ret) { + ret = -EBUSY; + continue; + } + + rcar_mmc_reset_and_mask_irqs(dev); + + rcar_mmc_write_reg32(dev, RCAR_MMC_ARG, cmd->arg); + + reg = cmd->opcode; + + if (data) { + rcar_mmc_write_reg32(dev, RCAR_MMC_SIZE, data->block_size); + rcar_mmc_write_reg32(dev, RCAR_MMC_SECCNT, data->blocks); + reg |= rcar_mmc_gen_data_cmd(cmd, data); + is_read = (reg & RCAR_MMC_CMD_RD) ? true : false; + } + + /* CMD55 is always sended before ACMD */ + if (dev_data->is_last_cmd_app_cmd) { + reg |= RCAR_MMC_CMD_APP; + } + + ret = rcar_mmc_convert_sd_to_mmc_resp(response_type); + if (ret < 0) { + /* don't need to retry we will always have the same result */ + return -EINVAL; + } + + reg |= ret; + + LOG_DBG("(SD_CMD=%08x, SD_ARG=%08x)", cmd->opcode, cmd->arg); + rcar_mmc_write_reg32(dev, RCAR_MMC_CMD, reg); + + /* wait until response end flag is set or errors occur */ + ret = rcar_mmc_poll_reg_flags_check_err(dev, RCAR_MMC_INFO1, RCAR_MMC_INFO1_RSP, + RCAR_MMC_INFO1_RSP, true, false, + cmd->timeout_ms * 1000LL); + if (ret) { + continue; + } + + /* clear response end flag */ + reg = rcar_mmc_read_reg32(dev, RCAR_MMC_INFO1); + reg &= ~RCAR_MMC_INFO1_RSP; + rcar_mmc_write_reg32(dev, RCAR_MMC_INFO1, reg); + + rcar_mmc_extract_resp(dev, cmd, response_type); + + if (data) { + ret = rcar_mmc_rx_tx_data(dev, data, is_read); + if (ret) { + continue; + } + } + + /* wait until the SD bus (CMD, DAT) is free or errors occur */ + ret = rcar_mmc_poll_reg_flags_check_err( + dev, RCAR_MMC_INFO2, RCAR_MMC_INFO2_SCLKDIVEN, RCAR_MMC_INFO2_SCLKDIVEN, + true, false, MMC_POLL_FLAGS_TIMEOUT_US); + } + + if (ret) { + rcar_mmc_reset(dev); +#ifdef CONFIG_RCAR_MMC_SCC_SUPPORT + rcar_mmc_retune_if_needed(dev, true); +#endif + } + + dev_data->is_last_cmd_app_cmd = (cmd->opcode == SD_APP_CMD); + + return ret; +} + +/* convert sd_voltage to string */ +static inline const char *const rcar_mmc_get_signal_voltage_str(enum sd_voltage voltage) +{ + static const char *const sig_vol_str[] = { + [0] = "Unset", [SD_VOL_3_3_V] = "3.3V", [SD_VOL_3_0_V] = "3.0V", + [SD_VOL_1_8_V] = "1.8V", [SD_VOL_1_2_V] = "1.2V", + }; + + if (voltage >= 0 && voltage < ARRAY_SIZE(sig_vol_str)) { + return sig_vol_str[voltage]; + } else { + return "Unknown"; + } +} + +/* convert sdhc_timing_mode to string */ +static inline const char *const rcar_mmc_get_timing_str(enum sdhc_timing_mode timing) +{ + static const char *const timing_str[] = { + [0] = "Unset", + [SDHC_TIMING_LEGACY] = "LEGACY", + [SDHC_TIMING_HS] = "HS", + [SDHC_TIMING_SDR12] = "SDR12", + [SDHC_TIMING_SDR25] = "SDR25", + [SDHC_TIMING_SDR50] = "SDR50", + [SDHC_TIMING_SDR104] = "SDR104", + [SDHC_TIMING_DDR50] = "DDR50", + [SDHC_TIMING_DDR52] = "DDR52", + [SDHC_TIMING_HS200] = "HS200", + [SDHC_TIMING_HS400] = "HS400", + }; + + if (timing >= 0 && timing < ARRAY_SIZE(timing_str)) { + return timing_str[timing]; + } else { + return "Unknown"; + } +} + +/* change voltage of MMC */ +static int rcar_mmc_change_voltage(const struct mmc_rcar_cfg *cfg, struct sdhc_io *host_io, + struct sdhc_io *ios) +{ + int ret = 0; + + /* Set host signal voltage */ + if (!ios->signal_voltage || ios->signal_voltage == host_io->signal_voltage) { + return 0; + } + + switch (ios->signal_voltage) { + case SD_VOL_3_3_V: + ret = regulator_set_voltage(cfg->regulator_vqmmc, 3300000, 3300000); + if (ret && ret != -ENOSYS) { + break; + } + + ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT); + break; + case SD_VOL_1_8_V: + ret = regulator_set_voltage(cfg->regulator_vqmmc, 1800000, 1800000); + if (ret && ret != -ENOSYS) { + break; + } + + ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_UHS); + break; + case SD_VOL_3_0_V: + case SD_VOL_1_2_V: + /* fall through */ + default: + ret = -ENOTSUP; + return ret; + } + + if (!ret) { + host_io->signal_voltage = ios->signal_voltage; + } + + return ret; +} + +/* note: for zero val function returns zero */ +static inline uint32_t round_up_next_pwr_of_2(uint32_t val) +{ + __ASSERT(val, "Zero val passed to %s", __func__); + + val--; + val |= val >> 1; + val |= val >> 2; + val |= val >> 4; + val |= val >> 8; + val |= val >> 16; + return ++val; +} + +/** + * @brief configure clock divider on MMC controller + * + * @note In/out parameters should be checked by a caller function. + * @note In the case of data transfer in HS400 mode (HS400 bit in + * SDIF_MODE = 1), do not set this width equal to 1. + * @note In the case of writing of one-byte block, 8-bit width cannot + * be specified for the bus width. Change the bus width to 4 bits + * or 1 bit before writing one-byte block. + * + * @param dev MMC device + * @param io I/O properties + * + * @retval 0 I/O was configured correctly + * @retval -ENOTSUP: controller does not support these I/O settings + * @retval -ETIMEDOUT: card busy flag is set during long time + */ +static int rcar_mmc_set_clk_rate(const struct device *dev, struct sdhc_io *ios) +{ + int ret = 0; + uint32_t divisor; + uint32_t mmc_clk_ctl; + struct mmc_rcar_data *data = dev->data; + const struct mmc_rcar_cfg *cfg = dev->config; + struct sdhc_io *host_io = &data->host_io; + + if (host_io->clock == ios->clock) { + return 0; + } + + if (ios->clock == 0) { + host_io->clock = 0; + return rcar_mmc_enable_clock(dev, false); + } + + if (ios->clock > data->props.f_max || ios->clock < data->props.f_min) { + LOG_ERR("SDHC I/O: clock (%d) isn't in range %d - %d Hz", ios->clock, + data->props.f_min, data->props.f_max); + return -EINVAL; + } + + divisor = DIV_ROUND_UP(cfg->max_frequency, ios->clock); + + /* Do not set divider to 0xff in DDR mode */ + if (data->ddr_mode && (divisor == 1)) { + divisor = 2; + } + + divisor = round_up_next_pwr_of_2(divisor); + if (divisor == 1) { + divisor = RCAR_MMC_CLKCTL_RCAR_DIV1; + } else { + divisor >>= 2; + } + + /* + * Stop the clock before changing its rate + * to avoid a glitch signal + */ + ret = rcar_mmc_enable_clock(dev, false); + if (ret) { + return ret; + } + + mmc_clk_ctl = rcar_mmc_read_reg32(dev, RCAR_MMC_CLKCTL); + if ((mmc_clk_ctl & RCAR_MMC_CLKCTL_SCLKEN) && + (mmc_clk_ctl & RCAR_MMC_CLKCTL_DIV_MASK) == divisor) { + host_io->clock = ios->clock; + return rcar_mmc_enable_clock(dev, false); + } + + /* + * Do not change the values of these bits + * when the CBSY bit in SD_INFO2 is 1 + */ + ret = rcar_mmc_poll_reg_flags_check_err(dev, RCAR_MMC_INFO2, RCAR_MMC_INFO2_CBSY, 0, false, + false, MMC_POLL_FLAGS_TIMEOUT_US); + if (ret) { + return -ETIMEDOUT; + } + + mmc_clk_ctl &= ~RCAR_MMC_CLKCTL_DIV_MASK; + mmc_clk_ctl |= divisor; + + rcar_mmc_write_reg32(dev, RCAR_MMC_CLKCTL, mmc_clk_ctl); + ret = rcar_mmc_enable_clock(dev, true); + if (ret) { + return ret; + } + + host_io->clock = ios->clock; + + LOG_DBG("%s: set clock rate to %d", dev->name, ios->clock); + + return 0; +} + +/** + * @brief set bus width of MMC + * + * @note In/out parameters should be checked by a caller function. + * @note In the case of data transfer in HS400 mode (HS400 bit in + * SDIF_MODE = 1), do not set this width equal to 1. + * @note In the case of writing of one-byte block, 8-bit width cannot + * be specified for the bus width. Change the bus width to 4 bits + * or 1 bit before writing one-byte block. + * + * @param dev MMC device + * @param io I/O properties + * + * @retval 0 I/O was configured correctly + * @retval -ENOTSUP: controller does not support these I/O settings + * @retval -ETIMEDOUT: card busy flag is set during long time + */ +static int rcar_mmc_set_bus_width(const struct device *dev, struct sdhc_io *ios) +{ + int ret = 0; + uint32_t mmc_option_reg; + uint32_t reg_width; + struct mmc_rcar_data *data = dev->data; + struct sdhc_io *host_io = &data->host_io; + + /* Set bus width */ + if (host_io->bus_width == ios->bus_width) { + return 0; + } + + if (!ios->bus_width) { + return 0; + } + + switch (ios->bus_width) { + case SDHC_BUS_WIDTH1BIT: + reg_width = RCAR_MMC_OPTION_WIDTH_1; + break; + case SDHC_BUS_WIDTH4BIT: + if (data->props.host_caps.bus_4_bit_support) { + reg_width = RCAR_MMC_OPTION_WIDTH_4; + } else { + LOG_ERR("SDHC I/O: 4-bits bus width isn't supported"); + return -ENOTSUP; + } + break; + case SDHC_BUS_WIDTH8BIT: + if (data->props.host_caps.bus_8_bit_support) { + reg_width = RCAR_MMC_OPTION_WIDTH_8; + } else { + LOG_ERR("SDHC I/O: 8-bits bus width isn't supported"); + return -ENOTSUP; + } + break; + default: + return -ENOTSUP; + } + + /* + * Do not change the values of these bits + * when the CBSY bit in SD_INFO2 is 1 + */ + ret = rcar_mmc_poll_reg_flags_check_err(dev, RCAR_MMC_INFO2, RCAR_MMC_INFO2_CBSY, 0, false, + false, MMC_POLL_FLAGS_TIMEOUT_US); + if (ret) { + return -ETIMEDOUT; + } + + mmc_option_reg = rcar_mmc_read_reg32(dev, RCAR_MMC_OPTION); + mmc_option_reg &= ~RCAR_MMC_OPTION_WIDTH_MASK; + mmc_option_reg |= reg_width; + rcar_mmc_write_reg32(dev, RCAR_MMC_OPTION, mmc_option_reg); + + host_io->bus_width = ios->bus_width; + + LOG_DBG("%s: set bus-width to %d", dev->name, host_io->bus_width); + return 0; +} + +/** + * set DDR mode on MMC controller according to value inside + * ddr_mode field from @ref mmc_rcar_data structure. + */ +static int rcar_mmc_set_ddr_mode(const struct device *dev) +{ + int ret = 0; + uint32_t if_mode_reg; + struct mmc_rcar_data *data = dev->data; + + /* + * Do not change the values of these bits + * when the CBSY bit in SD_INFO2 is 1 + */ + ret = rcar_mmc_poll_reg_flags_check_err(dev, RCAR_MMC_INFO2, RCAR_MMC_INFO2_CBSY, 0, false, + false, MMC_POLL_FLAGS_TIMEOUT_US); + if (ret) { + return -ETIMEDOUT; + } + + if_mode_reg = rcar_mmc_read_reg32(dev, RCAR_MMC_IF_MODE); + if (data->ddr_mode) { + /* HS400 mode (DDR mode) */ + if_mode_reg |= RCAR_MMC_IF_MODE_DDR; + } else { + /* Normal mode (default, high speed, or SDR) */ + if_mode_reg &= ~RCAR_MMC_IF_MODE_DDR; + } + rcar_mmc_write_reg32(dev, RCAR_MMC_IF_MODE, if_mode_reg); + + return 0; +} + +/** + * @brief set timing property of MMC + * + * For now function only can enable DDR mode and call the function for + * changing voltage. It is expectable that we change clock using another + * I/O option. + * @note In/out parameters should be checked by a caller function. + * + * @param dev MMC device + * @param io I/O properties + * + * @retval 0 I/O was configured correctly + * @retval -ENOTSUP: controller does not support these I/O settings + * @retval -ETIMEDOUT: card busy flag is set during long time + */ +static int rcar_mmc_set_timings(const struct device *dev, struct sdhc_io *ios) +{ + int ret; + struct mmc_rcar_data *data = dev->data; + struct sdhc_io *host_io = &data->host_io; + enum sd_voltage new_voltage = host_io->signal_voltage; + + if (host_io->timing == ios->timing) { + return 0; + } + + if (!host_io->timing) { + return 0; + } + + data->ddr_mode = 0; + + switch (ios->timing) { + case SDHC_TIMING_LEGACY: + break; + case SDHC_TIMING_HS: + if (!data->props.host_caps.high_spd_support) { + LOG_ERR("SDHC I/O: HS timing isn't supported"); + return -ENOTSUP; + } + break; + case SDHC_TIMING_SDR12: + case SDHC_TIMING_SDR25: + case SDHC_TIMING_SDR50: + break; + case SDHC_TIMING_SDR104: + if (!data->props.host_caps.sdr104_support) { + LOG_ERR("SDHC I/O: SDR104 timing isn't supported"); + return -ENOTSUP; + } + break; + case SDHC_TIMING_HS400: + if (!data->props.host_caps.hs400_support) { + LOG_ERR("SDHC I/O: HS400 timing isn't supported"); + return -ENOTSUP; + } + new_voltage = SD_VOL_1_8_V; + data->ddr_mode = 1; + break; + case SDHC_TIMING_DDR50: + case SDHC_TIMING_DDR52: + if (!data->props.host_caps.ddr50_support) { + LOG_ERR("SDHC I/O: DDR50/DDR52 timing isn't supported"); + return -ENOTSUP; + } + data->ddr_mode = 1; + break; + case SDHC_TIMING_HS200: + if (!data->props.host_caps.hs200_support) { + LOG_ERR("SDHC I/O: HS200 timing isn't supported"); + return -ENOTSUP; + } + new_voltage = SD_VOL_1_8_V; + break; + default: + return -ENOTSUP; + } + + ios->signal_voltage = new_voltage; + if (rcar_mmc_change_voltage(dev->config, host_io, ios)) { + return -ENOTSUP; + } + + ret = rcar_mmc_set_ddr_mode(dev); + if (ret) { + return ret; + } + + host_io->timing = ios->timing; + return 0; +} + +/** + * @brief set I/O properties of MMC + * + * I/O properties should be reconfigured when the card has been sent a command + * to change its own MMC settings. This function can also be used to toggle + * power to the SD card. + * + * @param dev MMC device + * @param io I/O properties + * + * @retval 0 I/O was configured correctly + * @retval -ENOTSUP: controller does not support these I/O settings + * @retval -EINVAL: some of pointers provided to the function are NULL + * @retval -ETIMEDOUT: card busy flag is set during long time + */ +static int rcar_mmc_set_io(const struct device *dev, struct sdhc_io *ios) +{ + int ret = 0; + struct mmc_rcar_data *data; + struct sdhc_io *host_io; + + if (!dev || !ios || !dev->data || !dev->config) { + return -EINVAL; + } + + data = dev->data; + host_io = &data->host_io; + + LOG_DBG("SDHC I/O: bus width %d, clock %dHz, card power %s, " + "timing %s, voltage %s", + ios->bus_width, ios->clock, ios->power_mode == SDHC_POWER_ON ? "ON" : "OFF", + rcar_mmc_get_timing_str(ios->timing), + rcar_mmc_get_signal_voltage_str(ios->signal_voltage)); + + /* Set host clock */ + ret = rcar_mmc_set_clk_rate(dev, ios); + if (ret) { + LOG_ERR("SDHC I/O: can't change clock rate error %d old %d new %d", ret, + host_io->clock, ios->clock); + return ret; + } + + /* + * Set card bus mode + * + * SD Specifications Part 1 Physical Layer Simplified Specification Version 9.00 + * 4.7.1 Command Types: "... there is no Open Drain mode in SD Memory Card" + * + * The use of open-drain mode is not possible in SD memory cards because the SD bus uses + * push-pull signaling, where both the host and the card can actively drive the data lines + * high or low. + * In an SD card, the command and response signaling needs to be bidirectional, and each + * signal line needs to be actively driven high or low. The use of open-drain mode in this + * scenario would not allow for the necessary bidirectional signaling and could result in + * communication errors. + * + * JEDEC Standard No. 84-B51, 10 The eMMC bus: + * "The eā€¢MMC bus has eleven communication lines: + * - CMD: Command is a bidirectional signal. The host and Device drivers are operating in + * two modes, open drain and push/pull. + * - DAT0-7: Data lines are bidirectional signals. Host and Device drivers are operating + * in push-pull mode. + * - CLK: Clock is a host to Device signal. CLK operates in push-pull mode. + * - Data Strobe: Data Strobe is a Device to host signal. Data Strobe operates in + * push-pull mode." + * + * So, open-drain mode signaling is supported in eMMC as one of the signaling modes for + * the CMD line. But Gen3 and Gen4 boards has MMC/SD controller which is a specialized + * component designed specifically for managing communication with MMC/SD devices. It + * handles low-level operations such as protocol handling, data transfer, and error + * checking and should take care of the low-level details of communicating with the + * MMC/SD card, including setting the bus mode. Moreover, we can use only MMIO mode, the + * processor communicates with the MMC/SD controller through memory read and write + * operations, rather than through dedicated I/O instructions or specialized data transfer + * protocols like SPI or SDIO. Finally, R-Car Gen3 and Gen4 "Userā€™s manuals: Hardware" + * don't have direct configurations for open-drain mode for both PFC and GPIO and Zephyr + * SDHC subsystem doesn't support any bus mode except push-pull. + */ + if (ios->bus_mode != SDHC_BUSMODE_PUSHPULL) { + LOG_ERR("SDHC I/O: not supported bus mode %d", ios->bus_mode); + return -ENOTSUP; + } + host_io->bus_mode = ios->bus_mode; + + /* Set card power */ + if (ios->power_mode && host_io->power_mode != ios->power_mode) { + const struct mmc_rcar_cfg *cfg = dev->config; + + switch (ios->power_mode) { + case SDHC_POWER_ON: + ret = regulator_enable(cfg->regulator_vmmc); + if (ret) { + break; + } + + k_msleep(data->props.power_delay); + + ret = regulator_enable(cfg->regulator_vqmmc); + if (ret) { + break; + } + + k_msleep(data->props.power_delay); + ret = rcar_mmc_enable_clock(dev, true); + break; + case SDHC_POWER_OFF: + if (regulator_is_enabled(cfg->regulator_vqmmc)) { + ret = regulator_disable(cfg->regulator_vqmmc); + if (ret) { + break; + } + } + + if (regulator_is_enabled(cfg->regulator_vmmc)) { + ret = regulator_disable(cfg->regulator_vmmc); + if (ret) { + break; + } + } + + ret = rcar_mmc_enable_clock(dev, false); + break; + default: + LOG_ERR("SDHC I/O: not supported power mode %d", ios->power_mode); + return -ENOTSUP; + } + + if (ret) { + return ret; + } + host_io->power_mode = ios->power_mode; + } + + ret = rcar_mmc_set_bus_width(dev, ios); + if (ret) { + LOG_ERR("SDHC I/O: can't change bus width error %d old %d new %d", ret, + host_io->bus_width, ios->bus_width); + return ret; + } + + ret = rcar_mmc_set_timings(dev, ios); + if (ret) { + LOG_ERR("SDHC I/O: can't change timing error %d old %d new %d", ret, + host_io->timing, ios->timing); + return ret; + } + + ret = rcar_mmc_change_voltage(dev->config, host_io, ios); + if (ret) { + LOG_ERR("SDHC I/O: can't change voltage! error %d old %d new %d", ret, + host_io->signal_voltage, ios->signal_voltage); + return ret; + } + + return 0; +} + +/** + * @brief check for MMC card presence + * + * Checks if card is present on the bus. + * + * @param dev MMC device + * + * @retval 1 card is present + * @retval 0 card is not present + * @retval -EINVAL: some of pointers provided to the function are NULL + */ +static int rcar_mmc_get_card_present(const struct device *dev) +{ + const struct mmc_rcar_cfg *cfg; + + if (!dev || !dev->config) { + return -EINVAL; + } + + cfg = dev->config; + if (cfg->non_removable) { + return 1; + } + + return !!(rcar_mmc_read_reg32(dev, RCAR_MMC_INFO1) & RCAR_MMC_INFO1_CD); +} + +#ifdef CONFIG_RCAR_MMC_SCC_SUPPORT + +/* JESD84-B51, 6.6.5.1 Sampling Tuning Sequence for HS200 */ +static const uint8_t tun_block_8_bits_bus[] = { + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, + 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc, + 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff, + 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff, + 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd, + 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb, + 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff, + 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff, + 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, + 0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, + 0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, + 0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, + 0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, + 0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, + 0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, + 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, +}; + +/* + * In 4 bit mode the same pattern is used as shown above, + * but only first 4 bits least significant from every byte is used, examle: + * 8-bits pattern: 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00 ... + * f f 0 f f f 0 0 ... + * 4-bits pattern: 0xff 0x0f 0xff 0x00 ... + */ +static const uint8_t tun_block_4_bits_bus[] = { + 0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc, + 0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef, + 0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb, + 0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef, + 0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c, + 0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee, + 0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff, + 0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde, +}; + +#define RENESAS_TAPNUM 8 + +/** + * @brief run MMC tuning + * + * MMC cards require signal tuning for UHS modes SDR104, HS200 or HS400. + * This function allows an application to request the SD host controller + * to tune the card. + * + * @param dev MMC device + * + * @retval 0 tuning succeeded (card is ready for commands), otherwise negative number is returned + */ +static int rcar_mmc_execute_tuning(const struct device *dev) +{ + int ret = -ENOTSUP; + const uint8_t *tun_block_ptr; + uint8_t tap_idx; + uint8_t is_mmc_cmd = false; + struct sdhc_command cmd = {0}; + struct sdhc_data data = {0}; + struct mmc_rcar_data *dev_data; + uint16_t valid_taps = 0; + uint16_t smpcmp_bitmask = 0; + + BUILD_ASSERT(sizeof(valid_taps) * 8 >= 2 * RENESAS_TAPNUM); + BUILD_ASSERT(sizeof(smpcmp_bitmask) * 8 >= 2 * RENESAS_TAPNUM); + + if (!dev) { + return -EINVAL; + } + + dev_data = dev->data; + dev_data->can_retune = 0; + + if (dev_data->host_io.timing == SDHC_TIMING_HS200) { + cmd.opcode = MMC_SEND_TUNING_BLOCK; + is_mmc_cmd = true; + } else if (dev_data->host_io.timing != SDHC_TIMING_HS400) { + cmd.opcode = SD_SEND_TUNING_BLOCK; + } else { + LOG_ERR("%s: tuning isn't possible in HS400 mode, it should be done in HS200", + dev->name); + return -EINVAL; + } + + cmd.response_type = SD_RSP_TYPE_R1; + cmd.timeout_ms = CONFIG_SD_CMD_TIMEOUT; + + data.blocks = 1; + data.data = dev_data->tuning_buf; + data.timeout_ms = CONFIG_SD_DATA_TIMEOUT; + if (dev_data->host_io.bus_width == SDHC_BUS_WIDTH4BIT) { + data.block_size = sizeof(tun_block_4_bits_bus); + tun_block_ptr = tun_block_4_bits_bus; + } else if (dev_data->host_io.bus_width == SDHC_BUS_WIDTH8BIT) { + data.block_size = sizeof(tun_block_8_bits_bus); + tun_block_ptr = tun_block_8_bits_bus; + } else { + LOG_ERR("%s: don't support tuning for 1-bit bus width", dev->name); + return -EINVAL; + } + + ret = rcar_mmc_enable_clock(dev, false); + if (ret) { + return ret; + } + + /* enable modes SDR104/HS200/HS400 */ + rcar_mmc_write_reg32(dev, RENESAS_SDHI_SCC_DT2FF, 0x300); + /* SCC sampling clock operation is enabled */ + rcar_mmc_write_reg32(dev, RENESAS_SDHI_SCC_DTCNTL, + RENESAS_SDHI_SCC_DTCNTL_TAPEN | RENESAS_TAPNUM << 16); + /* SCC sampling clock is used */ + rcar_mmc_write_reg32(dev, RENESAS_SDHI_SCC_CKSEL, RENESAS_SDHI_SCC_CKSEL_DTSEL); + /* SCC sampling clock position correction is disabled */ + rcar_mmc_write_reg32(dev, RENESAS_SDHI_SCC_RVSCNTL, 0); + /* cleanup errors */ + rcar_mmc_write_reg32(dev, RENESAS_SDHI_SCC_RVSREQ, 0); + + ret = rcar_mmc_enable_clock(dev, true); + if (ret) { + return ret; + } + + /* + * two runs is better for detecting TAP ok cases like next: + * - one burn: 0b10000011 + * - two burns: 0b1000001110000011 + * it is more easly to detect 3 OK taps in a row + */ + for (tap_idx = 0; tap_idx < 2 * RENESAS_TAPNUM; tap_idx++) { + /* clear flags */ + rcar_mmc_reset_and_mask_irqs(dev); + rcar_mmc_write_reg32(dev, RENESAS_SDHI_SCC_TAPSET, tap_idx % RENESAS_TAPNUM); + memset(dev_data->tuning_buf, 0, data.block_size); + ret = rcar_mmc_request(dev, &cmd, &data); + if (ret) { + LOG_DBG("%s: received an error (%d) during tuning request", dev->name, ret); + + if (is_mmc_cmd) { + struct sdhc_command stop_cmd = { + .opcode = SD_STOP_TRANSMISSION, + .response_type = SD_RSP_TYPE_R1b, + .timeout_ms = CONFIG_SD_CMD_TIMEOUT, + }; + + rcar_mmc_request(dev, &stop_cmd, NULL); + } + continue; + } + + smpcmp_bitmask |= !rcar_mmc_read_reg32(dev, RENESAS_SDHI_SCC_SMPCMP) << tap_idx; + + if (memcmp(tun_block_ptr, dev_data->tuning_buf, data.block_size)) { + LOG_DBG("%s: received tuning block doesn't equal to pattert TAP index %u", + dev->name, tap_idx); + continue; + } + + valid_taps |= BIT(tap_idx); + + LOG_DBG("%s: smpcmp_bitmask[%u] 0x%08x", dev->name, tap_idx, smpcmp_bitmask); + } + + /* both parts of bitmasks have to be the same */ + valid_taps &= (valid_taps >> RENESAS_TAPNUM); + valid_taps |= (valid_taps << RENESAS_TAPNUM); + + smpcmp_bitmask &= (smpcmp_bitmask >> RENESAS_TAPNUM); + smpcmp_bitmask |= (smpcmp_bitmask << RENESAS_TAPNUM); + + rcar_mmc_write_reg32(dev, RENESAS_SDHI_SCC_RVSREQ, 0); + + if (!valid_taps) { + LOG_ERR("%s: there isn't any valid tap during tuning", dev->name); + goto reset_scc; + } + + /* + * If all of the taps[i] is OK, the sampling clock position is selected by identifying + * the change point of data. Change point of the data can be found in the value of + * SCC_SMPCMP register + */ + if ((valid_taps >> RENESAS_TAPNUM) == (1 << RENESAS_TAPNUM) - 1) { + valid_taps = smpcmp_bitmask; + } + + /* do we have 3 set bits in a row at least */ + if (valid_taps & (valid_taps >> 1) & (valid_taps >> 2)) { + uint32_t max_len_range_pos = 0; + uint32_t max_bits_in_range = 0; + uint32_t pos_of_lsb_set = 0; + + /* all bits are set */ + if ((valid_taps >> RENESAS_TAPNUM) == (1 << RENESAS_TAPNUM) - 1) { + rcar_mmc_write_reg32(dev, RENESAS_SDHI_SCC_TAPSET, 0); + + if (!dev_data->manual_retuning) { + rcar_mmc_write_reg32(dev, RENESAS_SDHI_SCC_RVSCNTL, 1); + } + dev_data->can_retune = 1; + return 0; + } + + /* searching the longest range of set bits */ + while (valid_taps) { + uint32_t num_bits_in_range; + uint32_t rsh = 0; + + rsh = find_lsb_set(valid_taps) - 1; + pos_of_lsb_set += rsh; + + /* shift all leading zeros */ + valid_taps >>= rsh; + + num_bits_in_range = find_lsb_set(~valid_taps) - 1; + + /* shift all leading ones */ + valid_taps >>= num_bits_in_range; + + if (max_bits_in_range < num_bits_in_range) { + max_bits_in_range = num_bits_in_range; + max_len_range_pos = pos_of_lsb_set; + } + pos_of_lsb_set += num_bits_in_range; + } + + tap_idx = (max_len_range_pos + max_bits_in_range / 2) % RENESAS_TAPNUM; + rcar_mmc_write_reg32(dev, RENESAS_SDHI_SCC_TAPSET, tap_idx); + + LOG_DBG("%s: valid_taps %08x smpcmp_bitmask %08x tap_idx %u", dev->name, valid_taps, + smpcmp_bitmask, tap_idx); + + if (!dev_data->manual_retuning) { + rcar_mmc_write_reg32(dev, RENESAS_SDHI_SCC_RVSCNTL, 1); + } + dev_data->can_retune = 1; + return 0; + } + +reset_scc: + rcar_mmc_disable_scc(dev); + return ret; +} + +/* retune SCC in case of error during xref */ +static int rcar_mmc_retune_if_needed(const struct device *dev, bool request_retune) +{ + struct mmc_rcar_data *dev_data = dev->data; + int ret = 0; + uint32_t reg; + bool scc_pos_err = false; + uint8_t scc_tapset; + + if (!dev_data->can_retune) { + return 0; + } + + reg = rcar_mmc_read_reg32(dev, RENESAS_SDHI_SCC_RVSREQ); + if (reg & RENESAS_SDHI_SCC_RVSREQ_ERR) { + scc_pos_err = true; + } + + scc_tapset = rcar_mmc_read_reg32(dev, RENESAS_SDHI_SCC_TAPSET); + + LOG_DBG("%s: scc_tapset %08x scc_rvsreq %08x request %d is manual tuning %d", dev->name, + scc_tapset, reg, request_retune, dev_data->manual_retuning); + + if (request_retune || (scc_pos_err && !dev_data->manual_retuning)) { + return rcar_mmc_execute_tuning(dev); + } + + rcar_mmc_write_reg32(dev, RENESAS_SDHI_SCC_RVSREQ, 0); + + switch (reg & RENESAS_SDHI_SCC_RVSREQ_REQTAP_MASK) { + case RENESAS_SDHI_SCC_RVSREQ_REQTAPDOWN: + scc_tapset = (scc_tapset - 1) % RENESAS_TAPNUM; + break; + case RENESAS_SDHI_SCC_RVSREQ_REQTAPUP: + scc_tapset = (scc_tapset + 1) % RENESAS_TAPNUM; + break; + default: + ret = -EINVAL; + LOG_ERR("%s: can't perform manual tuning SCC_RVSREQ %08x", dev->name, reg); + break; + } + + if (!ret) { + rcar_mmc_write_reg32(dev, RENESAS_SDHI_SCC_TAPSET, scc_tapset); + } + + return ret; +} + +#endif /* CONFIG_RCAR_MMC_SCC_SUPPORT */ + +/** + * @brief Get MMC controller properties + * + * Gets host properties from the host controller. Host controller should + * initialize all values in the @ref sdhc_host_props structure provided. + * + * @param dev Renesas MMC device + * @param props property structure to be filled by MMC driver + * + * @retval 0 function succeeded. + * @retval -EINVAL: some of pointers provided to the function are NULL + */ +static int rcar_mmc_get_host_props(const struct device *dev, struct sdhc_host_props *props) +{ + struct mmc_rcar_data *data; + + if (!props || !dev || !dev->data) { + return -EINVAL; + } + + data = dev->data; + memcpy(props, &data->props, sizeof(*props)); + return 0; +} + +static const struct sdhc_driver_api rcar_sdhc_api = { + .card_busy = rcar_mmc_card_busy, +#ifdef CONFIG_RCAR_MMC_SCC_SUPPORT + .execute_tuning = rcar_mmc_execute_tuning, +#endif + .get_card_present = rcar_mmc_get_card_present, + .get_host_props = rcar_mmc_get_host_props, + .request = rcar_mmc_request, + .reset = rcar_mmc_reset, + .set_io = rcar_mmc_set_io, +}; + +/* start SD-IF clock at max frequency configured in dts */ +static int rcar_mmc_init_start_clk(const struct mmc_rcar_cfg *cfg) +{ + int ret = 0; + const struct device *cpg_dev = cfg->cpg_dev; + uintptr_t rate = cfg->max_frequency; + + ret = clock_control_on(cpg_dev, (clock_control_subsys_t *)&cfg->bus_clk); + if (ret < 0) { + return ret; + } + + ret = clock_control_on(cpg_dev, (clock_control_subsys_t *)&cfg->cpg_clk); + if (ret < 0) { + return ret; + } + + ret = clock_control_set_rate(cpg_dev, (clock_control_subsys_t *)&cfg->cpg_clk, + (clock_control_subsys_rate_t)rate); + if (ret < 0) { + clock_control_off(cpg_dev, (clock_control_subsys_t *)&cfg->cpg_clk); + } + + rate = MMC_BUS_CLOCK_FREQ; + ret = clock_control_set_rate(cpg_dev, (clock_control_subsys_t *)&cfg->bus_clk, + (clock_control_subsys_rate_t)rate); + /* SD spec recommends at least 1 ms of delay after start of clock */ + k_msleep(1); + + return ret; +} + +static void rcar_mmc_init_host_props(const struct device *dev) +{ + struct mmc_rcar_data *data = dev->data; + const struct mmc_rcar_cfg *cfg = dev->config; + struct sdhc_host_props *props = &data->props; + struct sdhc_host_caps *host_caps = &props->host_caps; + + memset(props, 0, sizeof(*props)); + + /* Note: init only properties that are used for mmc/sdhc */ + + props->f_max = cfg->max_frequency; + /* + * note: actually, it's possible to get lower frequency + * if we use divider from cpg too + */ + props->f_min = (cfg->max_frequency >> 9); + + props->power_delay = 100; /* ms */ + + props->is_spi = 0; + + switch (cfg->bus_width) { + case SDHC_BUS_WIDTH8BIT: + host_caps->bus_8_bit_support = 1; + case SDHC_BUS_WIDTH4BIT: + host_caps->bus_4_bit_support = 1; + default: + break; + } + + host_caps->high_spd_support = 1; +#ifdef CONFIG_RCAR_MMC_SCC_SUPPORT + host_caps->sdr104_support = cfg->mmc_sdr104_support; + host_caps->sdr50_support = cfg->uhs_support; + /* neither Linux nor U-boot support DDR50 mode, that's why we don't support it too */ + host_caps->ddr50_support = 0; + host_caps->hs200_support = cfg->mmc_hs200_1_8v; + /* TODO: add support */ + host_caps->hs400_support = 0; +#endif + + host_caps->vol_330_support = + regulator_is_supported_voltage(cfg->regulator_vqmmc, 3300000, 3300000); + host_caps->vol_300_support = + regulator_is_supported_voltage(cfg->regulator_vqmmc, 3000000, 3000000); + host_caps->vol_180_support = + regulator_is_supported_voltage(cfg->regulator_vqmmc, 1800000, 1800000); +} + +/* reset sampling clock controller registers */ +static int rcar_mmc_disable_scc(const struct device *dev) +{ + int ret; + uint32_t reg; + struct mmc_rcar_data *data = dev->data; + uint32_t mmc_clk_ctl = rcar_mmc_read_reg32(dev, RCAR_MMC_CLKCTL); + + /* just to be to be sure that the SD clock is disabled */ + ret = rcar_mmc_enable_clock(dev, false); + if (ret) { + return ret; + } + + /* + * Reset SCC registers, need to disable and enable clock + * before and after reset + */ + + /* Disable SCC sampling clock */ + reg = rcar_mmc_read_reg32(dev, RENESAS_SDHI_SCC_CKSEL); + reg &= ~RENESAS_SDHI_SCC_CKSEL_DTSEL; + rcar_mmc_write_reg32(dev, RENESAS_SDHI_SCC_CKSEL, reg); + + /* disable hs400 mode & data output timing */ + reg = rcar_mmc_read_reg32(dev, RENESAS_SDHI_SCC_TMPPORT2); + reg &= ~(RENESAS_SDHI_SCC_TMPPORT2_HS400EN | RENESAS_SDHI_SCC_TMPPORT2_HS400OSEL); + rcar_mmc_write_reg32(dev, RENESAS_SDHI_SCC_TMPPORT2, reg); + + ret = rcar_mmc_enable_clock(dev, (mmc_clk_ctl & RCAR_MMC_CLKCTL_OFFEN) ? false : true); + if (ret) { + return ret; + } + + /* disable SCC sampling clock position correction */ + reg = rcar_mmc_read_reg32(dev, RENESAS_SDHI_SCC_RVSCNTL); + reg &= ~RENESAS_SDHI_SCC_RVSCNTL_RVSEN; + rcar_mmc_write_reg32(dev, RENESAS_SDHI_SCC_RVSCNTL, reg); + + data->can_retune = 0; + + return 0; +} + +/* initialize and configure the Renesas MMC controller registers */ +static int rcar_mmc_init_controller_regs(const struct device *dev) +{ + int ret = 0; + uint32_t reg; + struct mmc_rcar_data *data = dev->data; + struct sdhc_io ios = {0}; + + rcar_mmc_reset(dev); + + /* Disable SD clock (SD_CLK) output */ + ret = rcar_mmc_enable_clock(dev, false); + if (ret) { + return ret; + } + + /* set transfer data length to 0 */ + rcar_mmc_write_reg32(dev, RCAR_MMC_SIZE, 0); + + /* disable the SD_BUF read/write DMA transfer */ + reg = rcar_mmc_read_reg32(dev, RCAR_MMC_EXTMODE); + reg &= ~RCAR_MMC_EXTMODE_DMA_EN; + rcar_mmc_write_reg32(dev, RCAR_MMC_EXTMODE, reg); + /* mask DMA irqs and clear dma irq flags */ + rcar_mmc_reset_and_mask_irqs(dev); + /* set system address increment mode selector & 64-bit bus width */ + reg = rcar_mmc_read_reg32(dev, RCAR_MMC_DMA_MODE); + reg |= RCAR_MMC_DMA_MODE_ADDR_INC | RCAR_MMC_DMA_MODE_WIDTH; + rcar_mmc_write_reg32(dev, RCAR_MMC_DMA_MODE, reg); + + /* store version of of introductory IP */ + data->ver = rcar_mmc_read_reg32(dev, RCAR_MMC_VERSION); + data->ver &= RCAR_MMC_VERSION_IP; + + /* + * set bus width to 1 + * timeout counter: SDCLK * 2^27 + * card detect time counter: SDĻ• * 2^24 + */ + reg = rcar_mmc_read_reg32(dev, RCAR_MMC_OPTION); + reg |= RCAR_MMC_OPTION_WIDTH_MASK | 0xEE; + rcar_mmc_write_reg32(dev, RCAR_MMC_OPTION, reg); + + /* block count enable */ + rcar_mmc_write_reg32(dev, RCAR_MMC_STOP, RCAR_MMC_STOP_SEC); + /* number of transfer blocks */ + rcar_mmc_write_reg32(dev, RCAR_MMC_SECCNT, 0); + + /* + * SD_BUF0 data swap disabled. + * Read/write access to SD_BUF0 can be performed with the 64-bit access. + * + * Note: when using the DMA, the bus width should be fixed at 64 bits. + */ + rcar_mmc_write_reg32(dev, RCAR_MMC_HOST_MODE, 0); + data->width_access_sd_buf0 = 8; + + /* disable sampling clock controller, it is used for uhs/sdr104, hs200 and hs400 */ + ret = rcar_mmc_disable_scc(dev); + if (ret) { + return ret; + } + + /* + * configure divider inside MMC controller + * set maximum possible divider + */ + ios.clock = data->props.f_min; + rcar_mmc_set_clk_rate(dev, &ios); + + data->restore_cfg_after_reset = 1; + + return 0; +} + +#ifdef CONFIG_RCAR_MMC_DMA_IRQ_DRIVEN_SUPPORT +static void rcar_mmc_irq_handler(const void *arg) +{ + const struct device *dev = arg; + + uint32_t dma_info1 = rcar_mmc_read_reg32(dev, RCAR_MMC_DMA_INFO1); + uint32_t dma_info2 = rcar_mmc_read_reg32(dev, RCAR_MMC_DMA_INFO2); + + if (dma_info1 || dma_info2) { + struct mmc_rcar_data *data = dev->data; + + rcar_mmc_write_reg32(dev, RCAR_MMC_DMA_INFO1_MASK, 0xfffffeff); + rcar_mmc_write_reg32(dev, RCAR_MMC_DMA_INFO2_MASK, ~0); + k_sem_give(&data->irq_xref_fin); + } else { + LOG_WRN("%s: warning: non-dma event triggers irq", dev->name); + } +} +#endif /* CONFIG_RCAR_MMC_DMA_IRQ_DRIVEN_SUPPORT */ + +/* initialize and configure the Renesas MMC driver */ +static int rcar_mmc_init(const struct device *dev) +{ + int ret = 0; + struct mmc_rcar_data *data = dev->data; + const struct mmc_rcar_cfg *cfg = dev->config; + +#ifdef CONFIG_RCAR_MMC_DMA_IRQ_DRIVEN_SUPPORT + ret = k_sem_init(&data->irq_xref_fin, 0, 1); + if (ret) { + LOG_ERR("%s: can't init semaphore", dev->name); + return ret; + } +#endif + + DEVICE_MMIO_MAP(dev, K_MEM_CACHE_NONE); + + /* Configure dt provided device signals when available */ + ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT); + if (ret < 0) { + LOG_ERR("%s: error can't apply pinctrl state", dev->name); + goto exit_unmap; + } + + if (!device_is_ready(cfg->cpg_dev)) { + LOG_ERR("%s: error cpg_dev isn't ready", dev->name); + ret = -ENODEV; + goto exit_unmap; + } + + ret = rcar_mmc_init_start_clk(cfg); + if (ret < 0) { + LOG_ERR("%s: error can't turn on the cpg", dev->name); + goto exit_unmap; + } + + /* it's needed for SDHC */ + rcar_mmc_init_host_props(dev); + + ret = rcar_mmc_init_controller_regs(dev); + if (ret) { + goto exit_disable_clk; + } + +#ifdef CONFIG_RCAR_MMC_DMA_IRQ_DRIVEN_SUPPORT + cfg->irq_config_func(dev); +#endif /* CONFIG_RCAR_MMC_DMA_IRQ_DRIVEN_SUPPORT */ + + LOG_INF("%s: initialize driver, MMC version 0x%hhx", dev->name, data->ver); + + return 0; + +exit_disable_clk: + clock_control_off(cfg->cpg_dev, (clock_control_subsys_t *)&cfg->cpg_clk); + +exit_unmap: +#if defined(DEVICE_MMIO_IS_IN_RAM) && defined(CONFIG_MMU) + z_phys_unmap((uint8_t *)DEVICE_MMIO_GET(dev), DEVICE_MMIO_ROM_PTR(dev)->size); +#endif + return ret; +} + +#ifdef CONFIG_RCAR_MMC_DMA_IRQ_DRIVEN_SUPPORT +#define RCAR_MMC_CONFIG_FUNC(n) \ + static void irq_config_func_##n(const struct device *dev) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), rcar_mmc_irq_handler, \ + DEVICE_DT_INST_GET(n), DT_INST_IRQ(n, flags)); \ + irq_enable(DT_INST_IRQN(n)); \ + } +#define RCAR_MMC_IRQ_CFG_FUNC_INIT(n) .irq_config_func = irq_config_func_##n, +#else +#define RCAR_MMC_IRQ_CFG_FUNC_INIT(n) +#define RCAR_MMC_CONFIG_FUNC(n) +#endif + +#define RCAR_MMC_INIT(n) \ + static struct mmc_rcar_data mmc_rcar_data_##n; \ + PINCTRL_DT_INST_DEFINE(n); \ + RCAR_MMC_CONFIG_FUNC(n); \ + static const struct mmc_rcar_cfg mmc_rcar_cfg_##n = { \ + DEVICE_MMIO_ROM_INIT(DT_DRV_INST(n)), \ + .cpg_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)), \ + .cpg_clk.module = DT_INST_CLOCKS_CELL_BY_IDX(n, 0, module), \ + .cpg_clk.domain = DT_INST_CLOCKS_CELL_BY_IDX(n, 0, domain), \ + .bus_clk.module = DT_INST_CLOCKS_CELL_BY_IDX(n, 1, module), \ + .bus_clk.domain = DT_INST_CLOCKS_CELL_BY_IDX(n, 1, domain), \ + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + .regulator_vqmmc = DEVICE_DT_GET(DT_PHANDLE(DT_DRV_INST(n), vqmmc_supply)), \ + .regulator_vmmc = DEVICE_DT_GET(DT_PHANDLE(DT_DRV_INST(n), vmmc_supply)), \ + .max_frequency = DT_INST_PROP(n, max_bus_freq), \ + .non_removable = DT_INST_PROP(n, non_removable), \ + .mmc_hs200_1_8v = DT_INST_PROP(n, mmc_hs200_1_8v), \ + .mmc_hs400_1_8v = DT_INST_PROP(n, mmc_hs400_1_8v), \ + .mmc_sdr104_support = DT_INST_PROP(n, mmc_sdr104_support), \ + .uhs_support = 1, \ + .bus_width = DT_INST_PROP(n, bus_width), \ + RCAR_MMC_IRQ_CFG_FUNC_INIT(n)}; \ + DEVICE_DT_INST_DEFINE(n, rcar_mmc_init, NULL, &mmc_rcar_data_##n, &mmc_rcar_cfg_##n, \ + POST_KERNEL, CONFIG_SDHC_INIT_PRIORITY, &rcar_sdhc_api); + +DT_INST_FOREACH_STATUS_OKAY(RCAR_MMC_INIT) diff --git a/drivers/sdhc/rcar_mmc_registers.h b/drivers/sdhc/rcar_mmc_registers.h new file mode 100644 index 00000000000..067ca4f112e --- /dev/null +++ b/drivers/sdhc/rcar_mmc_registers.h @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2023 EPAM Systems + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef __RCAR_MMC_REGISTERS_H__ +#define __RCAR_MMC_REGISTERS_H__ + +#include /* for BIT macro */ + +/* + * The command type register is used to select the command type + * and response type + */ +#define RCAR_MMC_CMD 0x000 /* command */ +#define RCAR_MMC_CMD_NOSTOP BIT(14) /* No automatic CMD12 issue */ +#define RCAR_MMC_CMD_MULTI BIT(13) /* multiple block transfer */ +#define RCAR_MMC_CMD_RD BIT(12) /* 1: read, 0: write */ +#define RCAR_MMC_CMD_DATA BIT(11) /* data transfer */ +#define RCAR_MMC_CMD_APP BIT(6) /* ACMD preceded by CMD55 */ +#define RCAR_MMC_CMD_NORMAL (0 << 8) /* auto-detect of resp-type */ +#define RCAR_MMC_CMD_RSP_NONE (3 << 8) /* response: none */ +#define RCAR_MMC_CMD_RSP_R1 (4 << 8) /* response: R1, R5, R6, R7 */ +#define RCAR_MMC_CMD_RSP_R1B (5 << 8) /* response: R1b, R5b */ +#define RCAR_MMC_CMD_RSP_R2 (6 << 8) /* response: R2 */ +#define RCAR_MMC_CMD_RSP_R3 (7 << 8) /* response: R3, R4 */ + +/* Command arguments register for SD card */ +#define RCAR_MMC_ARG 0x010 /* command argument */ + +/* + * The data stop register is used to enable or disable block counting at + * multiple block transfer, and to control the issuing of CMD12 within + * command sequences. + */ +#define RCAR_MMC_STOP 0x020 /* stop action control */ +#define RCAR_MMC_STOP_SEC BIT(8) /* use sector count */ +#define RCAR_MMC_STOP_STP BIT(0) /* issue CMD12 */ + +/* + * The block count register is used to specify the number of + * transfer blocks at multiple block transfer. + */ +#define RCAR_MMC_SECCNT 0x028 /* sector counter */ + +/* The SD card response registers hold the response from the SD card */ +#define RCAR_MMC_RSP10 0x030 /* response[39:8] */ +#define RCAR_MMC_RSP32 0x040 /* response[71:40] */ +#define RCAR_MMC_RSP54 0x050 /* response[103:72] */ +#define RCAR_MMC_RSP76 0x060 /* response[127:104] */ + +/* + * The SD card interrupt flag register 1 indicates the response end and access + * end in the command sequence. This register also indicates the card + * detect/write protect state. + */ +#define RCAR_MMC_INFO1 0x070 /* IRQ status 1 */ +#define RCAR_MMC_INFO1_CD BIT(5) /* state of card detect */ +#define RCAR_MMC_INFO1_INSERT BIT(4) /* card inserted */ +#define RCAR_MMC_INFO1_REMOVE BIT(3) /* card removed */ +#define RCAR_MMC_INFO1_CMP BIT(2) /* data complete */ +#define RCAR_MMC_INFO1_RSP BIT(0) /* response complete */ + +/* + * The SD card interrupt flag register 2 indicates the access status of the + * SD buffer and SD card. + */ +#define RCAR_MMC_INFO2 0x078 /* IRQ status 2 */ +#define RCAR_MMC_INFO2_ERR_ILA BIT(15) /* illegal access err */ +#define RCAR_MMC_INFO2_CBSY BIT(14) /* command busy */ +#define RCAR_MMC_INFO2_SCLKDIVEN BIT(13) /* command setting reg ena */ +#define RCAR_MMC_INFO2_CLEAR BIT(11) /* the write value should always be 1 */ +#define RCAR_MMC_INFO2_BWE BIT(9) /* write buffer ready */ +#define RCAR_MMC_INFO2_BRE BIT(8) /* read buffer ready */ +#define RCAR_MMC_INFO2_DAT0 BIT(7) /* SDDAT0 */ +#define RCAR_MMC_INFO2_ERR_RTO BIT(6) /* response time out */ +#define RCAR_MMC_INFO2_ERR_ILR BIT(5) /* illegal read err */ +#define RCAR_MMC_INFO2_ERR_ILW BIT(4) /* illegal write err */ +#define RCAR_MMC_INFO2_ERR_TO BIT(3) /* time out error */ +#define RCAR_MMC_INFO2_ERR_END BIT(2) /* END bit error */ +#define RCAR_MMC_INFO2_ERR_CRC BIT(1) /* CRC error */ +#define RCAR_MMC_INFO2_ERR_IDX BIT(0) /* cmd index error */ + +#define RCAR_MMC_INFO2_ERRORS \ + (RCAR_MMC_INFO2_ERR_RTO | RCAR_MMC_INFO2_ERR_ILR | \ + RCAR_MMC_INFO2_ERR_ILW | RCAR_MMC_INFO2_ERR_TO | \ + RCAR_MMC_INFO2_ERR_END | RCAR_MMC_INFO2_ERR_CRC | \ + RCAR_MMC_INFO2_ERR_IDX | RCAR_MMC_INFO2_ERR_ILA) + +/* + * The interrupt mask 1 register is used to enable or disable + * the RCAR_MMC_INFO1 interrupt. + */ +#define RCAR_MMC_INFO1_MASK 0x080 + +/* + * The interrupt mask 2 register is used to enable or disable + * the RCAR_MMC_INFO2 interrupt. + */ +#define RCAR_MMC_INFO2_MASK 0x088 + +/* + * The SD clock control register is used to control + * the SD clock output and to set the frequency. + */ +#define RCAR_MMC_CLKCTL 0x090 +#define RCAR_MMC_CLKCTL_DIV_MASK 0x104ff +#define RCAR_MMC_CLKCTL_DIV512 BIT(7) /* SDCLK = CLK / 512 */ +#define RCAR_MMC_CLKCTL_DIV256 BIT(6) /* SDCLK = CLK / 256 */ +#define RCAR_MMC_CLKCTL_DIV128 BIT(5) /* SDCLK = CLK / 128 */ +#define RCAR_MMC_CLKCTL_DIV64 BIT(4) /* SDCLK = CLK / 64 */ +#define RCAR_MMC_CLKCTL_DIV32 BIT(3) /* SDCLK = CLK / 32 */ +#define RCAR_MMC_CLKCTL_DIV16 BIT(2) /* SDCLK = CLK / 16 */ +#define RCAR_MMC_CLKCTL_DIV8 BIT(1) /* SDCLK = CLK / 8 */ +#define RCAR_MMC_CLKCTL_DIV4 BIT(0) /* SDCLK = CLK / 4 */ +#define RCAR_MMC_CLKCTL_DIV2 0 /* SDCLK = CLK / 2 */ +#define RCAR_MMC_CLKCTL_RCAR_DIV1 0xff /* SDCLK = CLK (RCar ver.) */ +#define RCAR_MMC_CLKCTL_OFFEN BIT(9) /* stop SDCLK when unused */ +#define RCAR_MMC_CLKCTL_SCLKEN BIT(8) /* SDCLK output enable */ + +/* + * The transfer data length register is used to specify + * the transfer data size. + */ +#define RCAR_MMC_SIZE 0x098 + +/* + * The SD card access control option register is used to set + * the bus width and timeout counter. + */ +#define RCAR_MMC_OPTION 0x0A0 +#define RCAR_MMC_OPTION_WIDTH_MASK (5 << 13) +#define RCAR_MMC_OPTION_WIDTH_1 (4 << 13) +#define RCAR_MMC_OPTION_WIDTH_4 (0 << 13) +#define RCAR_MMC_OPTION_WIDTH_8 (1 << 13) + +/* + * The SD error status register 1 indicates the CRC status, CRC error, + * End error, and CMD error. + */ +#define RCAR_MMC_ERR_STS1 0x0B0 + +/* The SD error status register 2 indicates the timeout state. */ +#define RCAR_MMC_ERR_STS2 0x0B8 + +/* SD Buffer Read/Write Register */ +#define RCAR_MMC_BUF0 0x0C0 + +/* The DMA mode enable register enables the DMA transfer. */ +#define RCAR_MMC_EXTMODE 0x360 +#define RCAR_MMC_EXTMODE_DMA_EN BIT(1) /* transfer 1: DMA, 0: pio */ + +/* The software reset register sets a software reset. */ +#define RCAR_MMC_SOFT_RST 0x380 +#define RCAR_MMC_SOFT_RST_RSTX BIT(0) /* reset deassert */ + +/* The version register indicates the version of the SD host interface. */ +#define RCAR_MMC_VERSION 0x388 +#define RCAR_MMC_VERSION_IP 0xff /* IP version */ + +/* + * The host interface mode setting register selects the width for access to + * the data bus. + */ +#define RCAR_MMC_HOST_MODE 0x390 + +/* The SD interface mode setting register specifies HS400 mode. */ +#define RCAR_MMC_IF_MODE 0x398 +#define RCAR_MMC_IF_MODE_DDR BIT(0) /* DDR mode */ + +/* Set of DMAC registers */ +#define RCAR_MMC_DMA_MODE 0x820 +#define RCAR_MMC_DMA_MODE_DIR_RD BIT(16) /* 1: from device, 0: to dev */ +#define RCAR_MMC_DMA_MODE_WIDTH (BIT(4) | BIT(5)) +#define RCAR_MMC_DMA_MODE_ADDR_INC BIT(0) /* 1: address inc, 0: fixed */ +#define RCAR_MMC_DMA_CTL 0x828 +#define RCAR_MMC_DMA_CTL_START BIT(0) /* start DMA (auto cleared) */ +#define RCAR_MMC_DMA_RST 0x830 +#define RCAR_MMC_DMA_RST_DTRAN0 BIT(8) +#define RCAR_MMC_DMA_RST_DTRAN1 BIT(9) +#define RCAR_MMC_DMA_INFO1 0x840 +#define RCAR_MMC_DMA_INFO1_END_RD2 BIT(20) /* DMA from device is complete (uniphier) */ +#define RCAR_MMC_DMA_INFO1_END_RD BIT(17) /* DMA from device is complete (renesas) */ +#define RCAR_MMC_DMA_INFO1_END_WR BIT(16) /* DMA to device is complete */ +#define RCAR_MMC_DMA_INFO1_MASK 0x848 +#define RCAR_MMC_DMA_INFO2 0x850 +#define RCAR_MMC_DMA_INFO2_ERR_RD BIT(17) +#define RCAR_MMC_DMA_INFO2_ERR_WR BIT(16) +#define RCAR_MMC_DMA_INFO2_MASK 0x858 +#define RCAR_MMC_DMA_ADDR_L 0x880 +#define RCAR_MMC_DMA_ADDR_H 0x888 + +/* set of SCC registers */ + +/* Initial setting register */ +#define RENESAS_SDHI_SCC_DTCNTL 0x1000 +#define RENESAS_SDHI_SCC_DTCNTL_TAPEN BIT(0) +/* Sampling clock position setting register */ +#define RENESAS_SDHI_SCC_TAPSET 0x1008 +#define RENESAS_SDHI_SCC_DT2FF 0x1010 +/* Sampling Clock Selection Register */ +#define RENESAS_SDHI_SCC_CKSEL 0x1018 +#define RENESAS_SDHI_SCC_CKSEL_DTSEL BIT(0) +/* Sampling Clock Position Correction Register */ +#define RENESAS_SDHI_SCC_RVSCNTL 0x1020 +#define RENESAS_SDHI_SCC_RVSCNTL_RVSEN BIT(0) +/* Sampling Clock Position Correction Request Register */ +#define RENESAS_SDHI_SCC_RVSREQ 0x1028 +#define RENESAS_SDHI_SCC_RVSREQ_REQTAPDOWN BIT(0) +#define RENESAS_SDHI_SCC_RVSREQ_REQTAPUP BIT(1) +#define RENESAS_SDHI_SCC_RVSREQ_REQTAP_MASK \ + (RENESAS_SDHI_SCC_RVSREQ_REQTAPDOWN | RENESAS_SDHI_SCC_RVSREQ_REQTAPUP) +#define RENESAS_SDHI_SCC_RVSREQ_ERR BIT(2) +/* Sampling data comparison register */ +#define RENESAS_SDHI_SCC_SMPCMP 0x1030 +/* Hardware Adjustment Register 2, used for configuration HS400 mode */ +#define RENESAS_SDHI_SCC_TMPPORT2 0x1038 +#define RENESAS_SDHI_SCC_TMPPORT2_HS400EN BIT(31) +#define RENESAS_SDHI_SCC_TMPPORT2_HS400OSEL BIT(4) + +#endif /* __RCAR_MMC_REGISTERS_H__ */ diff --git a/drivers/sdhc/sdhc_esp32.c b/drivers/sdhc/sdhc_esp32.c new file mode 100644 index 00000000000..f77c5858aa4 --- /dev/null +++ b/drivers/sdhc/sdhc_esp32.c @@ -0,0 +1,1458 @@ +/* + * Copyright (c) 2024 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT espressif_esp32_sdhc_slot + +#include +#include +#include +#include +#include +#include + +/* ESP32 includes */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sdhc_esp32.h" + +LOG_MODULE_REGISTER(sdhc, CONFIG_SDHC_LOG_LEVEL); + +#define SDMMC_SLOT_WIDTH_DEFAULT 1 + +#define SDMMC_HOST_CLOCK_UPDATE_CMD_TIMEOUT_US 1000 * 1000 +#define SDMMC_HOST_RESET_TIMEOUT_US 5000 * 1000 +#define SDMMC_HOST_START_CMD_TIMEOUT_US 1000 * 1000 +#define SDMMC_HOST_WAIT_EVENT_TIMEOUT_US 1000 * 1000 + +#define SDMMC_EVENT_QUEUE_LENGTH 32 + +#define SDMMC_TIMEOUT_MAX 0xFFFFFFFF + +/* Number of DMA descriptors used for transfer. + * Increasing this value above 4 doesn't improve performance for the usual case + * of SD memory cards (most data transfers are multiples of 512 bytes). + */ +#define SDMMC_DMA_DESC_CNT 4 + +/* mask for card current state */ +#define MMC_R1_CURRENT_STATE(resp) (((resp)[0] >> 9) & 0xf) + +struct sdhc_esp32_config { + + int slot; + const sdmmc_dev_t *sdio_hw; + const struct pinctrl_dev_config *pcfg; + const struct gpio_dt_spec pwr_gpio; + /* + * Pins below are only defined for ESP32. For SoC's with GPIO matrix feature + * please use pinctrl for pin configuration. + */ + const int clk_pin; + const int cmd_pin; + const int d0_pin; + const int d1_pin; + const int d2_pin; + const int d3_pin; + + int irq_source; + uint8_t bus_width_cfg; + + struct sdhc_host_props props; +}; + +struct sdhc_esp32_data { + + uint8_t bus_width; /* Bus width used by the slot (can change during execution) */ + uint32_t bus_clock; /* Value in Hz. ESP-IDF functions use kHz instead */ + + enum sdhc_power power_mode; + enum sdhc_timing_mode timing; + + struct host_ctx s_host_ctx; + struct k_mutex s_request_mutex; + bool s_is_app_cmd; + sdmmc_desc_t s_dma_desc[SDMMC_DMA_DESC_CNT]; + struct sdmmc_transfer_state s_cur_transfer; +}; + +/********************************************************************** + * ESP32 low level functions + **********************************************************************/ + +/* We have two clock divider stages: + * - one is the clock generator which drives SDMMC peripheral, + * it can be configured using sdio_hw->clock register. It can generate + * frequencies 160MHz/(N + 1), where 0 < N < 16, I.e. from 10 to 80 MHz. + * - 4 clock dividers inside SDMMC peripheral, which can divide clock + * from the first stage by 2 * M, where 0 < M < 255 + * (they can also be bypassed). + * + * For cards which aren't UHS-1 or UHS-2 cards, which we don't support, + * maximum bus frequency in high speed (HS) mode is 50 MHz. + * Note: for non-UHS-1 cards, HS mode is optional. + * Default speed (DS) mode is mandatory, it works up to 25 MHz. + * Whether the card supports HS or not can be determined using TRAN_SPEED + * field of card's CSD register. + * + * 50 MHz can not be obtained exactly, closest we can get is 53 MHz. + * + * The first stage divider is set to the highest possible value for the given + * frequency, and the second stage dividers are used if division factor + * is >16. + * + * Of the second stage dividers, div0 is used for card 0, and div1 is used + * for card 1. + */ +static int sdmmc_host_set_clk_div(sdmmc_dev_t *sdio_hw, int div) +{ + if (!((div > 1) && (div <= 16))) { + LOG_ERR("Invalid parameter 'div'"); + return ESP_ERR_INVALID_ARG; + } + + sdmmc_ll_set_clock_div(sdio_hw, div); + sdmmc_ll_select_clk_source(sdio_hw, SDMMC_CLK_SRC_DEFAULT); + sdmmc_ll_init_phase_delay(sdio_hw); + + /* Wait for the clock to propagate */ + esp_rom_delay_us(10); + + return 0; +} + +static void sdmmc_host_dma_init(sdmmc_dev_t *sdio_hw) +{ + sdio_hw->ctrl.dma_enable = 1; + sdio_hw->bmod.val = 0; + sdio_hw->bmod.sw_reset = 1; + sdio_hw->idinten.ni = 1; + sdio_hw->idinten.ri = 1; + sdio_hw->idinten.ti = 1; +} + +static void sdmmc_host_dma_stop(sdmmc_dev_t *sdio_hw) +{ + sdio_hw->ctrl.use_internal_dma = 0; + sdio_hw->ctrl.dma_reset = 1; + sdio_hw->bmod.fb = 0; + sdio_hw->bmod.enable = 0; +} + +static int sdmmc_host_transaction_handler_init(struct sdhc_esp32_data *data) +{ + k_mutex_init(&data->s_request_mutex); + + data->s_is_app_cmd = false; + + return 0; +} + +static int sdmmc_host_wait_for_event(struct sdhc_esp32_data *data, int timeout_ms, + struct sdmmc_event *out_event) +{ + if (!out_event) { + return ESP_ERR_INVALID_ARG; + } + + if (!data->s_host_ctx.event_queue) { + return ESP_ERR_INVALID_STATE; + } + + int ret = k_msgq_get(data->s_host_ctx.event_queue, out_event, K_MSEC(timeout_ms)); + + return ret; +} + +static int handle_idle_state_events(struct sdhc_esp32_data *data) +{ + /* Handle any events which have happened in between transfers. + * Under current assumptions (no SDIO support) only card detect events + * can happen in the idle state. + */ + struct sdmmc_event evt; + + int64_t yield_delay_us = 100 * 1000; /* initially 100ms */ + int64_t t0 = esp_timer_get_time(); + int64_t t1 = 0; + + while (sdmmc_host_wait_for_event(data, 0, &evt) == 0) { + + if (evt.sdmmc_status & SDMMC_INTMASK_CD) { + LOG_DBG("card detect event"); + evt.sdmmc_status &= ~SDMMC_INTMASK_CD; + } + + if (evt.sdmmc_status != 0 || evt.dma_status != 0) { + LOG_DBG("%s unhandled: %08" PRIx32 " %08" PRIx32, __func__, + evt.sdmmc_status, evt.dma_status); + } + + /* Loop timeout */ + t1 = esp_timer_get_time(); + + if (t1 - t0 > SDMMC_HOST_WAIT_EVENT_TIMEOUT_US) { + return ESP_ERR_TIMEOUT; + } + + if (t1 - t0 > yield_delay_us) { + yield_delay_us *= 2; + k_sleep(K_MSEC(1)); + } + } + + return 0; +} + +static void fill_dma_descriptors(struct sdhc_esp32_data *data, size_t num_desc) +{ + for (size_t i = 0; i < num_desc; ++i) { + if (data->s_cur_transfer.size_remaining == 0) { + return; + } + + const size_t next = data->s_cur_transfer.next_desc; + sdmmc_desc_t *desc = &data->s_dma_desc[next]; + + if (desc->owned_by_idmac) { + return; + } + + size_t size_to_fill = (data->s_cur_transfer.size_remaining < SDMMC_DMA_MAX_BUF_LEN) + ? data->s_cur_transfer.size_remaining + : SDMMC_DMA_MAX_BUF_LEN; + + bool last = size_to_fill == data->s_cur_transfer.size_remaining; + + desc->last_descriptor = last; + desc->second_address_chained = 1; + desc->owned_by_idmac = 1; + desc->buffer1_ptr = data->s_cur_transfer.ptr; + desc->next_desc_ptr = + (last) ? NULL : &data->s_dma_desc[(next + 1) % SDMMC_DMA_DESC_CNT]; + + if (!((size_to_fill < 4) || ((size_to_fill % 4) == 0))) { + return; + } + + desc->buffer1_size = (size_to_fill + 3) & (~3); + + data->s_cur_transfer.size_remaining -= size_to_fill; + data->s_cur_transfer.ptr += size_to_fill; + data->s_cur_transfer.next_desc = + (data->s_cur_transfer.next_desc + 1) % SDMMC_DMA_DESC_CNT; + + LOG_DBG("fill %d desc=%d rem=%d next=%d last=%d sz=%d", num_desc, next, + data->s_cur_transfer.size_remaining, data->s_cur_transfer.next_desc, + desc->last_descriptor, desc->buffer1_size); + } +} + +static void sdmmc_host_dma_resume(sdmmc_dev_t *sdio_hw) +{ + sdmmc_ll_poll_demand(sdio_hw); +} + +static void sdmmc_host_dma_prepare(sdmmc_dev_t *sdio_hw, sdmmc_desc_t *desc, size_t block_size, + size_t data_size) +{ + /* Set size of data and DMA descriptor pointer */ + sdmmc_ll_set_data_transfer_len(sdio_hw, data_size); + sdmmc_ll_set_block_size(sdio_hw, block_size); + sdmmc_ll_set_desc_addr(sdio_hw, (uint32_t)desc); + + /* Enable everything needed to use DMA */ + sdmmc_ll_enable_dma(sdio_hw, true); + sdmmc_host_dma_resume(sdio_hw); +} + +static int sdmmc_host_start_command(sdmmc_dev_t *sdio_hw, int slot, sdmmc_hw_cmd_t cmd, + uint32_t arg) +{ + if (!(slot == 0 || slot == 1)) { + return ESP_ERR_INVALID_ARG; + } + if (!sdmmc_ll_is_card_detected(sdio_hw, slot)) { + return ESP_ERR_NOT_FOUND; + } + if (cmd.data_expected && cmd.rw && sdmmc_ll_is_card_write_protected(sdio_hw, slot)) { + return ESP_ERR_INVALID_STATE; + } + /* Outputs should be synchronized to cclk_out */ + cmd.use_hold_reg = 1; + + int64_t yield_delay_us = 100 * 1000; /* initially 100ms */ + int64_t t0 = esp_timer_get_time(); + int64_t t1 = 0; + + while (sdio_hw->cmd.start_command == 1) { + t1 = esp_timer_get_time(); + + if (t1 - t0 > SDMMC_HOST_START_CMD_TIMEOUT_US) { + return ESP_ERR_TIMEOUT; + } + if (t1 - t0 > yield_delay_us) { + yield_delay_us *= 2; + k_sleep(K_MSEC(1)); + } + } + + sdio_hw->cmdarg = arg; + cmd.card_num = slot; + cmd.start_command = 1; + sdio_hw->cmd = cmd; + + return ESP_OK; +} + +static void process_command_response(sdmmc_dev_t *sdio_hw, uint32_t status, + struct sdmmc_command *cmd) +{ + if (cmd->flags & SCF_RSP_PRESENT) { + if (cmd->flags & SCF_RSP_136) { + /* Destination is 4-byte aligned, can memcopy from peripheral registers */ + memcpy(cmd->response, (uint32_t *)sdio_hw->resp, 4 * sizeof(uint32_t)); + } else { + cmd->response[0] = sdio_hw->resp[0]; + cmd->response[1] = 0; + cmd->response[2] = 0; + cmd->response[3] = 0; + } + } + + int err = ESP_OK; + + if (status & SDMMC_INTMASK_RTO) { + /* response timeout is only possible when response is expected */ + if (!(cmd->flags & SCF_RSP_PRESENT)) { + return; + } + + err = ESP_ERR_TIMEOUT; + } else if ((cmd->flags & SCF_RSP_CRC) && (status & SDMMC_INTMASK_RCRC)) { + err = ESP_ERR_INVALID_CRC; + } else if (status & SDMMC_INTMASK_RESP_ERR) { + err = ESP_ERR_INVALID_RESPONSE; + } + + if (err != ESP_OK) { + cmd->error = err; + if (cmd->data) { + sdmmc_host_dma_stop(sdio_hw); + } + LOG_DBG("%s: error 0x%x (status=%08" PRIx32 ")", __func__, err, status); + } +} + +static void process_data_status(sdmmc_dev_t *sdio_hw, uint32_t status, struct sdmmc_command *cmd) +{ + if (status & SDMMC_DATA_ERR_MASK) { + if (status & SDMMC_INTMASK_DTO) { + cmd->error = ESP_ERR_TIMEOUT; + } else if (status & SDMMC_INTMASK_DCRC) { + cmd->error = ESP_ERR_INVALID_CRC; + } else if ((status & SDMMC_INTMASK_EBE) && (cmd->flags & SCF_CMD_READ) == 0) { + cmd->error = ESP_ERR_TIMEOUT; + } else { + cmd->error = ESP_FAIL; + } + sdio_hw->ctrl.fifo_reset = 1; + } + + if (cmd->error != 0) { + if (cmd->data) { + sdmmc_host_dma_stop(sdio_hw); + } + LOG_DBG("%s: error 0x%x (status=%08" PRIx32 ")", __func__, cmd->error, status); + } +} + +static inline bool mask_check_and_clear(uint32_t *state, uint32_t mask) +{ + bool ret = ((*state) & mask) != 0; + + *state &= ~mask; + + return ret; +} + +static size_t get_free_descriptors_count(struct sdhc_esp32_data *data) +{ + const size_t next = data->s_cur_transfer.next_desc; + size_t count = 0; + + /* Starting with the current DMA descriptor, count the number of + * descriptors which have 'owned_by_idmac' set to 0. These are the + * descriptors already processed by the DMA engine. + */ + for (size_t i = 0; i < SDMMC_DMA_DESC_CNT; ++i) { + sdmmc_desc_t *desc = &data->s_dma_desc[(next + i) % SDMMC_DMA_DESC_CNT]; + + if (desc->owned_by_idmac) { + break; + } + ++count; + if (desc->next_desc_ptr == NULL) { + /* final descriptor in the chain */ + break; + } + } + + return count; +} + +static int process_events(const struct device *dev, struct sdmmc_event evt, + struct sdmmc_command *cmd, enum sdmmc_req_state *pstate, + struct sdmmc_event *unhandled_events) +{ + const struct sdhc_esp32_config *cfg = dev->config; + struct sdhc_esp32_data *data = dev->data; + sdmmc_dev_t *sdio_hw = (sdmmc_dev_t *)cfg->sdio_hw; + + const char *const s_state_names[] + __attribute__((unused)) = {"IDLE", "SENDING_CMD", "SENDIND_DATA", "BUSY"}; + struct sdmmc_event orig_evt = evt; + + LOG_DBG("%s: state=%s evt=%" PRIx32 " dma=%" PRIx32, __func__, s_state_names[*pstate], + evt.sdmmc_status, evt.dma_status); + + enum sdmmc_req_state next_state = *pstate; + enum sdmmc_req_state state = (enum sdmmc_req_state) -1; + + while (next_state != state) { + + state = next_state; + + switch (state) { + + case SDMMC_IDLE: + break; + + case SDMMC_SENDING_CMD: + if (mask_check_and_clear(&evt.sdmmc_status, SDMMC_CMD_ERR_MASK)) { + process_command_response(sdio_hw, orig_evt.sdmmc_status, cmd); + /* + * In addition to the error interrupt, CMD_DONE will also be + * reported. It may occur immediately (in the same sdmmc_event_t) or + * be delayed until the next interrupt + */ + } + if (mask_check_and_clear(&evt.sdmmc_status, SDMMC_INTMASK_CMD_DONE)) { + process_command_response(sdio_hw, orig_evt.sdmmc_status, cmd); + if (cmd->error != ESP_OK) { + next_state = SDMMC_IDLE; + break; + } + + if (cmd->data == NULL) { + next_state = SDMMC_IDLE; + } else { + next_state = SDMMC_SENDING_DATA; + } + } + break; + + case SDMMC_SENDING_DATA: + if (mask_check_and_clear(&evt.sdmmc_status, SDMMC_DATA_ERR_MASK)) { + process_data_status(sdio_hw, orig_evt.sdmmc_status, cmd); + sdmmc_host_dma_stop(sdio_hw); + } + if (mask_check_and_clear(&evt.dma_status, SDMMC_DMA_DONE_MASK)) { + + data->s_cur_transfer.desc_remaining--; + + if (data->s_cur_transfer.size_remaining) { + + int desc_to_fill = get_free_descriptors_count(data); + + fill_dma_descriptors(data, desc_to_fill); + sdmmc_host_dma_resume(sdio_hw); + } + if (data->s_cur_transfer.desc_remaining == 0) { + next_state = SDMMC_BUSY; + } + } + if (orig_evt.sdmmc_status & (SDMMC_INTMASK_SBE | SDMMC_INTMASK_DATA_OVER)) { + /* On start bit error, DATA_DONE interrupt will not be generated */ + next_state = SDMMC_IDLE; + break; + } + break; + + case SDMMC_BUSY: + if (!mask_check_and_clear(&evt.sdmmc_status, SDMMC_INTMASK_DATA_OVER)) { + break; + } + process_data_status(sdio_hw, orig_evt.sdmmc_status, cmd); + next_state = SDMMC_IDLE; + break; + } + LOG_DBG("%s state=%s next_state=%s", __func__, s_state_names[state], + s_state_names[next_state]); + } + + *pstate = state; + *unhandled_events = evt; + + return ESP_OK; +} + +static int handle_event(const struct device *dev, struct sdmmc_command *cmd, + enum sdmmc_req_state *state, struct sdmmc_event *unhandled_events) +{ + const struct sdhc_esp32_config *cfg = dev->config; + struct sdhc_esp32_data *data = dev->data; + sdmmc_dev_t *sdio_hw = (sdmmc_dev_t *)cfg->sdio_hw; + struct sdmmc_event event; + + int err = sdmmc_host_wait_for_event(data, cmd->timeout_ms, &event); + + if (err != 0) { + LOG_ERR("sdmmc_handle_event: sdmmc_host_wait_for_event returned 0x%x, timeout %d " + "ms", + err, cmd->timeout_ms); + if (err == -EAGAIN) { + sdmmc_host_dma_stop(sdio_hw); + } + return err; + } + + LOG_DBG("sdmmc_handle_event: event %08" PRIx32 " %08" PRIx32 ", unhandled %08" PRIx32 + " %08" PRIx32, + event.sdmmc_status, event.dma_status, unhandled_events->sdmmc_status, + unhandled_events->dma_status); + + event.sdmmc_status |= unhandled_events->sdmmc_status; + event.dma_status |= unhandled_events->dma_status; + + process_events(dev, event, cmd, state, unhandled_events); + LOG_DBG("sdmmc_handle_event: events unhandled: %08" PRIx32 " %08" PRIx32, + unhandled_events->sdmmc_status, unhandled_events->dma_status); + + return ESP_OK; +} + +static bool wait_for_busy_cleared(const sdmmc_dev_t *sdio_hw, uint32_t timeout_ms) +{ + if (timeout_ms == 0) { + return !(sdio_hw->status.data_busy == 1); + } + + /* It would have been nice to do this without polling, however the peripheral + * can only generate Busy Clear Interrupt for data write commands, and waiting + * for busy clear is mostly needed for other commands such as MMC_SWITCH. + */ + uint32_t timeout_ticks = k_ms_to_ticks_ceil32(timeout_ms); + + while (timeout_ticks-- > 0) { + if (!(sdio_hw->status.data_busy == 1)) { + return true; + } + k_sleep(K_MSEC(1)); + } + + return false; +} + +static bool cmd_needs_auto_stop(const struct sdmmc_command *cmd) +{ + /* SDMMC host needs an "auto stop" flag for the following commands: */ + return cmd->datalen > 0 && + (cmd->opcode == SD_WRITE_MULTIPLE_BLOCK || cmd->opcode == SD_READ_MULTIPLE_BLOCK); +} + +static sdmmc_hw_cmd_t make_hw_cmd(struct sdmmc_command *cmd) +{ + sdmmc_hw_cmd_t res = {0}; + + res.cmd_index = cmd->opcode; + if (cmd->opcode == SD_STOP_TRANSMISSION) { + res.stop_abort_cmd = 1; + } else if (cmd->opcode == SD_GO_IDLE_STATE) { + res.send_init = 1; + } else { + res.wait_complete = 1; + } + if (cmd->opcode == SD_GO_IDLE_STATE) { + res.send_init = 1; + } + if (cmd->flags & SCF_RSP_PRESENT) { + res.response_expect = 1; + if (cmd->flags & SCF_RSP_136) { + res.response_long = 1; + } + } + if (cmd->flags & SCF_RSP_CRC) { + res.check_response_crc = 1; + } + if (cmd->data) { + res.data_expected = 1; + + if ((cmd->flags & SCF_CMD_READ) == 0) { + res.rw = 1; + } + + if ((cmd->datalen % cmd->blklen) != 0) { + return res; /* Error situation, data will be invalid */ + } + + res.send_auto_stop = cmd_needs_auto_stop(cmd) ? 1 : 0; + } + LOG_DBG("%s: opcode=%d, rexp=%d, crc=%d, auto_stop=%d", __func__, res.cmd_index, + res.response_expect, res.check_response_crc, res.send_auto_stop); + + return res; +} + +static int sdmmc_host_do_transaction(const struct device *dev, int slot, + struct sdmmc_command *cmdinfo) +{ + const struct sdhc_esp32_config *cfg = dev->config; + struct sdhc_esp32_data *data = dev->data; + sdmmc_dev_t *sdio_hw = (sdmmc_dev_t *)cfg->sdio_hw; + int ret; + + if (k_mutex_lock(&data->s_request_mutex, K_FOREVER) != 0) { + return ESP_ERR_NO_MEM; + } + + /* dispose of any events which happened asynchronously */ + handle_idle_state_events(data); + + /* convert cmdinfo to hardware register value */ + sdmmc_hw_cmd_t hw_cmd = make_hw_cmd(cmdinfo); + + if (cmdinfo->data) { + /* Length should be either <4 or >=4 and =0 (mod 4) */ + if ((cmdinfo->datalen >= 4) && (cmdinfo->datalen % 4) != 0) { + LOG_DBG("%s: invalid size: total=%d", __func__, cmdinfo->datalen); + ret = ESP_ERR_INVALID_SIZE; + goto out; + } + + if ((((intptr_t)cmdinfo->data % 4) != 0) || !esp_ptr_dma_capable(cmdinfo->data)) { + LOG_DBG("%s: buffer %p can not be used for DMA", __func__, cmdinfo->data); + ret = ESP_ERR_INVALID_ARG; + goto out; + } + + /* this clears "owned by IDMAC" bits */ + memset(data->s_dma_desc, 0, sizeof(data->s_dma_desc)); + + /* initialize first descriptor */ + data->s_dma_desc[0].first_descriptor = 1; + + /* save transfer info */ + data->s_cur_transfer.ptr = (uint8_t *)cmdinfo->data; + data->s_cur_transfer.size_remaining = cmdinfo->datalen; + data->s_cur_transfer.next_desc = 0; + data->s_cur_transfer.desc_remaining = + (cmdinfo->datalen + SDMMC_DMA_MAX_BUF_LEN - 1) / SDMMC_DMA_MAX_BUF_LEN; + + /* prepare descriptors */ + fill_dma_descriptors(data, SDMMC_DMA_DESC_CNT); + + /* write transfer info into hardware */ + sdmmc_host_dma_prepare(sdio_hw, &data->s_dma_desc[0], cmdinfo->blklen, + cmdinfo->datalen); + } + + /* write command into hardware, this also sends the command to the card */ + ret = sdmmc_host_start_command(sdio_hw, slot, hw_cmd, cmdinfo->arg); + + if (ret != ESP_OK) { + goto out; + } + + /* process events until transfer is complete */ + cmdinfo->error = ESP_OK; + + enum sdmmc_req_state state = SDMMC_SENDING_CMD; + struct sdmmc_event unhandled_events = {0}; + + while (state != SDMMC_IDLE) { + ret = handle_event(dev, cmdinfo, &state, &unhandled_events); + if (ret != 0) { + break; + } + } + + if (ret == 0 && (cmdinfo->flags & SCF_WAIT_BUSY)) { + if (!wait_for_busy_cleared(sdio_hw, cmdinfo->timeout_ms)) { + ret = ESP_ERR_TIMEOUT; + } + } + + data->s_is_app_cmd = (ret == ESP_OK && cmdinfo->opcode == SD_APP_CMD); + +out: + + k_mutex_unlock(&data->s_request_mutex); + + return ret; +} + +static int sdmmc_host_clock_update_command(sdmmc_dev_t *sdio_hw, int slot) +{ + int ret; + bool repeat = true; + + /* Clock update command (not a real command; just updates CIU registers) */ + sdmmc_hw_cmd_t cmd_val = {.card_num = slot, .update_clk_reg = 1, .wait_complete = 1}; + + while (repeat) { + + ret = sdmmc_host_start_command(sdio_hw, slot, cmd_val, 0); + + if (ret != 0) { + return ret; + } + + int64_t yield_delay_us = 100 * 1000; /* initially 100ms */ + int64_t t0 = esp_timer_get_time(); + int64_t t1 = 0; + + while (true) { + t1 = esp_timer_get_time(); + + if (t1 - t0 > SDMMC_HOST_CLOCK_UPDATE_CMD_TIMEOUT_US) { + return ESP_ERR_TIMEOUT; + } + /* Sending clock update command to the CIU can generate HLE error */ + /* According to the manual, this is okay and we must retry the command */ + if (sdio_hw->rintsts.hle) { + sdio_hw->rintsts.hle = 1; + repeat = true; + break; + } + /* When the command is accepted by CIU, start_command bit will be */ + /* cleared in sdio_hw->cmd register */ + if (sdio_hw->cmd.start_command == 0) { + repeat = false; + break; + } + if (t1 - t0 > yield_delay_us) { + yield_delay_us *= 2; + k_sleep(K_MSEC(1)); + } + } + } + + return 0; +} + +void sdmmc_host_get_clk_dividers(uint32_t freq_khz, int *host_div, int *card_div) +{ + uint32_t clk_src_freq_hz = 0; + + esp_clk_tree_src_get_freq_hz(SDMMC_CLK_SRC_DEFAULT, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, + &clk_src_freq_hz); + assert(clk_src_freq_hz == (160 * 1000 * 1000)); + + /* Calculate new dividers */ + if (freq_khz >= SDMMC_FREQ_HIGHSPEED) { + *host_div = 4; /* 160 MHz / 4 = 40 MHz */ + *card_div = 0; + } else if (freq_khz == SDMMC_FREQ_DEFAULT) { + *host_div = 8; /* 160 MHz / 8 = 20 MHz */ + *card_div = 0; + } else if (freq_khz == SDMMC_FREQ_PROBING) { + *host_div = 10; /* 160 MHz / 10 / (20 * 2) = 400 kHz */ + *card_div = 20; + } else { + /* + * for custom frequencies use maximum range of host divider (1-16), find the closest + * <= div. combination if exceeded, combine with the card divider to keep reasonable + * precision (applies mainly to low frequencies) effective frequency range: 400 kHz + * - 32 MHz (32.1 - 39.9 MHz cannot be covered with given divider scheme) + */ + *host_div = (clk_src_freq_hz) / (freq_khz * 1000); + if (*host_div > 15) { + *host_div = 2; + *card_div = (clk_src_freq_hz / 2) / (2 * freq_khz * 1000); + if (((clk_src_freq_hz / 2) % (2 * freq_khz * 1000)) > 0) { + (*card_div)++; + } + } else if ((clk_src_freq_hz % (freq_khz * 1000)) > 0) { + (*host_div)++; + } + } +} + +static int sdmmc_host_calc_freq(const int host_div, const int card_div) +{ + uint32_t clk_src_freq_hz = 0; + + esp_clk_tree_src_get_freq_hz(SDMMC_CLK_SRC_DEFAULT, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, + &clk_src_freq_hz); + assert(clk_src_freq_hz == (160 * 1000 * 1000)); + + return clk_src_freq_hz / host_div / ((card_div == 0) ? 1 : card_div * 2) / 1000; +} + +int sdmmc_host_set_card_clk(sdmmc_dev_t *sdio_hw, int slot, uint32_t freq_khz) +{ + if (!(slot == 0 || slot == 1)) { + return ESP_ERR_INVALID_ARG; + } + + /* Disable clock first */ + sdmmc_ll_enable_card_clock(sdio_hw, slot, false); + int err = sdmmc_host_clock_update_command(sdio_hw, slot); + + if (err != 0) { + LOG_ERR("disabling clk failed"); + LOG_ERR("%s: sdmmc_host_clock_update_command returned 0x%x", __func__, err); + return err; + } + + int host_div = 0; /* clock divider of the host (sdio_hw->clock) */ + int card_div = 0; /* 1/2 of card clock divider (sdio_hw->clkdiv) */ + + sdmmc_host_get_clk_dividers(freq_khz, &host_div, &card_div); + + int real_freq = sdmmc_host_calc_freq(host_div, card_div); + + LOG_DBG("slot=%d host_div=%d card_div=%d freq=%dkHz (max %" PRIu32 "kHz)", slot, host_div, + card_div, real_freq, freq_khz); + + /* Program card clock settings, send them to the CIU */ + sdmmc_ll_set_card_clock_div(sdio_hw, slot, card_div); + err = sdmmc_host_set_clk_div(sdio_hw, host_div); + + if (err != 0) { + return err; + } + + err = sdmmc_host_clock_update_command(sdio_hw, slot); + + if (err != 0) { + LOG_ERR("setting clk div failed"); + LOG_ERR("%s: sdmmc_host_clock_update_command returned 0x%x", __func__, err); + return err; + } + + /* Re-enable clocks */ + sdmmc_ll_enable_card_clock(sdio_hw, slot, true); + sdmmc_ll_enable_card_clock_low_power(sdio_hw, slot, true); + + err = sdmmc_host_clock_update_command(sdio_hw, slot); + + if (err != 0) { + LOG_ERR("re-enabling clk failed"); + LOG_ERR("%s: sdmmc_host_clock_update_command returned 0x%x", __func__, err); + return err; + } + + /* set data timeout */ + const uint32_t data_timeout_ms = 100; + uint32_t data_timeout_cycles = data_timeout_ms * freq_khz; + + sdmmc_ll_set_data_timeout(sdio_hw, data_timeout_cycles); + /* always set response timeout to highest value, it's small enough anyway */ + sdmmc_ll_set_response_timeout(sdio_hw, 255); + + return 0; +} + +int sdmmc_host_set_bus_width(sdmmc_dev_t *sdio_hw, int slot, size_t width) +{ + if (!(slot == 0 || slot == 1)) { + return ESP_ERR_INVALID_ARG; + } + + const uint16_t mask = BIT(slot); + uint16_t temp; + + if (width == 1) { + temp = sdio_hw->ctype.card_width_8 & ~mask; + HAL_FORCE_MODIFY_U32_REG_FIELD(sdio_hw->ctype, card_width_8, temp); + + temp = sdio_hw->ctype.card_width & ~mask; + HAL_FORCE_MODIFY_U32_REG_FIELD(sdio_hw->ctype, card_width, temp); + + } else if (width == 4) { + temp = sdio_hw->ctype.card_width_8 & ~mask; + HAL_FORCE_MODIFY_U32_REG_FIELD(sdio_hw->ctype, card_width_8, temp); + + temp = sdio_hw->ctype.card_width | mask; + HAL_FORCE_MODIFY_U32_REG_FIELD(sdio_hw->ctype, card_width, temp); + } else if (width == 8) { + temp = sdio_hw->ctype.card_width_8 | mask; + HAL_FORCE_MODIFY_U32_REG_FIELD(sdio_hw->ctype, card_width_8, temp); + } else { + return ESP_ERR_INVALID_ARG; + } + + LOG_DBG("slot=%d width=%d", slot, width); + return ESP_OK; +} + +static void configure_pin_iomux(int gpio_num) +{ + const int sdmmc_func = SDMMC_LL_IOMUX_FUNC; + const int drive_strength = 3; + + if (gpio_num == GPIO_NUM_NC) { + return; /* parameter check*/ + } + + int rtc_num = rtc_io_num_map[gpio_num]; + + rtcio_hal_pulldown_disable(rtc_num); + rtcio_hal_pullup_enable(rtc_num); + + uint32_t reg = GPIO_PIN_MUX_REG[gpio_num]; + + PIN_INPUT_ENABLE(reg); + gpio_hal_iomux_func_sel(reg, sdmmc_func); + PIN_SET_DRV(reg, drive_strength); +} + +/********************************************************************** + * Zephyr API + **********************************************************************/ + +/* + * Reset USDHC controller + */ +static int sdhc_esp32_reset(const struct device *dev) +{ + const struct sdhc_esp32_config *cfg = dev->config; + sdmmc_dev_t *sdio_hw = (sdmmc_dev_t *)cfg->sdio_hw; + + /* Set reset bits */ + sdio_hw->ctrl.controller_reset = 1; + sdio_hw->ctrl.dma_reset = 1; + sdio_hw->ctrl.fifo_reset = 1; + + /* Wait for the reset bits to be cleared by hardware */ + int64_t yield_delay_us = 100 * 1000; /* initially 100ms */ + int64_t t0 = esp_timer_get_time(); + int64_t t1 = 0; + + while (sdio_hw->ctrl.controller_reset || sdio_hw->ctrl.fifo_reset || + sdio_hw->ctrl.dma_reset) { + t1 = esp_timer_get_time(); + + if (t1 - t0 > SDMMC_HOST_RESET_TIMEOUT_US) { + return -ETIMEDOUT; + } + + if (t1 - t0 > yield_delay_us) { + yield_delay_us *= 2; + k_busy_wait(1); + } + } + + /* Reset carried out successfully */ + return 0; +} + +/* + * Set SDHC io properties + */ +static int sdhc_esp32_set_io(const struct device *dev, struct sdhc_io *ios) +{ + const struct sdhc_esp32_config *cfg = dev->config; + sdmmc_dev_t *sdio_hw = (sdmmc_dev_t *)cfg->sdio_hw; + struct sdhc_esp32_data *data = dev->data; + uint8_t bus_width; + int ret = 0; + + LOG_INF("SDHC I/O: slot: %d, bus width %d, clock %dHz, card power %s, voltage %s", + cfg->slot, ios->bus_width, ios->clock, + ios->power_mode == SDHC_POWER_ON ? "ON" : "OFF", + ios->signal_voltage == SD_VOL_1_8_V ? "1.8V" : "3.3V"); + + if (ios->clock) { + /* Check for frequency boundaries supported by host */ + if (ios->clock > cfg->props.f_max || ios->clock < cfg->props.f_min) { + LOG_ERR("Proposed clock outside supported host range"); + return -EINVAL; + } + + if (data->bus_clock != (uint32_t)ios->clock) { + /* Try setting new clock */ + ret = sdmmc_host_set_card_clk(sdio_hw, cfg->slot, (ios->clock / 1000)); + + if (ret == 0) { + LOG_INF("Bus clock successfully set to %d kHz", ios->clock / 1000); + } else { + LOG_ERR("Error configuring card clock"); + return err_esp2zep(ret); + } + + data->bus_clock = (uint32_t)ios->clock; + } + } + + if (ios->bus_width > 0) { + /* Set bus width */ + switch (ios->bus_width) { + case SDHC_BUS_WIDTH1BIT: + bus_width = 1; + break; + case SDHC_BUS_WIDTH4BIT: + bus_width = 4; + break; + default: + return -ENOTSUP; + } + + if (data->bus_width != bus_width) { + ret = sdmmc_host_set_bus_width(sdio_hw, cfg->slot, bus_width); + + if (ret == 0) { + LOG_INF("Bus width set successfully to %d bit", bus_width); + } else { + LOG_ERR("Error configuring bus width"); + return err_esp2zep(ret); + } + + data->bus_width = bus_width; + } + } + + /* Toggle card power supply */ + if ((data->power_mode != ios->power_mode) && (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); + } + data->power_mode = ios->power_mode; + } + + if (ios->timing > 0) { + /* Set I/O timing */ + if (data->timing != ios->timing) { + switch (ios->timing) { + case SDHC_TIMING_LEGACY: + case SDHC_TIMING_HS: + sdmmc_ll_enable_ddr_mode(sdio_hw, cfg->slot, false); + break; + case SDHC_TIMING_DDR50: + case SDHC_TIMING_DDR52: + /* Enable DDR mode */ + sdmmc_ll_enable_ddr_mode(sdio_hw, cfg->slot, true); + LOG_INF("DDR mode enabled"); + break; + case SDHC_TIMING_SDR12: + case SDHC_TIMING_SDR25: + sdmmc_ll_enable_ddr_mode(sdio_hw, cfg->slot, false); + break; + case SDHC_TIMING_SDR50: + case SDHC_TIMING_HS400: + case SDHC_TIMING_SDR104: + case SDHC_TIMING_HS200: + default: + LOG_ERR("Timing mode not supported for this device"); + ret = -ENOTSUP; + break; + } + + LOG_INF("Bus timing successfully changed to %s", timingStr[ios->timing]); + data->timing = ios->timing; + } + } + + return ret; +} + +/* + * Return 0 if card is not busy, 1 if it is + */ +static int sdhc_esp32_card_busy(const struct device *dev) +{ + const struct sdhc_esp32_config *cfg = dev->config; + const sdmmc_dev_t *sdio_hw = cfg->sdio_hw; + + return (sdio_hw->status.data_busy == 1); +} + +/* + * Send CMD or CMD/DATA via SDHC + */ +static int sdhc_esp32_request(const struct device *dev, struct sdhc_command *cmd, + struct sdhc_data *data) +{ + const struct sdhc_esp32_config *cfg = dev->config; + const sdmmc_dev_t *sdio_hw = cfg->sdio_hw; + int retries = (int)(cmd->retries + 1); /* first try plus retries */ + uint32_t timeout_cfg; + int ret_esp; + int ret = 0; + + /* convert command structures Zephyr vs ESP */ + struct sdmmc_command esp_cmd = { + .opcode = cmd->opcode, + .arg = cmd->arg, + }; + + if (data) { + esp_cmd.data = data->data; + esp_cmd.blklen = data->block_size; + esp_cmd.datalen = (data->blocks * data->block_size); + esp_cmd.buflen = esp_cmd.datalen; + timeout_cfg = data->timeout_ms; + } else { + timeout_cfg = cmd->timeout_ms; + } + + /* setting timeout according to command type */ + if (cmd->timeout_ms == SDHC_TIMEOUT_FOREVER) { + esp_cmd.timeout_ms = SDMMC_TIMEOUT_MAX; + } else { + esp_cmd.timeout_ms = timeout_cfg; + } + + /* + * Handle flags and arguments with ESP32 specifics + */ + switch (cmd->opcode) { + case SD_GO_IDLE_STATE: + esp_cmd.flags = SCF_CMD_BC | SCF_RSP_R0; + break; + + case SD_APP_CMD: + case SD_SEND_STATUS: + case SD_SET_BLOCK_SIZE: + esp_cmd.flags = SCF_CMD_AC | SCF_RSP_R1; + break; + + case SD_SEND_IF_COND: + esp_cmd.flags = SCF_CMD_BCR | SCF_RSP_R7; + break; + + case SD_APP_SEND_OP_COND: + esp_cmd.flags = SCF_CMD_BCR | SCF_RSP_R3; + esp_cmd.arg = SD_OCR_SDHC_CAP | SD_OCR_VOL_MASK; + break; + + case SDIO_RW_DIRECT: + esp_cmd.flags = SCF_CMD_AC | SCF_RSP_R5; + break; + + case SDIO_SEND_OP_COND: + esp_cmd.flags = SCF_CMD_BCR | SCF_RSP_R4; + break; + + case SD_ALL_SEND_CID: + esp_cmd.flags = SCF_CMD_BCR | SCF_RSP_R2; + break; + + case SD_SEND_RELATIVE_ADDR: + esp_cmd.flags = SCF_CMD_BCR | SCF_RSP_R6; + break; + + case SD_SEND_CSD: + esp_cmd.flags = SCF_CMD_AC | SCF_RSP_R2; + esp_cmd.datalen = 0; + break; + + case SD_SELECT_CARD: + /* Don't expect to see a response when de-selecting a card */ + esp_cmd.flags = SCF_CMD_AC | (cmd->arg > 0 ? SCF_RSP_R1 : 0); + break; + + case SD_APP_SEND_SCR: + case SD_SWITCH: + case SD_READ_SINGLE_BLOCK: + case SD_READ_MULTIPLE_BLOCK: + case SD_APP_SEND_NUM_WRITTEN_BLK: + esp_cmd.flags = SCF_CMD_ADTC | SCF_CMD_READ | SCF_RSP_R1; + break; + + case SD_WRITE_SINGLE_BLOCK: + case SD_WRITE_MULTIPLE_BLOCK: + esp_cmd.flags = SCF_CMD_ADTC | SCF_RSP_R1; + break; + + default: + LOG_INF("SDHC driver: command %u not supported", cmd->opcode); + return -ENOTSUP; + } + + while (retries > 0) { + + ret_esp = sdmmc_host_do_transaction(dev, cfg->slot, &esp_cmd); + + if (ret_esp) { + retries--; /* error, retry */ + } else { + break; + } + } + + if ((ret_esp != 0) || esp_cmd.error) { + LOG_DBG("\nError for command: %u arg %08x ret_esp = 0x%x error = 0x%x\n", + cmd->opcode, cmd->arg, ret_esp, esp_cmd.error); + + ret_esp = (ret_esp > 0) ? ret_esp : esp_cmd.error; + + ret = err_esp2zep(ret_esp); + } else { + /* fill response buffer */ + memcpy(cmd->response, esp_cmd.response, sizeof(cmd->response)); + + int state = MMC_R1_CURRENT_STATE(esp_cmd.response); + + LOG_DBG("cmd %u arg %08x response %08x %08x %08x %08x err=0x%x state=%d", + esp_cmd.opcode, esp_cmd.arg, esp_cmd.response[0], esp_cmd.response[1], + esp_cmd.response[2], esp_cmd.response[3], esp_cmd.error, state); + + if (data) { + /* Record number of bytes xfered */ + data->bytes_xfered = esp_cmd.datalen; + } + } + + return ret; +} + +/* + * Get card presence + */ +static int sdhc_esp32_get_card_present(const struct device *dev) +{ + const struct sdhc_esp32_config *cfg = dev->config; + sdmmc_dev_t *sdio_hw = (sdmmc_dev_t *)cfg->sdio_hw; + + return sdmmc_ll_is_card_detected(sdio_hw, cfg->slot); +} + +/* + * Get host properties + */ +static int sdhc_esp32_get_host_props(const struct device *dev, struct sdhc_host_props *props) +{ + const struct sdhc_esp32_config *cfg = dev->config; + + memcpy(props, &cfg->props, sizeof(struct sdhc_host_props)); + return 0; +} + +/** + * @brief SDMMC interrupt handler + * + * All communication in SD protocol is driven by the master, and the hardware + * handles things like stop commands automatically. + * So the interrupt handler doesn't need to do much, we just push interrupt + * status into a queue, clear interrupt flags, and let the task currently + * doing communication figure out what to do next. + * + * Card detect interrupts pose a small issue though, because if a card is + * plugged in and out a few times, while there is no task to process + * the events, event queue can become full and some card detect events + * may be dropped. We ignore this problem for now, since the there are no other + * interesting events which can get lost due to this. + */ +static void IRAM_ATTR sdio_esp32_isr(void *arg) +{ + const struct device *dev = (const struct device *)arg; + const struct sdhc_esp32_config *cfg = dev->config; + struct sdhc_esp32_data *data = dev->data; + sdmmc_dev_t *sdio_hw = (sdmmc_dev_t *)cfg->sdio_hw; + + struct sdmmc_event event; + struct k_msgq *queue = data->s_host_ctx.event_queue; + uint32_t pending = sdmmc_ll_get_intr_status(sdio_hw) & 0xFFFF; + + sdio_hw->rintsts.val = pending; + event.sdmmc_status = pending; + + uint32_t dma_pending = sdio_hw->idsts.val; + + sdio_hw->idsts.val = dma_pending; + event.dma_status = dma_pending & 0x1f; + + if ((pending != 0) || (dma_pending != 0)) { + k_msgq_put(queue, &event, K_NO_WAIT); + } +} + +/* + * Perform early system init for SDHC + */ +static int sdhc_esp32_init(const struct device *dev) +{ + const struct sdhc_esp32_config *cfg = dev->config; + struct sdhc_esp32_data *data = dev->data; + sdmmc_dev_t *sdio_hw = (sdmmc_dev_t *)cfg->sdio_hw; + int ret; + + /* Pin configuration */ + + /* Set power GPIO high, so card starts powered */ + if (cfg->pwr_gpio.port) { + ret = gpio_pin_configure_dt(&cfg->pwr_gpio, GPIO_OUTPUT_ACTIVE); + + if (ret) { + return -EIO; + } + } + + /* + * Pins below are only defined for ESP32. For SoC's with GPIO matrix feature + * please use pinctrl for pin configuration. + */ + configure_pin_iomux(cfg->clk_pin); + configure_pin_iomux(cfg->cmd_pin); + configure_pin_iomux(cfg->d0_pin); + configure_pin_iomux(cfg->d1_pin); + configure_pin_iomux(cfg->d2_pin); + configure_pin_iomux(cfg->d3_pin); + + ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT); + + if (ret < 0) { + LOG_ERR("Failed to configure SDHC pins"); + return -EINVAL; + } + + /* enable bus clock for registers */ + sdmmc_ll_enable_bus_clock(sdio_hw, true); + sdmmc_ll_reset_register(sdio_hw); + + /* Enable clock to peripheral. Use smallest divider first */ + ret = sdmmc_host_set_clk_div(sdio_hw, 2); + + if (ret != 0) { + return err_esp2zep(ret); + } + + /* Reset controller */ + sdhc_esp32_reset(dev); + + /* Clear interrupt status and set interrupt mask to known state */ + sdio_hw->rintsts.val = 0xffffffff; + sdio_hw->intmask.val = 0; + sdio_hw->ctrl.int_enable = 0; + + /* Attach interrupt handler */ + ret = esp_intr_alloc(cfg->irq_source, 0, &sdio_esp32_isr, (void *)dev, + &data->s_host_ctx.intr_handle); + + if (ret != 0) { + k_msgq_purge(data->s_host_ctx.event_queue); + return -EFAULT; + } + + /* Enable interrupts */ + sdio_hw->intmask.val = SDMMC_INTMASK_CD | SDMMC_INTMASK_CMD_DONE | SDMMC_INTMASK_DATA_OVER | + SDMMC_INTMASK_RCRC | SDMMC_INTMASK_DCRC | SDMMC_INTMASK_RTO | + SDMMC_INTMASK_DTO | SDMMC_INTMASK_HTO | SDMMC_INTMASK_SBE | + SDMMC_INTMASK_EBE | SDMMC_INTMASK_RESP_ERR | + SDMMC_INTMASK_HLE; /* sdio is enabled only when use */ + + sdio_hw->ctrl.int_enable = 1; + + /* Disable generation of Busy Clear Interrupt */ + sdio_hw->cardthrctl.busy_clr_int_en = 0; + + /* Enable DMA */ + sdmmc_host_dma_init(sdio_hw); + + /* Initialize transaction handler */ + ret = sdmmc_host_transaction_handler_init(data); + + if (ret != 0) { + k_msgq_purge(data->s_host_ctx.event_queue); + esp_intr_free(data->s_host_ctx.intr_handle); + data->s_host_ctx.intr_handle = NULL; + + return ret; + } + + /* post init settings */ + ret = sdmmc_host_set_card_clk(sdio_hw, cfg->slot, data->bus_clock / 1000); + + if (ret != 0) { + LOG_ERR("Error configuring card clock"); + return err_esp2zep(ret); + } + + ret = sdmmc_host_set_bus_width(sdio_hw, cfg->slot, data->bus_width); + + if (ret != 0) { + LOG_ERR("Error configuring bus width"); + return err_esp2zep(ret); + } + + return 0; +} + +static const struct sdhc_driver_api sdhc_api = {.reset = sdhc_esp32_reset, + .request = sdhc_esp32_request, + .set_io = sdhc_esp32_set_io, + .get_card_present = sdhc_esp32_get_card_present, + .card_busy = sdhc_esp32_card_busy, + .get_host_props = sdhc_esp32_get_host_props}; + +#define SDHC_ESP32_INIT(n) \ + \ + PINCTRL_DT_DEFINE(DT_DRV_INST(n)); \ + K_MSGQ_DEFINE(sdhc##n##_queue, sizeof(struct sdmmc_event), SDMMC_EVENT_QUEUE_LENGTH, 1); \ + \ + static const struct sdhc_esp32_config sdhc_esp32_##n##_config = { \ + .sdio_hw = (const sdmmc_dev_t *)DT_REG_ADDR(DT_INST_PARENT(n)), \ + .irq_source = DT_IRQN(DT_INST_PARENT(n)), \ + .slot = DT_REG_ADDR(DT_DRV_INST(n)), \ + .bus_width_cfg = DT_INST_PROP(n, bus_width), \ + .pcfg = PINCTRL_DT_DEV_CONFIG_GET(DT_DRV_INST(n)), \ + .pwr_gpio = GPIO_DT_SPEC_INST_GET_OR(n, pwr_gpios, {0}), \ + .clk_pin = DT_INST_PROP_OR(n, clk_pin, GPIO_NUM_NC), \ + .cmd_pin = DT_INST_PROP_OR(n, cmd_pin, GPIO_NUM_NC), \ + .d0_pin = DT_INST_PROP_OR(n, d0_pin, GPIO_NUM_NC), \ + .d1_pin = DT_INST_PROP_OR(n, d1_pin, GPIO_NUM_NC), \ + .d2_pin = DT_INST_PROP_OR(n, d2_pin, GPIO_NUM_NC), \ + .d3_pin = DT_INST_PROP_OR(n, d3_pin, GPIO_NUM_NC), \ + .props = {.is_spi = false, \ + .f_max = DT_INST_PROP(n, max_bus_freq), \ + .f_min = DT_INST_PROP(n, min_bus_freq), \ + .max_current_330 = DT_INST_PROP(n, max_current_330), \ + .max_current_180 = DT_INST_PROP(n, max_current_180), \ + .power_delay = DT_INST_PROP_OR(n, power_delay_ms, 0), \ + .host_caps = {.vol_180_support = false, \ + .vol_300_support = false, \ + .vol_330_support = true, \ + .suspend_res_support = false, \ + .sdma_support = true, \ + .high_spd_support = \ + (DT_INST_PROP(n, bus_width) == 4) ? true : false, \ + .adma_2_support = false, \ + .max_blk_len = 0, \ + .ddr50_support = false, \ + .sdr104_support = false, \ + .sdr50_support = false, \ + .bus_8_bit_support = false, \ + .bus_4_bit_support = \ + (DT_INST_PROP(n, bus_width) == 4) ? true : false, \ + .hs200_support = false, \ + .hs400_support = false}}}; \ + \ + static struct sdhc_esp32_data sdhc_esp32_##n##_data = { \ + .bus_width = SDMMC_SLOT_WIDTH_DEFAULT, \ + .bus_clock = (SDMMC_FREQ_PROBING * 1000), \ + .power_mode = SDHC_POWER_ON, \ + .timing = SDHC_TIMING_LEGACY, \ + .s_host_ctx = {.event_queue = &sdhc##n##_queue}}; \ + \ + DEVICE_DT_INST_DEFINE(n, &sdhc_esp32_init, NULL, &sdhc_esp32_##n##_data, \ + &sdhc_esp32_##n##_config, POST_KERNEL, CONFIG_SDHC_INIT_PRIORITY, \ + &sdhc_api); + +DT_INST_FOREACH_STATUS_OKAY(SDHC_ESP32_INIT) + +BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 1, + "Currently, only one espressif,esp32-sdhc-slot compatible node is supported"); diff --git a/drivers/sdhc/sdhc_esp32.h b/drivers/sdhc/sdhc_esp32.h new file mode 100644 index 00000000000..7b7b8574ff1 --- /dev/null +++ b/drivers/sdhc/sdhc_esp32.h @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2024 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define SDMMC_FREQ_DEFAULT 20000 /*!< SD/MMC Default speed (limited by clock divider) */ +#define SDMMC_FREQ_HIGHSPEED 40000 /*!< SD High speed (limited by clock divider) */ +#define SDMMC_FREQ_PROBING 400 /*!< SD/MMC probing speed */ +#define SDMMC_FREQ_52M 52000 /*!< MMC 52MHz speed */ +#define SDMMC_FREQ_26M 26000 /*!< MMC 26MHz speed */ + +#define SDMMC_DATA_ERR_MASK \ + (uint32_t)(SDMMC_INTMASK_DTO | SDMMC_INTMASK_DCRC | SDMMC_INTMASK_HTO | \ + SDMMC_INTMASK_SBE | SDMMC_INTMASK_EBE) + +#define SDMMC_DMA_DONE_MASK \ + (uint32_t)(SDMMC_IDMAC_INTMASK_RI | SDMMC_IDMAC_INTMASK_TI | SDMMC_IDMAC_INTMASK_NI) + +#define SDMMC_CMD_ERR_MASK \ + (uint32_t)(SDMMC_INTMASK_RTO | SDMMC_INTMASK_RCRC | SDMMC_INTMASK_RESP_ERR) + +enum sdmmc_req_state { + SDMMC_IDLE, + SDMMC_SENDING_CMD, + SDMMC_SENDING_DATA, + SDMMC_BUSY, +}; + +/* SDHC command flags */ +#define SCF_ITSDONE 0x0001 /*!< command is complete */ +#define SCF_CMD(flags) ((flags) & 0x00f0) +#define SCF_CMD_AC 0x0000 +#define SCF_CMD_ADTC 0x0010 +#define SCF_CMD_BC 0x0020 +#define SCF_CMD_BCR 0x0030 +#define SCF_CMD_READ 0x0040 /*!< read command (data expected) */ +#define SCF_RSP_BSY 0x0100 +#define SCF_RSP_136 0x0200 +#define SCF_RSP_CRC 0x0400 +#define SCF_RSP_IDX 0x0800 +#define SCF_RSP_PRESENT 0x1000 +/* response types */ +#define SCF_RSP_R0 0 /*!< none */ +#define SCF_RSP_R1 (SCF_RSP_PRESENT | SCF_RSP_CRC | SCF_RSP_IDX) +#define SCF_RSP_R1B (SCF_RSP_PRESENT | SCF_RSP_CRC | SCF_RSP_IDX | SCF_RSP_BSY) +#define SCF_RSP_R2 (SCF_RSP_PRESENT | SCF_RSP_CRC | SCF_RSP_136) +#define SCF_RSP_R3 (SCF_RSP_PRESENT) +#define SCF_RSP_R4 (SCF_RSP_PRESENT) +#define SCF_RSP_R5 (SCF_RSP_PRESENT | SCF_RSP_CRC | SCF_RSP_IDX) +#define SCF_RSP_R5B (SCF_RSP_PRESENT | SCF_RSP_CRC | SCF_RSP_IDX | SCF_RSP_BSY) +#define SCF_RSP_R6 (SCF_RSP_PRESENT | SCF_RSP_CRC | SCF_RSP_IDX) +#define SCF_RSP_R7 (SCF_RSP_PRESENT | SCF_RSP_CRC | SCF_RSP_IDX) +/* special flags */ +#define SCF_WAIT_BUSY 0x2000 /*!< Wait for completion of card busy signal before returning */ + +#define SD_OCR_SDHC_CAP (1 << 30) +#define SD_OCR_VOL_MASK 0xFF8000 /* bits 23:15 */ + +/* For debug only */ +static const char *const timingStr[] = {"UNKNOWN", "LEGACY", "HS", "SDR12", "SDR25", "SDR50", + "SDR104", "DDR50", "DDR52", "HS200", "HS400"}; + +struct sdmmc_transfer_state { + uint8_t *ptr; + size_t size_remaining; + size_t next_desc; + size_t desc_remaining; +}; + +struct sdmmc_event { + uint32_t header_DUMMY; /* Reserved for system use (Zephyr message queue) */ + uint32_t sdmmc_status; /* masked SDMMC interrupt status */ + uint32_t dma_status; /* masked DMA interrupt status */ +}; + +/** + * Host contexts + */ +struct host_ctx { + intr_handle_t intr_handle; + struct k_msgq *event_queue; +}; + +/** + * SD/MMC command information + */ +struct sdmmc_command { + uint32_t opcode; /*!< SD or MMC command index */ + uint32_t arg; /*!< SD/MMC command argument */ + uint32_t response[4]; /*!< response buffer */ + void *data; /*!< buffer to send or read into */ + size_t datalen; /*!< length of data in the buffer */ + size_t buflen; /*!< length of the buffer */ + size_t blklen; /*!< block length */ + int flags; /*!< see below */ + esp_err_t error; /*!< error returned from transfer */ + uint32_t timeout_ms; /*!< response timeout, in milliseconds */ +}; + +/** + * @brief Convert ESP to Zephyr error codes + * + * @param ret_esp ESP return value + * + * @return Zephyr error code + */ +static __attribute__((always_inline)) inline int err_esp2zep(int ret_esp) +{ + int ret; + + switch (ret_esp) { + /* Treating the error codes most relevant to be individuated */ + case ESP_ERR_INVALID_ARG: + ret = -EINVAL; + break; + case ESP_ERR_TIMEOUT: + ret = -ETIMEDOUT; + break; + case ESP_ERR_NOT_FOUND: + ret = -ENODEV; /* SD card not inserted (requires CD signal) */ + break; + case ESP_ERR_INVALID_STATE: + ret = -EACCES; /* SD card write-protected (requires WP sinal) */ + break; + default: + ret = -EIO; + break; + } + + return ret; +} diff --git a/drivers/sdhc/sdhc_spi.c b/drivers/sdhc/sdhc_spi.c index 7462e711dcd..7e7e22b9f17 100644 --- a/drivers/sdhc/sdhc_spi.c +++ b/drivers/sdhc/sdhc_spi.c @@ -1,5 +1,5 @@ /* - * Copyright 2022 NXP + * Copyright 2022,2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -143,6 +143,7 @@ static int sdhc_spi_init_card(const struct device *dev) spi_cfg->operation |= SPI_CS_ACTIVE_HIGH; ret = sdhc_spi_rx(config->spi_dev, spi_cfg, data->scratch, 10); if (ret != 0) { + spi_release(config->spi_dev, spi_cfg); spi_cfg->operation &= ~SPI_CS_ACTIVE_HIGH; return ret; } @@ -603,7 +604,7 @@ static int sdhc_spi_request(const struct device *dev, { const struct sdhc_spi_config *config = dev->config; struct sdhc_spi_data *dev_data = dev->data; - int ret, retries = cmd->retries; + int ret, stop_ret, retries = cmd->retries; const struct sdhc_command stop_cmd = { .opcode = SD_STOP_TRANSMISSION, .arg = 0, @@ -617,6 +618,7 @@ static int sdhc_spi_request(const struct device *dev, } while ((ret != 0) && (retries-- > 0)); } else { do { + retries--; ret = sdhc_spi_send_cmd(dev, cmd, true); if (ret) { continue; @@ -628,16 +630,27 @@ static int sdhc_spi_request(const struct device *dev, ret = sdhc_spi_read_data(dev, data); } if (ret || (cmd->opcode == SD_READ_MULTIPLE_BLOCK)) { + int stop_retries = cmd->retries; + /* CMD12 is required after multiple read, or * to retry failed transfer */ - sdhc_spi_send_cmd(dev, + stop_ret = sdhc_spi_send_cmd(dev, (struct sdhc_command *)&stop_cmd, false); + while ((stop_ret != 0) && (stop_retries > 0)) { + /* Retry stop command */ + ret = stop_ret = sdhc_spi_send_cmd(dev, + (struct sdhc_command *)&stop_cmd, + false); + stop_retries--; + } } - } while ((ret != 0) && (retries-- > 0)); + } while ((ret != 0) && (retries > 0)); } if (ret) { + /* Release SPI bus */ + spi_release(config->spi_dev, dev_data->spi_cfg); return ret; } /* Release SPI bus */ diff --git a/drivers/sensor/CMakeLists.txt b/drivers/sensor/CMakeLists.txt index 78051027fce..76a8cff9b96 100644 --- a/drivers/sensor/CMakeLists.txt +++ b/drivers/sensor/CMakeLists.txt @@ -52,6 +52,7 @@ add_subdirectory_ifdef(CONFIG_MC3419 mc3419) add_subdirectory_ifdef(CONFIG_MHZ19B mhz19b) add_subdirectory_ifdef(CONFIG_MPU6050 tdk/mpu6050) add_subdirectory_ifdef(CONFIG_MPU9250 tdk/mpu9250) +add_subdirectory_ifdef(CONFIG_NCT75 nct75) add_subdirectory_ifdef(CONFIG_NTC_THERMISTOR ntc_thermistor) add_subdirectory_ifdef(CONFIG_PMS7003 pms7003) add_subdirectory_ifdef(CONFIG_QDEC_SAM qdec_sam) @@ -60,6 +61,8 @@ add_subdirectory_ifdef(CONFIG_S11059 s11059) add_subdirectory_ifdef(CONFIG_SBS_GAUGE sbs_gauge) add_subdirectory_ifdef(CONFIG_SX9500 sx9500) add_subdirectory_ifdef(CONFIG_TH02 th02) +add_subdirectory_ifdef(CONFIG_TSIC_XX6 tsic_xx6) +add_subdirectory_ifdef(CONFIG_VEAA_X_3 veaa_x_3) add_subdirectory_ifdef(CONFIG_VOLTAGE_DIVIDER voltage_divider) add_subdirectory_ifdef(CONFIG_TACH_ENE_KB1200 ene_tach_kb1200) diff --git a/drivers/sensor/Kconfig b/drivers/sensor/Kconfig index 89552e3b746..85589a541c9 100644 --- a/drivers/sensor/Kconfig +++ b/drivers/sensor/Kconfig @@ -133,6 +133,7 @@ source "drivers/sensor/mc3419/Kconfig" source "drivers/sensor/mhz19b/Kconfig" source "drivers/sensor/tdk/mpu6050/Kconfig" source "drivers/sensor/tdk/mpu9250/Kconfig" +source "drivers/sensor/nct75/Kconfig" source "drivers/sensor/ntc_thermistor/Kconfig" source "drivers/sensor/pms7003/Kconfig" source "drivers/sensor/qdec_sam/Kconfig" @@ -141,6 +142,8 @@ source "drivers/sensor/s11059/Kconfig" source "drivers/sensor/sbs_gauge/Kconfig" source "drivers/sensor/sx9500/Kconfig" source "drivers/sensor/th02/Kconfig" +source "drivers/sensor/tsic_xx6/Kconfig" +source "drivers/sensor/veaa_x_3/Kconfig" source "drivers/sensor/voltage_divider/Kconfig" source "drivers/sensor/ene_tach_kb1200/Kconfig" diff --git a/drivers/sensor/adi/adxl362/adxl362.c b/drivers/sensor/adi/adxl362/adxl362.c index 9d387881182..fcd94b1792b 100644 --- a/drivers/sensor/adi/adxl362/adxl362.c +++ b/drivers/sensor/adi/adxl362/adxl362.c @@ -561,7 +561,8 @@ static void adxl362_accel_convert(struct sensor_value *val, int accel, static void adxl362_temp_convert(struct sensor_value *val, int temp) { /* See sensitivity and bias specifications in table 1 of datasheet */ - int milli_c = (temp - ADXL362_TEMP_BIAS_LSB) * ADXL362_TEMP_MC_PER_LSB; + int milli_c = (temp - ADXL362_TEMP_BIAS_LSB) * ADXL362_TEMP_MC_PER_LSB + + (ADXL362_TEMP_BIAS_TEST_CONDITION * 1000); val->val1 = milli_c / 1000; val->val2 = (milli_c % 1000) * 1000; diff --git a/drivers/sensor/adi/adxl362/adxl362.h b/drivers/sensor/adi/adxl362/adxl362.h index 5dea56e107a..ac41a2ff2ee 100644 --- a/drivers/sensor/adi/adxl362/adxl362.h +++ b/drivers/sensor/adi/adxl362/adxl362.h @@ -169,6 +169,7 @@ /* ADXL362 temperature sensor specifications */ #define ADXL362_TEMP_MC_PER_LSB 65 #define ADXL362_TEMP_BIAS_LSB 350 +#define ADXL362_TEMP_BIAS_TEST_CONDITION 25 struct adxl362_config { struct spi_dt_spec bus; diff --git a/drivers/sensor/amd_sb_tsi/sb_tsi_emul.c b/drivers/sensor/amd_sb_tsi/sb_tsi_emul.c index 1c12942c876..08ef4026ccf 100644 --- a/drivers/sensor/amd_sb_tsi/sb_tsi_emul.c +++ b/drivers/sensor/amd_sb_tsi/sb_tsi_emul.c @@ -99,7 +99,7 @@ static int sb_tsi_emul_init(const struct emul *target, const struct device *pare return 0; } -static int sb_tsi_emul_set_channel(const struct emul *target, enum sensor_channel chan, +static int sb_tsi_emul_set_channel(const struct emul *target, struct sensor_chan_spec ch, const q31_t *value, int8_t shift) { struct sb_tsi_emul_data *data = target->data; @@ -107,7 +107,7 @@ static int sb_tsi_emul_set_channel(const struct emul *target, enum sensor_channe int32_t millicelsius; int32_t reg_value; - if (chan != SENSOR_CHAN_AMBIENT_TEMP) { + if (ch.chan_type != SENSOR_CHAN_AMBIENT_TEMP && ch.chan_idx != 0) { return -ENOTSUP; } @@ -121,10 +121,10 @@ static int sb_tsi_emul_set_channel(const struct emul *target, enum sensor_channe return 0; } -static int sb_tsi_emul_get_sample_range(const struct emul *target, enum sensor_channel chan, +static int sb_tsi_emul_get_sample_range(const struct emul *target, struct sensor_chan_spec ch, q31_t *lower, q31_t *upper, q31_t *epsilon, int8_t *shift) { - if (chan != SENSOR_CHAN_AMBIENT_TEMP) { + if (ch.chan_type != SENSOR_CHAN_AMBIENT_TEMP || ch.chan_idx != 0) { return -ENOTSUP; } @@ -140,7 +140,7 @@ 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 = { +static const struct emul_sensor_driver_api sb_tsi_emul_api_sensor = { .set_channel = sb_tsi_emul_set_channel, .get_sample_range = sb_tsi_emul_get_sample_range, }; diff --git a/drivers/sensor/asahi_kasei/akm09918c/akm09918c_decoder.c b/drivers/sensor/asahi_kasei/akm09918c/akm09918c_decoder.c index 9bd6b312b7a..9f13cc4b31d 100644 --- a/drivers/sensor/asahi_kasei/akm09918c/akm09918c_decoder.c +++ b/drivers/sensor/asahi_kasei/akm09918c/akm09918c_decoder.c @@ -5,22 +5,22 @@ #include "akm09918c.h" -static int akm09918c_decoder_get_frame_count(const uint8_t *buffer, enum sensor_channel channel, - size_t channel_idx, uint16_t *frame_count) +static int akm09918c_decoder_get_frame_count(const uint8_t *buffer, + struct sensor_chan_spec chan_spec, + uint16_t *frame_count) { ARG_UNUSED(buffer); - ARG_UNUSED(channel); - ARG_UNUSED(channel_idx); + ARG_UNUSED(chan_spec); /* This sensor lacks a FIFO; there will always only be one frame at a time. */ *frame_count = 1; return 0; } -static int akm09918c_decoder_get_size_info(enum sensor_channel channel, size_t *base_size, +static int akm09918c_decoder_get_size_info(struct sensor_chan_spec chan_spec, size_t *base_size, size_t *frame_size) { - switch (channel) { + switch (chan_spec.chan_type) { case SENSOR_CHAN_MAGN_X: case SENSOR_CHAN_MAGN_Y: case SENSOR_CHAN_MAGN_Z: @@ -48,9 +48,8 @@ static int akm09918c_convert_raw_to_q31(int16_t reading, q31_t *out) return 0; } -static int akm09918c_decoder_decode(const uint8_t *buffer, enum sensor_channel channel, - size_t channel_idx, uint32_t *fit, - uint16_t max_count, void *data_out) +static int akm09918c_decoder_decode(const uint8_t *buffer, struct sensor_chan_spec chan_spec, + uint32_t *fit, uint16_t max_count, void *data_out) { const struct akm09918c_encoded_data *edata = (const struct akm09918c_encoded_data *)buffer; @@ -58,7 +57,7 @@ static int akm09918c_decoder_decode(const uint8_t *buffer, enum sensor_channel c return 0; } - switch (channel) { + switch (chan_spec.chan_type) { case SENSOR_CHAN_MAGN_X: case SENSOR_CHAN_MAGN_Y: case SENSOR_CHAN_MAGN_Z: diff --git a/drivers/sensor/asahi_kasei/akm09918c/akm09918c_emul.c b/drivers/sensor/asahi_kasei/akm09918c/akm09918c_emul.c index adb237e1256..5dce0d0d827 100644 --- a/drivers/sensor/asahi_kasei/akm09918c/akm09918c_emul.c +++ b/drivers/sensor/asahi_kasei/akm09918c/akm09918c_emul.c @@ -133,7 +133,7 @@ static int akm09918c_emul_init(const struct emul *target, const struct device *p return 0; } -static int akm09918c_emul_backend_set_channel(const struct emul *target, enum sensor_channel ch, +static int akm09918c_emul_backend_set_channel(const struct emul *target, struct sensor_chan_spec ch, const q31_t *value, int8_t shift) { if (!target || !target->data) { @@ -143,7 +143,7 @@ static int akm09918c_emul_backend_set_channel(const struct emul *target, enum se struct akm09918c_emul_data *data = target->data; uint8_t reg; - switch (ch) { + switch (ch.chan_type) { case SENSOR_CHAN_MAGN_X: reg = AKM09918C_REG_HXL; break; @@ -178,7 +178,7 @@ static int akm09918c_emul_backend_set_channel(const struct emul *target, enum se } static int akm09918c_emul_backend_get_sample_range(const struct emul *target, - enum sensor_channel ch, q31_t *lower, + struct sensor_chan_spec ch, q31_t *lower, q31_t *upper, q31_t *epsilon, int8_t *shift) { ARG_UNUSED(target); @@ -187,7 +187,7 @@ static int akm09918c_emul_backend_get_sample_range(const struct emul *target, return -EINVAL; } - switch (ch) { + switch (ch.chan_type) { case SENSOR_CHAN_MAGN_X: case SENSOR_CHAN_MAGN_Y: case SENSOR_CHAN_MAGN_Z: @@ -208,7 +208,7 @@ static const struct i2c_emul_api akm09918c_emul_api_i2c = { .transfer = akm09918c_emul_transfer_i2c, }; -static const struct emul_sensor_backend_api akm09918c_emul_sensor_backend_api = { +static const struct emul_sensor_driver_api akm09918c_emul_sensor_driver_api = { .set_channel = akm09918c_emul_backend_set_channel, .get_sample_range = akm09918c_emul_backend_get_sample_range, }; @@ -218,6 +218,6 @@ static const struct emul_sensor_backend_api akm09918c_emul_sensor_backend_api = struct akm09918c_emul_data akm09918c_emul_data_##n; \ EMUL_DT_INST_DEFINE(n, akm09918c_emul_init, &akm09918c_emul_data_##n, \ &akm09918c_emul_cfg_##n, &akm09918c_emul_api_i2c, \ - &akm09918c_emul_sensor_backend_api) + &akm09918c_emul_sensor_driver_api) DT_INST_FOREACH_STATUS_OKAY(AKM09918C_EMUL) diff --git a/drivers/sensor/bosch/bma4xx/bma4xx.c b/drivers/sensor/bosch/bma4xx/bma4xx.c index 9d8656d67aa..db717cc0c04 100644 --- a/drivers/sensor/bosch/bma4xx/bma4xx.c +++ b/drivers/sensor/bosch/bma4xx/bma4xx.c @@ -343,7 +343,7 @@ static int bma4xx_submit_one_shot(const struct device *dev, struct rtio_iodev_sq 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 struct sensor_chan_spec *const channels = cfg->channels; const size_t num_channels = cfg->count; uint32_t min_buf_len = sizeof(struct bma4xx_encoded_data); @@ -370,7 +370,11 @@ static int bma4xx_submit_one_shot(const struct device *dev, struct rtio_iodev_sq /* Determine what channels we need to fetch */ for (int i = 0; i < num_channels; i++) { - switch (channels[i]) { + if (channels[i].chan_idx != 0) { + LOG_ERR("Only channel index 0 supported"); + return -ENOTSUP; + } + switch (channels[i].chan_type) { case SENSOR_CHAN_ALL: edata->has_accel = 1; #ifdef CONFIG_BMA4XX_TEMPERATURE @@ -389,7 +393,8 @@ static int bma4xx_submit_one_shot(const struct device *dev, struct rtio_iodev_sq break; #endif /* CONFIG_BMA4XX_TEMPERATURE */ default: - LOG_ERR("Requested unsupported channel ID %d", channels[i]); + LOG_ERR("Requested unsupported channel type %d, idx %d", + channels[i].chan_type, channels[i].chan_idx); return -ENOTSUP; } } @@ -436,18 +441,18 @@ static int bma4xx_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_ * 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) +static int bma4xx_decoder_get_frame_count(const uint8_t *buffer, struct sensor_chan_spec ch, + 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) { + if (ch.chan_idx != 0) { return -ENOTSUP; } if (!header->is_fifo) { - switch (channel) { + switch (ch.chan_type) { case SENSOR_CHAN_ACCEL_X: case SENSOR_CHAN_ACCEL_Y: case SENSOR_CHAN_ACCEL_Z: @@ -467,10 +472,10 @@ static int bma4xx_decoder_get_frame_count(const uint8_t *buffer, enum sensor_cha return -ENOTSUP; } -static int bma4xx_decoder_get_size_info(enum sensor_channel channel, size_t *base_size, +static int bma4xx_decoder_get_size_info(struct sensor_chan_spec ch, size_t *base_size, size_t *frame_size) { - switch (channel) { + switch (ch.chan_type) { case SENSOR_CHAN_ACCEL_X: case SENSOR_CHAN_ACCEL_Y: case SENSOR_CHAN_ACCEL_Z: @@ -487,9 +492,9 @@ static int bma4xx_decoder_get_size_info(enum sensor_channel channel, size_t *bas } } -static int bma4xx_get_shift(enum sensor_channel channel, uint8_t accel_fs, int8_t *shift) +static int bma4xx_get_shift(struct sensor_chan_spec ch, uint8_t accel_fs, int8_t *shift) { - switch (channel) { + switch (ch.chan_type) { case SENSOR_CHAN_ACCEL_X: case SENSOR_CHAN_ACCEL_Y: case SENSOR_CHAN_ACCEL_Z: @@ -562,9 +567,8 @@ static void bma4xx_convert_raw_temp_to_q31(int8_t raw_val, q31_t *out) } #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) +static int bma4xx_one_shot_decode(const uint8_t *buffer, struct sensor_chan_spec ch, + 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; @@ -573,11 +577,11 @@ static int bma4xx_one_shot_decode(const uint8_t *buffer, enum sensor_channel cha if (*fit != 0) { return 0; } - if (max_count == 0 || channel_idx != 0) { + if (max_count == 0 || ch.chan_idx != 0) { return -EINVAL; } - switch (channel) { + switch (ch.chan_type) { case SENSOR_CHAN_ACCEL_X: case SENSOR_CHAN_ACCEL_Y: case SENSOR_CHAN_ACCEL_Z: @@ -590,7 +594,9 @@ static int bma4xx_one_shot_decode(const uint8_t *buffer, enum sensor_channel cha 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); + rc = bma4xx_get_shift((struct sensor_chan_spec){.chan_type = SENSOR_CHAN_ACCEL_XYZ, + .chan_idx = 0}, + header->accel_fs, &out->shift); if (rc != 0) { return -EINVAL; } @@ -628,8 +634,8 @@ static int bma4xx_one_shot_decode(const uint8_t *buffer, enum sensor_channel cha } } -static int bma4xx_decoder_decode(const uint8_t *buffer, enum sensor_channel channel, - size_t channel_idx, uint32_t *fit, uint16_t max_count, +static int bma4xx_decoder_decode(const uint8_t *buffer, struct sensor_chan_spec ch, + uint32_t *fit, uint16_t max_count, void *data_out) { const struct bma4xx_decoder_header *header = (const struct bma4xx_decoder_header *)buffer; @@ -639,7 +645,7 @@ static int bma4xx_decoder_decode(const uint8_t *buffer, enum sensor_channel chan return -ENOTSUP; } - return bma4xx_one_shot_decode(buffer, channel, channel_idx, fit, max_count, data_out); + return bma4xx_one_shot_decode(buffer, ch, fit, max_count, data_out); } SENSOR_DECODER_API_DT_DEFINE() = { diff --git a/drivers/sensor/bosch/bma4xx/bma4xx_emul.c b/drivers/sensor/bosch/bma4xx/bma4xx_emul.c index b5c96d29817..ec5f069da53 100644 --- a/drivers/sensor/bosch/bma4xx/bma4xx_emul.c +++ b/drivers/sensor/bosch/bma4xx/bma4xx_emul.c @@ -216,7 +216,7 @@ void bma4xx_emul_set_accel_data(const struct emul *target, q31_t value, int8_t s data->regs[reg + 1] = FIELD_GET(GENMASK(11, 4), reg_val); } -static int bma4xx_emul_backend_set_channel(const struct emul *target, enum sensor_channel ch, +static int bma4xx_emul_backend_set_channel(const struct emul *target, struct sensor_chan_spec ch, const q31_t *value, int8_t shift) { @@ -226,7 +226,7 @@ static int bma4xx_emul_backend_set_channel(const struct emul *target, enum senso struct bma4xx_emul_data *data = target->data; - switch (ch) { + switch (ch.chan_type) { case SENSOR_CHAN_ACCEL_X: bma4xx_emul_set_accel_data(target, value[0], shift, BMA4XX_REG_DATA_8); break; @@ -250,15 +250,15 @@ static int bma4xx_emul_backend_set_channel(const struct emul *target, enum senso return 0; } -static int bma4xx_emul_backend_get_sample_range(const struct emul *target, enum sensor_channel ch, - q31_t *lower, q31_t *upper, q31_t *epsilon, - int8_t *shift) +static int bma4xx_emul_backend_get_sample_range(const struct emul *target, + struct sensor_chan_spec ch, q31_t *lower, + q31_t *upper, q31_t *epsilon, int8_t *shift) { if (!lower || !upper || !epsilon || !shift) { return -EINVAL; } - switch (ch) { + switch (ch.chan_type) { case SENSOR_CHAN_ACCEL_X: case SENSOR_CHAN_ACCEL_Y: case SENSOR_CHAN_ACCEL_Z: @@ -306,7 +306,7 @@ static int bma4xx_emul_backend_get_sample_range(const struct emul *target, enum return 0; } -static const struct emul_sensor_backend_api bma4xx_emul_sensor_backend_api = { +static const struct emul_sensor_driver_api bma4xx_emul_sensor_driver_api = { .set_channel = bma4xx_emul_backend_set_channel, .get_sample_range = bma4xx_emul_backend_get_sample_range, }; @@ -319,6 +319,6 @@ static struct i2c_emul_api bma4xx_emul_api_i2c = { static struct bma4xx_emul_data bma4xx_emul_data_##n = {}; \ static const struct bma4xx_emul_cfg bma4xx_emul_cfg_##n = {}; \ EMUL_DT_INST_DEFINE(n, bma4xx_emul_init, &bma4xx_emul_data_##n, &bma4xx_emul_cfg_##n, \ - &bma4xx_emul_api_i2c, &bma4xx_emul_sensor_backend_api); + &bma4xx_emul_api_i2c, &bma4xx_emul_sensor_driver_api); DT_INST_FOREACH_STATUS_OKAY(INIT_BMA4XX) diff --git a/drivers/sensor/bosch/bmi160/emul_bmi160.c b/drivers/sensor/bosch/bmi160/emul_bmi160.c index 3ed71790fbe..9fc33b48b6a 100644 --- a/drivers/sensor/bosch/bmi160/emul_bmi160.c +++ b/drivers/sensor/bosch/bmi160/emul_bmi160.c @@ -279,7 +279,7 @@ 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, +static int bmi160_emul_backend_set_channel(const struct emul *target, struct sensor_chan_spec ch, const q31_t *value, int8_t shift) { const struct bmi160_emul_cfg *cfg = target->cfg; @@ -288,11 +288,11 @@ static int bmi160_emul_backend_set_channel(const struct emul *target, enum senso int8_t scale_shift = 0; int reg_lsb; - switch (ch) { + switch (ch.chan_type) { 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; + reg_lsb = BMI160_REG_DATA_ACC_X + (ch.chan_type - SENSOR_CHAN_ACCEL_X) * 2; scale = 0x4e7404ea; switch (FIELD_GET(GENMASK(3, 0), cfg->reg[BMI160_REG_ACC_RANGE])) { @@ -313,7 +313,7 @@ static int bmi160_emul_backend_set_channel(const struct emul *target, enum senso 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; + reg_lsb = BMI160_REG_DATA_GYR_X + (ch.chan_type - SENSOR_CHAN_GYRO_X) * 2; scale = 0x45d02bea; switch (FIELD_GET(GENMASK(2, 0), cfg->reg[BMI160_REG_GYR_RANGE])) { @@ -353,7 +353,7 @@ static int bmi160_emul_backend_set_channel(const struct emul *target, enum senso intermediate <<= shift - scale_shift; } - if (ch == SENSOR_CHAN_DIE_TEMP) { + if (ch.chan_type == SENSOR_CHAN_DIE_TEMP) { /* Need to subtract 23C */ intermediate -= INT64_C(23) << (31 - scale_shift); } @@ -366,13 +366,13 @@ static int bmi160_emul_backend_set_channel(const struct emul *target, enum senso 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) +static int bmi160_emul_backend_get_sample_range(const struct emul *target, + struct sensor_chan_spec ch, q31_t *lower, + q31_t *upper, q31_t *epsilon, int8_t *shift) { const struct bmi160_emul_cfg *cfg = target->cfg; - switch (ch) { + switch (ch.chan_type) { case SENSOR_CHAN_ACCEL_X: case SENSOR_CHAN_ACCEL_Y: case SENSOR_CHAN_ACCEL_Z: @@ -440,10 +440,10 @@ static int bmi160_emul_backend_get_sample_range(const struct emul *target, enum } } -static int bmi160_emul_backend_set_offset(const struct emul *target, enum sensor_channel ch, +static int bmi160_emul_backend_set_offset(const struct emul *target, struct sensor_chan_spec ch, const q31_t *values, int8_t shift) { - if (ch != SENSOR_CHAN_ACCEL_XYZ && ch != SENSOR_CHAN_GYRO_XYZ) { + if (ch.chan_type != SENSOR_CHAN_ACCEL_XYZ && ch.chan_type != SENSOR_CHAN_GYRO_XYZ) { return -EINVAL; } @@ -452,20 +452,20 @@ static int bmi160_emul_backend_set_offset(const struct emul *target, enum sensor int8_t scale_shift = 0; if (values[0] == 0 && values[1] == 0 && values[2] == 0) { - if (ch == SENSOR_CHAN_ACCEL_XYZ) { + if (ch.chan_type == 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) { + if (ch.chan_type == 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) { + if (ch.chan_type == SENSOR_CHAN_ACCEL_XYZ) { /* * bits = (values[i]mps2 / 9.80665g/mps2) / 0.0039g * = values[i] / 0.038245935mps2/bit @@ -493,11 +493,11 @@ static int bmi160_emul_backend_set_offset(const struct emul *target, enum sensor int64_t reg_value = intermediate / scale; - __ASSERT_NO_MSG(ch != SENSOR_CHAN_ACCEL_XYZ || + __ASSERT_NO_MSG(ch.chan_type != SENSOR_CHAN_ACCEL_XYZ || (reg_value >= INT8_MIN && reg_value <= INT8_MAX)); - __ASSERT_NO_MSG(ch != SENSOR_CHAN_GYRO_XYZ || + __ASSERT_NO_MSG(ch.chan_type != SENSOR_CHAN_GYRO_XYZ || (reg_value >= -0x1ff - 1 && reg_value <= 0x1ff)); - if (ch == SENSOR_CHAN_ACCEL_XYZ) { + if (ch.chan_type == 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; @@ -510,11 +510,11 @@ static int bmi160_emul_backend_set_offset(const struct emul *target, enum sensor return 0; } -static int bmi160_emul_backend_set_attribute(const struct emul *target, enum sensor_channel ch, +static int bmi160_emul_backend_set_attribute(const struct emul *target, struct sensor_chan_spec ch, enum sensor_attribute attribute, const void *value) { if (attribute == SENSOR_ATTR_OFFSET && - (ch == SENSOR_CHAN_ACCEL_XYZ || ch == SENSOR_CHAN_GYRO_XYZ)) { + (ch.chan_type == SENSOR_CHAN_ACCEL_XYZ || ch.chan_type == SENSOR_CHAN_GYRO_XYZ)) { const struct sensor_three_axis_attribute *attribute_value = value; return bmi160_emul_backend_set_offset(target, ch, attribute_value->values, @@ -524,12 +524,12 @@ static int bmi160_emul_backend_set_attribute(const struct emul *target, enum sen } static int bmi160_emul_backend_get_attribute_metadata(const struct emul *target, - enum sensor_channel ch, + struct sensor_chan_spec ch, enum sensor_attribute attribute, q31_t *min, q31_t *max, q31_t *increment, int8_t *shift) { ARG_UNUSED(target); - switch (ch) { + switch (ch.chan_type) { case SENSOR_CHAN_ACCEL_X: case SENSOR_CHAN_ACCEL_Y: case SENSOR_CHAN_ACCEL_Z: @@ -569,7 +569,7 @@ static int bmi160_emul_backend_get_attribute_metadata(const struct emul *target, } } -static const struct emul_sensor_backend_api backend_api = { +static const struct emul_sensor_driver_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, diff --git a/drivers/sensor/bosch/bmi270/bmi270.c b/drivers/sensor/bosch/bmi270/bmi270.c index c3d61d3275a..33daf00dbf0 100644 --- a/drivers/sensor/bosch/bmi270/bmi270.c +++ b/drivers/sensor/bosch/bmi270/bmi270.c @@ -793,7 +793,7 @@ static const struct bmi270_feature_config bmi270_feature_base = { }; #define BMI270_FEATURE(inst) ( \ - DT_NODE_HAS_COMPAT(DT_DRV_INST(inst), bosch_bmi270_base) ? \ + DT_INST_NODE_HAS_COMPAT(inst, bosch_bmi270_base) ? \ &bmi270_feature_base : \ &bmi270_feature_max_fifo) diff --git a/drivers/sensor/current_amp/Kconfig b/drivers/sensor/current_amp/Kconfig index 62ea9bc0d12..b167221256d 100644 --- a/drivers/sensor/current_amp/Kconfig +++ b/drivers/sensor/current_amp/Kconfig @@ -8,6 +8,6 @@ config CURRENT_AMP bool "Current sense amplifier driver" default y depends on DT_HAS_CURRENT_SENSE_AMPLIFIER_ENABLED - depends on ADC + select ADC help Enable current sense amplifier driver. diff --git a/drivers/sensor/default_rtio_sensor.c b/drivers/sensor/default_rtio_sensor.c index 3f9377c33b3..c95dcedfe87 100644 --- a/drivers/sensor/default_rtio_sensor.c +++ b/drivers/sensor/default_rtio_sensor.c @@ -13,10 +13,10 @@ LOG_MODULE_REGISTER(sensor_compat, CONFIG_SENSOR_LOG_LEVEL); /* - * Ensure that the size of the generic header aligns with the sensor channel enum. If it doesn't, - * then cores that require aligned memory access will fail to read channel[0]. + * Ensure that the size of the generic header aligns with the sensor channel specifier . If it + * doesn't, then cores that require aligned memory access will fail to read channel[0]. */ -BUILD_ASSERT((sizeof(struct sensor_data_generic_header) % sizeof(enum sensor_channel)) == 0); +BUILD_ASSERT((sizeof(struct sensor_data_generic_header) % sizeof(struct sensor_chan_spec)) == 0); static void sensor_submit_fallback(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe); @@ -46,12 +46,13 @@ const struct rtio_iodev_api __sensor_iodev_api = { * @param[in] num_channels Number of channels on the @p channels array * @return The number of samples required to read the given channels */ -static inline int compute_num_samples(const enum sensor_channel *channels, size_t num_channels) +static inline int compute_num_samples(const struct sensor_chan_spec *const channels, + size_t num_channels) { int num_samples = 0; for (size_t i = 0; i < num_channels; ++i) { - num_samples += SENSOR_CHANNEL_3_AXIS(channels[i]) ? 3 : 1; + num_samples += SENSOR_CHANNEL_3_AXIS(channels[i].chan_type) ? 3 : 1; } return num_samples; @@ -68,7 +69,7 @@ static inline int compute_num_samples(const enum sensor_channel *channels, size_ static inline uint32_t compute_header_size(int num_output_samples) { uint32_t size = sizeof(struct sensor_data_generic_header) + - (num_output_samples * sizeof(enum sensor_channel)); + (num_output_samples * sizeof(struct sensor_chan_spec)); return (size + 3) & ~0x3; } @@ -92,12 +93,12 @@ static inline uint32_t compute_min_buf_len(int num_output_samples) * @return Index of the @p channel if found or negative if not found */ static inline int check_header_contains_channel(const struct sensor_data_generic_header *header, - enum sensor_channel channel, int num_channels) + struct sensor_chan_spec chan_spec, int num_channels) { - __ASSERT_NO_MSG(!SENSOR_CHANNEL_3_AXIS(channel)); + __ASSERT_NO_MSG(!SENSOR_CHANNEL_3_AXIS(chan_spec.chan_type)); for (int i = 0; i < num_channels; ++i) { - if (header->channels[i] == channel) { + if (sensor_chan_spec_eq(header->channels[i], chan_spec)) { return i; } } @@ -113,7 +114,7 @@ static inline int check_header_contains_channel(const struct sensor_data_generic static void sensor_submit_fallback(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; + const struct sensor_chan_spec *const channels = cfg->channels; const int num_output_samples = compute_num_samples(channels, cfg->count); uint32_t min_buf_len = compute_min_buf_len(num_output_samples); uint64_t timestamp_ns = k_ticks_to_ns_floor64(k_uptime_ticks()); @@ -148,24 +149,34 @@ static void sensor_submit_fallback(const struct device *dev, struct rtio_iodev_s /* Populate values, update shift, and set channels */ for (size_t i = 0, sample_idx = 0; i < cfg->count; ++i) { struct sensor_value value[3]; - const int num_samples = SENSOR_CHANNEL_3_AXIS(channels[i]) ? 3 : 1; + const int num_samples = SENSOR_CHANNEL_3_AXIS(channels[i].chan_type) ? 3 : 1; /* Get the current channel requested by the user */ - rc = sensor_channel_get(dev, channels[i], value); + rc = sensor_channel_get(dev, channels[i].chan_type, value); if (num_samples == 3) { - header->channels[sample_idx++] = - rc == 0 ? channels[i] - 3 : SENSOR_CHAN_MAX; - header->channels[sample_idx++] = - rc == 0 ? channels[i] - 2 : SENSOR_CHAN_MAX; - header->channels[sample_idx++] = - rc == 0 ? channels[i] - 1 : SENSOR_CHAN_MAX; + header->channels[sample_idx++] = (struct sensor_chan_spec) { + rc == 0 ? channels[i].chan_type - 3 : SENSOR_CHAN_MAX, + 0 + }; + header->channels[sample_idx++] = (struct sensor_chan_spec) { + rc == 0 ? channels[i].chan_type - 2 : SENSOR_CHAN_MAX, + 0 + }; + header->channels[sample_idx++] = (struct sensor_chan_spec) { + rc == 0 ? channels[i].chan_type - 1 : SENSOR_CHAN_MAX, + 0 + }; } else { - header->channels[sample_idx++] = rc == 0 ? channels[i] : SENSOR_CHAN_MAX; + header->channels[sample_idx++] = (struct sensor_chan_spec) { + rc == 0 ? channels[i].chan_type : SENSOR_CHAN_MAX, + 0 + }; } if (rc != 0) { - LOG_DBG("Failed to get channel %d, skipping", channels[i]); + LOG_DBG("Failed to get channel (type: %d, index %d), skipping", + channels[i].chan_type, channels[i].chan_idx); continue; } @@ -230,10 +241,11 @@ static void sensor_submit_fallback(const struct device *dev, struct rtio_iodev_s q[sample_idx + sample] = ((value_u * ((INT64_C(1) << 31) - 1)) / 1000000) >> header->shift; - LOG_DBG("value[%d]=%s%d.%06d, q[%d]@%p=%d", sample, value_u < 0 ? "-" : "", + LOG_DBG("value[%d]=%s%d.%06d, q[%d]@%p=%d, shift: %d", + sample, value_u < 0 ? "-" : "", abs((int)value[sample].val1), abs((int)value[sample].val2), (int)(sample_idx + sample), (void *)&q[sample_idx + sample], - q[sample_idx + sample]); + q[sample_idx + sample], header->shift); } sample_idx += num_samples; } @@ -277,45 +289,45 @@ void sensor_processing_with_callback(struct rtio *ctx, sensor_processing_callbac * @param[out] frame_count The number of frames in the buffer (always 1) * @return 0 in all cases */ -static int get_frame_count(const uint8_t *buffer, enum sensor_channel channel, size_t channel_idx, +static int get_frame_count(const uint8_t *buffer, struct sensor_chan_spec channel, uint16_t *frame_count) { struct sensor_data_generic_header *header = (struct sensor_data_generic_header *)buffer; - size_t count = 0; - switch (channel) { + switch (channel.chan_type) { case SENSOR_CHAN_ACCEL_XYZ: - channel = SENSOR_CHAN_ACCEL_X; + channel.chan_type = SENSOR_CHAN_ACCEL_X; break; case SENSOR_CHAN_GYRO_XYZ: - channel = SENSOR_CHAN_GYRO_X; + channel.chan_type = SENSOR_CHAN_GYRO_X; break; case SENSOR_CHAN_MAGN_XYZ: - channel = SENSOR_CHAN_MAGN_X; + channel.chan_type = SENSOR_CHAN_MAGN_X; break; default: break; } for (size_t i = 0; i < header->num_channels; ++i) { - if (header->channels[i] == channel) { - if (channel_idx == count) { - *frame_count = 1; - return 0; - } - ++count; + if (sensor_chan_spec_eq(header->channels[i], channel)) { + *frame_count = 1; + return 0; } } return -ENOTSUP; } -int sensor_natively_supported_channel_size_info(enum sensor_channel channel, size_t *base_size, +int sensor_natively_supported_channel_size_info(struct sensor_chan_spec channel, size_t *base_size, size_t *frame_size) { __ASSERT_NO_MSG(base_size != NULL); __ASSERT_NO_MSG(frame_size != NULL); - switch (channel) { + if (((int)channel.chan_type < 0) || channel.chan_type >= (SENSOR_CHAN_ALL)) { + return -ENOTSUP; + } + + switch (channel.chan_type) { case SENSOR_CHAN_ACCEL_X: case SENSOR_CHAN_ACCEL_Y: case SENSOR_CHAN_ACCEL_Z: @@ -334,49 +346,6 @@ int sensor_natively_supported_channel_size_info(enum sensor_channel channel, siz *base_size = sizeof(struct sensor_three_axis_data); *frame_size = sizeof(struct sensor_three_axis_sample_data); return 0; - case SENSOR_CHAN_DIE_TEMP: - case SENSOR_CHAN_AMBIENT_TEMP: - case SENSOR_CHAN_PRESS: - case SENSOR_CHAN_HUMIDITY: - case SENSOR_CHAN_LIGHT: - case SENSOR_CHAN_IR: - case SENSOR_CHAN_RED: - case SENSOR_CHAN_GREEN: - case SENSOR_CHAN_BLUE: - case SENSOR_CHAN_ALTITUDE: - case SENSOR_CHAN_PM_1_0: - case SENSOR_CHAN_PM_2_5: - case SENSOR_CHAN_PM_10: - case SENSOR_CHAN_DISTANCE: - case SENSOR_CHAN_CO2: - case SENSOR_CHAN_VOC: - case SENSOR_CHAN_GAS_RES: - case SENSOR_CHAN_VOLTAGE: - case SENSOR_CHAN_CURRENT: - case SENSOR_CHAN_POWER: - case SENSOR_CHAN_RESISTANCE: - case SENSOR_CHAN_ROTATION: - case SENSOR_CHAN_RPM: - case SENSOR_CHAN_GAUGE_VOLTAGE: - case SENSOR_CHAN_GAUGE_AVG_CURRENT: - case SENSOR_CHAN_GAUGE_STDBY_CURRENT: - case SENSOR_CHAN_GAUGE_MAX_LOAD_CURRENT: - case SENSOR_CHAN_GAUGE_TEMP: - case SENSOR_CHAN_GAUGE_STATE_OF_CHARGE: - case SENSOR_CHAN_GAUGE_FULL_CHARGE_CAPACITY: - case SENSOR_CHAN_GAUGE_REMAINING_CHARGE_CAPACITY: - case SENSOR_CHAN_GAUGE_NOM_AVAIL_CAPACITY: - case SENSOR_CHAN_GAUGE_FULL_AVAIL_CAPACITY: - case SENSOR_CHAN_GAUGE_AVG_POWER: - case SENSOR_CHAN_GAUGE_STATE_OF_HEALTH: - case SENSOR_CHAN_GAUGE_TIME_TO_EMPTY: - case SENSOR_CHAN_GAUGE_TIME_TO_FULL: - case SENSOR_CHAN_GAUGE_DESIGN_VOLTAGE: - case SENSOR_CHAN_GAUGE_DESIRED_VOLTAGE: - case SENSOR_CHAN_GAUGE_DESIRED_CHARGING_CURRENT: - *base_size = sizeof(struct sensor_q31_data); - *frame_size = sizeof(struct sensor_q31_sample_data); - return 0; case SENSOR_CHAN_PROX: *base_size = sizeof(struct sensor_byte_data); *frame_size = sizeof(struct sensor_byte_sample_data); @@ -386,24 +355,20 @@ int sensor_natively_supported_channel_size_info(enum sensor_channel channel, siz *frame_size = sizeof(struct sensor_uint64_sample_data); return 0; default: - return -ENOTSUP; + *base_size = sizeof(struct sensor_q31_data); + *frame_size = sizeof(struct sensor_q31_sample_data); + return 0; } } static int get_q31_value(const struct sensor_data_generic_header *header, const q31_t *values, - enum sensor_channel channel, size_t channel_idx, q31_t *out) + struct sensor_chan_spec chan_spec, q31_t *out) { - size_t count = 0; - for (size_t i = 0; i < header->num_channels; ++i) { - if (channel != header->channels[i]) { - continue; - } - if (count == channel_idx) { + if (sensor_chan_spec_eq(chan_spec, header->channels[i])) { *out = values[i]; return 0; } - ++count; } return -EINVAL; } @@ -419,15 +384,18 @@ static int decode_three_axis(const struct sensor_data_generic_header *header, co data_out->shift = header->shift; data_out->readings[0].timestamp_delta = 0; - rc = get_q31_value(header, values, x, channel_idx, &data_out->readings[0].values[0]); + rc = get_q31_value(header, values, (struct sensor_chan_spec){x, channel_idx}, + &data_out->readings[0].values[0]); if (rc < 0) { return rc; } - rc = get_q31_value(header, values, y, channel_idx, &data_out->readings[0].values[1]); + rc = get_q31_value(header, values, (struct sensor_chan_spec){y, channel_idx}, + &data_out->readings[0].values[1]); if (rc < 0) { return rc; } - rc = get_q31_value(header, values, z, channel_idx, &data_out->readings[0].values[2]); + rc = get_q31_value(header, values, (struct sensor_chan_spec){z, channel_idx}, + &data_out->readings[0].values[2]); if (rc < 0) { return rc; } @@ -435,8 +403,7 @@ static int decode_three_axis(const struct sensor_data_generic_header *header, co } static int decode_q31(const struct sensor_data_generic_header *header, const q31_t *values, - struct sensor_q31_data *data_out, enum sensor_channel channel, - size_t channel_idx) + struct sensor_q31_data *data_out, struct sensor_chan_spec chan_spec) { int rc; @@ -445,7 +412,7 @@ static int decode_q31(const struct sensor_data_generic_header *header, const q31 data_out->shift = header->shift; data_out->readings[0].timestamp_delta = 0; - rc = get_q31_value(header, values, channel, channel_idx, &data_out->readings[0].value); + rc = get_q31_value(header, values, chan_spec, &data_out->readings[0].value); if (rc < 0) { return rc; } @@ -469,92 +436,57 @@ static int decode_q31(const struct sensor_data_generic_header *header, const q31 * @return >0 the number of decoded frames * @return <0 on error */ -static int decode(const uint8_t *buffer, enum sensor_channel channel, size_t channel_idx, +static int decode(const uint8_t *buffer, struct sensor_chan_spec chan_spec, uint32_t *fit, uint16_t max_count, void *data_out) { const struct sensor_data_generic_header *header = (const struct sensor_data_generic_header *)buffer; - const q31_t *q = - (const q31_t *)(buffer + sizeof(struct sensor_data_generic_header) + - header->num_channels * sizeof(enum sensor_channel)); + const q31_t *q = (const q31_t *)(buffer + compute_header_size(header->num_channels)); int count = 0; if (*fit != 0 || max_count < 1) { return -EINVAL; } + if (((int)chan_spec.chan_type < 0) || chan_spec.chan_type >= (SENSOR_CHAN_ALL)) { + return 0; + } + /* Check for 3d channel mappings */ - switch (channel) { + switch (chan_spec.chan_type) { case SENSOR_CHAN_ACCEL_X: case SENSOR_CHAN_ACCEL_Y: case SENSOR_CHAN_ACCEL_Z: case SENSOR_CHAN_ACCEL_XYZ: count = decode_three_axis(header, q, data_out, SENSOR_CHAN_ACCEL_X, - SENSOR_CHAN_ACCEL_Y, SENSOR_CHAN_ACCEL_Z, channel_idx); + SENSOR_CHAN_ACCEL_Y, SENSOR_CHAN_ACCEL_Z, + chan_spec.chan_idx); break; case SENSOR_CHAN_GYRO_X: case SENSOR_CHAN_GYRO_Y: case SENSOR_CHAN_GYRO_Z: case SENSOR_CHAN_GYRO_XYZ: count = decode_three_axis(header, q, data_out, SENSOR_CHAN_GYRO_X, - SENSOR_CHAN_GYRO_Y, SENSOR_CHAN_GYRO_Z, channel_idx); + SENSOR_CHAN_GYRO_Y, SENSOR_CHAN_GYRO_Z, + chan_spec.chan_idx); break; case SENSOR_CHAN_MAGN_X: case SENSOR_CHAN_MAGN_Y: case SENSOR_CHAN_MAGN_Z: case SENSOR_CHAN_MAGN_XYZ: count = decode_three_axis(header, q, data_out, SENSOR_CHAN_MAGN_X, - SENSOR_CHAN_MAGN_Y, SENSOR_CHAN_MAGN_Z, channel_idx); + SENSOR_CHAN_MAGN_Y, SENSOR_CHAN_MAGN_Z, + chan_spec.chan_idx); break; case SENSOR_CHAN_POS_DX: case SENSOR_CHAN_POS_DY: case SENSOR_CHAN_POS_DZ: count = decode_three_axis(header, q, data_out, SENSOR_CHAN_POS_DX, - SENSOR_CHAN_POS_DY, SENSOR_CHAN_POS_DZ, channel_idx); - break; - case SENSOR_CHAN_DIE_TEMP: - case SENSOR_CHAN_AMBIENT_TEMP: - case SENSOR_CHAN_PRESS: - case SENSOR_CHAN_HUMIDITY: - case SENSOR_CHAN_LIGHT: - case SENSOR_CHAN_IR: - case SENSOR_CHAN_RED: - case SENSOR_CHAN_GREEN: - case SENSOR_CHAN_BLUE: - case SENSOR_CHAN_ALTITUDE: - case SENSOR_CHAN_PM_1_0: - case SENSOR_CHAN_PM_2_5: - case SENSOR_CHAN_PM_10: - case SENSOR_CHAN_DISTANCE: - case SENSOR_CHAN_CO2: - case SENSOR_CHAN_VOC: - case SENSOR_CHAN_GAS_RES: - case SENSOR_CHAN_VOLTAGE: - case SENSOR_CHAN_CURRENT: - case SENSOR_CHAN_POWER: - case SENSOR_CHAN_RESISTANCE: - case SENSOR_CHAN_ROTATION: - case SENSOR_CHAN_RPM: - case SENSOR_CHAN_GAUGE_VOLTAGE: - case SENSOR_CHAN_GAUGE_AVG_CURRENT: - case SENSOR_CHAN_GAUGE_STDBY_CURRENT: - case SENSOR_CHAN_GAUGE_MAX_LOAD_CURRENT: - case SENSOR_CHAN_GAUGE_TEMP: - case SENSOR_CHAN_GAUGE_STATE_OF_CHARGE: - case SENSOR_CHAN_GAUGE_FULL_CHARGE_CAPACITY: - case SENSOR_CHAN_GAUGE_REMAINING_CHARGE_CAPACITY: - case SENSOR_CHAN_GAUGE_NOM_AVAIL_CAPACITY: - case SENSOR_CHAN_GAUGE_FULL_AVAIL_CAPACITY: - case SENSOR_CHAN_GAUGE_AVG_POWER: - case SENSOR_CHAN_GAUGE_STATE_OF_HEALTH: - case SENSOR_CHAN_GAUGE_TIME_TO_EMPTY: - case SENSOR_CHAN_GAUGE_TIME_TO_FULL: - case SENSOR_CHAN_GAUGE_DESIGN_VOLTAGE: - case SENSOR_CHAN_GAUGE_DESIRED_VOLTAGE: - case SENSOR_CHAN_GAUGE_DESIRED_CHARGING_CURRENT: - count = decode_q31(header, q, data_out, channel, channel_idx); + SENSOR_CHAN_POS_DY, SENSOR_CHAN_POS_DZ, + chan_spec.chan_idx); break; default: + count = decode_q31(header, q, data_out, chan_spec); break; } if (count > 0) { diff --git a/drivers/sensor/f75303/f75303_emul.c b/drivers/sensor/f75303/f75303_emul.c index 5bab9cd4294..fe1dbc5d345 100644 --- a/drivers/sensor/f75303/f75303_emul.c +++ b/drivers/sensor/f75303/f75303_emul.c @@ -103,7 +103,7 @@ static int f75303_emul_init(const struct emul *target, const struct device *pare return 0; } -static int f75303_emul_set_channel(const struct emul *target, enum sensor_channel chan, +static int f75303_emul_set_channel(const struct emul *target, struct sensor_chan_spec ch, const q31_t *value, int8_t shift) { struct f75303_emul_data *data = target->data; @@ -112,7 +112,7 @@ static int f75303_emul_set_channel(const struct emul *target, enum sensor_channe int32_t reg_value; uint8_t reg_h, reg_l; - switch ((int32_t)chan) { + switch ((int32_t)ch.chan_type) { case SENSOR_CHAN_AMBIENT_TEMP: reg_h = F75303_LOCAL_TEMP_H; reg_l = F75303_LOCAL_TEMP_L; @@ -139,12 +139,12 @@ static int f75303_emul_set_channel(const struct emul *target, enum sensor_channe return 0; } -static int f75303_emul_get_sample_range(const struct emul *target, enum sensor_channel chan, +static int f75303_emul_get_sample_range(const struct emul *target, struct sensor_chan_spec ch, q31_t *lower, q31_t *upper, q31_t *epsilon, int8_t *shift) { - if (chan != SENSOR_CHAN_AMBIENT_TEMP && - chan != (enum sensor_channel)SENSOR_CHAN_F75303_REMOTE1 && - chan != (enum sensor_channel)SENSOR_CHAN_F75303_REMOTE2) { + if (ch.chan_type != SENSOR_CHAN_AMBIENT_TEMP && + ch.chan_type != (enum sensor_channel)SENSOR_CHAN_F75303_REMOTE1 && + ch.chan_type != (enum sensor_channel)SENSOR_CHAN_F75303_REMOTE2) { return -ENOTSUP; } @@ -160,7 +160,7 @@ static const struct i2c_emul_api f75303_emul_api_i2c = { .transfer = f75303_emul_transfer_i2c, }; -static const struct emul_sensor_backend_api f75303_emul_api_sensor = { +static const struct emul_sensor_driver_api f75303_emul_api_sensor = { .set_channel = f75303_emul_set_channel, .get_sample_range = f75303_emul_get_sample_range, }; diff --git a/drivers/sensor/grow_r502a/Kconfig b/drivers/sensor/grow_r502a/Kconfig index 53c31f3c804..35297b90b65 100644 --- a/drivers/sensor/grow_r502a/Kconfig +++ b/drivers/sensor/grow_r502a/Kconfig @@ -13,6 +13,15 @@ menuconfig GROW_R502A if GROW_R502A +config R502A_DATA_PKT_SIZE + int "Template data packet size" + default 128 + help + Template data packet size for upload and download + to the sensor device. + valid values are: + 32, 64, 128, 256. + choice prompt "Trigger mode" default GROW_R502A_TRIGGER_NONE diff --git a/drivers/sensor/grow_r502a/grow_r502a.c b/drivers/sensor/grow_r502a/grow_r502a.c index 028b5919407..15714314b95 100644 --- a/drivers/sensor/grow_r502a/grow_r502a.c +++ b/drivers/sensor/grow_r502a/grow_r502a.c @@ -4,14 +4,14 @@ * SPDX-License-Identifier: Apache-2.0 */ -#define DT_DRV_COMPAT hzgrow_r502a - #include #include #include #include #include #include +#include +#include #include #include "grow_r502a.h" @@ -19,35 +19,107 @@ #include LOG_MODULE_REGISTER(GROW_R502A, CONFIG_SENSOR_LOG_LEVEL); -static void transceive_packet(const struct device *dev, union r502a_packet *tx_packet, - union r502a_packet *rx_packet, char const data_len) +static int transceive_packet(const struct device *dev, union r502a_packet *tx_packet, + union r502a_packet *rx_packet, uint16_t data_len) { const struct grow_r502a_config *cfg = dev->config; struct grow_r502a_data *drv_data = dev->data; - uint16_t check_sum, pkg_len; - pkg_len = data_len + R502A_CHECKSUM_LEN; - check_sum = pkg_len + tx_packet->pid; + if (tx_packet) { + uint16_t check_sum, pkg_len; + + pkg_len = data_len + R502A_CHECKSUM_LEN; + check_sum = (pkg_len >> 8) + (pkg_len & 0xFF) + tx_packet->pid; + + tx_packet->start = sys_cpu_to_be16(R502A_STARTCODE); + tx_packet->addr = sys_cpu_to_be32(cfg->comm_addr); + tx_packet->len = sys_cpu_to_be16(pkg_len); + + for (int i = 0; i < data_len; i++) { + check_sum += tx_packet->data[i]; + } + sys_put_be16(check_sum, &tx_packet->buf[data_len + R502A_HEADER_LEN]); + + drv_data->tx_buf.len = pkg_len + R502A_HEADER_LEN; + drv_data->tx_buf.data = tx_packet->buf; + + LOG_HEXDUMP_DBG(drv_data->tx_buf.data, drv_data->tx_buf.len, "TX"); + + uart_irq_tx_enable(cfg->dev); - sys_put_be16(R502A_STARTCODE, tx_packet->start); - sys_put_be32(cfg->comm_addr, tx_packet->addr); - sys_put_be16(pkg_len, tx_packet->len); - for (int i = 0; i < data_len; i++) { - check_sum += tx_packet->data[i]; + if (k_sem_take(&drv_data->uart_tx_sem, K_MSEC(1500)) != 0) { + LOG_ERR("Tx data timeout"); + return -ETIMEDOUT; + } } - sys_put_be16(check_sum, &tx_packet->buf[data_len + R502A_HEADER_LEN]); - drv_data->tx_buf.len = pkg_len + R502A_HEADER_LEN; - drv_data->tx_buf.data = tx_packet->buf; + if (rx_packet) { + drv_data->rx_buf.data = rx_packet->buf; + drv_data->rx_buf.len = 0; + drv_data->pkt_len = R502A_HEADER_LEN; + uart_irq_rx_enable(cfg->dev); + if (k_sem_take(&drv_data->uart_rx_sem, K_MSEC(1500)) != 0) { + LOG_ERR("Rx data timeout"); + return -ETIMEDOUT; + } + } - drv_data->rx_buf.data = rx_packet->buf; + return 0; +} - LOG_HEXDUMP_DBG(drv_data->tx_buf.data, drv_data->tx_buf.len, "TX"); +static int r502a_validate_rx_packet(union r502a_packet *rx_packet) +{ + uint16_t recv_cks = 0, calc_cks = 0; + uint8_t cks_start_idx; - uart_irq_rx_disable(cfg->dev); - uart_irq_tx_enable(cfg->dev); + if (sys_be16_to_cpu(rx_packet->start) == R502A_STARTCODE) { + LOG_DBG("startcode matched 0x%X", sys_be16_to_cpu(rx_packet->start)); + } else { + LOG_ERR("startcode didn't match 0x%X", sys_be16_to_cpu(rx_packet->start)); + return -EINVAL; + } + + if (sys_be32_to_cpu(rx_packet->addr) == R502A_DEFAULT_ADDRESS) { + LOG_DBG("Address matched 0x%X", sys_be32_to_cpu(rx_packet->addr)); + } else { + LOG_ERR("Address didn't match 0x%X", sys_be32_to_cpu(rx_packet->addr)); + return -EINVAL; + } - k_sem_take(&drv_data->uart_rx_sem, K_FOREVER); + switch (rx_packet->pid) { + case R502A_DATA_PACKET: + LOG_DBG("Data Packet Received 0x%X", rx_packet->pid); + break; + case R502A_END_DATA_PACKET: + LOG_DBG("End of Data Packet Received 0x%X", rx_packet->pid); + break; + case R502A_ACK_PACKET: + LOG_DBG("Acknowledgment Packet Received 0x%X", rx_packet->pid); + break; + default: + LOG_ERR("Error Package ID 0x%X", rx_packet->pid); + return -EINVAL; + } + + cks_start_idx = sys_be16_to_cpu(rx_packet->len) - R502A_CHECKSUM_LEN; + + recv_cks = sys_get_be16(&rx_packet->data[cks_start_idx]); + + calc_cks += rx_packet->pid + (sys_be16_to_cpu(rx_packet->len) >> 8) + + (sys_be16_to_cpu(rx_packet->len) & 0xFF); + + for (int i = 0; i < cks_start_idx; i++) { + calc_cks += rx_packet->data[i]; + } + + if (recv_cks == calc_cks) { + LOG_DBG("Checksum matched calculated 0x%x received 0x%x", calc_cks, recv_cks); + } else { + LOG_ERR("Checksum mismatch calculated 0x%x received 0x%x", calc_cks, recv_cks); + return -EINVAL; + } + + return 0; } static void uart_cb_tx_handler(const struct device *dev) @@ -55,21 +127,18 @@ static void uart_cb_tx_handler(const struct device *dev) const struct grow_r502a_config *config = dev->config; struct grow_r502a_data *drv_data = dev->data; int sent = 0; - uint8_t retries = 3; - while (drv_data->tx_buf.len) { - sent = uart_fifo_fill(config->dev, &drv_data->tx_buf.data[sent], + if (drv_data->tx_buf.len > 0) { + sent = uart_fifo_fill(config->dev, drv_data->tx_buf.data, drv_data->tx_buf.len); + drv_data->tx_buf.data += sent; drv_data->tx_buf.len -= sent; } - while (retries--) { - if (uart_irq_tx_complete(config->dev)) { - uart_irq_tx_disable(config->dev); - drv_data->rx_buf.len = 0; - uart_irq_rx_enable(config->dev); - break; - } + if (!drv_data->tx_buf.len && uart_irq_tx_complete(config->dev) > 0) { + uart_irq_tx_disable(config->dev); + k_sem_give(&drv_data->uart_tx_sem); + return; } } @@ -77,7 +146,7 @@ static void uart_cb_handler(const struct device *dev, void *user_data) { const struct device *uart_dev = user_data; struct grow_r502a_data *drv_data = uart_dev->data; - int len, pkt_sz = 0; + int len = 0; int offset = drv_data->rx_buf.len; if ((uart_irq_update(dev) > 0) && (uart_irq_is_pending(dev) > 0)) { @@ -87,28 +156,131 @@ static void uart_cb_handler(const struct device *dev, void *user_data) while (uart_irq_rx_ready(dev)) { len = uart_fifo_read(dev, &drv_data->rx_buf.data[offset], - R502A_BUF_SIZE - offset); + drv_data->pkt_len); offset += len; drv_data->rx_buf.len = offset; - if (offset >= R502A_HEADER_LEN) { - pkt_sz = R502A_HEADER_LEN + - drv_data->rx_buf.data[R502A_HEADER_LEN-1]; + if (drv_data->pkt_len != len) { + drv_data->pkt_len -= len; + continue; } - if (offset < pkt_sz) { + + if (offset == R502A_HEADER_LEN) { + drv_data->pkt_len = sys_get_be16( + &drv_data->rx_buf.data[R502A_PKG_LEN_IDX] + ); continue; } + LOG_HEXDUMP_DBG(drv_data->rx_buf.data, offset, "RX"); + uart_irq_rx_disable(dev); k_sem_give(&drv_data->uart_rx_sem); break; } } } -static int fps_led_control(const struct device *dev, struct led_params *led_control) +/** + * @brief Set sensor device's basic parameters like baud rate, security level + * and data package length. + */ +static int fps_set_sys_param(const struct device *dev, const struct sensor_value *val) +{ + union r502a_packet rx_packet = {0}; + int ret = 0; + char const set_sys_param_len = 3; + + union r502a_packet tx_packet = { + .pid = R502A_COMMAND_PACKET, + .data = { R502A_SETSYSPARAM, val->val1, val->val2} + }; + + ret = transceive_packet(dev, &tx_packet, &rx_packet, set_sys_param_len); + if (ret != 0) { + return ret; + } + + ret = r502a_validate_rx_packet(&rx_packet); + if (ret != 0) { + return ret; + } + + if (rx_packet.buf[R502A_CC_IDX] == R502A_OK) { + LOG_DBG("R502A set system parameter success"); + } else { + LOG_ERR("R502A set system parameter error %d", rx_packet.buf[R502A_CC_IDX]); + return -EIO; + } + + return 0; +} + +int r502a_read_sys_param(const struct device *dev, struct r502a_sys_param *val) +{ + struct grow_r502a_data *drv_data = dev->data; + + union r502a_packet rx_packet = {0}; + int offset = 0, ret = 0; + char const read_sys_param_len = 1; + + union r502a_packet tx_packet = { + .pid = R502A_COMMAND_PACKET, + .data = {R502A_READSYSPARAM} + }; + + k_mutex_lock(&drv_data->lock, K_FOREVER); + + ret = transceive_packet(dev, &tx_packet, &rx_packet, read_sys_param_len); + if (ret != 0) { + goto unlock; + } + + ret = r502a_validate_rx_packet(&rx_packet); + if (ret != 0) { + goto unlock; + } + + if (rx_packet.buf[R502A_CC_IDX] == R502A_OK) { + LOG_DBG("R502A read system parameter success"); + } else { + LOG_ERR("R502A read system parameter error %d", rx_packet.buf[R502A_CC_IDX]); + ret = -EIO; + goto unlock; + } + + val->status_reg = sys_get_be16( + &rx_packet.data[offsetof(struct r502a_sys_param, status_reg) + 1] + ); + val->system_id = sys_get_be16( + &rx_packet.data[offsetof(struct r502a_sys_param, system_id) + 1] + ); + val->lib_size = sys_get_be16( + &rx_packet.data[offsetof(struct r502a_sys_param, lib_size) + 1] + ); + val->sec_level = sys_get_be16( + &rx_packet.data[offsetof(struct r502a_sys_param, sec_level) + 1] + ); + val->addr = sys_get_be32( + &rx_packet.data[offsetof(struct r502a_sys_param, addr) + 1] + ); + offset = sys_get_be16( + &rx_packet.data[offsetof(struct r502a_sys_param, data_pkt_size) + 1] + ); + val->data_pkt_size = 32 * (1 << offset); + val->baud = sys_get_be16( + &rx_packet.data[offsetof(struct r502a_sys_param, baud) + 1] + ) * 9600; + +unlock: + k_mutex_unlock(&drv_data->lock); + return ret; +} + +static int fps_led_control(const struct device *dev, struct r502a_led_params *led_control) { union r502a_packet rx_packet = {0}; char const led_ctrl_len = 5; + int ret = 0; union r502a_packet tx_packet = { .pid = R502A_COMMAND_PACKET, @@ -116,11 +288,14 @@ static int fps_led_control(const struct device *dev, struct led_params *led_cont led_control->speed, led_control->color_idx, led_control->cycle} }; - transceive_packet(dev, &tx_packet, &rx_packet, led_ctrl_len); + ret = transceive_packet(dev, &tx_packet, &rx_packet, led_ctrl_len); + if (ret != 0) { + return ret; + } - if (rx_packet.pid != R502A_ACK_PACKET) { - LOG_ERR("Error receiving ack packet 0x%X", rx_packet.pid); - return -EIO; + ret = r502a_validate_rx_packet(&rx_packet); + if (ret != 0) { + return ret; } if (rx_packet.buf[R502A_CC_IDX] == R502A_OK) { @@ -138,6 +313,7 @@ static int fps_verify_password(const struct device *dev) { union r502a_packet rx_packet = {0}; char const verify_pwd_len = 5; + int ret = 0; union r502a_packet tx_packet = { .pid = R502A_COMMAND_PACKET, @@ -146,17 +322,20 @@ static int fps_verify_password(const struct device *dev) sys_put_be32(R502A_DEFAULT_PASSWORD, &tx_packet.data[1]); - transceive_packet(dev, &tx_packet, &rx_packet, verify_pwd_len); + ret = transceive_packet(dev, &tx_packet, &rx_packet, verify_pwd_len); + if (ret != 0) { + return ret; + } - if (rx_packet.pid != R502A_ACK_PACKET) { - LOG_ERR("Error receiving ack packet 0x%X", rx_packet.pid); - return -EIO; + ret = r502a_validate_rx_packet(&rx_packet); + if (ret != 0) { + return ret; } if (rx_packet.buf[R502A_CC_IDX] == R502A_OK) { LOG_DBG("Correct password, R502A verified"); } else { - LOG_ERR("Package receive error 0x%X", rx_packet.buf[R502A_CC_IDX]); + LOG_ERR("Password verification error 0x%X", rx_packet.buf[R502A_CC_IDX]); return -EIO; } @@ -168,17 +347,21 @@ static int fps_get_template_count(const struct device *dev) struct grow_r502a_data *drv_data = dev->data; union r502a_packet rx_packet = {0}; char const get_temp_cnt_len = 1; + int ret = 0; union r502a_packet tx_packet = { .pid = R502A_COMMAND_PACKET, .data = {R502A_TEMPLATECOUNT}, }; - transceive_packet(dev, &tx_packet, &rx_packet, get_temp_cnt_len); + ret = transceive_packet(dev, &tx_packet, &rx_packet, get_temp_cnt_len); + if (ret != 0) { + return ret; + } - if (rx_packet.pid != R502A_ACK_PACKET) { - LOG_ERR("Error receiving ack packet 0x%X", rx_packet.pid); - return -EIO; + ret = r502a_validate_rx_packet(&rx_packet); + if (ret != 0) { + return ret; } if (rx_packet.buf[R502A_CC_IDX] == R502A_OK) { @@ -193,7 +376,7 @@ static int fps_get_template_count(const struct device *dev) return 0; } -static int fps_read_template_table(const struct device *dev) +static int fps_read_template_table(const struct device *dev, uint32_t *free_idx) { struct grow_r502a_data *drv_data = dev->data; union r502a_packet rx_packet = {0}; @@ -207,13 +390,14 @@ static int fps_read_template_table(const struct device *dev) k_mutex_lock(&drv_data->lock, K_FOREVER); - transceive_packet(dev, &tx_packet, &rx_packet, temp_table_len); - - if (rx_packet.pid != R502A_ACK_PACKET) { - LOG_ERR("Error receiving ack packet 0x%X", rx_packet.pid); - ret = -EIO; + ret = transceive_packet(dev, &tx_packet, &rx_packet, temp_table_len); + if (ret != 0) { goto unlock; + } + ret = r502a_validate_rx_packet(&rx_packet); + if (ret != 0) { + goto unlock; } if (rx_packet.buf[R502A_CC_IDX] == R502A_OK) { @@ -232,7 +416,7 @@ static int fps_read_template_table(const struct device *dev) continue; } - drv_data->free_idx = (group_idx * 8) + find_lsb_set(~group) - 1; + *free_idx = (group_idx * 8) + find_lsb_set(~group) - 1; goto unlock; } @@ -245,11 +429,12 @@ static int fps_get_image(const struct device *dev) { union r502a_packet rx_packet = {0}; char const get_img_len = 1; + int ret = 0; - struct led_params led_ctrl = { - .ctrl_code = LED_CTRL_BREATHING, - .color_idx = LED_COLOR_BLUE, - .speed = LED_SPEED_HALF, + struct r502a_led_params led_ctrl = { + .ctrl_code = R502A_LED_CTRL_BREATHING, + .color_idx = R502A_LED_COLOR_BLUE, + .speed = R502A_LED_SPEED_HALF, .cycle = 0x01, }; @@ -258,19 +443,22 @@ static int fps_get_image(const struct device *dev) .data = {R502A_GENIMAGE}, }; - transceive_packet(dev, &tx_packet, &rx_packet, get_img_len); + ret = transceive_packet(dev, &tx_packet, &rx_packet, get_img_len); + if (ret != 0) { + return ret; + } - if (rx_packet.pid != R502A_ACK_PACKET) { - LOG_ERR("Error receiving ack packet 0x%X", rx_packet.pid); - return -EIO; + ret = r502a_validate_rx_packet(&rx_packet); + if (ret != 0) { + return ret; } if (rx_packet.buf[R502A_CC_IDX] == R502A_OK) { fps_led_control(dev, &led_ctrl); LOG_DBG("Image taken"); } else { - led_ctrl.ctrl_code = LED_CTRL_ON_ALWAYS; - led_ctrl.color_idx = LED_COLOR_RED; + led_ctrl.ctrl_code = R502A_LED_CTRL_ON_ALWAYS; + led_ctrl.color_idx = R502A_LED_COLOR_RED; fps_led_control(dev, &led_ctrl); LOG_ERR("Error getting image 0x%X", rx_packet.buf[R502A_CC_IDX]); return -EIO; @@ -283,17 +471,21 @@ static int fps_image_to_char(const struct device *dev, uint8_t char_buf_idx) { union r502a_packet rx_packet = {0}; char const img_to_char_len = 2; + int ret = 0; union r502a_packet tx_packet = { .pid = R502A_COMMAND_PACKET, .data = {R502A_IMAGE2TZ, char_buf_idx} }; - transceive_packet(dev, &tx_packet, &rx_packet, img_to_char_len); + ret = transceive_packet(dev, &tx_packet, &rx_packet, img_to_char_len); + if (ret != 0) { + return ret; + } - if (rx_packet.pid != R502A_ACK_PACKET) { - LOG_ERR("Error receiving ack packet 0x%X", rx_packet.pid); - return -EIO; + ret = r502a_validate_rx_packet(&rx_packet); + if (ret != 0) { + return ret; } if (rx_packet.buf[R502A_CC_IDX] == R502A_OK) { @@ -310,17 +502,21 @@ static int fps_create_model(const struct device *dev) { union r502a_packet rx_packet = {0}; char const create_model_len = 1; + int ret = 0; union r502a_packet tx_packet = { .pid = R502A_COMMAND_PACKET, .data = {R502A_REGMODEL} }; - transceive_packet(dev, &tx_packet, &rx_packet, create_model_len); + ret = transceive_packet(dev, &tx_packet, &rx_packet, create_model_len); + if (ret != 0) { + return ret; + } - if (rx_packet.pid != R502A_ACK_PACKET) { - LOG_ERR("Error receiving ack packet 0x%X", rx_packet.pid); - return -EIO; + ret = r502a_validate_rx_packet(&rx_packet); + if (ret != 0) { + return ret; } if (rx_packet.buf[R502A_CC_IDX] == R502A_OK) { @@ -335,13 +531,15 @@ static int fps_create_model(const struct device *dev) static int fps_store_model(const struct device *dev, uint16_t id) { + struct grow_r502a_data *drv_data = dev->data; union r502a_packet rx_packet = {0}; char const store_model_len = 4; + int ret = 0; - struct led_params led_ctrl = { - .ctrl_code = LED_CTRL_BREATHING, - .color_idx = LED_COLOR_BLUE, - .speed = LED_SPEED_HALF, + struct r502a_led_params led_ctrl = { + .ctrl_code = R502A_LED_CTRL_BREATHING, + .color_idx = R502A_LED_COLOR_BLUE, + .speed = R502A_LED_SPEED_HALF, .cycle = 0x01, }; @@ -351,31 +549,39 @@ static int fps_store_model(const struct device *dev, uint16_t id) }; sys_put_be16(id, &tx_packet.data[2]); - transceive_packet(dev, &tx_packet, &rx_packet, store_model_len); + k_mutex_lock(&drv_data->lock, K_FOREVER); - if (rx_packet.pid != R502A_ACK_PACKET) { - LOG_ERR("Error receiving ack packet 0x%X", rx_packet.pid); - return -EIO; + ret = transceive_packet(dev, &tx_packet, &rx_packet, store_model_len); + if (ret != 0) { + goto unlock; + } + + ret = r502a_validate_rx_packet(&rx_packet); + if (ret != 0) { + goto unlock; } if (rx_packet.buf[R502A_CC_IDX] == R502A_OK) { - led_ctrl.color_idx = LED_COLOR_BLUE; - led_ctrl.ctrl_code = LED_CTRL_FLASHING; + led_ctrl.color_idx = R502A_LED_COLOR_BLUE; + led_ctrl.ctrl_code = R502A_LED_CTRL_FLASHING; led_ctrl.cycle = 0x03; fps_led_control(dev, &led_ctrl); LOG_INF("Fingerprint stored! at ID #%d", id); } else { LOG_ERR("Error storing model 0x%X", rx_packet.buf[R502A_CC_IDX]); - return -EIO; + ret = -EIO; } - - return 0; +unlock: + k_mutex_unlock(&drv_data->lock); + return ret; } static int fps_delete_model(const struct device *dev, uint16_t id, uint16_t count) { + struct grow_r502a_data *drv_data = dev->data; union r502a_packet rx_packet = {0}; char const delete_model_len = 5; + int ret = 0; union r502a_packet tx_packet = { .pid = R502A_COMMAND_PACKET, @@ -384,21 +590,27 @@ static int fps_delete_model(const struct device *dev, uint16_t id, uint16_t coun sys_put_be16(id, &tx_packet.data[1]); sys_put_be16(count + R502A_DELETE_COUNT_OFFSET, &tx_packet.data[3]); - transceive_packet(dev, &tx_packet, &rx_packet, delete_model_len); + k_mutex_lock(&drv_data->lock, K_FOREVER); - if (rx_packet.pid != R502A_ACK_PACKET) { - LOG_ERR("Error receiving ack packet 0x%X", rx_packet.pid); - return -EIO; + ret = transceive_packet(dev, &tx_packet, &rx_packet, delete_model_len); + if (ret != 0) { + goto unlock; + } + + ret = r502a_validate_rx_packet(&rx_packet); + if (ret != 0) { + goto unlock; } if (rx_packet.buf[R502A_CC_IDX] == R502A_OK) { LOG_INF("Fingerprint Deleted from ID #%d to #%d", id, (id + count)); } else { LOG_ERR("Error deleting image 0x%X", rx_packet.buf[R502A_CC_IDX]); - return -EIO; + ret = -EIO; } - - return 0; +unlock: + k_mutex_unlock(&drv_data->lock); + return ret; } static int fps_empty_db(const struct device *dev) @@ -415,11 +627,13 @@ static int fps_empty_db(const struct device *dev) k_mutex_lock(&drv_data->lock, K_FOREVER); - transceive_packet(dev, &tx_packet, &rx_packet, empty_db_len); + ret = transceive_packet(dev, &tx_packet, &rx_packet, empty_db_len); + if (ret != 0) { + goto unlock; + } - if (rx_packet.pid != R502A_ACK_PACKET) { - LOG_ERR("Error receiving ack packet 0x%X", rx_packet.pid); - ret = -EIO; + ret = r502a_validate_rx_packet(&rx_packet); + if (ret != 0) { goto unlock; } @@ -429,152 +643,320 @@ static int fps_empty_db(const struct device *dev) LOG_ERR("Error emptying fingerprint library 0x%X", rx_packet.buf[R502A_CC_IDX]); ret = -EIO; - goto unlock; } unlock: k_mutex_unlock(&drv_data->lock); - return 0; + return ret; } -static int fps_search(const struct device *dev, uint8_t char_buf_idx) +static int fps_search(const struct device *dev, struct sensor_value *val) { struct grow_r502a_data *drv_data = dev->data; union r502a_packet rx_packet = {0}; char const search_len = 6; + int ret = 0; - struct led_params led_ctrl = { - .ctrl_code = LED_CTRL_BREATHING, - .color_idx = LED_COLOR_BLUE, - .speed = LED_SPEED_HALF, + struct r502a_led_params led_ctrl = { + .ctrl_code = R502A_LED_CTRL_BREATHING, + .color_idx = R502A_LED_COLOR_BLUE, + .speed = R502A_LED_SPEED_HALF, .cycle = 0x01, }; union r502a_packet tx_packet = { .pid = R502A_COMMAND_PACKET, - .data = {R502A_SEARCH, char_buf_idx} + .data = {R502A_SEARCH, R502A_CHAR_BUF_1} }; - sys_put_be16(R02A_LIBRARY_START_IDX, &tx_packet.data[1]); - sys_put_be16(R502A_DEFAULT_CAPACITY, &tx_packet.data[3]); + sys_put_be16(R02A_LIBRARY_START_IDX, &tx_packet.data[2]); + sys_put_be16(R502A_DEFAULT_CAPACITY, &tx_packet.data[4]); - transceive_packet(dev, &tx_packet, &rx_packet, search_len); + k_mutex_lock(&drv_data->lock, K_FOREVER); - if (rx_packet.pid != R502A_ACK_PACKET) { - LOG_ERR("Error receiving ack packet 0x%X", rx_packet.pid); - return -EIO; + ret = transceive_packet(dev, &tx_packet, &rx_packet, search_len); + if (ret != 0) { + goto unlock; + } + + ret = r502a_validate_rx_packet(&rx_packet); + if (ret != 0) { + goto unlock; } if (rx_packet.buf[R502A_CC_IDX] == R502A_OK) { - led_ctrl.ctrl_code = LED_CTRL_FLASHING; - led_ctrl.color_idx = LED_COLOR_PURPLE; + led_ctrl.ctrl_code = R502A_LED_CTRL_FLASHING; + led_ctrl.color_idx = R502A_LED_COLOR_PURPLE; led_ctrl.cycle = 0x01; fps_led_control(dev, &led_ctrl); - drv_data->finger_id = sys_get_be16(&rx_packet.data[1]); - drv_data->matching_score = sys_get_be16(&rx_packet.data[3]); - LOG_INF("Found a matching print! at ID #%d", drv_data->finger_id); - } else if (rx_packet.buf[R502A_CC_IDX] == R502A_NOT_FOUND) { - led_ctrl.ctrl_code = LED_CTRL_BREATHING; - led_ctrl.color_idx = LED_COLOR_RED; + val->val1 = sys_get_be16(&rx_packet.data[1]); + val->val2 = sys_get_be16(&rx_packet.data[3]); + LOG_INF("Found a matching print! at ID #%d", val->val1); + } else if (rx_packet.buf[R502A_CC_IDX] == R502A_NOT_FOUND_CC) { + led_ctrl.ctrl_code = R502A_LED_CTRL_BREATHING; + led_ctrl.color_idx = R502A_LED_COLOR_RED; led_ctrl.cycle = 0x02; fps_led_control(dev, &led_ctrl); LOG_ERR("Did not find a match"); + ret = -ENOENT; } else { - led_ctrl.ctrl_code = LED_CTRL_ON_ALWAYS; - led_ctrl.color_idx = LED_COLOR_RED; + led_ctrl.ctrl_code = R502A_LED_CTRL_ON_ALWAYS; + led_ctrl.color_idx = R502A_LED_COLOR_RED; fps_led_control(dev, &led_ctrl); LOG_ERR("Error searching for image 0x%X", rx_packet.buf[R502A_CC_IDX]); - return -EIO; + ret = -EIO; } - - return 0; +unlock: + k_mutex_unlock(&drv_data->lock); + return ret; } -static int fps_enroll(const struct device *dev, const struct sensor_value *val) +static int fps_load_template(const struct device *dev, uint16_t id) { struct grow_r502a_data *drv_data = dev->data; - int ret = -1; + union r502a_packet rx_packet = {0}; + char const load_tmp_len = 4; + int ret = 0; - if (val->val1 < 0 || val->val1 > R502A_DEFAULT_CAPACITY) { - LOG_ERR("Invalid ID number"); - return -EINVAL; + union r502a_packet tx_packet = { + .pid = R502A_COMMAND_PACKET, + .data = {R502A_LOAD, R502A_CHAR_BUF_1} + }; + sys_put_be16(id, &tx_packet.data[2]); + + k_mutex_lock(&drv_data->lock, K_FOREVER); + + ret = transceive_packet(dev, &tx_packet, &rx_packet, load_tmp_len); + if (ret != 0) { + goto unlock; } + ret = r502a_validate_rx_packet(&rx_packet); + if (ret != 0) { + goto unlock; + } + + if (rx_packet.buf[R502A_CC_IDX] == R502A_OK) { + LOG_DBG("Load template data from id #%d to Char_buffer2", id); + } else { + LOG_ERR("Error Loading template 0x%X", + rx_packet.buf[R502A_CC_IDX]); + ret = -EIO; + } + +unlock: + k_mutex_unlock(&drv_data->lock); + return ret; +} + +static int fps_match_templates(const struct device *dev, struct sensor_value *val) +{ + struct grow_r502a_data *drv_data = dev->data; + union r502a_packet rx_packet = {0}; + char const match_templates_len = 1; + int ret = 0; + + struct r502a_led_params led_ctrl = { + .ctrl_code = R502A_LED_CTRL_BREATHING, + .color_idx = R502A_LED_COLOR_BLUE, + .speed = R502A_LED_SPEED_HALF, + .cycle = 0x01, + }; + + union r502a_packet tx_packet = { + .pid = R502A_COMMAND_PACKET, + .data = {R502A_MATCH} + }; + k_mutex_lock(&drv_data->lock, K_FOREVER); - ret = fps_get_image(dev); + ret = transceive_packet(dev, &tx_packet, &rx_packet, match_templates_len); if (ret != 0) { goto unlock; } - ret = fps_image_to_char(dev, R502A_CHAR_BUF_1); + ret = r502a_validate_rx_packet(&rx_packet); if (ret != 0) { goto unlock; } + if (rx_packet.buf[R502A_CC_IDX] == R502A_OK) { + fps_led_control(dev, &led_ctrl); + val->val1 = R502A_FINGER_MATCH_FOUND; + val->val2 = sys_get_be16(&rx_packet.data[1]); + LOG_INF("Fingerprint matched with a score %d", val->val2); + } else if (rx_packet.buf[R502A_CC_IDX] == R502A_NOT_MATCH_CC) { + val->val1 = R502A_FINGER_MATCH_NOT_FOUND; + LOG_ERR("Fingerprint not matched"); + ret = -ENOENT; + } else { + led_ctrl.ctrl_code = R502A_LED_CTRL_ON_ALWAYS; + led_ctrl.color_idx = R502A_LED_COLOR_RED; + fps_led_control(dev, &led_ctrl); + LOG_ERR("Error Matching templates 0x%X", + rx_packet.buf[R502A_CC_IDX]); + ret = -EIO; + } +unlock: + k_mutex_unlock(&drv_data->lock); + return ret; +} + +static int fps_capture(const struct device *dev) +{ + struct grow_r502a_data *drv_data = dev->data; + int ret; + + k_mutex_lock(&drv_data->lock, K_FOREVER); + ret = fps_get_image(dev); if (ret != 0) { goto unlock; } - ret = fps_image_to_char(dev, R502A_CHAR_BUF_2); + ret = fps_image_to_char(dev, R502A_CHAR_BUF_1); if (ret != 0) { goto unlock; } - ret = fps_create_model(dev); + ret = fps_get_image(dev); if (ret != 0) { goto unlock; } - ret = fps_store_model(dev, val->val1); + ret = fps_image_to_char(dev, R502A_CHAR_BUF_2); unlock: k_mutex_unlock(&drv_data->lock); return ret; } -static int fps_delete(const struct device *dev, const struct sensor_value *val) +/** + * @brief upload template from sensor device's RAM buffer 1 to controller. + * + * @result temp->data holds the template to be uploaded to controller. + * temp->len holds the length of the template. + */ +int fps_upload_char_buf(const struct device *dev, struct r502a_template *temp) { struct grow_r502a_data *drv_data = dev->data; - int ret = -1; + union r502a_packet rx_packet = {0}; + char const upload_temp_len = 2; + int ret = 0, idx = 0; + + if (!temp->data || (temp->len < R502A_TEMPLATE_MAX_SIZE)) { + LOG_ERR("Invalid temp data"); + return -EINVAL; + } + + union r502a_packet tx_packet = { + .pid = R502A_COMMAND_PACKET, + .data = {R502A_UPCHAR, R502A_CHAR_BUF_1} + }; k_mutex_lock(&drv_data->lock, K_FOREVER); - ret = fps_delete_model(dev, val->val1, val->val2); + ret = transceive_packet(dev, &tx_packet, &rx_packet, upload_temp_len); if (ret != 0) { goto unlock; } - ret = fps_get_template_count(dev); + ret = r502a_validate_rx_packet(&rx_packet); + if (ret != 0) { + goto unlock; + } + + if (rx_packet.buf[R502A_CC_IDX] == R502A_OK) { + LOG_DBG("Upload to host controller"); + } else { + LOG_ERR("Error uploading template 0x%X", + rx_packet.buf[R502A_CC_IDX]); + ret = -EIO; + goto unlock; + } + + do { + ret = transceive_packet(dev, NULL, &rx_packet, 0); + if (ret != 0) { + goto unlock; + } + + ret = r502a_validate_rx_packet(&rx_packet); + if (ret != 0) { + goto unlock; + } + + memcpy(&temp->data[idx], &rx_packet.data, + sys_be16_to_cpu(rx_packet.len) - R502A_CHECKSUM_LEN); + idx += sys_be16_to_cpu(rx_packet.len) - R502A_CHECKSUM_LEN; + } while (rx_packet.pid != R502A_END_DATA_PACKET); + + temp->len = idx; unlock: k_mutex_unlock(&drv_data->lock); return ret; } -static int fps_match(const struct device *dev, struct sensor_value *val) +/** + * @brief download template from controller to sensor device's RAM buffer. + * @Notes char_buf_id - other than value 1 will be considered as value 2 + * by R502A sensor. + */ +int fps_download_char_buf(const struct device *dev, uint8_t char_buf_id, + const struct r502a_template *temp) { struct grow_r502a_data *drv_data = dev->data; - int ret = -1; + union r502a_packet rx_packet = {0}; + char const down_temp_len = 2; + int ret = 0, i = 0; + + if (!temp->data || (temp->len < R502A_TEMPLATE_MAX_SIZE)) { + LOG_ERR("Invalid temp data"); + return -EINVAL; + } + + union r502a_packet tx_packet = { + .pid = R502A_COMMAND_PACKET, + .data = {R502A_DOWNCHAR, char_buf_id} + }; k_mutex_lock(&drv_data->lock, K_FOREVER); - ret = fps_get_image(dev); + ret = transceive_packet(dev, &tx_packet, &rx_packet, down_temp_len); if (ret != 0) { goto unlock; } - ret = fps_image_to_char(dev, R502A_CHAR_BUF_1); + ret = r502a_validate_rx_packet(&rx_packet); if (ret != 0) { goto unlock; } - ret = fps_search(dev, R502A_CHAR_BUF_1); - if (ret == 0) { - val->val1 = drv_data->finger_id; - val->val2 = drv_data->matching_score; + if (rx_packet.buf[R502A_CC_IDX] == R502A_OK) { + LOG_DBG("Download to R502A sensor"); + } else { + LOG_ERR("Error downloading template 0x%X", + rx_packet.buf[R502A_CC_IDX]); + ret = -EIO; + goto unlock; + } + + while (i < (R502A_TEMPLATE_MAX_SIZE - CONFIG_R502A_DATA_PKT_SIZE)) { + tx_packet.pid = R502A_DATA_PACKET; + memcpy(tx_packet.data, &temp->data[i], CONFIG_R502A_DATA_PKT_SIZE); + + ret = transceive_packet(dev, &tx_packet, NULL, CONFIG_R502A_DATA_PKT_SIZE); + if (ret != 0) { + goto unlock; + } + + i += CONFIG_R502A_DATA_PKT_SIZE; } + memcpy(tx_packet.data, &temp->data[i], (R502A_TEMPLATE_MAX_SIZE - i)); + tx_packet.pid = R502A_END_DATA_PACKET; + ret = transceive_packet(dev, &tx_packet, NULL, (R502A_TEMPLATE_MAX_SIZE - i)); + unlock: k_mutex_unlock(&drv_data->lock); return ret; @@ -583,12 +965,13 @@ static int fps_match(const struct device *dev, struct sensor_value *val) static int fps_init(const struct device *dev) { struct grow_r502a_data *drv_data = dev->data; + struct sensor_value val; int ret; - struct led_params led_ctrl = { - .ctrl_code = LED_CTRL_FLASHING, - .color_idx = LED_COLOR_PURPLE, - .speed = LED_SPEED_HALF, + struct r502a_led_params led_ctrl = { + .ctrl_code = R502A_LED_CTRL_FLASHING, + .color_idx = R502A_LED_COLOR_PURPLE, + .speed = R502A_LED_SPEED_HALF, .cycle = 0x02, }; @@ -599,6 +982,13 @@ static int fps_init(const struct device *dev) goto unlock; } + val.val1 = R502A_DATA_PKG_LEN; + val.val2 = LOG2(CONFIG_R502A_DATA_PKT_SIZE >> 5); + ret = fps_set_sys_param(dev, &val); + if (ret != 0) { + goto unlock; + } + ret = fps_led_control(dev, &led_ctrl); unlock: @@ -636,18 +1026,42 @@ static int grow_r502a_channel_get(const struct device *dev, enum sensor_channel static int grow_r502a_attr_set(const struct device *dev, enum sensor_channel chan, enum sensor_attribute attr, const struct sensor_value *val) { + struct grow_r502a_data *drv_data = dev->data; + if ((enum sensor_channel_grow_r502a)chan != SENSOR_CHAN_FINGERPRINT) { LOG_ERR("Channel not supported"); return -ENOTSUP; } switch ((enum sensor_attribute_grow_r502a)attr) { + case SENSOR_ATTR_R502A_CAPTURE: + return fps_capture(dev); + case SENSOR_ATTR_R502A_TEMPLATE_CREATE: + return fps_create_model(dev); case SENSOR_ATTR_R502A_RECORD_ADD: - return fps_enroll(dev, val); + return fps_store_model(dev, val->val1); case SENSOR_ATTR_R502A_RECORD_DEL: - return fps_delete(dev, val); + return fps_delete_model(dev, val->val1, val->val2); case SENSOR_ATTR_R502A_RECORD_EMPTY: return fps_empty_db(dev); + case SENSOR_ATTR_R502A_RECORD_LOAD: + return fps_load_template(dev, val->val1); + case SENSOR_ATTR_R502A_SYS_PARAM: { + int ret = 0; + + if (val->val1 == R502A_DATA_PKG_LEN) { + LOG_ERR("Data package length should not be runtime configurable"); + return -EINVAL; + }; + k_mutex_lock(&drv_data->lock, K_FOREVER); + ret = fps_set_sys_param(dev, val); + if (ret != 0) { + k_mutex_unlock(&drv_data->lock); + return ret; + } + k_mutex_unlock(&drv_data->lock); + return 0; + } default: LOG_ERR("Sensor attribute not supported"); return -ENOTSUP; @@ -659,7 +1073,6 @@ static int grow_r502a_attr_get(const struct device *dev, enum sensor_channel cha enum sensor_attribute attr, struct sensor_value *val) { int ret; - struct grow_r502a_data *drv_data = dev->data; if ((enum sensor_channel_grow_r502a)chan != SENSOR_CHAN_FINGERPRINT) { LOG_ERR("Channel not supported"); @@ -668,11 +1081,13 @@ static int grow_r502a_attr_get(const struct device *dev, enum sensor_channel cha switch ((enum sensor_attribute_grow_r502a)attr) { case SENSOR_ATTR_R502A_RECORD_FIND: - ret = fps_match(dev, val); + ret = fps_search(dev, val); break; case SENSOR_ATTR_R502A_RECORD_FREE_IDX: - ret = fps_read_template_table(dev); - val->val1 = drv_data->free_idx; + ret = fps_read_template_table(dev, &val->val1); + break; + case SENSOR_ATTR_R502A_COMPARE: + ret = fps_match_templates(dev, val); break; default: LOG_ERR("Sensor attribute not supported"); @@ -734,9 +1149,13 @@ static int grow_r502a_init(const struct device *dev) k_mutex_init(&drv_data->lock); k_sem_init(&drv_data->uart_rx_sem, 0, 1); + k_sem_init(&drv_data->uart_tx_sem, 0, 1); uart_irq_callback_user_data_set(cfg->dev, uart_cb_handler, (void *)dev); + uart_irq_rx_disable(cfg->dev); + uart_irq_tx_disable(cfg->dev); + #ifdef CONFIG_GROW_R502A_TRIGGER ret = grow_r502a_init_interrupt(dev); @@ -759,6 +1178,53 @@ static const struct sensor_driver_api grow_r502a_api = { #endif }; +#ifdef CONFIG_LED +static int grow_r502a_led_set_color(const struct device *dev, uint32_t led, + uint8_t num_colors, const uint8_t *color) +{ + struct grow_r502a_data *drv_data = dev->data; + + if (!(*color)) { + LOG_ERR("invalid color code value"); + return -ENOTSUP; + } + drv_data->led_color = *color; + + return 0; +} + +static int grow_r502a_led_on(const struct device *dev, uint32_t led) +{ + struct grow_r502a_data *drv_data = dev->data; + + if (!drv_data->led_color) { + drv_data->led_color = R502A_LED_COLOR_BLUE; + } + + struct r502a_led_params led_ctrl = { + .ctrl_code = R502A_LED_CTRL_ON_ALWAYS, + .color_idx = drv_data->led_color, + }; + + return fps_led_control(dev, &led_ctrl); +} + +static int grow_r502a_led_off(const struct device *dev, uint32_t led) +{ + struct r502a_led_params led_ctrl = { + .ctrl_code = R502A_LED_CTRL_OFF_ALWAYS, + }; + + return fps_led_control(dev, &led_ctrl); +} + +static const struct led_driver_api grow_r502a_leds_api = { + .set_color = grow_r502a_led_set_color, + .on = grow_r502a_led_on, + .off = grow_r502a_led_off, +}; +#endif + #define GROW_R502A_INIT(index) \ static struct grow_r502a_data grow_r502a_data_##index; \ \ @@ -773,7 +1239,20 @@ static const struct sensor_driver_api grow_r502a_api = { }; \ \ DEVICE_DT_INST_DEFINE(index, &grow_r502a_init, NULL, &grow_r502a_data_##index, \ - &grow_r502a_config_##index, POST_KERNEL, \ - CONFIG_SENSOR_INIT_PRIORITY, &grow_r502a_api); + &grow_r502a_config_##index, POST_KERNEL, \ + CONFIG_SENSOR_INIT_PRIORITY, &grow_r502a_api); \ + +#define GROW_R502A_LED_INIT(index) \ + DEVICE_DT_INST_DEFINE(index, NULL, NULL, &grow_r502a_data_##index, \ + &grow_r502a_config_##index, POST_KERNEL, \ + CONFIG_LED_INIT_PRIORITY, &grow_r502a_leds_api); \ +#define DT_DRV_COMPAT hzgrow_r502a DT_INST_FOREACH_STATUS_OKAY(GROW_R502A_INIT) +#undef DT_DRV_COMPAT + +#ifdef CONFIG_LED +#define DT_DRV_COMPAT hzgrow_r502a_led +DT_INST_FOREACH_STATUS_OKAY(GROW_R502A_LED_INIT) +#undef DT_DRV_COMPAT +#endif diff --git a/drivers/sensor/grow_r502a/grow_r502a.h b/drivers/sensor/grow_r502a/grow_r502a.h index c8374fb17d3..154693f5701 100644 --- a/drivers/sensor/grow_r502a/grow_r502a.h +++ b/drivers/sensor/grow_r502a/grow_r502a.h @@ -61,7 +61,6 @@ */ #define R502A_OK 0x00 /*commad execution complete*/ -#define R502A_NOT_FOUND 0x09 /*fail to find the matching finger*/ /*Package Identifier's definition*/ #define R502A_COMMAND_PACKET 0x1 /*Command packet*/ @@ -95,6 +94,11 @@ #define R502A_HANDSHAKE 0x40 /*Handshake*/ #define R502A_BADPACKET 0xFE /* Bad packet was sent*/ +#define R502A_NOT_MATCH_CC 0x08 /* templates of two buffers not matching*/ +#define R502A_NOT_FOUND_CC 0x09 /*fail to find the matching finger*/ +#define R502A_FINGER_MATCH_NOT_FOUND 0 +#define R502A_FINGER_MATCH_FOUND 1 + #define R502A_STARTCODE 0xEF01 /*Fixed value, High byte transferred first*/ #define R502A_DEFAULT_PASSWORD 0x00000000 #define R502A_DEFAULT_ADDRESS 0xFFFFFFFF @@ -108,6 +112,8 @@ #define R502A_PKG_LEN_IDX 7 #define R502A_CC_IDX 9 /* Confirmation code index*/ +#define R502A_COMMON_ACK_LEN 12 + #define R502A_STARTCODE_LEN 2 #define R502A_ADDRESS_LEN 4 #define R502A_PKG_LEN 2 @@ -116,10 +122,14 @@ #define R502A_CHAR_BUF_1 1 #define R502A_CHAR_BUF_2 2 +#define R502A_CHAR_BUF_TOTAL 2 + #define R502A_CHAR_BUF_SIZE 384 /* Maximum size of characteristic value buffer*/ #define R502A_TEMPLATE_SIZE 768 /* Maximum size of template, twice of CHAR_BUF*/ -#define R502A_MAX_BUF_SIZE 779 /*sum of checksum, header and template sizes*/ -#define R502A_BUF_SIZE 64 +#define R502A_TEMPLATE_MAX_SIZE (R502A_CHAR_BUF_TOTAL * R502A_TEMPLATE_SIZE) + +#define R502A_MAX_BUF_SIZE (CONFIG_R502A_DATA_PKT_SIZE + R502A_COMMON_ACK_LEN) + #define R502A_TEMPLATES_PER_PAGE 256 #define R502A_TEMP_TABLE_BUF_SIZE 32 #define R502A_DELETE_COUNT_OFFSET 1 @@ -127,21 +137,40 @@ #define R502A_DELAY 200 #define R502A_RETRY_DELAY 5 -#define LED_CTRL_BREATHING 0x01 -#define LED_CTRL_FLASHING 0x02 -#define LED_CTRL_ON_ALWAYS 0x03 -#define LED_CTRL_OFF_ALWAYS 0x04 -#define LED_CTRL_ON_GRADUALLY 0x05 -#define LED_CTRL_OFF_GRADUALLY 0x06 +/*LED glow control code*/ +enum r502a_led_ctrl_code { + R502A_LED_CTRL_BREATHING = 0x01, + R502A_LED_CTRL_FLASHING, + R502A_LED_CTRL_ON_ALWAYS, + R502A_LED_CTRL_OFF_ALWAYS, + R502A_LED_CTRL_ON_GRADUALLY, + R502A_LED_CTRL_OFF_GRADUALLY, +}; -#define LED_SPEED_HALF 0x50 -#define LED_SPEED_FULL 0xFF +/* LED glow speed code + * if needed, use desired speed between 0-255 + */ +enum r502a_led_speed { + R502A_LED_SPEED_MAX = 0x00, + R502A_LED_SPEED_HALF = 0x50, + R502A_LED_SPEED_MIN = 0xFF, +}; + +/* LED glowing cycle + * if needed, use desired cycle count between 1-255 + */ +enum r502a_led_cycle { + R502A_LED_CYCLE_INFINITE = 0x00, + R502A_LED_CYCLE_1, + R502A_LED_CYCLE_2, + R502A_LED_CYCLE_3, + R502A_LED_CYCLE_4, + R502A_LED_CYCLE_5, + R502A_LED_CYCLE_255 = 0xFF, +}; -#define LED_COLOR_RED 0x01 -#define LED_COLOR_BLUE 0x02 -#define LED_COLOR_PURPLE 0x03 -struct led_params { +struct r502a_led_params { uint8_t ctrl_code; uint8_t color_idx; uint8_t speed; /* Speed 0x00-0xff */ @@ -150,14 +179,14 @@ struct led_params { union r502a_packet { struct { - uint8_t start[R502A_STARTCODE_LEN]; - uint8_t addr[R502A_ADDRESS_LEN]; + uint16_t start; + uint32_t addr; uint8_t pid; - uint8_t len[R502A_PKG_LEN]; - uint8_t data[R502A_BUF_SIZE]; - }; + uint16_t len; + uint8_t data[CONFIG_R502A_DATA_PKT_SIZE]; + } __packed; - uint8_t buf[R502A_BUF_SIZE]; + uint8_t buf[R502A_MAX_BUF_SIZE]; }; struct r502a_buf { @@ -183,14 +212,14 @@ struct grow_r502a_data { struct r502a_buf tx_buf; struct r502a_buf rx_buf; + uint16_t pkt_len; struct k_mutex lock; + struct k_sem uart_tx_sem; struct k_sem uart_rx_sem; - uint16_t finger_id; - uint16_t matching_score; uint16_t template_count; - int8_t free_idx; + uint8_t led_color; }; struct grow_r502a_config { diff --git a/drivers/sensor/maxim/ds18b20/Kconfig b/drivers/sensor/maxim/ds18b20/Kconfig index ac7fe02ac46..82f5160ff73 100644 --- a/drivers/sensor/maxim/ds18b20/Kconfig +++ b/drivers/sensor/maxim/ds18b20/Kconfig @@ -6,7 +6,7 @@ config DS18B20 bool "DS18B20 Temperature Sensor" default y - depends on DT_HAS_MAXIM_DS18B20_ENABLED + depends on DT_HAS_MAXIM_DS18B20_ENABLED || DT_HAS_MAXIM_DS18S20_ENABLED depends on W1_NET help Enable driver for DS18B20 1-Wire temperature sensors. diff --git a/drivers/sensor/maxim/ds18b20/ds18b20.c b/drivers/sensor/maxim/ds18b20/ds18b20.c index 15c7370b8e4..35e9a82df02 100644 --- a/drivers/sensor/maxim/ds18b20/ds18b20.c +++ b/drivers/sensor/maxim/ds18b20/ds18b20.c @@ -9,9 +9,11 @@ * A datasheet is available at: * https://datasheets.maximintegrated.com/en/ds/DS18B20.pdf * + * Driver also support the older DS18S20 1-Wire temperature sensors. + * https://www.analog.com/media/en/technical-documentation/data-sheets/ds18b20.pdf + * * Parasite power configuration is not supported by the driver. */ -#define DT_DRV_COMPAT maxim_ds18b20 #include #include @@ -25,15 +27,25 @@ LOG_MODULE_REGISTER(DS18B20, CONFIG_SENSOR_LOG_LEVEL); static int ds18b20_configure(const struct device *dev); /* measure wait time for 9-bit, 10-bit, 11-bit, 12-bit resolution respectively */ -static const uint16_t measure_wait_ms[4] = { 94, 188, 376, 750 }; +static const uint16_t measure_wait_ds18b20_ms[4] = { 94, 188, 376, 750 }; -static inline void ds18b20_temperature_from_raw(uint8_t *temp_raw, +/* ds18s20 always needs 750ms */ +static const uint16_t measure_wait_ds18s20_ms = { 750 }; + +static inline void ds18b20_temperature_from_raw(const struct device *dev, + uint8_t *temp_raw, struct sensor_value *val) { - int16_t temp = sys_get_le16(temp_raw); - - val->val1 = temp / 16; - val->val2 = (temp % 16) * 1000000 / 16; + const struct ds18b20_config *cfg = dev->config; + int16_t temp = sys_get_le16 (temp_raw); + + if (cfg->chip == type_ds18s20) { + val->val1 = temp / 2; + val->val2 = (temp % 2) * 5000000; + } else { + val->val1 = temp / 16; + val->val2 = (temp % 16) * 1000000 / 16; + } } /* @@ -95,10 +107,20 @@ static void ds18b20_set_resolution(const struct device *dev, uint8_t resolution) data->scratchpad.config |= DS18B20_RESOLUTION(resolution); } +static uint16_t measure_wait_ms(const struct device *dev) +{ + const struct ds18b20_config *cfg = dev->config; + + if (cfg->chip == type_ds18s20) { + return measure_wait_ds18s20_ms; + } + + return measure_wait_ds18b20_ms[DS18B20_RESOLUTION_INDEX(cfg->resolution)]; +} + static int ds18b20_sample_fetch(const struct device *dev, enum sensor_channel chan) { - const struct ds18b20_config *cfg = dev->config; struct ds18b20_data *data = dev->data; int status; @@ -118,7 +140,7 @@ static int ds18b20_sample_fetch(const struct device *dev, LOG_DBG("W1 fetch error"); return status; } - k_msleep(measure_wait_ms[DS18B20_RESOLUTION_INDEX(cfg->resolution)]); + k_msleep(measure_wait_ms(dev)); return ds18b20_read_scratchpad(dev, &data->scratchpad); } @@ -132,7 +154,7 @@ static int ds18b20_channel_get(const struct device *dev, return -ENOTSUP; } - ds18b20_temperature_from_raw((uint8_t *)&data->scratchpad.temp, val); + ds18b20_temperature_from_raw(dev, (uint8_t *)&data->scratchpad.temp, val); return 0; } @@ -159,17 +181,19 @@ static int ds18b20_configure(const struct device *dev) } if ((cfg->family != 0) && (cfg->family != data->config.rom.family)) { - LOG_ERR("Found 1-Wire slave is not a DS18B20"); + LOG_ERR("Found 1-Wire slave is not a %s", dev->name); return -EINVAL; } /* write default configuration */ - ds18b20_set_resolution(dev, cfg->resolution); - ret = ds18b20_write_scratchpad(dev, data->scratchpad); - if (ret < 0) { - return ret; + if (cfg->chip == type_ds18b20) { + ds18b20_set_resolution(dev, cfg->resolution); + ret = ds18b20_write_scratchpad(dev, data->scratchpad); + if (ret < 0) { + return ret; + } } - LOG_DBG("Init DS18B20: ROM=%016llx\n", + LOG_DBG("Init %s: ROM=%016llx\n", dev->name, w1_rom_to_uint64(&data->config.rom)); return 0; @@ -214,24 +238,35 @@ static int ds18b20_init(const struct device *dev) return 0; } -#define DS18B20_CONFIG_INIT(inst) \ - { \ +#define DS18B20_CONFIG_INIT(inst, default_family_code, chip_type) \ + { \ .bus = DEVICE_DT_GET(DT_INST_BUS(inst)), \ - .family = (uint8_t)DT_INST_PROP_OR(inst, family_code, 0x28), \ - .resolution = DT_INST_PROP(inst, resolution), \ + .family = (uint8_t)DT_INST_PROP_OR(inst, family_code, default_family_code), \ + .resolution = DT_INST_PROP_OR(inst, resolution, 12), \ + .chip = chip_type, \ } -#define DS18B20_DEFINE(inst) \ - static struct ds18b20_data ds18b20_data_##inst; \ - static const struct ds18b20_config ds18b20_config_##inst = \ - DS18B20_CONFIG_INIT(inst); \ +#define DS18B20_DEFINE(inst, name, family_code, chip_type) \ + static struct ds18b20_data data_##name##_##inst; \ + static const struct ds18b20_config config_##name##_##inst = \ + DS18B20_CONFIG_INIT(inst, family_code, chip_type); \ SENSOR_DEVICE_DT_INST_DEFINE(inst, \ ds18b20_init, \ NULL, \ - &ds18b20_data_##inst, \ - &ds18b20_config_##inst, \ + &data_##name##_##inst, \ + &config_##name##_##inst, \ POST_KERNEL, \ CONFIG_SENSOR_INIT_PRIORITY, \ &ds18b20_driver_api); -DT_INST_FOREACH_STATUS_OKAY(DS18B20_DEFINE) +#define DT_DRV_COMPAT maxim_ds18b20 +DT_INST_FOREACH_STATUS_OKAY_VARGS(DS18B20_DEFINE, DT_DRV_COMPAT, + DS18B20_FAMILYCODE, + type_ds18b20) +#undef DT_DRV_COMPAT + +#define DT_DRV_COMPAT maxim_ds18s20 +DT_INST_FOREACH_STATUS_OKAY_VARGS(DS18B20_DEFINE, DT_DRV_COMPAT, + DS18S20_FAMILYCODE, + type_ds18s20) +#undef DT_DRV_COMPAT diff --git a/drivers/sensor/maxim/ds18b20/ds18b20.h b/drivers/sensor/maxim/ds18b20/ds18b20.h index cf318cb9f9f..a85e91c58ae 100644 --- a/drivers/sensor/maxim/ds18b20/ds18b20.h +++ b/drivers/sensor/maxim/ds18b20/ds18b20.h @@ -31,6 +31,11 @@ /* convert resolution in bits to array index (for resolution specific elements) */ #define DS18B20_RESOLUTION_INDEX(res) (res - 9) +#define DS18B20_FAMILYCODE 0x28 +#define DS18S20_FAMILYCODE 0x10 + +enum chip_type {type_ds18b20, type_ds18s20}; + struct ds18b20_scratchpad { int16_t temp; uint8_t alarm_temp_high; @@ -44,6 +49,7 @@ struct ds18b20_config { const struct device *bus; uint8_t family; uint8_t resolution; + enum chip_type chip; }; struct ds18b20_data { diff --git a/drivers/sensor/nct75/CMakeLists.txt b/drivers/sensor/nct75/CMakeLists.txt new file mode 100644 index 00000000000..65fe03ae5f9 --- /dev/null +++ b/drivers/sensor/nct75/CMakeLists.txt @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_sources_ifdef(CONFIG_NCT75 nct75.c) diff --git a/drivers/sensor/nct75/Kconfig b/drivers/sensor/nct75/Kconfig new file mode 100644 index 00000000000..b53990f371c --- /dev/null +++ b/drivers/sensor/nct75/Kconfig @@ -0,0 +1,10 @@ +# Copyright (c) 2024 Benedikt Schmidt +# SPDX-License-Identifier: Apache-2.0 + +config NCT75 + bool "NCT75 temperature sensor" + default y + depends on DT_HAS_ONNN_NCT75_ENABLED + select I2C + help + Enable driver for the NCT75 temperature sensor. diff --git a/drivers/sensor/nct75/nct75.c b/drivers/sensor/nct75/nct75.c new file mode 100644 index 00000000000..2759c632d27 --- /dev/null +++ b/drivers/sensor/nct75/nct75.c @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2024 Benedikt Schmidt + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT onnn_nct75 + +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(NCT75, CONFIG_SENSOR_LOG_LEVEL); + +#define NCT75REGISTER_STOREDTEMPERATUREVALUE 0x00 +#define NCT75REGISTER_CONFIGURATION 0x01 +#define NCT75REGISTER_ONESHOT 0x04 + +#define NCT75_CONFIGURATION_ONESHOTMODE_POS 5 + +#define NCT75_TEMPERATURE_CONVERSION_TIME_US 48500 +#define NCT75_TEMPERATURE_CONVERSION_WAIT_TIME_US (NCT75_TEMPERATURE_CONVERSION_TIME_US + 1000) + +struct nct75_config { + struct i2c_dt_spec i2c; +}; + +struct nct75_data { + /* temperature in 1e-6 Ā°C */ + int64_t value; +}; + +static int nct75_sample_fetch(const struct device *dev, enum sensor_channel chan) +{ + const struct nct75_config *config = dev->config; + struct nct75_data *data = dev->data; + int result; + uint8_t write_buffer = 0; + uint16_t read_buffer; + int16_t raw_value; + + __ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL); + + result = i2c_reg_write_byte_dt(&config->i2c, NCT75REGISTER_ONESHOT, 0); + if (result != 0) { + LOG_ERR("%s: unable to trigger temperature one shot measurement", dev->name); + return result; + } + + k_sleep(K_USEC(NCT75_TEMPERATURE_CONVERSION_WAIT_TIME_US)); + + write_buffer = NCT75REGISTER_STOREDTEMPERATUREVALUE; + result = i2c_write_read_dt(&config->i2c, &write_buffer, sizeof(write_buffer), &read_buffer, + sizeof(read_buffer)); + if (result != 0) { + LOG_ERR("%s: unable to read temperature", dev->name); + return result; + } + + raw_value = arithmetic_shift_right(sys_be16_to_cpu(read_buffer), 4); + data->value = (raw_value * 1000 * 1000) * 100 / 0x640; + + return 0; +} + +static int nct75_channel_get(const struct device *dev, enum sensor_channel chan, + struct sensor_value *val) +{ + struct nct75_data *data = dev->data; + + if (chan != SENSOR_CHAN_AMBIENT_TEMP) { + LOG_ERR("%s: requesting unsupported channel %i", dev->name, chan); + return -ENOTSUP; + } + + val->val1 = data->value / (1000 * 1000); + val->val2 = data->value - val->val1 * 1000 * 1000; + return 0; +} + +static const struct sensor_driver_api nct75_api = { + .sample_fetch = nct75_sample_fetch, + .channel_get = nct75_channel_get, +}; + +static int nct75_init(const struct device *dev) +{ + const struct nct75_config *config = dev->config; + uint8_t configuration_register_value = BIT(NCT75_CONFIGURATION_ONESHOTMODE_POS); + int result; + + if (!i2c_is_ready_dt(&config->i2c)) { + LOG_ERR("I2C device not ready"); + return -ENODEV; + } + + result = i2c_reg_write_byte_dt(&config->i2c, NCT75REGISTER_CONFIGURATION, + configuration_register_value); + if (result != 0) { + LOG_ERR("%s: unable to configure temperature sensor", dev->name); + return result; + } + + return 0; +} + +#define NCT75_INIT(inst) \ + static const struct nct75_config nct75_##inst##_config = { \ + .i2c = I2C_DT_SPEC_INST_GET(inst), \ + }; \ + \ + static struct nct75_data nct75_##inst##_data; \ + \ + SENSOR_DEVICE_DT_INST_DEFINE(inst, nct75_init, NULL, &nct75_##inst##_data, \ + &nct75_##inst##_config, POST_KERNEL, \ + CONFIG_SENSOR_INIT_PRIORITY, &nct75_api); + +DT_INST_FOREACH_STATUS_OKAY(NCT75_INIT); diff --git a/drivers/sensor/nordic/CMakeLists.txt b/drivers/sensor/nordic/CMakeLists.txt index 0169664e6aa..89265c0e59d 100644 --- a/drivers/sensor/nordic/CMakeLists.txt +++ b/drivers/sensor/nordic/CMakeLists.txt @@ -2,7 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 # zephyr-keep-sorted-start +add_subdirectory(temp) add_subdirectory_ifdef(CONFIG_NPM1300_CHARGER npm1300_charger) add_subdirectory_ifdef(CONFIG_QDEC_NRFX qdec_nrfx) -add_subdirectory_ifdef(CONFIG_TEMP_NRF5 nrf5) # zephyr-keep-sorted-stop diff --git a/drivers/sensor/nordic/Kconfig b/drivers/sensor/nordic/Kconfig index 42678ed2fcc..27f1cfedf59 100644 --- a/drivers/sensor/nordic/Kconfig +++ b/drivers/sensor/nordic/Kconfig @@ -3,6 +3,6 @@ # zephyr-keep-sorted-start source "drivers/sensor/nordic/npm1300_charger/Kconfig" -source "drivers/sensor/nordic/nrf5/Kconfig" source "drivers/sensor/nordic/qdec_nrfx/Kconfig" +source "drivers/sensor/nordic/temp/Kconfig" # zephyr-keep-sorted-stop diff --git a/drivers/sensor/nordic/nrf5/CMakeLists.txt b/drivers/sensor/nordic/nrf5/CMakeLists.txt deleted file mode 100644 index d57e18cdf1b..00000000000 --- a/drivers/sensor/nordic/nrf5/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -if(CONFIG_TEMP_NRF5 AND NOT CONFIG_TEMP_NRF5_FORCE_ALT) - zephyr_library() - zephyr_library_sources(temp_nrf5.c) -endif() diff --git a/drivers/sensor/nordic/nrf5/Kconfig b/drivers/sensor/nordic/nrf5/Kconfig deleted file mode 100644 index aa0e3d6fc0f..00000000000 --- a/drivers/sensor/nordic/nrf5/Kconfig +++ /dev/null @@ -1,20 +0,0 @@ -# nRF5 temperature sensor configuration options - -# Copyright (c) 2016 ARM Ltd. -# SPDX-License-Identifier: Apache-2.0 - -config TEMP_NRF5_FORCE_ALT - bool - depends on SOC_COMPATIBLE_NRF - help - This option can be enabled to force an alternative implementation - of the temperature sensor driver. - -config TEMP_NRF5 - bool "nRF5 Temperature Sensor" - default y - depends on DT_HAS_NORDIC_NRF_TEMP_ENABLED - depends on HAS_HW_NRF_TEMP - depends on MULTITHREADING || TEMP_NRF5_FORCE_ALT - help - Enable driver for nRF5 temperature sensor. diff --git a/drivers/sensor/nordic/temp/CMakeLists.txt b/drivers/sensor/nordic/temp/CMakeLists.txt new file mode 100644 index 00000000000..e3f81b50ac4 --- /dev/null +++ b/drivers/sensor/nordic/temp/CMakeLists.txt @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: Apache-2.0 + +if(CONFIG_TEMP_NRF5 AND NOT CONFIG_TEMP_NRF5_FORCE_ALT) + zephyr_library() + zephyr_library_sources(temp_nrf5.c) +elseif(CONFIG_TEMP_NRFS) + zephyr_library() + zephyr_library_sources(temp_nrfs.c) +endif() diff --git a/drivers/sensor/nordic/temp/Kconfig b/drivers/sensor/nordic/temp/Kconfig new file mode 100644 index 00000000000..e32fb1b8fdd --- /dev/null +++ b/drivers/sensor/nordic/temp/Kconfig @@ -0,0 +1,38 @@ +# nRF temperature sensor configuration options + +# Copyright (c) 2016 ARM Ltd. +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config TEMP_NRF5_FORCE_ALT + bool + depends on SOC_COMPATIBLE_NRF + help + This option can be enabled to force an alternative implementation + of the temperature sensor driver. + +config TEMP_NRF5 + bool "nRF5 Temperature Sensor" + default y + depends on DT_HAS_NORDIC_NRF_TEMP_ENABLED + depends on MULTITHREADING || TEMP_NRF5_FORCE_ALT + help + Enable driver for nRF5 temperature sensor. + +config TEMP_NRFS + bool "nRF Temperature Sensor accessed via nrfs" + default y + depends on DT_HAS_NORDIC_NRF_TEMP_NRFS_ENABLED + depends on NRFS + help + Enable driver for nRF temperature sensor accessed through the nRF + Services (nrfs) layer. + +if TEMP_NRFS + +module = TEMP_NRFS +thread_priority = 10 +thread_stack_size = 1024 +source "drivers/sensor/Kconfig.trigger_template" + +endif # TEMP_NRFS diff --git a/drivers/sensor/nordic/nrf5/temp_nrf5.c b/drivers/sensor/nordic/temp/temp_nrf5.c similarity index 100% rename from drivers/sensor/nordic/nrf5/temp_nrf5.c rename to drivers/sensor/nordic/temp/temp_nrf5.c diff --git a/drivers/sensor/nordic/temp/temp_nrfs.c b/drivers/sensor/nordic/temp/temp_nrfs.c new file mode 100644 index 00000000000..015e05918f0 --- /dev/null +++ b/drivers/sensor/nordic/temp/temp_nrfs.c @@ -0,0 +1,312 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nordic_nrf_temp_nrfs + +#include +#include +#include +#include + +#include + +LOG_MODULE_REGISTER(temp_nrfs, CONFIG_SENSOR_LOG_LEVEL); + +struct temp_nrfs_data { + struct k_sem measure_sem; + struct k_mutex mutex; + int32_t raw_temp; + +#ifdef CONFIG_TEMP_NRFS_TRIGGER + struct sensor_trigger trigger; + sensor_trigger_handler_t handler; + const struct device *dev; + struct sensor_value sampling_freq; + struct sensor_value up_threshold; + struct sensor_value low_threshold; +#endif +#if defined(CONFIG_TEMP_NRFS_TRIGGER_OWN_THREAD) + K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_TEMP_NRFS_THREAD_STACK_SIZE); + struct k_thread thread; + struct k_sem event_sem; +#elif defined(CONFIG_TEMP_NRFS_TRIGGER_GLOBAL_THREAD) + struct k_work work; +#endif +}; + +#ifdef CONFIG_TEMP_NRFS_TRIGGER + +#define DEFAULT_SAMPLING_FREQ { 1, 0 } +#define DEFAULT_UP_THRESHOLD { 25, 0 } +#define DEFAULT_LOW_THRESHOLD { 0, 0 } + +static void temp_nrfs_handle_event(const struct device *dev) +{ + struct temp_nrfs_data *data = dev->data; + struct sensor_trigger trigger; + sensor_trigger_handler_t handler; + + k_mutex_lock(&data->mutex, K_FOREVER); + trigger = data->trigger; + handler = data->handler; + k_mutex_unlock(&data->mutex); + + if (handler) { + handler(dev, &trigger); + } +} + +#if defined(CONFIG_TEMP_NRFS_TRIGGER_OWN_THREAD) +static void temp_nrfs_thread(void *p1, void *p2, void *p3) +{ + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct temp_nrfs_data *data = p1; + + while (1) { + k_sem_take(&data->event_sem, K_FOREVER); + temp_nrfs_handle_event(data->dev); + } +} +#elif defined(CONFIG_TEMP_NRFS_TRIGGER_GLOBAL_THREAD) +static void temp_nrfs_work_handler(struct k_work *work) +{ + struct temp_nrfs_data *data = + CONTAINER_OF(work, struct temp_nrfs_data, work); + + temp_nrfs_handle_event(data->dev); +} +#endif + +static uint16_t to_measure_rate_ms(const struct sensor_value *freq_val) +{ + uint32_t measure_rate_ms = (MSEC_PER_SEC * 1000) / + (uint32_t)sensor_value_to_milli(freq_val); + + return (uint16_t)MIN(measure_rate_ms, UINT16_MAX); +} + +static int32_t to_raw_temp(const struct sensor_value *temp_val) +{ + int32_t temp_mul_100 = (int32_t)(sensor_value_to_milli(temp_val) / 10); + + return nrfs_temp_to_raw(temp_mul_100); +} + +static int api_sensor_trigger_set(const struct device *dev, + const struct sensor_trigger *trig, + sensor_trigger_handler_t handler) +{ + struct temp_nrfs_data *data = dev->data; + nrfs_err_t err; + + if (trig->chan != SENSOR_CHAN_ALL && + trig->chan != SENSOR_CHAN_DIE_TEMP) { + return -ENOTSUP; + } + + switch (trig->type) { + case SENSOR_TRIG_THRESHOLD: + k_mutex_lock(&data->mutex, K_FOREVER); + data->trigger = *trig; + data->handler = handler; + k_mutex_unlock(&data->mutex); + + if (handler) { + err = nrfs_temp_subscribe( + to_measure_rate_ms(&data->sampling_freq), + to_raw_temp(&data->low_threshold), + to_raw_temp(&data->up_threshold), + data); + } else { + err = nrfs_temp_unsubscribe(); + } + + switch (err) { + case NRFS_SUCCESS: + break; + case NRFS_ERR_INVALID_STATE: + return -EAGAIN; + default: + return -EIO; + } + break; + + default: + return -ENOTSUP; + } + + return 0; +} + +static int api_sensor_attr_set(const struct device *dev, + enum sensor_channel chan, + enum sensor_attribute attr, + const struct sensor_value *val) +{ + struct temp_nrfs_data *data = dev->data; + + if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_DIE_TEMP) { + return -ENOTSUP; + } + + switch (attr) { + case SENSOR_ATTR_SAMPLING_FREQUENCY: + if (sensor_value_to_milli(val) <= 0) { + return -EINVAL; + } + data->sampling_freq = *val; + break; + case SENSOR_ATTR_UPPER_THRESH: + data->up_threshold = *val; + break; + case SENSOR_ATTR_LOWER_THRESH: + data->low_threshold = *val; + break; + default: + return -ENOTSUP; + } + return 0; +} + +#endif /* CONFIG_TEMP_NRFS_TRIGGER */ + +static void sensor_handler(nrfs_temp_evt_t const *p_evt, void *context) +{ + ARG_UNUSED(context); + + struct temp_nrfs_data *data = context; + + switch (p_evt->type) { + case NRFS_TEMP_EVT_MEASURE_DONE: + data->raw_temp = p_evt->raw_temp; + k_sem_give(&data->measure_sem); + break; + +#ifdef CONFIG_TEMP_NRFS_TRIGGER + case NRFS_TEMP_EVT_CHANGE: + data->raw_temp = p_evt->raw_temp; +#if defined(CONFIG_TEMP_NRFS_TRIGGER_OWN_THREAD) + k_sem_give(&data->event_sem); +#elif defined(CONFIG_TEMP_NRFS_TRIGGER_GLOBAL_THREAD) + k_work_submit(&data->work); +#endif + break; +#endif /* CONFIG_TEMP_NRFS_TRIGGER */ + + default: + LOG_DBG("Temperature handler - unsupported event: 0x%x", + p_evt->type); + break; + } +} + +static int api_sample_fetch(const struct device *dev, + enum sensor_channel chan) +{ + struct temp_nrfs_data *data = dev->data; + int nrfs_rc; + int rc = 0; + + if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_DIE_TEMP) { + return -ENOTSUP; + } + + k_mutex_lock(&data->mutex, K_FOREVER); + nrfs_rc = nrfs_temp_measure_request(data); + switch (nrfs_rc) { + case NRFS_SUCCESS: + k_sem_take(&data->measure_sem, K_FOREVER); + LOG_DBG("Temperature sample: %d", data->raw_temp); + break; + case NRFS_ERR_INVALID_STATE: + LOG_DBG("Backend is not ready, try again."); + rc = -EAGAIN; + break; + default: + LOG_DBG("Measure request failed: %d", nrfs_rc); + rc = -EIO; + break; + } + k_mutex_unlock(&data->mutex); + + return rc; +} + +static int api_channel_get(const struct device *dev, + enum sensor_channel chan, + struct sensor_value *val) +{ + struct temp_nrfs_data *data = dev->data; + + if (chan != SENSOR_CHAN_DIE_TEMP) { + return -ENOTSUP; + } + + int32_t uval = nrfs_temp_from_raw(data->raw_temp); + + val->val1 = uval / 100; + val->val2 = (abs(uval) % 100) * 10000; + + LOG_DBG("Temperature: %d.%02u[C]", uval / 100, abs(uval) % 100); + + return 0; +} + +static int temp_nrfs_init(const struct device *dev) +{ + int rc; + + rc = nrfs_temp_init(sensor_handler); + if (rc < 0) { + return rc; + } + +#if defined(CONFIG_TEMP_NRFS_TRIGGER_OWN_THREAD) + struct temp_nrfs_data *data = dev->data; + + k_thread_create(&data->thread, data->thread_stack, + CONFIG_TEMP_NRFS_THREAD_STACK_SIZE, + temp_nrfs_thread, + data, NULL, NULL, + K_PRIO_COOP(CONFIG_TEMP_NRFS_THREAD_PRIORITY), + 0, K_NO_WAIT); + k_thread_name_set(&data->thread, dev->name); +#endif + + return 0; +} + +static const struct sensor_driver_api temp_nrfs_drv_api = { +#ifdef CONFIG_TEMP_NRFS_TRIGGER + .attr_set = api_sensor_attr_set, + .trigger_set = api_sensor_trigger_set, +#endif + .sample_fetch = api_sample_fetch, + .channel_get = api_channel_get +}; + +static struct temp_nrfs_data temp_nrfs_drv_data = { + .mutex = Z_MUTEX_INITIALIZER(temp_nrfs_drv_data.mutex), + .measure_sem = Z_SEM_INITIALIZER(temp_nrfs_drv_data.measure_sem, 0, 1), +#ifdef CONFIG_TEMP_NRFS_TRIGGER + .dev = DEVICE_DT_INST_GET(0), + .sampling_freq = DEFAULT_SAMPLING_FREQ, + .up_threshold = DEFAULT_UP_THRESHOLD, + .low_threshold = DEFAULT_LOW_THRESHOLD, +#endif +#if defined(CONFIG_TEMP_NRFS_TRIGGER_OWN_THREAD) + .event_sem = Z_SEM_INITIALIZER(temp_nrfs_drv_data.event_sem, 0, 1), +#elif defined(CONFIG_TEMP_NRFS_TRIGGER_GLOBAL_THREAD) + .work = Z_WORK_INITIALIZER(temp_nrfs_work_handler), +#endif +}; + +DEVICE_DT_INST_DEFINE(0, temp_nrfs_init, NULL, + &temp_nrfs_drv_data, NULL, + POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, + &temp_nrfs_drv_api); diff --git a/drivers/sensor/ntc_thermistor/Kconfig b/drivers/sensor/ntc_thermistor/Kconfig index 140d324e9aa..1d0af864a88 100644 --- a/drivers/sensor/ntc_thermistor/Kconfig +++ b/drivers/sensor/ntc_thermistor/Kconfig @@ -8,7 +8,8 @@ config NTC_THERMISTOR depends on DT_HAS_NTC_THERMISTOR_GENERIC_ENABLED || \ DT_HAS_EPCOS_B57861S0103A039_ENABLED || \ DT_HAS_MURATA_NCP15WB473_ENABLED || \ - DT_HAS_TDK_NTCG163JF103FT1_ENABLED + DT_HAS_TDK_NTCG163JF103FT1_ENABLED || \ + DT_HAS_MURATA_NCP15XH103_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 185e8c27673..18ed9cd3e04 100644 --- a/drivers/sensor/ntc_thermistor/ntc_thermistor.c +++ b/drivers/sensor/ntc_thermistor/ntc_thermistor.c @@ -243,3 +243,29 @@ static __unused const struct ntc_compensation comp_tdk_ntcg163jf103ft1[] = { DT_INST_FOREACH_STATUS_OKAY_VARGS(NTC_THERMISTOR_DEFINE, DT_DRV_COMPAT, comp_tdk_ntcg163jf103ft1) + +/* murata,ncp15xh103 */ +#undef DT_DRV_COMPAT +#define DT_DRV_COMPAT murata_ncp15xh103 + +static __unused const struct ntc_compensation comp_murata_ncp15xh103[] = { + { -25, 87558 }, + { -15, 53649 }, + { -5, 33892 }, + { 5, 22021 }, + { 15, 14673 }, + { 25, 10000 }, + { 35, 6947 }, + { 45, 4916 }, + { 55, 3535 }, + { 64, 2586 }, + { 75, 1924 }, + { 85, 1452 }, + { 95, 1109 }, + { 105, 858 }, + { 115, 671 }, + { 125, 531 }, +}; + +DT_INST_FOREACH_STATUS_OKAY_VARGS(NTC_THERMISTOR_DEFINE, DT_DRV_COMPAT, + comp_murata_ncp15xh103) diff --git a/drivers/sensor/nxp/nxp_kinetis_temp/Kconfig b/drivers/sensor/nxp/nxp_kinetis_temp/Kconfig index 63c91cde176..10436fda53a 100644 --- a/drivers/sensor/nxp/nxp_kinetis_temp/Kconfig +++ b/drivers/sensor/nxp/nxp_kinetis_temp/Kconfig @@ -7,7 +7,8 @@ config TEMP_KINETIS bool "NXP Kinetis Temperature Sensor" default y depends on DT_HAS_NXP_KINETIS_TEMPERATURE_ENABLED - depends on (ADC && SOC_FAMILY_KINETIS) + depends on SOC_FAMILY_KINETIS + select ADC help Enable driver for NXP Kinetis temperature sensor. diff --git a/drivers/sensor/nxp/nxp_kinetis_temp/temp_kinetis.c b/drivers/sensor/nxp/nxp_kinetis_temp/temp_kinetis.c index b72b5eece6c..7f5beda55eb 100644 --- a/drivers/sensor/nxp/nxp_kinetis_temp/temp_kinetis.c +++ b/drivers/sensor/nxp/nxp_kinetis_temp/temp_kinetis.c @@ -159,7 +159,7 @@ static int temp_kinetis_init(const struct device *dev) }, }; - memset(&data->buffer, 0, ARRAY_SIZE(data->buffer)); + memset(&data->buffer, 0, sizeof(data->buffer)); if (!device_is_ready(config->adc)) { LOG_ERR("ADC device is not ready"); diff --git a/drivers/sensor/rpi_pico_temp/Kconfig b/drivers/sensor/rpi_pico_temp/Kconfig index 9b618984d88..33a9b7f9b27 100644 --- a/drivers/sensor/rpi_pico_temp/Kconfig +++ b/drivers/sensor/rpi_pico_temp/Kconfig @@ -7,7 +7,7 @@ config RPI_PICO_TEMP bool "Raspberry Pi Pico CPU Temperature Sensor" default y depends on DT_HAS_RASPBERRYPI_PICO_TEMP_ENABLED - depends on ADC + select ADC help Enable driver for Raspberry Pi Pico CPU temperature sensor. diff --git a/drivers/sensor/seeed/grove/Kconfig b/drivers/sensor/seeed/grove/Kconfig index f3804f3323f..9563bdd7b3a 100644 --- a/drivers/sensor/seeed/grove/Kconfig +++ b/drivers/sensor/seeed/grove/Kconfig @@ -16,7 +16,8 @@ config GROVE_LIGHT_SENSOR bool "The Seeed Grove Light Sensor" default y depends on DT_HAS_SEEED_GROVE_LIGHT_ENABLED - depends on ADC && !MINIMAL_LIBC + depends on !MINIMAL_LIBC + select ADC help Setting this value will enable driver support for the Grove Light Sensor. @@ -25,7 +26,8 @@ config GROVE_TEMPERATURE_SENSOR bool "The Seeed Grove Temperature Sensor" default y depends on DT_HAS_SEEED_GROVE_TEMPERATURE_ENABLED - depends on ADC && !MINIMAL_LIBC + depends on !MINIMAL_LIBC + select ADC help Setting this value will enable driver support for the Grove Temperature Sensor. diff --git a/drivers/sensor/sensor_shell.c b/drivers/sensor/sensor_shell.c index 758e658816a..972f62c7fe3 100644 --- a/drivers/sensor/sensor_shell.c +++ b/drivers/sensor/sensor_shell.c @@ -217,7 +217,7 @@ static enum dynamic_command_context current_cmd_ctx = NONE; K_MUTEX_DEFINE(cmd_get_mutex); /* Crate a single common config for one-shot reading */ -static enum sensor_channel iodev_sensor_shell_channels[SENSOR_CHAN_ALL]; +static struct sensor_chan_spec iodev_sensor_shell_channels[SENSOR_CHAN_ALL]; static struct sensor_read_config iodev_sensor_shell_read_config = { .sensor = NULL, .is_streaming = false, @@ -330,23 +330,31 @@ void sensor_shell_processing_callback(int result, uint8_t *buf, uint32_t buf_len : sensor_trigger_table[trigger].name)); } - for (int channel = 0; channel < SENSOR_CHAN_ALL; ++channel) { + + + for (struct sensor_chan_spec ch = {0, 0}; ch.chan_type < SENSOR_CHAN_ALL; ch.chan_type++) { uint32_t fit = 0; size_t base_size; size_t frame_size; - size_t channel_idx = 0; uint16_t frame_count; - if (channel == SENSOR_CHAN_ACCEL_X || channel == SENSOR_CHAN_ACCEL_Y || - channel == SENSOR_CHAN_ACCEL_Z || channel == SENSOR_CHAN_GYRO_X || - channel == SENSOR_CHAN_GYRO_Y || channel == SENSOR_CHAN_GYRO_Z || - channel == SENSOR_CHAN_MAGN_X || channel == SENSOR_CHAN_MAGN_Y || - channel == SENSOR_CHAN_MAGN_Z || channel == SENSOR_CHAN_POS_DY || - channel == SENSOR_CHAN_POS_DZ) { + /* Channels with multi-axis equivalents are skipped */ + switch (ch.chan_type) { + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + case SENSOR_CHAN_GYRO_X: + case SENSOR_CHAN_GYRO_Y: + case SENSOR_CHAN_GYRO_Z: + case SENSOR_CHAN_MAGN_X: + case SENSOR_CHAN_MAGN_Y: + case SENSOR_CHAN_MAGN_Z: + case SENSOR_CHAN_POS_DY: + case SENSOR_CHAN_POS_DZ: continue; } - rc = decoder->get_size_info(channel, &base_size, &frame_size); + rc = decoder->get_size_info(ch, &base_size, &frame_size); if (rc != 0) { /* Channel not supported, skipping */ continue; @@ -354,19 +362,18 @@ void sensor_shell_processing_callback(int result, uint8_t *buf, uint32_t buf_len if (base_size > ARRAY_SIZE(decoded_buffer)) { shell_error(ctx->sh, - "Channel (%d) requires %zu bytes to decode, but only %zu are " - "available", - channel, base_size, ARRAY_SIZE(decoded_buffer)); + "Channel (type %d, idx %d) requires %zu bytes to decode, but " + "only %zu are available", + ch.chan_type, ch.chan_idx, base_size, + ARRAY_SIZE(decoded_buffer)); continue; } - while (decoder->get_frame_count(buf, channel, channel_idx, &frame_count) == 0) { + while (decoder->get_frame_count(buf, ch, &frame_count) == 0) { fit = 0; memset(&accumulator_buffer, 0, sizeof(accumulator_buffer)); - while (decoder->decode(buf, channel, channel_idx, &fit, 1, decoded_buffer) > - 0) { - - switch (channel) { + while (decoder->decode(buf, ch, &fit, 1, decoded_buffer) > 0) { + switch (ch.chan_type) { case SENSOR_CHAN_ACCEL_XYZ: case SENSOR_CHAN_GYRO_XYZ: case SENSOR_CHAN_MAGN_XYZ: @@ -420,7 +427,7 @@ void sensor_shell_processing_callback(int result, uint8_t *buf, uint32_t buf_len } /* Print the accumulated value average */ - switch (channel) { + switch (ch.chan_type) { case SENSOR_CHAN_ACCEL_XYZ: case SENSOR_CHAN_GYRO_XYZ: case SENSOR_CHAN_MAGN_XYZ: @@ -442,10 +449,10 @@ void sensor_shell_processing_callback(int result, uint8_t *buf, uint32_t buf_len 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 " + "channel type=%d(%s) index=%d shift=%d num_samples=%d " "value=%" PRIsensor_three_axis_data, - channel, sensor_channel_name[channel], - data->shift, accumulator_buffer.count, + ch.chan_type, sensor_channel_name[ch.chan_type], + ch.chan_idx, data->shift, accumulator_buffer.count, PRIsensor_three_axis_data_arg(*data, 0)); break; } @@ -463,10 +470,10 @@ void sensor_shell_processing_callback(int result, uint8_t *buf, uint32_t buf_len accumulator_buffer.values[0] / accumulator_buffer.count; shell_info(ctx->sh, - "channel idx=%d %s num_samples=%d " + "channel type=%d(%s) index=%d num_samples=%d " "value=%" PRIsensor_byte_data(is_near), - channel, sensor_channel_name[channel], - accumulator_buffer.count, + ch.chan_type, sensor_channel_name[ch.chan_type], + ch.chan_idx, accumulator_buffer.count, PRIsensor_byte_data_arg(*data, 0, is_near)); break; } @@ -485,17 +492,18 @@ void sensor_shell_processing_callback(int result, uint8_t *buf, uint32_t buf_len accumulator_buffer.count); shell_info(ctx->sh, - "channel idx=%d %s shift=%d num_samples=%d " + "channel type=%d(%s) index=%d shift=%d num_samples=%d " "value=%" PRIsensor_q31_data, - channel, - (channel >= ARRAY_SIZE(sensor_channel_name)) + ch.chan_type, + (ch.chan_type >= ARRAY_SIZE(sensor_channel_name)) ? "" - : sensor_channel_name[channel], + : sensor_channel_name[ch.chan_type], + ch.chan_idx, data->shift, accumulator_buffer.count, PRIsensor_q31_data_arg(*data, 0)); } } - ++channel_idx; + ++ch.chan_idx; } } } @@ -521,12 +529,12 @@ static int cmd_get_sensor(const struct shell *sh, size_t argc, char *argv[]) } if (argc == 2) { - /* read all channels */ + /* read all channel types */ for (int i = 0; i < ARRAY_SIZE(iodev_sensor_shell_channels); ++i) { if (SENSOR_CHANNEL_3_AXIS(i)) { continue; } - iodev_sensor_shell_channels[count++] = i; + iodev_sensor_shell_channels[count++] = (struct sensor_chan_spec){i, 0}; } } else { /* read specific channels */ @@ -538,7 +546,8 @@ static int cmd_get_sensor(const struct shell *sh, size_t argc, char *argv[]) shell_error(sh, "Failed to read channel (%s)", argv[i]); continue; } - iodev_sensor_shell_channels[count++] = chan; + iodev_sensor_shell_channels[count++] = + (struct sensor_chan_spec){chan, 0}; } } @@ -570,7 +579,6 @@ static int cmd_get_sensor(const struct shell *sh, size_t argc, char *argv[]) return 0; } - static int cmd_sensor_attr_set(const struct shell *shell_ptr, size_t argc, char *argv[]) { const struct device *dev; @@ -990,6 +998,7 @@ static int cmd_trig_sensor(const struct shell *sh, size_t argc, char **argv) { const struct device *dev; int trigger; + bool trigger_enabled = false; int err; if (argc < 4) { @@ -1030,6 +1039,7 @@ static int cmd_trig_sensor(const struct shell *sh, size_t argc, char **argv) } err = sensor_trigger_set(dev, &sensor_trigger_table[trigger].trigger, sensor_trigger_table[trigger].handler); + trigger_enabled = true; } } else if (strcmp(argv[2], "off") == 0) { /* Clear the handler for the given trigger on this device */ @@ -1052,6 +1062,10 @@ static int cmd_trig_sensor(const struct shell *sh, size_t argc, char **argv) if (err) { shell_error(sh, "Error while setting trigger %d on device %s (%d)", trigger, argv[1], err); + } else { + shell_info(sh, "%s trigger idx=%d %s on device %s", + trigger_enabled ? "Enabled" : "Disabled", trigger, + sensor_trigger_table[trigger].name, argv[1]); } return err; diff --git a/drivers/sensor/st/lis2dh/lis2dh.c b/drivers/sensor/st/lis2dh/lis2dh.c index a12bb0e097d..9eca45335ad 100644 --- a/drivers/sensor/st/lis2dh/lis2dh.c +++ b/drivers/sensor/st/lis2dh/lis2dh.c @@ -437,9 +437,17 @@ static int lis2dh_pm_action(const struct device *dev, { int status; struct lis2dh_data *lis2dh = dev->data; + uint8_t regdata; switch (action) { case PM_DEVICE_ACTION_RESUME: + /* read REFERENCE register (see datasheet rev 6 section 8.9 footnote 1) */ + status = lis2dh->hw_tf->read_reg(dev, LIS2DH_REG_REFERENCE, ®data); + if (status < 0) { + LOG_ERR("failed to read reg_reference"); + return status; + } + /* Resume previous mode. */ status = lis2dh->hw_tf->write_reg(dev, LIS2DH_REG_CTRL1, lis2dh->reg_ctrl1_active_val); @@ -492,7 +500,7 @@ static int lis2dh_pm_action(const struct device *dev, &lis2dh_driver_api); #define IS_LSM303AGR_DEV(inst) \ - DT_NODE_HAS_COMPAT(DT_DRV_INST(inst), st_lsm303agr_accel) + DT_INST_NODE_HAS_COMPAT(inst, st_lsm303agr_accel) #define DISC_PULL_UP(inst) \ DT_INST_PROP(inst, disconnect_sdo_sa0_pull_up) @@ -537,8 +545,8 @@ static int lis2dh_pm_action(const struct device *dev, * compat(lis2dh) cannot be used here because it is the base part. */ #define FRACTIONAL_BITS(inst) \ - (DT_NODE_HAS_COMPAT(DT_DRV_INST(inst), st_lis2dh12) || \ - DT_NODE_HAS_COMPAT(DT_DRV_INST(inst), st_lis3dh)) ? \ + (DT_INST_NODE_HAS_COMPAT(inst, st_lis2dh12) || \ + DT_INST_NODE_HAS_COMPAT(inst, st_lis3dh)) ? \ (IS_ENABLED(CONFIG_LIS2DH_OPER_MODE_LOW_POWER) ? 0 : 2) : \ 0 diff --git a/drivers/sensor/st/lis2dh/lis2dh_trigger.c b/drivers/sensor/st/lis2dh/lis2dh_trigger.c index 3c075b2a0e8..16b0ea52fb8 100644 --- a/drivers/sensor/st/lis2dh/lis2dh_trigger.c +++ b/drivers/sensor/st/lis2dh/lis2dh_trigger.c @@ -19,7 +19,7 @@ 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_BOTH, GPIO_INT_EDGE_RISING, GPIO_INT_EDGE_FALLING, GPIO_INT_LEVEL_HIGH, @@ -467,17 +467,15 @@ static void lis2dh_thread_cb(const struct device *dev) TRIGGED_INT2)) { uint8_t reg_val = 0; - if (cfg->hw.anym_latch) { - /* clear interrupt to de-assert int line */ - status = lis2dh->hw_tf->read_reg(dev, - cfg->hw.anym_on_int1 ? - LIS2DH_REG_INT1_SRC : - LIS2DH_REG_INT2_SRC, - ®_val); - if (status < 0) { - LOG_ERR("clearing interrupt 2 failed: %d", status); - return; - } + /* if necessary also clears an interrupt to de-assert int line */ + status = lis2dh->hw_tf->read_reg(dev, + cfg->hw.anym_on_int1 ? + LIS2DH_REG_INT1_SRC : + LIS2DH_REG_INT2_SRC, + ®_val); + if (status < 0) { + LOG_ERR("clearing interrupt 2 failed: %d", status); + return; } if (likely(lis2dh->handler_anymotion != NULL) && diff --git a/drivers/sensor/st/lps25hb/lps25hb.c b/drivers/sensor/st/lps25hb/lps25hb.c index 0ce9b8862a3..38291b11471 100644 --- a/drivers/sensor/st/lps25hb/lps25hb.c +++ b/drivers/sensor/st/lps25hb/lps25hb.c @@ -69,9 +69,14 @@ static int lps25hb_sample_fetch(const struct device *dev, static inline void lps25hb_press_convert(struct sensor_value *val, int32_t raw_val) { - /* val = raw_val / 40960 */ + /* Pressure sensitivity is 4096 LSB/hPa */ + /* Also convert hPa into kPa */ val->val1 = raw_val / 40960; - val->val2 = ((int32_t)raw_val * 1000000 / 40960) % 1000000; + + /* For the decimal part use (3125 / 128) as a factor instead of + * (1000000 / 40960) to avoid int32 overflow + */ + val->val2 = (raw_val % 40960) * 3125 / 128; } static inline void lps25hb_temp_convert(struct sensor_value *val, diff --git a/drivers/sensor/st/lps2xdf/lps2xdf.c b/drivers/sensor/st/lps2xdf/lps2xdf.c index 33d909dfbf6..2196c265ffc 100644 --- a/drivers/sensor/st/lps2xdf/lps2xdf.c +++ b/drivers/sensor/st/lps2xdf/lps2xdf.c @@ -159,7 +159,7 @@ static const struct sensor_driver_api lps2xdf_driver_api = { .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), \ + IF_ENABLED(DT_INST_NODE_HAS_COMPAT(inst, st_lps28dfw), \ (.fs = DT_INST_PROP(inst, fs),)) \ IF_ENABLED(DT_INST_NODE_HAS_PROP(inst, drdy_gpios), \ (LPS2XDF_CFG_IRQ(inst))) diff --git a/drivers/sensor/st/lsm6dsl/lsm6dsl.c b/drivers/sensor/st/lsm6dsl/lsm6dsl.c index 0a0f3525804..a29b18e8fea 100644 --- a/drivers/sensor/st/lsm6dsl/lsm6dsl.c +++ b/drivers/sensor/st/lsm6dsl/lsm6dsl.c @@ -472,14 +472,12 @@ static int lsm6dsl_sample_fetch(const struct device *dev, static inline void lsm6dsl_accel_convert(struct sensor_value *val, int raw_val, float sensitivity) { - double dval; + int64_t dval; - /* Sensitivity is exposed in mg/LSB */ + /* Sensitivity is exposed in ug/LSB */ /* Convert to m/s^2 */ - dval = (double)(raw_val) * (double)sensitivity * SENSOR_G_DOUBLE / 1000; - val->val1 = (int32_t)dval; - val->val2 = (((int32_t)(dval * 1000)) % 1000) * 1000; - + dval = (int64_t)raw_val * sensitivity; + sensor_ug_to_ms2(dval, val); } static inline int lsm6dsl_accel_get_channel(enum sensor_channel chan, @@ -522,13 +520,12 @@ static int lsm6dsl_accel_channel_get(enum sensor_channel chan, static inline void lsm6dsl_gyro_convert(struct sensor_value *val, int raw_val, float sensitivity) { - double dval; + int64_t dval; - /* Sensitivity is exposed in mdps/LSB */ - /* Convert to rad/s */ - dval = (double)(raw_val * (double)sensitivity * SENSOR_DEG2RAD_DOUBLE / 1000); - val->val1 = (int32_t)dval; - val->val2 = (((int32_t)(dval * 1000)) % 1000) * 1000; + /* Sensitivity is exposed in udps/LSB */ + /* So, calculate value in 10 udps unit and then to rad/s */ + dval = (int64_t)raw_val * sensitivity / 10; + sensor_10udegrees_to_rad(dval, val); } static inline int lsm6dsl_gyro_get_channel(enum sensor_channel chan, diff --git a/drivers/sensor/st/lsm6dsl/lsm6dsl.h b/drivers/sensor/st/lsm6dsl/lsm6dsl.h index da176f4f692..524cc6bd314 100644 --- a/drivers/sensor/st/lsm6dsl/lsm6dsl.h +++ b/drivers/sensor/st/lsm6dsl/lsm6dsl.h @@ -553,14 +553,11 @@ #define LSM6DSL_REG_Z_OFS_USR 0x75 -/* Accel sensor sensitivity grain is 0.061 mg/LSB */ -#define SENSI_GRAIN_XL (61LL / 1000.0) - -/* Gyro sensor sensitivity grain is 4.375 mdps/LSB */ -#define SENSI_GRAIN_G (4375LL / 1000.0) -#define SENSOR_PI_DOUBLE (SENSOR_PI / 1000000.0) -#define SENSOR_DEG2RAD_DOUBLE (SENSOR_PI_DOUBLE / 180) -#define SENSOR_G_DOUBLE (SENSOR_G / 1000000.0) +/* Accel sensor sensitivity grain is 61 ug/LSB */ +#define SENSI_GRAIN_XL 61LL + +/* Gyro sensor sensitivity grain is 4375 udps/LSB */ +#define SENSI_GRAIN_G 4375LL #if CONFIG_LSM6DSL_ACCEL_FS == 0 #define LSM6DSL_ACCEL_FS_RUNTIME 1 diff --git a/drivers/sensor/st/lsm6dso/lsm6dso.c b/drivers/sensor/st/lsm6dso/lsm6dso.c index 974c0307ba8..fbd2f552356 100644 --- a/drivers/sensor/st/lsm6dso/lsm6dso.c +++ b/drivers/sensor/st/lsm6dso/lsm6dso.c @@ -909,7 +909,7 @@ static int lsm6dso_init(const struct device *dev) .accel_pm = DT_INST_PROP(inst, accel_pm), \ .accel_odr = DT_INST_PROP(inst, accel_odr), \ .accel_range = DT_INST_PROP(inst, accel_range) | \ - (DT_NODE_HAS_COMPAT(DT_DRV_INST(inst), st_lsm6dso32) ? \ + (DT_INST_NODE_HAS_COMPAT(inst, st_lsm6dso32) ? \ ACCEL_RANGE_DOUBLE : 0), \ .gyro_pm = DT_INST_PROP(inst, gyro_pm), \ .gyro_odr = DT_INST_PROP(inst, gyro_odr), \ diff --git a/drivers/sensor/st/stm32_temp/stm32_temp.c b/drivers/sensor/st/stm32_temp/stm32_temp.c index 5e594b0fe0c..48abc493718 100644 --- a/drivers/sensor/st/stm32_temp/stm32_temp.c +++ b/drivers/sensor/st/stm32_temp/stm32_temp.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #if defined(CONFIG_SOC_SERIES_STM32H5X) #include @@ -74,6 +75,7 @@ static int stm32_temp_sample_fetch(const struct device *dev, enum sensor_channel } k_mutex_lock(&data->mutex, K_FOREVER); + pm_device_runtime_get(data->adc); rc = adc_channel_setup(data->adc, &data->adc_cfg); if (rc) { @@ -97,6 +99,7 @@ static int stm32_temp_sample_fetch(const struct device *dev, enum sensor_channel path &= ~LL_ADC_PATH_INTERNAL_TEMPSENSOR); unlock: + pm_device_runtime_put(data->adc); k_mutex_unlock(&data->mutex); return rc; @@ -149,7 +152,7 @@ static int stm32_temp_channel_get(const struct device *dev, enum sensor_channel temp += 25; #endif - return sensor_value_from_double(val, temp); + return sensor_value_from_float(val, temp); } static const struct sensor_driver_api stm32_temp_driver_api = { diff --git a/drivers/sensor/st/stm32_vbat/Kconfig b/drivers/sensor/st/stm32_vbat/Kconfig index 8f1c7e03875..f5430c91a6b 100644 --- a/drivers/sensor/st/stm32_vbat/Kconfig +++ b/drivers/sensor/st/stm32_vbat/Kconfig @@ -7,6 +7,8 @@ config STM32_VBAT bool "STM32 Vbat Sensor" default y depends on DT_HAS_ST_STM32_VBAT_ENABLED - depends on ADC && (SOC_FAMILY_STM32 && !SOC_SERIES_STM32F1X) + depends on DT_HAS_ST_STM32_ADC_ENABLED + depends on SOC_FAMILY_STM32 && !SOC_SERIES_STM32F1X + select ADC help Enable driver for STM32 Vbat sensor and then also ADC diff --git a/drivers/sensor/st/stm32_vbat/stm32_vbat.c b/drivers/sensor/st/stm32_vbat/stm32_vbat.c index 8379670fab3..87942f4bfd2 100644 --- a/drivers/sensor/st/stm32_vbat/stm32_vbat.c +++ b/drivers/sensor/st/stm32_vbat/stm32_vbat.c @@ -9,6 +9,7 @@ #include #include #include +#include #include LOG_MODULE_REGISTER(stm32_vbat, CONFIG_SENSOR_LOG_LEVEL); @@ -45,6 +46,7 @@ static int stm32_vbat_sample_fetch(const struct device *dev, enum sensor_channel } k_mutex_lock(&data->mutex, K_FOREVER); + pm_device_runtime_get(data->adc); rc = adc_channel_setup(data->adc, &data->adc_cfg); @@ -67,6 +69,7 @@ static int stm32_vbat_sample_fetch(const struct device *dev, enum sensor_channel path &= ~LL_ADC_PATH_INTERNAL_VBAT); unlock: + pm_device_runtime_put(data->adc); k_mutex_unlock(&data->mutex); return rc; @@ -77,18 +80,16 @@ static int stm32_vbat_channel_get(const struct device *dev, enum sensor_channel { struct stm32_vbat_data *data = dev->data; const struct stm32_vbat_config *cfg = dev->config; - float voltage; + int32_t voltage; if (chan != SENSOR_CHAN_VOLTAGE) { return -ENOTSUP; } - /* Sensor value in millivolts */ - voltage = data->raw * adc_ref_internal(data->adc) / 0x0FFF; - /* considering the vbat input through a resistor bridge */ - voltage = voltage * cfg->ratio / 1000; /* value of SENSOR_CHAN_VOLTAGE in Volt */ + /* Sensor value in millivolts considering the vbat input through a resistor bridge */ + voltage = data->raw * adc_ref_internal(data->adc) * cfg->ratio / 0x0FFF; - return sensor_value_from_double(val, voltage); + return sensor_value_from_milli(val, voltage); } static const struct sensor_driver_api stm32_vbat_driver_api = { @@ -103,6 +104,11 @@ static int stm32_vbat_init(const struct device *dev) k_mutex_init(&data->mutex); + if (data->adc == NULL) { + LOG_ERR("ADC is not enabled"); + return -ENODEV; + } + if (!device_is_ready(data->adc)) { LOG_ERR("Device %s is not ready", data->adc->name); return -ENODEV; @@ -118,9 +124,13 @@ static int stm32_vbat_init(const struct device *dev) return 0; } +#define STM32_VBAT_GET_ADC_OR_NULL(inst) \ + COND_CODE_1(DT_NODE_HAS_STATUS(DT_INST_IO_CHANNELS_CTLR(inst), okay), \ + (DEVICE_DT_GET(DT_INST_IO_CHANNELS_CTLR(inst))), (NULL)) + #define STM32_VBAT_DEFINE(inst) \ static struct stm32_vbat_data stm32_vbat_dev_data_##inst = { \ - .adc = DEVICE_DT_GET(DT_INST_IO_CHANNELS_CTLR(inst)), \ + .adc = STM32_VBAT_GET_ADC_OR_NULL(inst), \ .adc_base = (ADC_TypeDef *)DT_REG_ADDR(DT_INST_IO_CHANNELS_CTLR(0)), \ .adc_cfg = { \ .gain = ADC_GAIN_1, \ @@ -138,6 +148,6 @@ static int stm32_vbat_init(const struct device *dev) SENSOR_DEVICE_DT_INST_DEFINE(inst, stm32_vbat_init, NULL, \ &stm32_vbat_dev_data_##inst, &stm32_vbat_dev_config_##inst, \ POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, \ - &stm32_vbat_driver_api); \ + &stm32_vbat_driver_api); DT_INST_FOREACH_STATUS_OKAY(STM32_VBAT_DEFINE) diff --git a/drivers/sensor/st/stm32_vref/Kconfig b/drivers/sensor/st/stm32_vref/Kconfig index 192cd3fd922..3e76dcd4f79 100644 --- a/drivers/sensor/st/stm32_vref/Kconfig +++ b/drivers/sensor/st/stm32_vref/Kconfig @@ -7,6 +7,7 @@ config STM32_VREF bool "STM32 VREF Sensor" default y depends on DT_HAS_ST_STM32_VREF_ENABLED - depends on ADC && (SOC_FAMILY_STM32 && !SOC_SERIES_STM32F1X) + depends on SOC_FAMILY_STM32 && !SOC_SERIES_STM32F1X + select ADC help Enable driver for STM32 Vref sensor. diff --git a/drivers/sensor/st/stm32_vref/stm32_vref.c b/drivers/sensor/st/stm32_vref/stm32_vref.c index 3532d2aeddd..5db5a857167 100644 --- a/drivers/sensor/st/stm32_vref/stm32_vref.c +++ b/drivers/sensor/st/stm32_vref/stm32_vref.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #if defined(CONFIG_SOC_SERIES_STM32H5X) #include @@ -45,6 +46,7 @@ static int stm32_vref_sample_fetch(const struct device *dev, enum sensor_channel } k_mutex_lock(&data->mutex, K_FOREVER); + pm_device_runtime_get(data->adc); rc = adc_channel_setup(data->adc, &data->adc_cfg); if (rc) { @@ -71,6 +73,7 @@ static int stm32_vref_sample_fetch(const struct device *dev, enum sensor_channel unlock: + pm_device_runtime_put(data->adc); k_mutex_unlock(&data->mutex); return rc; @@ -81,7 +84,7 @@ static int stm32_vref_channel_get(const struct device *dev, enum sensor_channel { struct stm32_vref_data *data = dev->data; const struct stm32_vref_config *cfg = dev->config; - float vref; + int32_t vref; if (chan != SENSOR_CHAN_VOLTAGE) { return -ENOTSUP; @@ -112,14 +115,12 @@ static int stm32_vref_channel_get(const struct device *dev, enum sensor_channel #else vref = cfg->cal_mv * (*cfg->cal_addr) / data->raw; #endif /* CONFIG_SOC_SERIES_STM32H5X */ - /* millivolt to volt */ - vref /= 1000; #if defined(CONFIG_SOC_SERIES_STM32H5X) LL_ICACHE_Enable(); #endif /* CONFIG_SOC_SERIES_STM32H5X */ - return sensor_value_from_double(val, vref); + return sensor_value_from_milli(val, vref); } static const struct sensor_driver_api stm32_vref_driver_api = { diff --git a/drivers/sensor/tdk/icm42688/icm42688_decoder.c b/drivers/sensor/tdk/icm42688/icm42688_decoder.c index 3dc556ac61c..b71d06b7f3a 100644 --- a/drivers/sensor/tdk/icm42688/icm42688_decoder.c +++ b/drivers/sensor/tdk/icm42688/icm42688_decoder.c @@ -178,7 +178,7 @@ static uint8_t icm42688_encode_channel(enum sensor_channel chan) return encode_bmask; } -int icm42688_encode(const struct device *dev, const enum sensor_channel *const channels, +int icm42688_encode(const struct device *dev, const struct sensor_chan_spec *const channels, const size_t num_channels, uint8_t *buf) { struct icm42688_dev_data *data = dev->data; @@ -187,7 +187,7 @@ int icm42688_encode(const struct device *dev, const enum sensor_channel *const c edata->channels = 0; for (int i = 0; i < num_channels; i++) { - edata->channels |= icm42688_encode_channel(channels[i]); + edata->channels |= icm42688_encode_channel(channels[i].chan_type); } edata->header.is_fifo = false; @@ -345,9 +345,8 @@ static uint32_t gyro_period_ns[] = { [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) +static int icm42688_fifo_decode(const uint8_t *buffer, struct sensor_chan_spec chan_spec, + 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; @@ -356,7 +355,7 @@ static int icm42688_fifo_decode(const uint8_t *buffer, enum sensor_channel chann int count = 0; int rc; - if ((uintptr_t)buffer_end <= *fit || channel_idx != 0) { + if ((uintptr_t)buffer_end <= *fit || chan_spec.chan_idx != 0) { return 0; } @@ -388,7 +387,7 @@ static int icm42688_fifo_decode(const uint8_t *buffer, enum sensor_channel chann buffer = frame_end; continue; } - if (channel == SENSOR_CHAN_DIE_TEMP) { + if (chan_spec.chan_type == SENSOR_CHAN_DIE_TEMP) { struct sensor_q31_data *data = (struct sensor_q31_data *)data_out; data->shift = 9; @@ -401,7 +400,7 @@ static int icm42688_fifo_decode(const uint8_t *buffer, enum sensor_channel chann } data->readings[count].temperature = icm42688_read_temperature_from_packet(buffer); - } else if (IS_ACCEL(channel) && has_accel) { + } else if (IS_ACCEL(chan_spec.chan_type) && has_accel) { /* Decode accel */ struct sensor_three_axis_data *data = (struct sensor_three_axis_data *)data_out; @@ -422,7 +421,7 @@ static int icm42688_fifo_decode(const uint8_t *buffer, enum sensor_channel chann buffer = frame_end; continue; } - } else if (IS_GYRO(channel) && has_gyro) { + } else if (IS_GYRO(chan_spec.chan_type) && has_gyro) { /* Decode gyro */ struct sensor_three_axis_data *data = (struct sensor_three_axis_data *)data_out; @@ -451,9 +450,8 @@ static int icm42688_fifo_decode(const uint8_t *buffer, enum sensor_channel chann 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) +static int icm42688_one_shot_decode(const uint8_t *buffer, struct sensor_chan_spec chan_spec, + 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; @@ -467,11 +465,11 @@ static int icm42688_one_shot_decode(const uint8_t *buffer, enum sensor_channel c if (*fit != 0) { return 0; } - if (max_count == 0 || channel_idx != 0) { + if (max_count == 0 || chan_spec.chan_idx != 0) { return -EINVAL; } - switch (channel) { + switch (chan_spec.chan_type) { case SENSOR_CHAN_ACCEL_X: case SENSOR_CHAN_ACCEL_Y: case SENSOR_CHAN_ACCEL_Z: @@ -570,31 +568,31 @@ 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) +static int icm42688_decoder_decode(const uint8_t *buffer, struct sensor_chan_spec chan_spec, + 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_fifo_decode(buffer, chan_spec, fit, max_count, data_out); } - return icm42688_one_shot_decode(buffer, channel, channel_idx, fit, max_count, data_out); + return icm42688_one_shot_decode(buffer, chan_spec, 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) +static int icm42688_decoder_get_frame_count(const uint8_t *buffer, + struct sensor_chan_spec chan_spec, + uint16_t *frame_count) { const struct icm42688_fifo_data *data = (const struct icm42688_fifo_data *)buffer; const struct icm42688_decoder_header *header = &data->header; - if (channel_idx != 0) { + if (chan_spec.chan_idx != 0) { return -ENOTSUP; } if (!header->is_fifo) { - switch (channel) { + switch (chan_spec.chan_type) { case SENSOR_CHAN_ACCEL_X: case SENSOR_CHAN_ACCEL_Y: case SENSOR_CHAN_ACCEL_Z: @@ -643,10 +641,10 @@ static int icm42688_decoder_get_frame_count(const uint8_t *buffer, enum sensor_c return 0; } -static int icm42688_decoder_get_size_info(enum sensor_channel channel, size_t *base_size, +static int icm42688_decoder_get_size_info(struct sensor_chan_spec chan_spec, size_t *base_size, size_t *frame_size) { - switch (channel) { + switch (chan_spec.chan_type) { case SENSOR_CHAN_ACCEL_X: case SENSOR_CHAN_ACCEL_Y: case SENSOR_CHAN_ACCEL_Z: diff --git a/drivers/sensor/tdk/icm42688/icm42688_decoder.h b/drivers/sensor/tdk/icm42688/icm42688_decoder.h index 499cf3d0801..9eadcbcecad 100644 --- a/drivers/sensor/tdk/icm42688/icm42688_decoder.h +++ b/drivers/sensor/tdk/icm42688/icm42688_decoder.h @@ -36,7 +36,7 @@ struct icm42688_encoded_data { int16_t readings[7]; }; -int icm42688_encode(const struct device *dev, const enum sensor_channel *const channels, +int icm42688_encode(const struct device *dev, const struct sensor_chan_spec *const channels, const size_t num_channels, uint8_t *buf); int icm42688_get_decoder(const struct device *dev, const struct sensor_decoder_api **decoder); diff --git a/drivers/sensor/tdk/icm42688/icm42688_emul.c b/drivers/sensor/tdk/icm42688/icm42688_emul.c index 732af64289b..41b6b11ea5f 100644 --- a/drivers/sensor/tdk/icm42688/icm42688_emul.c +++ b/drivers/sensor/tdk/icm42688/icm42688_emul.c @@ -295,15 +295,15 @@ static void icm42688_emul_get_gyro_ranges(const struct emul *target, q31_t *lowe *lower = -*upper; } -static int icm42688_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) +static int icm42688_emul_backend_get_sample_range(const struct emul *target, + struct sensor_chan_spec ch, q31_t *lower, + q31_t *upper, q31_t *epsilon, int8_t *shift) { if (!lower || !upper || !epsilon || !shift) { return -EINVAL; } - switch (ch) { + switch (ch.chan_type) { case SENSOR_CHAN_DIE_TEMP: /* degrees C = ([16-bit signed temp_data register] / 132.48) + 25 */ *shift = 9; @@ -328,7 +328,7 @@ static int icm42688_emul_backend_get_sample_range(const struct emul *target, enu return 0; } -static int icm42688_emul_backend_set_channel(const struct emul *target, enum sensor_channel ch, +static int icm42688_emul_backend_set_channel(const struct emul *target, struct sensor_chan_spec ch, const q31_t *value, int8_t shift) { if (!target || !target->data) { @@ -343,7 +343,7 @@ static int icm42688_emul_backend_set_channel(const struct emul *target, enum sen int64_t value_unshifted = shift < 0 ? ((int64_t)*value >> -shift) : ((int64_t)*value << shift); - switch (ch) { + switch (ch.chan_type) { case SENSOR_CHAN_DIE_TEMP: reg_addr = REG_TEMP_DATA1; reg_val = ((value_unshifted - (25 * Q31_SCALE)) * 13248) / (100 * Q31_SCALE); @@ -351,7 +351,7 @@ static int icm42688_emul_backend_set_channel(const struct emul *target, enum sen case SENSOR_CHAN_ACCEL_X: case SENSOR_CHAN_ACCEL_Y: case SENSOR_CHAN_ACCEL_Z: - switch (ch) { + switch (ch.chan_type) { case SENSOR_CHAN_ACCEL_X: reg_addr = REG_ACCEL_DATA_X1; break; @@ -370,7 +370,7 @@ static int icm42688_emul_backend_set_channel(const struct emul *target, enum sen case SENSOR_CHAN_GYRO_X: case SENSOR_CHAN_GYRO_Y: case SENSOR_CHAN_GYRO_Z: - switch (ch) { + switch (ch.chan_type) { case SENSOR_CHAN_GYRO_X: reg_addr = REG_GYRO_DATA_X1; break; @@ -402,14 +402,14 @@ static int icm42688_emul_backend_set_channel(const struct emul *target, enum sen return 0; } -static const struct emul_sensor_backend_api icm42688_emul_sensor_backend_api = { +static const struct emul_sensor_driver_api icm42688_emul_sensor_driver_api = { .set_channel = icm42688_emul_backend_set_channel, .get_sample_range = icm42688_emul_backend_get_sample_range, }; #define ICM42688_EMUL_DEFINE(n, api) \ EMUL_DT_INST_DEFINE(n, icm42688_emul_init, &icm42688_emul_data_##n, \ - &icm42688_emul_cfg_##n, &api, &icm42688_emul_sensor_backend_api) + &icm42688_emul_cfg_##n, &api, &icm42688_emul_sensor_driver_api) #define ICM42688_EMUL_SPI(n) \ static struct icm42688_emul_data icm42688_emul_data_##n; \ diff --git a/drivers/sensor/tdk/icm42688/icm42688_rtio.c b/drivers/sensor/tdk/icm42688/icm42688_rtio.c index ccb9532ee45..ad00fd7abf2 100644 --- a/drivers/sensor/tdk/icm42688/icm42688_rtio.c +++ b/drivers/sensor/tdk/icm42688/icm42688_rtio.c @@ -46,7 +46,7 @@ static int icm42688_rtio_sample_fetch(const struct device *dev, int16_t readings 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; + const struct sensor_chan_spec *const channels = cfg->channels; const size_t num_channels = cfg->count; uint32_t min_buf_len = sizeof(struct icm42688_encoded_data); int rc; diff --git a/drivers/sensor/ti/CMakeLists.txt b/drivers/sensor/ti/CMakeLists.txt index 39c7af3042f..4af7aa8996d 100644 --- a/drivers/sensor/ti/CMakeLists.txt +++ b/drivers/sensor/ti/CMakeLists.txt @@ -5,6 +5,7 @@ add_subdirectory_ifdef(CONFIG_BQ274XX bq274xx) add_subdirectory_ifdef(CONFIG_FDC2X1X fdc2x1x) add_subdirectory_ifdef(CONFIG_INA219 ina219) +add_subdirectory_ifdef(CONFIG_INA226 ina226) add_subdirectory_ifdef(CONFIG_INA23X ina23x) add_subdirectory_ifdef(CONFIG_INA3221 ina3221) add_subdirectory_ifdef(CONFIG_OPT3001 opt3001) @@ -15,5 +16,6 @@ add_subdirectory_ifdef(CONFIG_TMAG5273 tmag5273) add_subdirectory_ifdef(CONFIG_TMP007 tmp007) add_subdirectory_ifdef(CONFIG_TMP108 tmp108) add_subdirectory_ifdef(CONFIG_TMP112 tmp112) +add_subdirectory_ifdef(CONFIG_TMP114 tmp114) add_subdirectory_ifdef(CONFIG_TMP116 tmp116) # zephyr-keep-sorted-stop diff --git a/drivers/sensor/ti/Kconfig b/drivers/sensor/ti/Kconfig index 713c8f2f099..02c5a6e9780 100644 --- a/drivers/sensor/ti/Kconfig +++ b/drivers/sensor/ti/Kconfig @@ -5,6 +5,7 @@ source "drivers/sensor/ti/bq274xx/Kconfig" source "drivers/sensor/ti/fdc2x1x/Kconfig" source "drivers/sensor/ti/ina219/Kconfig" +source "drivers/sensor/ti/ina226/Kconfig" source "drivers/sensor/ti/ina23x/Kconfig" source "drivers/sensor/ti/ina3221/Kconfig" source "drivers/sensor/ti/opt3001/Kconfig" @@ -15,5 +16,6 @@ source "drivers/sensor/ti/tmag5273/Kconfig" source "drivers/sensor/ti/tmp007/Kconfig" source "drivers/sensor/ti/tmp108/Kconfig" source "drivers/sensor/ti/tmp112/Kconfig" +source "drivers/sensor/ti/tmp114/Kconfig" source "drivers/sensor/ti/tmp116/Kconfig" # zephyr-keep-sorted-stop diff --git a/drivers/sensor/ti/ina226/CMakeLists.txt b/drivers/sensor/ti/ina226/CMakeLists.txt new file mode 100644 index 00000000000..fd0e774e908 --- /dev/null +++ b/drivers/sensor/ti/ina226/CMakeLists.txt @@ -0,0 +1,6 @@ +# Copyright 2024 NXP +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_sources_ifdef(CONFIG_INA226 ina226.c) diff --git a/drivers/sensor/ti/ina226/Kconfig b/drivers/sensor/ti/ina226/Kconfig new file mode 100644 index 00000000000..f0e9cc75bee --- /dev/null +++ b/drivers/sensor/ti/ina226/Kconfig @@ -0,0 +1,26 @@ +# INA226 Bidirectional Current/Power Monitor + +# Copyright 2024 NXP +# SPDX-License-Identifier: Apache-2.0 + +config INA226 + bool "INA226 Current/Power Monitor" + default y + depends on DT_HAS_TI_INA226_ENABLED + select I2C + help + Enable driver for INA226 Bidirectional Current/Power Monitor. + +config INA226_VSHUNT + bool "INA226 VShunt Measurement Enable" + depends on DT_HAS_TI_INA226_ENABLED + help + Enable shunt voltage measurement for INA226. + + This is the actual shunt voltage measured which is scaled within the + INA226 based upon the SHUNT_CAL register. This value is useful for + determining the measurement noise or debugging the SHUNT_CAL value. + + Note that enabling this option requires an extra I2C read when the + SENSOR_CHAN_ALL is selected. Hence, only enable this option if the + shunt voltage measurement is required. diff --git a/drivers/sensor/ti/ina226/ina226.c b/drivers/sensor/ti/ina226/ina226.c new file mode 100644 index 00000000000..5f46b0322f0 --- /dev/null +++ b/drivers/sensor/ti/ina226/ina226.c @@ -0,0 +1,335 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* TODO: Add functionality for Trigger. */ + +#define DT_DRV_COMPAT ti_ina226 + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* Device register addresses. */ +#define INA226_REG_CONFIG 0x00 +#define INA226_REG_SHUNT_VOLT 0x01 +#define INA226_REG_BUS_VOLT 0x02 +#define INA226_REG_POWER 0x03 +#define INA226_REG_CURRENT 0x04 +#define INA226_REG_CALIB 0x05 +#define INA226_REG_MASK 0x06 +#define INA226_REG_ALERT 0x07 +#define INA226_REG_MANUFACTURER_ID 0xFE +#define INA226_REG_DEVICE_ID 0xFF + +/* Device register values. */ +#define INA226_MANUFACTURER_ID 0x5449 +#define INA226_DEVICE_ID 0x2260 + +struct ina226_data { + const struct device *dev; + int16_t current; + uint16_t bus_voltage; + uint16_t power; +#ifdef CONFIG_INA226_VSHUNT + int16_t shunt_voltage; +#endif + enum sensor_channel chan; +}; + +struct ina226_config { + const struct i2c_dt_spec bus; + uint16_t config; + uint32_t current_lsb; + uint16_t cal; +}; + +LOG_MODULE_REGISTER(INA226, CONFIG_SENSOR_LOG_LEVEL); + +/** @brief Calibration scaling value (scaled by 10^-5) */ +#define INA226_CAL_SCALING 512ULL + +/** @brief The LSB value for the bus voltage register, in microvolts/LSB. */ +#define INA226_BUS_VOLTAGE_TO_uV(x) ((x) * 1250U) + +/** @brief The LSB value for the shunt voltage register, in microvolts/LSB. */ +#define INA226_SHUNT_VOLTAGE_TO_uV(x) ((x) * 2500U / 1000U) + +/** @brief Power scaling (need factor of 0.2) */ +#define INA226_POWER_TO_uW(x) ((x) * 25ULL) + + +int ina226_reg_read_16(const struct i2c_dt_spec *bus, uint8_t reg, uint16_t *val) +{ + uint8_t data[2]; + int ret; + + ret = i2c_burst_read_dt(bus, reg, data, sizeof(data)); + if (ret < 0) { + return ret; + } + + *val = sys_get_be16(data); + + return ret; +} + +int ina226_reg_write(const struct i2c_dt_spec *bus, uint8_t reg, uint16_t val) +{ + uint8_t tx_buf[3]; + + tx_buf[0] = reg; + sys_put_be16(val, &tx_buf[1]); + + return i2c_write_dt(bus, tx_buf, sizeof(tx_buf)); +} + +static void micro_s32_to_sensor_value(struct sensor_value *val, int32_t value_microX) +{ + val->val1 = value_microX / 1000000L; + val->val2 = value_microX % 1000000L; +} + +static int ina226_channel_get(const struct device *dev, enum sensor_channel chan, + struct sensor_value *val) +{ + const struct ina226_data *data = dev->data; + const struct ina226_config *config = dev->config; + + switch (chan) { + case SENSOR_CHAN_VOLTAGE: + micro_s32_to_sensor_value(val, INA226_BUS_VOLTAGE_TO_uV(data->bus_voltage)); + break; + case SENSOR_CHAN_CURRENT: + /* see datasheet "Current and Power calculations" section */ + micro_s32_to_sensor_value(val, data->current * config->current_lsb); + break; + case SENSOR_CHAN_POWER: + /* power in uW is power_reg * current_lsb * 0.2 */ + micro_s32_to_sensor_value(val, + INA226_POWER_TO_uW((uint32_t)data->power * config->current_lsb)); + break; +#ifdef CONFIG_INA226_VSHUNT + case SENSOR_CHAN_VSHUNT: + micro_s32_to_sensor_value(val, INA226_SHUNT_VOLTAGE_TO_uV(data->shunt_voltage)); + break; +#endif /* CONFIG_INA226_VSHUNT */ + default: + return -ENOTSUP; + } + + return 0; +} + +static int ina226_read_data(const struct device *dev) +{ + struct ina226_data *data = dev->data; + const struct ina226_config *config = dev->config; + int ret; + + if ((data->chan == SENSOR_CHAN_ALL) || (data->chan == SENSOR_CHAN_VOLTAGE)) { + ret = ina226_reg_read_16(&config->bus, INA226_REG_BUS_VOLT, &data->bus_voltage); + if (ret < 0) { + LOG_ERR("Failed to read bus voltage"); + return ret; + } + } + + if ((data->chan == SENSOR_CHAN_ALL) || (data->chan == SENSOR_CHAN_CURRENT)) { + ret = ina226_reg_read_16(&config->bus, INA226_REG_CURRENT, &data->current); + if (ret < 0) { + LOG_ERR("Failed to read current"); + return ret; + } + } + + if ((data->chan == SENSOR_CHAN_ALL) || (data->chan == SENSOR_CHAN_POWER)) { + ret = ina226_reg_read_16(&config->bus, INA226_REG_POWER, &data->power); + if (ret < 0) { + LOG_ERR("Failed to read power"); + return ret; + } + } + +#ifdef CONFIG_INA226_VSHUNT + if ((data->chan == SENSOR_CHAN_ALL) || (data->chan == SENSOR_CHAN_VSHUNT)) { + ret = ina226_reg_read_16(&config->bus, INA226_REG_SHUNT_VOLT, &data->shunt_voltage); + if (ret < 0) { + LOG_ERR("Failed to read shunt voltage"); + return ret; + } + } +#endif /* CONFIG_INA226_VSHUNT */ + + return 0; +} + +static int ina226_sample_fetch(const struct device *dev, enum sensor_channel chan) +{ + struct ina226_data *data = dev->data; + + if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_VOLTAGE + && chan != SENSOR_CHAN_CURRENT && chan != SENSOR_CHAN_POWER +#ifdef CONFIG_INA226_VSHUNT + && chan != SENSOR_CHAN_VSHUNT +#endif /* CONFIG_INA226_VSHUNT */ + ) { + return -ENOTSUP; + } + + data->chan = chan; + + return ina226_read_data(dev); +} + +static int ina226_attr_set(const struct device *dev, enum sensor_channel chan, + enum sensor_attribute attr, const struct sensor_value *val) +{ + const struct ina226_config *config = dev->config; + uint16_t data = val->val1; + + switch (attr) { + case SENSOR_ATTR_CONFIGURATION: + return ina226_reg_write(&config->bus, INA226_REG_CONFIG, data); + case SENSOR_ATTR_CALIBRATION: + return ina226_reg_write(&config->bus, INA226_REG_CALIB, data); + default: + LOG_ERR("INA226 attribute not supported."); + return -ENOTSUP; + } +} + +static int ina226_attr_get(const struct device *dev, enum sensor_channel chan, + enum sensor_attribute attr, struct sensor_value *val) +{ + const struct ina226_config *config = dev->config; + uint16_t data; + int ret; + + switch (attr) { + case SENSOR_ATTR_CONFIGURATION: + ret = ina226_reg_read_16(&config->bus, INA226_REG_CONFIG, &data); + if (ret < 0) { + return ret; + } + break; + case SENSOR_ATTR_CALIBRATION: + ret = ina226_reg_read_16(&config->bus, INA226_REG_CALIB, &data); + if (ret < 0) { + return ret; + } + break; + default: + LOG_ERR("INA226 attribute not supported."); + return -ENOTSUP; + } + + val->val1 = data; + val->val2 = 0; + + return 0; +} + +static int ina226_calibrate(const struct device *dev) +{ + const struct ina226_config *config = dev->config; + int ret; + + ret = ina226_reg_write(&config->bus, INA226_REG_CALIB, config->cal); + if (ret < 0) { + return ret; + } + + return 0; +} + +static int ina226_init(const struct device *dev) +{ + struct ina226_data *data = dev->data; + const struct ina226_config *config = dev->config; + uint16_t id; + int ret; + + if (!i2c_is_ready_dt(&config->bus)) { + LOG_ERR("I2C bus %s is not ready", config->bus.bus->name); + return -ENODEV; + } + + data->dev = dev; + + ret = ina226_reg_read_16(&config->bus, INA226_REG_MANUFACTURER_ID, &id); + if (ret < 0) { + LOG_ERR("Failed to read manufacturer register."); + return ret; + } + + if (id != INA226_MANUFACTURER_ID) { + LOG_ERR("Manufacturer ID doesn't match."); + return -ENODEV; + } + + ret = ina226_reg_read_16(&config->bus, INA226_REG_DEVICE_ID, &id); + if (ret < 0) { + LOG_ERR("Failed to read device register."); + return ret; + } + + if (id != INA226_DEVICE_ID) { + LOG_ERR("Device ID doesn't match."); + return -ENODEV; + } + + ret = ina226_reg_write(&config->bus, INA226_REG_CONFIG, config->config); + if (ret < 0) { + LOG_ERR("Failed to write configuration register."); + return ret; + } + + ret = ina226_calibrate(dev); + if (ret < 0) { + LOG_ERR("Failed to write calibration register."); + return ret; + } + + return 0; +} + +static const struct sensor_driver_api ina226_driver_api = { + .attr_set = ina226_attr_set, + .attr_get = ina226_attr_get, + .sample_fetch = ina226_sample_fetch, + .channel_get = ina226_channel_get, +}; + +#define INA226_DRIVER_INIT(inst) \ + static struct ina226_data ina226_data_##inst; \ + static const struct ina226_config ina226_config_##inst = { \ + .bus = I2C_DT_SPEC_INST_GET(inst), \ + .current_lsb = DT_INST_PROP(inst, current_lsb_microamps), \ + .cal = INA226_CAL_SCALING * 10000000ULL / \ + (DT_INST_PROP(inst, current_lsb_microamps) * \ + DT_INST_PROP(inst, rshunt_micro_ohms)), \ + .config = (DT_INST_ENUM_IDX(inst, avg_count) << 9) | \ + (DT_INST_ENUM_IDX(inst, vbus_conversion_time_us) << 6) | \ + (DT_INST_ENUM_IDX(inst, vshunt_conversion_time_us) << 3) | \ + DT_INST_ENUM_IDX(inst, operating_mode), \ + }; \ + SENSOR_DEVICE_DT_INST_DEFINE(inst, \ + &ina226_init, \ + NULL, \ + &ina226_data_##inst, \ + &ina226_config_##inst, \ + POST_KERNEL, \ + CONFIG_SENSOR_INIT_PRIORITY, \ + &ina226_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(INA226_DRIVER_INIT) diff --git a/drivers/sensor/ti/tmag5273/tmag5273.c b/drivers/sensor/ti/tmag5273/tmag5273.c index bade48fa80f..0ef91725dee 100644 --- a/drivers/sensor/ti/tmag5273/tmag5273.c +++ b/drivers/sensor/ti/tmag5273/tmag5273.c @@ -65,7 +65,7 @@ struct tmag5273_config { struct gpio_dt_spec int_gpio; -#if CONFIG_CRC +#ifdef CONFIG_CRC bool crc_enabled; #endif }; @@ -146,7 +146,7 @@ static int tmag5273_check_device_status(const struct tmag5273_config *drv_cfg, if ((*device_status & TMAG5273_VCC_UV_ER_MSK) == TMAG5273_VCC_UV_ERR) { LOG_WRN("VCC undervoltage detected"); } -#if CONFIG_CRC +#ifdef CONFIG_CRC if (drv_cfg->crc_enabled && ((*device_status & TMAG5273_OTP_CRC_ER_MSK) == TMAG5273_OTP_CRC_ERR)) { LOG_WRN("OTP CRC error detected"); @@ -387,7 +387,7 @@ static inline int tmag5273_attr_get_xyz_calc(const struct device *dev, struct se static inline uint8_t tmag5273_get_fetch_block_size(const struct tmag5273_config *drv_cfg, uint8_t remaining_bytes) { -#if CONFIG_CRC +#ifdef CONFIG_CRC if (drv_cfg->crc_enabled && (remaining_bytes > TMAG5273_CRC_DATA_BYTES)) { return TMAG5273_CRC_DATA_BYTES; } @@ -398,10 +398,13 @@ static inline uint8_t tmag5273_get_fetch_block_size(const struct tmag5273_config /** @brief returns the size of the CRC field if active */ static inline uint8_t tmag5273_get_crc_size(const struct tmag5273_config *drv_cfg) { +#ifdef CONFIG_CRC if (drv_cfg->crc_enabled) { return TMAG5273_CRC_I2C_SIZE; } - +#else + ARG_UNUSED(drv_cfg); +#endif return 0; } @@ -624,7 +627,7 @@ static int tmag5273_sample_fetch(const struct device *dev, enum sensor_channel c uint32_t nb_bytes = end_address - start_address + 1; -#if CONFIG_CRC +#ifdef CONFIG_CRC /* if CRC is enabled multiples of TMAG5273_CRC_DATA_BYTES need to be read */ if (drv_cfg->crc_enabled && ((nb_bytes % TMAG5273_CRC_DATA_BYTES) != 0)) { const uint8_t diff = TMAG5273_CRC_DATA_BYTES - (nb_bytes % TMAG5273_CRC_DATA_BYTES); @@ -659,7 +662,7 @@ static int tmag5273_sample_fetch(const struct device *dev, enum sensor_channel c return -EIO; } -#if CONFIG_CRC +#ifdef CONFIG_CRC /* check data validity, if activated */ if (drv_cfg->crc_enabled) { const uint8_t crc = crc8_ccitt(0xFF, &i2c_buffer[offset], block_size); @@ -891,7 +894,7 @@ static inline int tmag5273_init_device_config(const struct device *dev) /* REG_DEVICE_CONFIG_1 */ regdata = 0; -#if CONFIG_CRC +#ifdef CONFIG_CRC if (drv_cfg->crc_enabled) { regdata |= TMAG5273_CRC_ENABLE; } diff --git a/drivers/sensor/ti/tmp112/Kconfig b/drivers/sensor/ti/tmp112/Kconfig index 19baeade7dc..c6ece4e4b8c 100644 --- a/drivers/sensor/ti/tmp112/Kconfig +++ b/drivers/sensor/ti/tmp112/Kconfig @@ -15,6 +15,8 @@ config TMP112 The TMP102 is compatible with the TMP112 but is less accurate and has been successfully tested with this driver. +if TMP112 + config TMP112_FULL_SCALE_RUNTIME bool "Allow to set extended mode at runtime" default y @@ -28,3 +30,5 @@ config TMP112_SAMPLING_FREQUENCY_RUNTIME help When set conversion rate can be set at runtime using sensor_attr_set with SENSOR_ATTR_SAMPLING_FREQUENCY + +endif # TMP112 diff --git a/drivers/sensor/ti/tmp114/CMakeLists.txt b/drivers/sensor/ti/tmp114/CMakeLists.txt new file mode 100644 index 00000000000..c15a1091d20 --- /dev/null +++ b/drivers/sensor/ti/tmp114/CMakeLists.txt @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_sources(tmp114.c) diff --git a/drivers/sensor/ti/tmp114/Kconfig b/drivers/sensor/ti/tmp114/Kconfig new file mode 100644 index 00000000000..eb532e2f557 --- /dev/null +++ b/drivers/sensor/ti/tmp114/Kconfig @@ -0,0 +1,12 @@ +# TMP114 temperature sensor configuration options + +# Copyright (c) 2024 Fredrik Gihl +# SPDX-License-Identifier: Apache-2.0 + +config TMP114 + bool "TMP114 Temperature Sensor" + default y + depends on DT_HAS_TI_TMP114_ENABLED + select I2C + help + Enable driver for TMP114 temperature sensors. diff --git a/drivers/sensor/ti/tmp114/tmp114.c b/drivers/sensor/ti/tmp114/tmp114.c new file mode 100644 index 00000000000..747a8250578 --- /dev/null +++ b/drivers/sensor/ti/tmp114/tmp114.c @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2024 Fredrik Gihl + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT ti_tmp114 + +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(TMP114, CONFIG_SENSOR_LOG_LEVEL); + +#define TMP114_REG_TEMP 0x0 +#define TMP114_REG_ALERT 0x2 +#define TMP114_REG_CFGR 0x3 +#define TMP114_REG_DEVICE_ID 0xb + +#define TMP114_RESOLUTION 78125 /* in tens of uCelsius*/ +#define TMP114_RESOLUTION_DIV 10000000 + +#define TMP114_DEVICE_ID 0x1114 + +#define TMP114_ALERT_DATA_READY BIT(0) + +struct tmp114_data { + uint16_t sample; + uint16_t id; +}; + +struct tmp114_dev_config { + struct i2c_dt_spec bus; +}; + +static int tmp114_reg_read(const struct device *dev, uint8_t reg, + uint16_t *val) +{ + const struct tmp114_dev_config *cfg = dev->config; + + if (i2c_burst_read_dt(&cfg->bus, reg, (uint8_t *)val, 2) + < 0) { + return -EIO; + } + + *val = sys_be16_to_cpu(*val); + + return 0; +} + +static inline int tmp114_device_id_check(const struct device *dev, uint16_t *id) +{ + if (tmp114_reg_read(dev, TMP114_REG_DEVICE_ID, id) != 0) { + LOG_ERR("%s: Failed to get Device ID register!", dev->name); + return -EIO; + } + + if (*id != TMP114_DEVICE_ID) { + LOG_ERR("%s: Failed to match the device ID!", dev->name); + return -EINVAL; + } + + return 0; +} + +static int tmp114_sample_fetch(const struct device *dev, + enum sensor_channel chan) +{ + struct tmp114_data *drv_data = dev->data; + uint16_t value; + uint16_t cfg_reg = 0; + int rc; + + __ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL || + chan == SENSOR_CHAN_AMBIENT_TEMP); + + /* clear sensor values */ + drv_data->sample = 0U; + + /* Check alert register to make sure that a data is available */ + rc = tmp114_reg_read(dev, TMP114_REG_ALERT, &cfg_reg); + if (rc < 0) { + LOG_ERR("%s, Failed to read from CFGR register", dev->name); + return rc; + } + + if ((cfg_reg & TMP114_ALERT_DATA_READY) == 0) { + LOG_DBG("%s: no data ready", dev->name); + return -EBUSY; + } + + /* Get the most recent temperature measurement */ + rc = tmp114_reg_read(dev, TMP114_REG_TEMP, &value); + if (rc < 0) { + LOG_ERR("%s: Failed to read from TEMP register!", dev->name); + return rc; + } + + /* store measurements to the driver */ + drv_data->sample = (int16_t)value; + + return 0; +} + +static int tmp114_channel_get(const struct device *dev, + enum sensor_channel chan, + struct sensor_value *val) +{ + struct tmp114_data *drv_data = dev->data; + int32_t tmp; + + if (chan != SENSOR_CHAN_AMBIENT_TEMP) { + return -ENOTSUP; + } + + /* + * See datasheet for tmp114, section 'Temp_Result Register' section + * for more details on processing sample data. + */ + tmp = ((int16_t)drv_data->sample * (int32_t)TMP114_RESOLUTION) / 10; + val->val1 = tmp / 1000000; /* uCelsius */ + val->val2 = tmp % 1000000; + + return 0; +} + +static int tmp114_attr_get(const struct device *dev, enum sensor_channel chan, + enum sensor_attribute attr, struct sensor_value *val) +{ + uint16_t data; + int rc; + + if (chan != SENSOR_CHAN_AMBIENT_TEMP) { + return -ENOTSUP; + } + + switch (attr) { + case SENSOR_ATTR_CONFIGURATION: + rc = tmp114_reg_read(dev, TMP114_REG_CFGR, &data); + if (rc < 0) { + return rc; + } + break; + default: + return -ENOTSUP; + } + + val->val1 = data; + val->val2 = 0; + + return 0; +} + +static const struct sensor_driver_api tmp114_driver_api = { + .attr_get = tmp114_attr_get, + .sample_fetch = tmp114_sample_fetch, + .channel_get = tmp114_channel_get +}; + +static int tmp114_init(const struct device *dev) +{ + struct tmp114_data *drv_data = dev->data; + const struct tmp114_dev_config *cfg = dev->config; + int rc; + uint16_t id; + + if (!i2c_is_ready_dt(&cfg->bus)) { + LOG_ERR("I2C dev %s not ready", cfg->bus.bus->name); + return -EINVAL; + } + + /* Check the Device ID */ + rc = tmp114_device_id_check(dev, &id); + if (rc < 0) { + return rc; + } + LOG_INF("Got device ID: %x", id); + drv_data->id = id; + + return 0; +} + +#define DEFINE_TMP114(_num) \ + static struct tmp114_data tmp114_data_##_num; \ + static const struct tmp114_dev_config tmp114_config_##_num = { \ + .bus = I2C_DT_SPEC_INST_GET(_num) \ + }; \ + SENSOR_DEVICE_DT_INST_DEFINE(_num, tmp114_init, NULL, \ + &tmp114_data_##_num, &tmp114_config_##_num, POST_KERNEL, \ + CONFIG_SENSOR_INIT_PRIORITY, &tmp114_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(DEFINE_TMP114) diff --git a/drivers/sensor/tsic_xx6/CMakeLists.txt b/drivers/sensor/tsic_xx6/CMakeLists.txt new file mode 100644 index 00000000000..968d4cfe796 --- /dev/null +++ b/drivers/sensor/tsic_xx6/CMakeLists.txt @@ -0,0 +1,5 @@ +# Copyright (c) 2024 Vitrolife A/S +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() +zephyr_library_sources_ifdef(CONFIG_TSIC_XX6 tsic_xx6.c) diff --git a/drivers/sensor/tsic_xx6/Kconfig b/drivers/sensor/tsic_xx6/Kconfig new file mode 100644 index 00000000000..761eae1d963 --- /dev/null +++ b/drivers/sensor/tsic_xx6/Kconfig @@ -0,0 +1,11 @@ +# Copyright (c) 2024 Vitrolife A/S +# SPDX-License-Identifier: Apache-2.0 + +config TSIC_XX6 + bool "TSic xx6 driver" + default y + depends on DT_HAS_IST_TSIC_XX6_ENABLED + select PWM + select PWM_CAPTURE + help + Enable driver for TSic 206/306/316/506F/516/716. diff --git a/drivers/sensor/tsic_xx6/tsic_xx6.c b/drivers/sensor/tsic_xx6/tsic_xx6.c new file mode 100644 index 00000000000..5470394a49f --- /dev/null +++ b/drivers/sensor/tsic_xx6/tsic_xx6.c @@ -0,0 +1,284 @@ +/* + * Copyright (c) 2024, Vitrolife A/S + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT ist_tsic_xx6 + +#include +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(TSIC_XX6, CONFIG_SENSOR_LOG_LEVEL); + +#define FRAME_BIT_PERIOD_US 125 + +enum { + FRAME_PARITIY_BIT_LSB, + FRAME_DATA_BIT_0, + FRAME_DATA_BIT_1, + FRAME_DATA_BIT_2, + FRAME_DATA_BIT_3, + FRAME_DATA_BIT_4, + FRAME_DATA_BIT_5, + FRAME_DATA_BIT_6, + FRAME_DATA_BIT_7, + FRAME_START_BIT_LSB, + /* Theres a single bit period between the two packets that is constant high. This bit will + * be part of the 2nd packet's start bit thus frame length is not affected. + */ + FRAME_PARITIY_BIT_MSB, + FRAME_DATA_BIT_8, + FRAME_DATA_BIT_9, + FRAME_DATA_BIT_10, + FRAME_DATA_BIT_11, + FRAME_DATA_BIT_12, + FRAME_DATA_BIT_13, + FRAME_ZERO_BIT_0, + FRAME_ZERO_BIT_1, + FRAME_START_BIT_MSB, + FRAME_READY_BIT, + FRAME_FLAGS, +}; + +struct tsic_xx6_config { + const struct pwm_dt_spec pwm; + const int8_t lower_temperature_limit; + const uint8_t higher_temperature_limit; + const uint8_t data_bits; +}; + +struct tsic_xx6_data { + uint64_t frame_cycles; + struct sensor_value val; + + ATOMIC_DEFINE(frame, FRAME_FLAGS); + uint32_t buf; + uint8_t buf_index; +}; + +static inline void tsic_xx6_buf_reset(struct tsic_xx6_data *data) +{ + data->buf_index = FRAME_START_BIT_MSB; +} + +static inline bool tsic_xx6_is_buf_reset(struct tsic_xx6_data *data) +{ + return data->buf_index == FRAME_START_BIT_MSB; +} + +static inline bool tsic_xx6_is_data_line_idle(struct tsic_xx6_data *data, uint64_t period_cycles) +{ + /* If the period is larger than two frames assume the data line has been idle */ + return period_cycles > data->frame_cycles * 2; +} + +static void tsic_xx6_pwm_callback(const struct device *dev, uint32_t channel, + uint32_t period_cycles, uint32_t pulse_cycles, int status, + void *user_data) +{ + const struct device *tsic_xx6_dev = user_data; + const struct tsic_xx6_config *config = tsic_xx6_dev->config; + struct tsic_xx6_data *data = tsic_xx6_dev->data; + uint32_t low_cycles; + bool val; + + if (dev != config->pwm.dev || channel != config->pwm.channel) { + return; + } + + if (status != 0) { + LOG_ERR("callback failed: %d", status); + return; + } + + if (!tsic_xx6_is_buf_reset(data) && tsic_xx6_is_data_line_idle(data, period_cycles)) { + LOG_ERR("unexpected data idle"); + tsic_xx6_buf_reset(data); + } + + /* + * Calculate low cycles: The sensor sends the pulse in the last part of the period. The PWM + * capture driver triggers on rising edge with normal polarity. Therefore only the low part + * of the frame bit is present. + */ + low_cycles = period_cycles - pulse_cycles; + + /* 25 % duty cycle is 0, 75 % duty cycle is 1 */ + val = low_cycles * 2 < data->frame_cycles; + WRITE_BIT(data->buf, data->buf_index, val); + + if (data->buf_index > 0) { + --data->buf_index; + } else { + WRITE_BIT(data->buf, FRAME_READY_BIT, 1); + (void)atomic_set(data->frame, data->buf); + tsic_xx6_buf_reset(data); + } +} + +static inline bool tsic_xx6_parity_check(uint8_t data, bool parity) +{ + bool data_parity = false; + size_t i; + + for (i = 0; i < 8; ++i) { + data_parity ^= FIELD_GET(BIT(i), data); + } + + return (parity ^ data_parity) == 0; +} + +static int tsic_xx6_get_data_bits(const struct tsic_xx6_config *config, uint16_t *data_bits, + uint32_t frame) +{ + uint8_t frame_data_bit_high = + config->data_bits == 14 ? FRAME_DATA_BIT_13 : FRAME_DATA_BIT_10; + uint8_t data_msb = FIELD_GET(GENMASK(frame_data_bit_high, FRAME_DATA_BIT_8), frame); + uint8_t data_lsb = FIELD_GET(GENMASK(FRAME_DATA_BIT_7, FRAME_DATA_BIT_0), frame); + bool parity_msb = FIELD_GET(BIT(FRAME_PARITIY_BIT_MSB), frame); + bool parity_lsb = BIT(FRAME_PARITIY_BIT_LSB) & frame; + + if (!tsic_xx6_parity_check(data_msb, parity_msb) || + !tsic_xx6_parity_check(data_lsb, parity_lsb)) { + return -EIO; + } + + *data_bits = data_msb << 8 | data_lsb; + + return 0; +} + +static void tsic_xx6_get_value(const struct tsic_xx6_config *config, struct tsic_xx6_data *data, + uint16_t data_bits) +{ + int64_t tmp; + + /* Apply the datasheet formula scaled to micro celcius */ + tmp = data_bits * (config->higher_temperature_limit - config->lower_temperature_limit); + tmp = tmp * 1000000 / (BIT(config->data_bits) - 1); + tmp += (int64_t)config->lower_temperature_limit * 1000000; + + data->val.val1 = tmp / 1000000; + data->val.val2 = tmp % 1000000; +} + +static int tsic_xx6_sample_fetch(const struct device *dev, enum sensor_channel chan) +{ + const struct tsic_xx6_config *config = dev->config; + struct tsic_xx6_data *data = dev->data; + uint32_t frame; + uint16_t data_bits; + int rc; + + if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_AMBIENT_TEMP) { + return -ENOTSUP; + } + + frame = atomic_and(data->frame, ~BIT(FRAME_READY_BIT)); + + if (FIELD_GET(BIT(FRAME_READY_BIT), frame) == 0) { + return -EBUSY; + } + + rc = tsic_xx6_get_data_bits(config, &data_bits, frame); + if (rc != 0) { + return rc; + } + + tsic_xx6_get_value(config, data, data_bits); + + return 0; +} + +static int tsic_xx6_channel_get(const struct device *dev, enum sensor_channel chan, + struct sensor_value *val) +{ + struct tsic_xx6_data *data = dev->data; + + if (chan != SENSOR_CHAN_AMBIENT_TEMP) { + return -ENOTSUP; + } + + *val = data->val; + + return 0; +} + +static const struct sensor_driver_api tsic_xx6_driver_api = {.sample_fetch = tsic_xx6_sample_fetch, + .channel_get = tsic_xx6_channel_get}; + +static int tsic_xx6_get_frame_cycles(const struct tsic_xx6_config *config, uint64_t *frame_cycles) +{ + uint64_t tmp; + int rc; + + rc = pwm_get_cycles_per_sec(config->pwm.dev, config->pwm.channel, &tmp); + if (rc != 0) { + return rc; + } + + if (u64_mul_overflow(tmp, FRAME_BIT_PERIOD_US, &tmp)) { + return -ERANGE; + } + + *frame_cycles = tmp / USEC_PER_SEC; + + return 0; +} + +static int tsic_xx6_init(const struct device *dev) +{ + const struct tsic_xx6_config *config = dev->config; + struct tsic_xx6_data *data = dev->data; + int rc; + + if (!pwm_is_ready_dt(&config->pwm)) { + return -ENODEV; + } + + rc = tsic_xx6_get_frame_cycles(config, &data->frame_cycles); + if (rc != 0) { + return rc; + } + + rc = pwm_configure_capture(config->pwm.dev, config->pwm.channel, + config->pwm.flags | PWM_CAPTURE_TYPE_BOTH | + PWM_CAPTURE_MODE_CONTINUOUS, + tsic_xx6_pwm_callback, (void *)dev); + if (rc != 0) { + return rc; + } + + tsic_xx6_buf_reset(data); + + rc = pwm_enable_capture(config->pwm.dev, config->pwm.channel); + if (rc != 0) { + return rc; + } + + return 0; +} + +#define TSIC_XX6_DEVICE(n) \ + \ + static struct tsic_xx6_data tsic_xx6_data_##n; \ + \ + static const struct tsic_xx6_config tsic_xx6_config_##n = { \ + .pwm = PWM_DT_SPEC_INST_GET(n), \ + .lower_temperature_limit = (int8_t)DT_INST_PROP(n, lower_temperature_limit), \ + .higher_temperature_limit = DT_INST_PROP(n, higher_temperature_limit), \ + .data_bits = DT_INST_PROP(n, data_bits), \ + }; \ + \ + SENSOR_DEVICE_DT_INST_DEFINE(n, &tsic_xx6_init, NULL, &tsic_xx6_data_##n, \ + &tsic_xx6_config_##n, POST_KERNEL, \ + CONFIG_SENSOR_INIT_PRIORITY, &tsic_xx6_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(TSIC_XX6_DEVICE) diff --git a/drivers/sensor/veaa_x_3/CMakeLists.txt b/drivers/sensor/veaa_x_3/CMakeLists.txt new file mode 100644 index 00000000000..07db1686942 --- /dev/null +++ b/drivers/sensor/veaa_x_3/CMakeLists.txt @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_sources(veaa_x_3.c) diff --git a/drivers/sensor/veaa_x_3/Kconfig b/drivers/sensor/veaa_x_3/Kconfig new file mode 100644 index 00000000000..143618c6838 --- /dev/null +++ b/drivers/sensor/veaa_x_3/Kconfig @@ -0,0 +1,18 @@ +# VEAA-X-3 configuration options + +# Copyright (c) 2024, Vitrolife A/S +# SPDX-License-Identifier: Apache-2.0 + +config VEAA_X_3 + bool "VEAA-X-3 pressure driver" + default y + depends on DT_HAS_FESTO_VEAA_X_3_ENABLED + depends on ADC + depends on DAC + help + Enable driver for Festo VEAA-X-3. + + The driver assumes that the maximum ADC value matches the maximum + output from the device, and that the maximum DAC value matches the + maximum input value for the device. External hardware is probably + required between the ADC/DAC and the device. diff --git a/drivers/sensor/veaa_x_3/veaa_x_3.c b/drivers/sensor/veaa_x_3/veaa_x_3.c new file mode 100644 index 00000000000..c5935942069 --- /dev/null +++ b/drivers/sensor/veaa_x_3/veaa_x_3.c @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2024, Vitrolife A/S + * + * SPDX-License-Identifier: Apache-2.0 + * + * Datasheet: + * https://www.festo.com/media/pim/620/D15000100140620.PDF + * + */ + +#define DT_DRV_COMPAT festo_veaa_x_3 + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(veaa_x_3_sensor, CONFIG_SENSOR_LOG_LEVEL); + +struct veaa_x_3_data { + uint16_t adc_buf; +}; + +struct veaa_x_3_cfg { + const struct adc_dt_spec adc; + const struct device *dac; + const uint8_t dac_channel; + const uint8_t dac_resolution; + const uint16_t kpa_max; + const uint8_t kpa_min; +}; + +static uint16_t veaa_x_3_kpa_range(const struct veaa_x_3_cfg *cfg) +{ + return cfg->kpa_max - cfg->kpa_min; +} + +static int veaa_x_3_attr_set(const struct device *dev, enum sensor_channel chan, + enum sensor_attribute attr, const struct sensor_value *val) +{ + const struct veaa_x_3_cfg *cfg = dev->config; + uint32_t tmp; + + if (chan != SENSOR_CHAN_PRESS) { + return -ENOTSUP; + } + + switch ((enum sensor_attribute_veaa_x_3)attr) { + case SENSOR_ATTR_VEAA_X_3_SETPOINT: + if (val->val1 > cfg->kpa_max || val->val1 < cfg->kpa_min) { + LOG_ERR("%d kPa outside range", val->val1); + return -EINVAL; + } + + /* Convert from kPa to DAC value */ + tmp = val->val1 - cfg->kpa_min; + if (u32_mul_overflow(tmp, BIT(cfg->dac_resolution) - 1, &tmp)) { + LOG_ERR("kPa to DAC overflow"); + return -ERANGE; + } + tmp /= veaa_x_3_kpa_range(cfg); + + return dac_write_value(cfg->dac, cfg->dac_channel, tmp); + default: + return -ENOTSUP; + } +} + +static int veaa_x_3_attr_get(const struct device *dev, enum sensor_channel chan, + enum sensor_attribute attr, struct sensor_value *val) +{ + const struct veaa_x_3_cfg *cfg = dev->config; + + if (chan != SENSOR_CHAN_PRESS) { + return -ENOTSUP; + } + + switch ((enum sensor_attribute_veaa_x_3)attr) { + case SENSOR_ATTR_VEAA_X_3_RANGE: + val->val1 = cfg->kpa_min; + val->val2 = cfg->kpa_max; + return 0; + default: + return -ENOTSUP; + } +} + +static int veaa_x_3_sample_fetch(const struct device *dev, enum sensor_channel chan) +{ + int rc; + const struct veaa_x_3_cfg *cfg = dev->config; + struct veaa_x_3_data *data = dev->data; + struct adc_sequence sequence = { + .buffer = &data->adc_buf, + .buffer_size = sizeof(data->adc_buf), + }; + + if (chan != SENSOR_CHAN_PRESS && chan != SENSOR_CHAN_ALL) { + return -ENOTSUP; + } + + rc = adc_sequence_init_dt(&cfg->adc, &sequence); + if (rc != 0) { + return rc; + } + sequence.options = NULL; + sequence.buffer = &data->adc_buf; + sequence.buffer_size = sizeof(data->adc_buf); + sequence.calibrate = false; + + rc = adc_read_dt(&cfg->adc, &sequence); + if (rc != 0) { + return rc; + } + + return 0; +} + +static int veaa_x_3_channel_get(const struct device *dev, enum sensor_channel chan, + struct sensor_value *val) +{ + const struct veaa_x_3_cfg *cfg = dev->config; + struct veaa_x_3_data *data = dev->data; + const uint32_t max_adc_val = BIT(cfg->adc.resolution) - 1; + + if (chan != SENSOR_CHAN_PRESS) { + return -ENOTSUP; + } + + /* Convert from ADC value to kPa */ + if (u32_mul_overflow(data->adc_buf, veaa_x_3_kpa_range(cfg), &val->val1)) { + LOG_ERR("ADC to kPa overflow"); + return -ERANGE; + } + val->val2 = (val->val1 % max_adc_val) * 1000000 / max_adc_val; + val->val1 = (val->val1 / max_adc_val) + cfg->kpa_min; + + return 0; +} + +static const struct sensor_driver_api veaa_x_3_api_funcs = { + .attr_set = veaa_x_3_attr_set, + .attr_get = veaa_x_3_attr_get, + .sample_fetch = veaa_x_3_sample_fetch, + .channel_get = veaa_x_3_channel_get, +}; + +static int veaa_x_3_init(const struct device *dev) +{ + int rc; + const struct veaa_x_3_cfg *cfg = dev->config; + const struct dac_channel_cfg dac_cfg = { + .channel_id = cfg->dac_channel, + .resolution = cfg->dac_resolution, + .buffered = false, + }; + + LOG_DBG("Initializing %s with range %u-%u kPa", dev->name, cfg->kpa_min, cfg->kpa_max); + + if (!adc_is_ready_dt(&cfg->adc)) { + LOG_ERR("ADC not ready"); + return -ENODEV; + } + + rc = adc_channel_setup_dt(&cfg->adc); + if (rc != 0) { + LOG_ERR("%s setup failed: %d", cfg->adc.dev->name, rc); + return -ENODEV; + } + + if (!device_is_ready(cfg->dac)) { + LOG_ERR("DAC not ready"); + return -ENODEV; + } + + rc = dac_channel_setup(cfg->dac, &dac_cfg); + if (rc != 0) { + LOG_ERR("%s setup failed: %d", cfg->dac->name, rc); + return -ENODEV; + } + + return 0; +} + +#define VEAA_X_3_RANGE_KPA_INIT(n) \ + COND_CODE_1(DT_INST_ENUM_HAS_VALUE(n, pressure_range_type, d11), ({.max = 1000, min = 5}), \ + (COND_CODE_1(DT_INST_ENUM_HAS_VALUE(n, pressure_range_type, d9), \ + ({.max = 600, min = 3}), ({.max = 200, .min = 1})))) + +#define VEAA_X_3_TYPE_INIT(n) \ + COND_CODE_1(DT_INST_ENUM_HAS_VALUE(n, pressure_range_type, d11), \ + (.kpa_max = 1000, .kpa_min = 5), \ + (COND_CODE_1(DT_INST_ENUM_HAS_VALUE(n, pressure_range_type, d9), \ + (.kpa_max = 600, kpa_min = 3), (.kpa_max = 200, .kpa_min = 1)))) + +#define VEAA_X_3_INIT(n) \ + \ + static struct veaa_x_3_data veaa_x_3_data_##n; \ + \ + static const struct veaa_x_3_cfg veaa_x_3_cfg_##n = { \ + .adc = ADC_DT_SPEC_INST_GET(n), \ + .dac = DEVICE_DT_GET(DT_INST_PHANDLE(n, dac)), \ + .dac_channel = DT_INST_PROP(n, dac_channel_id), \ + .dac_resolution = DT_INST_PROP(n, dac_resolution), \ + VEAA_X_3_TYPE_INIT(n)}; \ + \ + SENSOR_DEVICE_DT_INST_DEFINE(n, veaa_x_3_init, NULL, &veaa_x_3_data_##n, \ + &veaa_x_3_cfg_##n, POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, \ + &veaa_x_3_api_funcs); + +DT_INST_FOREACH_STATUS_OKAY(VEAA_X_3_INIT) diff --git a/drivers/sensor/vishay/veml7700/veml7700.c b/drivers/sensor/vishay/veml7700/veml7700.c index 7aed13cbdca..94c9643b31e 100644 --- a/drivers/sensor/vishay/veml7700/veml7700.c +++ b/drivers/sensor/vishay/veml7700/veml7700.c @@ -30,11 +30,11 @@ LOG_MODULE_REGISTER(VEML7700, CONFIG_SENSOR_LOG_LEVEL); * 16-bit command register addresses */ #define VEML7700_CMDCODE_ALS_CONF 0x00 -#define VEML7700_CMDCODE_ALS_WH 0x01 -#define VEML7700_CMDCODE_ALS_WL 0x02 -#define VEML7700_CMDCODE_PSM 0x03 -#define VEML7700_CMDCODE_ALS 0x04 -#define VEML7700_CMDCODE_WHITE 0x05 +#define VEML7700_CMDCODE_ALS_WH 0x01 +#define VEML7700_CMDCODE_ALS_WL 0x02 +#define VEML7700_CMDCODE_PSM 0x03 +#define VEML7700_CMDCODE_ALS 0x04 +#define VEML7700_CMDCODE_WHITE 0x05 #define VEML7700_CMDCODE_ALS_INT 0x06 /* @@ -92,6 +92,16 @@ struct veml7700_data { uint32_t int_flags; }; +static bool is_veml7700_gain_in_range(int32_t gain_selection) +{ + return ((gain_selection >= 0U) && (gain_selection < VEML7700_ALS_GAIN_ELEM_COUNT)); +} + +static bool is_veml7700_it_in_range(int32_t it_selection) +{ + return ((it_selection >= 0U) && (it_selection < VEML7700_ALS_IT_ELEM_COUNT)); +} + /** * @brief Waits for a specific amount of time which depends * on the current integration time setting. @@ -135,39 +145,47 @@ static void veml7700_sleep_by_integration_time(const struct veml7700_data *data) } } -static uint32_t veml7700_counts_to_lux(const struct veml7700_data *data, - uint16_t counts) +static int veml7700_counts_to_lux(const struct veml7700_data *data, uint16_t counts, + uint32_t *lux) { - return counts * veml7700_resolution[data->gain][data->it]; + if (!is_veml7700_gain_in_range(data->gain) || !is_veml7700_it_in_range(data->it)) { + return -EINVAL; + } + *lux = counts * veml7700_resolution[data->gain][data->it]; + return 0; } -static uint16_t veml7700_lux_to_counts(const struct veml7700_data *data, - uint32_t lux) +static int veml7700_lux_to_counts(const struct veml7700_data *data, uint32_t lux, + uint16_t *counts) { - return lux / veml7700_resolution[data->gain][data->it]; + if (!is_veml7700_gain_in_range(data->gain) || !is_veml7700_it_in_range(data->it)) { + return -EINVAL; + } + *counts = lux / veml7700_resolution[data->gain][data->it]; + return 0; } static int veml7700_check_gain(const struct sensor_value *val) { - return val->val1 >= VEML7700_ALS_GAIN_1 - && val->val1 <= VEML7700_ALS_GAIN_1_4; + return val->val1 >= VEML7700_ALS_GAIN_1 && val->val1 <= VEML7700_ALS_GAIN_1_4; } static int veml7700_check_it(const struct sensor_value *val) { - return val->val1 >= VEML7700_ALS_IT_25 - && val->val1 <= VEML7700_ALS_IT_800; + return val->val1 >= VEML7700_ALS_IT_25 && val->val1 <= VEML7700_ALS_IT_800; } static int veml7700_check_int_mode(const struct sensor_value *val) { - return (val->val1 >= VEML7700_ALS_PERS_1 - && val->val1 <= VEML7700_ALS_PERS_8) - || val->val1 == VEML7700_INT_DISABLED; + return (val->val1 >= VEML7700_ALS_PERS_1 && val->val1 <= VEML7700_ALS_PERS_8) || + val->val1 == VEML7700_INT_DISABLED; } -static uint16_t veml7700_build_als_conf_param(const struct veml7700_data *data) +static int veml7700_build_als_conf_param(const struct veml7700_data *data, uint16_t *return_value) { + if (!is_veml7700_gain_in_range(data->gain) || !is_veml7700_it_in_range(data->it)) { + return -EINVAL; + } uint16_t param = 0; /* Bits 15:13 -> reserved */ /* Bits 12:11 -> gain selection (ALS_GAIN) */ @@ -186,7 +204,8 @@ static uint16_t veml7700_build_als_conf_param(const struct veml7700_data *data) if (data->shut_down) { param |= BIT(0); } - return param; + *return_value = param; + return 0; } static uint16_t veml7700_build_psm_param(const struct veml7700_config *conf) @@ -200,7 +219,7 @@ static int veml7700_write(const struct device *dev, uint8_t cmd, uint16_t data) const struct veml7700_config *conf = dev->config; uint8_t send_buf[3]; - send_buf[0] = cmd; /* byte 0: command code */ + send_buf[0] = cmd; /* byte 0: command code */ sys_put_le16(data, &send_buf[1]); /* bytes 1,2: command arguments */ return i2c_write_dt(&conf->bus, send_buf, ARRAY_SIZE(send_buf)); @@ -211,11 +230,7 @@ static int veml7700_read(const struct device *dev, uint8_t cmd, uint16_t *data) const struct veml7700_config *conf = dev->config; uint8_t recv_buf[2]; - int ret = i2c_write_read_dt(&conf->bus, - &cmd, - sizeof(cmd), - &recv_buf, - ARRAY_SIZE(recv_buf)); + int ret = i2c_write_read_dt(&conf->bus, &cmd, sizeof(cmd), &recv_buf, ARRAY_SIZE(recv_buf)); if (ret < 0) { return ret; } @@ -229,8 +244,12 @@ static int veml7700_write_als_conf(const struct device *dev) { const struct veml7700_data *data = dev->data; uint16_t param; + int ret = 0; - param = veml7700_build_als_conf_param(data); + ret = veml7700_build_als_conf_param(data, ¶m); + if (ret < 0) { + return ret; + } LOG_DBG("Writing ALS configuration: 0x%04x", param); return veml7700_write(dev, VEML7700_CMDCODE_ALS_CONF, param); } @@ -289,7 +308,11 @@ static int veml7700_fetch_als(const struct device *dev) } data->als_counts = counts; - data->als_lux = veml7700_counts_to_lux(data, counts); + ret = veml7700_counts_to_lux(data, counts, &data->als_lux); + if (ret < 0) { + return ret; + } + LOG_DBG("Read ALS measurement: counts=%d, lux=%d", data->als_counts, data->als_lux); return 0; @@ -329,22 +352,27 @@ static int veml7700_fetch_int_flags(const struct device *dev) return 0; } -static int veml7700_attr_set(const struct device *dev, - enum sensor_channel chan, - enum sensor_attribute attr, - const struct sensor_value *val) +static int veml7700_attr_set(const struct device *dev, enum sensor_channel chan, + enum sensor_attribute attr, const struct sensor_value *val) { if (chan != SENSOR_CHAN_LIGHT) { return -ENOTSUP; } struct veml7700_data *data = dev->data; + int ret = 0; if (attr == SENSOR_ATTR_LOWER_THRESH) { - data->thresh_low = veml7700_lux_to_counts(data, val->val1); + ret = veml7700_lux_to_counts(data, val->val1, &data->thresh_low); + if (ret < 0) { + return ret; + } return veml7700_write_thresh_low(dev); } else if (attr == SENSOR_ATTR_UPPER_THRESH) { - data->thresh_high = veml7700_lux_to_counts(data, val->val1); + ret = veml7700_lux_to_counts(data, val->val1, &data->thresh_high); + if (ret < 0) { + return ret; + } return veml7700_write_thresh_high(dev); } else if ((enum sensor_attribute_veml7700)attr == SENSOR_ATTR_VEML7700_GAIN) { if (veml7700_check_gain(val)) { @@ -372,10 +400,8 @@ static int veml7700_attr_set(const struct device *dev, } } -static int veml7700_attr_get(const struct device *dev, - enum sensor_channel chan, - enum sensor_attribute attr, - struct sensor_value *val) +static int veml7700_attr_get(const struct device *dev, enum sensor_channel chan, + enum sensor_attribute attr, struct sensor_value *val) { if (chan != SENSOR_CHAN_LIGHT) { return -ENOTSUP; @@ -422,16 +448,15 @@ static int veml7700_perform_single_measurement(const struct device *dev) return veml7700_set_shutdown_flag(dev, 1); } -static int veml7700_sample_fetch(const struct device *dev, - enum sensor_channel chan) +static int veml7700_sample_fetch(const struct device *dev, enum sensor_channel chan) { const struct veml7700_config *conf = dev->config; struct veml7700_data *data; int ret; /* Start sensor for new measurement if power saving mode is disabled */ - if ((chan == SENSOR_CHAN_LIGHT || chan == SENSOR_CHAN_ALL) - && conf->psm == VEML7700_PSM_DISABLED) { + if ((chan == SENSOR_CHAN_LIGHT || chan == SENSOR_CHAN_ALL) && + conf->psm == VEML7700_PSM_DISABLED) { ret = veml7700_perform_single_measurement(dev); if (ret < 0) { return ret; @@ -467,8 +492,7 @@ static int veml7700_sample_fetch(const struct device *dev, } } -static int veml7700_channel_get(const struct device *dev, - enum sensor_channel chan, +static int veml7700_channel_get(const struct device *dev, enum sensor_channel chan, struct sensor_value *val) { struct veml7700_data *data = dev->data; @@ -492,8 +516,7 @@ static int veml7700_channel_get(const struct device *dev, #ifdef CONFIG_PM_DEVICE -static int veml7700_pm_action(const struct device *dev, - enum pm_device_action action) +static int veml7700_pm_action(const struct device *dev, enum pm_device_action action) { const struct veml7700_config *conf = dev->config; @@ -562,30 +585,21 @@ static int veml7700_init(const struct device *dev) return 0; } -static const struct sensor_driver_api veml7700_api = { - .sample_fetch = veml7700_sample_fetch, - .channel_get = veml7700_channel_get, - .attr_set = veml7700_attr_set, - .attr_get = veml7700_attr_get -}; - -#define VEML7700_INIT(n) \ - static struct veml7700_data veml7700_data_##n; \ - \ - static const struct veml7700_config veml7700_config_##n = { \ - .bus = I2C_DT_SPEC_INST_GET(n), \ - .psm = DT_INST_PROP(n, psm_mode) \ - }; \ - \ - PM_DEVICE_DT_INST_DEFINE(n, veml7700_pm_action); \ - \ - SENSOR_DEVICE_DT_INST_DEFINE(n, \ - veml7700_init, \ - PM_DEVICE_DT_INST_GET(n), \ - &veml7700_data_##n, \ - &veml7700_config_##n, \ - POST_KERNEL, \ - CONFIG_SENSOR_INIT_PRIORITY, \ - &veml7700_api); +static const struct sensor_driver_api veml7700_api = {.sample_fetch = veml7700_sample_fetch, + .channel_get = veml7700_channel_get, + .attr_set = veml7700_attr_set, + .attr_get = veml7700_attr_get}; + +#define VEML7700_INIT(n) \ + static struct veml7700_data veml7700_data_##n; \ + \ + static const struct veml7700_config veml7700_config_##n = { \ + .bus = I2C_DT_SPEC_INST_GET(n), .psm = DT_INST_PROP(n, psm_mode)}; \ + \ + PM_DEVICE_DT_INST_DEFINE(n, veml7700_pm_action); \ + \ + SENSOR_DEVICE_DT_INST_DEFINE(n, veml7700_init, PM_DEVICE_DT_INST_GET(n), \ + &veml7700_data_##n, &veml7700_config_##n, POST_KERNEL, \ + CONFIG_SENSOR_INIT_PRIORITY, &veml7700_api); DT_INST_FOREACH_STATUS_OKAY(VEML7700_INIT) diff --git a/drivers/sensor/voltage_divider/Kconfig b/drivers/sensor/voltage_divider/Kconfig index 19027aa9361..b89510c2b72 100644 --- a/drivers/sensor/voltage_divider/Kconfig +++ b/drivers/sensor/voltage_divider/Kconfig @@ -8,6 +8,6 @@ config VOLTAGE_DIVIDER bool "Voltage sensor driver" default y depends on DT_HAS_VOLTAGE_DIVIDER_ENABLED - depends on ADC + select ADC help Enable voltage sensor driver. diff --git a/drivers/sensor/voltage_divider/voltage.c b/drivers/sensor/voltage_divider/voltage.c index ef2b34c74b3..f10a6596222 100644 --- a/drivers/sensor/voltage_divider/voltage.c +++ b/drivers/sensor/voltage_divider/voltage.c @@ -17,14 +17,12 @@ LOG_MODULE_REGISTER(voltage, CONFIG_SENSOR_LOG_LEVEL); struct voltage_config { struct voltage_divider_dt_spec voltage; -#ifdef CONFIG_PM_DEVICE struct gpio_dt_spec gpio_power; -#endif }; struct voltage_data { struct adc_sequence sequence; - int16_t raw; + uint16_t raw; }; static int fetch(const struct device *dev, enum sensor_channel chan) @@ -49,7 +47,7 @@ static int get(const struct device *dev, enum sensor_channel chan, struct sensor { const struct voltage_config *config = dev->config; struct voltage_data *data = dev->data; - int32_t raw_val = data->raw; + int32_t raw_val; int32_t v_mv; int ret; @@ -59,6 +57,15 @@ static int get(const struct device *dev, enum sensor_channel chan, struct sensor return -ENOTSUP; } + if (config->voltage.port.channel_cfg.differential) { + raw_val = (int16_t)data->raw; + } else if (config->voltage.port.resolution < 16) { + /* Can be removed when issue #71119 is resolved */ + raw_val = (int16_t)data->raw; + } else { + raw_val = data->raw; + } + ret = adc_raw_to_millivolts_dt(&config->voltage.port, &raw_val); if (ret != 0) { LOG_ERR("raw_to_mv: %d", ret); @@ -90,8 +97,8 @@ static int pm_action(const struct device *dev, enum pm_device_action action) int ret; if (config->gpio_power.port == NULL) { - LOG_ERR("PM not supported"); - return -ENOTSUP; + /* No work to do */ + return 0; } switch (action) { @@ -126,7 +133,6 @@ static int voltage_init(const struct device *dev) return -ENODEV; } -#ifdef CONFIG_PM_DEVICE if (config->gpio_power.port != NULL) { if (!gpio_is_ready_dt(&config->gpio_power)) { LOG_ERR("Power GPIO is not ready"); @@ -138,7 +144,6 @@ static int voltage_init(const struct device *dev) LOG_ERR("failed to initialize GPIO for reset"); } } -#endif ret = adc_channel_setup_dt(&config->voltage.port); if (ret != 0) { @@ -158,18 +163,12 @@ static int voltage_init(const struct device *dev) return 0; } -#ifdef CONFIG_PM_DEVICE -#define POWER_GPIOS(inst) .gpio_power = GPIO_DT_SPEC_INST_GET_OR(inst, power_gpios, {0}), -#else -#define POWER_GPIOS(inst) -#endif - #define VOLTAGE_INIT(inst) \ static struct voltage_data voltage_##inst##_data; \ \ static const struct voltage_config voltage_##inst##_config = { \ .voltage = VOLTAGE_DIVIDER_DT_SPEC_GET(DT_DRV_INST(inst)), \ - POWER_GPIOS(inst) \ + .gpio_power = GPIO_DT_SPEC_INST_GET_OR(inst, power_gpios, {0}), \ }; \ \ PM_DEVICE_DT_INST_DEFINE(inst, pm_action); \ diff --git a/drivers/serial/Kconfig.bt b/drivers/serial/Kconfig.bt index 500613d6208..214109759ae 100644 --- a/drivers/serial/Kconfig.bt +++ b/drivers/serial/Kconfig.bt @@ -11,3 +11,19 @@ config UART_BT help Enable the UART over NUS Bluetooth driver, which can be used to pipe serial data over Bluetooth LE GATT using NUS (Nordic UART Service). + +if UART_BT + +config UART_BT_WORKQUEUE_PRIORITY + int "UART NUS Work-queue Priority" + default MAIN_THREAD_PRIORITY + help + Select UART NUS Work-queue priority based on the application context. + +config UART_BT_WORKQUEUE_STACK_SIZE + int "UART NUS Work-queue Stack Size" + default 1024 + help + Set UART NUS Work-queue Stack-size based on the application context. + +endif diff --git a/drivers/serial/Kconfig.npcx b/drivers/serial/Kconfig.npcx index 07a4b02a084..6284ed3a372 100644 --- a/drivers/serial/Kconfig.npcx +++ b/drivers/serial/Kconfig.npcx @@ -3,6 +3,8 @@ # Copyright (c) 2020 Nuvoton Technology Corporation. # SPDX-License-Identifier: Apache-2.0 +DT_UART_NPCX:=$(dt_nodelabel_path,uart1) + config UART_NPCX bool "Nuvoton NPCX embedded controller (EC) serial driver" default y @@ -13,3 +15,12 @@ config UART_NPCX This option enables the UART driver for NPCX family of processors. Say y if you wish to use serial port on NPCX MCU. + +# Expose this option when the reg porperty has two register base address. +# i.e. One UART register bass address and one MDMA register base address. +config UART_NPCX_USE_MDMA + bool "Nuvoton NPCX embedded controller (EC) serial driver DMA support" + depends on UART_NPCX && "$(dt_node_reg_addr_hex,$(DT_UART_NPCX),1)" != 0 + select SERIAL_SUPPORT_ASYNC + help + Enable support for npcx UART DMA mode. diff --git a/drivers/serial/Kconfig.nrfx_uart_instance b/drivers/serial/Kconfig.nrfx_uart_instance index b8a62084ce5..71b25dbeba0 100644 --- a/drivers/serial/Kconfig.nrfx_uart_instance +++ b/drivers/serial/Kconfig.nrfx_uart_instance @@ -76,6 +76,13 @@ 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)_HAS_RX_CACHE_SECTION + def_bool $(dt_nodelabel_has_prop,uart$(nrfx_uart_num),memory-regions) + imply NRFX_UARTE_CONFIG_RX_CACHE_ENABLED + help + This helper symbol indicates the existence of a linker section which + can be dedicated to an RX cache buffer. + config UART_$(nrfx_uart_num)_TX_CACHE_SIZE int "TX cache buffer size" depends on !UART_NRFX_UARTE_LEGACY_SHIM @@ -87,7 +94,7 @@ config UART_$(nrfx_uart_num)_TX_CACHE_SIZE 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,shared_ram3x_region,$(DT_COMPAT_NORDIC_OWNED_MEMORY)) + default 32 if UART_$(nrfx_uart_num)_HAS_RX_CACHE_SECTION default 5 range 5 255 help diff --git a/drivers/serial/Kconfig.smartbond b/drivers/serial/Kconfig.smartbond index 5572b5ba187..2ea73a37fa1 100644 --- a/drivers/serial/Kconfig.smartbond +++ b/drivers/serial/Kconfig.smartbond @@ -7,5 +7,6 @@ config UART_SMARTBOND depends on DT_HAS_RENESAS_SMARTBOND_UART_ENABLED select SERIAL_HAS_DRIVER select SERIAL_SUPPORT_INTERRUPT + select UART_INTERRUPT_DRIVEN if PM_DEVICE help Enable UART driver for Renesas SmartBond(tm) DA1469x series MCU. diff --git a/drivers/serial/uart_bt.c b/drivers/serial/uart_bt.c index ad450eea9aa..9e4a4de5930 100644 --- a/drivers/serial/uart_bt.c +++ b/drivers/serial/uart_bt.c @@ -4,6 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include #include #include #include @@ -14,6 +15,9 @@ #include LOG_MODULE_REGISTER(uart_nus, CONFIG_UART_LOG_LEVEL); +K_THREAD_STACK_DEFINE(nus_work_queue_stack, CONFIG_UART_BT_WORKQUEUE_STACK_SIZE); +static struct k_work_q nus_work_queue; + struct uart_bt_data { struct { struct bt_nus_inst *inst; @@ -47,7 +51,7 @@ static void bt_notif_enabled(bool enabled, void *ctx) LOG_DBG("%s() - %s", __func__, enabled ? "enabled" : "disabled"); if (!ring_buf_is_empty(dev_data->uart.tx_ringbuf)) { - k_work_reschedule(&dev_data->uart.tx_work, K_NO_WAIT); + k_work_reschedule_for_queue(&nus_work_queue, &dev_data->uart.tx_work, K_NO_WAIT); } } @@ -71,7 +75,7 @@ static void bt_received(struct bt_conn *conn, const void *data, uint16_t len, vo LOG_ERR("RX Ring buffer full. received: %d, added to queue: %d", len, put_len); } - k_work_submit(&dev_data->uart.cb_work); + k_work_submit_to_queue(&nus_work_queue, &dev_data->uart.cb_work); } static void cb_work_handler(struct k_work *work) @@ -113,7 +117,7 @@ static void tx_work_handler(struct k_work *work) } while (len > 0 && !err); if ((ring_buf_space_get(dev_data->uart.tx_ringbuf) > 0) && dev_data->uart.tx_irq_ena) { - k_work_submit(&dev_data->uart.cb_work); + k_work_submit_to_queue(&nus_work_queue, &dev_data->uart.cb_work); } } @@ -128,7 +132,7 @@ static int uart_bt_fifo_fill(const struct device *dev, const uint8_t *tx_data, i } if (atomic_get(&dev_data->bt.enabled)) { - k_work_reschedule(&dev_data->uart.tx_work, K_NO_WAIT); + k_work_reschedule_for_queue(&nus_work_queue, &dev_data->uart.tx_work, K_NO_WAIT); } return wrote; @@ -169,7 +173,7 @@ static void uart_bt_poll_out(const struct device *dev, unsigned char c) * data, so more than one byte is transmitted (e.g: when poll_out is * called inside a for-loop). */ - k_work_schedule(&dev_data->uart.tx_work, K_MSEC(1)); + k_work_schedule_for_queue(&nus_work_queue, &dev_data->uart.tx_work, K_MSEC(1)); } } @@ -191,7 +195,7 @@ static void uart_bt_irq_tx_enable(const struct device *dev) dev_data->uart.tx_irq_ena = true; if (uart_bt_irq_tx_ready(dev)) { - k_work_submit(&dev_data->uart.cb_work); + k_work_submit_to_queue(&nus_work_queue, &dev_data->uart.cb_work); } } @@ -219,7 +223,7 @@ static void uart_bt_irq_rx_enable(const struct device *dev) dev_data->uart.rx_irq_ena = true; - k_work_submit(&dev_data->uart.cb_work); + k_work_submit_to_queue(&nus_work_queue, &dev_data->uart.cb_work); } static void uart_bt_irq_rx_disable(const struct device *dev) @@ -267,6 +271,19 @@ static const struct uart_driver_api uart_bt_driver_api = { .irq_callback_set = uart_bt_irq_callback_set, }; +static int uart_bt_workqueue_init(void) +{ + k_work_queue_init(&nus_work_queue); + k_work_queue_start(&nus_work_queue, nus_work_queue_stack, + K_THREAD_STACK_SIZEOF(nus_work_queue_stack), + CONFIG_UART_BT_WORKQUEUE_PRIORITY, NULL); + + return 0; +} + +/** The work-queue is shared across all instances, hence we initialize it separatedly */ +SYS_INIT(uart_bt_workqueue_init, POST_KERNEL, CONFIG_SERIAL_INIT_PRIORITY); + static int uart_bt_init(const struct device *dev) { int err; diff --git a/drivers/serial/uart_esp32.c b/drivers/serial/uart_esp32.c index cb07de20adc..48f213c7394 100644 --- a/drivers/serial/uart_esp32.c +++ b/drivers/serial/uart_esp32.c @@ -67,6 +67,8 @@ struct uart_esp32_config { const clock_control_subsys_t clock_subsys; int irq_source; int irq_priority; + bool tx_invert; + bool rx_invert; #if CONFIG_UART_ASYNC_API const struct device *dma_dev; uint8_t tx_dma_channel; @@ -328,6 +330,13 @@ static int uart_esp32_configure(const struct device *dev, const struct uart_conf uart_hal_set_rx_timeout(&data->hal, 0x16); + if (config->tx_invert) { + uart_hal_inverse_signal(&data->hal, UART_SIGNAL_TXD_INV); + } + + if (config->rx_invert) { + uart_hal_inverse_signal(&data->hal, UART_SIGNAL_RXD_INV); + } return 0; } @@ -1004,6 +1013,8 @@ static const DRAM_ATTR struct uart_driver_api uart_esp32_api = { .clock_subsys = (clock_control_subsys_t)DT_INST_CLOCKS_CELL(idx, offset), \ .irq_source = DT_INST_IRQN(idx), \ .irq_priority = UART_IRQ_PRIORITY, \ + .tx_invert = DT_INST_PROP_OR(idx, tx_invert, false), \ + .rx_invert = DT_INST_PROP_OR(idx, rx_invert, false), \ ESP_UART_DMA_INIT(idx)}; \ \ static struct uart_esp32_data uart_esp32_data_##idx = { \ diff --git a/drivers/serial/uart_mcux_flexcomm.c b/drivers/serial/uart_mcux_flexcomm.c index f180c18c952..8a95edbe3bb 100644 --- a/drivers/serial/uart_mcux_flexcomm.c +++ b/drivers/serial/uart_mcux_flexcomm.c @@ -1144,7 +1144,7 @@ DT_INST_FOREACH_STATUS_OKAY(UART_MCUX_FLEXCOMM_RX_TIMEOUT_FUNC); .source_data_size = 1, \ .dest_data_size = 1, \ .complete_callback_en = 1, \ - .error_callback_en = 1, \ + .error_callback_dis = 1, \ .block_count = 1, \ .head_block = \ &mcux_flexcomm_##n##_data.tx_data.active_block, \ @@ -1165,7 +1165,7 @@ DT_INST_FOREACH_STATUS_OKAY(UART_MCUX_FLEXCOMM_RX_TIMEOUT_FUNC); .source_data_size = 1, \ .dest_data_size = 1, \ .complete_callback_en = 1, \ - .error_callback_en = 1, \ + .error_callback_dis = 1, \ .block_count = 1, \ .head_block = \ &mcux_flexcomm_##n##_data.rx_data.active_block, \ diff --git a/drivers/serial/uart_mcux_lpuart.c b/drivers/serial/uart_mcux_lpuart.c index 0ac8bff42f6..359944f477f 100644 --- a/drivers/serial/uart_mcux_lpuart.c +++ b/drivers/serial/uart_mcux_lpuart.c @@ -29,6 +29,14 @@ LOG_MODULE_REGISTER(uart_mcux_lpuart, LOG_LEVEL_ERR); #define PINCTRL_STATE_FLOWCONTROL PINCTRL_STATE_PRIV_START +#if defined(CONFIG_UART_ASYNC_API) && defined(CONFIG_UART_INTERRUPT_DRIVEN) +/* there are already going to be build errors, but at least this message will + * be the first error from this driver making the reason clear + */ +BUILD_ASSERT(IS_ENABLED(CONFIG_UART_EXCLUSIVE_API_CALLBACKS), "" + "LPUART must use exclusive api callbacks"); +#endif + #ifdef CONFIG_UART_ASYNC_API struct lpuart_dma_config { const struct device *dma_dev; @@ -50,6 +58,9 @@ struct mcux_lpuart_config { uint8_t parity; bool rs485_de_active_low; bool loopback_en; + bool single_wire; + bool tx_invert; + bool rx_invert; #ifdef CONFIG_UART_MCUX_LPUART_ISR_SUPPORT void (*irq_config_func)(const struct device *dev); #endif @@ -89,6 +100,14 @@ struct mcux_lpuart_async_data { }; #endif +#if defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS) +enum mcux_lpuart_api { + LPUART_NONE, + LPUART_IRQ_DRIVEN, + LPUART_ASYNC +}; +#endif + struct mcux_lpuart_data { #ifdef CONFIG_UART_INTERRUPT_DRIVEN uart_irq_callback_user_data_t callback; @@ -103,6 +122,9 @@ struct mcux_lpuart_data { struct mcux_lpuart_async_data async; #endif struct uart_config uart_config; +#if defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS) + enum mcux_lpuart_api api_type; +#endif }; #ifdef CONFIG_PM @@ -310,7 +332,6 @@ static void mcux_lpuart_irq_rx_enable(const struct device *dev) uint32_t mask = kLPUART_RxDataRegFullInterruptEnable; LPUART_EnableInterrupts(config->base, mask); - LPUART_EnableRx(config->base, true); } static void mcux_lpuart_irq_rx_disable(const struct device *dev) @@ -318,7 +339,6 @@ static void mcux_lpuart_irq_rx_disable(const struct device *dev) const struct mcux_lpuart_config *config = dev->config; uint32_t mask = kLPUART_RxDataRegFullInterruptEnable; - LPUART_EnableRx(config->base, false); LPUART_DisableInterrupts(config->base, mask); } @@ -376,12 +396,19 @@ static void mcux_lpuart_irq_callback_set(const struct device *dev, { struct mcux_lpuart_data *data = dev->data; +#if defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS) + if (data->api_type == LPUART_ASYNC) { + LOG_ERR("UART irq and async api are exclusive"); + } +#endif + data->callback = cb; data->cb_data = cb_data; #if defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS) data->async.user_callback = NULL; data->async.user_data = NULL; + data->api_type = LPUART_IRQ_DRIVEN; #endif } @@ -666,20 +693,30 @@ static void dma_callback(const struct device *dma_dev, void *callback_arg, uint3 } } +static int mcux_lpuart_configure_async(const struct device *dev); + static int mcux_lpuart_callback_set(const struct device *dev, uart_callback_t callback, void *user_data) { struct mcux_lpuart_data *data = dev->data; +#if defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS) + if (data->api_type == LPUART_IRQ_DRIVEN) { + LOG_ERR("UART irq and async api are exclusive"); + return -ENOTSUP; + } +#endif + data->async.user_callback = callback; data->async.user_data = user_data; #if defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS) data->callback = NULL; data->cb_data = NULL; + data->api_type = LPUART_ASYNC; #endif - return 0; + return mcux_lpuart_configure_async(dev); } static int mcux_lpuart_tx(const struct device *dev, const uint8_t *buf, size_t len, @@ -859,26 +896,12 @@ static void mcux_lpuart_async_tx_timeout(struct k_work *work) #endif /* CONFIG_UART_ASYNC_API */ #if CONFIG_UART_MCUX_LPUART_ISR_SUPPORT -static void mcux_lpuart_isr(const struct device *dev) -{ - struct mcux_lpuart_data *data = dev->data; - const struct mcux_lpuart_config *config = dev->config; - const uint32_t status = LPUART_GetStatusFlags(config->base); - -#if CONFIG_PM - if (status & kLPUART_TransmissionCompleteFlag) { - - if (data->tx_poll_stream_on) { - /* Poll transmission complete. Allow system to sleep */ - LPUART_DisableInterrupts(config->base, - kLPUART_TransmissionCompleteInterruptEnable); - data->tx_poll_stream_on = false; - mcux_lpuart_pm_policy_state_lock_put(dev); - } - } -#endif /* CONFIG_PM */ -#if CONFIG_UART_INTERRUPT_DRIVEN +#ifdef CONFIG_UART_INTERRUPT_DRIVEN +static inline void mcux_lpuart_irq_driven_isr(const struct device *dev, + struct mcux_lpuart_data *data, + const struct mcux_lpuart_config *config, + const uint32_t status) { if (data->callback) { data->callback(dev, data->cb_data); } @@ -886,46 +909,67 @@ static void mcux_lpuart_isr(const struct device *dev) if (status & kLPUART_RxOverrunFlag) { LPUART_ClearStatusFlags(config->base, kLPUART_RxOverrunFlag); } +} #endif -#if CONFIG_UART_ASYNC_API +#ifdef CONFIG_UART_ASYNC_API +static inline void mcux_lpuart_async_isr(struct mcux_lpuart_data *data, + const struct mcux_lpuart_config *config, + const uint32_t status) { if (status & kLPUART_IdleLineFlag) { async_timer_start(&data->async.rx_dma_params.timeout_work, data->async.rx_dma_params.timeout_us); LPUART_ClearStatusFlags(config->base, kLPUART_IdleLineFlag); } -#endif /* CONFIG_UART_ASYNC_API */ } -#endif /* CONFIG_UART_MCUX_LPUART_ISR_SUPPORT */ +#endif -static int mcux_lpuart_configure_init(const struct device *dev, const struct uart_config *cfg) +static void mcux_lpuart_isr(const struct device *dev) { - const struct mcux_lpuart_config *config = dev->config; struct mcux_lpuart_data *data = dev->data; - uint32_t clock_freq; + const struct mcux_lpuart_config *config = dev->config; + const uint32_t status = LPUART_GetStatusFlags(config->base); - if (!device_is_ready(config->clock_dev)) { - return -ENODEV; - } +#if CONFIG_PM + if (status & kLPUART_TransmissionCompleteFlag) { - if (clock_control_get_rate(config->clock_dev, config->clock_subsys, - &clock_freq)) { - return -EINVAL; + if (data->tx_poll_stream_on) { + /* Poll transmission complete. Allow system to sleep */ + LPUART_DisableInterrupts(config->base, + kLPUART_TransmissionCompleteInterruptEnable); + data->tx_poll_stream_on = false; + mcux_lpuart_pm_policy_state_lock_put(dev); + } } +#endif /* CONFIG_PM */ - lpuart_config_t uart_config; - LPUART_GetDefaultConfig(&uart_config); +#if defined(CONFIG_UART_ASYNC_API) && defined(CONFIG_UART_INTERRUPT_DRIVEN) + if (data->api_type == LPUART_IRQ_DRIVEN) { + mcux_lpuart_irq_driven_isr(dev, data, config, status); + } else if (data->api_type == LPUART_ASYNC) { + mcux_lpuart_async_isr(data, config, status); + } +#elif defined(CONFIG_UART_INTERRUPT_DRIVEN) + mcux_lpuart_irq_driven_isr(dev, data, config, status); +#elif defined(CONFIG_UART_ASYNC_API) + mcux_lpuart_async_isr(data, config, status); +#endif /* API */ +} +#endif /* CONFIG_UART_MCUX_LPUART_ISR_SUPPORT */ +static int mcux_lpuart_configure_basic(const struct device *dev, const struct uart_config *cfg, + lpuart_config_t *uart_config) +{ /* Translate UART API enum to LPUART enum from HAL */ switch (cfg->parity) { case UART_CFG_PARITY_NONE: - uart_config.parityMode = kLPUART_ParityDisabled; + uart_config->parityMode = kLPUART_ParityDisabled; break; case UART_CFG_PARITY_ODD: - uart_config.parityMode = kLPUART_ParityOdd; + uart_config->parityMode = kLPUART_ParityOdd; break; case UART_CFG_PARITY_EVEN: - uart_config.parityMode = kLPUART_ParityEven; + uart_config->parityMode = kLPUART_ParityEven; break; default: return -ENOTSUP; @@ -935,11 +979,11 @@ static int mcux_lpuart_configure_init(const struct device *dev, const struct uar #if defined(FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT) && \ FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT case UART_CFG_DATA_BITS_7: - uart_config.dataBitsCount = kLPUART_SevenDataBits; + uart_config->dataBitsCount = kLPUART_SevenDataBits; break; #endif case UART_CFG_DATA_BITS_8: - uart_config.dataBitsCount = kLPUART_EightDataBits; + uart_config->dataBitsCount = kLPUART_EightDataBits; break; default: return -ENOTSUP; @@ -949,10 +993,10 @@ static int mcux_lpuart_configure_init(const struct device *dev, const struct uar FSL_FEATURE_LPUART_HAS_STOP_BIT_CONFIG_SUPPORT switch (cfg->stop_bits) { case UART_CFG_STOP_BITS_1: - uart_config.stopBitCount = kLPUART_OneStopBit; + uart_config->stopBitCount = kLPUART_OneStopBit; break; case UART_CFG_STOP_BITS_2: - uart_config.stopBitCount = kLPUART_TwoStopBit; + uart_config->stopBitCount = kLPUART_TwoStopBit; break; default: return -ENOTSUP; @@ -964,25 +1008,41 @@ static int mcux_lpuart_configure_init(const struct device *dev, const struct uar switch (cfg->flow_ctrl) { case UART_CFG_FLOW_CTRL_NONE: case UART_CFG_FLOW_CTRL_RS485: - uart_config.enableTxCTS = false; - uart_config.enableRxRTS = false; + uart_config->enableTxCTS = false; + uart_config->enableRxRTS = false; break; case UART_CFG_FLOW_CTRL_RTS_CTS: - uart_config.enableTxCTS = true; - uart_config.enableRxRTS = true; + uart_config->enableTxCTS = true; + uart_config->enableRxRTS = true; break; default: return -ENOTSUP; } #endif - uart_config.baudRate_Bps = cfg->baudrate; - uart_config.enableRx = true; + uart_config->baudRate_Bps = cfg->baudrate; + uart_config->enableRx = true; /* Tx will be enabled manually after set tx-rts */ - uart_config.enableTx = false; + uart_config->enableTx = false; + return 0; +} #ifdef CONFIG_UART_ASYNC_API +static int mcux_lpuart_configure_async(const struct device *dev) +{ + const struct mcux_lpuart_config *config = dev->config; + struct mcux_lpuart_data *data = dev->data; + lpuart_config_t uart_config; + int ret; + + LPUART_GetDefaultConfig(&uart_config); + + ret = mcux_lpuart_configure_basic(dev, &data->uart_config, &uart_config); + if (ret) { + return ret; + } + uart_config.rxIdleType = kLPUART_IdleTypeStopBit; uart_config.rxIdleConfig = kLPUART_IdleCharacter1; data->async.next_rx_buffer = NULL; @@ -997,8 +1057,38 @@ static int mcux_lpuart_configure_init(const struct device *dev, const struct uar * to receive into with rx_enable */ uart_config.enableRx = false; + /* Clearing the fifo of any junk received before the async rx enable was called */ + while (LPUART_GetRxFifoCount(config->base) > 0) { + LPUART_ReadByte(config->base); + } -#endif /* CONFIG_UART_ASYNC_API */ + return 0; +} +#endif + +static int mcux_lpuart_configure_init(const struct device *dev, const struct uart_config *cfg) +{ + const struct mcux_lpuart_config *config = dev->config; + struct mcux_lpuart_data *data = dev->data; + lpuart_config_t uart_config; + uint32_t clock_freq; + int ret; + + if (!device_is_ready(config->clock_dev)) { + return -ENODEV; + } + + if (clock_control_get_rate(config->clock_dev, config->clock_subsys, + &clock_freq)) { + return -EINVAL; + } + + LPUART_GetDefaultConfig(&uart_config); + + ret = mcux_lpuart_configure_basic(dev, cfg, &uart_config); + if (ret) { + return ret; + } LPUART_Init(config->base, &uart_config, clock_freq); @@ -1017,8 +1107,30 @@ static int mcux_lpuart_configure_init(const struct device *dev, const struct uar /* Set the LPUART into loopback mode */ config->base->CTRL |= LPUART_CTRL_LOOPS_MASK; config->base->CTRL &= ~LPUART_CTRL_RSRC_MASK; + } else if (config->single_wire) { + /* Enable the single wire / half-duplex mode, only possible when + * loopback is disabled. We need a critical section to prevent + * the UART firing an interrupt during mode switch + */ + unsigned int key = irq_lock(); + + config->base->CTRL |= (LPUART_CTRL_LOOPS_MASK | LPUART_CTRL_RSRC_MASK); + irq_unlock(key); + } else { +#ifdef LPUART_CTRL_TXINV + /* Only invert TX in full-duplex mode */ + if (config->tx_invert) { + config->base->CTRL |= LPUART_CTRL_TXINV(1); + } +#endif } +#ifdef LPUART_STAT_RXINV + if (config->rx_invert) { + config->base->STAT |= LPUART_STAT_RXINV(1); + } +#endif + /* update internal uart_config */ data->uart_config = *cfg; @@ -1038,6 +1150,9 @@ static int mcux_lpuart_configure(const struct device *dev, { const struct mcux_lpuart_config *config = dev->config; + /* Make sure that RSRC is de-asserted otherwise deinit will hang. */ + config->base->CTRL &= ~LPUART_CTRL_RSRC_MASK; + /* disable LPUART */ LPUART_Deinit(config->base); @@ -1093,6 +1208,9 @@ static int mcux_lpuart_init(const struct device *dev) /* Interrupt is managed by this driver */ config->irq_config_func(dev); #endif +#ifdef CONFIG_UART_EXCLUSIVE_API_CALLBACKS + data->api_type = LPUART_NONE; +#endif #endif #ifdef CONFIG_PM @@ -1176,7 +1294,7 @@ static const struct uart_driver_api mcux_lpuart_driver_api = { .source_data_size = 1, \ .dest_data_size = 1, \ .complete_callback_en = 1, \ - .error_callback_en = 1, \ + .error_callback_dis = 0, \ .block_count = 1, \ .head_block = \ &mcux_lpuart_##id##_data.async.tx_dma_params.active_dma_block, \ @@ -1199,7 +1317,7 @@ static const struct uart_driver_api mcux_lpuart_driver_api = { .source_data_size = 1, \ .dest_data_size = 1, \ .complete_callback_en = 1, \ - .error_callback_en = 1, \ + .error_callback_dis = 0, \ .block_count = 1, \ .head_block = \ &mcux_lpuart_##id##_data.async.rx_dma_params.active_dma_block, \ @@ -1239,6 +1357,9 @@ static const struct mcux_lpuart_config mcux_lpuart_##n##_config = { \ .parity = DT_INST_ENUM_IDX_OR(n, parity, UART_CFG_PARITY_NONE), \ .rs485_de_active_low = DT_INST_PROP(n, nxp_rs485_de_active_low), \ .loopback_en = DT_INST_PROP(n, nxp_loopback), \ + .single_wire = DT_INST_PROP(n, single_wire), \ + .rx_invert = DT_INST_PROP(n, rx_invert), \ + .tx_invert = DT_INST_PROP(n, tx_invert), \ .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ MCUX_LPUART_IRQ_INIT(n) \ RX_DMA_CONFIG(n) \ diff --git a/drivers/serial/uart_native_tty.c b/drivers/serial/uart_native_tty.c index 8eb51bff5b8..4f2acc50b34 100644 --- a/drivers/serial/uart_native_tty.c +++ b/drivers/serial/uart_native_tty.c @@ -90,7 +90,7 @@ static int native_tty_conv_to_bottom_cfg(struct native_tty_bottom_cfg *bottom_cf return -ENOTSUP; } - switch (cfg->data_bits) { + switch (cfg->stop_bits) { case UART_CFG_STOP_BITS_1: bottom_cfg->stop_bits = NTB_STOP_BITS_1; break; diff --git a/drivers/serial/uart_native_tty_bottom.c b/drivers/serial/uart_native_tty_bottom.c index cb8e4162a66..279ebca4100 100644 --- a/drivers/serial/uart_native_tty_bottom.c +++ b/drivers/serial/uart_native_tty_bottom.c @@ -144,7 +144,7 @@ static inline void native_tty_stop_bits_set(struct termios *ter, * @brief Set the number of data bits in the termios structure * * @param ter - * @param stop_bits + * @param data_bits * */ static inline void native_tty_data_bits_set(struct termios *ter, diff --git a/drivers/serial/uart_npcx.c b/drivers/serial/uart_npcx.c index 979cbd038b3..085f7cccd3d 100644 --- a/drivers/serial/uart_npcx.c +++ b/drivers/serial/uart_npcx.c @@ -25,7 +25,7 @@ LOG_MODULE_REGISTER(uart_npcx, CONFIG_UART_LOG_LEVEL); /* Driver config */ struct uart_npcx_config { struct uart_reg *inst; -#ifdef CONFIG_UART_INTERRUPT_DRIVEN +#if defined(CONFIG_UART_INTERRUPT_DRIVEN) || defined(CONFIG_UART_ASYNC_API) uart_irq_config_func_t irq_config_func; #endif /* clock configuration */ @@ -34,6 +34,10 @@ struct uart_npcx_config { const struct npcx_wui uart_rx_wui; /* pinmux configuration */ const struct pinctrl_dev_config *pcfg; +#ifdef CONFIG_UART_ASYNC_API + struct npcx_clk_cfg mdma_clk_cfg; + struct mdma_reg *mdma_reg_base; +#endif }; enum uart_pm_policy_state_flag { @@ -43,6 +47,36 @@ enum uart_pm_policy_state_flag { UART_PM_POLICY_STATE_FLAG_COUNT, }; +#ifdef CONFIG_UART_ASYNC_API +struct uart_npcx_rx_dma_params { + uint8_t *buf; + size_t buf_len; + size_t offset; + size_t counter; + size_t timeout_us; + struct k_work_delayable timeout_work; + bool enabled; +}; + +struct uart_npcx_tx_dma_params { + const uint8_t *buf; + size_t buf_len; + struct k_work_delayable timeout_work; + size_t timeout_us; +}; + +struct uart_npcx_async_data { + const struct device *uart_dev; + uart_callback_t user_callback; + void *user_data; + struct uart_npcx_rx_dma_params rx_dma_params; + struct uart_npcx_tx_dma_params tx_dma_params; + uint8_t *next_rx_buffer; + size_t next_rx_buffer_len; + bool tx_in_progress; +}; +#endif + /* Driver data */ struct uart_npcx_data { /* Baud rate */ @@ -59,6 +93,9 @@ struct uart_npcx_data { struct k_work_delayable rx_refresh_timeout_work; #endif #endif +#ifdef CONFIG_UART_ASYNC_API + struct uart_npcx_async_data async; +#endif }; #ifdef CONFIG_PM @@ -71,7 +108,7 @@ static void uart_npcx_pm_policy_state_lock_get(struct uart_npcx_data *data, } static void uart_npcx_pm_policy_state_lock_put(struct uart_npcx_data *data, - enum uart_pm_policy_state_flag flag) + enum uart_pm_policy_state_flag flag) { if (atomic_test_and_clear_bit(data->pm_policy_state_flag, flag) == 1) { pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); @@ -82,14 +119,37 @@ static void uart_npcx_pm_policy_state_lock_put(struct uart_npcx_data *data, /* UART local functions */ static int uart_set_npcx_baud_rate(struct uart_reg *const inst, int baud_rate, int src_clk) { - /* Fix baud rate to 115200 so far */ + /* + * Support two baud rate setting so far: + * - 115200 + * - 3000000 + */ if (baud_rate == 115200) { - if (src_clk == 15000000) { + if (src_clk == MHZ(15)) { inst->UPSR = 0x38; inst->UBAUD = 0x01; - } else if (src_clk == 20000000) { + } else if (src_clk == MHZ(20)) { inst->UPSR = 0x08; inst->UBAUD = 0x0a; + } else if (src_clk == MHZ(25)) { + inst->UPSR = 0x10; + inst->UBAUD = 0x08; + } else if (src_clk == MHZ(30)) { + inst->UPSR = 0x10; + inst->UBAUD = 0x0a; + } else if (src_clk == MHZ(48)) { + inst->UPSR = 0x08; + inst->UBAUD = 0x19; + } else if (src_clk == MHZ(50)) { + inst->UPSR = 0x08; + inst->UBAUD = 0x1a; + } else { + return -EINVAL; + } + } else if (baud_rate == MHZ(3)) { + if (src_clk == MHZ(48)) { + inst->UPSR = 0x08; + inst->UBAUD = 0x0; } else { return -EINVAL; } @@ -100,16 +160,7 @@ static int uart_set_npcx_baud_rate(struct uart_reg *const inst, int baud_rate, i return 0; } -#ifdef CONFIG_UART_INTERRUPT_DRIVEN -static int uart_npcx_tx_fifo_ready(const struct device *dev) -{ - const struct uart_npcx_config *const config = dev->config; - struct uart_reg *const inst = config->inst; - - /* True if the Tx FIFO is not completely full */ - return !(GET_FIELD(inst->UFTSTS, NPCX_UFTSTS_TEMPTY_LVL) == 0); -} - +#if defined(CONFIG_UART_INTERRUPT_DRIVEN) || defined(CONFIG_UART_ASYNC_API) static int uart_npcx_rx_fifo_available(const struct device *dev) { const struct uart_npcx_config *const config = dev->config; @@ -125,8 +176,7 @@ static void uart_npcx_dis_all_tx_interrupts(const struct device *dev) struct uart_reg *const inst = config->inst; /* Disable all Tx interrupts */ - inst->UFTCTL &= ~(BIT(NPCX_UFTCTL_TEMPTY_LVL_EN) | - BIT(NPCX_UFTCTL_TEMPTY_EN) | + inst->UFTCTL &= ~(BIT(NPCX_UFTCTL_TEMPTY_LVL_EN) | BIT(NPCX_UFTCTL_TEMPTY_EN) | BIT(NPCX_UFTCTL_NXMIP_EN)); } @@ -137,8 +187,21 @@ static void uart_npcx_clear_rx_fifo(const struct device *dev) uint8_t scratch; /* Read all dummy bytes out from Rx FIFO */ - while (uart_npcx_rx_fifo_available(dev)) + while (uart_npcx_rx_fifo_available(dev)) { scratch = inst->URBUF; + } +} + +#endif + +#ifdef CONFIG_UART_INTERRUPT_DRIVEN +static int uart_npcx_tx_fifo_ready(const struct device *dev) +{ + const struct uart_npcx_config *const config = dev->config; + struct uart_reg *const inst = config->inst; + + /* True if the Tx FIFO is not completely full */ + return !(GET_FIELD(inst->UFTSTS, NPCX_UFTSTS_TEMPTY_LVL) == 0); } static int uart_npcx_fifo_fill(const struct device *dev, const uint8_t *tx_data, int size) @@ -271,7 +334,7 @@ static void uart_npcx_irq_err_disable(const struct device *dev) static int uart_npcx_irq_is_pending(const struct device *dev) { return uart_npcx_irq_tx_ready(dev) || - (uart_npcx_irq_rx_ready(dev) && uart_npcx_irq_rx_is_enabled(dev)); + (uart_npcx_irq_rx_ready(dev) && uart_npcx_irq_rx_is_enabled(dev)); } static int uart_npcx_irq_update(const struct device *dev) @@ -288,42 +351,11 @@ static void uart_npcx_irq_callback_set(const struct device *dev, uart_irq_callba data->user_cb = cb; data->user_data = cb_data; -} -static void uart_npcx_isr(const struct device *dev) -{ - struct uart_npcx_data *data = dev->data; - - /* - * Set pm constraint to prevent the system enter suspend state within - * the CONFIG_UART_CONSOLE_INPUT_EXPIRED_TIMEOUT period. - */ -#ifdef CONFIG_UART_CONSOLE_INPUT_EXPIRED - if (uart_npcx_irq_rx_ready(dev)) { - k_timeout_t delay = K_MSEC(CONFIG_UART_CONSOLE_INPUT_EXPIRED_TIMEOUT); - - uart_npcx_pm_policy_state_lock_get(data, UART_PM_POLICY_STATE_RX_FLAG); - k_work_reschedule(&data->rx_refresh_timeout_work, delay); - } +#if defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS) + data->async.user_callback = NULL; + data->async.user_data = NULL; #endif - - if (data->user_cb) { - data->user_cb(dev, data->user_data); - } -#ifdef CONFIG_PM - const struct uart_npcx_config *const config = dev->config; - struct uart_reg *const inst = config->inst; - - if (IS_BIT_SET(inst->UFTCTL, NPCX_UFTCTL_NXMIP_EN) && - IS_BIT_SET(inst->UFTSTS, NPCX_UFTSTS_NXMIP)) { - k_spinlock_key_t key = k_spin_lock(&data->lock); - - /* Disable NXMIP interrupt */ - inst->UFTCTL &= ~BIT(NPCX_UFTCTL_NXMIP_EN); - k_spin_unlock(&data->lock, key); - uart_npcx_pm_policy_state_lock_put(data, UART_PM_POLICY_STATE_TX_FLAG); - } -#endif /* CONFIG_PM */ } /* @@ -341,11 +373,12 @@ static int uart_npcx_poll_in(const struct device *dev, unsigned char *c) */ static void uart_npcx_poll_out(const struct device *dev, unsigned char c) { - while (!uart_npcx_fifo_fill(dev, &c, 1)) + while (!uart_npcx_fifo_fill(dev, &c, 1)) { continue; + } } -#else /* !CONFIG_UART_INTERRUPT_DRIVEN */ +#else /* !CONFIG_UART_INTERRUPT_DRIVEN */ /* * Poll-in implementation for byte mode config, read byte from URBUF if @@ -357,8 +390,9 @@ static int uart_npcx_poll_in(const struct device *dev, unsigned char *c) struct uart_reg *const inst = config->inst; /* Rx single byte buffer is not full */ - if (!IS_BIT_SET(inst->UICTRL, NPCX_UICTRL_RBF)) + if (!IS_BIT_SET(inst->UICTRL, NPCX_UICTRL_RBF)) { return -1; + } *c = inst->URBUF; return 0; @@ -373,13 +407,517 @@ static void uart_npcx_poll_out(const struct device *dev, unsigned char c) struct uart_reg *const inst = config->inst; /* Wait while Tx single byte buffer is ready to send */ - while (!IS_BIT_SET(inst->UICTRL, NPCX_UICTRL_TBE)) + while (!IS_BIT_SET(inst->UICTRL, NPCX_UICTRL_TBE)) { continue; + } inst->UTBUF = c; } #endif /* !CONFIG_UART_INTERRUPT_DRIVEN */ +#ifdef CONFIG_UART_ASYNC_API +static void async_user_callback(const struct device *dev, struct uart_event *evt) +{ + const struct uart_npcx_data *data = dev->data; + + if (data->async.user_callback) { + data->async.user_callback(dev, evt, data->async.user_data); + } +} + +static void async_evt_rx_rdy(const struct device *dev) +{ + struct uart_npcx_data *data = dev->data; + struct uart_npcx_rx_dma_params *rx_dma_params = &data->async.rx_dma_params; + + struct uart_event event = {.type = UART_RX_RDY, + .data.rx.buf = rx_dma_params->buf, + .data.rx.len = rx_dma_params->counter - rx_dma_params->offset, + .data.rx.offset = rx_dma_params->offset}; + + LOG_DBG("RX Ready: (len: %d off: %d buf: %x)", event.data.rx.len, event.data.rx.offset, + (uint32_t)event.data.rx.buf); + + /* Update the current pos for new data */ + rx_dma_params->offset = rx_dma_params->counter; + + /* Only send event for new data */ + if (event.data.rx.len > 0) { + async_user_callback(dev, &event); + } +} + +static void async_evt_tx_done(const struct device *dev) +{ + struct uart_npcx_data *data = dev->data; + + (void)k_work_cancel_delayable(&data->async.tx_dma_params.timeout_work); + + LOG_DBG("TX done: %d", data->async.tx_dma_params.buf_len); + + struct uart_event event = {.type = UART_TX_DONE, + .data.tx.buf = data->async.tx_dma_params.buf, + .data.tx.len = data->async.tx_dma_params.buf_len}; + + /* Reset TX Buffer */ + data->async.tx_dma_params.buf = NULL; + data->async.tx_dma_params.buf_len = 0U; + async_user_callback(dev, &event); +} + +static void uart_npcx_async_rx_dma_get_status(const struct device *dev, size_t *pending_length) +{ + const struct uart_npcx_config *const config = dev->config; + struct mdma_reg *const mdma_reg_base = config->mdma_reg_base; + + if (IS_BIT_SET(mdma_reg_base->MDMA_CTL0, NPCX_MDMA_CTL_MDMAEN)) { + *pending_length = mdma_reg_base->MDMA_CTCNT0; + } else { + *pending_length = 0; + } +} + +static void uart_npcx_async_rx_flush(const struct device *dev) +{ + struct uart_npcx_data *data = dev->data; + struct uart_npcx_rx_dma_params *rx_dma_params = &data->async.rx_dma_params; + size_t curr_rcv_len, dma_pending_len; + + uart_npcx_async_rx_dma_get_status(dev, &dma_pending_len); + curr_rcv_len = rx_dma_params->buf_len - dma_pending_len; + + if (curr_rcv_len > rx_dma_params->offset) { + rx_dma_params->counter = curr_rcv_len; + async_evt_rx_rdy(dev); +#ifdef CONFIG_UART_CONSOLE_INPUT_EXPIRED + k_timeout_t delay = K_MSEC(CONFIG_UART_CONSOLE_INPUT_EXPIRED_TIMEOUT); + + uart_npcx_pm_policy_state_lock_get(data, UART_PM_POLICY_STATE_RX_FLAG); + k_work_reschedule(&data->rx_refresh_timeout_work, delay); +#endif + } +} + +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 int uart_npcx_async_callback_set(const struct device *dev, uart_callback_t callback, + void *user_data) +{ + struct uart_npcx_data *data = dev->data; + + data->async.user_callback = callback; + data->async.user_data = user_data; + +#if defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS) + data->user_cb = NULL; + data->user_data = NULL; +#endif + + return 0; +} + +static inline void async_timer_start(struct k_work_delayable *work, uint32_t timeout_us) +{ + if ((timeout_us != SYS_FOREVER_US) && (timeout_us != 0)) { + LOG_DBG("async timer started for %d us", timeout_us); + k_work_reschedule(work, K_USEC(timeout_us)); + } +} + +static int uart_npcx_async_tx_dma_get_status(const struct device *dev, size_t *pending_length) +{ + const struct uart_npcx_config *const config = dev->config; + struct mdma_reg *const mdma_reg_base = config->mdma_reg_base; + + if (IS_BIT_SET(mdma_reg_base->MDMA_CTL1, NPCX_MDMA_CTL_MDMAEN)) { + *pending_length = mdma_reg_base->MDMA_CTCNT1; + } else { + *pending_length = 0; + return -EBUSY; + } + + return 0; +} + +static int uart_npcx_async_tx(const struct device *dev, const uint8_t *buf, size_t len, + int32_t timeout) +{ + const struct uart_npcx_config *const config = dev->config; + struct uart_reg *const inst = config->inst; + struct mdma_reg *const mdma_reg_base = config->mdma_reg_base; + struct uart_npcx_data *data = dev->data; + struct uart_npcx_tx_dma_params *tx_dma_params = &data->async.tx_dma_params; + int key = irq_lock(); + + if (buf == NULL || len == 0) { + irq_unlock(key); + return -EINVAL; + } + + if (tx_dma_params->buf) { + irq_unlock(key); + return -EBUSY; + } + + data->async.tx_in_progress = true; + + data->async.tx_dma_params.buf = buf; + data->async.tx_dma_params.buf_len = len; + data->async.tx_dma_params.timeout_us = timeout; + + mdma_reg_base->MDMA_SRCB1 = (uint32_t)buf; + mdma_reg_base->MDMA_TCNT1 = len; + + async_timer_start(&data->async.tx_dma_params.timeout_work, timeout); + mdma_reg_base->MDMA_CTL1 |= BIT(NPCX_MDMA_CTL_MDMAEN) | BIT(NPCX_MDMA_CTL_SIEN); + + inst->UMDSL |= BIT(NPCX_UMDSL_ETD); + +#ifdef CONFIG_PM + /* Do not allow system to suspend until transmission has completed */ + uart_npcx_pm_policy_state_lock_get(data, UART_PM_POLICY_STATE_TX_FLAG); +#endif + irq_unlock(key); + + return 0; +} + +static int uart_npcx_async_tx_abort(const struct device *dev) +{ + const struct uart_npcx_config *const config = dev->config; + struct uart_npcx_data *data = dev->data; + struct mdma_reg *const mdma_reg_base = config->mdma_reg_base; + size_t dma_pending_len, bytes_transmitted; + int ret; + + k_work_cancel_delayable(&data->async.tx_dma_params.timeout_work); + + mdma_reg_base->MDMA_CTL1 &= ~BIT(NPCX_MDMA_CTL_MDMAEN); + + ret = uart_npcx_async_tx_dma_get_status(dev, &dma_pending_len); + if (ret != 0) { + bytes_transmitted = 0; + } else { + bytes_transmitted = data->async.tx_dma_params.buf_len - dma_pending_len; + } + + struct uart_event tx_aborted_event = { + .type = UART_TX_ABORTED, + .data.tx.buf = data->async.tx_dma_params.buf, + .data.tx.len = bytes_transmitted, + }; + async_user_callback(dev, &tx_aborted_event); + + return ret; +} + +static void uart_npcx_async_tx_timeout(struct k_work *work) +{ + struct k_work_delayable *dwork = k_work_delayable_from_work(work); + struct uart_npcx_tx_dma_params *tx_params = + CONTAINER_OF(dwork, struct uart_npcx_tx_dma_params, timeout_work); + struct uart_npcx_async_data *async_data = + CONTAINER_OF(tx_params, struct uart_npcx_async_data, tx_dma_params); + const struct device *dev = async_data->uart_dev; + + LOG_ERR("Async Tx Timeout"); + uart_npcx_async_tx_abort(dev); +} + +static int uart_npcx_async_rx_enable(const struct device *dev, uint8_t *buf, const size_t len, + const int32_t timeout_us) +{ + const struct uart_npcx_config *const config = dev->config; + struct uart_reg *const inst = config->inst; + struct mdma_reg *const mdma_reg_base = config->mdma_reg_base; + struct uart_npcx_data *data = dev->data; + struct uart_npcx_rx_dma_params *rx_dma_params = &data->async.rx_dma_params; + unsigned int key; + + LOG_DBG("Enable RX DMA, len:%d", len); + + key = irq_lock(); + + __ASSERT_NO_MSG(buf != NULL); + __ASSERT_NO_MSG(len > 0); + + rx_dma_params->timeout_us = timeout_us; + rx_dma_params->buf = buf; + rx_dma_params->buf_len = len; + + rx_dma_params->offset = 0; + rx_dma_params->counter = 0; + + SET_FIELD(inst->UFRCTL, NPCX_UFRCTL_RFULL_LVL_SEL, 1); + + mdma_reg_base->MDMA_DSTB0 = (uint32_t)buf; + mdma_reg_base->MDMA_TCNT0 = len; + mdma_reg_base->MDMA_CTL0 |= BIT(NPCX_MDMA_CTL_MDMAEN) | BIT(NPCX_MDMA_CTL_SIEN); + + inst->UMDSL |= BIT(NPCX_UMDSL_ERD); + + rx_dma_params->enabled = true; + + async_evt_rx_buf_request(dev); + + inst->UFRCTL |= BIT(NPCX_UFRCTL_RNEMPTY_EN); + + irq_unlock(key); + + return 0; +} + +static void async_evt_rx_buf_release(const struct device *dev) +{ + struct uart_npcx_data *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 int uart_npcx_async_rx_disable(const struct device *dev) +{ + const struct uart_npcx_config *const config = dev->config; + struct uart_reg *const inst = config->inst; + struct uart_npcx_data *data = dev->data; + struct mdma_reg *const mdma_reg_base = config->mdma_reg_base; + struct uart_npcx_rx_dma_params *rx_dma_params = &data->async.rx_dma_params; + unsigned int key; + + LOG_DBG("Async RX Disable"); + + key = irq_lock(); + inst->UFRCTL &= ~(BIT(NPCX_UFRCTL_RNEMPTY_EN)); + + k_work_cancel_delayable(&rx_dma_params->timeout_work); + + if (rx_dma_params->buf == NULL) { + LOG_DBG("No buffers to release from RX DMA!"); + } else { + uart_npcx_async_rx_flush(dev); + async_evt_rx_buf_release(dev); + } + + rx_dma_params->enabled = false; + + if (data->async.next_rx_buffer != NULL) { + rx_dma_params->buf = data->async.next_rx_buffer; + rx_dma_params->buf_len = data->async.next_rx_buffer_len; + data->async.next_rx_buffer = NULL; + data->async.next_rx_buffer_len = 0; + /* Release the next buffer as well */ + async_evt_rx_buf_release(dev); + } + + mdma_reg_base->MDMA_CTL0 &= ~BIT(NPCX_MDMA_CTL_MDMAEN); + + struct uart_event disabled_event = {.type = UART_RX_DISABLED}; + + async_user_callback(dev, &disabled_event); + + irq_unlock(key); + + return 0; +} + +static int uart_npcx_async_rx_buf_rsp(const struct device *dev, uint8_t *buf, size_t len) +{ + struct uart_npcx_data *data = dev->data; + + if (data->async.next_rx_buffer != NULL) { + return -EBUSY; + } else if (data->async.rx_dma_params.enabled == false) { + return -EACCES; + } + + data->async.next_rx_buffer = buf; + data->async.next_rx_buffer_len = len; + + LOG_DBG("Next RX buf rsp, new: %d", len); + + return 0; +} + +static void uart_npcx_async_rx_timeout(struct k_work *work) +{ + struct k_work_delayable *dwork = k_work_delayable_from_work(work); + struct uart_npcx_rx_dma_params *rx_params = + CONTAINER_OF(dwork, struct uart_npcx_rx_dma_params, timeout_work); + struct uart_npcx_async_data *async_data = + CONTAINER_OF(rx_params, struct uart_npcx_async_data, rx_dma_params); + const struct device *dev = async_data->uart_dev; + + LOG_DBG("Async RX timeout"); + uart_npcx_async_rx_flush(dev); +} + +static void uart_npcx_async_dma_load_new_rx_buf(const struct device *dev) +{ + const struct uart_npcx_config *const config = dev->config; + struct uart_reg *const inst = config->inst; + struct mdma_reg *const mdma_reg_base = config->mdma_reg_base; + struct uart_npcx_data *data = dev->data; + struct uart_npcx_rx_dma_params *rx_dma_params = &data->async.rx_dma_params; + + rx_dma_params->offset = 0; + rx_dma_params->counter = 0; + + rx_dma_params->buf = data->async.next_rx_buffer; + rx_dma_params->buf_len = data->async.next_rx_buffer_len; + data->async.next_rx_buffer = NULL; + data->async.next_rx_buffer_len = 0; + + mdma_reg_base->MDMA_DSTB0 = (uint32_t)rx_dma_params->buf; + mdma_reg_base->MDMA_TCNT0 = rx_dma_params->buf_len; + mdma_reg_base->MDMA_CTL0 |= BIT(NPCX_MDMA_CTL_MDMAEN) | BIT(NPCX_MDMA_CTL_SIEN); + inst->UMDSL |= BIT(NPCX_UMDSL_ERD); +} + +/* DMA rx reaches the terminal Count */ +static void uart_npcx_async_dma_rx_complete(const struct device *dev) +{ + struct uart_npcx_data *data = dev->data; + struct uart_npcx_rx_dma_params *rx_dma_params = &data->async.rx_dma_params; + + rx_dma_params->counter = rx_dma_params->buf_len; + + async_evt_rx_rdy(dev); + + /* A new buffer was available. */ + if (data->async.next_rx_buffer != NULL) { + async_evt_rx_buf_release(dev); + uart_npcx_async_dma_load_new_rx_buf(dev); + /* Request the next buffer */ + async_evt_rx_buf_request(dev); + async_timer_start(&rx_dma_params->timeout_work, rx_dma_params->timeout_us); + } else { + /* Buffer full without valid next buffer, disable RX DMA */ + LOG_DBG("Disabled RX DMA, no valid next buffer "); + uart_npcx_async_rx_disable(dev); + } +} +#endif + +#if defined(CONFIG_UART_INTERRUPT_DRIVEN) || defined(CONFIG_UART_ASYNC_API) +static void uart_npcx_isr(const struct device *dev) +{ + struct uart_npcx_data *data = dev->data; +#if defined(CONFIG_PM) || defined(CONFIG_UART_ASYNC_API) + const struct uart_npcx_config *const config = dev->config; + struct uart_reg *const inst = config->inst; +#endif + + /* + * Set pm constraint to prevent the system enter suspend state within + * the CONFIG_UART_CONSOLE_INPUT_EXPIRED_TIMEOUT period. + */ +#ifdef CONFIG_UART_CONSOLE_INPUT_EXPIRED + if (uart_npcx_irq_rx_ready(dev)) { + k_timeout_t delay = K_MSEC(CONFIG_UART_CONSOLE_INPUT_EXPIRED_TIMEOUT); + + uart_npcx_pm_policy_state_lock_get(data, UART_PM_POLICY_STATE_RX_FLAG); + k_work_reschedule(&data->rx_refresh_timeout_work, delay); + } +#endif + +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + if (data->user_cb) { + data->user_cb(dev, data->user_data); + } +#endif + +#ifdef CONFIG_UART_ASYNC_API + if (data->async.user_callback) { + struct mdma_reg *const mdma_reg_base = config->mdma_reg_base; + + /* + * Check rx in any way because the RFIFO_NEMPTY_STS is not valid when MDMA mode is + * used. This is needed when the rx timeout_us is zero. In the case that the + * rx timeout_us is not zero, rx_flush is done in the tiemout_work callback. + */ + if (data->async.rx_dma_params.timeout_us == 0) { + uart_npcx_async_rx_flush(dev); + } else if (IS_BIT_SET(inst->UFRCTL, NPCX_UFRCTL_RNEMPTY_EN)) { + async_timer_start(&data->async.rx_dma_params.timeout_work, + data->async.rx_dma_params.timeout_us); + } + + /* MDMA rx end interrupt */ + if (IS_BIT_SET(mdma_reg_base->MDMA_CTL0, NPCX_MDMA_CTL_TC) && + IS_BIT_SET(mdma_reg_base->MDMA_CTL0, NPCX_MDMA_CTL_SIEN)) { + mdma_reg_base->MDMA_CTL0 &= ~BIT(NPCX_MDMA_CTL_SIEN); + /* TC is write-0-clear bit */ + mdma_reg_base->MDMA_CTL0 &= ~BIT(NPCX_MDMA_CTL_TC); + inst->UMDSL &= ~BIT(NPCX_UMDSL_ERD); + uart_npcx_async_dma_rx_complete(dev); + LOG_DBG("DMA Rx TC"); + } + + /* MDMA tx done interrupt */ + if (IS_BIT_SET(mdma_reg_base->MDMA_CTL1, NPCX_MDMA_CTL_TC) && + IS_BIT_SET(mdma_reg_base->MDMA_CTL1, NPCX_MDMA_CTL_SIEN)) { + mdma_reg_base->MDMA_CTL1 &= ~BIT(NPCX_MDMA_CTL_SIEN); + /* TC is write-0-clear bit */ + mdma_reg_base->MDMA_CTL1 &= ~BIT(NPCX_MDMA_CTL_TC); + + /* + * MDMA tx is done (i.e. all data in the memory are moved to UART tx FIFO), + * but data in the tx FIFO are not completely sent to the bus. + */ + if (!IS_BIT_SET(inst->UFTSTS, NPCX_UFTSTS_NXMIP)) { + k_spinlock_key_t key = k_spin_lock(&data->lock); + + inst->UFTCTL |= BIT(NPCX_UFTCTL_NXMIP_EN); + k_spin_unlock(&data->lock, key); + } else { + data->async.tx_in_progress = false; +#ifdef CONFIG_PM + uart_npcx_pm_policy_state_lock_put(data, + UART_PM_POLICY_STATE_TX_FLAG); +#endif /* CONFIG_PM */ + async_evt_tx_done(dev); + } + } + } +#endif + +#if defined(CONFIG_PM) || defined(CONFIG_UART_ASYNC_API) + if (IS_BIT_SET(inst->UFTCTL, NPCX_UFTCTL_NXMIP_EN) && + IS_BIT_SET(inst->UFTSTS, NPCX_UFTSTS_NXMIP)) { + k_spinlock_key_t key = k_spin_lock(&data->lock); + + /* Disable NXMIP interrupt */ + inst->UFTCTL &= ~BIT(NPCX_UFTCTL_NXMIP_EN); + k_spin_unlock(&data->lock, key); +#ifdef CONFIG_PM + uart_npcx_pm_policy_state_lock_put(data, UART_PM_POLICY_STATE_TX_FLAG); +#endif +#ifdef CONFIG_UART_ASYNC_API + if (data->async.tx_in_progress) { + data->async.tx_in_progress = false; + async_evt_tx_done(dev); + LOG_DBG("Tx wait-empty done"); + } +#endif + } +#endif +} +#endif + /* UART api functions */ static int uart_npcx_err_check(const struct device *dev) { @@ -388,14 +926,17 @@ static int uart_npcx_err_check(const struct device *dev) uint32_t err = 0U; uint8_t stat = inst->USTAT; - if (IS_BIT_SET(stat, NPCX_USTAT_DOE)) + if (IS_BIT_SET(stat, NPCX_USTAT_DOE)) { err |= UART_ERROR_OVERRUN; + } - if (IS_BIT_SET(stat, NPCX_USTAT_PE)) + if (IS_BIT_SET(stat, NPCX_USTAT_PE)) { err |= UART_ERROR_PARITY; + } - if (IS_BIT_SET(stat, NPCX_USTAT_FE)) + if (IS_BIT_SET(stat, NPCX_USTAT_FE)) { err |= UART_ERROR_FRAMING; + } return err; } @@ -406,6 +947,7 @@ static __unused void uart_npcx_rx_wk_isr(const struct device *dev, struct npcx_w * Set pm constraint to prevent the system enter suspend state within * the CONFIG_UART_CONSOLE_INPUT_EXPIRED_TIMEOUT period. */ + LOG_DBG("-->%s", dev->name); #ifdef CONFIG_UART_CONSOLE_INPUT_EXPIRED struct uart_npcx_data *data = dev->data; k_timeout_t delay = K_MSEC(CONFIG_UART_CONSOLE_INPUT_EXPIRED_TIMEOUT); @@ -453,6 +995,14 @@ static const struct uart_driver_api uart_npcx_driver_api = { .irq_update = uart_npcx_irq_update, .irq_callback_set = uart_npcx_irq_callback_set, #endif /* CONFIG_UART_INTERRUPT_DRIVEN */ +#ifdef CONFIG_UART_ASYNC_API + .callback_set = uart_npcx_async_callback_set, + .tx = uart_npcx_async_tx, + .tx_abort = uart_npcx_async_tx_abort, + .rx_enable = uart_npcx_async_rx_enable, + .rx_buf_rsp = uart_npcx_async_rx_buf_rsp, + .rx_disable = uart_npcx_async_rx_disable, +#endif /* CONFIG_UART_ASYNC_API */ }; static int uart_npcx_init(const struct device *dev) @@ -476,12 +1026,19 @@ static int uart_npcx_init(const struct device *dev) return ret; } +#ifdef CONFIG_UART_ASYNC_API + ret = clock_control_on(clk_dev, (clock_control_subsys_t)&config->mdma_clk_cfg); + if (ret < 0) { + LOG_ERR("Turn on UART MDMA clock fail %d", ret); + return ret; + } +#endif + /* * If apb2's clock is not 15MHz, we need to find the other optimized * values of UPSR and UBAUD for baud rate 115200. */ - ret = clock_control_get_rate(clk_dev, (clock_control_subsys_t)&config->clk_cfg, - &uart_rate); + ret = clock_control_get_rate(clk_dev, (clock_control_subsys_t)&config->clk_cfg, &uart_rate); if (ret < 0) { LOG_ERR("Get UART clock rate error %d", ret); return ret; @@ -502,7 +1059,7 @@ static int uart_npcx_init(const struct device *dev) inst->UFRS = 0x00; /* Initialize UART FIFO if mode is interrupt driven */ -#ifdef CONFIG_UART_INTERRUPT_DRIVEN +#if defined(CONFIG_UART_INTERRUPT_DRIVEN) || defined(CONFIG_UART_ASYNC_API) /* Enable the UART FIFO mode */ inst->UMDSL |= BIT(NPCX_UMDSL_FIFO_MD); @@ -516,6 +1073,14 @@ static int uart_npcx_init(const struct device *dev) config->irq_config_func(dev); #endif +#ifdef CONFIG_UART_ASYNC_API + 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_npcx_async_rx_timeout); + k_work_init_delayable(&data->async.tx_dma_params.timeout_work, uart_npcx_async_tx_timeout); +#endif + if (IS_ENABLED(CONFIG_PM)) { /* Initialize a miwu device input and its callback function */ npcx_miwu_init_dev_callback(&data->uart_rx_cb, &config->uart_rx_wui, @@ -543,7 +1108,7 @@ static int uart_npcx_init(const struct device *dev) return 0; } -#ifdef CONFIG_UART_INTERRUPT_DRIVEN +#if defined(CONFIG_UART_INTERRUPT_DRIVEN) || defined(CONFIG_UART_ASYNC_API) #define NPCX_UART_IRQ_CONFIG_FUNC_DECL(inst) \ static void uart_npcx_irq_config_##inst(const struct device *dev) #define NPCX_UART_IRQ_CONFIG_FUNC_INIT(inst) .irq_config_func = uart_npcx_irq_config_##inst, @@ -560,32 +1125,37 @@ static int uart_npcx_init(const struct device *dev) #define NPCX_UART_IRQ_CONFIG_FUNC(inst) #endif -#define NPCX_UART_INIT(i) \ - NPCX_UART_IRQ_CONFIG_FUNC_DECL(i); \ - \ - PINCTRL_DT_INST_DEFINE(i); \ - \ - static const struct uart_npcx_config uart_npcx_cfg_##i = { \ - .inst = (struct uart_reg *)DT_INST_REG_ADDR(i), \ - .clk_cfg = NPCX_DT_CLK_CFG_ITEM(i), \ - .uart_rx_wui = NPCX_DT_WUI_ITEM_BY_NAME(0, uart_rx), \ - .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(i), \ - NPCX_UART_IRQ_CONFIG_FUNC_INIT(i) \ - }; \ - \ - static struct uart_npcx_data uart_npcx_data_##i = { .baud_rate = DT_INST_PROP( \ - i, current_speed) }; \ - \ - DEVICE_DT_INST_DEFINE(i, &uart_npcx_init, NULL, &uart_npcx_data_##i, \ - &uart_npcx_cfg_##i, PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY, \ - &uart_npcx_driver_api); \ - \ +#define NPCX_UART_INIT(i) \ + NPCX_UART_IRQ_CONFIG_FUNC_DECL(i); \ + \ + PINCTRL_DT_INST_DEFINE(i); \ + \ + static const struct uart_npcx_config uart_npcx_cfg_##i = { \ + .inst = (struct uart_reg *)DT_INST_REG_ADDR(i), \ + .clk_cfg = NPCX_DT_CLK_CFG_ITEM(i), \ + .uart_rx_wui = NPCX_DT_WUI_ITEM_BY_NAME(i, uart_rx), \ + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(i), \ + NPCX_UART_IRQ_CONFIG_FUNC_INIT(i) \ + \ + IF_ENABLED(CONFIG_UART_ASYNC_API, ( \ + .mdma_clk_cfg = NPCX_DT_CLK_CFG_ITEM_BY_IDX(i, 1), \ + .mdma_reg_base = (struct mdma_reg *)DT_INST_REG_ADDR_BY_IDX(i, 1), \ + )) \ + }; \ + \ + static struct uart_npcx_data uart_npcx_data_##i = { \ + .baud_rate = DT_INST_PROP(i, current_speed), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(i, &uart_npcx_init, NULL, &uart_npcx_data_##i, &uart_npcx_cfg_##i, \ + PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY, &uart_npcx_driver_api); \ + \ NPCX_UART_IRQ_CONFIG_FUNC(i) DT_INST_FOREACH_STATUS_OKAY(NPCX_UART_INIT) -#define ENABLE_MIWU_CRIN_IRQ(i) \ - npcx_miwu_irq_get_and_clear_pending(&uart_npcx_cfg_##i.uart_rx_wui); \ +#define ENABLE_MIWU_CRIN_IRQ(i) \ + npcx_miwu_irq_get_and_clear_pending(&uart_npcx_cfg_##i.uart_rx_wui); \ npcx_miwu_irq_enable(&uart_npcx_cfg_##i.uart_rx_wui); #define DISABLE_MIWU_CRIN_IRQ(i) npcx_miwu_irq_disable(&uart_npcx_cfg_##i.uart_rx_wui); diff --git a/drivers/serial/uart_nrfx_uarte.c b/drivers/serial/uart_nrfx_uarte.c index b6d138dc2e0..cc2c9b90594 100644 --- a/drivers/serial/uart_nrfx_uarte.c +++ b/drivers/serial/uart_nrfx_uarte.c @@ -548,7 +548,7 @@ static void tx_start(const struct device *dev, const uint8_t *buf, size_t len) const struct uarte_nrfx_config *config = dev->config; NRF_UARTE_Type *uarte = get_uarte_instance(dev); -#if CONFIG_PM_DEVICE +#ifdef CONFIG_PM_DEVICE enum pm_device_state state; (void)pm_device_state_get(dev, &state); diff --git a/drivers/serial/uart_nrfx_uarte2.c b/drivers/serial/uart_nrfx_uarte2.c index ebe85448cea..99c70f47831 100644 --- a/drivers/serial/uart_nrfx_uarte2.c +++ b/drivers/serial/uart_nrfx_uarte2.c @@ -242,23 +242,22 @@ 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; + 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; } data->async->user_callback(dev, &evt, data->async->user_data); + } else if (event->data.rx.length) { + 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; @@ -390,7 +389,7 @@ static int api_tx(const struct device *dev, const uint8_t *buf, size_t len, int3 (void)pm_device_state_get(dev, &state); if (state != PM_DEVICE_STATE_ACTIVE) { - return 0; + return -ECANCELED; } #endif diff --git a/drivers/serial/uart_ns16550.c b/drivers/serial/uart_ns16550.c index bf07240c0ce..a9515d8c7a5 100644 --- a/drivers/serial/uart_ns16550.c +++ b/drivers/serial/uart_ns16550.c @@ -242,18 +242,18 @@ BUILD_ASSERT(IS_ENABLED(CONFIG_PCIE), "NS16550(s) in DT need CONFIG_PCIE"); #define MSR_RI 0x40 /* complement of ring signal */ #define MSR_DCD 0x80 /* complement of dcd */ -#define THR(dev) (get_port(dev) + REG_THR * reg_interval(dev)) -#define RDR(dev) (get_port(dev) + REG_RDR * reg_interval(dev)) -#define BRDL(dev) (get_port(dev) + REG_BRDL * reg_interval(dev)) -#define BRDH(dev) (get_port(dev) + REG_BRDH * reg_interval(dev)) -#define IER(dev) (get_port(dev) + REG_IER * reg_interval(dev)) -#define IIR(dev) (get_port(dev) + REG_IIR * reg_interval(dev)) -#define FCR(dev) (get_port(dev) + REG_FCR * reg_interval(dev)) -#define LCR(dev) (get_port(dev) + REG_LCR * reg_interval(dev)) -#define MDC(dev) (get_port(dev) + REG_MDC * reg_interval(dev)) -#define LSR(dev) (get_port(dev) + REG_LSR * reg_interval(dev)) -#define MSR(dev) (get_port(dev) + REG_MSR * reg_interval(dev)) -#define MDR1(dev) (get_port(dev) + REG_MDR1 * reg_interval(dev)) +#define THR(dev) (get_port(dev) + (REG_THR * reg_interval(dev))) +#define RDR(dev) (get_port(dev) + (REG_RDR * reg_interval(dev))) +#define BRDL(dev) (get_port(dev) + (REG_BRDL * reg_interval(dev))) +#define BRDH(dev) (get_port(dev) + (REG_BRDH * reg_interval(dev))) +#define IER(dev) (get_port(dev) + (REG_IER * reg_interval(dev))) +#define IIR(dev) (get_port(dev) + (REG_IIR * reg_interval(dev))) +#define FCR(dev) (get_port(dev) + (REG_FCR * reg_interval(dev))) +#define LCR(dev) (get_port(dev) + (REG_LCR * reg_interval(dev))) +#define MDC(dev) (get_port(dev) + (REG_MDC * reg_interval(dev))) +#define LSR(dev) (get_port(dev) + (REG_LSR * reg_interval(dev))) +#define MSR(dev) (get_port(dev) + (REG_MSR * reg_interval(dev))) +#define MDR1(dev) (get_port(dev) + (REG_MDR1 * reg_interval(dev))) #define DLF(dev) (get_port(dev) + REG_DLF) #define PCP(dev) (get_port(dev) + REG_PCP) @@ -1862,7 +1862,7 @@ static const struct uart_driver_api uart_ns16550_driver_api = { .source_data_size = 1, \ .dest_data_size = 1, \ .complete_callback_en = 0, \ - .error_callback_en = 1, \ + .error_callback_dis = 1, \ .block_count = 1, \ .channel_direction = MEMORY_TO_PERIPHERAL, \ .dma_slot = DT_INST_DMAS_CELL_BY_NAME(n, tx, channel), \ @@ -1881,7 +1881,7 @@ static const struct uart_driver_api uart_ns16550_driver_api = { .source_data_size = 1, \ .dest_data_size = 1, \ .complete_callback_en = 0, \ - .error_callback_en = 1, \ + .error_callback_dis = 1, \ .block_count = 1, \ .channel_direction = PERIPHERAL_TO_MEMORY, \ .dma_slot = DT_INST_DMAS_CELL_BY_NAME(n, rx, channel), \ diff --git a/drivers/serial/uart_pl011_ambiq.h b/drivers/serial/uart_pl011_ambiq.h index 24a356571a2..62d6d929123 100644 --- a/drivers/serial/uart_pl011_ambiq.h +++ b/drivers/serial/uart_pl011_ambiq.h @@ -54,17 +54,35 @@ static inline int clk_enable_ambiq_uart(const struct device *dev, uint32_t clk) * 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. */ - +#if defined(CONFIG_SOC_SERIES_APOLLO3X) +#define DEVPWRSTATUS_OFFSET 0x10 +#define HCPA_MASK 0x4 +#define AMBIQ_UART_DEFINE(n) \ + static int pwr_on_ambiq_uart_##n(void) \ + { \ + 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 + DEVPWRSTATUS_OFFSET; \ + sys_write32((sys_read32(addr) | DT_INST_PHA(n, ambiq_pwrcfg, mask)), addr); \ + while (!(sys_read32(pwr_status_addr) & HCPA_MASK)) { \ + }; \ + return 0; \ + } \ + static inline int clk_enable_ambiq_uart_##n(const struct device *dev, uint32_t clk) \ + { \ + return clk_enable_ambiq_uart(dev, clk); \ + } +#else +#define DEVPWRSTATUS_OFFSET 0x4 #define AMBIQ_UART_DEFINE(n) \ static int pwr_on_ambiq_uart_##n(void) \ { \ 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; \ + uint32_t pwr_status_addr = addr + DEVPWRSTATUS_OFFSET; \ sys_write32((sys_read32(addr) | DT_INST_PHA(n, ambiq_pwrcfg, mask)), addr); \ while ((sys_read32(pwr_status_addr) & DT_INST_PHA(n, ambiq_pwrcfg, mask)) != \ DT_INST_PHA(n, ambiq_pwrcfg, mask)) { \ - arch_nop(); \ }; \ return 0; \ } \ @@ -72,5 +90,6 @@ static inline int clk_enable_ambiq_uart(const struct device *dev, uint32_t clk) { \ return clk_enable_ambiq_uart(dev, clk); \ } +#endif #endif /* ZEPHYR_DRIVERS_SERIAL_UART_PL011_AMBIQ_H_ */ diff --git a/drivers/serial/uart_rcar.c b/drivers/serial/uart_rcar.c index 4be9376b758..c330f0f4f96 100644 --- a/drivers/serial/uart_rcar.c +++ b/drivers/serial/uart_rcar.c @@ -550,7 +550,7 @@ static const struct uart_driver_api uart_rcar_driver_api = { .bus_clk.module = DT_INST_CLOCKS_CELL_BY_IDX(n, 1, module), \ .bus_clk.domain = DT_INST_CLOCKS_CELL_BY_IDX(n, 1, domain), \ .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ - .is_hscif = DT_NODE_HAS_COMPAT(DT_DRV_INST(n), renesas_rcar_hscif), \ + .is_hscif = DT_INST_NODE_HAS_COMPAT(n, renesas_rcar_hscif), \ IRQ_FUNC_INIT \ } diff --git a/drivers/serial/uart_smartbond.c b/drivers/serial/uart_smartbond.c index 7d5ef34cc72..8656ae8dc43 100644 --- a/drivers/serial/uart_smartbond.c +++ b/drivers/serial/uart_smartbond.c @@ -7,13 +7,17 @@ #define DT_DRV_COMPAT renesas_smartbond_uart #include +#include #include #include +#include +#include #include #include #include #include #include +#include #define IIR_NO_INTR 1 #define IIR_THR_EMPTY 2 @@ -75,10 +79,29 @@ struct uart_smartbond_cfg { #ifdef CONFIG_UART_INTERRUPT_DRIVEN void (*irq_config_func)(const struct device *dev); #endif +#if CONFIG_PM_DEVICE + int rx_wake_timeout; + struct gpio_dt_spec rx_wake_gpio; + struct gpio_dt_spec dtr_gpio; +#endif +}; + +struct uart_smartbond_runtime_cfg { + uint32_t baudrate_cfg; + uint32_t lcr_reg_val; + uint8_t mcr_reg_val; + uint8_t ier_reg_val; +}; + +enum uart_smartbond_pm_policy_state_flag { + UART_SMARTBOND_PM_POLICY_STATE_RX_FLAG, + UART_SMARTBOND_PM_POLICY_STATE_DTR_FLAG, + UART_SMARTBOND_PM_POLICY_STATE_FLAG_COUNT, }; struct uart_smartbond_data { struct uart_config current_config; + struct uart_smartbond_runtime_cfg runtime_cfg; struct k_spinlock lock; #ifdef CONFIG_UART_INTERRUPT_DRIVEN uart_irq_callback_user_data_t callback; @@ -86,9 +109,44 @@ struct uart_smartbond_data { uint32_t flags; uint8_t rx_enabled; uint8_t tx_enabled; +#if CONFIG_PM_DEVICE + struct gpio_callback dtr_wake_cb; + const struct uart_smartbond_cfg *config; + struct gpio_callback rx_wake_cb; + int rx_wake_timeout; + struct k_work_delayable rx_timeout_work; + + ATOMIC_DEFINE(pm_policy_state_flag, UART_SMARTBOND_PM_POLICY_STATE_FLAG_COUNT); +#endif #endif }; +#if defined(CONFIG_PM_DEVICE) + +static void uart_smartbond_pm_policy_state_lock_get(struct uart_smartbond_data *data, int flag) +{ + if (atomic_test_and_set_bit(data->pm_policy_state_flag, flag) == 0) { + pm_policy_state_lock_get(PM_STATE_STANDBY, PM_ALL_SUBSTATES); + } +} + +static void uart_smartbond_pm_policy_state_lock_put(struct uart_smartbond_data *data, int flag) +{ + if (atomic_test_and_clear_bit(data->pm_policy_state_flag, flag) == 1) { + pm_policy_state_lock_put(PM_STATE_STANDBY, PM_ALL_SUBSTATES); + } +} + +static void uart_smartbond_rx_refresh_timeout(struct k_work *work) +{ + struct uart_smartbond_data *data = CONTAINER_OF(work, struct uart_smartbond_data, + rx_timeout_work.work); + + uart_smartbond_pm_policy_state_lock_put(data, UART_SMARTBOND_PM_POLICY_STATE_RX_FLAG); +} + +#endif + static int uart_smartbond_poll_in(const struct device *dev, unsigned char *p_char) { const struct uart_smartbond_cfg *config = dev->config; @@ -122,14 +180,48 @@ static void uart_smartbond_poll_out(const struct device *dev, unsigned char out_ k_spin_unlock(&data->lock, key); } +static void apply_runtime_config(const struct device *dev) +{ + const struct uart_smartbond_cfg *config = dev->config; + struct uart_smartbond_data *data = dev->data; + k_spinlock_key_t key; + + key = k_spin_lock(&data->lock); + + CRG_COM->SET_CLK_COM_REG = config->periph_clock_config; + + config->regs->UART2_MCR_REG = data->runtime_cfg.mcr_reg_val; + config->regs->UART2_SRR_REG = UART2_UART2_SRR_REG_UART_UR_Msk | + UART2_UART2_SRR_REG_UART_RFR_Msk | + UART2_UART2_SRR_REG_UART_XFR_Msk; + + /* Configure baudrate */ + config->regs->UART2_LCR_REG |= UART2_UART2_LCR_REG_UART_DLAB_Msk; + config->regs->UART2_IER_DLH_REG = BAUDRATE_CFG_DLH(data->runtime_cfg.baudrate_cfg); + config->regs->UART2_RBR_THR_DLL_REG = BAUDRATE_CFG_DLL(data->runtime_cfg.baudrate_cfg); + config->regs->UART2_DLF_REG = BAUDRATE_CFG_DLF(data->runtime_cfg.baudrate_cfg); + config->regs->UART2_LCR_REG &= ~UART2_UART2_LCR_REG_UART_DLAB_Msk; + + /* Configure frame */ + config->regs->UART2_LCR_REG = data->runtime_cfg.lcr_reg_val; + + /* Enable hardware FIFO */ + config->regs->UART2_SFE_REG = UART2_UART2_SFE_REG_UART_SHADOW_FIFO_ENABLE_Msk; + + config->regs->UART2_SRT_REG = RX_FIFO_TRIG_1_CHAR; + config->regs->UART2_STET_REG = TX_FIFO_TRIG_1_2_FULL; + config->regs->UART2_IER_DLH_REG = data->runtime_cfg.ier_reg_val; + + k_spin_unlock(&data->lock, key); +} + static int uart_smartbond_configure(const struct device *dev, - const struct uart_config *cfg) + const struct uart_config *cfg) { const struct uart_smartbond_cfg *config = dev->config; struct uart_smartbond_data *data = dev->data; uint32_t baudrate_cfg = 0; - k_spinlock_key_t key; - uint32_t reg_val; + uint32_t lcr_reg_val; int err; int i; @@ -161,63 +253,44 @@ static int uart_smartbond_configure(const struct device *dev, return -ENOTSUP; } - key = k_spin_lock(&data->lock); - - CRG_COM->SET_CLK_COM_REG = config->periph_clock_config; - - config->regs->UART2_SRR_REG = UART2_UART2_SRR_REG_UART_UR_Msk | - UART2_UART2_SRR_REG_UART_RFR_Msk | - UART2_UART2_SRR_REG_UART_XFR_Msk; - - config->regs->UART2_LCR_REG |= UART2_UART2_LCR_REG_UART_DLAB_Msk; - config->regs->UART2_IER_DLH_REG = BAUDRATE_CFG_DLH(baudrate_cfg); - config->regs->UART2_RBR_THR_DLL_REG = BAUDRATE_CFG_DLL(baudrate_cfg); - config->regs->UART2_DLF_REG = BAUDRATE_CFG_DLF(baudrate_cfg); - config->regs->UART2_LCR_REG &= ~UART2_UART2_LCR_REG_UART_DLAB_Msk; - - /* Configure frame */ - - reg_val = 0; + /* Calculate frame configuration register value */ + lcr_reg_val = 0; switch (cfg->parity) { case UART_CFG_PARITY_NONE: break; case UART_CFG_PARITY_EVEN: - reg_val |= UART2_UART2_LCR_REG_UART_EPS_Msk; + lcr_reg_val |= UART2_UART2_LCR_REG_UART_EPS_Msk; /* no break */ case UART_CFG_PARITY_ODD: - reg_val |= UART2_UART2_LCR_REG_UART_PEN_Msk; + lcr_reg_val |= UART2_UART2_LCR_REG_UART_PEN_Msk; break; } if (cfg->stop_bits == UART_CFG_STOP_BITS_2) { - reg_val |= STOP_BITS_2 << UART2_UART2_LCR_REG_UART_STOP_Pos; + lcr_reg_val |= STOP_BITS_2 << UART2_UART2_LCR_REG_UART_STOP_Pos; } switch (cfg->data_bits) { case UART_CFG_DATA_BITS_6: - reg_val |= DATA_BITS_6 << UART2_UART2_LCR_REG_UART_DLS_Pos; + lcr_reg_val |= DATA_BITS_6 << UART2_UART2_LCR_REG_UART_DLS_Pos; break; case UART_CFG_DATA_BITS_7: - reg_val |= DATA_BITS_7 << UART2_UART2_LCR_REG_UART_DLS_Pos; + lcr_reg_val |= DATA_BITS_7 << UART2_UART2_LCR_REG_UART_DLS_Pos; break; case UART_CFG_DATA_BITS_8: - reg_val |= DATA_BITS_8 << UART2_UART2_LCR_REG_UART_DLS_Pos; + lcr_reg_val |= DATA_BITS_8 << UART2_UART2_LCR_REG_UART_DLS_Pos; break; } - config->regs->UART2_LCR_REG = reg_val; - - /* Enable hardware FIFO */ - config->regs->UART2_SFE_REG = UART2_UART2_SFE_REG_UART_SHADOW_FIFO_ENABLE_Msk; + data->runtime_cfg.baudrate_cfg = baudrate_cfg; + data->runtime_cfg.lcr_reg_val = lcr_reg_val; + data->runtime_cfg.mcr_reg_val = cfg->flow_ctrl ? UART2_UART2_MCR_REG_UART_AFCE_Msk : 0; - config->regs->UART2_SRT_REG = RX_FIFO_TRIG_1_CHAR; - config->regs->UART2_STET_REG = TX_FIFO_TRIG_1_2_FULL; + apply_runtime_config(dev); data->current_config = *cfg; - k_spin_unlock(&data->lock, key); - err = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); if (err < 0) { return err; @@ -238,11 +311,103 @@ static int uart_smartbond_config_get(const struct device *dev, } #endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */ +#if CONFIG_PM_DEVICE + +static void uart_smartbond_wake_handler(const struct device *gpio, struct gpio_callback *cb, + uint32_t pins) +{ + struct uart_smartbond_data *data = CONTAINER_OF(cb, struct uart_smartbond_data, + rx_wake_cb); + + /* Disable interrupts on UART RX pin to avoid repeated interrupts. */ + (void)gpio_pin_interrupt_configure(gpio, (find_msb_set(pins) - 1), + GPIO_INT_DISABLE); + /* Refresh console expired time */ + if (data->rx_wake_timeout) { + + uart_smartbond_pm_policy_state_lock_get(data, + UART_SMARTBOND_PM_POLICY_STATE_RX_FLAG); + k_work_reschedule(&data->rx_timeout_work, K_MSEC(data->rx_wake_timeout)); + } +} + +static void uart_smartbond_dtr_handler(const struct device *gpio, struct gpio_callback *cb, + uint32_t pins) +{ + struct uart_smartbond_data *data = CONTAINER_OF(cb, struct uart_smartbond_data, + dtr_wake_cb); + int pin = find_lsb_set(pins) - 1; + + if (gpio_pin_get(gpio, pin) == 1) { + uart_smartbond_pm_policy_state_lock_put(data, + UART_SMARTBOND_PM_POLICY_STATE_DTR_FLAG); + } else { + uart_smartbond_pm_policy_state_lock_get(data, + UART_SMARTBOND_PM_POLICY_STATE_DTR_FLAG); + } +} + +#endif + static int uart_smartbond_init(const struct device *dev) { struct uart_smartbond_data *data = dev->data; + int ret = 0; + + da1469x_pd_acquire(MCU_PD_DOMAIN_COM); + +#ifdef CONFIG_PM_DEVICE + int rx_wake_timeout; + const struct uart_smartbond_cfg *config = dev->config; + const struct device *uart_console_dev = + DEVICE_DT_GET(DT_CHOSEN(zephyr_console)); + /* All uarts can have wake time specified in device tree to keep + * device awake after receiving data + */ + rx_wake_timeout = config->rx_wake_timeout; + if (dev == uart_console_dev) { +#ifdef CONFIG_UART_CONSOLE_INPUT_EXPIRED + /* For device configured as console wake time is taken from + * Kconfig same way it is configured for other platforms + */ + rx_wake_timeout = CONFIG_UART_CONSOLE_INPUT_EXPIRED_TIMEOUT; +#endif + } + /* If DTR pin is configured, use it for power management */ + if (config->dtr_gpio.port != NULL) { + gpio_init_callback(&data->dtr_wake_cb, uart_smartbond_dtr_handler, + BIT(config->dtr_gpio.pin)); + ret = gpio_add_callback(config->dtr_gpio.port, &data->dtr_wake_cb); + if (ret == 0) { + ret = gpio_pin_interrupt_configure_dt(&config->dtr_gpio, + GPIO_INT_MODE_EDGE | + GPIO_INT_TRIG_BOTH); + /* Check if DTR is already active (low), if so lock power state */ + if (gpio_pin_get(config->dtr_gpio.port, config->dtr_gpio.pin) == 0) { + uart_smartbond_pm_policy_state_lock_get(data, + UART_SMARTBOND_PM_POLICY_STATE_DTR_FLAG); + } + } + } + if (rx_wake_timeout > 0 && config->rx_wake_gpio.port != NULL) { + k_work_init_delayable(&data->rx_timeout_work, + uart_smartbond_rx_refresh_timeout); + gpio_init_callback(&data->rx_wake_cb, uart_smartbond_wake_handler, + BIT(config->rx_wake_gpio.pin)); + + ret = gpio_add_callback(config->rx_wake_gpio.port, &data->rx_wake_cb); + if (ret == 0) { + data->rx_wake_timeout = rx_wake_timeout; + } + } +#endif - return uart_smartbond_configure(dev, &data->current_config); + ret = uart_smartbond_configure(dev, &data->current_config); + if (ret < 0) { + da1469x_pd_release(MCU_PD_DOMAIN_COM); + } + + return ret; } #ifdef CONFIG_UART_INTERRUPT_DRIVEN @@ -316,6 +481,11 @@ static int uart_smartbond_fifo_read(const struct device *dev, uint8_t *rx_data, irq_rx_enable(dev); } +#ifdef CONFIG_PM_DEVICE + if (data->rx_wake_timeout) { + k_work_reschedule(&data->rx_timeout_work, K_MSEC(data->rx_wake_timeout)); + } +#endif k_spin_unlock(&data->lock, key); return num_rx; @@ -455,6 +625,60 @@ static void uart_smartbond_isr(const struct device *dev) } #endif /* CONFIG_UART_INTERRUPT_DRIVEN */ +#ifdef CONFIG_PM_DEVICE +static int uart_disable(const struct device *dev) +{ + const struct uart_smartbond_cfg *config = dev->config; + struct uart_smartbond_data *data = dev->data; + + /* Store IER register in case UART will go to sleep */ + data->runtime_cfg.ier_reg_val = config->regs->UART2_IER_DLH_REG; + + if (config->regs->UART2_USR_REG & UART2_UART2_USR_REG_UART_RFNE_Msk) { + return -EBUSY; + } + while (!(config->regs->UART2_USR_REG & UART2_UART2_USR_REG_UART_TFE_Msk) || + (config->regs->UART2_USR_REG & UART2_UART2_USR_REG_UART_BUSY_Msk)) { + /* Wait until FIFO is empty and UART finished tx */ + if (config->regs->UART2_USR_REG & UART2_UART2_USR_REG_UART_RFNE_Msk) { + return -EBUSY; + } + } + + CRG_COM->RESET_CLK_COM_REG = config->periph_clock_config; + da1469x_pd_release(MCU_PD_DOMAIN_COM); + + return 0; +} + +static int uart_smartbond_pm_action(const struct device *dev, + enum pm_device_action action) +{ + const struct uart_smartbond_cfg *config; + int ret = 0; + + switch (action) { + case PM_DEVICE_ACTION_RESUME: + da1469x_pd_acquire(MCU_PD_DOMAIN_COM); + apply_runtime_config(dev); + break; + case PM_DEVICE_ACTION_SUSPEND: + config = dev->config; + ret = uart_disable(dev); + if (ret == 0 && config->rx_wake_gpio.port != NULL) { + ret = gpio_pin_interrupt_configure_dt(&config->rx_wake_gpio, + GPIO_INT_MODE_EDGE | + GPIO_INT_TRIG_LOW); + } + break; + default: + ret = -ENOTSUP; + } + + return ret; +} +#endif /* CONFIG_PM_DEVICE */ + static const struct uart_driver_api uart_smartbond_driver_api = { .poll_in = uart_smartbond_poll_in, .poll_out = uart_smartbond_poll_out, @@ -494,6 +718,19 @@ static const struct uart_driver_api uart_smartbond_driver_api = { #define UART_SMARTBOND_CONFIGURE(id) #endif +#ifdef CONFIG_PM_DEVICE +#define UART_PM_WAKE_RX_TIMEOUT(n) \ + .rx_wake_timeout = (DT_INST_PROP_OR(n, rx_wake_timeout, 0)), +#define UART_PM_WAKE_RX_PIN(n) \ + .rx_wake_gpio = GPIO_DT_SPEC_INST_GET_OR(n, rx_wake_gpios, {0}), +#define UART_PM_WAKE_DTR_PIN(n) \ + .dtr_gpio = GPIO_DT_SPEC_INST_GET_OR(n, dtr_gpios, {0}), +#else +#define UART_PM_WAKE_RX_PIN(n) /* Not used */ +#define UART_PM_WAKE_RX_TIMEOUT(n) /* Not used */ +#define UART_PM_WAKE_DTR_PIN(n) /* Not used */ +#endif + #define UART_SMARTBOND_DEVICE(id) \ PINCTRL_DT_INST_DEFINE(id); \ static const struct uart_smartbond_cfg uart_smartbond_##id##_cfg = { \ @@ -501,6 +738,9 @@ static const struct uart_driver_api uart_smartbond_driver_api = { .periph_clock_config = DT_INST_PROP(id, periph_clock_config), \ .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(id), \ .hw_flow_control_supported = DT_INST_PROP(id, hw_flow_control_supported), \ + UART_PM_WAKE_RX_TIMEOUT(id) \ + UART_PM_WAKE_RX_PIN(id) \ + UART_PM_WAKE_DTR_PIN(id) \ }; \ static struct uart_smartbond_data uart_smartbond_##id##_data = { \ .current_config = { \ @@ -516,9 +756,10 @@ static const struct uart_driver_api uart_smartbond_driver_api = { UART_SMARTBOND_CONFIGURE(id); \ return uart_smartbond_init(dev); \ } \ + PM_DEVICE_DT_INST_DEFINE(id, uart_smartbond_pm_action); \ DEVICE_DT_INST_DEFINE(id, \ uart_smartbond_##id##_init, \ - NULL, \ + PM_DEVICE_DT_INST_GET(id), \ &uart_smartbond_##id##_data, \ &uart_smartbond_##id##_cfg, \ PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY, \ diff --git a/drivers/serial/uart_stm32.c b/drivers/serial/uart_stm32.c index e79ba3bf0f3..f5a831f0d2b 100644 --- a/drivers/serial/uart_stm32.c +++ b/drivers/serial/uart_stm32.c @@ -1,6 +1,7 @@ /* * Copyright (c) 2016 Open-RnD Sp. z o.o. * Copyright (c) 2016 Linaro Limited. + * Copyright (c) 2024 STMicroelectronics * * SPDX-License-Identifier: Apache-2.0 */ @@ -39,6 +40,12 @@ #include #endif /* CONFIG_PM */ +#ifdef CONFIG_DCACHE +#include +#include +#include +#endif /* CONFIG_DCACHE */ + #include #include LOG_MODULE_REGISTER(uart_stm32, CONFIG_UART_LOG_LEVEL); @@ -1301,6 +1308,32 @@ static void uart_stm32_isr(const struct device *dev) #ifdef CONFIG_UART_ASYNC_API +#ifdef CONFIG_DCACHE +static bool buf_in_nocache(uintptr_t buf, size_t len_bytes) +{ + bool buf_within_nocache = false; + +#ifdef CONFIG_NOCACHE_MEMORY + buf_within_nocache = (buf >= ((uintptr_t)_nocache_ram_start)) && + ((buf + len_bytes - 1) <= ((uintptr_t)_nocache_ram_end)); + if (buf_within_nocache) { + return true; + } +#endif /* CONFIG_NOCACHE_MEMORY */ + + buf_within_nocache = mem_attr_check_buf( + (void *)buf, len_bytes, DT_MEM_ARM_MPU_RAM_NOCACHE) == 0; + if (buf_within_nocache) { + return true; + } + + buf_within_nocache = (buf >= ((uintptr_t)__rodata_region_start)) && + ((buf + len_bytes - 1) <= ((uintptr_t)__rodata_region_end)); + + return buf_within_nocache; +} +#endif /* CONFIG_DCACHE */ + static int uart_stm32_async_callback_set(const struct device *dev, uart_callback_t callback, void *user_data) @@ -1512,6 +1545,13 @@ static int uart_stm32_async_tx(const struct device *dev, return -EBUSY; } +#ifdef CONFIG_DCACHE + if (!buf_in_nocache((uintptr_t)tx_data, buf_size)) { + LOG_ERR("Tx buffer should be placed in a nocache memory region"); + return -EFAULT; + } +#endif /* CONFIG_DCACHE */ + data->dma_tx.buffer = (uint8_t *)tx_data; data->dma_tx.buffer_length = buf_size; data->dma_tx.timeout = timeout; @@ -1572,6 +1612,13 @@ static int uart_stm32_async_rx_enable(const struct device *dev, return -EBUSY; } +#ifdef CONFIG_DCACHE + if (!buf_in_nocache((uintptr_t)rx_buf, buf_size)) { + LOG_ERR("Rx buffer should be placed in a nocache memory region"); + return -EFAULT; + } +#endif /* CONFIG_DCACHE */ + data->dma_rx.offset = 0; data->dma_rx.buffer = rx_buf; data->dma_rx.buffer_length = buf_size; @@ -1696,6 +1743,12 @@ static int uart_stm32_async_rx_buf_rsp(const struct device *dev, uint8_t *buf, } else if (!data->dma_rx.enabled) { err = -EACCES; } else { +#ifdef CONFIG_DCACHE + if (!buf_in_nocache((uintptr_t)buf, len)) { + LOG_ERR("Rx buffer should be placed in a nocache memory region"); + return -EFAULT; + } +#endif /* CONFIG_DCACHE */ data->rx_next_buffer = buf; data->rx_next_buffer_len = len; } diff --git a/drivers/spi/CMakeLists.txt b/drivers/spi/CMakeLists.txt index 8bbae49d1c2..840c9dcdc5f 100644 --- a/drivers/spi/CMakeLists.txt +++ b/drivers/spi/CMakeLists.txt @@ -4,6 +4,7 @@ zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/spi.h) zephyr_library() +zephyr_library_sources_ifdef(CONFIG_SPI_SHELL spi_shell.c) zephyr_library_sources_ifdef(CONFIG_SPI_TELINK_B91 spi_b91.c) zephyr_library_sources_ifdef(CONFIG_SPI_CC13XX_CC26XX spi_cc13xx_cc26xx.c) zephyr_library_sources_ifdef(CONFIG_SPI_DW spi_dw.c) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index c7e40016b4e..9dc7908552f 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -13,6 +13,15 @@ menuconfig SPI if SPI +config SPI_SHELL + bool "SPI Shell" + depends on SHELL + help + Enable SPI Shell. + + The currently SPI shell supports simple SPI write/read (transceive) + operation. + config SPI_ASYNC bool "Asynchronous call support" select POLL @@ -45,7 +54,7 @@ config SPI_EXTENDED_MODES config SPI_INIT_PRIORITY int "Init priority" - default 70 + default KERNEL_INIT_PRIORITY_DEVICE help Device driver initialization priority. diff --git a/drivers/spi/Kconfig.mcux_flexcomm b/drivers/spi/Kconfig.mcux_flexcomm index ff07a5ec038..68ef16aa3e8 100644 --- a/drivers/spi/Kconfig.mcux_flexcomm +++ b/drivers/spi/Kconfig.mcux_flexcomm @@ -7,6 +7,7 @@ config SPI_MCUX_FLEXCOMM default y depends on DT_HAS_NXP_LPC_SPI_ENABLED select PINCTRL + select RESET help Enable support for mcux flexcomm spi driver. diff --git a/drivers/spi/spi_andes_atcspi200.c b/drivers/spi/spi_andes_atcspi200.c index adc7b2e9157..1d95d9fc263 100644 --- a/drivers/spi/spi_andes_atcspi200.c +++ b/drivers/spi/spi_andes_atcspi200.c @@ -887,7 +887,7 @@ static void spi_atcspi200_irq_handler(void *arg) .channel_direction = ANDES_DMA_CONFIG_DIRECTION( \ DMA_CHANNEL_CONFIG(index, dir)), \ .complete_callback_en = 0, \ - .error_callback_en = 0, \ + .error_callback_dis = 0, \ .source_data_size = \ ANDES_DMA_CONFIG_##src_dev##_DATA_SIZE( \ DMA_CHANNEL_CONFIG(index, dir) \ diff --git a/drivers/spi/spi_ll_stm32.c b/drivers/spi/spi_ll_stm32.c index e24b9722d06..7b557ebd07b 100644 --- a/drivers/spi/spi_ll_stm32.c +++ b/drivers/spi/spi_ll_stm32.c @@ -18,6 +18,9 @@ LOG_MODULE_REGISTER(spi_ll_stm32); #include #include #include +#include +#include +#include #ifdef CONFIG_SPI_STM32_DMA #include #include @@ -27,9 +30,9 @@ LOG_MODULE_REGISTER(spi_ll_stm32); #include #include -#ifdef CONFIG_SOC_SERIES_STM32H7X +#ifdef CONFIG_DCACHE #include -#endif +#endif /* CONFIG_DCACHE */ #ifdef CONFIG_NOCACHE_MEMORY #include @@ -39,17 +42,13 @@ LOG_MODULE_REGISTER(spi_ll_stm32); #include "spi_ll_stm32.h" -/* - * Check defined(CONFIG_DCACHE) because some platforms disable it in the tests - * e.g. nucleo_f746zg - */ -#if defined(CONFIG_CPU_HAS_DCACHE) && \ - defined(CONFIG_DCACHE) && \ +#if defined(CONFIG_DCACHE) && \ !defined(CONFIG_NOCACHE_MEMORY) +/* currently, manual cache coherency management is only done on dummy_rx_tx_buffer */ #define SPI_STM32_MANUAL_CACHE_COHERENCY_REQUIRED 1 #else #define SPI_STM32_MANUAL_CACHE_COHERENCY_REQUIRED 0 -#endif /* defined(CONFIG_CPU_HAS_DCACHE) && !defined(CONFIG_NOCACHE_MEMORY) */ +#endif /* defined(CONFIG_DCACHE) && !defined(CONFIG_NOCACHE_MEMORY) */ #define WAIT_1US 1U @@ -73,31 +72,54 @@ LOG_MODULE_REGISTER(spi_ll_stm32); #endif #endif /* CONFIG_SOC_SERIES_STM32MP1X */ +static void spi_stm32_pm_policy_state_lock_get(const struct device *dev) +{ + if (IS_ENABLED(CONFIG_PM)) { + struct spi_stm32_data *data = dev->data; + + 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); + } + pm_device_runtime_get(dev); + } + } +} + +static void spi_stm32_pm_policy_state_lock_put(const struct device *dev) +{ + if (IS_ENABLED(CONFIG_PM)) { + struct spi_stm32_data *data = dev->data; + + if (data->pm_policy_state_on) { + data->pm_policy_state_on = false; + pm_device_runtime_put(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); + } + } + } +} + #ifdef CONFIG_SPI_STM32_DMA static uint32_t bits2bytes(uint32_t bits) { return bits / 8; } -/* dummy value used for transferring NOP when tx buf is null - * and use as dummy sink for when rx buf is null. +/* dummy buffer is used for transferring NOP when tx buf is null + * and used as a dummy sink for when rx buf is null. */ -#ifdef CONFIG_NOCACHE_MEMORY /* - * If a nocache area is available, place it there to avoid potential DMA - * cache-coherency problems. - */ -static __aligned(32) uint32_t dummy_rx_tx_buffer - __attribute__((__section__(".nocache"))); - -#else /* CONFIG_NOCACHE_MEMORY */ - -/* - * If nocache areas are not available, cache coherency might need to be kept + * If Nocache Memory is supported, buffer will be placed in nocache region by + * the linker to avoid potential DMA cache-coherency problems. + * If Nocache Memory is not supported, cache coherency might need to be kept * manually. See SPI_STM32_MANUAL_CACHE_COHERENCY_REQUIRED. */ -static __aligned(32) uint32_t dummy_rx_tx_buffer; -#endif /* CONFIG_NOCACHE_MEMORY */ +static __aligned(32) uint32_t dummy_rx_tx_buffer __nocache; /* This function is executed in the interrupt context */ static void dma_callback(const struct device *dev, void *arg, @@ -150,7 +172,7 @@ static int spi_stm32_dma_tx_load(const struct device *dev, const uint8_t *buf, dummy_rx_tx_buffer = 0; #if SPI_STM32_MANUAL_CACHE_COHERENCY_REQUIRED arch_dcache_flush_range((void *)&dummy_rx_tx_buffer, sizeof(uint32_t)); -#endif /* CONFIG_CPU_HAS_DCACHE && !defined(CONFIG_NOCACHE_MEMORY) */ +#endif /* SPI_STM32_MANUAL_CACHE_COHERENCY_REQUIRED */ blk_cfg->source_address = (uint32_t)&dummy_rx_tx_buffer; blk_cfg->source_addr_adj = DMA_ADDR_ADJ_NO_CHANGE; } else { @@ -500,6 +522,8 @@ static void spi_stm32_complete(const struct device *dev, int status) #ifdef CONFIG_SPI_STM32_INTERRUPT spi_context_complete(&data->ctx, dev, status); #endif + + spi_stm32_pm_policy_state_lock_put(dev); } #ifdef CONFIG_SPI_STM32_INTERRUPT @@ -768,6 +792,8 @@ static int transceive(const struct device *dev, spi_context_lock(&data->ctx, asynchronous, cb, userdata, config); + spi_stm32_pm_policy_state_lock_get(dev); + ret = spi_stm32_configure(dev, config); if (ret) { goto end; @@ -901,12 +927,13 @@ static int wait_dma_rx_tx_done(const struct device *dev) return res; } -#ifdef CONFIG_SOC_SERIES_STM32H7X +#ifdef CONFIG_DCACHE static bool buf_in_nocache(uintptr_t buf, size_t len_bytes) { bool buf_within_nocache = false; #ifdef CONFIG_NOCACHE_MEMORY + /* Check if buffer is in nocache region defined by the linker */ buf_within_nocache = (buf >= ((uintptr_t)_nocache_ram_start)) && ((buf + len_bytes - 1) <= ((uintptr_t)_nocache_ram_end)); if (buf_within_nocache) { @@ -914,6 +941,7 @@ static bool buf_in_nocache(uintptr_t buf, size_t len_bytes) } #endif /* CONFIG_NOCACHE_MEMORY */ + /* Check if buffer is in nocache memory region defined in DT */ buf_within_nocache = mem_attr_check_buf( (void *)buf, len_bytes, DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE)) == 0; @@ -937,7 +965,7 @@ static bool spi_buf_set_in_nocache(const struct spi_buf_set *bufs) } return true; } -#endif /* CONFIG_SOC_SERIES_STM32H7X */ +#endif /* CONFIG_DCACHE */ static int transceive_dma(const struct device *dev, const struct spi_config *config, @@ -960,15 +988,17 @@ static int transceive_dma(const struct device *dev, return -ENOTSUP; } -#ifdef CONFIG_SOC_SERIES_STM32H7X +#ifdef CONFIG_DCACHE if ((tx_bufs != NULL && !spi_buf_set_in_nocache(tx_bufs)) || (rx_bufs != NULL && !spi_buf_set_in_nocache(rx_bufs))) { return -EFAULT; } -#endif /* CONFIG_SOC_SERIES_STM32H7X */ +#endif /* CONFIG_DCACHE */ spi_context_lock(&data->ctx, asynchronous, cb, userdata, config); + spi_stm32_pm_policy_state_lock_get(dev); + k_sem_reset(&data->status_sem); ret = spi_stm32_configure(dev, config); @@ -1077,6 +1107,8 @@ static int transceive_dma(const struct device *dev, end: spi_context_release(&data->ctx, ret); + spi_stm32_pm_policy_state_lock_put(dev); + return ret; } #endif /* CONFIG_SPI_STM32_DMA */ @@ -1195,8 +1227,61 @@ static int spi_stm32_init(const struct device *dev) spi_context_unlock_unconditionally(&data->ctx); + return pm_device_runtime_enable(dev); +} + +#ifdef CONFIG_PM_DEVICE +static int spi_stm32_pm_action(const struct device *dev, + enum pm_device_action action) +{ + const struct spi_stm32_config *config = dev->config; + const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE); + int err; + + + 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; + } + + /* enable clock */ + err = clock_control_on(clk, (clock_control_subsys_t)&config->pclken[0]); + if (err != 0) { + LOG_ERR("Could not enable SPI clock"); + return err; + } + break; + case PM_DEVICE_ACTION_SUSPEND: + /* Stop device clock. */ + err = clock_control_off(clk, (clock_control_subsys_t)&config->pclken[0]); + if (err != 0) { + LOG_ERR("Could not enable SPI clock"); + return err; + } + + /* 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, + * "SPI pinctrl sleep state not available" + * and don't block PM suspend. + * Else return the error. + */ + return err; + } + break; + default: + return -ENOTSUP; + } + return 0; } +#endif /* CONFIG_PM_DEVICE */ #ifdef CONFIG_SPI_STM32_INTERRUPT #define STM32_SPI_IRQ_HANDLER_DECL(id) \ @@ -1297,7 +1382,9 @@ static struct spi_stm32_data spi_stm32_dev_data_##id = { \ SPI_CONTEXT_CS_GPIOS_INITIALIZE(DT_DRV_INST(id), ctx) \ }; \ \ -DEVICE_DT_INST_DEFINE(id, &spi_stm32_init, NULL, \ +PM_DEVICE_DT_INST_DEFINE(id, spi_stm32_pm_action); \ + \ +DEVICE_DT_INST_DEFINE(id, &spi_stm32_init, PM_DEVICE_DT_INST_GET(id), \ &spi_stm32_dev_data_##id, &spi_stm32_cfg_##id, \ POST_KERNEL, CONFIG_SPI_INIT_PRIORITY, \ &api_funcs); \ diff --git a/drivers/spi/spi_ll_stm32.h b/drivers/spi/spi_ll_stm32.h index 23a08e24208..d0f6ac46dad 100644 --- a/drivers/spi/spi_ll_stm32.h +++ b/drivers/spi/spi_ll_stm32.h @@ -68,6 +68,7 @@ struct spi_stm32_data { struct stream dma_rx; struct stream dma_tx; #endif /* CONFIG_SPI_STM32_DMA */ + bool pm_policy_state_on; }; #ifdef CONFIG_SPI_STM32_DMA diff --git a/drivers/spi/spi_mcux_dspi.c b/drivers/spi/spi_mcux_dspi.c index 14d47db4dd9..12bd97422b9 100644 --- a/drivers/spi/spi_mcux_dspi.c +++ b/drivers/spi/spi_mcux_dspi.c @@ -836,7 +836,7 @@ static const struct spi_driver_api spi_mcux_driver_api = { .dest_data_size = 4, \ .dma_callback = dma_callback, \ .complete_callback_en = 1, \ - .error_callback_en = 1, \ + .error_callback_dis = 0, \ .block_count = 1, \ .head_block = &spi_mcux_data_##id.tx_dma_block, \ .channel_direction = MEMORY_TO_PERIPHERAL, \ @@ -857,7 +857,7 @@ static const struct spi_driver_api spi_mcux_driver_api = { .dest_data_size = 2, \ .dma_callback = dma_callback, \ .complete_callback_en = 1, \ - .error_callback_en = 1, \ + .error_callback_dis = 0, \ .block_count = \ _UTIL_AND2(DT_INST_NODE_HAS_PROP( \ id, nxp_rx_tx_chn_share), 2), \ diff --git a/drivers/spi/spi_mcux_flexcomm.c b/drivers/spi/spi_mcux_flexcomm.c index cb20fcea6e3..411244c21a9 100644 --- a/drivers/spi/spi_mcux_flexcomm.c +++ b/drivers/spi/spi_mcux_flexcomm.c @@ -18,6 +18,7 @@ #include #include #include +#include LOG_MODULE_REGISTER(spi_mcux_flexcomm, CONFIG_SPI_LOG_LEVEL); @@ -37,6 +38,7 @@ struct spi_mcux_config { uint32_t transfer_delay; uint32_t def_char; const struct pinctrl_dev_config *pincfg; + const struct reset_dt_spec reset; }; #ifdef CONFIG_SPI_MCUX_FLEXCOMM_DMA @@ -764,9 +766,19 @@ static int spi_mcux_release(const struct device *dev, static int spi_mcux_init(const struct device *dev) { - int err; const struct spi_mcux_config *config = dev->config; struct spi_mcux_data *data = dev->data; + int err = 0; + + if (!device_is_ready(config->reset.dev)) { + LOG_ERR("Reset device not ready"); + return -ENODEV; + } + + err = reset_line_toggle(config->reset.dev, config->reset.id); + if (err) { + return err; + } config->irq_config_func(dev); @@ -866,6 +878,7 @@ static void spi_mcux_config_func_##id(const struct device *dev) \ .transfer_delay = DT_INST_PROP_OR(id, transfer_delay, 0), \ .def_char = DT_INST_PROP_OR(id, def_char, 0), \ .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(id), \ + .reset = RESET_DT_SPEC_INST_GET(id), \ }; \ static struct spi_mcux_data spi_mcux_data_##id = { \ SPI_CONTEXT_INIT_LOCK(spi_mcux_data_##id, ctx), \ diff --git a/drivers/spi/spi_mcux_lpspi.c b/drivers/spi/spi_mcux_lpspi.c index e946b236aff..5432debd68a 100644 --- a/drivers/spi/spi_mcux_lpspi.c +++ b/drivers/spi/spi_mcux_lpspi.c @@ -135,7 +135,6 @@ static int spi_mcux_transfer_next_packet(const struct device *dev) transfer.txData = (uint8_t *) ctx->tx_buf; transfer.rxData = ctx->rx_buf; transfer.dataSize = ctx->rx_len; - transfer.configFlags |= kLPSPI_MasterPcsContinuous; } else { /* Break up the rx into multiple transfers so we don't have to * tx from a longer intermediate buffer. Leave chip select @@ -144,11 +143,6 @@ static int spi_mcux_transfer_next_packet(const struct device *dev) transfer.txData = (uint8_t *) ctx->tx_buf; transfer.rxData = ctx->rx_buf; transfer.dataSize = ctx->tx_len; - transfer.configFlags |= kLPSPI_MasterPcsContinuous; - } - - if (!(ctx->tx_count <= 1 && ctx->rx_count <= 1)) { - transfer.configFlags |= kLPSPI_MasterPcsContinuous; } data->transfer_len = transfer.dataSize; diff --git a/drivers/spi/spi_rpi_pico_pio.c b/drivers/spi/spi_rpi_pico_pio.c index ed5179e3466..c7eb014d9d5 100644 --- a/drivers/spi/spi_rpi_pico_pio.c +++ b/drivers/spi/spi_rpi_pico_pio.c @@ -22,6 +22,8 @@ LOG_MODULE_REGISTER(spi_pico_pio); #include #include "hardware/clocks.h" +#define SPI_RPI_PICO_PIO_HALF_DUPLEX_ENABLED DT_ANY_INST_HAS_PROP_STATUS_OKAY(sio_gpios) + #define PIO_CYCLES (4) #define PIO_FIFO_DEPTH (4) @@ -31,6 +33,7 @@ struct spi_pico_pio_config { struct gpio_dt_spec clk_gpio; struct gpio_dt_spec mosi_gpio; struct gpio_dt_spec miso_gpio; + struct gpio_dt_spec sio_gpio; const struct device *clk_dev; clock_control_subsys_t clk_id; }; @@ -41,17 +44,39 @@ struct spi_pico_pio_data { uint32_t rx_count; PIO pio; size_t pio_sm; + uint32_t pio_tx_offset; + uint32_t pio_rx_offset; + uint32_t pio_rx_wrap_target; + uint32_t pio_rx_wrap; + uint32_t tx_period_ticks; + uint32_t bits; uint32_t dfs; }; -RPI_PICO_PIO_DEFINE_PROGRAM(spi_cpol_0_cpha_0, 0, 1, +/* ------------ */ +/* spi_mode_0_0 */ +/* ------------ */ + +#define SPI_MODE_0_0_WRAP_TARGET 0 +#define SPI_MODE_0_0_WRAP 1 +#define SPI_MODE_0_0_CYCLES 4 + +RPI_PICO_PIO_DEFINE_PROGRAM(spi_mode_0_0, SPI_MODE_0_0_WRAP_TARGET, SPI_MODE_0_0_WRAP, /* .wrap_target */ 0x6101, /* 0: out pins, 1 side 0 [1] */ 0x5101, /* 1: in pins, 1 side 1 [1] */ /* .wrap */ ); -RPI_PICO_PIO_DEFINE_PROGRAM(spi_cpol_1_cpha_1, 0, 2, +/* ------------ */ +/* spi_mode_1_1 */ +/* ------------ */ + +#define SPI_MODE_1_1_WRAP_TARGET 0 +#define SPI_MODE_1_1_WRAP 2 +#define SPI_MODE_1_1_CYCLES 4 + +RPI_PICO_PIO_DEFINE_PROGRAM(spi_mode_1_1, SPI_MODE_1_1_WRAP_TARGET, SPI_MODE_1_1_WRAP, /* .wrap_target */ 0x7021, /* 0: out x, 1 side 1 */ 0xa101, /* 1: mov pins, x side 0 [1] */ @@ -59,19 +84,102 @@ RPI_PICO_PIO_DEFINE_PROGRAM(spi_cpol_1_cpha_1, 0, 2, /* .wrap */ ); -static float spi_pico_pio_clock_divisor(const uint32_t clock_freq, uint32_t spi_frequency) +#if SPI_RPI_PICO_PIO_HALF_DUPLEX_ENABLED +/* ------------------- */ +/* spi_sio_mode_0_0_tx */ +/* ------------------- */ + +#define SPI_SIO_MODE_0_0_TX_WRAP_TARGET 0 +#define SPI_SIO_MODE_0_0_TX_WRAP 2 +#define SPI_SIO_MODE_0_0_TX_CYCLES 2 + +RPI_PICO_PIO_DEFINE_PROGRAM(spi_sio_mode_0_0_tx, SPI_SIO_MODE_0_0_TX_WRAP_TARGET, + SPI_SIO_MODE_0_0_TX_WRAP, + /* .wrap_target */ + 0x80a0, /* 0: pull block side 0 */ + 0x6001, /* 1: out pins, 1 side 0 */ + 0x10e1, /* 2: jmp !osre, 1 side 1 */ + /* .wrap */ +); + +/* ------------------------- */ +/* spi_sio_mode_0_0_8_bit_rx */ +/* ------------------------- */ + +#define SPI_SIO_MODE_0_0_8_BIT_RX_WRAP_TARGET 0 +#define SPI_SIO_MODE_0_0_8_BIT_RX_WRAP 6 +#define SPI_SIO_MODE_0_0_8_BIT_RX_CYCLES 2 + +RPI_PICO_PIO_DEFINE_PROGRAM(spi_sio_mode_0_0_8_bit_rx, SPI_SIO_MODE_0_0_8_BIT_RX_WRAP_TARGET, + SPI_SIO_MODE_0_0_8_BIT_RX_WRAP, + /* .wrap_target */ + 0x80a0, /* 0: pull block side 0 */ + 0x6020, /* 1: out x, 32 side 0 */ + 0xe047, /* 2: set y, 7 side 0 */ + 0x5001, /* 3: in pins, 1 side 1 */ + 0x0083, /* 4: jmp y--, 3 side 0 */ + 0x8020, /* 5: push block side 0 */ + 0x0042, /* 6: jmp x--, 2 side 0 */ + /* .wrap */ +); + +/* -------------------------- */ +/* spi_sio_mode_0_0_16_bit_rx */ +/* -------------------------- */ + +#define SPI_SIO_MODE_0_0_16_BIT_RX_WRAP_TARGET 0 +#define SPI_SIO_MODE_0_0_16_BIT_RX_WRAP 6 +#define SPI_SIO_MODE_0_0_16_BIT_RX_CYCLES 2 + +RPI_PICO_PIO_DEFINE_PROGRAM(spi_sio_mode_0_0_16_bit_rx, SPI_SIO_MODE_0_0_16_BIT_RX_WRAP_TARGET, + SPI_SIO_MODE_0_0_16_BIT_RX_WRAP, + /* .wrap_target */ + 0x80a0, /* 0: pull block side 0 */ + 0x6020, /* 1: out x, 32 side 0 */ + 0xe04f, /* 2: set y, 15 side 0 */ + 0x5001, /* 3: in pins, 1 side 1 */ + 0x0083, /* 4: jmp y--, 3 side 0 */ + 0x8020, /* 5: push block side 0 */ + 0x0042, /* 6: jmp x--, 2 side 0 */ + /* .wrap */ +); + +/* -------------------------- */ +/* spi_sio_mode_0_0_32_bit_rx */ +/* -------------------------- */ + +#define SPI_SIO_MODE_0_0_32_BIT_RX_WRAP_TARGET 0 +#define SPI_SIO_MODE_0_0_32_BIT_RX_WRAP 6 +#define SPI_SIO_MODE_0_0_32_BIT_RX_CYCLES 2 + +RPI_PICO_PIO_DEFINE_PROGRAM(spi_sio_mode_0_0_32_bit_rx, SPI_SIO_MODE_0_0_32_BIT_RX_WRAP_TARGET, + SPI_SIO_MODE_0_0_32_BIT_RX_WRAP, + /* .wrap_target */ + 0x80a0, /* 0: pull block side 0 */ + 0x6020, /* 1: out x, 32 side 0 */ + 0xe05f, /* 2: set y, 31 side 0 */ + 0x5001, /* 3: in pins, 1 side 1 */ + 0x0083, /* 4: jmp y--, 3 side 0 */ + 0x8020, /* 5: push block side 0 */ + 0x0042, /* 6: jmp x--, 2 side 0 */ + /* .wrap */ +); +#endif /* SPI_RPI_PICO_PIO_HALF_DUPLEX_ENABLED */ + +static float spi_pico_pio_clock_divisor(const uint32_t clock_freq, int cycles, + uint32_t spi_frequency) { - return (float)clock_freq / (float)(PIO_CYCLES * spi_frequency); + return (float)clock_freq / (float)(cycles * spi_frequency); } -static uint32_t spi_pico_pio_maximum_clock_frequency(const uint32_t clock_freq) +static uint32_t spi_pico_pio_maximum_clock_frequency(const uint32_t clock_freq, int cycles) { - return clock_freq / PIO_CYCLES; + return clock_freq / cycles; } -static uint32_t spi_pico_pio_minimum_clock_frequency(const uint32_t clock_freq) +static uint32_t spi_pico_pio_minimum_clock_frequency(const uint32_t clock_freq, int cycles) { - return clock_freq / (PIO_CYCLES * 65536); + return clock_freq / (cycles * 65536); } static inline bool spi_pico_pio_transfer_ongoing(struct spi_pico_pio_data *data) @@ -97,23 +205,51 @@ static inline uint8_t spi_pico_pio_sm_get8(PIO pio, uint sm) return *rxfifo; } +static inline void spi_pico_pio_sm_put16(PIO pio, uint sm, uint16_t data) +{ + /* Do 16 bit accesses on FIFO, so that write data is halfword-replicated. This */ + /* gets us the left-justification for free (for MSB-first shift-out) */ + io_rw_16 *txfifo = (io_rw_16 *)&pio->txf[sm]; + + *txfifo = data; +} + +static inline uint16_t spi_pico_pio_sm_get16(PIO pio, uint sm) +{ + io_rw_16 *rxfifo = (io_rw_16 *)&pio->rxf[sm]; + + return *rxfifo; +} + +static inline void spi_pico_pio_sm_put32(PIO pio, uint sm, uint32_t data) +{ + io_rw_32 *txfifo = (io_rw_32 *)&pio->txf[sm]; + + *txfifo = data; +} + +static inline uint32_t spi_pico_pio_sm_get32(PIO pio, uint sm) +{ + io_rw_32 *rxfifo = (io_rw_32 *)&pio->rxf[sm]; + + return *rxfifo; +} + +static inline int spi_pico_pio_sm_complete(struct spi_pico_pio_data *data) +{ + return (data->pio->sm[data->pio_sm].addr == data->pio_tx_offset); +} + static int spi_pico_pio_configure(const struct spi_pico_pio_config *dev_cfg, struct spi_pico_pio_data *data, const struct spi_config *spi_cfg) { - const struct gpio_dt_spec *miso; - const struct gpio_dt_spec *mosi; - const struct gpio_dt_spec *clk; + const struct gpio_dt_spec *clk = NULL; pio_sm_config sm_config; - uint32_t offset; - uint32_t wrap_target; - uint32_t wrap; + bool lsb = false; uint32_t cpol = 0; uint32_t cpha = 0; - uint32_t bits; + uint32_t rc = 0; 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) { @@ -136,9 +272,12 @@ static int spi_pico_pio_configure(const struct spi_pico_pio_config *dev_cfg, return -ENOTSUP; } + /* Note that SPI_TRANSFER_LSB controls the direction of shift, not the */ + /* "endianness" of the data. In MSB mode, the high-order bit of the */ + /* most significant byte is sent first; in LSB mode, the low-order */ + /* bit of the least-significant byte is sent first. */ if (spi_cfg->operation & SPI_TRANSFER_LSB) { - LOG_ERR("Unsupported configuration"); - return -ENOTSUP; + lsb = true; } #if defined(CONFIG_SPI_EXTENDED_MODES) @@ -148,27 +287,17 @@ static int spi_pico_pio_configure(const struct spi_pico_pio_config *dev_cfg, } #endif /* CONFIG_SPI_EXTENDED_MODES */ - bits = SPI_WORD_SIZE_GET(spi_cfg->operation); + data->bits = SPI_WORD_SIZE_GET(spi_cfg->operation); - if (bits != 8) { - LOG_ERR("Only 8 bit word size is supported"); + if ((data->bits != 8) && (data->bits != 16) && (data->bits != 32)) { + LOG_ERR("Only 8, 16, and 32 bit word sizes are supported"); return -ENOTSUP; } - data->dfs = DIV_ROUND_UP(bits, 8); + data->dfs = ((data->bits - 1) / 8) + 1; - 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(clock_freq, spi_cfg->frequency); - - /* Half-duplex mode has not been implemented */ - if (spi_cfg->operation & SPI_HALF_DUPLEX) { - LOG_ERR("Half-duplex not supported"); - return -ENOTSUP; + if (spi_cfg->operation & SPI_CS_ACTIVE_HIGH) { + gpio_set_outover(data->spi_ctx.config->cs.gpio.pin, GPIO_OVERRIDE_INVERT); } if (SPI_MODE_GET(spi_cfg->operation) & SPI_MODE_CPOL) { @@ -182,8 +311,31 @@ static int spi_pico_pio_configure(const struct spi_pico_pio_config *dev_cfg, return -ENOTSUP; } - mosi = &dev_cfg->mosi_gpio; - miso = &dev_cfg->miso_gpio; +#if SPI_RPI_PICO_PIO_HALF_DUPLEX_ENABLED + if (spi_cfg->operation & SPI_HALF_DUPLEX) { + if ((cpol != 0) || (cpha != 0)) { + LOG_ERR("Only mode (0, 0) supported in 3-wire SIO"); + return -ENOTSUP; + } + + if ((spi_cfg->frequency > spi_pico_pio_maximum_clock_frequency( + clock_freq, SPI_SIO_MODE_0_0_TX_CYCLES)) || + (spi_cfg->frequency < spi_pico_pio_minimum_clock_frequency( + clock_freq, SPI_SIO_MODE_0_0_TX_CYCLES))) { + LOG_ERR("clock-frequency out of range"); + return -EINVAL; + } + } else if (dev_cfg->sio_gpio.port) { + LOG_ERR("SPI_HALF_DUPLEX operation needed for sio-gpios"); + return -EINVAL; + } +#else + if (spi_cfg->operation & SPI_HALF_DUPLEX) { + LOG_ERR("No sio-gpios defined, half-duplex not enabled"); + return -EINVAL; + } +#endif /* SPI_RPI_PICO_PIO_HALF_DUPLEX_ENABLED */ + clk = &dev_cfg->clk_gpio; data->pio = pio_rpi_pico_get_pio(dev_cfg->piodev); rc = pio_rpi_pico_allocate_sm(dev_cfg->piodev, &data->pio_sm); @@ -191,53 +343,156 @@ static int spi_pico_pio_configure(const struct spi_pico_pio_config *dev_cfg, return rc; } - if ((cpol == 0) && (cpha == 0)) { - program = RPI_PICO_PIO_GET_PROGRAM(spi_cpol_0_cpha_0); - wrap_target = RPI_PICO_PIO_GET_WRAP_TARGET(spi_cpol_0_cpha_0); - wrap = RPI_PICO_PIO_GET_WRAP(spi_cpol_0_cpha_0); - } else if ((cpol == 1) && (cpha == 1)) { - program = RPI_PICO_PIO_GET_PROGRAM(spi_cpol_1_cpha_1); - wrap_target = RPI_PICO_PIO_GET_WRAP_TARGET(spi_cpol_1_cpha_1); - wrap = RPI_PICO_PIO_GET_WRAP(spi_cpol_1_cpha_1); + if (dev_cfg->sio_gpio.port) { +#if SPI_RPI_PICO_PIO_HALF_DUPLEX_ENABLED + const struct gpio_dt_spec *sio = &dev_cfg->sio_gpio; + + float clock_div = spi_pico_pio_clock_divisor(clock_freq, SPI_SIO_MODE_0_0_TX_CYCLES, + spi_cfg->frequency); + data->tx_period_ticks = DIV_ROUND_UP((data->bits * CONFIG_SYS_CLOCK_TICKS_PER_SEC), + spi_cfg->frequency); + + data->pio_tx_offset = + pio_add_program(data->pio, RPI_PICO_PIO_GET_PROGRAM(spi_sio_mode_0_0_tx)); + + switch (data->dfs) { + case 4: + data->pio_rx_offset = pio_add_program( + data->pio, RPI_PICO_PIO_GET_PROGRAM(spi_sio_mode_0_0_32_bit_rx)); + data->pio_rx_wrap_target = + data->pio_rx_offset + + RPI_PICO_PIO_GET_WRAP_TARGET(spi_sio_mode_0_0_32_bit_rx); + data->pio_rx_wrap = data->pio_rx_offset + + RPI_PICO_PIO_GET_WRAP(spi_sio_mode_0_0_32_bit_rx); + break; + + case 2: + data->pio_rx_offset = pio_add_program( + data->pio, RPI_PICO_PIO_GET_PROGRAM(spi_sio_mode_0_0_16_bit_rx)); + data->pio_rx_wrap_target = + data->pio_rx_offset + + RPI_PICO_PIO_GET_WRAP_TARGET(spi_sio_mode_0_0_16_bit_rx); + data->pio_rx_wrap = data->pio_rx_offset + + RPI_PICO_PIO_GET_WRAP(spi_sio_mode_0_0_16_bit_rx); + break; + + case 1: + data->pio_rx_offset = pio_add_program( + data->pio, RPI_PICO_PIO_GET_PROGRAM(spi_sio_mode_0_0_8_bit_rx)); + data->pio_rx_wrap_target = + data->pio_rx_offset + + RPI_PICO_PIO_GET_WRAP_TARGET(spi_sio_mode_0_0_8_bit_rx); + data->pio_rx_wrap = data->pio_rx_offset + + RPI_PICO_PIO_GET_WRAP(spi_sio_mode_0_0_8_bit_rx); + break; + + default: + LOG_ERR("Support for %d transfer size not enabled", (data->dfs * 8)); + return -EINVAL; + } + + sm_config = pio_get_default_sm_config(); + + sm_config_set_clkdiv(&sm_config, clock_div); + sm_config_set_in_pins(&sm_config, sio->pin); + sm_config_set_in_shift(&sm_config, lsb, false, data->bits); + sm_config_set_out_pins(&sm_config, sio->pin, 1); + sm_config_set_out_shift(&sm_config, lsb, false, data->bits); + hw_set_bits(&data->pio->input_sync_bypass, 1u << sio->pin); + + sm_config_set_sideset_pins(&sm_config, clk->pin); + sm_config_set_sideset(&sm_config, 1, false, false); + sm_config_set_wrap( + &sm_config, + data->pio_tx_offset + RPI_PICO_PIO_GET_WRAP_TARGET(spi_sio_mode_0_0_tx), + data->pio_tx_offset + RPI_PICO_PIO_GET_WRAP(spi_sio_mode_0_0_tx)); + + pio_sm_set_pindirs_with_mask(data->pio, data->pio_sm, + (BIT(clk->pin) | BIT(sio->pin)), + (BIT(clk->pin) | BIT(sio->pin))); + pio_sm_set_pins_with_mask(data->pio, data->pio_sm, 0, + BIT(clk->pin) | BIT(sio->pin)); + pio_gpio_init(data->pio, sio->pin); + pio_gpio_init(data->pio, clk->pin); + + pio_sm_init(data->pio, data->pio_sm, data->pio_tx_offset, &sm_config); + pio_sm_set_enabled(data->pio, data->pio_sm, true); +#else + LOG_ERR("SIO pin requires half-duplex support"); + return -EINVAL; +#endif /* SPI_RPI_PICO_PIO_HALF_DUPLEX_ENABLED */ } else { - LOG_ERR("Not supported: cpol=%d, cpha=%d\n", cpol, cpha); - return -ENOTSUP; - } + /* 4-wire mode */ + const struct gpio_dt_spec *miso = miso = &dev_cfg->miso_gpio; + const struct gpio_dt_spec *mosi = &dev_cfg->mosi_gpio; + const pio_program_t *program; + uint32_t wrap_target; + uint32_t wrap; + int cycles; + + if ((cpol == 0) && (cpha == 0)) { + program = RPI_PICO_PIO_GET_PROGRAM(spi_mode_0_0); + wrap_target = RPI_PICO_PIO_GET_WRAP_TARGET(spi_mode_0_0); + wrap = RPI_PICO_PIO_GET_WRAP(spi_mode_0_0); + cycles = SPI_MODE_0_0_CYCLES; + } else if ((cpol == 1) && (cpha == 1)) { + program = RPI_PICO_PIO_GET_PROGRAM(spi_mode_1_1); + wrap_target = RPI_PICO_PIO_GET_WRAP_TARGET(spi_mode_1_1); + wrap = RPI_PICO_PIO_GET_WRAP(spi_mode_1_1); + cycles = SPI_MODE_1_1_CYCLES; + } else { + LOG_ERR("Not supported: cpol=%d, cpha=%d\n", cpol, cpha); + return -ENOTSUP; + } - if (!pio_can_add_program(data->pio, program)) { - return -EBUSY; - } + if ((spi_cfg->frequency > + spi_pico_pio_maximum_clock_frequency(clock_freq, cycles)) || + (spi_cfg->frequency < + spi_pico_pio_minimum_clock_frequency(clock_freq, cycles))) { + LOG_ERR("clock-frequency out of range"); + return -EINVAL; + } - offset = pio_add_program(data->pio, program); - sm_config = pio_get_default_sm_config(); - - sm_config_set_clkdiv(&sm_config, clock_div); - sm_config_set_in_pins(&sm_config, miso->pin); - sm_config_set_in_shift(&sm_config, false, true, bits); - sm_config_set_out_pins(&sm_config, mosi->pin, 1); - sm_config_set_out_shift(&sm_config, false, true, bits); - sm_config_set_sideset_pins(&sm_config, clk->pin); - sm_config_set_sideset(&sm_config, 1, false, false); - sm_config_set_wrap(&sm_config, offset + wrap_target, offset + wrap); - - pio_sm_set_consecutive_pindirs(data->pio, data->pio_sm, miso->pin, 1, false); - pio_sm_set_pindirs_with_mask(data->pio, data->pio_sm, (BIT(clk->pin) | BIT(mosi->pin)), - (BIT(clk->pin) | BIT(mosi->pin))); - pio_sm_set_pins_with_mask(data->pio, data->pio_sm, (cpol << clk->pin), - BIT(clk->pin) | BIT(mosi->pin)); - pio_gpio_init(data->pio, mosi->pin); - pio_gpio_init(data->pio, miso->pin); - pio_gpio_init(data->pio, clk->pin); - - pio_sm_init(data->pio, data->pio_sm, offset, &sm_config); - pio_sm_set_enabled(data->pio, data->pio_sm, true); + float clock_div = + spi_pico_pio_clock_divisor(clock_freq, cycles, spi_cfg->frequency); + + if (!pio_can_add_program(data->pio, program)) { + return -EBUSY; + } + + data->pio_tx_offset = pio_add_program(data->pio, program); + sm_config = pio_get_default_sm_config(); + + sm_config_set_clkdiv(&sm_config, clock_div); + sm_config_set_in_pins(&sm_config, miso->pin); + sm_config_set_in_shift(&sm_config, lsb, true, data->bits); + sm_config_set_out_pins(&sm_config, mosi->pin, 1); + sm_config_set_out_shift(&sm_config, lsb, true, data->bits); + sm_config_set_sideset_pins(&sm_config, clk->pin); + sm_config_set_sideset(&sm_config, 1, false, false); + sm_config_set_wrap(&sm_config, data->pio_tx_offset + wrap_target, + data->pio_tx_offset + wrap); + + pio_sm_set_consecutive_pindirs(data->pio, data->pio_sm, miso->pin, 1, false); + pio_sm_set_pindirs_with_mask(data->pio, data->pio_sm, + (BIT(clk->pin) | BIT(mosi->pin)), + (BIT(clk->pin) | BIT(mosi->pin))); + pio_sm_set_pins_with_mask(data->pio, data->pio_sm, (cpol << clk->pin), + BIT(clk->pin) | BIT(mosi->pin)); + pio_gpio_init(data->pio, mosi->pin); + pio_gpio_init(data->pio, miso->pin); + pio_gpio_init(data->pio, clk->pin); + + pio_sm_init(data->pio, data->pio_sm, data->pio_tx_offset, &sm_config); + pio_sm_set_enabled(data->pio, data->pio_sm, true); + } data->spi_ctx.config = spi_cfg; return 0; } -static void spi_pico_pio_txrx(const struct device *dev) +static void spi_pico_pio_txrx_4_wire(const struct device *dev) { struct spi_pico_pio_data *data = dev->data; const size_t chunk_len = spi_context_max_continuous_chunk(&data->spi_ctx); @@ -258,28 +513,204 @@ static void spi_pico_pio_txrx(const struct device *dev) /* Send 0 in the case of read only operation */ txrx = 0; - if (txbuf) { - txrx = ((uint8_t *)txbuf)[data->tx_count]; + switch (data->dfs) { + case 4: { + if (txbuf) { + txrx = ((uint32_t *)txbuf)[data->tx_count]; + } + spi_pico_pio_sm_put32(data->pio, data->pio_sm, txrx); + data->tx_count += 4; + } break; + + case 2: { + if (txbuf) { + txrx = ((uint16_t *)txbuf)[data->tx_count]; + } + spi_pico_pio_sm_put16(data->pio, data->pio_sm, txrx); + data->tx_count += 2; + } break; + + case 1: { + if (txbuf) { + txrx = ((uint8_t *)txbuf)[data->tx_count]; + } + spi_pico_pio_sm_put8(data->pio, data->pio_sm, txrx); + data->tx_count++; + } break; + + default: + LOG_ERR("Support fot %d bits not enabled", (data->dfs * 8)); + break; } - spi_pico_pio_sm_put8(data->pio, data->pio_sm, txrx); - data->tx_count++; fifo_cnt++; } while ((!pio_sm_is_rx_fifo_empty(data->pio, data->pio_sm)) && data->rx_count < chunk_len && fifo_cnt > 0) { - txrx = spi_pico_pio_sm_get8(data->pio, data->pio_sm); - - /* Discard received data if rx buffer not assigned */ - if (rxbuf) { - ((uint8_t *)rxbuf)[data->rx_count] = (uint8_t)txrx; + switch (data->dfs) { + case 4: { + txrx = spi_pico_pio_sm_get32(data->pio, data->pio_sm); + + /* Discard received data if rx buffer not assigned */ + if (rxbuf) { + ((uint32_t *)rxbuf)[data->rx_count] = (uint32_t)txrx; + } + data->rx_count += 4; + } break; + + case 2: { + txrx = spi_pico_pio_sm_get16(data->pio, data->pio_sm); + + /* Discard received data if rx buffer not assigned */ + if (rxbuf) { + ((uint16_t *)rxbuf)[data->rx_count] = (uint16_t)txrx; + } + data->rx_count += 2; + } break; + + case 1: { + txrx = spi_pico_pio_sm_get8(data->pio, data->pio_sm); + + /* Discard received data if rx buffer not assigned */ + if (rxbuf) { + ((uint8_t *)rxbuf)[data->rx_count] = (uint8_t)txrx; + } + data->rx_count++; + } break; + + default: + LOG_ERR("Support fot %d bits not enabled", (data->dfs * 8)); + break; } - data->rx_count++; fifo_cnt--; } } } +static void spi_pico_pio_txrx_3_wire(const struct device *dev) +{ +#if SPI_RPI_PICO_PIO_HALF_DUPLEX_ENABLED + struct spi_pico_pio_data *data = dev->data; + const struct spi_pico_pio_config *dev_cfg = dev->config; + const void *txbuf = data->spi_ctx.tx_buf; + void *rxbuf = data->spi_ctx.rx_buf; + uint32_t txrx; + int sio_pin = dev_cfg->sio_gpio.pin; + uint32_t tx_size = data->spi_ctx.tx_len; /* Number of WORDS to send */ + uint32_t rx_size = data->spi_ctx.rx_len; /* Number of WORDS to receive */ + + data->tx_count = 0; + data->rx_count = 0; + + if (txbuf) { + pio_sm_set_enabled(data->pio, data->pio_sm, false); + pio_sm_set_wrap(data->pio, data->pio_sm, + data->pio_tx_offset + + RPI_PICO_PIO_GET_WRAP_TARGET(spi_sio_mode_0_0_tx), + data->pio_tx_offset + RPI_PICO_PIO_GET_WRAP(spi_sio_mode_0_0_tx)); + pio_sm_clear_fifos(data->pio, data->pio_sm); + pio_sm_set_pindirs_with_mask(data->pio, data->pio_sm, BIT(sio_pin), BIT(sio_pin)); + pio_sm_restart(data->pio, data->pio_sm); + pio_sm_clkdiv_restart(data->pio, data->pio_sm); + pio_sm_exec(data->pio, data->pio_sm, pio_encode_jmp(data->pio_tx_offset)); + pio_sm_set_enabled(data->pio, data->pio_sm, true); + + while (data->tx_count < tx_size) { + /* Fill up fifo with available TX data */ + while ((!pio_sm_is_tx_fifo_full(data->pio, data->pio_sm)) && + data->tx_count < tx_size) { + + switch (data->dfs) { + case 4: { + txrx = ((uint32_t *)txbuf)[data->tx_count]; + spi_pico_pio_sm_put32(data->pio, data->pio_sm, txrx); + data->tx_count += 4; + } break; + + case 2: { + txrx = ((uint16_t *)txbuf)[data->tx_count]; + spi_pico_pio_sm_put16(data->pio, data->pio_sm, txrx); + data->tx_count += 2; + } break; + + case 1: { + txrx = ((uint8_t *)txbuf)[data->tx_count]; + spi_pico_pio_sm_put8(data->pio, data->pio_sm, txrx); + data->tx_count++; + } break; + + default: + LOG_ERR("Support fot %d bits not enabled", (data->dfs * 8)); + break; + } + } + } + while ((!pio_sm_is_tx_fifo_empty(data->pio, data->pio_sm)) || + (!spi_pico_pio_sm_complete(data))) { + k_sleep(K_TICKS(data->tx_period_ticks)); + } + } + + if (rxbuf) { + pio_sm_set_enabled(data->pio, data->pio_sm, false); + pio_sm_set_wrap(data->pio, data->pio_sm, data->pio_rx_wrap_target, + data->pio_rx_wrap); + pio_sm_clear_fifos(data->pio, data->pio_sm); + pio_sm_set_pindirs_with_mask(data->pio, data->pio_sm, 0, BIT(sio_pin)); + pio_sm_restart(data->pio, data->pio_sm); + pio_sm_clkdiv_restart(data->pio, data->pio_sm); + pio_sm_put(data->pio, data->pio_sm, rx_size - 1); + pio_sm_exec(data->pio, data->pio_sm, pio_encode_out(pio_x, 32)); + pio_sm_exec(data->pio, data->pio_sm, pio_encode_jmp(data->pio_rx_offset)); + pio_sm_set_enabled(data->pio, data->pio_sm, true); + + while (data->rx_count < rx_size) { + while ((!pio_sm_is_rx_fifo_empty(data->pio, data->pio_sm)) && + data->rx_count < rx_size) { + + switch (data->dfs) { + case 4: { + txrx = spi_pico_pio_sm_get32(data->pio, data->pio_sm); + ((uint32_t *)rxbuf)[data->rx_count] = (uint32_t)txrx; + data->rx_count += 4; + } break; + + case 2: { + txrx = spi_pico_pio_sm_get16(data->pio, data->pio_sm); + ((uint16_t *)rxbuf)[data->rx_count] = (uint16_t)txrx; + data->rx_count += 2; + } break; + + case 1: { + txrx = spi_pico_pio_sm_get8(data->pio, data->pio_sm); + ((uint8_t *)rxbuf)[data->rx_count] = (uint8_t)txrx; + data->rx_count++; + } break; + + default: + LOG_ERR("Support fot %d bits not enabled", (data->dfs * 8)); + break; + } + } + } + } +#else + LOG_ERR("SIO pin requires half-duplex support"); +#endif /* SPI_RPI_PICO_PIO_HALF_DUPLEX_ENABLED */ +} + +static void spi_pico_pio_txrx(const struct device *dev) +{ + const struct spi_pico_pio_config *dev_cfg = dev->config; + + /* 3-wire or 4-wire mode? */ + if (dev_cfg->sio_gpio.port) { + spi_pico_pio_txrx_3_wire(dev); + } else { + spi_pico_pio_txrx_4_wire(dev); + } +} + static int spi_pico_pio_transceive_impl(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, @@ -335,6 +766,24 @@ static const struct spi_driver_api spi_pico_pio_api = { .release = spi_pico_pio_release, }; +static int config_gpio(const struct gpio_dt_spec *gpio, const char *tag, int mode) +{ + int rc = 0; + + if (!device_is_ready(gpio->port)) { + LOG_ERR("GPIO port for %s pin is not ready", tag); + return -ENODEV; + } + + rc = gpio_pin_configure_dt(gpio, mode); + if (rc < 0) { + LOG_ERR("Couldn't configure %s pin; (%d)", tag, rc); + return rc; + } + + return 0; +} + int spi_pico_pio_init(const struct device *dev) { const struct spi_pico_pio_config *dev_cfg = dev->config; @@ -347,6 +796,25 @@ int spi_pico_pio_init(const struct device *dev) return rc; } + rc = config_gpio(&dev_cfg->clk_gpio, "clk", GPIO_OUTPUT_ACTIVE); + if (rc < 0) { + return rc; + } + + if (dev_cfg->mosi_gpio.port != NULL) { + rc = config_gpio(&dev_cfg->mosi_gpio, "mosi", GPIO_OUTPUT); + if (rc < 0) { + return rc; + } + } + + if (dev_cfg->miso_gpio.port != NULL) { + rc = config_gpio(&dev_cfg->miso_gpio, "miso", GPIO_INPUT); + if (rc < 0) { + return rc; + } + } + rc = spi_context_cs_configure_all(&data->spi_ctx); if (rc < 0) { LOG_ERR("Failed to configure CS pins: %d", rc); @@ -358,26 +826,32 @@ int spi_pico_pio_init(const struct device *dev) return 0; } -#define SPI_PICO_PIO_INIT(inst) \ - PINCTRL_DT_INST_DEFINE(inst); \ - static struct spi_pico_pio_config spi_pico_pio_config_##inst = { \ - .piodev = DEVICE_DT_GET(DT_INST_PARENT(inst)), \ - .pin_cfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \ - .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}), \ - .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), \ - SPI_CONTEXT_INIT_SYNC(spi_pico_pio_data_##inst, spi_ctx), \ - SPI_CONTEXT_CS_GPIOS_INITIALIZE(DT_DRV_INST(inst), spi_ctx)}; \ - DEVICE_DT_INST_DEFINE(inst, spi_pico_pio_init, NULL, &spi_pico_pio_data_##inst, \ - &spi_pico_pio_config_##inst, POST_KERNEL, CONFIG_SPI_INIT_PRIORITY, \ - &spi_pico_pio_api); \ - BUILD_ASSERT(DT_INST_NODE_HAS_PROP(inst, clk_gpios)); \ - BUILD_ASSERT(DT_INST_NODE_HAS_PROP(inst, mosi_gpios)); \ - BUILD_ASSERT(DT_INST_NODE_HAS_PROP(inst, miso_gpios)); +#define SPI_PICO_PIO_INIT(inst) \ + PINCTRL_DT_INST_DEFINE(inst); \ + static struct spi_pico_pio_config spi_pico_pio_config_##inst = { \ + .piodev = DEVICE_DT_GET(DT_INST_PARENT(inst)), \ + .pin_cfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \ + .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}), \ + .sio_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, sio_gpios, {0}), \ + .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), \ + SPI_CONTEXT_INIT_SYNC(spi_pico_pio_data_##inst, spi_ctx), \ + SPI_CONTEXT_CS_GPIOS_INITIALIZE(DT_DRV_INST(inst), spi_ctx)}; \ + DEVICE_DT_INST_DEFINE(inst, spi_pico_pio_init, NULL, &spi_pico_pio_data_##inst, \ + &spi_pico_pio_config_##inst, POST_KERNEL, CONFIG_SPI_INIT_PRIORITY, \ + &spi_pico_pio_api); \ + BUILD_ASSERT(DT_INST_NODE_HAS_PROP(inst, clk_gpios), "Missing clock GPIO"); \ + BUILD_ASSERT(((DT_INST_NODE_HAS_PROP(inst, mosi_gpios) \ + || DT_INST_NODE_HAS_PROP(inst, miso_gpios)) \ + && (!DT_INST_NODE_HAS_PROP(inst, sio_gpios))) \ + || (DT_INST_NODE_HAS_PROP(inst, sio_gpios) \ + && !(DT_INST_NODE_HAS_PROP(inst, mosi_gpios) \ + || DT_INST_NODE_HAS_PROP(inst, miso_gpios))), \ + "Invalid GPIO Configuration"); DT_INST_FOREACH_STATUS_OKAY(SPI_PICO_PIO_INIT) diff --git a/drivers/spi/spi_sam.c b/drivers/spi/spi_sam.c index ebc0b9758e4..7cb6e8dc90c 100644 --- a/drivers/spi/spi_sam.c +++ b/drivers/spi/spi_sam.c @@ -340,7 +340,6 @@ static int spi_sam_dma_txrx(const struct device *dev, .source_burst_length = 1, .dest_burst_length = 1, .complete_callback_en = true, - .error_callback_en = true, .dma_callback = NULL, .user_data = (void *)dev, }; @@ -373,7 +372,6 @@ static int spi_sam_dma_txrx(const struct device *dev, .source_burst_length = 1, .dest_burst_length = 1, .complete_callback_en = true, - .error_callback_en = true, .dma_callback = dma_callback, .user_data = (void *)dev, }; diff --git a/drivers/spi/spi_shell.c b/drivers/spi/spi_shell.c new file mode 100644 index 00000000000..a7e01d3e270 --- /dev/null +++ b/drivers/spi/spi_shell.c @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2024 Astrolight + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +#define TXRX_ARGV_BYTES (1) +#define CONF_ARGV_DEV (1) +#define CONF_ARGV_FREQUENCY (2) +#define CONF_ARGV_SETTINGS (3) + +/* Maximum bytes we can write and read at once */ +#define MAX_SPI_BYTES MIN((CONFIG_SHELL_ARGC_MAX - TXRX_ARGV_BYTES), 32) + +static struct device *spi_device; +static struct spi_config config = {.frequency = 1000000, + .operation = SPI_OP_MODE_MASTER | SPI_WORD_SET(8)}; + +static void device_name_get(size_t idx, struct shell_static_entry *entry) +{ + const struct device *dev = shell_device_lookup(idx, "spi"); + + 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); + +static int cmd_spi_transceive(const struct shell *ctx, size_t argc, char **argv) +{ + uint8_t rx_buffer[MAX_SPI_BYTES] = {0}; + uint8_t tx_buffer[MAX_SPI_BYTES] = {0}; + + if (spi_device == NULL) { + shell_error(ctx, "SPI device isn't configured. Use `spi conf`"); + return -ENODEV; + } + + int bytes_to_send = argc - TXRX_ARGV_BYTES; + + for (int i = 0; i < bytes_to_send; i++) { + tx_buffer[i] = strtol(argv[TXRX_ARGV_BYTES + i], NULL, 16); + } + + const struct spi_buf tx_buffers = {.buf = tx_buffer, .len = bytes_to_send}; + const struct spi_buf rx_buffers = {.buf = rx_buffer, .len = bytes_to_send}; + + const struct spi_buf_set tx_buf_set = {.buffers = &tx_buffers, .count = 1}; + const struct spi_buf_set rx_buf_set = {.buffers = &rx_buffers, .count = 1}; + + int ret = spi_transceive(spi_device, &config, &tx_buf_set, &rx_buf_set); + + if (ret < 0) { + shell_error(ctx, "spi_transceive returned %d", ret); + return ret; + } + + shell_print(ctx, "TX:"); + shell_hexdump(ctx, tx_buffer, bytes_to_send); + + shell_print(ctx, "RX:"); + shell_hexdump(ctx, rx_buffer, bytes_to_send); + + return ret; +} + +static int cmd_spi_conf(const struct shell *ctx, size_t argc, char **argv) +{ + spi_operation_t operation = SPI_WORD_SET(8) | SPI_OP_MODE_MASTER; + + /* warning: initialization discards 'const' qualifier from pointer */ + /* target type */ + struct device *dev = (struct device *)device_get_binding(argv[CONF_ARGV_DEV]); + + if (dev == NULL) { + shell_error(ctx, "device %s not found.", argv[CONF_ARGV_DEV]); + return -ENODEV; + } + + uint32_t frequency = strtol(argv[CONF_ARGV_FREQUENCY], NULL, 10); + + if (!IN_RANGE(frequency, 100 * 1000, 80 * 1000 * 1000)) { + shell_error(ctx, "frequency must be between 100000 and 80000000"); + return -EINVAL; + } + + /* no settings */ + if (argc == (CONF_ARGV_FREQUENCY + 1)) { + goto out; + } + + char *opts = argv[CONF_ARGV_SETTINGS]; + bool all_opts_is_valid = true; + + while (*opts != '\0') { + switch (*opts) { + case 'o': + operation |= SPI_MODE_CPOL; + break; + case 'h': + operation |= SPI_MODE_CPHA; + break; + case 'l': + operation |= SPI_TRANSFER_LSB; + break; + case 'T': + operation |= SPI_FRAME_FORMAT_TI; + break; + default: + all_opts_is_valid = false; + shell_error(ctx, "invalid setting %c", *opts); + } + opts++; + } + + if (!all_opts_is_valid) { + return -EINVAL; + } + +out: + config.frequency = frequency; + config.operation = operation; + spi_device = dev; + + return 0; +} + +SHELL_STATIC_SUBCMD_SET_CREATE(sub_spi_cmds, + SHELL_CMD_ARG(conf, &dsub_device_name, + "Configure SPI\n" + "Usage: spi conf []\n" + " - any sequence of letters:" + "o - SPI_MODE_CPOL\n" + "h - SPI_MODE_CPHA\n" + "l - SPI_TRANSFER_LSB\n" + "T - SPI_FRAME_FORMAT_TI\n" + "example: spi conf spi1 1000000 ol", + cmd_spi_conf, 3, 1), + SHELL_CMD_ARG(transceive, NULL, + "Transceive data to and from an SPI device\n" + "Usage: spi transceive [ ...]", + cmd_spi_transceive, 2, MAX_SPI_BYTES - 1), + SHELL_SUBCMD_SET_END); + +SHELL_CMD_REGISTER(spi, &sub_spi_cmds, "SPI commands", NULL); diff --git a/drivers/timer/CMakeLists.txt b/drivers/timer/CMakeLists.txt index 10edb91416f..c44acda2ae6 100644 --- a/drivers/timer/CMakeLists.txt +++ b/drivers/timer/CMakeLists.txt @@ -33,3 +33,4 @@ zephyr_library_sources_ifdef(CONFIG_SAM0_RTC_TIMER sam0_rtc_timer.c) zephyr_library_sources_ifdef(CONFIG_STM32_LPTIM_TIMER stm32_lptim_timer.c) zephyr_library_sources_ifdef(CONFIG_XLNX_PSTTC_TIMER xlnx_psttc_timer.c) zephyr_library_sources_ifdef(CONFIG_XTENSA_TIMER xtensa_sys_timer.c) +zephyr_library_sources_ifdef(CONFIG_SMARTBOND_TIMER smartbond_timer.c) diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index 317efd71d8c..2ddfe321e77 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -90,6 +90,7 @@ source "drivers/timer/Kconfig.rcar_cmt" source "drivers/timer/Kconfig.riscv_machine" source "drivers/timer/Kconfig.rv32m1_lptmr" source "drivers/timer/Kconfig.sam0_rtc" +source "drivers/timer/Kconfig.smartbond" source "drivers/timer/Kconfig.stm32_lptim" source "drivers/timer/Kconfig.xlnx_psttc" source "drivers/timer/Kconfig.xtensa" diff --git a/drivers/timer/Kconfig.ambiq b/drivers/timer/Kconfig.ambiq index 4d804a76998..1c661421e8f 100644 --- a/drivers/timer/Kconfig.ambiq +++ b/drivers/timer/Kconfig.ambiq @@ -10,4 +10,4 @@ config AMBIQ_STIMER_TIMER select TICKLESS_CAPABLE select AMBIQ_HAL_USE_STIMER help - Ambiq Apollo4 stimer driver + Ambiq Apollo stimer driver diff --git a/drivers/timer/Kconfig.nrf_grtc b/drivers/timer/Kconfig.nrf_grtc index 444d13aab31..cda39ae8b1c 100644 --- a/drivers/timer/Kconfig.nrf_grtc +++ b/drivers/timer/Kconfig.nrf_grtc @@ -3,7 +3,8 @@ menuconfig NRF_GRTC_TIMER bool "nRF GRTC Timer" - default y if DT_HAS_NORDIC_NRF_GRTC_ENABLED + default y + depends on DT_HAS_NORDIC_NRF_GRTC_ENABLED select TICKLESS_CAPABLE select TIMER_HAS_64BIT_CYCLE_COUNTER select NRFX_GRTC diff --git a/drivers/timer/Kconfig.smartbond b/drivers/timer/Kconfig.smartbond new file mode 100644 index 00000000000..2b5cb3c32e5 --- /dev/null +++ b/drivers/timer/Kconfig.smartbond @@ -0,0 +1,13 @@ +# Copyright (c) 2023 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +config SMARTBOND_TIMER + bool "Renesas SmartBond(tm) timer" + default y + depends on SOC_FAMILY_RENESAS_SMARTBOND + depends on CLOCK_CONTROL + depends on !$(dt_nodelabel_enabled,timer2) + select TICKLESS_CAPABLE + help + This module implements a kernel device driver for the TIMER2 timer + and provides the standard "system clock driver" interfaces. diff --git a/drivers/timer/ambiq_stimer.c b/drivers/timer/ambiq_stimer.c index 8a469f35907..e2c9d9976f4 100644 --- a/drivers/timer/ambiq_stimer.c +++ b/drivers/timer/ambiq_stimer.c @@ -24,11 +24,10 @@ #define COUNTER_MAX UINT32_MAX -#define CYC_PER_TICK (sys_clock_hw_cycles_per_sec() \ - / CONFIG_SYS_CLOCK_TICKS_PER_SEC) -#define MAX_TICKS ((k_ticks_t)(COUNTER_MAX / CYC_PER_TICK) - 1) -#define MAX_CYCLES (MAX_TICKS * CYC_PER_TICK) -#define MIN_DELAY 1 +#define CYC_PER_TICK (sys_clock_hw_cycles_per_sec() / CONFIG_SYS_CLOCK_TICKS_PER_SEC) +#define MAX_TICKS ((k_ticks_t)(COUNTER_MAX / CYC_PER_TICK) - 1) +#define MAX_CYCLES (MAX_TICKS * CYC_PER_TICK) +#define MIN_DELAY 1 #define TIMER_IRQ (DT_INST_IRQN(0)) @@ -102,8 +101,7 @@ uint32_t sys_clock_elapsed(void) } k_spinlock_key_t key = k_spin_lock(&g_lock); - uint32_t ret = (am_hal_stimer_counter_get() - - g_last_count) / CYC_PER_TICK; + uint32_t ret = (am_hal_stimer_counter_get() - g_last_count) / CYC_PER_TICK; k_spin_unlock(&g_lock, key); return ret; @@ -121,10 +119,13 @@ static int stimer_init(void) oldCfg = am_hal_stimer_config(AM_HAL_STIMER_CFG_FREEZE); - am_hal_stimer_config((oldCfg & ~(AM_HAL_STIMER_CFG_FREEZE | STIMER_STCFG_CLKSEL_Msk)) - | AM_HAL_STIMER_XTAL_32KHZ - | AM_HAL_STIMER_CFG_COMPARE_A_ENABLE); - +#if defined(CONFIG_SOC_SERIES_APOLLO3X) + am_hal_stimer_config((oldCfg & ~(AM_HAL_STIMER_CFG_FREEZE | CTIMER_STCFG_CLKSEL_Msk)) | + AM_HAL_STIMER_XTAL_32KHZ | AM_HAL_STIMER_CFG_COMPARE_A_ENABLE); +#else + am_hal_stimer_config((oldCfg & ~(AM_HAL_STIMER_CFG_FREEZE | STIMER_STCFG_CLKSEL_Msk)) | + AM_HAL_STIMER_XTAL_32KHZ | AM_HAL_STIMER_CFG_COMPARE_A_ENABLE); +#endif g_last_count = am_hal_stimer_counter_get(); k_spin_unlock(&g_lock, key); @@ -141,5 +142,4 @@ static int stimer_init(void) return 0; } -SYS_INIT(stimer_init, PRE_KERNEL_2, - CONFIG_SYSTEM_CLOCK_INIT_PRIORITY); +SYS_INIT(stimer_init, PRE_KERNEL_2, CONFIG_SYSTEM_CLOCK_INIT_PRIORITY); diff --git a/drivers/timer/apic_tsc.c b/drivers/timer/apic_tsc.c index 59b0017375c..3c6ab1e0a6d 100644 --- a/drivers/timer/apic_tsc.c +++ b/drivers/timer/apic_tsc.c @@ -2,7 +2,11 @@ * Copyright (c) 2021 Intel Corporation * SPDX-License-Identifier: Apache-2.0 */ + +#include /* Header provided by the toolchain. */ + #include +#include #include #include #include @@ -64,7 +68,7 @@ void sys_clock_set_timeout(int32_t ticks, bool idle) uint64_t now = rdtsc(); k_spinlock_key_t key = k_spin_lock(&lock); - uint64_t expires = now + MAX(ticks - 1, 0) * CYC_PER_TICK; + uint64_t expires = now + (MAX(ticks - 1, 0) * CYC_PER_TICK); expires = last_announce + (((expires - last_announce + CYC_PER_TICK - 1) / CYC_PER_TICK) * CYC_PER_TICK); @@ -77,7 +81,7 @@ void sys_clock_set_timeout(int32_t ticks, bool idle) * real hardware it requires more than a century of uptime, * but this is cheap and safe. */ - if (ticks == K_TICKS_FOREVER || expires < last_announce) { + if ((ticks == K_TICKS_FOREVER) || (expires < last_announce)) { expires = UINT64_MAX; } @@ -149,28 +153,21 @@ void smp_timer_init(void) irq_enable(timer_irq()); } -static inline void cpuid(uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx) -{ - __asm__ volatile("cpuid" - : "=b"(*ebx), "=c"(*ecx), "=d"(*edx) - : "a"(*eax), "c"(*ecx)); -} - static int sys_clock_driver_init(void) { #ifdef CONFIG_ASSERT uint32_t eax, ebx, ecx, edx; - eax = 1; ecx = 0; - cpuid(&eax, &ebx, &ecx, &edx); + ecx = 0; /* prevent compiler warning */ + __get_cpuid(CPUID_BASIC_INFO_1, &eax, &ebx, &ecx, &edx); __ASSERT((ecx & BIT(24)) != 0, "No TSC Deadline support"); - eax = 0x80000007; ecx = 0; - cpuid(&eax, &ebx, &ecx, &edx); + edx = 0; /* prevent compiler warning */ + __get_cpuid(0x80000007, &eax, &ebx, &ecx, &edx); __ASSERT((edx & BIT(8)) != 0, "No Invariant TSC support"); - eax = 7; ecx = 0; - cpuid(&eax, &ebx, &ecx, &edx); + ebx = 0; /* prevent compiler warning */ + __get_cpuid_count(CPUID_EXTENDED_FEATURES_LVL, 0, &eax, &ebx, &ecx, &edx); __ASSERT((ebx & BIT(1)) != 0, "No TSC_ADJUST MSR support"); #endif diff --git a/drivers/timer/arm_arch_timer.c b/drivers/timer/arm_arch_timer.c index 718fecea582..885eb3a369b 100644 --- a/drivers/timer/arm_arch_timer.c +++ b/drivers/timer/arm_arch_timer.c @@ -22,14 +22,45 @@ static uint32_t cyc_per_tick; #if defined(CONFIG_GDBSTUB) /* When interactively debugging, the cycle diff can overflow 32-bit variable */ -#define TO_CYCLE_DIFF(x) (x) +#define cycle_diff_t uint64_t #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 +#endif +#define CYCLE_DIFF_MAX (~(cycle_diff_t)0) + +/* + * We have two constraints on the maximum number of cycles we can wait for. + * + * 1) sys_clock_announce() accepts at most INT32_MAX ticks. + * + * 2) The number of cycles between two reports must fit in a cycle_diff_t + * variable before converting it to ticks. + * + * Then: + * + * 3) Pick the smallest between (1) and (2). + * + * 4) Take into account some room for the unavoidable IRQ servicing latency. + * Let's use 3/4 of the max range. + * + * Finally let's add the LSB value to the result so to clear out a bunch of + * consecutive set bits coming from the original max values to produce a + * nicer literal for assembly generation. + */ +#define CYCLES_MAX_1 ((uint64_t)INT32_MAX * (uint64_t)CYC_PER_TICK) +#define CYCLES_MAX_2 ((uint64_t)CYCLE_DIFF_MAX) +#define CYCLES_MAX_3 MIN(CYCLES_MAX_1, CYCLES_MAX_2) +#define CYCLES_MAX_4 (CYCLES_MAX_3 / 2 + CYCLES_MAX_3 / 4) +#define CYCLES_MAX_5 (CYCLES_MAX_4 + LSB_GET(CYCLES_MAX_4)) + +#ifdef CONFIG_TIMER_READS_ITS_FREQUENCY_AT_RUNTIME +/* precompute CYCLES_MAX at driver init to avoid runtime double divisions */ +static uint64_t cycles_max; +#define CYCLES_MAX cycles_max +#else +#define CYCLES_MAX CYCLES_MAX_5 +#endif static struct k_spinlock lock; static uint64_t last_cycle; @@ -66,7 +97,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 = TO_CYCLE_DIFF(delta_cycles) / CYC_PER_TICK; + uint32_t delta_ticks = (cycle_diff_t)delta_cycles / CYC_PER_TICK; last_cycle += (cycle_diff_t)delta_ticks * CYC_PER_TICK; last_tick += delta_ticks; @@ -109,39 +140,29 @@ static void arm_arch_timer_compare_isr(const void *arg) void sys_clock_set_timeout(int32_t ticks, bool idle) { -#if defined(CONFIG_TICKLESS_KERNEL) - - if (ticks == K_TICKS_FOREVER) { - if (idle) { - return; - } - ticks = INT32_MAX; + if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) { + return; } - /* - * Clamp the max period length to a number of cycles that can fit - * in half the range of a cycle_diff_t for native width divisions - * to be usable elsewhere. Also clamp it to half the range of an - * int32_t as this is the type used for elapsed tick announcements. - * The half range gives us one bit of extra room to cope with the - * unavoidable IRQ servicing latency (we never need as much but this - * is simple). The compiler should optimize away the least restrictive - * of those tests automatically. - */ - ticks = CLAMP(ticks, 0, (cycle_diff_t)-1 / 2 / CYC_PER_TICK); - ticks = CLAMP(ticks, 0, INT32_MAX / 2); + if (idle && ticks == K_TICKS_FOREVER) { + return; + } k_spinlock_key_t key = k_spin_lock(&lock); - uint64_t next_cycle = (last_tick + last_elapsed + ticks) * CYC_PER_TICK; + uint64_t next_cycle; + + if (ticks == K_TICKS_FOREVER) { + next_cycle = last_cycle + CYCLES_MAX; + } else { + next_cycle = (last_tick + last_elapsed + ticks) * CYC_PER_TICK; + if ((next_cycle - last_cycle) > CYCLES_MAX) { + next_cycle = last_cycle + CYCLES_MAX; + } + } arm_arch_timer_set_compare(next_cycle); arm_arch_timer_set_irq_mask(false); k_spin_unlock(&lock, key); - -#else /* CONFIG_TICKLESS_KERNEL */ - ARG_UNUSED(ticks); - ARG_UNUSED(idle); -#endif } uint32_t sys_clock_elapsed(void) @@ -213,6 +234,7 @@ static int sys_clock_driver_init(void) arm_arch_timer_init(); #ifdef CONFIG_TIMER_READS_ITS_FREQUENCY_AT_RUNTIME cyc_per_tick = sys_clock_hw_cycles_per_sec() / CONFIG_SYS_CLOCK_TICKS_PER_SEC; + cycles_max = CYCLES_MAX_5; #endif arm_arch_timer_enable(true); last_tick = arm_arch_timer_count() / CYC_PER_TICK; diff --git a/drivers/timer/nrf_grtc_timer.c b/drivers/timer/nrf_grtc_timer.c index 7a31cde7bfa..a8b29b9dcc7 100644 --- a/drivers/timer/nrf_grtc_timer.c +++ b/drivers/timer/nrf_grtc_timer.c @@ -56,7 +56,7 @@ const int32_t z_sys_timer_irq_for_test = DT_IRQN(GRTC_NODE); 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 uint64_t last_count; /* Time (SYSCOUNTER value) @last sys_clock_announce() */ static atomic_t int_mask; static uint8_t ext_channels_allocated; static nrfx_grtc_channel_t system_clock_channel_data = { @@ -81,22 +81,24 @@ static inline uint64_t counter(void) return now; } -static inline uint64_t get_comparator(uint32_t chan) +static inline int get_comparator(uint32_t chan, uint64_t *cc) { - uint64_t cc; nrfx_err_t result; - result = nrfx_grtc_syscounter_cc_value_read(chan, &cc); + 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; + return 0; } -static void system_timeout_set(uint64_t value) +/* + * Program a new callback microseconds in the future + */ +static void system_timeout_set_relative(uint64_t value) { if (value <= NRF_GRTC_SYSCOUNTER_CCADD_MASK) { nrfx_grtc_syscounter_cc_relative_set(&system_clock_channel_data, value, true, @@ -107,6 +109,15 @@ static void system_timeout_set(uint64_t value) } } +/* + * Program a new callback in the absolute time given by + */ +static void system_timeout_set_abs(uint64_t value) +{ + nrfx_grtc_syscounter_cc_absolute_set(&system_clock_channel_data, value, + true); +} + static bool compare_int_lock(int32_t chan) { atomic_val_t prev = atomic_and(&int_mask, ~BIT(chan)); @@ -129,22 +140,19 @@ static void sys_clock_timeout_handler(int32_t id, uint64_t cc_val, void *p_conte ARG_UNUSED(id); ARG_UNUSED(p_context); uint64_t dticks; - uint64_t now = counter(); - if (unlikely(now < cc_val)) { - return; - } + dticks = counter_sub(cc_val, last_count) / CYC_PER_TICK; + + last_count += dticks * CYC_PER_TICK; + 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); + system_timeout_set_abs(last_count + 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)); + sys_clock_announce((int32_t)dticks); } int32_t z_nrf_grtc_timer_chan_alloc(void) @@ -216,11 +224,11 @@ void z_nrf_grtc_timer_compare_int_unlock(int32_t chan, bool key) compare_int_unlock(chan, key); } -uint64_t z_nrf_grtc_timer_compare_read(int32_t chan) +int z_nrf_grtc_timer_compare_read(int32_t chan, uint64_t *val) { IS_CHANNEL_ALLOWED_ASSERT(chan); - return get_comparator(chan); + return get_comparator(chan, val); } static int compare_set_nolocks(int32_t chan, uint64_t target_time, @@ -477,7 +485,7 @@ static int sys_clock_driver_init(void) int_mask = NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK; if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) { - system_timeout_set(CYC_PER_TICK); + system_timeout_set_relative(CYC_PER_TICK); } #if defined(CONFIG_CLOCK_CONTROL_NRF) @@ -497,34 +505,23 @@ static int sys_clock_driver_init(void) 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(); + ticks = (ticks == K_TICKS_FOREVER) ? MAX_TICKS : MIN(MAX_TICKS, MAX(ticks, 0)); - /* Round up to the next tick boundary */ - off = (now - last_count) + (CYC_PER_TICK - 1); - off = (off / CYC_PER_TICK) * CYC_PER_TICK; + uint64_t delta_time = ticks * CYC_PER_TICK; - /* Get the offset with respect to now */ - off -= (now - last_count); + uint64_t target_time = counter() + delta_time; - /* 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. + /* Rounded down target_time to the tick boundary + * (but not less than one tick after the last) */ - if (cyc > MAX_CYCLES) { - cyc = MAX_CYCLES; - } + target_time = MAX((target_time - last_count)/CYC_PER_TICK, 1)*CYC_PER_TICK + last_count; - system_timeout_set(cyc == 0 ? 1 : cyc); + system_timeout_set_abs(target_time); } #if defined(CONFIG_NRF_GRTC_TIMER_APP_DEFINED_INIT) diff --git a/drivers/timer/riscv_machine_timer.c b/drivers/timer/riscv_machine_timer.c index abfb28a9628..36e29c6aadb 100644 --- a/drivers/timer/riscv_machine_timer.c +++ b/drivers/timer/riscv_machine_timer.c @@ -78,6 +78,32 @@ /* the unsigned long cast limits divisions to native CPU register width */ #define cycle_diff_t unsigned long +#define CYCLE_DIFF_MAX (~(cycle_diff_t)0) + +/* + * We have two constraints on the maximum number of cycles we can wait for. + * + * 1) sys_clock_announce() accepts at most INT32_MAX ticks. + * + * 2) The number of cycles between two reports must fit in a cycle_diff_t + * variable before converting it to ticks. + * + * Then: + * + * 3) Pick the smallest between (1) and (2). + * + * 4) Take into account some room for the unavoidable IRQ servicing latency. + * Let's use 3/4 of the max range. + * + * Finally let's add the LSB value to the result so to clear out a bunch of + * consecutive set bits coming from the original max values to produce a + * nicer literal for assembly generation. + */ +#define CYCLES_MAX_1 ((uint64_t)INT32_MAX * (uint64_t)CYC_PER_TICK) +#define CYCLES_MAX_2 ((uint64_t)CYCLE_DIFF_MAX) +#define CYCLES_MAX_3 MIN(CYCLES_MAX_1, CYCLES_MAX_2) +#define CYCLES_MAX_4 (CYCLES_MAX_3 / 2 + CYCLES_MAX_3 / 4) +#define CYCLES_MAX (CYCLES_MAX_4 + LSB_GET(CYCLES_MAX_4)) static struct k_spinlock lock; static uint64_t last_count; @@ -170,27 +196,19 @@ void sys_clock_set_timeout(int32_t ticks, bool idle) return; } - if (ticks == K_TICKS_FOREVER) { - set_mtimecmp(UINT64_MAX); - return; - } - - /* - * Clamp the max period length to a number of cycles that can fit - * in half the range of a cycle_diff_t for native width divisions - * to be usable elsewhere. Also clamp it to half the range of an - * int32_t as this is the type used for elapsed tick announcements. - * The half range gives us extra room to cope with the unavoidable IRQ - * servicing latency. The compiler should optimize away the least - * restrictive of those tests automatically. - */ - ticks = CLAMP(ticks, 0, (cycle_diff_t)-1 / 2 / CYC_PER_TICK); - ticks = CLAMP(ticks, 0, INT32_MAX / 2); - k_spinlock_key_t key = k_spin_lock(&lock); - uint64_t cyc = (last_ticks + last_elapsed + ticks) * CYC_PER_TICK; + uint64_t cyc; + if (ticks == K_TICKS_FOREVER) { + cyc = last_count + CYCLES_MAX; + } else { + cyc = (last_ticks + last_elapsed + ticks) * CYC_PER_TICK; + if ((cyc - last_count) > CYCLES_MAX) { + cyc = last_count + CYCLES_MAX; + } + } set_mtimecmp(cyc); + k_spin_unlock(&lock, key); } diff --git a/drivers/timer/smartbond_timer.c b/drivers/timer/smartbond_timer.c new file mode 100644 index 00000000000..4ab03f5d956 --- /dev/null +++ b/drivers/timer/smartbond_timer.c @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2023 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +#define COUNTER_SPAN BIT(24) +#define CYC_PER_TICK k_ticks_to_cyc_ceil32(1) +#define TICK_TO_CYC(tick) k_ticks_to_cyc_ceil32(tick) +#define CYC_TO_TICK(cyc) k_cyc_to_ticks_ceil32(cyc) +#define MAX_TICKS (((COUNTER_SPAN / 2) - CYC_PER_TICK) / (CYC_PER_TICK)) + +static uint32_t last_timer_val_reg; +static uint32_t timer_val_31_24; + +static uint32_t last_isr_val; +static uint32_t last_isr_val_rounded; +static uint32_t announced_ticks; + +static void set_reload(uint32_t val) +{ + TIMER2->TIMER2_RELOAD_REG = val & TIMER2_TIMER2_RELOAD_REG_TIM_RELOAD_Msk; +} + +static uint32_t timer_val_32(void) +{ + uint32_t timer_val_reg; + uint32_t val; + + timer_val_reg = TIMER2->TIMER2_TIMER_VAL_REG & + TIMER2_TIMER2_TIMER_VAL_REG_TIM_TIMER_VALUE_Msk; + if (timer_val_reg < last_timer_val_reg) { + timer_val_31_24 += COUNTER_SPAN; + } + last_timer_val_reg = timer_val_reg; + + val = timer_val_31_24 + timer_val_reg; + + return val; +} + +static uint32_t timer_val_32_noupdate(void) +{ + uint32_t timer_val_reg; + uint32_t val; + + timer_val_reg = TIMER2->TIMER2_TIMER_VAL_REG & + TIMER2_TIMER2_TIMER_VAL_REG_TIM_TIMER_VALUE_Msk; + val = timer_val_31_24 + timer_val_reg; + if (timer_val_reg < last_timer_val_reg) { + val += COUNTER_SPAN; + } + + return val; +} + +void sys_clock_set_timeout(int32_t ticks, bool idle) +{ + uint32_t target_val; + uint32_t timer_val; + + if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) { + return; + } + + if (ticks == K_TICKS_FOREVER) { + /* FIXME we could disable timer here */ + } + + /* + * When Watchdog is NOT enabled but power management is, system + * starts watchdog before PD_SYS is powered off. + * Watchdog default reload value is 0x1FFF (~82s for RC32K and 172s for RCX). + * After this time watchdog will reset system if not woken up before. + * When Watchdog is not configured power management freezes watchdog + * as soon as system is awaken. Following code makes sure that + * system never goes to sleep for longer time that watchdog reload value. + */ + if (!IS_ENABLED(CONFIG_WDT_SMARTBOND) && IS_ENABLED(CONFIG_PM)) { + uint32_t watchdog_expire_ticks; + + if (CRG_TOP->CLK_RCX_REG & CRG_TOP_CLK_RCX_REG_RCX_ENABLE_Msk) { + watchdog_expire_ticks = SYS_WDOG->WATCHDOG_REG * 21 * + CONFIG_SYS_CLOCK_TICKS_PER_SEC / 1000; + } else { + watchdog_expire_ticks = SYS_WDOG->WATCHDOG_REG * + CONFIG_SYS_CLOCK_TICKS_PER_SEC / 100; + } + if (watchdog_expire_ticks - 2 < ticks) { + ticks = watchdog_expire_ticks - 2; + } + } + ticks = (ticks == K_TICKS_FOREVER) ? MAX_TICKS : ticks; + ticks = CLAMP(ticks - 1, 0, (int32_t)MAX_TICKS); + + timer_val = timer_val_32_noupdate(); + + /* Calculate target timer value and align to full tick */ + target_val = timer_val + TICK_TO_CYC(ticks); + target_val = ((target_val + CYC_PER_TICK - 1) / CYC_PER_TICK) * CYC_PER_TICK; + + set_reload(target_val); +} + +uint32_t sys_clock_elapsed(void) +{ + if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) { + return 0; + } + + return CYC_TO_TICK(timer_val_32_noupdate() - last_isr_val); +} + +uint32_t sys_clock_cycle_get_32(void) +{ + return timer_val_32_noupdate(); +} + +void sys_clock_idle_exit(void) +{ + TIMER2->TIMER2_CTRL_REG |= TIMER2_TIMER2_CTRL_REG_TIM_EN_Msk; +} + +void sys_clock_disable(void) +{ + TIMER2->TIMER2_CTRL_REG &= ~TIMER2_TIMER2_CTRL_REG_TIM_EN_Msk; +} + +static void timer2_isr(const void *arg) +{ + uint32_t val; + int32_t delta; + int32_t dticks; + + ARG_UNUSED(arg); + + TIMER2->TIMER2_CLEAR_IRQ_REG = 1; + + val = timer_val_32(); + delta = (int32_t)(val - last_isr_val_rounded); + last_isr_val = val; + dticks = CYC_TO_TICK(delta); + last_isr_val_rounded += TICK_TO_CYC(dticks); + announced_ticks += dticks; + sys_clock_announce(dticks); +} + +static int sys_clock_driver_init(void) +{ +#if CONFIG_PM + uint8_t pdc_idx; + uint8_t en_xtal; + + en_xtal = DT_NODE_HAS_STATUS(DT_NODELABEL(xtal32m), okay) ? MCU_PDC_EN_XTAL : 0; + + /* Enable wakeup by TIMER2 */ + pdc_idx = da1469x_pdc_add(MCU_PDC_TRIGGER_TIMER2, MCU_PDC_MASTER_M33, en_xtal); + __ASSERT_NO_MSG(pdc_idx >= 0); + da1469x_pdc_set(pdc_idx); + da1469x_pdc_ack(pdc_idx); +#endif + + TIMER2->TIMER2_CTRL_REG = 0; + TIMER2->TIMER2_PRESCALER_REG = 0; + TIMER2->TIMER2_CTRL_REG |= TIMER2_TIMER2_CTRL_REG_TIM_CLK_EN_Msk; + TIMER2->TIMER2_CTRL_REG |= TIMER2_TIMER2_CTRL_REG_TIM_FREE_RUN_MODE_EN_Msk | + TIMER2_TIMER2_CTRL_REG_TIM_IRQ_EN_Msk | + TIMER2_TIMER2_CTRL_REG_TIM_EN_Msk; + + IRQ_CONNECT(TIMER2_IRQn, _IRQ_PRIO_OFFSET, timer2_isr, 0, 0); + irq_enable(TIMER2_IRQn); + + return 0; +} + +SYS_INIT(sys_clock_driver_init, PRE_KERNEL_2, CONFIG_SYSTEM_CLOCK_INIT_PRIORITY); diff --git a/drivers/usb/common/usb_dwc2_hw.h b/drivers/usb/common/usb_dwc2_hw.h index f216a423968..b137a526ede 100644 --- a/drivers/usb/common/usb_dwc2_hw.h +++ b/drivers/usb/common/usb_dwc2_hw.h @@ -190,32 +190,81 @@ USB_DWC2_SET_FIELD_DEFINE(grstctl_txfnum, GRSTCTL_TXFNUM) #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_SESSREQINT_POS 30UL +#define USB_DWC2_GINTSTS_SESSREQINT BIT(USB_DWC2_GINTSTS_SESSREQINT_POS) +#define USB_DWC2_GINTSTS_DISCONNINT_POS 29UL +#define USB_DWC2_GINTSTS_DISCONNINT BIT(USB_DWC2_GINTSTS_DISCONNINT_POS) +#define USB_DWC2_GINTSTS_CONIDSTSCHNG_POS 28UL +#define USB_DWC2_GINTSTS_CONIDSTSCHNG BIT(USB_DWC2_GINTSTS_CONIDSTSCHNG_POS) +#define USB_DWC2_GINTSTS_LPM_INT_POS 27UL +#define USB_DWC2_GINTSTS_LPM_INT BIT(USB_DWC2_GINTSTS_LPM_INT_POS) +#define USB_DWC2_GINTSTS_HCHINT_POS 25UL +#define USB_DWC2_GINTSTS_HCHINT BIT(USB_DWC2_GINTSTS_HCHINT_POS) +#define USB_DWC2_GINTSTS_PRTINT_POS 24UL +#define USB_DWC2_GINTSTS_PRTINT BIT(USB_DWC2_GINTSTS_PRTINT_POS) +#define USB_DWC2_GINTSTS_RESETDET_POS 23UL +#define USB_DWC2_GINTSTS_RESETDET BIT(USB_DWC2_GINTSTS_RESETDET_POS) +#define USB_DWC2_GINTSTS_FETSUSP_POS 22UL +#define USB_DWC2_GINTSTS_FETSUSP BIT(USB_DWC2_GINTSTS_FETSUSP_POS) +#define USB_DWC2_GINTSTS_INCOMPIP_POS 21UL +#define USB_DWC2_GINTSTS_INCOMPIP BIT(USB_DWC2_GINTSTS_INCOMPIP_POS) +#define USB_DWC2_GINTSTS_INCOMPISOIN_POS 20UL +#define USB_DWC2_GINTSTS_INCOMPISOIN BIT(USB_DWC2_GINTSTS_INCOMPISOIN_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_EPMIS_POS 17UL +#define USB_DWC2_GINTSTS_EPMIS BIT(USB_DWC2_GINTSTS_EPMIS_POS) +#define USB_DWC2_GINTSTS_RSTRDONEINT_POS 16UL +#define USB_DWC2_GINTSTS_RSTRDONEINT BIT(USB_DWC2_GINTSTS_RSTRDONEINT_POS) +#define USB_DWC2_GINTSTS_EOPF_POS 15UL +#define USB_DWC2_GINTSTS_EOPF BIT(USB_DWC2_GINTSTS_EOPF_POS) +#define USB_DWC2_GINTSTS_ISOOUTDROP_POS 14UL +#define USB_DWC2_GINTSTS_ISOOUTDROP BIT(USB_DWC2_GINTSTS_ISOOUTDROP_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_ERLYSUSP_POS 10UL +#define USB_DWC2_GINTSTS_ERLYSUSP BIT(USB_DWC2_GINTSTS_ERLYSUSP_POS) +#define USB_DWC2_GINTSTS_GOUTNAKEFF_POS 7UL +#define USB_DWC2_GINTSTS_GOUTNAKEFF BIT(USB_DWC2_GINTSTS_GOUTNAKEFF_POS) +#define USB_DWC2_GINTSTS_GINNAKEFF_POS 6UL +#define USB_DWC2_GINTSTS_GINNAKEFF BIT(USB_DWC2_GINTSTS_GINNAKEFF_POS) +#define USB_DWC2_GINTSTS_NPTXFEMP_POS 5UL +#define USB_DWC2_GINTSTS_NPTXFEMP BIT(USB_DWC2_GINTSTS_NPTXFEMP_POS) #define USB_DWC2_GINTSTS_RXFLVL_POS 4UL #define USB_DWC2_GINTSTS_RXFLVL BIT(USB_DWC2_GINTSTS_RXFLVL_POS) #define USB_DWC2_GINTSTS_SOF_POS 3UL #define USB_DWC2_GINTSTS_SOF BIT(USB_DWC2_GINTSTS_SOF_POS) #define USB_DWC2_GINTSTS_OTGINT_POS 2UL #define USB_DWC2_GINTSTS_OTGINT BIT(USB_DWC2_GINTSTS_OTGINT_POS) +#define USB_DWC2_GINTSTS_MODEMIS_POS 1UL +#define USB_DWC2_GINTSTS_MODEMIS BIT(USB_DWC2_GINTSTS_MODEMIS_POS) +#define USB_DWC2_GINTSTS_CURMOD_POS 0UL +#define USB_DWC2_GINTSTS_CURMOD BIT(USB_DWC2_GINTSTS_CURMOD_POS) /* Status read and pop registers */ #define USB_DWC2_GRXSTSR 0x001CUL #define USB_DWC2_GRXSTSP 0x0020UL +#define USB_DWC2_GRXSTSR_FN_POS 21UL +#define USB_DWC2_GRXSTSR_FN_MASK (0xFUL << USB_DWC2_GRXSTSR_FN_POS) #define USB_DWC2_GRXSTSR_PKTSTS_POS 17UL #define USB_DWC2_GRXSTSR_PKTSTS_MASK (0xFUL << USB_DWC2_GRXSTSR_PKTSTS_POS) +#define USB_DWC2_GRXSTSR_PKTSTS_GLOBAL_OUT_NAK 1 #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_DPID_POS 15UL +#define USB_DWC2_GRXSTSR_DPID_MASK (0x3UL << USB_DWC2_GRXSTSR_DPID_POS) +#define USB_DWC2_GRXSTSR_DPID_DATA0 0 +#define USB_DWC2_GRXSTSR_DPID_DATA2 1 +#define USB_DWC2_GRXSTSR_DPID_DATA1 2 +#define USB_DWC2_GRXSTSR_DPID_MDATA 3 #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 @@ -223,6 +272,7 @@ USB_DWC2_SET_FIELD_DEFINE(grstctl_txfnum, GRSTCTL_TXFNUM) #define USB_DWC2_GRXSTSR_CHNUM_POS 0UL #define USB_DWC2_GRXSTSR_CHNUM_MASK 0x0000000FUL +USB_DWC2_GET_FIELD_DEFINE(grxstsp_fn, GRXSTSR_FN) 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) @@ -456,6 +506,8 @@ USB_DWC2_GET_FIELD_DEFINE(dsts_enumspd, DSTS_ENUMSPD) #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_SETD1PID_POS 29UL +#define USB_DWC2_DEPCTL_SETD1PID BIT(USB_DWC2_DEPCTL_SETD1PID_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 @@ -472,6 +524,10 @@ USB_DWC2_GET_FIELD_DEFINE(dsts_enumspd, DSTS_ENUMSPD) #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_NAKSTS_POS 17UL +#define USB_DWC2_DEPCTL_NAKSTS BIT(USB_DWC2_DEPCTL_NAKSTS_POS) +#define USB_DWC2_DEPCTL_DPID_POS 16UL +#define USB_DWC2_DEPCTL_DPID BIT(USB_DWC2_DEPCTL_DPID_POS) #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 diff --git a/drivers/usb/device/Kconfig b/drivers/usb/device/Kconfig index 3dc1a365bea..ad2432998c4 100644 --- a/drivers/usb/device/Kconfig +++ b/drivers/usb/device/Kconfig @@ -225,6 +225,7 @@ endif # USB_DC_NUMAKER config USB_NATIVE_POSIX bool "Native Posix USB Device Controller Driver" depends on ARCH_POSIX && EXTERNAL_LIBC + default y if BOARD_NATIVE_SIM || BOARD_NATIVE_POSIX help Native Posix USB Device Controller Driver. diff --git a/drivers/usb/device/usb_dc_dw.c b/drivers/usb/device/usb_dc_dw.c index b2f6a8f0e3c..31af5cfcc49 100644 --- a/drivers/usb/device/usb_dc_dw.c +++ b/drivers/usb/device/usb_dc_dw.c @@ -128,12 +128,12 @@ static int usb_dw_init_pinctrl(const struct usb_dw_config *const config) #define USB_DW_GET_COMPAT_QUIRK_NONE(n) NULL #define USB_DW_GET_COMPAT_CLK_QUIRK_0(n) \ - COND_CODE_1(DT_NODE_HAS_COMPAT(DT_DRV_INST(n), st_stm32f4_fsotg), \ + COND_CODE_1(DT_INST_NODE_HAS_COMPAT(n, st_stm32f4_fsotg), \ (clk_enable_st_stm32f4_fsotg_##n), \ USB_DW_GET_COMPAT_QUIRK_NONE(n)) #define USB_DW_GET_COMPAT_PWR_QUIRK_0(n) \ - COND_CODE_1(DT_NODE_HAS_COMPAT(DT_DRV_INST(n), st_stm32f4_fsotg), \ + COND_CODE_1(DT_INST_NODE_HAS_COMPAT(n, st_stm32f4_fsotg), \ (pwr_on_st_stm32f4_fsotg), \ USB_DW_GET_COMPAT_QUIRK_NONE(n)) diff --git a/drivers/usb/device/usb_dc_dw_stm32.h b/drivers/usb/device/usb_dc_dw_stm32.h index e2cd5208459..5040f28de69 100644 --- a/drivers/usb/device/usb_dc_dw_stm32.h +++ b/drivers/usb/device/usb_dc_dw_stm32.h @@ -74,7 +74,7 @@ static inline int pwr_on_st_stm32f4_fsotg(struct usb_dwc2_reg *const base) } #define USB_DW_QUIRK_ST_STM32F4_FSOTG_DEFINE(n) \ - COND_CODE_1(DT_NODE_HAS_COMPAT(DT_DRV_INST(n), st_stm32f4_fsotg), \ + COND_CODE_1(DT_INST_NODE_HAS_COMPAT(n, st_stm32f4_fsotg), \ (QUIRK_ST_STM32F4_FSOTG_DEFINE(n)), ()) #endif /* ZEPHYR_DRIVERS_USB_DEVICE_USB_DC_DW_STM32_H */ diff --git a/drivers/usb/device/usb_dc_mcux.c b/drivers/usb/device/usb_dc_mcux.c index e36eba89182..d62662063ee 100644 --- a/drivers/usb/device/usb_dc_mcux.c +++ b/drivers/usb/device/usb_dc_mcux.c @@ -89,7 +89,9 @@ BUILD_ASSERT(NUM_INSTS <= 1, "Only one USB device supported"); #elif DT_NODE_HAS_STATUS(DT_NODELABEL(usbfs), okay) #define CONTROLLER_ID kUSB_ControllerLpcIp3511Fs0 #endif /* LPC55s69 */ -#elif defined(CONFIG_SOC_SERIES_IMXRT11XX) || defined(CONFIG_SOC_SERIES_IMXRT10XX) +#elif defined(CONFIG_SOC_SERIES_IMXRT11XX) || \ + defined(CONFIG_SOC_SERIES_IMXRT10XX) || \ + defined(CONFIG_SOC_SERIES_MCXNX4X) #if DT_NODE_HAS_STATUS(DT_NODELABEL(usb1), okay) #define CONTROLLER_ID kUSB_ControllerEhci0 #elif DT_NODE_HAS_STATUS(DT_NODELABEL(usb2), okay) diff --git a/drivers/usb/device/usb_dc_stm32.c b/drivers/usb/device/usb_dc_stm32.c index ad9c6ac520c..fbc7ff07e71 100644 --- a/drivers/usb/device/usb_dc_stm32.c +++ b/drivers/usb/device/usb_dc_stm32.c @@ -265,27 +265,26 @@ static int usb_dc_stm32_clock_enable(void) #endif /* RCC_CFGR_OTGFSPRE / RCC_CFGR_USBPRE */ -#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_otghs) -#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_usbphyc) +#if USB_OTG_HS_ULPI_PHY +#if defined(CONFIG_SOC_SERIES_STM32H7X) + LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_USB1OTGHSULPI); +#else LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_OTGHSULPI); - LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_OTGPHYC); -#elif defined(CONFIG_SOC_SERIES_STM32H7X) -#if !USB_OTG_HS_ULPI_PHY - /* Disable ULPI interface (for external high-speed PHY) clock in sleep - * mode. - */ - LL_AHB1_GRP1_DisableClockSleep(LL_AHB1_GRP1_PERIPH_USB1OTGHSULPI); #endif -#else /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32_usbphyc) */ -#if !USB_OTG_HS_ULPI_PHY - /* Disable ULPI interface (for external high-speed PHY) clock in low - * power mode. It is disabled by default in run power mode, no need to - * disable it. +#elif DT_HAS_COMPAT_STATUS_OKAY(st_stm32_otghs) /* USB_OTG_HS_ULPI_PHY */ + /* Disable ULPI interface (for external high-speed PHY) clock in sleep/low-power mode. It is + * disabled by default in run power mode, no need to disable it. */ +#if defined(CONFIG_SOC_SERIES_STM32H7X) + LL_AHB1_GRP1_DisableClockSleep(LL_AHB1_GRP1_PERIPH_USB1OTGHSULPI); +#else LL_AHB1_GRP1_DisableClockLowPower(LL_AHB1_GRP1_PERIPH_OTGHSULPI); +#endif + +#if USB_OTG_HS_EMB_PHY + LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_OTGPHYC); +#endif #endif /* USB_OTG_HS_ULPI_PHY */ -#endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32_usbphyc) */ -#endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32_otghs) */ return 0; } diff --git a/drivers/usb/udc/Kconfig.dwc2 b/drivers/usb/udc/Kconfig.dwc2 index e7f7e782325..a1a1c9d22ce 100644 --- a/drivers/usb/udc/Kconfig.dwc2 +++ b/drivers/usb/udc/Kconfig.dwc2 @@ -5,6 +5,8 @@ config UDC_DWC2 bool "DWC2 USB device controller driver" default y depends on DT_HAS_SNPS_DWC2_ENABLED + select NRFS if NRFS_HAS_VBUS_DETECTOR_SERVICE + select NRFS_VBUS_DETECTOR_SERVICE_ENABLED if NRFS_HAS_VBUS_DETECTOR_SERVICE help DWC2 USB device controller driver. @@ -24,6 +26,7 @@ config UDC_DWC2_THREAD_PRIORITY config UDC_DWC2_MAX_QMESSAGES int "UDC DWC2 maximum number of ISR event messages" + depends on UDC_DWC2 range 4 64 default 8 help diff --git a/drivers/usb/udc/udc_common.c b/drivers/usb/udc/udc_common.c index 90a73d59230..eeed077ebc4 100644 --- a/drivers/usb/udc/udc_common.c +++ b/drivers/usb/udc/udc_common.c @@ -175,10 +175,6 @@ int udc_submit_event(const struct device *dev, .dev = dev, }; - if (!udc_is_initialized(dev)) { - return -EPERM; - } - return data->event_cb(dev, &drv_evt); } diff --git a/drivers/usb/udc/udc_dwc2.c b/drivers/usb/udc/udc_dwc2.c index 0c1463e9798..2f43eb00a50 100644 --- a/drivers/usb/udc/udc_dwc2.c +++ b/drivers/usb/udc/udc_dwc2.c @@ -6,7 +6,6 @@ #include "udc_common.h" #include "udc_dwc2.h" -#include "udc_dwc2_vendor_quirks.h" #include #include @@ -22,6 +21,7 @@ #include LOG_MODULE_REGISTER(udc_dwc2, CONFIG_UDC_DRIVER_LOG_LEVEL); +#include "udc_dwc2_vendor_quirks.h" enum dwc2_drv_event_type { /* Trigger next transfer, must not be used for control OUT */ @@ -54,12 +54,6 @@ K_MSGQ_DEFINE(drv_msgq, sizeof(struct dwc2_drv_event), /* 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)) @@ -75,7 +69,7 @@ struct udc_dwc2_data { uint32_t max_pktcnt; uint32_t tx_len[16]; unsigned int dynfifosizing : 1; - /* Number of endpoints in addition to control endpoint */ + /* Number of endpoints including control endpoint */ uint8_t numdeveps; /* Number of IN endpoints including control endpoint */ uint8_t ineps; @@ -265,6 +259,7 @@ static int dwc2_tx_fifo_write(const struct device *dev, 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; + mem_addr_t diepint_reg = (mem_addr_t)&base->in_ep[ep_idx].diepint; uint32_t max_xfersize, max_pktcnt, pktcnt, spcavail; const size_t d = sizeof(uint32_t); @@ -327,6 +322,8 @@ static int dwc2_tx_fifo_write(const struct device *dev, /* Clear NAK and set endpoint enable */ sys_set_bits(diepctl_reg, USB_DWC2_DEPCTL_EPENA | USB_DWC2_DEPCTL_CNAK); + /* Clear IN Endpoint NAK Effective interrupt in case it was set */ + sys_write32(USB_DWC2_DIEPINT_INEPNAKEFF, diepint_reg); /* FIFO access is always in 32-bit words */ @@ -355,7 +352,7 @@ 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)); + size_t len = buf ? MIN(size, net_buf_tailroom(buf)) : 0; const size_t d = sizeof(uint32_t); /* FIFO access is always in 32-bit words */ @@ -395,7 +392,7 @@ static void dwc2_prep_rx(const struct device *dev, doeptsiz = (1 << USB_DWC2_DOEPTSIZ0_PKTCNT_POS) | cfg->mps; if (cfg->addr == USB_CONTROL_EP_OUT) { - doeptsiz |= (1 << USB_DWC2_DOEPTSIZ0_SUPCNT_POS); + doeptsiz |= (3 << USB_DWC2_DOEPTSIZ0_SUPCNT_POS); } sys_write32(doeptsiz, doeptsiz_reg); @@ -656,7 +653,7 @@ static void dwc2_on_bus_reset(const struct device *dev) } } - sys_write32(0UL, (mem_addr_t)&base->doepmsk); + sys_write32(USB_DWC2_DOEPINT_SETUP, (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); @@ -674,13 +671,19 @@ static void dwc2_handle_enumdone(const struct device *dev) priv->enumspd = usb_dwc2_get_dsts_enumspd(dsts); } -static inline int dwc2_read_fifo_setup(const struct device *dev) +static inline int dwc2_read_fifo_setup(const struct device *dev, uint8_t ep, + const size_t size) { struct usb_dwc2_reg *const base = dwc2_get_base(dev); struct udc_dwc2_data *const priv = udc_get_private(dev); + size_t offset; /* FIFO access is always in 32-bit words */ + if (size != 8) { + LOG_ERR("%d bytes SETUP", size); + } + /* * We store the setup packet temporarily in the driver's private data * because there is always a race risk after the status stage OUT @@ -688,8 +691,16 @@ static inline int dwc2_read_fifo_setup(const struct device *dev) * 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]); + for (offset = 0; offset < MIN(size, 8); offset += 4) { + sys_put_le32(sys_read32(UDC_DWC2_EP_FIFO(base, ep)), + &priv->setup[offset]); + } + + /* On protocol error simply discard extra data */ + while (offset < size) { + sys_read32(UDC_DWC2_EP_FIFO(base, ep)); + offset += 4; + } return 0; } @@ -712,26 +723,23 @@ static inline void dwc2_handle_rxflvl(const struct device *dev) 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); + dwc2_read_fifo_setup(dev, evt.ep, evt.bcnt); 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); + + /* RxFIFO data must be retrieved even when buf is NULL */ + dwc2_read_fifo(dev, evt.ep, buf, evt.bcnt); + 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 { @@ -740,9 +748,13 @@ static inline void dwc2_handle_rxflvl(const struct device *dev) break; case USB_DWC2_GRXSTSR_PKTSTS_OUT_DATA_DONE: - case USB_DWC2_GRXSTSR_PKTSTS_SETUP_DONE: LOG_DBG("RX pktsts DONE"); break; + case USB_DWC2_GRXSTSR_PKTSTS_SETUP_DONE: + LOG_DBG("SETUP pktsts DONE"); + case USB_DWC2_GRXSTSR_PKTSTS_GLOBAL_OUT_NAK: + LOG_DBG("Global OUT NAK"); + break; default: break; } @@ -819,7 +831,6 @@ static inline void dwc2_handle_oepint(const struct device *dev) 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; @@ -832,6 +843,16 @@ static inline void dwc2_handle_oepint(const struct device *dev) sys_write32(status, doepint_reg); LOG_DBG("ep 0x%02x interrupt status: 0x%x", n, status); + + if (status & USB_DWC2_DOEPINT_SETUP) { + struct dwc2_drv_event evt = { + .type = DWC2_DRV_EVT_SETUP, + .ep = USB_CONTROL_EP_OUT, + .bcnt = 8, + }; + + k_msgq_put(&drv_msgq, &evt, K_NO_WAIT); + } } } @@ -865,13 +886,13 @@ static void udc_dwc2_isr_handler(const struct device *dev) 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); + udc_submit_event(dev, UDC_EVT_RESET, 0); } if (int_status & USB_DWC2_GINTSTS_USBSUSP) { @@ -888,25 +909,23 @@ static void udc_dwc2_isr_handler(const struct device *dev) 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_RXFLVL) { + /* Handle RxFIFO Non-Empty interrupt */ + dwc2_handle_rxflvl(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); - } + (void)dwc2_quirk_irq_clear(dev); } static int udc_dwc2_ep_enqueue(const struct device *dev, @@ -946,6 +965,9 @@ static int udc_dwc2_ep_dequeue(const struct device *dev, } irq_unlock(lock_key); + + udc_ep_set_busy(dev, cfg->addr, false); + LOG_DBG("dequeue ep 0x%02x", cfg->addr); return 0; @@ -956,7 +978,7 @@ 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--) { + for (uint8_t i = priv->ineps - 1U; i > 0; i--) { tmp = udc_get_ep_cfg(dev, i | USB_EP_DIR_IN); if (tmp->stat.enabled && (priv->txf_set & BIT(i))) { @@ -1094,8 +1116,8 @@ static int dwc2_ep_control_enable(const struct device *dev, return 0; } -static int udc_dwc2_ep_enable(const struct device *dev, - struct udc_ep_config *const cfg) +static int udc_dwc2_ep_activate(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); @@ -1168,7 +1190,7 @@ static int udc_dwc2_ep_enable(const struct device *dev, 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); + i, sys_read32((mem_addr_t)&base->dieptxf[i - 1U]), i, dxepctl); } return 0; @@ -1199,8 +1221,117 @@ static int dwc2_unset_dedicated_fifo(const struct device *dev, return 0; } -static int udc_dwc2_ep_disable(const struct device *dev, - struct udc_ep_config *const cfg) +static void dwc2_wait_for_bit(mem_addr_t addr, uint32_t bit) +{ + k_timepoint_t timeout = sys_timepoint_calc(K_MSEC(100)); + + /* This could potentially be converted to use proper synchronization + * primitives instead of busy looping, but the number of interrupt bits + * this function can be waiting for is rather high. + * + * Busy looping is most likely fine unless profiling shows otherwise. + */ + while (!(sys_read32(addr) & bit)) { + if (sys_timepoint_expired(timeout)) { + LOG_ERR("Timeout waiting for bit 0x%08X at 0x%08X", + bit, (uint32_t)addr); + return; + } + } +} + +/* Disabled IN endpoint means that device will send NAK (isochronous: ZLP) after + * receiving IN token from host even if there is packet available in TxFIFO. + * Disabled OUT endpoint means that device will NAK (isochronous: discard data) + * incoming OUT data (or HS PING) even if there is space available in RxFIFO. + * + * Set stall parameter to true if caller wants to send STALL instead of NAK. + */ +static void udc_dwc2_ep_disable(const struct device *dev, + struct udc_ep_config *const cfg, bool stall) +{ + struct usb_dwc2_reg *const base = dwc2_get_base(dev); + 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 (USB_EP_DIR_IS_OUT(cfg->addr)) { + mem_addr_t dctl_reg, gintsts_reg, doepint_reg; + uint32_t dctl; + + dctl_reg = (mem_addr_t)&base->dctl; + gintsts_reg = (mem_addr_t)&base->gintsts; + doepint_reg = (mem_addr_t)&base->out_ep[ep_idx].doepint; + + dctl = sys_read32(dctl_reg); + + if (sys_read32(gintsts_reg) & USB_DWC2_GINTSTS_GOUTNAKEFF) { + LOG_ERR("GOUTNAKEFF already active"); + } else { + dctl |= USB_DWC2_DCTL_SGOUTNAK; + sys_write32(dctl, dctl_reg); + dctl &= ~USB_DWC2_DCTL_SGOUTNAK; + } + + dwc2_wait_for_bit(gintsts_reg, USB_DWC2_GINTSTS_GOUTNAKEFF); + + dxepctl |= USB_DWC2_DEPCTL_EPENA | USB_DWC2_DEPCTL_EPDIS; + if (stall) { + /* For OUT endpoints STALL is set instead of SNAK */ + dxepctl |= USB_DWC2_DEPCTL_STALL; + } else { + dxepctl |= USB_DWC2_DEPCTL_SNAK; + } + sys_write32(dxepctl, dxepctl_reg); + + dwc2_wait_for_bit(doepint_reg, USB_DWC2_DOEPINT_EPDISBLD); + + /* Clear Endpoint Disabled interrupt */ + sys_write32(USB_DWC2_DIEPINT_EPDISBLD, doepint_reg); + + dctl |= USB_DWC2_DCTL_CGOUTNAK; + sys_write32(dctl, dctl_reg); + } else { + mem_addr_t diepint_reg; + + diepint_reg = (mem_addr_t)&base->in_ep[ep_idx].diepint; + + dxepctl |= USB_DWC2_DEPCTL_SNAK; + if (stall) { + /* For IN endpoints STALL is set in addition to SNAK */ + dxepctl |= USB_DWC2_DEPCTL_STALL; + } + sys_write32(dxepctl, dxepctl_reg); + + dwc2_wait_for_bit(diepint_reg, USB_DWC2_DIEPINT_INEPNAKEFF); + + dxepctl |= USB_DWC2_DEPCTL_EPENA | USB_DWC2_DEPCTL_EPDIS; + sys_write32(dxepctl, dxepctl_reg); + + dwc2_wait_for_bit(diepint_reg, USB_DWC2_DIEPINT_EPDISBLD); + + /* Clear Endpoint Disabled interrupt */ + sys_write32(USB_DWC2_DIEPINT_EPDISBLD, diepint_reg); + + /* TODO: Read DIEPTSIZn here? Programming Guide suggest it to + * let application know how many bytes of interrupted transfer + * were transferred to the host. + */ + + dwc2_flush_tx_fifo(dev, ep_idx); + } + + udc_ep_set_busy(dev, cfg->addr, false); +} + +/* Deactivated endpoint means that there will be a bus timeout when the host + * tries to access the endpoint. + */ +static int udc_dwc2_ep_deactivate(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; @@ -1212,7 +1343,11 @@ static int udc_dwc2_ep_disable(const struct device *dev, 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; + + udc_dwc2_ep_disable(dev, cfg, false); + + dxepctl = sys_read32(dxepctl_reg); + dxepctl &= ~USB_DWC2_DEPCTL_USBACTEP; } else { LOG_WRN("ep 0x%02x is not active DxEPCTL%u %x", cfg->addr, ep_idx, dxepctl); @@ -1233,7 +1368,7 @@ static int udc_dwc2_ep_set_halt(const struct device *dev, { uint8_t ep_idx = USB_EP_GET_IDX(cfg->addr); - sys_set_bits(dwc2_get_dxepctl_reg(dev, cfg->addr), USB_DWC2_DEPCTL_STALL); + udc_dwc2_ep_disable(dev, cfg, true); LOG_DBG("Set halt ep 0x%02x", cfg->addr); if (ep_idx != 0) { @@ -1246,11 +1381,26 @@ static int udc_dwc2_ep_set_halt(const struct device *dev, 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); + mem_addr_t dxepctl_reg = dwc2_get_dxepctl_reg(dev, cfg->addr); + uint32_t dxepctl; + struct dwc2_drv_event evt = { + .ep = cfg->addr, + .type = DWC2_DRV_EVT_XFER, + }; + + dxepctl = sys_read32(dxepctl_reg); + dxepctl &= ~USB_DWC2_DEPCTL_STALL; + dxepctl |= USB_DWC2_DEPCTL_SETD0PID; + sys_write32(dxepctl, dxepctl_reg); LOG_DBG("Clear halt ep 0x%02x", cfg->addr); cfg->stat.halted = false; + /* Resume queued transfers if any */ + if (udc_buf_peek(dev, cfg->addr)) { + k_msgq_put(&drv_msgq, &evt, K_NO_WAIT); + } + return 0; } @@ -1324,30 +1474,6 @@ static enum udc_bus_speed udc_dwc2_device_speed(const struct device *dev) } } -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); @@ -1386,7 +1512,7 @@ static int dwc2_core_soft_reset(const struct device *dev) return 0; } -static int udc_dwc2_init(const struct device *dev) +static int udc_dwc2_init_controller(const struct device *dev) { const struct udc_dwc2_config *const config = dev->config; struct udc_dwc2_data *const priv = udc_get_private(dev); @@ -1399,19 +1525,6 @@ static int udc_dwc2_init(const struct device *dev) 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; @@ -1441,10 +1554,10 @@ static int udc_dwc2_init(const struct device *dev) } /* 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); + priv->numdeveps = usb_dwc2_get_ghwcfg2_numdeveps(ghwcfg2) + 1U; + priv->ineps = usb_dwc2_get_ghwcfg4_ineps(ghwcfg4) + 1U; + LOG_DBG("Number of endpoints (NUMDEVEPS + 1) %u", priv->numdeveps); + LOG_DBG("Number of IN endpoints (INEPS + 1) %u", priv->ineps); LOG_DBG("Number of periodic IN endpoints (NUMDEVPERIOEPS) %u", usb_dwc2_get_ghwcfg4_numdevperioeps(ghwcfg4)); @@ -1551,27 +1664,53 @@ static int udc_dwc2_init(const struct device *dev) USB_DWC2_GINTSTS_SOF, (mem_addr_t)&base->gintmsk); + return 0; +} - /* 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; - } +static int udc_dwc2_enable(const struct device *dev) +{ + const struct udc_dwc2_config *const config = dev->config; + struct usb_dwc2_reg *const base = dwc2_get_base(dev); + int err; + + err = dwc2_quirk_pre_enable(dev); + if (err) { + LOG_ERR("Quirk pre enable failed %d", err); + return err; + } + + err = udc_dwc2_init_controller(dev); + if (err) { + return err; + } + + err = dwc2_quirk_post_enable(dev); + if (err) { + LOG_ERR("Quirk post enable failed %d", err); + return err; } /* Enable global interrupt */ sys_set_bits((mem_addr_t)&base->gahbcfg, USB_DWC2_GAHBCFG_GLBINTRMASK); config->irq_enable_func(dev); + /* Disable soft disconnect */ + sys_clear_bits((mem_addr_t)&base->dctl, USB_DWC2_DCTL_SFTDISCON); + LOG_DBG("Enable device %p", base); + return 0; } -static int udc_dwc2_shutdown(const struct device *dev) +static int udc_dwc2_disable(const struct device *dev) { const struct udc_dwc2_config *const config = dev->config; - struct usb_dwc2_reg *const base = config->base; + struct usb_dwc2_reg *const base = dwc2_get_base(dev); + mem_addr_t dctl_reg = (mem_addr_t)&base->dctl; + int err; + + /* Enable soft disconnect */ + sys_set_bits(dctl_reg, USB_DWC2_DCTL_SFTDISCON); + LOG_DBG("Disable device %p", dev); config->irq_disable_func(dev); sys_clear_bits((mem_addr_t)&base->gahbcfg, USB_DWC2_GAHBCFG_GLBINTRMASK); @@ -1586,6 +1725,38 @@ static int udc_dwc2_shutdown(const struct device *dev) return -EIO; } + err = dwc2_quirk_disable(dev); + if (err) { + LOG_ERR("Quirk disable failed %d", err); + return err; + } + + return 0; +} + +static int udc_dwc2_init(const struct device *dev) +{ + int ret; + + ret = dwc2_quirk_init(dev); + if (ret) { + LOG_ERR("Quirk init failed %d", ret); + return ret; + } + + return dwc2_init_pinctrl(dev); +} + +static int udc_dwc2_shutdown(const struct device *dev) +{ + int ret; + + ret = dwc2_quirk_shutdown(dev); + if (ret) { + LOG_ERR("Quirk shutdown failed %d", ret); + return ret; + } + return 0; } @@ -1594,6 +1765,8 @@ 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; + uint32_t numdeveps; + uint32_t ineps; int err; k_mutex_init(&data->mutex); @@ -1601,49 +1774,93 @@ static int dwc2_driver_preinit(const struct device *dev) 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; + + (void)dwc2_quirk_caps(dev); + if (data->caps.hs) { mps = 1024; } - for (int i = 0; i < config->num_of_eps; i++) { - config->ep_cfg_out[i].caps.out = 1; + /* + * At this point, we cannot or do not want to access the hardware + * registers to get GHWCFGn values. For now, we will use devicetree to + * get GHWCFGn values and use them to determine the number and type of + * configured endpoints in the hardware. This can be considered a + * workaround, and we may change the upper layer internals to avoid it + * in the future. + */ + ineps = usb_dwc2_get_ghwcfg4_ineps(config->ghwcfg4) + 1U; + numdeveps = usb_dwc2_get_ghwcfg2_numdeveps(config->ghwcfg2) + 1U; + LOG_DBG("Number of endpoints (NUMDEVEPS + 1) %u", numdeveps); + LOG_DBG("Number of IN endpoints (INEPS + 1) %u", ineps); + + for (uint32_t i = 0, n = 0; i < numdeveps; i++) { + uint32_t epdir = usb_dwc2_get_ghwcfg1_epdir(config->ghwcfg1, i); + + if (epdir != USB_DWC2_GHWCFG1_EPDIR_OUT && + epdir != USB_DWC2_GHWCFG1_EPDIR_BDIR) { + continue; + } + if (i == 0) { - config->ep_cfg_out[i].caps.control = 1; - config->ep_cfg_out[i].caps.mps = 64; + config->ep_cfg_out[n].caps.control = 1; + config->ep_cfg_out[n].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[n].caps.bulk = 1; + config->ep_cfg_out[n].caps.interrupt = 1; + config->ep_cfg_out[n].caps.iso = 1; + config->ep_cfg_out[n].caps.mps = mps; } - config->ep_cfg_out[i].addr = USB_EP_DIR_OUT | i; - err = udc_register_ep(dev, &config->ep_cfg_out[i]); + config->ep_cfg_out[n].caps.out = 1; + config->ep_cfg_out[n].addr = USB_EP_DIR_OUT | i; + + LOG_DBG("Register ep 0x%02x (%u)", i, n); + err = udc_register_ep(dev, &config->ep_cfg_out[n]); if (err != 0) { LOG_ERR("Failed to register endpoint"); return err; } + + n++; + /* Also check the number of desired OUT endpoints in devicetree. */ + if (n >= config->num_out_eps) { + break; + } } - for (int i = 0; i < config->num_of_eps; i++) { - config->ep_cfg_in[i].caps.in = 1; + for (uint32_t i = 0, n = 0; i < numdeveps; i++) { + uint32_t epdir = usb_dwc2_get_ghwcfg1_epdir(config->ghwcfg1, i); + + if (epdir != USB_DWC2_GHWCFG1_EPDIR_IN && + epdir != USB_DWC2_GHWCFG1_EPDIR_BDIR) { + continue; + } + if (i == 0) { - config->ep_cfg_in[i].caps.control = 1; - config->ep_cfg_in[i].caps.mps = 64; + config->ep_cfg_in[n].caps.control = 1; + config->ep_cfg_in[n].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[n].caps.bulk = 1; + config->ep_cfg_in[n].caps.interrupt = 1; + config->ep_cfg_in[n].caps.iso = 1; + config->ep_cfg_in[n].caps.mps = mps; } - config->ep_cfg_in[i].addr = USB_EP_DIR_IN | i; - err = udc_register_ep(dev, &config->ep_cfg_in[i]); + config->ep_cfg_in[n].caps.in = 1; + config->ep_cfg_in[n].addr = USB_EP_DIR_IN | i; + + LOG_DBG("Register ep 0x%02x (%u)", USB_EP_DIR_IN | i, n); + err = udc_register_ep(dev, &config->ep_cfg_in[n]); if (err != 0) { LOG_ERR("Failed to register endpoint"); return err; } + + n++; + /* Also check the number of desired IN endpoints in devicetree. */ + if (n >= MIN(ineps, config->num_in_eps)) { + break; + } } config->make_thread(dev); @@ -1672,8 +1889,8 @@ static const struct udc_api udc_dwc2_api = { .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_enable = udc_dwc2_ep_activate, + .ep_disable = udc_dwc2_ep_deactivate, .ep_set_halt = udc_dwc2_ep_set_halt, .ep_clear_halt = udc_dwc2_ep_clear_halt, .ep_enqueue = udc_dwc2_ep_enqueue, @@ -1751,19 +1968,23 @@ static const struct udc_api udc_dwc2_api = { 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 struct udc_ep_config ep_cfg_out[DT_INST_PROP(n, num_out_eps)]; \ + static struct udc_ep_config ep_cfg_in[DT_INST_PROP(n, num_in_eps)]; \ \ 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, \ + .num_out_eps = DT_INST_PROP(n, num_out_eps), \ + .num_in_eps = DT_INST_PROP(n, num_in_eps), \ + .ep_cfg_in = ep_cfg_in, \ + .ep_cfg_out = ep_cfg_out, \ .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), \ + .ghwcfg1 = DT_INST_PROP(n, ghwcfg1), \ + .ghwcfg2 = DT_INST_PROP(n, ghwcfg2), \ + .ghwcfg4 = DT_INST_PROP(n, ghwcfg4), \ }; \ \ static struct udc_dwc2_data udc_priv_##n = { \ diff --git a/drivers/usb/udc/udc_dwc2.h b/drivers/usb/udc/udc_dwc2.h index 11d8178c135..b54cb82fd2a 100644 --- a/drivers/usb/udc/udc_dwc2.h +++ b/drivers/usb/udc/udc_dwc2.h @@ -14,19 +14,28 @@ /* 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); + /* Called at the beginning of udc_dwc2_init() */ + int (*init)(const struct device *dev); + /* Called on udc_dwc2_enable() before the controller is initialized */ + int (*pre_enable)(const struct device *dev); + /* Called on udc_dwc2_enable() after the controller is initialized */ + int (*post_enable)(const struct device *dev); + /* Called at the end of udc_dwc2_disable() */ + int (*disable)(const struct device *dev); + /* Called at the end of udc_dwc2_shutdown() */ + int (*shutdown)(const struct device *dev); + /* Called at the end of IRQ handling */ int (*irq_clear)(const struct device *dev); + /* Called on driver pre-init */ + int (*caps)(const struct device *dev); }; /* Driver configuration per instance */ struct udc_dwc2_config { - size_t num_of_eps; + size_t num_in_eps; + size_t num_out_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; @@ -35,6 +44,30 @@ struct udc_dwc2_config { void (*make_thread)(const struct device *dev); void (*irq_enable_func)(const struct device *dev); void (*irq_disable_func)(const struct device *dev); + uint32_t ghwcfg1; + uint32_t ghwcfg2; + uint32_t ghwcfg4; }; +#define DWC2_QUIRK_FUNC_DEFINE(fname) \ +static inline int dwc2_quirk_##fname(const struct device *dev) \ +{ \ + const struct udc_dwc2_config *const config = dev->config; \ + struct dwc2_vendor_quirks *quirks = config->quirks; \ + \ + if (quirks != NULL && config->quirks->fname != NULL) { \ + return quirks->fname(dev); \ + } \ + \ + return 0; \ +} + +DWC2_QUIRK_FUNC_DEFINE(init) +DWC2_QUIRK_FUNC_DEFINE(pre_enable) +DWC2_QUIRK_FUNC_DEFINE(post_enable) +DWC2_QUIRK_FUNC_DEFINE(disable) +DWC2_QUIRK_FUNC_DEFINE(shutdown) +DWC2_QUIRK_FUNC_DEFINE(irq_clear) +DWC2_QUIRK_FUNC_DEFINE(caps) + #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 index 104cb5cb847..2311dd80308 100644 --- a/drivers/usb/udc/udc_dwc2_vendor_quirks.h +++ b/drivers/usb/udc/udc_dwc2_vendor_quirks.h @@ -11,13 +11,14 @@ #include #include +#include + +#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32f4_fsotg) + #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; @@ -26,7 +27,7 @@ struct usb_dw_stm32_clk { #define DT_DRV_COMPAT snps_dwc2 -static inline int clk_enable_stm32f4_fsotg(const struct usb_dw_stm32_clk *const clk) +static inline int stm32f4_fsotg_enable_clk(const struct usb_dw_stm32_clk *const clk) { int ret; @@ -59,7 +60,7 @@ static inline int clk_enable_stm32f4_fsotg(const struct usb_dw_stm32_clk *const return clock_control_on(clk->dev, (void *)&clk->pclken[0]); } -static inline int pwr_on_stm32f4_fsotg(const struct device *dev) +static inline int stm32f4_fsotg_enable_phy(const struct device *dev) { const struct udc_dwc2_config *const config = dev->config; mem_addr_t ggpio_reg = (mem_addr_t)&config->base->ggpio; @@ -69,6 +70,16 @@ static inline int pwr_on_stm32f4_fsotg(const struct device *dev) return 0; } +static inline int stm32f4_fsotg_disable_phy(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_clear_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);\ \ @@ -78,14 +89,15 @@ static inline int pwr_on_stm32f4_fsotg(const struct device *dev) .pclken_len = DT_INST_NUM_CLOCKS(n), \ }; \ \ - static int clk_enable_stm32f4_fsotg_##n(const struct device *dev) \ + static int stm32f4_fsotg_enable_clk_##n(const struct device *dev) \ { \ - return clk_enable_stm32f4_fsotg(&stm32f4_clk_##n); \ + return stm32f4_fsotg_enable_clk(&stm32f4_clk_##n); \ } \ \ struct dwc2_vendor_quirks dwc2_vendor_quirks_##n = { \ - .clk_enable = clk_enable_stm32f4_fsotg_##n, \ - .pwr_on = pwr_on_stm32f4_fsotg, \ + .pre_enable = stm32f4_fsotg_enable_clk_##n, \ + .post_enable = stm32f4_fsotg_enable_phy, \ + .disable = stm32f4_fsotg_disable_phy, \ .irq_clear = NULL, \ }; @@ -96,6 +108,158 @@ DT_INST_FOREACH_STATUS_OKAY(QUIRK_STM32F4_FSOTG_DEFINE) #endif /*DT_HAS_COMPAT_STATUS_OKAY(st_stm32f4_fsotg) */ +#if DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_usbhs) + +#define DT_DRV_COMPAT snps_dwc2 + +#include +#include + +#define USBHS_DT_WRAPPER_REG_ADDR(n) UINT_TO_POINTER(DT_INST_REG_ADDR_BY_NAME(n, wrapper)) + +/* + * On USBHS, we cannot access the DWC2 register until VBUS is detected and + * valid. If the user tries to force usbd_enable() and the corresponding + * udc_enable() without a "VBUS ready" notification, the event wait will block + * until a valid VBUS signal is detected. + */ +static K_EVENT_DEFINE(usbhs_events); +#define USBHS_VBUS_READY BIT(0) + +static void usbhs_vbus_handler(nrfs_usb_evt_t const *p_evt, void *const context) +{ + const struct device *dev = context; + + switch (p_evt->type) { + case NRFS_USB_EVT_VBUS_STATUS_CHANGE: + LOG_DBG("USBHS new status, pll_ok = %d vreg_ok = %d vbus_detected = %d", + p_evt->usbhspll_ok, p_evt->vregusb_ok, p_evt->vbus_detected); + + if (p_evt->usbhspll_ok && p_evt->vregusb_ok && p_evt->vbus_detected) { + k_event_post(&usbhs_events, USBHS_VBUS_READY); + udc_submit_event(dev, UDC_EVT_VBUS_READY, 0); + } else { + k_event_set_masked(&usbhs_events, 0, USBHS_VBUS_READY); + udc_submit_event(dev, UDC_EVT_VBUS_REMOVED, 0); + } + + break; + case NRFS_USB_EVT_REJECT: + LOG_ERR("Request rejected"); + break; + default: + LOG_ERR("Unknown event type 0x%x", p_evt->type); + break; + } +} + +static inline int usbhs_enable_nrfs_service(const struct device *dev) +{ + nrfs_err_t nrfs_err; + int err; + + err = nrfs_backend_wait_for_connection(K_MSEC(1000)); + if (err) { + LOG_INF("NRFS backend connection timeout"); + return err; + } + + nrfs_err = nrfs_usb_init(usbhs_vbus_handler); + if (nrfs_err != NRFS_SUCCESS) { + LOG_ERR("Failed to init NRFS VBUS handler: %d", nrfs_err); + return -EIO; + } + + nrfs_err = nrfs_usb_enable_request((void *)dev); + if (nrfs_err != NRFS_SUCCESS) { + LOG_ERR("Failed to enable NRFS VBUS service: %d", nrfs_err); + return -EIO; + } + + return 0; +} + +static inline int usbhs_enable_core(const struct device *dev) +{ + NRF_USBHS_Type *wrapper = USBHS_DT_WRAPPER_REG_ADDR(0); + + if (!k_event_wait(&usbhs_events, USBHS_VBUS_READY, false, K_NO_WAIT)) { + LOG_WRN("VBUS is not ready, block udc_enable()"); + k_event_wait(&usbhs_events, USBHS_VBUS_READY, false, K_FOREVER); + } + + wrapper->ENABLE = USBHS_ENABLE_PHY_Msk | USBHS_ENABLE_CORE_Msk; + wrapper->TASKS_START = 1UL; + + /* Enable interrupts */ + wrapper->INTENSET = 1UL; + + return 0; +} + +static inline int usbhs_disable_core(const struct device *dev) +{ + NRF_USBHS_Type *wrapper = USBHS_DT_WRAPPER_REG_ADDR(0); + + /* Disable interrupts */ + wrapper->INTENCLR = 1UL; + + wrapper->ENABLE = 0UL; + wrapper->TASKS_START = 1UL; + + return 0; +} + +static inline int usbhs_disable_nrfs_service(const struct device *dev) +{ + nrfs_err_t nrfs_err; + + nrfs_err = nrfs_usb_disable_request((void *)dev); + if (nrfs_err != NRFS_SUCCESS) { + LOG_ERR("Failed to disable NRFS VBUS service: %d", nrfs_err); + return -EIO; + } + + nrfs_usb_uninit(); + + return 0; +} + +static inline int usbhs_irq_clear(const struct device *dev) +{ + NRF_USBHS_Type *wrapper = USBHS_DT_WRAPPER_REG_ADDR(0); + + wrapper->EVENTS_CORE = 0UL; + + return 0; +} + +static inline int usbhs_init_caps(const struct device *dev) +{ + struct udc_data *data = dev->data; + + data->caps.can_detect_vbus = true; + data->caps.hs = true; + + return 0; +} + +#define QUIRK_NRF_USBHS_DEFINE(n) \ + struct dwc2_vendor_quirks dwc2_vendor_quirks_##n = { \ + .init = usbhs_enable_nrfs_service, \ + .pre_enable = usbhs_enable_core, \ + .disable = usbhs_disable_core, \ + .shutdown = usbhs_disable_nrfs_service, \ + .irq_clear = usbhs_irq_clear, \ + .caps = usbhs_init_caps, \ + }; + +DT_INST_FOREACH_STATUS_OKAY(QUIRK_NRF_USBHS_DEFINE) + +#undef DT_DRV_COMPAT + +#endif /*DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_usbhs) */ + /* Add next vendor quirks definition above this line */ #endif /* ZEPHYR_DRIVERS_USB_UDC_DWC2_VENDOR_QUIRKS_H */ diff --git a/drivers/usb/udc/udc_kinetis.c b/drivers/usb/udc/udc_kinetis.c index e5bee42c0ad..38dd1db2d04 100644 --- a/drivers/usb/udc/udc_kinetis.c +++ b/drivers/usb/udc/udc_kinetis.c @@ -821,7 +821,8 @@ static int usbfsotg_ep_clear_halt(const struct device *dev, if (USB_EP_GET_IDX(cfg->addr) == 0U) { usbfsotg_resume_tx(dev); } else { - /* TODO: trigger queued transfers? */ + /* trigger queued transfers */ + usbfsotg_event_submit(dev, cfg->addr, USBFSOTG_EVT_XFER); } return 0; diff --git a/drivers/usb/udc/udc_nrf.c b/drivers/usb/udc/udc_nrf.c index d4ecc130587..f02dfcdc308 100644 --- a/drivers/usb/udc/udc_nrf.c +++ b/drivers/usb/udc/udc_nrf.c @@ -470,14 +470,14 @@ static void udc_nrf_power_handler(nrfx_power_usb_evt_t pwr_evt) switch (pwr_evt) { case NRFX_POWER_USB_EVT_DETECTED: LOG_DBG("POWER event detected"); + udc_submit_event(udc_nrf_dev, UDC_EVT_VBUS_READY, 0); break; case NRFX_POWER_USB_EVT_READY: - LOG_INF("POWER event ready"); - udc_submit_event(udc_nrf_dev, UDC_EVT_VBUS_READY, 0); + LOG_DBG("POWER event ready"); nrf_usbd_common_start(true); break; case NRFX_POWER_USB_EVT_REMOVED: - LOG_INF("POWER event removed"); + LOG_DBG("POWER event removed"); udc_submit_event(udc_nrf_dev, UDC_EVT_VBUS_REMOVED, 0); break; default: @@ -631,9 +631,26 @@ static int udc_nrf_host_wakeup(const struct device *dev) static int udc_nrf_enable(const struct device *dev) { + unsigned int key; int ret; - nrf_usbd_common_enable(); + ret = nrf_usbd_common_init(usbd_event_handler); + if (ret != NRFX_SUCCESS) { + LOG_ERR("nRF USBD driver initialization failed"); + return -EIO; + } + + if (udc_ep_enable_internal(dev, USB_CONTROL_EP_OUT, + USB_EP_TYPE_CONTROL, UDC_NRF_EP0_SIZE, 0)) { + LOG_ERR("Failed to enable control endpoint"); + return -EIO; + } + + if (udc_ep_enable_internal(dev, USB_CONTROL_EP_IN, + USB_EP_TYPE_CONTROL, UDC_NRF_EP0_SIZE, 0)) { + LOG_ERR("Failed to enable control endpoint"); + return -EIO; + } sys_notify_init_spinwait(&hfxo_cli.notify); ret = onoff_request(hfxo_mgr, &hfxo_cli); @@ -642,6 +659,11 @@ static int udc_nrf_enable(const struct device *dev) return ret; } + /* Disable interrupts until USBD is enabled */ + key = irq_lock(); + nrf_usbd_common_enable(); + irq_unlock(key); + return 0; } @@ -651,6 +673,18 @@ static int udc_nrf_disable(const struct device *dev) nrf_usbd_common_disable(); + if (udc_ep_disable_internal(dev, USB_CONTROL_EP_OUT)) { + LOG_ERR("Failed to disable control endpoint"); + return -EIO; + } + + if (udc_ep_disable_internal(dev, USB_CONTROL_EP_IN)) { + LOG_ERR("Failed to disable control endpoint"); + return -EIO; + } + + nrf_usbd_common_uninit(); + ret = onoff_cancel_or_release(hfxo_mgr, &hfxo_cli); if (ret < 0) { LOG_ERR("Failed to stop HFXO %d", ret); @@ -663,7 +697,6 @@ static int udc_nrf_disable(const struct device *dev) static int udc_nrf_init(const struct device *dev) { const struct udc_nrf_config *cfg = dev->config; - int ret; hfxo_mgr = z_nrf_clock_control_get_onoff(cfg->clock); @@ -683,25 +716,7 @@ static int udc_nrf_init(const struct device *dev) (void)nrfx_power_init(&cfg->pwr); nrfx_power_usbevt_init(&cfg->evt); - ret = nrf_usbd_common_init(usbd_event_handler); - if (ret != NRFX_SUCCESS) { - LOG_ERR("nRF USBD driver initialization failed"); - return -EIO; - } - nrfx_power_usbevt_enable(); - if (udc_ep_enable_internal(dev, USB_CONTROL_EP_OUT, - USB_EP_TYPE_CONTROL, UDC_NRF_EP0_SIZE, 0)) { - LOG_ERR("Failed to enable control endpoint"); - return -EIO; - } - - if (udc_ep_enable_internal(dev, USB_CONTROL_EP_IN, - USB_EP_TYPE_CONTROL, UDC_NRF_EP0_SIZE, 0)) { - LOG_ERR("Failed to enable control endpoint"); - return -EIO; - } - LOG_INF("Initialized"); return 0; @@ -711,18 +726,7 @@ static int udc_nrf_shutdown(const struct device *dev) { LOG_INF("shutdown"); - if (udc_ep_disable_internal(dev, USB_CONTROL_EP_OUT)) { - LOG_ERR("Failed to disable control endpoint"); - return -EIO; - } - - if (udc_ep_disable_internal(dev, USB_CONTROL_EP_IN)) { - LOG_ERR("Failed to disable control endpoint"); - return -EIO; - } - nrfx_power_usbevt_disable(); - nrf_usbd_common_uninit(); nrfx_power_usbevt_uninit(); #ifdef CONFIG_HAS_HW_NRF_USBREG irq_disable(USBREGULATOR_IRQn); @@ -794,6 +798,7 @@ static int udc_nrf_driver_init(const struct device *dev) data->caps.rwup = true; data->caps.out_ack = true; data->caps.mps0 = UDC_NRF_MPS0; + data->caps.can_detect_vbus = true; return 0; } diff --git a/drivers/usb/udc/udc_stm32.c b/drivers/usb/udc/udc_stm32.c index 9b912f792c9..e86893b1b18 100644 --- a/drivers/usb/udc/udc_stm32.c +++ b/drivers/usb/udc/udc_stm32.c @@ -465,14 +465,17 @@ static int udc_stm32_ep_mem_config(const struct device *dev, return 0; } + words = MIN(ep->mps, cfg->ep_mps) / 4; + words = (words <= 64) ? words * 2 : words; + if (!enable) { + if (priv->occupied_mem >= (words * 4)) { + priv->occupied_mem -= (words * 4); + } HAL_PCDEx_SetTxFiFo(&priv->pcd, USB_EP_GET_IDX(ep->addr), 0); return 0; } - words = MIN(ep->mps, cfg->ep_mps) / 4; - words = (words <= 64) ? words * 2 : words; - if (cfg->dram_size - priv->occupied_mem < words * 4) { LOG_ERR("Unable to allocate FIFO for 0x%02x", ep->addr); return -ENOMEM; @@ -971,33 +974,31 @@ static int priv_clock_enable(void) #endif /* RCC_CFGR_OTGFSPRE / RCC_CFGR_USBPRE */ -#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_otghs) -#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_usbphyc) +#if USB_OTG_HS_ULPI_PHY +#if defined(CONFIG_SOC_SERIES_STM32H7X) + LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_USB1OTGHSULPI); +#else LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_OTGHSULPI); - LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_OTGPHYC); -#elif defined(CONFIG_SOC_SERIES_STM32H7X) -#if !USB_OTG_HS_ULPI_PHY - /* Disable ULPI interface (for external high-speed PHY) clock in sleep - * mode. +#endif +#elif DT_HAS_COMPAT_STATUS_OKAY(st_stm32_otghs) /* USB_OTG_HS_ULPI_PHY */ + /* Disable ULPI interface (for external high-speed PHY) clock in sleep/low-power mode. It is + * disabled by default in run power mode, no need to disable it. */ +#if defined(CONFIG_SOC_SERIES_STM32H7X) LL_AHB1_GRP1_DisableClockSleep(LL_AHB1_GRP1_PERIPH_USB1OTGHSULPI); +#else + LL_AHB1_GRP1_DisableClockLowPower(LL_AHB1_GRP1_PERIPH_OTGHSULPI); +#endif /* defined(CONFIG_SOC_SERIES_STM32H7X) */ + +#if USB_OTG_HS_EMB_PHY + LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_OTGPHYC); #endif -#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_otgfs) +#elif defined(CONFIG_SOC_SERIES_STM32H7X) && DT_HAS_COMPAT_STATUS_OKAY(st_stm32_otgfs) /* The USB2 controller only works in FS mode, but the ULPI clock needs * to be disabled in sleep mode for it to work. */ LL_AHB1_GRP1_DisableClockSleep(LL_AHB1_GRP1_PERIPH_USB2OTGHSULPI); -#endif -#else /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32_usbphyc) */ -#if !USB_OTG_HS_ULPI_PHY - /* Disable ULPI interface (for external high-speed PHY) clock in low - * power mode. It is disabled by default in run power mode, no need to - * disable it. - */ - LL_AHB1_GRP1_DisableClockLowPower(LL_AHB1_GRP1_PERIPH_OTGHSULPI); #endif /* USB_OTG_HS_ULPI_PHY */ -#endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32_usbphyc) */ -#endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32_otghs) */ return 0; } diff --git a/drivers/usb/uvb/uvb.ld b/drivers/usb/uvb/uvb.ld index 424fbf40daa..12f52aceb38 100644 --- a/drivers/usb/uvb/uvb.ld +++ b/drivers/usb/uvb/uvb.ld @@ -1 +1 @@ -ITERABLE_SECTION_RAM(uvb_node, 4) +ITERABLE_SECTION_RAM(uvb_node, Z_LINK_ITERABLE_SUBALIGN) diff --git a/drivers/usb_c/ppc/nxp_nx20p3483.c b/drivers/usb_c/ppc/nxp_nx20p3483.c index 8b6a2fe914d..35d1db70798 100644 --- a/drivers/usb_c/ppc/nxp_nx20p3483.c +++ b/drivers/usb_c/ppc/nxp_nx20p3483.c @@ -229,7 +229,7 @@ static int nx20p3483_dump_regs(const struct device *dev) return 0; } -static struct usbc_ppc_drv nx20p3483_driver_api = { +static struct usbc_ppc_driver_api 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, diff --git a/drivers/video/CMakeLists.txt b/drivers/video/CMakeLists.txt index 68fd96d1b4c..19ad0e2bc79 100644 --- a/drivers/video/CMakeLists.txt +++ b/drivers/video/CMakeLists.txt @@ -5,7 +5,10 @@ zephyr_library() zephyr_library_sources(video_common.c) zephyr_library_sources_ifdef(CONFIG_VIDEO_MCUX_CSI video_mcux_csi.c) +zephyr_library_sources_ifdef(CONFIG_VIDEO_MCUX_MIPI_CSI2RX video_mcux_mipi_csi2rx.c) zephyr_library_sources_ifdef(CONFIG_VIDEO_SW_GENERATOR video_sw_generator.c) zephyr_library_sources_ifdef(CONFIG_VIDEO_MT9M114 mt9m114.c) zephyr_library_sources_ifdef(CONFIG_VIDEO_OV7725 ov7725.c) zephyr_library_sources_ifdef(CONFIG_VIDEO_OV2640 ov2640.c) +zephyr_library_sources_ifdef(CONFIG_VIDEO_STM32_DCMI video_stm32_dcmi.c) +zephyr_library_sources_ifdef(CONFIG_VIDEO_OV5640 ov5640.c) diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 488ad6c80cc..787311622e0 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -33,6 +33,8 @@ config VIDEO_BUFFER_POOL_ALIGN source "drivers/video/Kconfig.mcux_csi" +source "drivers/video/Kconfig.mcux_mipi_csi2rx" + source "drivers/video/Kconfig.sw_generator" source "drivers/video/Kconfig.mt9m114" @@ -41,4 +43,8 @@ source "drivers/video/Kconfig.ov7725" source "drivers/video/Kconfig.ov2640" +source "drivers/video/Kconfig.stm32_dcmi" + +source "drivers/video/Kconfig.ov5640" + endif # VIDEO diff --git a/drivers/video/Kconfig.mcux_csi b/drivers/video/Kconfig.mcux_csi index 18adaab4c50..0f1263f041c 100644 --- a/drivers/video/Kconfig.mcux_csi +++ b/drivers/video/Kconfig.mcux_csi @@ -6,7 +6,6 @@ config VIDEO_MCUX_CSI bool "NXP MCUX CMOS Sensor Interface (CSI) driver" default y - depends on HAS_MCUX_CSI depends on DT_HAS_NXP_IMX_CSI_ENABLED config VIDEO_MCUX_CSI_INIT_PRIORITY diff --git a/drivers/video/Kconfig.mcux_mipi_csi2rx b/drivers/video/Kconfig.mcux_mipi_csi2rx new file mode 100644 index 00000000000..f9bf2f19f1e --- /dev/null +++ b/drivers/video/Kconfig.mcux_mipi_csi2rx @@ -0,0 +1,10 @@ +# NXP MIPI CSI-2 Rx driver configuration option + +# Copyright 2024 NXP +# SPDX-License-Identifier: Apache-2.0 + +config VIDEO_MCUX_MIPI_CSI2RX + bool "NXP MIPI CSI-2 Rx driver" + default y + depends on DT_HAS_NXP_MIPI_CSI2RX_ENABLED + select VIDEO_MCUX_CSI diff --git a/drivers/video/Kconfig.ov5640 b/drivers/video/Kconfig.ov5640 new file mode 100644 index 00000000000..950079dd355 --- /dev/null +++ b/drivers/video/Kconfig.ov5640 @@ -0,0 +1,12 @@ +# OV5640 + +# Copyright 2024 NXP +# SPDX-License-Identifier: Apache-2.0 + +config VIDEO_OV5640 + bool "OV5640 CMOS digital image sensor" + select I2C + depends on DT_HAS_OVTI_OV5640_ENABLED + default y + help + Enable driver for OV5640 CMOS digital image sensor device diff --git a/drivers/video/Kconfig.stm32_dcmi b/drivers/video/Kconfig.stm32_dcmi new file mode 100644 index 00000000000..8f0c11a42c7 --- /dev/null +++ b/drivers/video/Kconfig.stm32_dcmi @@ -0,0 +1,22 @@ +# STM32 DCMI driver configuration options + +# Copyright (c) 2024 Charles Dias +# SPDX-License-Identifier: Apache-2.0 + +DT_STM32_DCMI_HAS_DMA := $(dt_nodelabel_has_prop,dcmi,dmas) + +config VIDEO_STM32_DCMI + bool "STM32 Digital camera interface (DCMI) driver" + default y + depends on DT_HAS_ST_STM32_DCMI_ENABLED + select USE_STM32_HAL_DCMI + select USE_STM32_HAL_MDMA if SOC_SERIES_STM32H7X + select DMA if $(DT_STM32_DCMI_HAS_DMA) + select USE_STM32_HAL_DMA if $(DT_STM32_DCMI_HAS_DMA) + select USE_STM32_HAL_DMA_EX if $(DT_STM32_DCMI_HAS_DMA) + help + Enable driver for STM32 Digital camera interface periheral. + +module = STM32_DCMI +module-str = stm32_dcmi +source "subsys/logging/Kconfig.template.log_config" diff --git a/drivers/video/ov2640.c b/drivers/video/ov2640.c index 92e42bbb91f..c9da591fa42 100644 --- a/drivers/video/ov2640.c +++ b/drivers/video/ov2640.c @@ -435,6 +435,7 @@ struct ov2640_config { #if DT_INST_NODE_HAS_PROP(0, reset_gpios) struct gpio_dt_spec reset_gpio; #endif + uint8_t clock_rate_control; }; struct ov2640_data { @@ -821,7 +822,7 @@ static int ov2640_set_resolution(const struct device *dev, /* Set CLKRC */ ret |= ov2640_write_reg(&cfg->i2c, BANK_SEL, BANK_SEL_SENSOR); - ret |= ov2640_write_reg(&cfg->i2c, CLKRC, 0x87); + ret |= ov2640_write_reg(&cfg->i2c, CLKRC, cfg->clock_rate_control); /* Write DSP input registers */ ov2640_write_all(dev, uxga_regs, ARRAY_SIZE(uxga_regs)); @@ -1030,6 +1031,7 @@ static const struct ov2640_config ov2640_cfg_0 = { #if DT_INST_NODE_HAS_PROP(0, reset_gpios) .reset_gpio = GPIO_DT_SPEC_INST_GET(0, reset_gpios), #endif + .clock_rate_control = DT_INST_PROP(0, clock_rate_control), }; static struct ov2640_data ov2640_data_0; diff --git a/drivers/video/ov5640.c b/drivers/video/ov5640.c new file mode 100644 index 00000000000..7c76c7b88c9 --- /dev/null +++ b/drivers/video/ov5640.c @@ -0,0 +1,698 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT ovti_ov5640 + +#include +#include +#include +#include +#include + +#define LOG_LEVEL CONFIG_LOG_DEFAULT_LEVEL +#include +LOG_MODULE_REGISTER(ov5640); + +#include + +#define CHIP_ID_REG 0x300a +#define CHIP_ID_VAL 0x5640 + +#define SYS_CTRL0_REG 0x3008 +#define SYS_CTRL0_SW_PWDN 0x42 +#define SYS_CTRL0_SW_PWUP 0x02 +#define SYS_CTRL0_SW_RST 0x82 + +#define SYS_RESET00_REG 0x3000 +#define SYS_RESET02_REG 0x3002 +#define SYS_CLK_ENABLE00_REG 0x3004 +#define SYS_CLK_ENABLE02_REG 0x3006 +#define IO_MIPI_CTRL00_REG 0x300e +#define SYSTEM_CONTROL1_REG 0x302e +#define SCCB_SYS_CTRL1_REG 0x3103 +#define TIMING_TC_REG20_REG 0x3820 +#define TIMING_TC_REG21_REG 0x3821 +#define HZ5060_CTRL01_REG 0x3c01 +#define ISP_CTRL01_REG 0x5001 + +#define SC_PLL_CTRL0_REG 0x3034 +#define SC_PLL_CTRL1_REG 0x3035 +#define SC_PLL_CTRL2_REG 0x3036 +#define SC_PLL_CTRL3_REG 0x3037 +#define SYS_ROOT_DIV_REG 0x3108 +#define PCLK_PERIOD_REG 0x4837 + +#define AEC_CTRL00_REG 0x3a00 +#define AEC_CTRL0F_REG 0x3a0f +#define AEC_CTRL10_REG 0x3a10 +#define AEC_CTRL11_REG 0x3a11 +#define AEC_CTRL1B_REG 0x3a1b +#define AEC_CTRL1E_REG 0x3a1e +#define AEC_CTRL1F_REG 0x3a1f + +#define BLC_CTRL01_REG 0x4001 +#define BLC_CTRL04_REG 0x4004 +#define BLC_CTRL05_REG 0x4005 + +#define AWB_CTRL00_REG 0x5180 +#define AWB_CTRL01_REG 0x5181 +#define AWB_CTRL02_REG 0x5182 +#define AWB_CTRL03_REG 0x5183 +#define AWB_CTRL04_REG 0x5184 +#define AWB_CTRL05_REG 0x5185 +#define AWB_CTRL17_REG 0x5191 +#define AWB_CTRL18_REG 0x5192 +#define AWB_CTRL19_REG 0x5193 +#define AWB_CTRL20_REG 0x5194 +#define AWB_CTRL21_REG 0x5195 +#define AWB_CTRL22_REG 0x5196 +#define AWB_CTRL23_REG 0x5197 +#define AWB_CTRL30_REG 0x519e + +#define SDE_CTRL0_REG 0x5580 +#define SDE_CTRL3_REG 0x5583 +#define SDE_CTRL4_REG 0x5584 +#define SDE_CTRL9_REG 0x5589 +#define SDE_CTRL10_REG 0x558a +#define SDE_CTRL11_REG 0x558b + +#define DEFAULT_MIPI_CHANNEL 0 + +#define OV5640_RESOLUTION_PARAM_NUM 24 + +struct ov5640_config { + struct i2c_dt_spec i2c; + struct gpio_dt_spec reset_gpio; + struct gpio_dt_spec powerdown_gpio; +}; + +struct ov5640_data { + struct video_format fmt; +}; + +struct ov5640_reg { + uint16_t addr; + uint8_t val; +}; + +struct ov5640_mipi_clock_config { + uint8_t pllCtrl1; + uint8_t pllCtrl2; +}; + +struct ov5640_resolution_config { + uint16_t width; + uint16_t height; + const struct ov5640_reg *res_params; + const struct ov5640_mipi_clock_config mipi_pclk; +}; + +static const struct ov5640_reg ov5640InitParams[] = { + /* Power down */ + {SYS_CTRL0_REG, SYS_CTRL0_SW_PWDN}, + + /* System setting. */ + {SCCB_SYS_CTRL1_REG, 0x13}, + {SCCB_SYS_CTRL1_REG, 0x03}, + {SYS_RESET00_REG, 0x00}, + {SYS_CLK_ENABLE00_REG, 0xff}, + {SYS_RESET02_REG, 0x1c}, + {SYS_CLK_ENABLE02_REG, 0xc3}, + {SYSTEM_CONTROL1_REG, 0x08}, + {0x3618, 0x00}, + {0x3612, 0x29}, + {0x3708, 0x64}, + {0x3709, 0x52}, + {0x370c, 0x03}, + {TIMING_TC_REG20_REG, 0x41}, + {TIMING_TC_REG21_REG, 0x07}, + {0x3630, 0x36}, + {0x3631, 0x0e}, + {0x3632, 0xe2}, + {0x3633, 0x12}, + {0x3621, 0xe0}, + {0x3704, 0xa0}, + {0x3703, 0x5a}, + {0x3715, 0x78}, + {0x3717, 0x01}, + {0x370b, 0x60}, + {0x3705, 0x1a}, + {0x3905, 0x02}, + {0x3906, 0x10}, + {0x3901, 0x0a}, + {0x3731, 0x12}, + {0x3600, 0x08}, + {0x3601, 0x33}, + {0x302d, 0x60}, + {0x3620, 0x52}, + {0x371b, 0x20}, + {0x471c, 0x50}, + {0x3a13, 0x43}, + {0x3a18, 0x00}, + {0x3a19, 0x7c}, + {0x3635, 0x13}, + {0x3636, 0x03}, + {0x3634, 0x40}, + {0x3622, 0x01}, + {HZ5060_CTRL01_REG, 0x00}, + {AEC_CTRL00_REG, 0x58}, + {BLC_CTRL01_REG, 0x02}, + {BLC_CTRL04_REG, 0x02}, + {BLC_CTRL05_REG, 0x1a}, + {ISP_CTRL01_REG, 0xa3}, + + /* AEC */ + {AEC_CTRL0F_REG, 0x30}, + {AEC_CTRL10_REG, 0x28}, + {AEC_CTRL1B_REG, 0x30}, + {AEC_CTRL1E_REG, 0x26}, + {AEC_CTRL11_REG, 0x60}, + {AEC_CTRL1F_REG, 0x14}, + + /* AWB */ + {AWB_CTRL00_REG, 0xff}, + {AWB_CTRL01_REG, 0xf2}, + {AWB_CTRL02_REG, 0x00}, + {AWB_CTRL03_REG, 0x14}, + {AWB_CTRL04_REG, 0x25}, + {AWB_CTRL05_REG, 0x24}, + {0x5186, 0x09}, + {0x5187, 0x09}, + {0x5188, 0x09}, + {0x5189, 0x88}, + {0x518a, 0x54}, + {0x518b, 0xee}, + {0x518c, 0xb2}, + {0x518d, 0x50}, + {0x518e, 0x34}, + {0x518f, 0x6b}, + {0x5190, 0x46}, + {AWB_CTRL17_REG, 0xf8}, + {AWB_CTRL18_REG, 0x04}, + {AWB_CTRL19_REG, 0x70}, + {AWB_CTRL20_REG, 0xf0}, + {AWB_CTRL21_REG, 0xf0}, + {AWB_CTRL22_REG, 0x03}, + {AWB_CTRL23_REG, 0x01}, + {0x5198, 0x04}, + {0x5199, 0x6c}, + {0x519a, 0x04}, + {0x519b, 0x00}, + {0x519c, 0x09}, + {0x519d, 0x2b}, + {AWB_CTRL30_REG, 0x38}, + + /* Color Matrix */ + {0x5381, 0x1e}, + {0x5382, 0x5b}, + {0x5383, 0x08}, + {0x5384, 0x0a}, + {0x5385, 0x7e}, + {0x5386, 0x88}, + {0x5387, 0x7c}, + {0x5388, 0x6c}, + {0x5389, 0x10}, + {0x538a, 0x01}, + {0x538b, 0x98}, + + /* Sharp */ + {0x5300, 0x08}, + {0x5301, 0x30}, + {0x5302, 0x10}, + {0x5303, 0x00}, + {0x5304, 0x08}, + {0x5305, 0x30}, + {0x5306, 0x08}, + {0x5307, 0x16}, + {0x5309, 0x08}, + {0x530a, 0x30}, + {0x530b, 0x04}, + {0x530c, 0x06}, + + /* Gamma */ + {0x5480, 0x01}, + {0x5481, 0x08}, + {0x5482, 0x14}, + {0x5483, 0x28}, + {0x5484, 0x51}, + {0x5485, 0x65}, + {0x5486, 0x71}, + {0x5487, 0x7d}, + {0x5488, 0x87}, + {0x5489, 0x91}, + {0x548a, 0x9a}, + {0x548b, 0xaa}, + {0x548c, 0xb8}, + {0x548d, 0xcd}, + {0x548e, 0xdd}, + {0x548f, 0xea}, + {0x5490, 0x1d}, + + /* UV adjust. */ + {SDE_CTRL0_REG, 0x02}, + {SDE_CTRL3_REG, 0x40}, + {SDE_CTRL4_REG, 0x10}, + {SDE_CTRL9_REG, 0x10}, + {SDE_CTRL10_REG, 0x00}, + {SDE_CTRL11_REG, 0xf8}, + + /* Lens correction. */ + {0x5800, 0x23}, + {0x5801, 0x14}, + {0x5802, 0x0f}, + {0x5803, 0x0f}, + {0x5804, 0x12}, + {0x5805, 0x26}, + {0x5806, 0x0c}, + {0x5807, 0x08}, + {0x5808, 0x05}, + {0x5809, 0x05}, + {0x580a, 0x08}, + {0x580b, 0x0d}, + {0x580c, 0x08}, + {0x580d, 0x03}, + {0x580e, 0x00}, + {0x580f, 0x00}, + {0x5810, 0x03}, + {0x5811, 0x09}, + {0x5812, 0x07}, + {0x5813, 0x03}, + {0x5814, 0x00}, + {0x5815, 0x01}, + {0x5816, 0x03}, + {0x5817, 0x08}, + {0x5818, 0x0d}, + {0x5819, 0x08}, + {0x581a, 0x05}, + {0x581b, 0x06}, + {0x581c, 0x08}, + {0x581d, 0x0e}, + {0x581e, 0x29}, + {0x581f, 0x17}, + {0x5820, 0x11}, + {0x5821, 0x11}, + {0x5822, 0x15}, + {0x5823, 0x28}, + {0x5824, 0x46}, + {0x5825, 0x26}, + {0x5826, 0x08}, + {0x5827, 0x26}, + {0x5828, 0x64}, + {0x5829, 0x26}, + {0x582a, 0x24}, + {0x582b, 0x22}, + {0x582c, 0x24}, + {0x582d, 0x24}, + {0x582e, 0x06}, + {0x582f, 0x22}, + {0x5830, 0x40}, + {0x5831, 0x42}, + {0x5832, 0x24}, + {0x5833, 0x26}, + {0x5834, 0x24}, + {0x5835, 0x22}, + {0x5836, 0x22}, + {0x5837, 0x26}, + {0x5838, 0x44}, + {0x5839, 0x24}, + {0x583a, 0x26}, + {0x583b, 0x28}, + {0x583c, 0x42}, + {0x583d, 0xce}, + {0x5000, 0xa7}, +}; + +static const struct ov5640_reg ov5640_low_res_params[] = { + {0x3800, 0x00}, {0x3801, 0x00}, {0x3802, 0x00}, {0x3803, 0x04}, {0x3804, 0x0a}, + {0x3805, 0x3f}, {0x3806, 0x07}, {0x3807, 0x9b}, {0x3808, 0x02}, {0x3809, 0x80}, + {0x380a, 0x01}, {0x380b, 0xe0}, {0x380c, 0x07}, {0x380d, 0x68}, {0x380e, 0x03}, + {0x380f, 0xd8}, {0x3810, 0x00}, {0x3811, 0x10}, {0x3812, 0x00}, {0x3813, 0x06}, + {0x3814, 0x31}, {0x3815, 0x31}, {0x3824, 0x02}, {0x460c, 0x22}}; + +static const struct ov5640_reg ov5640_720p_res_params[] = { + {0x3800, 0x00}, {0x3801, 0x00}, {0x3802, 0x00}, {0x3803, 0xfa}, {0x3804, 0x0a}, + {0x3805, 0x3f}, {0x3806, 0x06}, {0x3807, 0xa9}, {0x3808, 0x05}, {0x3809, 0x00}, + {0x380a, 0x02}, {0x380b, 0xd0}, {0x380c, 0x07}, {0x380d, 0x64}, {0x380e, 0x02}, + {0x380f, 0xe4}, {0x3810, 0x00}, {0x3811, 0x10}, {0x3812, 0x00}, {0x3813, 0x04}, + {0x3814, 0x31}, {0x3815, 0x31}, {0x3824, 0x04}, {0x460c, 0x20}}; + +static const struct ov5640_resolution_config resolutionParams[] = { + {.width = 640, + .height = 480, + .res_params = ov5640_low_res_params, + .mipi_pclk = { + .pllCtrl1 = 0x14, + .pllCtrl2 = 0x38, + }}, + {.width = 1280, + .height = 720, + .res_params = ov5640_720p_res_params, + .mipi_pclk = { + .pllCtrl1 = 0x21, + .pllCtrl2 = 0x54, + }}, +}; + +#define OV5640_VIDEO_FORMAT_CAP(width, height, format) \ + { \ + .pixelformat = (format), .width_min = (width), .width_max = (width), \ + .height_min = (height), .height_max = (height), .width_step = 0, .height_step = 0 \ + } + +static const struct video_format_cap fmts[] = { + OV5640_VIDEO_FORMAT_CAP(1280, 720, VIDEO_PIX_FMT_RGB565), + OV5640_VIDEO_FORMAT_CAP(1280, 720, VIDEO_PIX_FMT_YUYV), + OV5640_VIDEO_FORMAT_CAP(640, 480, VIDEO_PIX_FMT_RGB565), + OV5640_VIDEO_FORMAT_CAP(640, 480, VIDEO_PIX_FMT_YUYV), + {0}}; + +static int ov5640_read_reg(const struct i2c_dt_spec *spec, const uint16_t addr, void *val, + const uint8_t val_size) +{ + int ret; + struct i2c_msg msg[2]; + uint8_t addr_buf[2]; + + if (val_size > 4) { + return -ENOTSUP; + } + + addr_buf[1] = addr & 0xFF; + addr_buf[0] = addr >> 8; + msg[0].buf = addr_buf; + msg[0].len = 2U; + msg[0].flags = I2C_MSG_WRITE; + + msg[1].buf = (uint8_t *)val; + msg[1].len = val_size; + msg[1].flags = I2C_MSG_READ | I2C_MSG_STOP | I2C_MSG_RESTART; + + ret = i2c_transfer_dt(spec, msg, 2); + if (ret) { + return ret; + } + + switch (val_size) { + case 4: + *(uint32_t *)val = sys_be32_to_cpu(*(uint32_t *)val); + break; + case 2: + *(uint16_t *)val = sys_be16_to_cpu(*(uint16_t *)val); + break; + case 1: + break; + default: + return -ENOTSUP; + } + + return 0; +} + +static int ov5640_write_reg(const struct i2c_dt_spec *spec, const uint16_t addr, const uint8_t val) +{ + uint8_t addr_buf[2]; + struct i2c_msg msg[2]; + + addr_buf[1] = addr & 0xFF; + addr_buf[0] = addr >> 8; + msg[0].buf = addr_buf; + msg[0].len = 2U; + msg[0].flags = I2C_MSG_WRITE; + + msg[1].buf = (uint8_t *)&val; + msg[1].len = 1; + msg[1].flags = I2C_MSG_WRITE | I2C_MSG_STOP; + + return i2c_transfer_dt(spec, msg, 2); +} + +static int ov5640_modify_reg(const struct i2c_dt_spec *spec, const uint16_t addr, + const uint8_t mask, const uint8_t val) +{ + uint8_t regVal = 0; + int ret = ov5640_read_reg(spec, addr, ®Val, sizeof(regVal)); + + if (ret) { + return ret; + } + + return ov5640_write_reg(spec, addr, (regVal & ~mask) | (val & mask)); +} + +static int ov5640_write_multi_regs(const struct i2c_dt_spec *spec, const struct ov5640_reg *regs, + const uint32_t num_regs) +{ + int ret; + + for (int i = 0; i < num_regs; i++) { + ret = ov5640_write_reg(spec, regs[i].addr, regs[i].val); + if (ret) { + return ret; + } + } + + return 0; +} + +static int ov5640_set_fmt(const struct device *dev, enum video_endpoint_id ep, + struct video_format *fmt) +{ + struct ov5640_data *drv_data = dev->data; + const struct ov5640_config *cfg = dev->config; + int ret; + int i; + + for (i = 0; i < ARRAY_SIZE(fmts); ++i) { + if (fmt->pixelformat == fmts[i].pixelformat && fmt->width >= fmts[i].width_min && + fmt->width <= fmts[i].width_max && fmt->height >= fmts[i].height_min && + fmt->height <= fmts[i].height_max) { + break; + } + } + + if (i == ARRAY_SIZE(fmts)) { + LOG_ERR("Unsupported pixel format or resolution"); + return -ENOTSUP; + } + + if (!memcmp(&drv_data->fmt, fmt, sizeof(drv_data->fmt))) { + return 0; + } + + drv_data->fmt = *fmt; + + /* Set resolution parameters */ + for (i = 0; i < ARRAY_SIZE(resolutionParams); i++) { + if (fmt->width == resolutionParams[i].width && + fmt->height == resolutionParams[i].height) { + ret = ov5640_write_multi_regs(&cfg->i2c, resolutionParams[i].res_params, + OV5640_RESOLUTION_PARAM_NUM); + if (ret) { + LOG_ERR("Unable to set resolution parameters"); + return ret; + } + break; + } + } + + /* Set pixel format, default to VIDEO_PIX_FMT_RGB565 */ + struct ov5640_reg fmt_params[2] = { + {0x4300, 0x6f}, + {0x501f, 0x01}, + }; + + if (fmt->pixelformat == VIDEO_PIX_FMT_YUYV) { + fmt_params[0].val = 0x3f; + fmt_params[1].val = 0x00; + } + + ret = ov5640_write_multi_regs(&cfg->i2c, fmt_params, ARRAY_SIZE(fmt_params)); + if (ret) { + LOG_ERR("Unable to set pixel format"); + return ret; + } + + /* Configure MIPI pixel clock */ + ret |= ov5640_modify_reg(&cfg->i2c, SC_PLL_CTRL0_REG, 0x0f, 0x08); + ret |= ov5640_modify_reg(&cfg->i2c, SC_PLL_CTRL1_REG, 0xff, + resolutionParams[i].mipi_pclk.pllCtrl1); + ret |= ov5640_modify_reg(&cfg->i2c, SC_PLL_CTRL2_REG, 0xff, + resolutionParams[i].mipi_pclk.pllCtrl2); + ret |= ov5640_modify_reg(&cfg->i2c, SC_PLL_CTRL3_REG, 0x1f, 0x13); + ret |= ov5640_modify_reg(&cfg->i2c, SYS_ROOT_DIV_REG, 0x3f, 0x01); + ret |= ov5640_write_reg(&cfg->i2c, PCLK_PERIOD_REG, 0x0a); + if (ret) { + LOG_ERR("Unable to configure MIPI pixel clock"); + return ret; + } + + return 0; +} + +static int ov5640_get_fmt(const struct device *dev, enum video_endpoint_id ep, + struct video_format *fmt) +{ + struct ov5640_data *drv_data = dev->data; + + *fmt = drv_data->fmt; + + return 0; +} + +static int ov5640_get_caps(const struct device *dev, enum video_endpoint_id ep, + struct video_caps *caps) +{ + caps->format_caps = fmts; + return 0; +} + +static int ov5640_stream_start(const struct device *dev) +{ + const struct ov5640_config *cfg = dev->config; + /* Power up MIPI PHY HS Tx & LP Rx in 2 data lanes mode */ + int ret = ov5640_write_reg(&cfg->i2c, IO_MIPI_CTRL00_REG, 0x45); + + if (ret) { + LOG_ERR("Unable to power up MIPI PHY"); + return ret; + } + return ov5640_write_reg(&cfg->i2c, SYS_CTRL0_REG, SYS_CTRL0_SW_PWUP); +} + +static int ov5640_stream_stop(const struct device *dev) +{ + const struct ov5640_config *cfg = dev->config; + /* Power down MIPI PHY HS Tx & LP Rx */ + int ret = ov5640_write_reg(&cfg->i2c, IO_MIPI_CTRL00_REG, 0x40); + + if (ret) { + LOG_ERR("Unable to power down MIPI PHY"); + return ret; + } + return ov5640_write_reg(&cfg->i2c, SYS_CTRL0_REG, SYS_CTRL0_SW_PWDN); +} + +static const struct video_driver_api ov5640_driver_api = { + .set_format = ov5640_set_fmt, + .get_format = ov5640_get_fmt, + .get_caps = ov5640_get_caps, + .stream_start = ov5640_stream_start, + .stream_stop = ov5640_stream_stop, +}; + +static int ov5640_init(const struct device *dev) +{ + const struct ov5640_config *cfg = dev->config; + struct video_format fmt; + uint16_t chip_id; + int ret; + + if (!device_is_ready(cfg->i2c.bus)) { + LOG_ERR("Bus device is not ready"); + return -ENODEV; + } + + if (!gpio_is_ready_dt(&cfg->reset_gpio)) { + LOG_ERR("%s: device %s is not ready", dev->name, cfg->reset_gpio.port->name); + return -ENODEV; + } + + if (!gpio_is_ready_dt(&cfg->powerdown_gpio)) { + LOG_ERR("%s: device %s is not ready", dev->name, cfg->powerdown_gpio.port->name); + return -ENODEV; + } + + /* Power up sequence */ + if (cfg->powerdown_gpio.port != NULL) { + ret = gpio_pin_configure_dt(&cfg->powerdown_gpio, GPIO_OUTPUT_ACTIVE); + if (ret) { + return ret; + } + } + + if (cfg->reset_gpio.port != NULL) { + ret = gpio_pin_configure_dt(&cfg->reset_gpio, GPIO_OUTPUT_ACTIVE); + if (ret) { + return ret; + } + } + + k_sleep(K_MSEC(5)); + + if (cfg->powerdown_gpio.port != NULL) { + gpio_pin_set_dt(&cfg->powerdown_gpio, 0); + } + + k_sleep(K_MSEC(1)); + + if (cfg->reset_gpio.port != NULL) { + gpio_pin_set_dt(&cfg->reset_gpio, 0); + } + + k_sleep(K_MSEC(20)); + + /* Software reset */ + ret = ov5640_write_reg(&cfg->i2c, SYS_CTRL0_REG, SYS_CTRL0_SW_RST); + if (ret) { + LOG_ERR("Unable to perform software reset"); + return -EIO; + } + + k_sleep(K_MSEC(5)); + + /* Initialize register values */ + ret = ov5640_write_multi_regs(&cfg->i2c, ov5640InitParams, ARRAY_SIZE(ov5640InitParams)); + if (ret) { + LOG_ERR("Unable to initialize the sensor"); + return -EIO; + } + + /* Set virtual channel */ + ret = ov5640_modify_reg(&cfg->i2c, 0x4814, 3U << 6, (uint8_t)(DEFAULT_MIPI_CHANNEL) << 6); + if (ret) { + LOG_ERR("Unable to set virtual channel"); + return -EIO; + } + + /* Check sensor chip id */ + ret = ov5640_read_reg(&cfg->i2c, CHIP_ID_REG, &chip_id, sizeof(chip_id)); + if (ret) { + LOG_ERR("Unable to read sensor chip ID, ret = %d", ret); + return -ENODEV; + } + + if (chip_id != CHIP_ID_VAL) { + LOG_ERR("Wrong chip ID: %04x (expected %04x)", chip_id, CHIP_ID_VAL); + return -ENODEV; + } + + /* Set default format to 720p RGB565 */ + fmt.pixelformat = VIDEO_PIX_FMT_RGB565; + fmt.width = 1280; + fmt.height = 720; + fmt.pitch = fmt.width * 2; + ret = ov5640_set_fmt(dev, VIDEO_EP_OUT, &fmt); + if (ret) { + LOG_ERR("Unable to configure default format"); + return -EIO; + } + + return 0; +} + +#define OV5640_INIT(n) \ + static struct ov5640_data ov5640_data_##n; \ + \ + static const struct ov5640_config ov5640_cfg_##n = { \ + .i2c = I2C_DT_SPEC_INST_GET(n), \ + .reset_gpio = GPIO_DT_SPEC_INST_GET_OR(n, reset_gpios, {0}), \ + .powerdown_gpio = GPIO_DT_SPEC_INST_GET_OR(n, powerdown_gpios, {0}), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(n, &ov5640_init, NULL, &ov5640_data_##n, &ov5640_cfg_##n, \ + POST_KERNEL, CONFIG_VIDEO_INIT_PRIORITY, &ov5640_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(OV5640_INIT) diff --git a/drivers/video/video_common.c b/drivers/video/video_common.c index 11786bd6928..5b1359ec7bc 100644 --- a/drivers/video/video_common.c +++ b/drivers/video/video_common.c @@ -19,7 +19,7 @@ struct mem_block { static struct mem_block video_block[CONFIG_VIDEO_BUFFER_POOL_NUM_MAX]; -struct video_buffer *video_buffer_alloc(size_t size) +struct video_buffer *video_buffer_aligned_alloc(size_t size, size_t align) { struct video_buffer *vbuf = NULL; struct mem_block *block; @@ -39,7 +39,7 @@ struct video_buffer *video_buffer_alloc(size_t size) } /* Alloc buffer memory */ - block->data = k_heap_alloc(&video_buffer_pool, size, K_FOREVER); + block->data = k_heap_aligned_alloc(&video_buffer_pool, align, size, K_FOREVER); if (block->data == NULL) { return NULL; } @@ -51,6 +51,11 @@ struct video_buffer *video_buffer_alloc(size_t size) return vbuf; } +struct video_buffer *video_buffer_alloc(size_t size) +{ + return video_buffer_aligned_alloc(size, sizeof(void *)); +} + void video_buffer_release(struct video_buffer *vbuf) { struct mem_block *block = NULL; diff --git a/drivers/video/video_mcux_csi.c b/drivers/video/video_mcux_csi.c index 1e7117c4393..2e8e4d50508 100644 --- a/drivers/video/video_mcux_csi.c +++ b/drivers/video/video_mcux_csi.c @@ -20,7 +20,7 @@ struct video_mcux_csi_config { CSI_Type *base; - const struct device *sensor_dev; + const struct device *source_dev; const struct pinctrl_dev_config *pincfg; }; @@ -30,7 +30,6 @@ struct video_mcux_csi_data { csi_handle_t csi_handle; struct k_fifo fifo_in; struct k_fifo fifo_out; - uint32_t pixelformat; struct k_poll_signal *signal; }; @@ -45,13 +44,15 @@ static inline unsigned int video_pix_fmt_bpp(uint32_t pixelformat) case VIDEO_PIX_FMT_RGB565: case VIDEO_PIX_FMT_YUYV: return 2; + case VIDEO_PIX_FMT_XRGB32: + case VIDEO_PIX_FMT_XYUV32: + return 4; default: return 0; } } -static void __frame_done_cb(CSI_Type *base, csi_handle_t *handle, - status_t status, void *user_data) +static void __frame_done_cb(CSI_Type *base, csi_handle_t *handle, status_t status, void *user_data) { struct video_mcux_csi_data *data = user_data; const struct device *dev = data->dev; @@ -66,8 +67,7 @@ static void __frame_done_cb(CSI_Type *base, csi_handle_t *handle, return; } - status = CSI_TransferGetFullBuffer(config->base, &(data->csi_handle), - &buffer_addr); + status = CSI_TransferGetFullBuffer(config->base, &(data->csi_handle), &buffer_addr); if (status != kStatus_Success) { result = VIDEO_BUF_ERROR; goto done; @@ -116,25 +116,62 @@ static void __frame_done_cb(CSI_Type *base, csi_handle_t *handle, return; } -static int video_mcux_csi_set_fmt(const struct device *dev, - enum video_endpoint_id ep, +#if defined(CONFIG_VIDEO_MCUX_MIPI_CSI2RX) +K_HEAP_DEFINE(csi_heap, 1000); +static struct video_format_cap *fmts; +/* + * On i.MX RT11xx SoCs which have MIPI CSI-2 Rx, image data from the camera sensor after passing + * through the pipeline (MIPI CSI-2 Rx --> Video Mux --> CSI) will be implicitly converted to a + * 32-bits pixel format. For example, an input in RGB565 or YUYV (2-bytes format) will become a + * XRGB32 or XYUV32 (4-bytes format) respectively, at the output of the CSI. + */ +static inline void video_pix_fmt_convert(struct video_format *fmt, bool isGetFmt) +{ + switch (fmt->pixelformat) { + case VIDEO_PIX_FMT_XRGB32: + fmt->pixelformat = isGetFmt ? VIDEO_PIX_FMT_XRGB32 : VIDEO_PIX_FMT_RGB565; + break; + case VIDEO_PIX_FMT_XYUV32: + fmt->pixelformat = isGetFmt ? VIDEO_PIX_FMT_XYUV32 : VIDEO_PIX_FMT_YUYV; + break; + case VIDEO_PIX_FMT_RGB565: + fmt->pixelformat = isGetFmt ? VIDEO_PIX_FMT_XRGB32 : VIDEO_PIX_FMT_RGB565; + break; + case VIDEO_PIX_FMT_YUYV: + fmt->pixelformat = isGetFmt ? VIDEO_PIX_FMT_XYUV32 : VIDEO_PIX_FMT_YUYV; + break; + } + + fmt->pitch = fmt->width * video_pix_fmt_bpp(fmt->pixelformat); +} +#endif + +static int video_mcux_csi_set_fmt(const struct device *dev, enum video_endpoint_id ep, struct video_format *fmt) { const struct video_mcux_csi_config *config = dev->config; struct video_mcux_csi_data *data = dev->data; unsigned int bpp = video_pix_fmt_bpp(fmt->pixelformat); status_t ret; + struct video_format format = *fmt; if (!bpp || ep != VIDEO_EP_OUT) { return -EINVAL; } - data->pixelformat = fmt->pixelformat; data->csi_config.bytesPerPixel = bpp; data->csi_config.linePitch_Bytes = fmt->pitch; +#if defined(CONFIG_VIDEO_MCUX_MIPI_CSI2RX) + if (fmt->pixelformat != VIDEO_PIX_FMT_XRGB32 && fmt->pixelformat != VIDEO_PIX_FMT_XYUV32) { + return -ENOTSUP; + } + video_pix_fmt_convert(&format, false); + data->csi_config.dataBus = kCSI_DataBus24Bit; +#else + data->csi_config.dataBus = kCSI_DataBus8Bit; +#endif data->csi_config.polarityFlags = kCSI_HsyncActiveHigh | kCSI_DataLatchOnRisingEdge; data->csi_config.workMode = kCSI_GatedClockMode; /* use VSYNC, HSYNC, and PIXCLK */ - data->csi_config.dataBus = kCSI_DataBus8Bit; data->csi_config.useExtVsync = true; data->csi_config.height = fmt->height; data->csi_config.width = fmt->width; @@ -144,42 +181,36 @@ static int video_mcux_csi_set_fmt(const struct device *dev, return -EIO; } - ret = CSI_TransferCreateHandle(config->base, &data->csi_handle, - __frame_done_cb, data); + ret = CSI_TransferCreateHandle(config->base, &data->csi_handle, __frame_done_cb, data); if (ret != kStatus_Success) { return -EIO; } - if (config->sensor_dev && video_set_format(config->sensor_dev, ep, fmt)) { + if (config->source_dev && video_set_format(config->source_dev, ep, &format)) { return -EIO; } return 0; } -static int video_mcux_csi_get_fmt(const struct device *dev, - enum video_endpoint_id ep, +static int video_mcux_csi_get_fmt(const struct device *dev, enum video_endpoint_id ep, struct video_format *fmt) { - struct video_mcux_csi_data *data = dev->data; const struct video_mcux_csi_config *config = dev->config; if (fmt == NULL || ep != VIDEO_EP_OUT) { return -EINVAL; } - if (config->sensor_dev && !video_get_format(config->sensor_dev, ep, fmt)) { - /* align CSI with sensor fmt */ + if (config->source_dev && !video_get_format(config->source_dev, ep, fmt)) { +#if defined(CONFIG_VIDEO_MCUX_MIPI_CSI2RX) + video_pix_fmt_convert(fmt, true); +#endif + /* align CSI with source fmt */ return video_mcux_csi_set_fmt(dev, ep, fmt); } - - fmt->pixelformat = data->pixelformat; - fmt->height = data->csi_config.height; - fmt->width = data->csi_config.width; - fmt->pitch = data->csi_config.linePitch_Bytes; - - return 0; + return -EIO; } static int video_mcux_csi_stream_start(const struct device *dev) @@ -193,7 +224,7 @@ static int video_mcux_csi_stream_start(const struct device *dev) return -EIO; } - if (config->sensor_dev && video_stream_start(config->sensor_dev)) { + if (config->source_dev && video_stream_start(config->source_dev)) { return -EIO; } @@ -206,7 +237,7 @@ static int video_mcux_csi_stream_stop(const struct device *dev) struct video_mcux_csi_data *data = dev->data; status_t ret; - if (config->sensor_dev && video_stream_stop(config->sensor_dev)) { + if (config->source_dev && video_stream_stop(config->source_dev)) { return -EIO; } @@ -218,10 +249,7 @@ static int video_mcux_csi_stream_stop(const struct device *dev) return 0; } - -static int video_mcux_csi_flush(const struct device *dev, - enum video_endpoint_id ep, - bool cancel) +static int video_mcux_csi_flush(const struct device *dev, enum video_endpoint_id ep, bool cancel) { const struct video_mcux_csi_config *config = dev->config; struct video_mcux_csi_data *data = dev->data; @@ -237,16 +265,14 @@ static int video_mcux_csi_flush(const struct device *dev, } else { /* Flush driver output queue */ do { - ret = CSI_TransferGetFullBuffer(config->base, - &(data->csi_handle), + ret = CSI_TransferGetFullBuffer(config->base, &(data->csi_handle), &buffer_addr); } while (ret == kStatus_Success); while ((vbuf = k_fifo_get(&data->fifo_in, K_NO_WAIT))) { k_fifo_put(&data->fifo_out, vbuf); if (IS_ENABLED(CONFIG_POLL) && data->signal) { - k_poll_signal_raise(data->signal, - VIDEO_BUF_ABORTED); + k_poll_signal_raise(data->signal, VIDEO_BUF_ABORTED); } } } @@ -254,8 +280,7 @@ static int video_mcux_csi_flush(const struct device *dev, return 0; } -static int video_mcux_csi_enqueue(const struct device *dev, - enum video_endpoint_id ep, +static int video_mcux_csi_enqueue(const struct device *dev, enum video_endpoint_id ep, struct video_buffer *vbuf) { const struct video_mcux_csi_config *config = dev->config; @@ -281,10 +306,8 @@ static int video_mcux_csi_enqueue(const struct device *dev, return 0; } -static int video_mcux_csi_dequeue(const struct device *dev, - enum video_endpoint_id ep, - struct video_buffer **vbuf, - k_timeout_t timeout) +static int video_mcux_csi_dequeue(const struct device *dev, enum video_endpoint_id ep, + struct video_buffer **vbuf, k_timeout_t timeout) { struct video_mcux_csi_data *data = dev->data; @@ -300,38 +323,33 @@ static int video_mcux_csi_dequeue(const struct device *dev, return 0; } -static inline int video_mcux_csi_set_ctrl(const struct device *dev, - unsigned int cid, - void *value) +static inline int video_mcux_csi_set_ctrl(const struct device *dev, unsigned int cid, void *value) { const struct video_mcux_csi_config *config = dev->config; int ret = -ENOTSUP; - /* Forward to sensor dev if any */ - if (config->sensor_dev) { - ret = video_set_ctrl(config->sensor_dev, cid, value); + /* Forward to source dev if any */ + if (config->source_dev) { + ret = video_set_ctrl(config->source_dev, cid, value); } return ret; } -static inline int video_mcux_csi_get_ctrl(const struct device *dev, - unsigned int cid, - void *value) +static inline int video_mcux_csi_get_ctrl(const struct device *dev, unsigned int cid, void *value) { const struct video_mcux_csi_config *config = dev->config; int ret = -ENOTSUP; - /* Forward to sensor dev if any */ - if (config->sensor_dev) { - ret = video_get_ctrl(config->sensor_dev, cid, value); + /* Forward to source dev if any */ + if (config->source_dev) { + ret = video_get_ctrl(config->source_dev, cid, value); } return ret; } -static int video_mcux_csi_get_caps(const struct device *dev, - enum video_endpoint_id ep, +static int video_mcux_csi_get_caps(const struct device *dev, enum video_endpoint_id ep, struct video_caps *caps) { const struct video_mcux_csi_config *config = dev->config; @@ -341,15 +359,43 @@ static int video_mcux_csi_get_caps(const struct device *dev, return -EINVAL; } - /* Just forward to sensor dev for now */ - if (config->sensor_dev) { - err = video_get_caps(config->sensor_dev, ep, caps); + /* Just forward to source dev for now */ + if (config->source_dev) { + err = video_get_caps(config->source_dev, ep, caps); +#if defined(CONFIG_VIDEO_MCUX_MIPI_CSI2RX) + /* + * On i.MX RT11xx SoCs which have MIPI CSI-2 Rx, image data from the camera sensor + * after passing through the pipeline (MIPI CSI-2 Rx --> Video Mux --> CSI) will be + * implicitly converted to a 32-bits pixel format. For example, an input in RGB565 + * or YUYV (2-bytes format) will become an XRGB32 or XYUV32 (4-bytes format) + * respectively, at the output of the CSI. So, we change the pixel formats of the + * source caps to reflect this. + */ + int ind = 0; + + while (caps->format_caps[ind].pixelformat) { + ind++; + } + k_heap_free(&csi_heap, fmts); + fmts = k_heap_alloc(&csi_heap, (ind + 1) * sizeof(struct video_format_cap), + K_FOREVER); + + for (int i = 0; i <= ind; i++) { + memcpy(&fmts[i], &caps->format_caps[i], sizeof(fmts[i])); + if (fmts[i].pixelformat == VIDEO_PIX_FMT_RGB565) { + fmts[i].pixelformat = VIDEO_PIX_FMT_XRGB32; + } else if (fmts[i].pixelformat == VIDEO_PIX_FMT_YUYV) { + fmts[i].pixelformat = VIDEO_PIX_FMT_XYUV32; + } + } + caps->format_caps = fmts; +#endif } /* NXP MCUX CSI request at least 2 buffer before starting */ caps->min_vbuf_count = 2; - /* no sensor dev */ + /* no source dev */ return err; } @@ -371,10 +417,10 @@ static int video_mcux_csi_init(const struct device *dev) CSI_GetDefaultConfig(&data->csi_config); - /* check if there is any sensor device (video ctrl device) + /* check if there is any source device (video ctrl device) * the device is not yet initialized so we only check if it exists */ - if (config->sensor_dev == NULL) { + if (config->source_dev == NULL) { return -ENODEV; } @@ -387,8 +433,7 @@ static int video_mcux_csi_init(const struct device *dev) } #ifdef CONFIG_POLL -static int video_mcux_csi_set_signal(const struct device *dev, - enum video_endpoint_id ep, +static int video_mcux_csi_set_signal(const struct device *dev, enum video_endpoint_id ep, struct k_poll_signal *signal) { struct video_mcux_csi_data *data = dev->data; @@ -424,7 +469,7 @@ PINCTRL_DT_INST_DEFINE(0); static const struct video_mcux_csi_config video_mcux_csi_config_0 = { .base = (CSI_Type *)DT_INST_REG_ADDR(0), - .sensor_dev = DEVICE_DT_GET(DT_INST_PHANDLE(0, sensor)), + .source_dev = DEVICE_DT_GET(DT_INST_PHANDLE(0, source)), .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0), }; @@ -434,8 +479,7 @@ static int video_mcux_csi_init_0(const struct device *dev) { struct video_mcux_csi_data *data = dev->data; - IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), - video_mcux_csi_isr, NULL, 0); + IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), video_mcux_csi_isr, NULL, 0); irq_enable(DT_INST_IRQN(0)); @@ -449,9 +493,7 @@ static int video_mcux_csi_init_0(const struct device *dev) * necessary since the clock to the camera is provided by the * CSI peripheral. */ -DEVICE_DT_INST_DEFINE(0, &video_mcux_csi_init_0, - NULL, &video_mcux_csi_data_0, - &video_mcux_csi_config_0, - POST_KERNEL, CONFIG_VIDEO_MCUX_CSI_INIT_PRIORITY, - &video_mcux_csi_driver_api); +DEVICE_DT_INST_DEFINE(0, &video_mcux_csi_init_0, NULL, &video_mcux_csi_data_0, + &video_mcux_csi_config_0, POST_KERNEL, CONFIG_VIDEO_MCUX_CSI_INIT_PRIORITY, + &video_mcux_csi_driver_api); #endif diff --git a/drivers/video/video_mcux_mipi_csi2rx.c b/drivers/video/video_mcux_mipi_csi2rx.c new file mode 100644 index 00000000000..6d9dc5729ed --- /dev/null +++ b/drivers/video/video_mcux_mipi_csi2rx.c @@ -0,0 +1,218 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nxp_mipi_csi2rx + +#include + +#include +#include + +#define LOG_LEVEL CONFIG_LOG_DEFAULT_LEVEL +#include +LOG_MODULE_REGISTER(mipi_csi); + +/* + * Two data lanes are set by default as 2-lanes camera sensors are + * more common and more performant but single lane is also supported. + */ +#define DEFAULT_MIPI_CSI_NUM_LANES 2 +#define DEFAULT_CAMERA_FRAME_RATE 30 + +struct mipi_csi2rx_config { + const MIPI_CSI2RX_Type *base; + const struct device *sensor_dev; +}; + +struct mipi_csi2rx_data { + csi2rx_config_t csi2rxConfig; +}; + +static int mipi_csi2rx_set_fmt(const struct device *dev, enum video_endpoint_id ep, + struct video_format *fmt) +{ + const struct mipi_csi2rx_config *config = dev->config; + struct mipi_csi2rx_data *drv_data = dev->data; + csi2rx_config_t csi2rxConfig = {0}; + uint8_t i = 0; + + /* + * Initialize the MIPI CSI2 + * + * From D-PHY specification, the T-HSSETTLE should in the range of 85ns+6*UI to 145ns+10*UI + * UI is Unit Interval, equal to the duration of any HS state on the Clock Lane + * + * T-HSSETTLE = csi2rxConfig.tHsSettle_EscClk * (Tperiod of RxClkInEsc) + * + * csi2rxConfig.tHsSettle_EscClk setting for camera: + * + * Resolution | frame rate | T_HS_SETTLE + * ============================================= + * 720P | 30 | 0x12 + * --------------------------------------------- + * 720P | 15 | 0x17 + * --------------------------------------------- + * VGA | 30 | 0x1F + * --------------------------------------------- + * VGA | 15 | 0x24 + * --------------------------------------------- + * QVGA | 30 | 0x1F + * --------------------------------------------- + * QVGA | 15 | 0x24 + * --------------------------------------------- + */ + static const uint32_t csi2rxHsSettle[][4] = { + { + 1280, + 720, + 30, + 0x12, + }, + { + 1280, + 720, + 15, + 0x17, + }, + { + 640, + 480, + 30, + 0x1F, + }, + { + 640, + 480, + 15, + 0x24, + }, + { + 320, + 240, + 30, + 0x1F, + }, + { + 320, + 240, + 15, + 0x24, + }, + }; + + csi2rxConfig.laneNum = DEFAULT_MIPI_CSI_NUM_LANES; + + for (i = 0; i < ARRAY_SIZE(csi2rxHsSettle); i++) { + if ((fmt->width == csi2rxHsSettle[i][0]) && (fmt->height == csi2rxHsSettle[i][1]) && + (DEFAULT_CAMERA_FRAME_RATE == csi2rxHsSettle[i][2])) { + csi2rxConfig.tHsSettle_EscClk = csi2rxHsSettle[i][3]; + break; + } + } + + if (i == ARRAY_SIZE(csi2rxHsSettle)) { + LOG_ERR("Unsupported resolution"); + return -ENOTSUP; + } + + drv_data->csi2rxConfig = csi2rxConfig; + + if (video_set_format(config->sensor_dev, ep, fmt)) { + return -EIO; + } + + return 0; +} + +static int mipi_csi2rx_get_fmt(const struct device *dev, enum video_endpoint_id ep, + struct video_format *fmt) +{ + const struct mipi_csi2rx_config *config = dev->config; + + if (fmt == NULL || ep != VIDEO_EP_OUT) { + return -EINVAL; + } + + if (video_get_format(config->sensor_dev, ep, fmt)) { + return -EIO; + } + + return 0; +} + +static int mipi_csi2rx_stream_start(const struct device *dev) +{ + const struct mipi_csi2rx_config *config = dev->config; + struct mipi_csi2rx_data *drv_data = dev->data; + + CSI2RX_Init((MIPI_CSI2RX_Type *)config->base, &drv_data->csi2rxConfig); + + if (video_stream_start(config->sensor_dev)) { + return -EIO; + } + + return 0; +} + +static int mipi_csi2rx_stream_stop(const struct device *dev) +{ + const struct mipi_csi2rx_config *config = dev->config; + + if (video_stream_stop(config->sensor_dev)) { + return -EIO; + } + + CSI2RX_Deinit((MIPI_CSI2RX_Type *)config->base); + + return 0; +} + +static int mipi_csi2rx_get_caps(const struct device *dev, enum video_endpoint_id ep, + struct video_caps *caps) +{ + const struct mipi_csi2rx_config *config = dev->config; + + if (ep != VIDEO_EP_OUT) { + return -EINVAL; + } + + /* Just forward to sensor dev for now */ + return video_get_caps(config->sensor_dev, ep, caps); +} + +static const struct video_driver_api mipi_csi2rx_driver_api = { + .get_caps = mipi_csi2rx_get_caps, + .get_format = mipi_csi2rx_get_fmt, + .set_format = mipi_csi2rx_set_fmt, + .stream_start = mipi_csi2rx_stream_start, + .stream_stop = mipi_csi2rx_stream_stop, +}; + +static int mipi_csi2rx_init(const struct device *dev) +{ + const struct mipi_csi2rx_config *config = dev->config; + + /* Check if there is any sensor device */ + if (!device_is_ready(config->sensor_dev)) { + return -ENODEV; + } + + return 0; +} + +#define MIPI_CSI2RX_INIT(n) \ + static struct mipi_csi2rx_data mipi_csi2rx_data_##n; \ + \ + static const struct mipi_csi2rx_config mipi_csi2rx_config_##n = { \ + .base = (MIPI_CSI2RX_Type *)DT_INST_REG_ADDR(n), \ + .sensor_dev = DEVICE_DT_GET(DT_INST_PHANDLE(n, sensor)), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(n, &mipi_csi2rx_init, NULL, &mipi_csi2rx_data_##n, \ + &mipi_csi2rx_config_##n, POST_KERNEL, CONFIG_VIDEO_INIT_PRIORITY, \ + &mipi_csi2rx_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(MIPI_CSI2RX_INIT) diff --git a/drivers/video/video_stm32_dcmi.c b/drivers/video/video_stm32_dcmi.c new file mode 100644 index 00000000000..d8f875b7673 --- /dev/null +++ b/drivers/video/video_stm32_dcmi.c @@ -0,0 +1,504 @@ +/* + * Copyright (c) 2024 Charles Dias + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT st_stm32_dcmi + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +LOG_MODULE_REGISTER(video_stm32_dcmi, CONFIG_STM32_DCMI_LOG_LEVEL); + +K_HEAP_DEFINE(video_stm32_buffer_pool, CONFIG_VIDEO_BUFFER_POOL_SZ_MAX); + +typedef void (*irq_config_func_t)(const struct device *dev); + +struct stream { + DMA_TypeDef *reg; + const struct device *dma_dev; + uint32_t channel; + struct dma_config cfg; +}; + +struct video_stm32_dcmi_data { + const struct device *dev; + DCMI_HandleTypeDef hdcmi; + struct video_format fmt; + struct k_fifo fifo_in; + struct k_fifo fifo_out; + uint32_t pixel_format; + uint32_t height; + uint32_t width; + uint32_t pitch; + uint8_t *buffer; +}; + +struct video_stm32_dcmi_config { + struct stm32_pclken pclken; + irq_config_func_t irq_config; + const struct pinctrl_dev_config *pctrl; + const struct device *sensor_dev; + const struct stream dma; +}; + +static inline unsigned int video_pix_fmt_bpp(uint32_t pixelformat) +{ + switch (pixelformat) { + case VIDEO_PIX_FMT_BGGR8: + case VIDEO_PIX_FMT_GBRG8: + case VIDEO_PIX_FMT_GRBG8: + case VIDEO_PIX_FMT_RGGB8: + return 1; + case VIDEO_PIX_FMT_RGB565: + case VIDEO_PIX_FMT_YUYV: + return 2; + default: + return 0; + } +} + +void HAL_DCMI_ErrorCallback(DCMI_HandleTypeDef *hdcmi) +{ + LOG_WRN("%s", __func__); +} + +void HAL_DCMI_FrameEventCallback(DCMI_HandleTypeDef *hdcmi) +{ + struct video_stm32_dcmi_data *dev_data = + CONTAINER_OF(hdcmi, struct video_stm32_dcmi_data, hdcmi); + struct video_buffer *vbuf; + + HAL_DCMI_Suspend(hdcmi); + + vbuf = k_fifo_get(&dev_data->fifo_in, K_NO_WAIT); + + if (vbuf == NULL) { + LOG_DBG("Failed to get buffer from fifo"); + goto resume; + } + + vbuf->timestamp = k_uptime_get_32(); + memcpy(vbuf->buffer, dev_data->buffer, vbuf->bytesused); + + k_fifo_put(&dev_data->fifo_out, vbuf); + +resume: + HAL_DCMI_Resume(hdcmi); +} + +static void stm32_dcmi_isr(const struct device *dev) +{ + struct video_stm32_dcmi_data *data = dev->data; + + HAL_DCMI_IRQHandler(&data->hdcmi); +} + +static void dmci_dma_callback(const struct device *dev, void *arg, + uint32_t channel, int status) +{ + DMA_HandleTypeDef *hdma = arg; + + ARG_UNUSED(dev); + + if (status < 0) { + LOG_ERR("DMA callback error with channel %d.", channel); + } + + HAL_DMA_IRQHandler(hdma); +} + +void HAL_DMA_ErrorCallback(DMA_HandleTypeDef *hdma) +{ + LOG_WRN("%s", __func__); +} + +static int stm32_dma_init(const struct device *dev) +{ + struct video_stm32_dcmi_data *data = dev->data; + const struct video_stm32_dcmi_config *config = dev->config; + int ret; + + /* Check if the DMA device is ready */ + if (!device_is_ready(config->dma.dma_dev)) { + LOG_ERR("%s DMA device not ready", config->dma.dma_dev->name); + return -ENODEV; + } + + /* + * DMA configuration + * Due to use of QSPI HAL API in current driver, + * both HAL and Zephyr DMA drivers should be configured. + * The required configuration for Zephyr DMA driver should only provide + * the minimum information to inform the DMA slot will be in used and + * how to route callbacks. + */ + struct dma_config dma_cfg = config->dma.cfg; + static DMA_HandleTypeDef hdma; + + /* Proceed to the minimum Zephyr DMA driver init */ + dma_cfg.user_data = &hdma; + /* HACK: This field is used to inform driver that it is overridden */ + dma_cfg.linked_channel = STM32_DMA_HAL_OVERRIDE; + /* Because of the STREAM OFFSET, the DMA channel given here is from 1 - 8 */ + ret = dma_config(config->dma.dma_dev, + config->dma.channel + STM32_DMA_STREAM_OFFSET, &dma_cfg); + if (ret != 0) { + LOG_ERR("Failed to configure DMA channel %d", + config->dma.channel + STM32_DMA_STREAM_OFFSET); + return ret; + } + + /*** Configure the DMA ***/ + /* Set the parameters to be configured */ + hdma.Init.Request = DMA_REQUEST_DCMI; + hdma.Init.Direction = DMA_PERIPH_TO_MEMORY; + hdma.Init.PeriphInc = DMA_PINC_DISABLE; + hdma.Init.MemInc = DMA_MINC_ENABLE; + hdma.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; + hdma.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; + hdma.Init.Mode = DMA_CIRCULAR; + hdma.Init.Priority = DMA_PRIORITY_HIGH; + hdma.Init.FIFOMode = DMA_FIFOMODE_DISABLE; + + hdma.Instance = __LL_DMA_GET_STREAM_INSTANCE(config->dma.reg, + config->dma.channel); + + /* Initialize DMA HAL */ + __HAL_LINKDMA(&data->hdcmi, DMA_Handle, hdma); + + if (HAL_DMA_Init(&hdma) != HAL_OK) { + LOG_ERR("DCMI DMA Init failed"); + return -EIO; + } + + return 0; +} + +static int stm32_dcmi_enable_clock(const struct device *dev) +{ + const struct video_stm32_dcmi_config *config = dev->config; + const struct device *dcmi_clock = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE); + int err; + + if (!device_is_ready(dcmi_clock)) { + LOG_ERR("clock control device not ready"); + return -ENODEV; + } + + /* Turn on DCMI peripheral clock */ + err = clock_control_on(dcmi_clock, (clock_control_subsys_t *) &config->pclken); + if (err < 0) { + LOG_ERR("Failed to enable DCMI clock. Error %d", err); + return err; + } + + return 0; +} + +static int video_stm32_dcmi_set_fmt(const struct device *dev, + enum video_endpoint_id ep, + struct video_format *fmt) +{ + const struct video_stm32_dcmi_config *config = dev->config; + struct video_stm32_dcmi_data *data = dev->data; + unsigned int bpp = video_pix_fmt_bpp(fmt->pixelformat); + + if (!bpp || ep != VIDEO_EP_OUT) { + return -EINVAL; + } + + data->pixel_format = fmt->pixelformat; + data->pitch = fmt->pitch; + data->height = fmt->height; + data->width = fmt->width; + + if (video_set_format(config->sensor_dev, ep, fmt)) { + return -EIO; + } + + return 0; +} + +static int video_stm32_dcmi_get_fmt(const struct device *dev, + enum video_endpoint_id ep, + struct video_format *fmt) +{ + struct video_stm32_dcmi_data *data = dev->data; + const struct video_stm32_dcmi_config *config = dev->config; + + if ((fmt == NULL) || (ep != VIDEO_EP_OUT)) { + return -EINVAL; + } + + if (!video_get_format(config->sensor_dev, ep, fmt)) { + /* align DCMI with sensor fmt */ + return video_stm32_dcmi_set_fmt(dev, ep, fmt); + } + + fmt->pixelformat = data->pixel_format; + fmt->height = data->height; + fmt->width = data->width; + fmt->pitch = data->pitch; + + return 0; +} + +static int video_stm32_dcmi_stream_start(const struct device *dev) +{ + struct video_stm32_dcmi_data *data = dev->data; + const struct video_stm32_dcmi_config *config = dev->config; + size_t buffer_size = data->pitch * data->height; + + data->buffer = k_heap_alloc(&video_stm32_buffer_pool, buffer_size, K_NO_WAIT); + if (data->buffer == NULL) { + LOG_ERR("Failed to allocate DCMI buffer for image. Size %d bytes", buffer_size); + return -ENOMEM; + } + + int err = HAL_DCMI_Start_DMA(&data->hdcmi, DCMI_MODE_CONTINUOUS, + (uint32_t)data->buffer, buffer_size / 4); + if (err != HAL_OK) { + LOG_ERR("Failed to start DCMI DMA"); + return -EIO; + } + + if (video_stream_start(config->sensor_dev)) { + return -EIO; + } + + return 0; +} + +static int video_stm32_dcmi_stream_stop(const struct device *dev) +{ + struct video_stm32_dcmi_data *data = dev->data; + const struct video_stm32_dcmi_config *config = dev->config; + int err; + + if (video_stream_stop(config->sensor_dev)) { + return -EIO; + } + + /* Release the buffer allocated in stream_start */ + k_heap_free(&video_stm32_buffer_pool, data->buffer); + + err = HAL_DCMI_Stop(&data->hdcmi); + if (err != HAL_OK) { + LOG_ERR("Failed to stop DCMI"); + return -EIO; + } + + return 0; +} + +static int video_stm32_dcmi_enqueue(const struct device *dev, + enum video_endpoint_id ep, + struct video_buffer *vbuf) +{ + struct video_stm32_dcmi_data *data = dev->data; + + if (ep != VIDEO_EP_OUT) { + return -EINVAL; + } + + vbuf->bytesused = data->pitch * data->height; + + k_fifo_put(&data->fifo_in, vbuf); + + return 0; +} + +static int video_stm32_dcmi_dequeue(const struct device *dev, + enum video_endpoint_id ep, + struct video_buffer **vbuf, + k_timeout_t timeout) +{ + struct video_stm32_dcmi_data *data = dev->data; + + if (ep != VIDEO_EP_OUT) { + return -EINVAL; + } + + *vbuf = k_fifo_get(&data->fifo_out, timeout); + if (*vbuf == NULL) { + return -EAGAIN; + } + + return 0; +} + +static int video_stm32_dcmi_get_caps(const struct device *dev, + enum video_endpoint_id ep, + struct video_caps *caps) +{ + const struct video_stm32_dcmi_config *config = dev->config; + int ret = -ENODEV; + + if (ep != VIDEO_EP_OUT) { + return -EINVAL; + } + + /* Forward the message to the sensor device */ + ret = video_get_caps(config->sensor_dev, ep, caps); + + return ret; +} + +static const struct video_driver_api video_stm32_dcmi_driver_api = { + .set_format = video_stm32_dcmi_set_fmt, + .get_format = video_stm32_dcmi_get_fmt, + .stream_start = video_stm32_dcmi_stream_start, + .stream_stop = video_stm32_dcmi_stream_stop, + .enqueue = video_stm32_dcmi_enqueue, + .dequeue = video_stm32_dcmi_dequeue, + .get_caps = video_stm32_dcmi_get_caps, +}; + +static void video_stm32_dcmi_irq_config_func(const struct device *dev) +{ + IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), + stm32_dcmi_isr, DEVICE_DT_INST_GET(0), 0); + irq_enable(DT_INST_IRQN(0)); +} + +#define DCMI_DMA_CHANNEL_INIT(index, src_dev, dest_dev) \ + .dma_dev = DEVICE_DT_GET(DT_INST_DMAS_CTLR_BY_IDX(index, 0)), \ + .channel = DT_INST_DMAS_CELL_BY_IDX(index, 0, channel), \ + .reg = (DMA_TypeDef *)DT_REG_ADDR( \ + DT_PHANDLE_BY_IDX(DT_DRV_INST(0), dmas, 0)), \ + .cfg = { \ + .dma_slot = STM32_DMA_SLOT_BY_IDX(index, 0, slot), \ + .channel_direction = STM32_DMA_CONFIG_DIRECTION( \ + STM32_DMA_CHANNEL_CONFIG_BY_IDX(index, 0)), \ + .source_data_size = STM32_DMA_CONFIG_##src_dev##_DATA_SIZE( \ + STM32_DMA_CHANNEL_CONFIG_BY_IDX(index, 0)), \ + .dest_data_size = STM32_DMA_CONFIG_##dest_dev##_DATA_SIZE( \ + 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_BY_IDX(index, 0)), \ + .dma_callback = dmci_dma_callback, \ + }, \ + +PINCTRL_DT_INST_DEFINE(0); + +#define STM32_DCMI_GET_CAPTURE_RATE(capture_rate) \ + ((capture_rate) == 1 ? DCMI_CR_ALL_FRAME : \ + (capture_rate) == 2 ? DCMI_CR_ALTERNATE_2_FRAME : \ + (capture_rate) == 4 ? DCMI_CR_ALTERNATE_4_FRAME : \ + DCMI_CR_ALL_FRAME) + +#define STM32_DCMI_GET_BUS_WIDTH(bus_width) \ + ((bus_width) == 8 ? DCMI_EXTEND_DATA_8B : \ + (bus_width) == 10 ? DCMI_EXTEND_DATA_10B : \ + (bus_width) == 12 ? DCMI_EXTEND_DATA_12B : \ + (bus_width) == 14 ? DCMI_EXTEND_DATA_14B : \ + DCMI_EXTEND_DATA_8B) + +#define DCMI_DMA_CHANNEL(id, src, dest) \ + .dma = { \ + COND_CODE_1(DT_INST_DMAS_HAS_IDX(id, 0), \ + (DCMI_DMA_CHANNEL_INIT(id, src, dest)), \ + (NULL)) \ + }, + +static struct video_stm32_dcmi_data video_stm32_dcmi_data_0 = { + .hdcmi = { + .Instance = (DCMI_TypeDef *) DT_INST_REG_ADDR(0), + .Init = { + .SynchroMode = DCMI_SYNCHRO_HARDWARE, + .PCKPolarity = (DT_INST_PROP(0, pixelclk_active) ? + DCMI_PCKPOLARITY_RISING : DCMI_PCKPOLARITY_FALLING), + .HSPolarity = (DT_INST_PROP(0, hsync_active) ? + DCMI_HSPOLARITY_HIGH : DCMI_HSPOLARITY_LOW), + .VSPolarity = (DT_INST_PROP(0, vsync_active) ? + DCMI_VSPOLARITY_HIGH : DCMI_VSPOLARITY_LOW), + .CaptureRate = STM32_DCMI_GET_CAPTURE_RATE( + DT_INST_PROP(0, capture_rate)), + .ExtendedDataMode = STM32_DCMI_GET_BUS_WIDTH( + DT_INST_PROP(0, bus_width)), + .JPEGMode = DCMI_JPEG_DISABLE, + .ByteSelectMode = DCMI_BSM_ALL, + .ByteSelectStart = DCMI_OEBS_ODD, + .LineSelectMode = DCMI_LSM_ALL, + .LineSelectStart = DCMI_OELS_ODD, + }, + }, +}; + +static const struct video_stm32_dcmi_config video_stm32_dcmi_config_0 = { + .pclken = { + .enr = DT_INST_CLOCKS_CELL(0, bits), + .bus = DT_INST_CLOCKS_CELL(0, bus) + }, + .irq_config = video_stm32_dcmi_irq_config_func, + .pctrl = PINCTRL_DT_INST_DEV_CONFIG_GET(0), + .sensor_dev = DEVICE_DT_GET(DT_INST_PHANDLE(0, sensor)), + DCMI_DMA_CHANNEL(0, PERIPHERAL, MEMORY) +}; + +static int video_stm32_dcmi_init(const struct device *dev) +{ + const struct video_stm32_dcmi_config *config = dev->config; + struct video_stm32_dcmi_data *data = dev->data; + int err; + + /* Configure DT provided pins */ + err = pinctrl_apply_state(config->pctrl, PINCTRL_STATE_DEFAULT); + if (err < 0) { + LOG_ERR("pinctrl setup failed. Error %d.", err); + return err; + } + + /* Initialize DMA peripheral */ + err = stm32_dma_init(dev); + if (err < 0) { + LOG_ERR("DMA initialization failed."); + return err; + } + + /* Enable DCMI clock */ + err = stm32_dcmi_enable_clock(dev); + if (err < 0) { + LOG_ERR("Clock enabling failed."); + return -EIO; + } + + data->dev = dev; + k_fifo_init(&data->fifo_in); + k_fifo_init(&data->fifo_out); + + /* Run IRQ init */ + config->irq_config(dev); + + /* Initialize DCMI peripheral */ + err = HAL_DCMI_Init(&data->hdcmi); + if (err != HAL_OK) { + LOG_ERR("DCMI initialization failed."); + return -EIO; + } + + k_sleep(K_MSEC(100)); + LOG_DBG("%s inited", dev->name); + + return 0; +} + +DEVICE_DT_INST_DEFINE(0, &video_stm32_dcmi_init, + NULL, &video_stm32_dcmi_data_0, + &video_stm32_dcmi_config_0, + POST_KERNEL, CONFIG_VIDEO_INIT_PRIORITY, + &video_stm32_dcmi_driver_api); diff --git a/drivers/watchdog/Kconfig.npcx b/drivers/watchdog/Kconfig.npcx index 8d25067be8c..864208b49fe 100644 --- a/drivers/watchdog/Kconfig.npcx +++ b/drivers/watchdog/Kconfig.npcx @@ -12,12 +12,11 @@ config WDT_NPCX processors. Say y if you wish to use watchdog on NPCX MCU. -config WDT_NPCX_DELAY_CYCLES - int "Number of delay cycles before generating watchdog event/signal" +config WDT_NPCX_WARNING_LEADING_TIME_MS + int "Milliseconds before generating watchdog event/signal" depends on WDT_NPCX - range 1 255 - default 10 + default 500 help This option defines the window in which a watchdog event must be - handled, in units of 31ms. After this time window, the watchdog reset - triggers immediately. + handled. After this time window, the watchdog reset triggers + immediately. diff --git a/drivers/watchdog/wdt_ambiq.c b/drivers/watchdog/wdt_ambiq.c index 5e3cf663b8e..91929c91e20 100644 --- a/drivers/watchdog/wdt_ambiq.c +++ b/drivers/watchdog/wdt_ambiq.c @@ -35,10 +35,13 @@ static void wdt_ambiq_isr(void *arg) const struct device *dev = (const struct device *)arg; struct wdt_ambiq_data *data = dev->data; +#if defined(CONFIG_SOC_SERIES_APOLLO3X) + am_hal_wdt_int_clear(); +#else uint32_t status; - am_hal_wdt_interrupt_status_get(AM_HAL_WDT_MCU, &status, false); am_hal_wdt_interrupt_clear(AM_HAL_WDT_MCU, status); +#endif if (data->callback) { data->callback(dev, 0); @@ -51,6 +54,25 @@ static int wdt_ambiq_setup(const struct device *dev, uint8_t options) struct wdt_ambiq_data *data = dev->data; am_hal_wdt_config_t cfg; +#if defined(CONFIG_SOC_SERIES_APOLLO3X) + uint32_t ui32ClockSource = AM_HAL_WDT_LFRC_CLK_DEFAULT; + + if (dev_cfg->clk_freq == 128) { + ui32ClockSource = AM_HAL_WDT_LFRC_CLK_128HZ; + } else if (dev_cfg->clk_freq == 16) { + ui32ClockSource = AM_HAL_WDT_LFRC_CLK_16HZ; + } else if (dev_cfg->clk_freq == 1) { + ui32ClockSource = AM_HAL_WDT_LFRC_CLK_1HZ; + } + cfg.ui32Config = ui32ClockSource | _VAL2FLD(WDT_CFG_RESEN, data->reset) | + AM_HAL_WDT_ENABLE_INTERRUPT; + cfg.ui16InterruptCount = data->timeout; + cfg.ui16ResetCount = data->timeout; + am_hal_clkgen_control(AM_HAL_CLKGEN_CONTROL_LFRC_START, 0); + am_hal_wdt_init(&cfg); + am_hal_wdt_int_enable(); + am_hal_wdt_start(); +#else if (dev_cfg->clk_freq == 128) { cfg.eClockSource = AM_HAL_WDT_128HZ; } else if (dev_cfg->clk_freq == 16) { @@ -68,7 +90,7 @@ static int wdt_ambiq_setup(const struct device *dev, uint8_t options) am_hal_wdt_config(AM_HAL_WDT_MCU, &cfg); am_hal_wdt_interrupt_enable(AM_HAL_WDT_MCU, AM_HAL_WDT_INTERRUPT_MCU); am_hal_wdt_start(AM_HAL_WDT_MCU, false); - +#endif return 0; } @@ -76,8 +98,11 @@ static int wdt_ambiq_disable(const struct device *dev) { ARG_UNUSED(dev); +#if defined(CONFIG_SOC_SERIES_APOLLO3X) + am_hal_wdt_halt(); +#else am_hal_wdt_stop(AM_HAL_WDT_MCU); - +#endif return 0; } @@ -114,7 +139,11 @@ static int wdt_ambiq_feed(const struct device *dev, int channel_id) ARG_UNUSED(dev); ARG_UNUSED(channel_id); +#if defined(CONFIG_SOC_SERIES_APOLLO3X) + am_hal_wdt_restart(); +#else am_hal_wdt_restart(AM_HAL_WDT_MCU); +#endif LOG_DBG("Fed the watchdog"); return 0; diff --git a/drivers/watchdog/wdt_iwdg_stm32.c b/drivers/watchdog/wdt_iwdg_stm32.c index 57f250c3dfa..bafd8f579df 100644 --- a/drivers/watchdog/wdt_iwdg_stm32.c +++ b/drivers/watchdog/wdt_iwdg_stm32.c @@ -190,8 +190,9 @@ static int iwdg_stm32_init(const struct device *dev) struct wdt_timeout_cfg config = { .window.max = CONFIG_IWDG_STM32_INITIAL_TIMEOUT }; - + /* Watchdog should be configured and started by `wdt_setup`*/ iwdg_stm32_install_timeout(dev, &config); + iwdg_stm32_setup(dev, 0); /* no option specified */ #endif /* diff --git a/drivers/watchdog/wdt_npcx.c b/drivers/watchdog/wdt_npcx.c index 482bbd1c733..31aadd86345 100644 --- a/drivers/watchdog/wdt_npcx.c +++ b/drivers/watchdog/wdt_npcx.c @@ -46,10 +46,13 @@ LOG_MODULE_REGISTER(wdt_npcx, CONFIG_WDT_LOG_LEVEL); #define NPCX_WDT_CLK LFCLK /* - * Maximum watchdog window time. Since the watchdog counter is 8-bits, maximum - * time supported by npcx watchdog is 256 * (32 * 32) / 32768 = 8 sec. + * Maximum watchdog window time. Keep the timer and watchdog clock prescaler + * (TWCP) to 0x5. Since the watchdog counter is 8-bits, maximum time supported + * by npcx watchdog is 256 * (32 * 32768) / 32768 = 8192 sec. + * The maximum time supported of T0OUT is 65536 * 32 / 32768 = 64 sec. + * Thus, the maximum time of watchdog set here is 64 sec. */ -#define NPCX_WDT_MAX_WND_TIME 8000UL +#define NPCX_WDT_MAX_WND_TIME 64000UL /* * Minimum watchdog window time. Ensure we have waited at least 3 watchdog @@ -139,7 +142,7 @@ static void wdt_t0out_isr(const struct device *dev, struct npcx_wui *wui) ARG_UNUSED(wui); LOG_DBG("WDT reset will issue after %d delay cycle! WUI(%d %d %d)", - CONFIG_WDT_NPCX_DELAY_CYCLES, wui->table, wui->group, wui->bit); + CONFIG_WDT_NPCX_WARNING_LEADING_TIME_MS, wui->table, wui->group, wui->bit); /* Handle watchdog event here. */ if (data->cb) { @@ -208,6 +211,9 @@ static int wdt_npcx_setup(const struct device *dev, uint8_t options) struct twd_reg *const inst = HAL_INSTANCE(dev); const struct wdt_npcx_config *const config = dev->config; struct wdt_npcx_data *const data = dev->data; + uint32_t wd_cnt, pre_scal; + uint8_t wdcp; + int rv; /* Disable irq of t0-out expired event first */ @@ -242,9 +248,24 @@ static int wdt_npcx_setup(const struct device *dev, uint8_t options) inst->TWDT0 = MAX(DIV_ROUND_UP(data->timeout * NPCX_WDT_CLK, 32 * 1000) - 1, 1); - /* Configure 8-bit watchdog counter */ - inst->WDCNT = MIN(DIV_ROUND_UP(data->timeout, 32) + - CONFIG_WDT_NPCX_DELAY_CYCLES, 0xff); + /* Configure 8-bit watchdog counter + * Change the prescaler of watchdog clock for larger timeout + */ + wd_cnt = DIV_ROUND_UP((data->timeout + CONFIG_WDT_NPCX_WARNING_LEADING_TIME_MS) * + NPCX_WDT_CLK, + 32 * 1000); + + pre_scal = DIV_ROUND_UP(wd_cnt, 255); + + /* + * Find the smallest power of 2 greater than or equal to the + * prescaler + */ + wdcp = LOG2(pre_scal - 1) + 1; + pre_scal = 1 << wdcp; + + inst->WDCP = wdcp; + inst->WDCNT = wd_cnt / pre_scal; LOG_DBG("WDT setup: TWDT0, WDCNT are %d, %d", inst->TWDT0, inst->WDCNT); @@ -265,12 +286,14 @@ static int wdt_npcx_disable(const struct device *dev) const struct wdt_npcx_config *const config = dev->config; struct wdt_npcx_data *const data = dev->data; struct twd_reg *const inst = HAL_INSTANCE(dev); + uint16_t min_wnd_t; /* * Ensure we have waited at least 3 watchdog ticks before * stopping watchdog */ - while (k_uptime_get() - data->last_watchdog_touch < NPCX_WDT_MIN_WND_TIME) { + min_wnd_t = DIV_ROUND_UP(3 * NPCX_WDT_CLK, 32 * (1 << inst->WDCP)); + while (k_uptime_get() - data->last_watchdog_touch < min_wnd_t) { continue; } diff --git a/drivers/watchdog/wdt_nrfx.c b/drivers/watchdog/wdt_nrfx.c index 706c2621bbb..1c23c9452b4 100644 --- a/drivers/watchdog/wdt_nrfx.c +++ b/drivers/watchdog/wdt_nrfx.c @@ -60,7 +60,9 @@ static int wdt_nrf_disable(const struct device *dev) { #if NRFX_WDT_HAS_STOP const struct wdt_nrfx_config *config = dev->config; + struct wdt_nrfx_data *data = dev->data; nrfx_err_t err_code; + int channel_id; err_code = nrfx_wdt_stop(&config->wdt); @@ -69,6 +71,13 @@ static int wdt_nrf_disable(const struct device *dev) return -EFAULT; } + nrfx_wdt_channels_free(&config->wdt); + + for (channel_id = 0; channel_id < data->m_allocated_channels; channel_id++) { + data->m_callbacks[channel_id] = NULL; + } + data->m_allocated_channels = 0; + return 0; #else ARG_UNUSED(dev); diff --git a/drivers/wifi/esp32/Kconfig.esp32 b/drivers/wifi/esp32/Kconfig.esp32 index 2efbbba1ce5..7760668b0bd 100644 --- a/drivers/wifi/esp32/Kconfig.esp32 +++ b/drivers/wifi/esp32/Kconfig.esp32 @@ -9,12 +9,6 @@ menuconfig WIFI_ESP32 select NET_L2_WIFI_MGMT select WIFI_USE_NATIVE_NETWORKING select MBEDTLS - select MBEDTLS_ENTROPY_ENABLED - select MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED - select MBEDTLS_ECP_ALL_ENABLED - select MBEDTLS_ECDH_C - select MBEDTLS_ECDSA_C - select MBEDTLS_ECP_C select THREAD_STACK_INFO select DYNAMIC_THREAD select DYNAMIC_THREAD_ALLOC diff --git a/drivers/wifi/esp_at/esp.c b/drivers/wifi/esp_at/esp.c index e2c84e4eb71..ff32e3884ef 100644 --- a/drivers/wifi/esp_at/esp.c +++ b/drivers/wifi/esp_at/esp.c @@ -256,7 +256,7 @@ MODEM_CMD_DEFINE(on_cmd_cipstamac) static int esp_pull_quoted(char **str, char *str_end, char **unquoted) { if (**str != '"') { - return -EBADMSG; + return -EAGAIN; } (*str)++; @@ -382,6 +382,8 @@ MODEM_CMD_DIRECT_DEFINE(on_cmd_cwlap) return err; } + res.channel = strtol(channel, NULL, 10); + if (dev->scan_cb) { dev->scan_cb(dev->net_iface, 0, &res); } diff --git a/dts/arm/ambiq/ambiq_apollo3_blue.dtsi b/dts/arm/ambiq/ambiq_apollo3_blue.dtsi new file mode 100644 index 00000000000..0005102b697 --- /dev/null +++ b/dts/arm/ambiq/ambiq_apollo3_blue.dtsi @@ -0,0 +1,215 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include +#include +#include +#include +#include + +/ { + clocks { + uartclk: apb-pclk { + compatible = "fixed-clock"; + clock-frequency = ; + #clock-cells = <0>; + }; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + compatible = "arm,cortex-m4f"; + reg = <0>; + }; + }; + + /* TCM */ + tcm: tcm@10000000 { + compatible = "zephyr,memory-region"; + reg = <0x10000000 0x10000>; + zephyr,memory-region = "ITCM"; + }; + + /* SRAM */ + sram0: memory@10010000 { + compatible = "mmio-sram"; + reg = <0x10010000 0x50000>; + }; + + soc { + compatible = "ambiq,apollo3-blue", "ambiq,apollo3x", "simple-bus"; + + flash: flash-controller@c000 { + compatible = "ambiq,flash-controller"; + reg = <0x0000c000 0xf4000>; + + #address-cells = <1>; + #size-cells = <1>; + + /* Flash region */ + flash0: flash@c000 { + compatible = "soc-nv-flash"; + reg = <0x0000c000 0xf4000>; + }; + }; + + pwrcfg: pwrcfg@40021000 { + compatible = "ambiq,pwrctrl"; + reg = <0x40021000 0x400>; + #pwrcfg-cells = <2>; + }; + + stimer0: stimer@40008140 { + compatible = "ambiq,stimer"; + reg = <0x40008140 0x80>; + interrupts = <23 0>; + status = "okay"; + }; + + counter0: counter@40008000 { + compatible = "ambiq,counter"; + reg = <0x40008000 0x80>; + interrupts = <14 0>; + status = "disabled"; + }; + + uart0: uart@4001c000 { + compatible = "ambiq,uart", "arm,pl011"; + reg = <0x4001c000 0x1000>; + interrupts = <15 0>; + interrupt-names = "UART0"; + status = "disabled"; + clocks = <&uartclk>; + ambiq,pwrcfg = <&pwrcfg 0x8 0x80>; + }; + + uart1: uart@4001d000 { + compatible = "ambiq,uart", "arm,pl011"; + reg = <0x4001d000 0x1000>; + interrupts = <16 0>; + interrupt-names = "UART1"; + status = "disabled"; + clocks = <&uartclk>; + ambiq,pwrcfg = <&pwrcfg 0x8 0x100>; + }; + + i2c0: i2c@50004000 { + reg = <0x50004000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <6 0>; + status = "disabled"; + ambiq,pwrcfg = <&pwrcfg 0x8 0x2>; + }; + + i2c1: i2c@50005000 { + reg = <0x50005000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <7 0>; + status = "disabled"; + ambiq,pwrcfg = <&pwrcfg 0x8 0x4>; + }; + + i2c2: i2c@50006000 { + reg = <0x50006000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <8 0>; + status = "disabled"; + ambiq,pwrcfg = <&pwrcfg 0x8 0x8>; + }; + + i2c3: i2c@50007000 { + reg = <0x50007000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <9 0>; + status = "disabled"; + ambiq,pwrcfg = <&pwrcfg 0x8 0x10>; + }; + + i2c4: i2c@50008000 { + reg = <0x50008000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <10 0>; + status = "disabled"; + ambiq,pwrcfg = <&pwrcfg 0x8 0x20>; + }; + + i2c5: i2c@50009000 { + reg = <0x50009000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <11 0>; + status = "disabled"; + ambiq,pwrcfg = <&pwrcfg 0x8 0x40>; + }; + + mspi0: spi@40020000 { + compatible = "ambiq,mspi"; + reg = <0x40020000 0x400>; + interrupts = <20 0>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + ambiq,pwrcfg = <&pwrcfg 0x8 0x800>; + }; + + pinctrl: pin-controller@40010000 { + compatible = "ambiq,apollo3-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 + >; + 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 = <13 0>; + status = "disabled"; + }; + + gpio32_63: gpio32_63@20 { + compatible = "ambiq,gpio-bank"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x20>; + interrupts = <13 0>; + status = "disabled"; + ngpios = <18>; + }; + }; + }; + + wdt0: watchdog@40024000 { + compatible = "ambiq,watchdog"; + reg = <0x40024000 0x400>; + interrupts = <1 0>; + clock-frequency = <16>; + status = "disabled"; + }; + }; +}; + +&nvic { + arm,num-irq-priority-bits = <3>; +}; diff --git a/dts/arm/ambiq/ambiq_apollo3p_blue.dtsi b/dts/arm/ambiq/ambiq_apollo3p_blue.dtsi new file mode 100644 index 00000000000..dc578356bf1 --- /dev/null +++ b/dts/arm/ambiq/ambiq_apollo3p_blue.dtsi @@ -0,0 +1,245 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include +#include +#include +#include +#include + +/ { + clocks { + uartclk: apb-pclk { + compatible = "fixed-clock"; + clock-frequency = ; + #clock-cells = <0>; + }; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + compatible = "arm,cortex-m4f"; + reg = <0>; + }; + }; + + /* TCM */ + tcm: tcm@10000000 { + compatible = "zephyr,memory-region"; + reg = <0x10000000 0x10000>; + zephyr,memory-region = "ITCM"; + }; + + /* SRAM */ + sram0: memory@10010000 { + compatible = "mmio-sram"; + reg = <0x10010000 0xB0000>; + }; + + soc { + compatible = "ambiq,apollo3p-blue", "ambiq,apollo3x", "simple-bus"; + + flash: flash-controller@c000 { + compatible = "ambiq,flash-controller"; + reg = <0x0000c000 0x1f4000>; + + #address-cells = <1>; + #size-cells = <1>; + + /* Flash region */ + flash0: flash@c000 { + compatible = "soc-nv-flash"; + reg = <0x0000c000 0x1f4000>; + }; + }; + + pwrcfg: pwrcfg@40021000 { + compatible = "ambiq,pwrctrl"; + reg = <0x40021000 0x400>; + #pwrcfg-cells = <2>; + }; + + stimer0: stimer@40008140 { + compatible = "ambiq,stimer"; + reg = <0x40008140 0x80>; + interrupts = <23 0>; + status = "okay"; + }; + + counter0: counter@40008000 { + compatible = "ambiq,counter"; + reg = <0x40008000 0x80>; + interrupts = <14 0>; + status = "disabled"; + }; + + uart0: uart@4001c000 { + compatible = "ambiq,uart", "arm,pl011"; + reg = <0x4001c000 0x1000>; + interrupts = <15 0>; + interrupt-names = "UART0"; + status = "disabled"; + clocks = <&uartclk>; + ambiq,pwrcfg = <&pwrcfg 0x8 0x80>; + }; + + uart1: uart@4001d000 { + compatible = "ambiq,uart", "arm,pl011"; + reg = <0x4001d000 0x1000>; + interrupts = <16 0>; + interrupt-names = "UART1"; + status = "disabled"; + clocks = <&uartclk>; + ambiq,pwrcfg = <&pwrcfg 0x8 0x100>; + }; + + i2c0: i2c@50004000 { + reg = <0x50004000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <6 0>; + status = "disabled"; + ambiq,pwrcfg = <&pwrcfg 0x8 0x2>; + }; + + i2c1: i2c@50005000 { + reg = <0x50005000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <7 0>; + status = "disabled"; + ambiq,pwrcfg = <&pwrcfg 0x8 0x4>; + }; + + i2c2: i2c@50006000 { + reg = <0x50006000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <8 0>; + status = "disabled"; + ambiq,pwrcfg = <&pwrcfg 0x8 0x8>; + }; + + i2c3: i2c@50007000 { + reg = <0x50007000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <9 0>; + status = "disabled"; + ambiq,pwrcfg = <&pwrcfg 0x8 0x10>; + }; + + i2c4: i2c@50008000 { + reg = <0x50008000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <10 0>; + status = "disabled"; + ambiq,pwrcfg = <&pwrcfg 0x8 0x20>; + }; + + i2c5: i2c@50009000 { + reg = <0x50009000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <11 0>; + status = "disabled"; + ambiq,pwrcfg = <&pwrcfg 0x8 0x40>; + }; + + mspi0: spi@50014000 { + compatible = "ambiq,mspi"; + reg = <0x50014000 0x400>; + interrupts = <20 0>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + ambiq,pwrcfg = <&pwrcfg 0x8 0x800>; + }; + + mspi1: spi@50015000 { + compatible = "ambiq,mspi"; + reg = <0x50015000 0x400>; + interrupts = <32 0>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + ambiq,pwrcfg = <&pwrcfg 0x8 0x1000>; + }; + + mspi2: spi@50016000 { + compatible = "ambiq,mspi"; + reg = <0x50016000 0x400>; + interrupts = <33 0>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + ambiq,pwrcfg = <&pwrcfg 0x8 0x2000>; + }; + + pinctrl: pin-controller@40010000 { + compatible = "ambiq,apollo3-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 + >; + 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 = <13 0>; + status = "disabled"; + }; + + gpio32_63: gpio32_63@20 { + compatible = "ambiq,gpio-bank"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x20>; + interrupts = <13 0>; + status = "disabled"; + }; + + gpio64_95: gpio64_95@40 { + compatible = "ambiq,gpio-bank"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x40>; + interrupts = <13 0>; + status = "disabled"; + ngpios = <10>; + }; + }; + }; + + wdt0: watchdog@40024000 { + compatible = "ambiq,watchdog"; + reg = <0x40024000 0x400>; + interrupts = <1 0>; + clock-frequency = <16>; + status = "disabled"; + }; + }; +}; + +&nvic { + arm,num-irq-priority-bits = <3>; +}; diff --git a/dts/arm/ambiq/ambiq_apollo4p.dtsi b/dts/arm/ambiq/ambiq_apollo4p.dtsi index a3abd1093e9..aa95ff80c9a 100644 --- a/dts/arm/ambiq/ambiq_apollo4p.dtsi +++ b/dts/arm/ambiq/ambiq_apollo4p.dtsi @@ -22,13 +22,35 @@ cpu0: cpu@0 { compatible = "arm,cortex-m4f"; reg = <0>; + cpu-power-states = <&idle &suspend_to_ram>; }; - }; + power-states { + idle: idle { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + /* + * As Apollo4 datasheet, run_to_sleep and sleep_to_run + * transition time are both lower than 1us, but + * considering the software overhead we set a + * bigger value. + */ + min-residency-us = <100>; + exit-latency-us = <5>; + }; - /* MRAM region */ - flash0: flash@18000 { - compatible = "soc-nv-flash"; - reg = <0x00018000 0x1e8000>; + suspend_to_ram: suspend_to_ram { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-ram"; + /* + * As Apollo4 datasheet, run_to_deepsleep transition + * time is lower than 1us and deepsleep_to_run + * transition time is about 25us, but considering + * the software overhead, we set a bigger value. + */ + min-residency-us = <2000>; + exit-latency-us = <125>; + }; + }; }; /* TCM */ @@ -47,6 +69,20 @@ soc { compatible = "ambiq,apollo4p", "ambiq,apollo4x", "simple-bus"; + flash: flash-controller@18000 { + compatible = "ambiq,flash-controller"; + reg = <0x00018000 0x1e8000>; + + #address-cells = <1>; + #size-cells = <1>; + + /* Flash region */ + flash0: flash@18000 { + compatible = "soc-nv-flash"; + reg = <0x00018000 0x1e8000>; + }; + }; + pwrcfg: pwrcfg@40021000 { compatible = "ambiq,pwrctrl"; reg = <0x40021000 0x400>; diff --git a/dts/arm/broadcom/viper-a72.dtsi b/dts/arm/broadcom/viper-a72.dtsi deleted file mode 100644 index d7a3ea35fe1..00000000000 --- a/dts/arm/broadcom/viper-a72.dtsi +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2020 Broadcom - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include - -#include "viper-common.dtsi" - -/ { - cpus { - #address-cells = <1>; - #size-cells = <0>; - - cpu@0 { - device_type = "cpu"; - compatible = "arm,cortex-a72"; - reg = <0>; - }; - }; - - timer { - compatible = "arm,armv8-timer"; - interrupt-parent = <&gic>; - interrupts = , - , - , - ; - }; - - soc { - gic: interrupt-controller@42700000 { - compatible = "arm,gic-v3", "arm,gic"; - reg = <0x42700000 0x010000>, - <0x42780000 0x600000>; - interrupt-controller; - #interrupt-cells = <4>; - status = "okay"; - }; - }; -}; - -&uart0 { - interrupt-parent = <&gic>; - interrupts = ; -}; - -&uart1 { - interrupt-parent = <&gic>; - interrupts = ; -}; - -&paxdma { - interrupt-parent = <&gic>; - interrupts = ; -}; diff --git a/dts/arm/broadcom/viper-m7.dtsi b/dts/arm/broadcom/viper-m7.dtsi index 85e38616e8b..6c8b6793ed4 100644 --- a/dts/arm/broadcom/viper-m7.dtsi +++ b/dts/arm/broadcom/viper-m7.dtsi @@ -5,8 +5,7 @@ */ #include - -#include "viper-common.dtsi" +#include / { cpus { diff --git a/dts/arm/cypress/pinctrl_cypress_psoc6.h b/dts/arm/infineon/cat1a/legacy/pinctrl_cypress_psoc6.h similarity index 100% rename from dts/arm/cypress/pinctrl_cypress_psoc6.h rename to dts/arm/infineon/cat1a/legacy/pinctrl_cypress_psoc6.h diff --git a/dts/arm/cypress/psoc6-pinctrl.dtsi b/dts/arm/infineon/cat1a/legacy/psoc6-pinctrl.dtsi similarity index 100% rename from dts/arm/cypress/psoc6-pinctrl.dtsi rename to dts/arm/infineon/cat1a/legacy/psoc6-pinctrl.dtsi diff --git a/dts/arm/cypress/psoc6.dtsi b/dts/arm/infineon/cat1a/legacy/psoc6.dtsi similarity index 100% rename from dts/arm/cypress/psoc6.dtsi rename to dts/arm/infineon/cat1a/legacy/psoc6.dtsi diff --git a/dts/arm/cypress/psoc6_cm0.dtsi b/dts/arm/infineon/cat1a/legacy/psoc6_cm0.dtsi similarity index 99% rename from dts/arm/cypress/psoc6_cm0.dtsi rename to dts/arm/infineon/cat1a/legacy/psoc6_cm0.dtsi index c4221dc1ad0..7a9d44ab17e 100644 --- a/dts/arm/cypress/psoc6_cm0.dtsi +++ b/dts/arm/infineon/cat1a/legacy/psoc6_cm0.dtsi @@ -5,7 +5,7 @@ */ #include -#include +#include / { cpus { diff --git a/dts/arm/cypress/psoc6_cm4.dtsi b/dts/arm/infineon/cat1a/legacy/psoc6_cm4.dtsi similarity index 84% rename from dts/arm/cypress/psoc6_cm4.dtsi rename to dts/arm/infineon/cat1a/legacy/psoc6_cm4.dtsi index c2693b61009..35e866413c6 100644 --- a/dts/arm/cypress/psoc6_cm4.dtsi +++ b/dts/arm/infineon/cat1a/legacy/psoc6_cm4.dtsi @@ -5,7 +5,7 @@ */ #include -#include +#include / { cpus { diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6016BZI_F04.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6016BZI_F04.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6016BZI_F04.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6016BZI_F04.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6036BZI_F04.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6036BZI_F04.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6036BZI_F04.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6036BZI_F04.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6116BZI_F54.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6116BZI_F54.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6116BZI_F54.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6116BZI_F54.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6117BZI_F34.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6117BZI_F34.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6117BZI_F34.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6117BZI_F34.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6117FDI_F02.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6117FDI_F02.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6117FDI_F02.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6117FDI_F02.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6117WI_F34.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6117WI_F34.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6117WI_F34.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6117WI_F34.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6136BZI_F14.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6136BZI_F14.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6136BZI_F14.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6136BZI_F14.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6136BZI_F34.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6136BZI_F34.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6136BZI_F34.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6136BZI_F34.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6136FDI_F42.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6136FDI_F42.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6136FDI_F42.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6136FDI_F42.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6136FTI_F42.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6136FTI_F42.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6136FTI_F42.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6136FTI_F42.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6137BZI_F14.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6137BZI_F14.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6137BZI_F14.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6137BZI_F14.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6137BZI_F34.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6137BZI_F34.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6137BZI_F34.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6137BZI_F34.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6137BZI_F54.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6137BZI_F54.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6137BZI_F54.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6137BZI_F54.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6137FDI_F02.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6137FDI_F02.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6137FDI_F02.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6137FDI_F02.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6137WI_F54.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6137WI_F54.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6137WI_F54.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6137WI_F54.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6144AZI_S4F12.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6144AZI_S4F12.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6144AZI_S4F12.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6144AZI_S4F12.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6144AZI_S4F62.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6144AZI_S4F62.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6144AZI_S4F62.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6144AZI_S4F62.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6144AZI_S4F82.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6144AZI_S4F82.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6144AZI_S4F82.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6144AZI_S4F82.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6144AZI_S4F83.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6144AZI_S4F83.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6144AZI_S4F83.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6144AZI_S4F83.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6144AZI_S4F92.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6144AZI_S4F92.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6144AZI_S4F92.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6144AZI_S4F92.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6144AZI_S4F93.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6144AZI_S4F93.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6144AZI_S4F93.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6144AZI_S4F93.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6144LQI_S4F12.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6144LQI_S4F12.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6144LQI_S4F12.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6144LQI_S4F12.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6144LQI_S4F62.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6144LQI_S4F62.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6144LQI_S4F62.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6144LQI_S4F62.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6144LQI_S4F82.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6144LQI_S4F82.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6144LQI_S4F82.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6144LQI_S4F82.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6144LQI_S4F92.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6144LQI_S4F92.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6144LQI_S4F92.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6144LQI_S4F92.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6145AZI_S3F02.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6145AZI_S3F02.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6145AZI_S3F02.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6145AZI_S3F02.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6145AZI_S3F12.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6145AZI_S3F12.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6145AZI_S3F12.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6145AZI_S3F12.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6145AZI_S3F42.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6145AZI_S3F42.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6145AZI_S3F42.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6145AZI_S3F42.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6145AZI_S3F62.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6145AZI_S3F62.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6145AZI_S3F62.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6145AZI_S3F62.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6145AZI_S3F72.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6145AZI_S3F72.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6145AZI_S3F72.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6145AZI_S3F72.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6145FNI_S3F11.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6145FNI_S3F11.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6145FNI_S3F11.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6145FNI_S3F11.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6145FNI_S3F41.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6145FNI_S3F41.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6145FNI_S3F41.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6145FNI_S3F41.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6145FNI_S3F71.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6145FNI_S3F71.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6145FNI_S3F71.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6145FNI_S3F71.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6145LQI_S3F02.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6145LQI_S3F02.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6145LQI_S3F02.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6145LQI_S3F02.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6145LQI_S3F12.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6145LQI_S3F12.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6145LQI_S3F12.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6145LQI_S3F12.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6145LQI_S3F42.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6145LQI_S3F42.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6145LQI_S3F42.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6145LQI_S3F42.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6145LQI_S3F62.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6145LQI_S3F62.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6145LQI_S3F62.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6145LQI_S3F62.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6145LQI_S3F72.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6145LQI_S3F72.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6145LQI_S3F72.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6145LQI_S3F72.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6148AZI_S2F44.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6148AZI_S2F44.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6148AZI_S2F44.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6148AZI_S2F44.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6148BZI_S2F44.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6148BZI_S2F44.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6148BZI_S2F44.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6148BZI_S2F44.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6148FNI_S2F43.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6148FNI_S2F43.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6148FNI_S2F43.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6148FNI_S2F43.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6148LQI_S2F02.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6148LQI_S2F02.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6148LQI_S2F02.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6148LQI_S2F02.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6148LQI_S2F42.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6148LQI_S2F42.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6148LQI_S2F42.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6148LQI_S2F42.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C614AAZI_S2F04.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C614AAZI_S2F04.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C614AAZI_S2F04.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C614AAZI_S2F04.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C614AAZI_S2F14.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C614AAZI_S2F14.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C614AAZI_S2F14.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C614AAZI_S2F14.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C614AAZI_S2F44.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C614AAZI_S2F44.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C614AAZI_S2F44.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C614AAZI_S2F44.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C614ABZI_S2F04.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C614ABZI_S2F04.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C614ABZI_S2F04.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C614ABZI_S2F04.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C614ABZI_S2F44.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C614ABZI_S2F44.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C614ABZI_S2F44.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C614ABZI_S2F44.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C614AFNI_S2F03.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C614AFNI_S2F03.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C614AFNI_S2F03.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C614AFNI_S2F03.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C614AFNI_S2F43.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C614AFNI_S2F43.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C614AFNI_S2F43.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C614AFNI_S2F43.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C614ALQI_S2F02.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C614ALQI_S2F02.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C614ALQI_S2F02.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C614ALQI_S2F02.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C614ALQI_S2F42.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C614ALQI_S2F42.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C614ALQI_S2F42.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C614ALQI_S2F42.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6244AZI_S4D12.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6244AZI_S4D12.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6244AZI_S4D12.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6244AZI_S4D12.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6244AZI_S4D62.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6244AZI_S4D62.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6244AZI_S4D62.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6244AZI_S4D62.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6244AZI_S4D82.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6244AZI_S4D82.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6244AZI_S4D82.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6244AZI_S4D82.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6244AZI_S4D83.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6244AZI_S4D83.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6244AZI_S4D83.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6244AZI_S4D83.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6244AZI_S4D92.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6244AZI_S4D92.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6244AZI_S4D92.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6244AZI_S4D92.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6244AZI_S4D93.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6244AZI_S4D93.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6244AZI_S4D93.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6244AZI_S4D93.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6244LQI_S4D12.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6244LQI_S4D12.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6244LQI_S4D12.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6244LQI_S4D12.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6244LQI_S4D62.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6244LQI_S4D62.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6244LQI_S4D62.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6244LQI_S4D62.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6244LQI_S4D82.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6244LQI_S4D82.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6244LQI_S4D82.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6244LQI_S4D82.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6244LQI_S4D92.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6244LQI_S4D92.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6244LQI_S4D92.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6244LQI_S4D92.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6245AZI_S3D02.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6245AZI_S3D02.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6245AZI_S3D02.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6245AZI_S3D02.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6245AZI_S3D12.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6245AZI_S3D12.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6245AZI_S3D12.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6245AZI_S3D12.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6245AZI_S3D42.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6245AZI_S3D42.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6245AZI_S3D42.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6245AZI_S3D42.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6245AZI_S3D62.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6245AZI_S3D62.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6245AZI_S3D62.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6245AZI_S3D62.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6245AZI_S3D72.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6245AZI_S3D72.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6245AZI_S3D72.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6245AZI_S3D72.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6245FNI_S3D11.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6245FNI_S3D11.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6245FNI_S3D11.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6245FNI_S3D11.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6245FNI_S3D41.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6245FNI_S3D41.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6245FNI_S3D41.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6245FNI_S3D41.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6245FNI_S3D71.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6245FNI_S3D71.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6245FNI_S3D71.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6245FNI_S3D71.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6245LQI_S3D02.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6245LQI_S3D02.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6245LQI_S3D02.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6245LQI_S3D02.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6245LQI_S3D12.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6245LQI_S3D12.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6245LQI_S3D12.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6245LQI_S3D12.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6245LQI_S3D42.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6245LQI_S3D42.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6245LQI_S3D42.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6245LQI_S3D42.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6245LQI_S3D62.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6245LQI_S3D62.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6245LQI_S3D62.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6245LQI_S3D62.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6245LQI_S3D72.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6245LQI_S3D72.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6245LQI_S3D72.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6245LQI_S3D72.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6246BZI_D04.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6246BZI_D04.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6246BZI_D04.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6246BZI_D04.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6247BFI_D54.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6247BFI_D54.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6247BFI_D54.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6247BFI_D54.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6247BZI_AUD54.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6247BZI_AUD54.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6247BZI_AUD54.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6247BZI_AUD54.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6247BZI_D34.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6247BZI_D34.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6247BZI_D34.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6247BZI_D34.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6247BZI_D44.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6247BZI_D44.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6247BZI_D44.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6247BZI_D44.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6247BZI_D54.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6247BZI_D54.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6247BZI_D54.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6247BZI_D54.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6247FDI_D02.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6247FDI_D02.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6247FDI_D02.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6247FDI_D02.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6247FDI_D32.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6247FDI_D32.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6247FDI_D32.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6247FDI_D32.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6247FDI_D52.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6247FDI_D52.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6247FDI_D52.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6247FDI_D52.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6247FTI_D52.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6247FTI_D52.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6247FTI_D52.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6247FTI_D52.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6247WI_D54.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6247WI_D54.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6247WI_D54.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6247WI_D54.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6248AZI_S2D14.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6248AZI_S2D14.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6248AZI_S2D14.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6248AZI_S2D14.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6248AZI_S2D44.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6248AZI_S2D44.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6248AZI_S2D44.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6248AZI_S2D44.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6248BZI_S2D44.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6248BZI_S2D44.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6248BZI_S2D44.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6248BZI_S2D44.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6248FNI_S2D43.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6248FNI_S2D43.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6248FNI_S2D43.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6248FNI_S2D43.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6248LQI_S2D02.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6248LQI_S2D02.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6248LQI_S2D02.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6248LQI_S2D02.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6248LQI_S2D42.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6248LQI_S2D42.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6248LQI_S2D42.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6248LQI_S2D42.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C624AAZI_S2D14.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C624AAZI_S2D14.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C624AAZI_S2D14.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C624AAZI_S2D14.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C624AAZI_S2D44.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C624AAZI_S2D44.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C624AAZI_S2D44.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C624AAZI_S2D44.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C624ABZI_D44.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C624ABZI_D44.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C624ABZI_D44.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C624ABZI_D44.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C624ABZI_S2D04.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C624ABZI_S2D04.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C624ABZI_S2D04.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C624ABZI_S2D04.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C624ABZI_S2D14.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C624ABZI_S2D14.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C624ABZI_S2D14.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C624ABZI_S2D14.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C624ABZI_S2D44.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C624ABZI_S2D44.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C624ABZI_S2D44.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C624ABZI_S2D44.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C624ABZI_S2D44A0.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C624ABZI_S2D44A0.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C624ABZI_S2D44A0.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C624ABZI_S2D44A0.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C624AFNI_S2D43.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C624AFNI_S2D43.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C624AFNI_S2D43.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C624AFNI_S2D43.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C624ALQI_S2D02.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C624ALQI_S2D02.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C624ALQI_S2D02.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C624ALQI_S2D02.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C624ALQI_S2D42.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C624ALQI_S2D42.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C624ALQI_S2D42.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C624ALQI_S2D42.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6316BZI_BLF03.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6316BZI_BLF03.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6316BZI_BLF03.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6316BZI_BLF03.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6316BZI_BLF04.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6316BZI_BLF04.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6316BZI_BLF04.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6316BZI_BLF04.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6316BZI_BLF53.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6316BZI_BLF53.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6316BZI_BLF53.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6316BZI_BLF53.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6316BZI_BLF54.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6316BZI_BLF54.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6316BZI_BLF54.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6316BZI_BLF54.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6336BZI_BLD13.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6336BZI_BLD13.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6336BZI_BLD13.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6336BZI_BLD13.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6336BZI_BLD14.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6336BZI_BLD14.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6336BZI_BLD14.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6336BZI_BLD14.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6336BZI_BLF03.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6336BZI_BLF03.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6336BZI_BLF03.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6336BZI_BLF03.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6336BZI_BLF04.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6336BZI_BLF04.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6336BZI_BLF04.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6336BZI_BLF04.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6336BZI_BUD13.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6336BZI_BUD13.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6336BZI_BUD13.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6336BZI_BUD13.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6336LQI_BLF02.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6336LQI_BLF02.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6336LQI_BLF02.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6336LQI_BLF02.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6336LQI_BLF42.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6336LQI_BLF42.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6336LQI_BLF42.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6336LQI_BLF42.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6337BZI_BLF13.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6337BZI_BLF13.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6337BZI_BLF13.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6337BZI_BLF13.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6347BZI_BLD33.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6347BZI_BLD33.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6347BZI_BLD33.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6347BZI_BLD33.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6347BZI_BLD34.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6347BZI_BLD34.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6347BZI_BLD34.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6347BZI_BLD34.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6347BZI_BLD43.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6347BZI_BLD43.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6347BZI_BLD43.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6347BZI_BLD43.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6347BZI_BLD44.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6347BZI_BLD44.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6347BZI_BLD44.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6347BZI_BLD44.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6347BZI_BLD53.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6347BZI_BLD53.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6347BZI_BLD53.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6347BZI_BLD53.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6347BZI_BLD54.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6347BZI_BLD54.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6347BZI_BLD54.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6347BZI_BLD54.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6347BZI_BUD33.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6347BZI_BUD33.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6347BZI_BUD33.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6347BZI_BUD33.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6347BZI_BUD43.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6347BZI_BUD43.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6347BZI_BUD43.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6347BZI_BUD43.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6347BZI_BUD53.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6347BZI_BUD53.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6347BZI_BUD53.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6347BZI_BUD53.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6347FMI_BLD13.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6347FMI_BLD13.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6347FMI_BLD13.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6347FMI_BLD13.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6347FMI_BLD33.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6347FMI_BLD33.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6347FMI_BLD33.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6347FMI_BLD33.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6347FMI_BLD43.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6347FMI_BLD43.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6347FMI_BLD43.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6347FMI_BLD43.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6347FMI_BLD53.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6347FMI_BLD53.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6347FMI_BLD53.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6347FMI_BLD53.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6347FMI_BUD13.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6347FMI_BUD13.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6347FMI_BUD13.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6347FMI_BUD13.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6347FMI_BUD33.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6347FMI_BUD33.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6347FMI_BUD33.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6347FMI_BUD33.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6347FMI_BUD43.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6347FMI_BUD43.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6347FMI_BUD43.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6347FMI_BUD43.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6347FMI_BUD53.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6347FMI_BUD53.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6347FMI_BUD53.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6347FMI_BUD53.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6347LQI_BLD52.dtsi b/dts/arm/infineon/cat1a/mpns/CY8C6347LQI_BLD52.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CY8C6347LQI_BLD52.dtsi rename to dts/arm/infineon/cat1a/mpns/CY8C6347LQI_BLD52.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CYB06445LQI_S3D42.dtsi b/dts/arm/infineon/cat1a/mpns/CYB06445LQI_S3D42.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CYB06445LQI_S3D42.dtsi rename to dts/arm/infineon/cat1a/mpns/CYB06445LQI_S3D42.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CYB06447BZI_BLD53.dtsi b/dts/arm/infineon/cat1a/mpns/CYB06447BZI_BLD53.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CYB06447BZI_BLD53.dtsi rename to dts/arm/infineon/cat1a/mpns/CYB06447BZI_BLD53.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CYB06447BZI_BLD54.dtsi b/dts/arm/infineon/cat1a/mpns/CYB06447BZI_BLD54.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CYB06447BZI_BLD54.dtsi rename to dts/arm/infineon/cat1a/mpns/CYB06447BZI_BLD54.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CYB06447BZI_D54.dtsi b/dts/arm/infineon/cat1a/mpns/CYB06447BZI_D54.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CYB06447BZI_D54.dtsi rename to dts/arm/infineon/cat1a/mpns/CYB06447BZI_D54.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CYB0644ABZI_S2D44.dtsi b/dts/arm/infineon/cat1a/mpns/CYB0644ABZI_S2D44.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CYB0644ABZI_S2D44.dtsi rename to dts/arm/infineon/cat1a/mpns/CYB0644ABZI_S2D44.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CYBLE_416045_02.dtsi b/dts/arm/infineon/cat1a/mpns/CYBLE_416045_02.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CYBLE_416045_02.dtsi rename to dts/arm/infineon/cat1a/mpns/CYBLE_416045_02.dtsi diff --git a/dts/arm/infineon/psoc6/mpns/CYS0644ABZI_S2D44.dtsi b/dts/arm/infineon/cat1a/mpns/CYS0644ABZI_S2D44.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/mpns/CYS0644ABZI_S2D44.dtsi rename to dts/arm/infineon/cat1a/mpns/CYS0644ABZI_S2D44.dtsi diff --git a/dts/arm/infineon/psoc6/psoc6_01/psoc6_01.104-m-csp-ble-usb.dtsi b/dts/arm/infineon/cat1a/psoc6_01/psoc6_01.104-m-csp-ble-usb.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/psoc6_01/psoc6_01.104-m-csp-ble-usb.dtsi rename to dts/arm/infineon/cat1a/psoc6_01/psoc6_01.104-m-csp-ble-usb.dtsi diff --git a/dts/arm/infineon/psoc6/psoc6_01/psoc6_01.104-m-csp-ble.dtsi b/dts/arm/infineon/cat1a/psoc6_01/psoc6_01.104-m-csp-ble.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/psoc6_01/psoc6_01.104-m-csp-ble.dtsi rename to dts/arm/infineon/cat1a/psoc6_01/psoc6_01.104-m-csp-ble.dtsi diff --git a/dts/arm/infineon/psoc6/psoc6_01/psoc6_01.116-bga-ble.dtsi b/dts/arm/infineon/cat1a/psoc6_01/psoc6_01.116-bga-ble.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/psoc6_01/psoc6_01.116-bga-ble.dtsi rename to dts/arm/infineon/cat1a/psoc6_01/psoc6_01.116-bga-ble.dtsi diff --git a/dts/arm/infineon/psoc6/psoc6_01/psoc6_01.116-bga-usb.dtsi b/dts/arm/infineon/cat1a/psoc6_01/psoc6_01.116-bga-usb.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/psoc6_01/psoc6_01.116-bga-usb.dtsi rename to dts/arm/infineon/cat1a/psoc6_01/psoc6_01.116-bga-usb.dtsi diff --git a/dts/arm/infineon/psoc6/psoc6_01/psoc6_01.124-bga-sip.dtsi b/dts/arm/infineon/cat1a/psoc6_01/psoc6_01.124-bga-sip.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/psoc6_01/psoc6_01.124-bga-sip.dtsi rename to dts/arm/infineon/cat1a/psoc6_01/psoc6_01.124-bga-sip.dtsi diff --git a/dts/arm/infineon/psoc6/psoc6_01/psoc6_01.124-bga.dtsi b/dts/arm/infineon/cat1a/psoc6_01/psoc6_01.124-bga.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/psoc6_01/psoc6_01.124-bga.dtsi rename to dts/arm/infineon/cat1a/psoc6_01/psoc6_01.124-bga.dtsi diff --git a/dts/arm/infineon/psoc6/psoc6_01/psoc6_01.43-smt.dtsi b/dts/arm/infineon/cat1a/psoc6_01/psoc6_01.43-smt.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/psoc6_01/psoc6_01.43-smt.dtsi rename to dts/arm/infineon/cat1a/psoc6_01/psoc6_01.43-smt.dtsi diff --git a/dts/arm/infineon/psoc6/psoc6_01/psoc6_01.68-qfn-ble.dtsi b/dts/arm/infineon/cat1a/psoc6_01/psoc6_01.68-qfn-ble.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/psoc6_01/psoc6_01.68-qfn-ble.dtsi rename to dts/arm/infineon/cat1a/psoc6_01/psoc6_01.68-qfn-ble.dtsi diff --git a/dts/arm/infineon/psoc6/psoc6_01/psoc6_01.80-wlcsp.dtsi b/dts/arm/infineon/cat1a/psoc6_01/psoc6_01.80-wlcsp.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/psoc6_01/psoc6_01.80-wlcsp.dtsi rename to dts/arm/infineon/cat1a/psoc6_01/psoc6_01.80-wlcsp.dtsi diff --git a/dts/arm/infineon/psoc6/psoc6_01/psoc6_01.dtsi b/dts/arm/infineon/cat1a/psoc6_01/psoc6_01.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/psoc6_01/psoc6_01.dtsi rename to dts/arm/infineon/cat1a/psoc6_01/psoc6_01.dtsi diff --git a/dts/arm/infineon/psoc6/psoc6_02/psoc6_02.100-wlcsp.dtsi b/dts/arm/infineon/cat1a/psoc6_02/psoc6_02.100-wlcsp.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/psoc6_02/psoc6_02.100-wlcsp.dtsi rename to dts/arm/infineon/cat1a/psoc6_02/psoc6_02.100-wlcsp.dtsi diff --git a/dts/arm/infineon/cat1a/psoc6_02/psoc6_02.124-bga.dtsi b/dts/arm/infineon/cat1a/psoc6_02/psoc6_02.124-bga.dtsi new file mode 100644 index 00000000000..aa1cd9a0c93 --- /dev/null +++ b/dts/arm/infineon/cat1a/psoc6_02/psoc6_02.124-bga.dtsi @@ -0,0 +1,969 @@ +/* + * Copyright (c) 2022 Cypress Semiconductor Corporation (an Infineon company) or + * an affiliate of Cypress Semiconductor Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "psoc6_02.dtsi" + +/ { + soc { + pinctrl: pinctrl@40300000 { + /* scb_i2c_scl */ + /omit-if-no-ref/ p0_2_scb0_i2c_scl: p0_2_scb0_i2c_scl { + pinmux = ; + }; + /omit-if-no-ref/ p1_0_scb7_i2c_scl: p1_0_scb7_i2c_scl { + pinmux = ; + }; + /omit-if-no-ref/ p2_0_scb1_i2c_scl: p2_0_scb1_i2c_scl { + pinmux = ; + }; + /omit-if-no-ref/ p2_4_scb9_i2c_scl: p2_4_scb9_i2c_scl { + pinmux = ; + }; + /omit-if-no-ref/ p3_0_scb2_i2c_scl: p3_0_scb2_i2c_scl { + pinmux = ; + }; + /omit-if-no-ref/ p4_0_scb7_i2c_scl: p4_0_scb7_i2c_scl { + pinmux = ; + }; + /omit-if-no-ref/ p5_0_scb5_i2c_scl: p5_0_scb5_i2c_scl { + pinmux = ; + }; + /omit-if-no-ref/ p5_4_scb10_i2c_scl: p5_4_scb10_i2c_scl { + pinmux = ; + }; + /omit-if-no-ref/ p6_0_scb3_i2c_scl: p6_0_scb3_i2c_scl { + pinmux = ; + }; + /omit-if-no-ref/ p6_0_scb8_i2c_scl: p6_0_scb8_i2c_scl { + pinmux = ; + }; + /omit-if-no-ref/ p6_4_scb6_i2c_scl: p6_4_scb6_i2c_scl { + pinmux = ; + }; + /omit-if-no-ref/ p6_4_scb8_i2c_scl: p6_4_scb8_i2c_scl { + pinmux = ; + }; + /omit-if-no-ref/ p7_0_scb4_i2c_scl: p7_0_scb4_i2c_scl { + pinmux = ; + }; + /omit-if-no-ref/ p8_0_scb4_i2c_scl: p8_0_scb4_i2c_scl { + pinmux = ; + }; + /omit-if-no-ref/ p8_4_scb11_i2c_scl: p8_4_scb11_i2c_scl { + pinmux = ; + }; + /omit-if-no-ref/ p9_0_scb2_i2c_scl: p9_0_scb2_i2c_scl { + pinmux = ; + }; + /omit-if-no-ref/ p10_0_scb1_i2c_scl: p10_0_scb1_i2c_scl { + pinmux = ; + }; + /omit-if-no-ref/ p11_0_scb5_i2c_scl: p11_0_scb5_i2c_scl { + pinmux = ; + }; + /omit-if-no-ref/ p12_0_scb6_i2c_scl: p12_0_scb6_i2c_scl { + pinmux = ; + }; + /omit-if-no-ref/ p13_0_scb6_i2c_scl: p13_0_scb6_i2c_scl { + pinmux = ; + }; + /omit-if-no-ref/ p13_4_scb12_i2c_scl: p13_4_scb12_i2c_scl { + pinmux = ; + }; + + /* scb_i2c_sda */ + /omit-if-no-ref/ p0_3_scb0_i2c_sda: p0_3_scb0_i2c_sda { + pinmux = ; + }; + /omit-if-no-ref/ p1_1_scb7_i2c_sda: p1_1_scb7_i2c_sda { + pinmux = ; + }; + /omit-if-no-ref/ p2_1_scb1_i2c_sda: p2_1_scb1_i2c_sda { + pinmux = ; + }; + /omit-if-no-ref/ p2_5_scb9_i2c_sda: p2_5_scb9_i2c_sda { + pinmux = ; + }; + /omit-if-no-ref/ p3_1_scb2_i2c_sda: p3_1_scb2_i2c_sda { + pinmux = ; + }; + /omit-if-no-ref/ p4_1_scb7_i2c_sda: p4_1_scb7_i2c_sda { + pinmux = ; + }; + /omit-if-no-ref/ p5_1_scb5_i2c_sda: p5_1_scb5_i2c_sda { + pinmux = ; + }; + /omit-if-no-ref/ p5_5_scb10_i2c_sda: p5_5_scb10_i2c_sda { + pinmux = ; + }; + /omit-if-no-ref/ p6_1_scb3_i2c_sda: p6_1_scb3_i2c_sda { + pinmux = ; + }; + /omit-if-no-ref/ p6_1_scb8_i2c_sda: p6_1_scb8_i2c_sda { + pinmux = ; + }; + /omit-if-no-ref/ p6_5_scb6_i2c_sda: p6_5_scb6_i2c_sda { + pinmux = ; + }; + /omit-if-no-ref/ p6_5_scb8_i2c_sda: p6_5_scb8_i2c_sda { + pinmux = ; + }; + /omit-if-no-ref/ p7_1_scb4_i2c_sda: p7_1_scb4_i2c_sda { + pinmux = ; + }; + /omit-if-no-ref/ p8_1_scb4_i2c_sda: p8_1_scb4_i2c_sda { + pinmux = ; + }; + /omit-if-no-ref/ p8_5_scb11_i2c_sda: p8_5_scb11_i2c_sda { + pinmux = ; + }; + /omit-if-no-ref/ p9_1_scb2_i2c_sda: p9_1_scb2_i2c_sda { + pinmux = ; + }; + /omit-if-no-ref/ p10_1_scb1_i2c_sda: p10_1_scb1_i2c_sda { + pinmux = ; + }; + /omit-if-no-ref/ p11_1_scb5_i2c_sda: p11_1_scb5_i2c_sda { + pinmux = ; + }; + /omit-if-no-ref/ p12_1_scb6_i2c_sda: p12_1_scb6_i2c_sda { + pinmux = ; + }; + /omit-if-no-ref/ p13_1_scb6_i2c_sda: p13_1_scb6_i2c_sda { + pinmux = ; + }; + /omit-if-no-ref/ p13_5_scb12_i2c_sda: p13_5_scb12_i2c_sda { + pinmux = ; + }; + + /* scb_uart_cts */ + /omit-if-no-ref/ p0_5_scb0_uart_cts: p0_5_scb0_uart_cts { + pinmux = ; + }; + /omit-if-no-ref/ p1_3_scb7_uart_cts: p1_3_scb7_uart_cts { + pinmux = ; + }; + /omit-if-no-ref/ p2_3_scb1_uart_cts: p2_3_scb1_uart_cts { + pinmux = ; + }; + /omit-if-no-ref/ p2_7_scb9_uart_cts: p2_7_scb9_uart_cts { + pinmux = ; + }; + /omit-if-no-ref/ p3_3_scb2_uart_cts: p3_3_scb2_uart_cts { + pinmux = ; + }; + /omit-if-no-ref/ p5_3_scb5_uart_cts: p5_3_scb5_uart_cts { + pinmux = ; + }; + /omit-if-no-ref/ p5_7_scb10_uart_cts: p5_7_scb10_uart_cts { + pinmux = ; + }; + /omit-if-no-ref/ p6_3_scb3_uart_cts: p6_3_scb3_uart_cts { + pinmux = ; + }; + /omit-if-no-ref/ p6_7_scb6_uart_cts: p6_7_scb6_uart_cts { + pinmux = ; + }; + /omit-if-no-ref/ p7_3_scb4_uart_cts: p7_3_scb4_uart_cts { + pinmux = ; + }; + /omit-if-no-ref/ p8_3_scb4_uart_cts: p8_3_scb4_uart_cts { + pinmux = ; + }; + /omit-if-no-ref/ p8_7_scb11_uart_cts: p8_7_scb11_uart_cts { + pinmux = ; + }; + /omit-if-no-ref/ p9_3_scb2_uart_cts: p9_3_scb2_uart_cts { + pinmux = ; + }; + /omit-if-no-ref/ p10_3_scb1_uart_cts: p10_3_scb1_uart_cts { + pinmux = ; + }; + /omit-if-no-ref/ p11_3_scb5_uart_cts: p11_3_scb5_uart_cts { + pinmux = ; + }; + /omit-if-no-ref/ p12_3_scb6_uart_cts: p12_3_scb6_uart_cts { + pinmux = ; + }; + /omit-if-no-ref/ p13_3_scb6_uart_cts: p13_3_scb6_uart_cts { + pinmux = ; + }; + /omit-if-no-ref/ p13_7_scb12_uart_cts: p13_7_scb12_uart_cts { + pinmux = ; + }; + + /* scb_uart_rts */ + /omit-if-no-ref/ p0_4_scb0_uart_rts: p0_4_scb0_uart_rts { + pinmux = ; + }; + /omit-if-no-ref/ p1_2_scb7_uart_rts: p1_2_scb7_uart_rts { + pinmux = ; + }; + /omit-if-no-ref/ p2_2_scb1_uart_rts: p2_2_scb1_uart_rts { + pinmux = ; + }; + /omit-if-no-ref/ p2_6_scb9_uart_rts: p2_6_scb9_uart_rts { + pinmux = ; + }; + /omit-if-no-ref/ p3_2_scb2_uart_rts: p3_2_scb2_uart_rts { + pinmux = ; + }; + /omit-if-no-ref/ p5_2_scb5_uart_rts: p5_2_scb5_uart_rts { + pinmux = ; + }; + /omit-if-no-ref/ p5_6_scb10_uart_rts: p5_6_scb10_uart_rts { + pinmux = ; + }; + /omit-if-no-ref/ p6_2_scb3_uart_rts: p6_2_scb3_uart_rts { + pinmux = ; + }; + /omit-if-no-ref/ p6_6_scb6_uart_rts: p6_6_scb6_uart_rts { + pinmux = ; + }; + /omit-if-no-ref/ p7_2_scb4_uart_rts: p7_2_scb4_uart_rts { + pinmux = ; + }; + /omit-if-no-ref/ p8_2_scb4_uart_rts: p8_2_scb4_uart_rts { + pinmux = ; + }; + /omit-if-no-ref/ p8_6_scb11_uart_rts: p8_6_scb11_uart_rts { + pinmux = ; + }; + /omit-if-no-ref/ p9_2_scb2_uart_rts: p9_2_scb2_uart_rts { + pinmux = ; + }; + /omit-if-no-ref/ p10_2_scb1_uart_rts: p10_2_scb1_uart_rts { + pinmux = ; + }; + /omit-if-no-ref/ p11_2_scb5_uart_rts: p11_2_scb5_uart_rts { + pinmux = ; + }; + /omit-if-no-ref/ p12_2_scb6_uart_rts: p12_2_scb6_uart_rts { + pinmux = ; + }; + /omit-if-no-ref/ p13_2_scb6_uart_rts: p13_2_scb6_uart_rts { + pinmux = ; + }; + /omit-if-no-ref/ p13_6_scb12_uart_rts: p13_6_scb12_uart_rts { + pinmux = ; + }; + + /* scb_uart_rx */ + /omit-if-no-ref/ p0_2_scb0_uart_rx: p0_2_scb0_uart_rx { + pinmux = ; + }; + /omit-if-no-ref/ p1_0_scb7_uart_rx: p1_0_scb7_uart_rx { + pinmux = ; + }; + /omit-if-no-ref/ p2_0_scb1_uart_rx: p2_0_scb1_uart_rx { + pinmux = ; + }; + /omit-if-no-ref/ p2_4_scb9_uart_rx: p2_4_scb9_uart_rx { + pinmux = ; + }; + /omit-if-no-ref/ p3_0_scb2_uart_rx: p3_0_scb2_uart_rx { + pinmux = ; + }; + /omit-if-no-ref/ p4_0_scb7_uart_rx: p4_0_scb7_uart_rx { + pinmux = ; + }; + /omit-if-no-ref/ p5_0_scb5_uart_rx: p5_0_scb5_uart_rx { + pinmux = ; + }; + /omit-if-no-ref/ p5_4_scb10_uart_rx: p5_4_scb10_uart_rx { + pinmux = ; + }; + /omit-if-no-ref/ p6_0_scb3_uart_rx: p6_0_scb3_uart_rx { + pinmux = ; + }; + /omit-if-no-ref/ p6_4_scb6_uart_rx: p6_4_scb6_uart_rx { + pinmux = ; + }; + /omit-if-no-ref/ p7_0_scb4_uart_rx: p7_0_scb4_uart_rx { + pinmux = ; + }; + /omit-if-no-ref/ p8_0_scb4_uart_rx: p8_0_scb4_uart_rx { + pinmux = ; + }; + /omit-if-no-ref/ p8_4_scb11_uart_rx: p8_4_scb11_uart_rx { + pinmux = ; + }; + /omit-if-no-ref/ p9_0_scb2_uart_rx: p9_0_scb2_uart_rx { + pinmux = ; + }; + /omit-if-no-ref/ p10_0_scb1_uart_rx: p10_0_scb1_uart_rx { + pinmux = ; + }; + /omit-if-no-ref/ p11_0_scb5_uart_rx: p11_0_scb5_uart_rx { + pinmux = ; + }; + /omit-if-no-ref/ p12_0_scb6_uart_rx: p12_0_scb6_uart_rx { + pinmux = ; + }; + /omit-if-no-ref/ p13_0_scb6_uart_rx: p13_0_scb6_uart_rx { + pinmux = ; + }; + /omit-if-no-ref/ p13_4_scb12_uart_rx: p13_4_scb12_uart_rx { + pinmux = ; + }; + + /* scb_uart_tx */ + /omit-if-no-ref/ p0_3_scb0_uart_tx: p0_3_scb0_uart_tx { + pinmux = ; + }; + /omit-if-no-ref/ p1_1_scb7_uart_tx: p1_1_scb7_uart_tx { + pinmux = ; + }; + /omit-if-no-ref/ p2_1_scb1_uart_tx: p2_1_scb1_uart_tx { + pinmux = ; + }; + /omit-if-no-ref/ p2_5_scb9_uart_tx: p2_5_scb9_uart_tx { + pinmux = ; + }; + /omit-if-no-ref/ p3_1_scb2_uart_tx: p3_1_scb2_uart_tx { + pinmux = ; + }; + /omit-if-no-ref/ p4_1_scb7_uart_tx: p4_1_scb7_uart_tx { + pinmux = ; + }; + /omit-if-no-ref/ p5_1_scb5_uart_tx: p5_1_scb5_uart_tx { + pinmux = ; + }; + /omit-if-no-ref/ p5_5_scb10_uart_tx: p5_5_scb10_uart_tx { + pinmux = ; + }; + /omit-if-no-ref/ p6_1_scb3_uart_tx: p6_1_scb3_uart_tx { + pinmux = ; + }; + /omit-if-no-ref/ p6_5_scb6_uart_tx: p6_5_scb6_uart_tx { + pinmux = ; + }; + /omit-if-no-ref/ p7_1_scb4_uart_tx: p7_1_scb4_uart_tx { + pinmux = ; + }; + /omit-if-no-ref/ p8_1_scb4_uart_tx: p8_1_scb4_uart_tx { + pinmux = ; + }; + /omit-if-no-ref/ p8_5_scb11_uart_tx: p8_5_scb11_uart_tx { + pinmux = ; + }; + /omit-if-no-ref/ p9_1_scb2_uart_tx: p9_1_scb2_uart_tx { + pinmux = ; + }; + /omit-if-no-ref/ p10_1_scb1_uart_tx: p10_1_scb1_uart_tx { + pinmux = ; + }; + /omit-if-no-ref/ p11_1_scb5_uart_tx: p11_1_scb5_uart_tx { + pinmux = ; + }; + /omit-if-no-ref/ p12_1_scb6_uart_tx: p12_1_scb6_uart_tx { + pinmux = ; + }; + /omit-if-no-ref/ p13_1_scb6_uart_tx: p13_1_scb6_uart_tx { + pinmux = ; + }; + /omit-if-no-ref/ p13_5_scb12_uart_tx: p13_5_scb12_uart_tx { + pinmux = ; + }; + + /* tcpwm_line */ + /omit-if-no-ref/ p0_0_tcpwm0_line: p0_0_tcpwm0_line { + pinmux = ; + }; + /omit-if-no-ref/ p0_0_tcpwm1_line: p0_0_tcpwm1_line { + pinmux = ; + }; + /omit-if-no-ref/ p0_2_tcpwm0_line: p0_2_tcpwm0_line { + pinmux = ; + }; + /omit-if-no-ref/ p0_2_tcpwm1_line: p0_2_tcpwm1_line { + pinmux = ; + }; + /omit-if-no-ref/ p0_4_tcpwm0_line: p0_4_tcpwm0_line { + pinmux = ; + }; + /omit-if-no-ref/ p0_4_tcpwm1_line: p0_4_tcpwm1_line { + pinmux = ; + }; + /omit-if-no-ref/ p1_0_tcpwm0_line: p1_0_tcpwm0_line { + pinmux = ; + }; + /omit-if-no-ref/ p1_0_tcpwm1_line: p1_0_tcpwm1_line { + pinmux = ; + }; + /omit-if-no-ref/ p1_2_tcpwm0_line: p1_2_tcpwm0_line { + pinmux = ; + }; + /omit-if-no-ref/ p1_2_tcpwm1_line: p1_2_tcpwm1_line { + pinmux = ; + }; + /omit-if-no-ref/ p1_4_tcpwm0_line: p1_4_tcpwm0_line { + pinmux = ; + }; + /omit-if-no-ref/ p1_4_tcpwm1_line: p1_4_tcpwm1_line { + pinmux = ; + }; + /omit-if-no-ref/ p2_0_tcpwm0_line: p2_0_tcpwm0_line { + pinmux = ; + }; + /omit-if-no-ref/ p2_0_tcpwm1_line: p2_0_tcpwm1_line { + pinmux = ; + }; + /omit-if-no-ref/ p2_2_tcpwm0_line: p2_2_tcpwm0_line { + pinmux = ; + }; + /omit-if-no-ref/ p2_2_tcpwm1_line: p2_2_tcpwm1_line { + pinmux = ; + }; + /omit-if-no-ref/ p2_4_tcpwm0_line: p2_4_tcpwm0_line { + pinmux = ; + }; + /omit-if-no-ref/ p2_4_tcpwm1_line: p2_4_tcpwm1_line { + pinmux = ; + }; + /omit-if-no-ref/ p2_6_tcpwm0_line: p2_6_tcpwm0_line { + pinmux = ; + }; + /omit-if-no-ref/ p2_6_tcpwm1_line: p2_6_tcpwm1_line { + pinmux = ; + }; + /omit-if-no-ref/ p3_0_tcpwm0_line: p3_0_tcpwm0_line { + pinmux = ; + }; + /omit-if-no-ref/ p3_0_tcpwm1_line: p3_0_tcpwm1_line { + pinmux = ; + }; + /omit-if-no-ref/ p3_2_tcpwm0_line: p3_2_tcpwm0_line { + pinmux = ; + }; + /omit-if-no-ref/ p3_2_tcpwm1_line: p3_2_tcpwm1_line { + pinmux = ; + }; + /omit-if-no-ref/ p3_4_tcpwm0_line: p3_4_tcpwm0_line { + pinmux = ; + }; + /omit-if-no-ref/ p3_4_tcpwm1_line: p3_4_tcpwm1_line { + pinmux = ; + }; + /omit-if-no-ref/ p4_0_tcpwm0_line: p4_0_tcpwm0_line { + pinmux = ; + }; + /omit-if-no-ref/ p4_0_tcpwm1_line: p4_0_tcpwm1_line { + pinmux = ; + }; + /omit-if-no-ref/ p5_0_tcpwm0_line: p5_0_tcpwm0_line { + pinmux = ; + }; + /omit-if-no-ref/ p5_0_tcpwm1_line: p5_0_tcpwm1_line { + pinmux = ; + }; + /omit-if-no-ref/ p5_2_tcpwm0_line: p5_2_tcpwm0_line { + pinmux = ; + }; + /omit-if-no-ref/ p5_2_tcpwm1_line: p5_2_tcpwm1_line { + pinmux = ; + }; + /omit-if-no-ref/ p5_4_tcpwm0_line: p5_4_tcpwm0_line { + pinmux = ; + }; + /omit-if-no-ref/ p5_4_tcpwm1_line: p5_4_tcpwm1_line { + pinmux = ; + }; + /omit-if-no-ref/ p5_6_tcpwm0_line: p5_6_tcpwm0_line { + pinmux = ; + }; + /omit-if-no-ref/ p5_6_tcpwm1_line: p5_6_tcpwm1_line { + pinmux = ; + }; + /omit-if-no-ref/ p6_0_tcpwm0_line: p6_0_tcpwm0_line { + pinmux = ; + }; + /omit-if-no-ref/ p6_0_tcpwm1_line: p6_0_tcpwm1_line { + pinmux = ; + }; + /omit-if-no-ref/ p6_2_tcpwm0_line: p6_2_tcpwm0_line { + pinmux = ; + }; + /omit-if-no-ref/ p6_2_tcpwm1_line: p6_2_tcpwm1_line { + pinmux = ; + }; + /omit-if-no-ref/ p6_4_tcpwm0_line: p6_4_tcpwm0_line { + pinmux = ; + }; + /omit-if-no-ref/ p6_4_tcpwm1_line: p6_4_tcpwm1_line { + pinmux = ; + }; + /omit-if-no-ref/ p6_6_tcpwm0_line: p6_6_tcpwm0_line { + pinmux = ; + }; + /omit-if-no-ref/ p6_6_tcpwm1_line: p6_6_tcpwm1_line { + pinmux = ; + }; + /omit-if-no-ref/ p7_0_tcpwm0_line: p7_0_tcpwm0_line { + pinmux = ; + }; + /omit-if-no-ref/ p7_0_tcpwm1_line: p7_0_tcpwm1_line { + pinmux = ; + }; + /omit-if-no-ref/ p7_2_tcpwm0_line: p7_2_tcpwm0_line { + pinmux = ; + }; + /omit-if-no-ref/ p7_2_tcpwm1_line: p7_2_tcpwm1_line { + pinmux = ; + }; + /omit-if-no-ref/ p7_4_tcpwm0_line: p7_4_tcpwm0_line { + pinmux = ; + }; + /omit-if-no-ref/ p7_4_tcpwm1_line: p7_4_tcpwm1_line { + pinmux = ; + }; + /omit-if-no-ref/ p7_6_tcpwm0_line: p7_6_tcpwm0_line { + pinmux = ; + }; + /omit-if-no-ref/ p7_6_tcpwm1_line: p7_6_tcpwm1_line { + pinmux = ; + }; + /omit-if-no-ref/ p8_0_tcpwm0_line: p8_0_tcpwm0_line { + pinmux = ; + }; + /omit-if-no-ref/ p8_0_tcpwm1_line: p8_0_tcpwm1_line { + pinmux = ; + }; + /omit-if-no-ref/ p8_2_tcpwm0_line: p8_2_tcpwm0_line { + pinmux = ; + }; + /omit-if-no-ref/ p8_2_tcpwm1_line: p8_2_tcpwm1_line { + pinmux = ; + }; + /omit-if-no-ref/ p8_4_tcpwm0_line: p8_4_tcpwm0_line { + pinmux = ; + }; + /omit-if-no-ref/ p8_4_tcpwm1_line: p8_4_tcpwm1_line { + pinmux = ; + }; + /omit-if-no-ref/ p8_6_tcpwm0_line: p8_6_tcpwm0_line { + pinmux = ; + }; + /omit-if-no-ref/ p8_6_tcpwm1_line: p8_6_tcpwm1_line { + pinmux = ; + }; + /omit-if-no-ref/ p9_0_tcpwm0_line: p9_0_tcpwm0_line { + pinmux = ; + }; + /omit-if-no-ref/ p9_0_tcpwm1_line: p9_0_tcpwm1_line { + pinmux = ; + }; + /omit-if-no-ref/ p9_2_tcpwm0_line: p9_2_tcpwm0_line { + pinmux = ; + }; + /omit-if-no-ref/ p9_2_tcpwm1_line: p9_2_tcpwm1_line { + pinmux = ; + }; + /omit-if-no-ref/ p9_4_tcpwm0_line: p9_4_tcpwm0_line { + pinmux = ; + }; + /omit-if-no-ref/ p9_4_tcpwm1_line: p9_4_tcpwm1_line { + pinmux = ; + }; + /omit-if-no-ref/ p9_6_tcpwm0_line: p9_6_tcpwm0_line { + pinmux = ; + }; + /omit-if-no-ref/ p9_6_tcpwm1_line: p9_6_tcpwm1_line { + pinmux = ; + }; + /omit-if-no-ref/ p10_0_tcpwm0_line: p10_0_tcpwm0_line { + pinmux = ; + }; + /omit-if-no-ref/ p10_0_tcpwm1_line: p10_0_tcpwm1_line { + pinmux = ; + }; + /omit-if-no-ref/ p10_2_tcpwm0_line: p10_2_tcpwm0_line { + pinmux = ; + }; + /omit-if-no-ref/ p10_2_tcpwm1_line: p10_2_tcpwm1_line { + pinmux = ; + }; + /omit-if-no-ref/ p10_4_tcpwm0_line: p10_4_tcpwm0_line { + pinmux = ; + }; + /omit-if-no-ref/ p10_4_tcpwm1_line: p10_4_tcpwm1_line { + pinmux = ; + }; + /omit-if-no-ref/ p10_6_tcpwm0_line: p10_6_tcpwm0_line { + pinmux = ; + }; + /omit-if-no-ref/ p10_6_tcpwm1_line: p10_6_tcpwm1_line { + pinmux = ; + }; + /omit-if-no-ref/ p11_0_tcpwm0_line: p11_0_tcpwm0_line { + pinmux = ; + }; + /omit-if-no-ref/ p11_0_tcpwm1_line: p11_0_tcpwm1_line { + pinmux = ; + }; + /omit-if-no-ref/ p11_2_tcpwm0_line: p11_2_tcpwm0_line { + pinmux = ; + }; + /omit-if-no-ref/ p11_2_tcpwm1_line: p11_2_tcpwm1_line { + pinmux = ; + }; + /omit-if-no-ref/ p11_4_tcpwm0_line: p11_4_tcpwm0_line { + pinmux = ; + }; + /omit-if-no-ref/ p11_4_tcpwm1_line: p11_4_tcpwm1_line { + pinmux = ; + }; + /omit-if-no-ref/ p12_0_tcpwm0_line: p12_0_tcpwm0_line { + pinmux = ; + }; + /omit-if-no-ref/ p12_0_tcpwm1_line: p12_0_tcpwm1_line { + pinmux = ; + }; + /omit-if-no-ref/ p12_2_tcpwm0_line: p12_2_tcpwm0_line { + pinmux = ; + }; + /omit-if-no-ref/ p12_2_tcpwm1_line: p12_2_tcpwm1_line { + pinmux = ; + }; + /omit-if-no-ref/ p12_4_tcpwm0_line: p12_4_tcpwm0_line { + pinmux = ; + }; + /omit-if-no-ref/ p12_4_tcpwm1_line: p12_4_tcpwm1_line { + pinmux = ; + }; + /omit-if-no-ref/ p12_6_tcpwm0_line: p12_6_tcpwm0_line { + pinmux = ; + }; + /omit-if-no-ref/ p12_6_tcpwm1_line: p12_6_tcpwm1_line { + pinmux = ; + }; + /omit-if-no-ref/ p13_0_tcpwm0_line: p13_0_tcpwm0_line { + pinmux = ; + }; + /omit-if-no-ref/ p13_0_tcpwm1_line: p13_0_tcpwm1_line { + pinmux = ; + }; + /omit-if-no-ref/ p13_2_tcpwm0_line: p13_2_tcpwm0_line { + pinmux = ; + }; + /omit-if-no-ref/ p13_2_tcpwm1_line: p13_2_tcpwm1_line { + pinmux = ; + }; + /omit-if-no-ref/ p13_4_tcpwm0_line: p13_4_tcpwm0_line { + pinmux = ; + }; + /omit-if-no-ref/ p13_4_tcpwm1_line: p13_4_tcpwm1_line { + pinmux = ; + }; + /omit-if-no-ref/ p13_6_tcpwm0_line: p13_6_tcpwm0_line { + pinmux = ; + }; + /omit-if-no-ref/ p13_6_tcpwm1_line: p13_6_tcpwm1_line { + pinmux = ; + }; + + /* tcpwm_line_compl */ + /omit-if-no-ref/ p0_1_tcpwm0_line_compl: p0_1_tcpwm0_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p0_1_tcpwm1_line_compl: p0_1_tcpwm1_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p0_3_tcpwm0_line_compl: p0_3_tcpwm0_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p0_3_tcpwm1_line_compl: p0_3_tcpwm1_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p0_5_tcpwm0_line_compl: p0_5_tcpwm0_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p0_5_tcpwm1_line_compl: p0_5_tcpwm1_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p1_1_tcpwm0_line_compl: p1_1_tcpwm0_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p1_1_tcpwm1_line_compl: p1_1_tcpwm1_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p1_3_tcpwm0_line_compl: p1_3_tcpwm0_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p1_3_tcpwm1_line_compl: p1_3_tcpwm1_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p1_5_tcpwm0_line_compl: p1_5_tcpwm0_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p1_5_tcpwm1_line_compl: p1_5_tcpwm1_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p2_1_tcpwm0_line_compl: p2_1_tcpwm0_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p2_1_tcpwm1_line_compl: p2_1_tcpwm1_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p2_3_tcpwm0_line_compl: p2_3_tcpwm0_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p2_3_tcpwm1_line_compl: p2_3_tcpwm1_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p2_5_tcpwm0_line_compl: p2_5_tcpwm0_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p2_5_tcpwm1_line_compl: p2_5_tcpwm1_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p2_7_tcpwm0_line_compl: p2_7_tcpwm0_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p2_7_tcpwm1_line_compl: p2_7_tcpwm1_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p3_1_tcpwm0_line_compl: p3_1_tcpwm0_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p3_1_tcpwm1_line_compl: p3_1_tcpwm1_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p3_3_tcpwm0_line_compl: p3_3_tcpwm0_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p3_3_tcpwm1_line_compl: p3_3_tcpwm1_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p3_5_tcpwm0_line_compl: p3_5_tcpwm0_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p3_5_tcpwm1_line_compl: p3_5_tcpwm1_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p4_1_tcpwm0_line_compl: p4_1_tcpwm0_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p4_1_tcpwm1_line_compl: p4_1_tcpwm1_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p5_1_tcpwm0_line_compl: p5_1_tcpwm0_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p5_1_tcpwm1_line_compl: p5_1_tcpwm1_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p5_3_tcpwm0_line_compl: p5_3_tcpwm0_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p5_3_tcpwm1_line_compl: p5_3_tcpwm1_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p5_5_tcpwm0_line_compl: p5_5_tcpwm0_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p5_5_tcpwm1_line_compl: p5_5_tcpwm1_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p5_7_tcpwm0_line_compl: p5_7_tcpwm0_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p5_7_tcpwm1_line_compl: p5_7_tcpwm1_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p6_1_tcpwm0_line_compl: p6_1_tcpwm0_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p6_1_tcpwm1_line_compl: p6_1_tcpwm1_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p6_3_tcpwm0_line_compl: p6_3_tcpwm0_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p6_3_tcpwm1_line_compl: p6_3_tcpwm1_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p6_5_tcpwm0_line_compl: p6_5_tcpwm0_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p6_5_tcpwm1_line_compl: p6_5_tcpwm1_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p6_7_tcpwm0_line_compl: p6_7_tcpwm0_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p6_7_tcpwm1_line_compl: p6_7_tcpwm1_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p7_1_tcpwm0_line_compl: p7_1_tcpwm0_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p7_1_tcpwm1_line_compl: p7_1_tcpwm1_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p7_3_tcpwm0_line_compl: p7_3_tcpwm0_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p7_3_tcpwm1_line_compl: p7_3_tcpwm1_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p7_5_tcpwm0_line_compl: p7_5_tcpwm0_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p7_5_tcpwm1_line_compl: p7_5_tcpwm1_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p7_7_tcpwm0_line_compl: p7_7_tcpwm0_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p7_7_tcpwm1_line_compl: p7_7_tcpwm1_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p8_1_tcpwm0_line_compl: p8_1_tcpwm0_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p8_1_tcpwm1_line_compl: p8_1_tcpwm1_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p8_3_tcpwm0_line_compl: p8_3_tcpwm0_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p8_3_tcpwm1_line_compl: p8_3_tcpwm1_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p8_5_tcpwm0_line_compl: p8_5_tcpwm0_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p8_5_tcpwm1_line_compl: p8_5_tcpwm1_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p8_7_tcpwm0_line_compl: p8_7_tcpwm0_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p8_7_tcpwm1_line_compl: p8_7_tcpwm1_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p9_1_tcpwm0_line_compl: p9_1_tcpwm0_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p9_1_tcpwm1_line_compl: p9_1_tcpwm1_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p9_3_tcpwm0_line_compl: p9_3_tcpwm0_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p9_3_tcpwm1_line_compl: p9_3_tcpwm1_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p9_5_tcpwm0_line_compl: p9_5_tcpwm0_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p9_5_tcpwm1_line_compl: p9_5_tcpwm1_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p9_7_tcpwm0_line_compl: p9_7_tcpwm0_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p9_7_tcpwm1_line_compl: p9_7_tcpwm1_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p10_1_tcpwm0_line_compl: p10_1_tcpwm0_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p10_1_tcpwm1_line_compl: p10_1_tcpwm1_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p10_3_tcpwm0_line_compl: p10_3_tcpwm0_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p10_3_tcpwm1_line_compl: p10_3_tcpwm1_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p10_5_tcpwm0_line_compl: p10_5_tcpwm0_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p10_5_tcpwm1_line_compl: p10_5_tcpwm1_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p10_7_tcpwm0_line_compl: p10_7_tcpwm0_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p10_7_tcpwm1_line_compl: p10_7_tcpwm1_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p11_1_tcpwm0_line_compl: p11_1_tcpwm0_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p11_1_tcpwm1_line_compl: p11_1_tcpwm1_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p11_3_tcpwm0_line_compl: p11_3_tcpwm0_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p11_3_tcpwm1_line_compl: p11_3_tcpwm1_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p11_5_tcpwm0_line_compl: p11_5_tcpwm0_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p11_5_tcpwm1_line_compl: p11_5_tcpwm1_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p12_1_tcpwm0_line_compl: p12_1_tcpwm0_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p12_1_tcpwm1_line_compl: p12_1_tcpwm1_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p12_3_tcpwm0_line_compl: p12_3_tcpwm0_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p12_3_tcpwm1_line_compl: p12_3_tcpwm1_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p12_5_tcpwm0_line_compl: p12_5_tcpwm0_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p12_5_tcpwm1_line_compl: p12_5_tcpwm1_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p12_7_tcpwm0_line_compl: p12_7_tcpwm0_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p12_7_tcpwm1_line_compl: p12_7_tcpwm1_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p13_1_tcpwm0_line_compl: p13_1_tcpwm0_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p13_1_tcpwm1_line_compl: p13_1_tcpwm1_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p13_3_tcpwm0_line_compl: p13_3_tcpwm0_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p13_3_tcpwm1_line_compl: p13_3_tcpwm1_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p13_5_tcpwm0_line_compl: p13_5_tcpwm0_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p13_5_tcpwm1_line_compl: p13_5_tcpwm1_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p13_7_tcpwm0_line_compl: p13_7_tcpwm0_line_compl { + pinmux = ; + }; + /omit-if-no-ref/ p13_7_tcpwm1_line_compl: p13_7_tcpwm1_line_compl { + pinmux = ; + }; + + }; + }; +}; diff --git a/dts/arm/infineon/psoc6/psoc6_02/psoc6_02.128-tqfp.dtsi b/dts/arm/infineon/cat1a/psoc6_02/psoc6_02.128-tqfp.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/psoc6_02/psoc6_02.128-tqfp.dtsi rename to dts/arm/infineon/cat1a/psoc6_02/psoc6_02.128-tqfp.dtsi diff --git a/dts/arm/infineon/psoc6/psoc6_02/psoc6_02.68-qfn.dtsi b/dts/arm/infineon/cat1a/psoc6_02/psoc6_02.68-qfn.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/psoc6_02/psoc6_02.68-qfn.dtsi rename to dts/arm/infineon/cat1a/psoc6_02/psoc6_02.68-qfn.dtsi diff --git a/dts/arm/infineon/psoc6/psoc6_02/psoc6_02.dtsi b/dts/arm/infineon/cat1a/psoc6_02/psoc6_02.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/psoc6_02/psoc6_02.dtsi rename to dts/arm/infineon/cat1a/psoc6_02/psoc6_02.dtsi diff --git a/dts/arm/infineon/psoc6/psoc6_03/psoc6_03.100-tqfp.dtsi b/dts/arm/infineon/cat1a/psoc6_03/psoc6_03.100-tqfp.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/psoc6_03/psoc6_03.100-tqfp.dtsi rename to dts/arm/infineon/cat1a/psoc6_03/psoc6_03.100-tqfp.dtsi diff --git a/dts/arm/infineon/psoc6/psoc6_03/psoc6_03.49-wlcsp.dtsi b/dts/arm/infineon/cat1a/psoc6_03/psoc6_03.49-wlcsp.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/psoc6_03/psoc6_03.49-wlcsp.dtsi rename to dts/arm/infineon/cat1a/psoc6_03/psoc6_03.49-wlcsp.dtsi diff --git a/dts/arm/infineon/psoc6/psoc6_03/psoc6_03.68-qfn.dtsi b/dts/arm/infineon/cat1a/psoc6_03/psoc6_03.68-qfn.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/psoc6_03/psoc6_03.68-qfn.dtsi rename to dts/arm/infineon/cat1a/psoc6_03/psoc6_03.68-qfn.dtsi diff --git a/dts/arm/infineon/psoc6/psoc6_03/psoc6_03.dtsi b/dts/arm/infineon/cat1a/psoc6_03/psoc6_03.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/psoc6_03/psoc6_03.dtsi rename to dts/arm/infineon/cat1a/psoc6_03/psoc6_03.dtsi diff --git a/dts/arm/infineon/psoc6/psoc6_04/psoc6_04.64-tqfp-epad.dtsi b/dts/arm/infineon/cat1a/psoc6_04/psoc6_04.64-tqfp-epad.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/psoc6_04/psoc6_04.64-tqfp-epad.dtsi rename to dts/arm/infineon/cat1a/psoc6_04/psoc6_04.64-tqfp-epad.dtsi diff --git a/dts/arm/infineon/psoc6/psoc6_04/psoc6_04.68-qfn.dtsi b/dts/arm/infineon/cat1a/psoc6_04/psoc6_04.68-qfn.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/psoc6_04/psoc6_04.68-qfn.dtsi rename to dts/arm/infineon/cat1a/psoc6_04/psoc6_04.68-qfn.dtsi diff --git a/dts/arm/infineon/psoc6/psoc6_04/psoc6_04.80-tqfp.dtsi b/dts/arm/infineon/cat1a/psoc6_04/psoc6_04.80-tqfp.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/psoc6_04/psoc6_04.80-tqfp.dtsi rename to dts/arm/infineon/cat1a/psoc6_04/psoc6_04.80-tqfp.dtsi diff --git a/dts/arm/infineon/psoc6/psoc6_04/psoc6_04.dtsi b/dts/arm/infineon/cat1a/psoc6_04/psoc6_04.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/psoc6_04/psoc6_04.dtsi rename to dts/arm/infineon/cat1a/psoc6_04/psoc6_04.dtsi diff --git a/dts/arm/infineon/psoc6/system_clocks.dtsi b/dts/arm/infineon/cat1a/system_clocks.dtsi similarity index 100% rename from dts/arm/infineon/psoc6/system_clocks.dtsi rename to dts/arm/infineon/cat1a/system_clocks.dtsi diff --git a/dts/arm/infineon/xmc4500_F100x1024-intc.dtsi b/dts/arm/infineon/cat3/xmc/xmc4500_F100x1024-intc.dtsi similarity index 100% rename from dts/arm/infineon/xmc4500_F100x1024-intc.dtsi rename to dts/arm/infineon/cat3/xmc/xmc4500_F100x1024-intc.dtsi diff --git a/dts/arm/infineon/xmc4500_F100x1024-pinctrl.dtsi b/dts/arm/infineon/cat3/xmc/xmc4500_F100x1024-pinctrl.dtsi similarity index 99% rename from dts/arm/infineon/xmc4500_F100x1024-pinctrl.dtsi rename to dts/arm/infineon/cat3/xmc/xmc4500_F100x1024-pinctrl.dtsi index 4506e0c995f..d5eb1ba0039 100644 --- a/dts/arm/infineon/xmc4500_F100x1024-pinctrl.dtsi +++ b/dts/arm/infineon/cat3/xmc/xmc4500_F100x1024-pinctrl.dtsi @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include #include &pinctrl { diff --git a/dts/arm/infineon/xmc4500_F100x1024.dtsi b/dts/arm/infineon/cat3/xmc/xmc4500_F100x1024.dtsi similarity index 97% rename from dts/arm/infineon/xmc4500_F100x1024.dtsi rename to dts/arm/infineon/cat3/xmc/xmc4500_F100x1024.dtsi index d368e397ea3..ff64b9bd9c1 100644 --- a/dts/arm/infineon/xmc4500_F100x1024.dtsi +++ b/dts/arm/infineon/cat3/xmc/xmc4500_F100x1024.dtsi @@ -6,7 +6,7 @@ */ #include -#include +#include / { psram1: memory@10000000 { diff --git a/dts/arm/infineon/xmc4700_F144x2048-intc.dtsi b/dts/arm/infineon/cat3/xmc/xmc4700_F144x2048-intc.dtsi similarity index 100% rename from dts/arm/infineon/xmc4700_F144x2048-intc.dtsi rename to dts/arm/infineon/cat3/xmc/xmc4700_F144x2048-intc.dtsi diff --git a/dts/arm/infineon/xmc4700_F144x2048-pinctrl.dtsi b/dts/arm/infineon/cat3/xmc/xmc4700_F144x2048-pinctrl.dtsi similarity index 99% rename from dts/arm/infineon/xmc4700_F144x2048-pinctrl.dtsi rename to dts/arm/infineon/cat3/xmc/xmc4700_F144x2048-pinctrl.dtsi index e6bab488049..b40ba24a8a5 100644 --- a/dts/arm/infineon/xmc4700_F144x2048-pinctrl.dtsi +++ b/dts/arm/infineon/cat3/xmc/xmc4700_F144x2048-pinctrl.dtsi @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include #include &pinctrl { diff --git a/dts/arm/infineon/xmc4700_F144x2048.dtsi b/dts/arm/infineon/cat3/xmc/xmc4700_F144x2048.dtsi similarity index 98% rename from dts/arm/infineon/xmc4700_F144x2048.dtsi rename to dts/arm/infineon/cat3/xmc/xmc4700_F144x2048.dtsi index ad8e1ea6413..7a1d6f4db6e 100644 --- a/dts/arm/infineon/xmc4700_F144x2048.dtsi +++ b/dts/arm/infineon/cat3/xmc/xmc4700_F144x2048.dtsi @@ -5,7 +5,7 @@ */ #include -#include +#include / { psram1: memory@1ffe8000 { diff --git a/dts/arm/infineon/xmc4xxx.dtsi b/dts/arm/infineon/cat3/xmc/xmc4xxx.dtsi similarity index 100% rename from dts/arm/infineon/xmc4xxx.dtsi rename to dts/arm/infineon/cat3/xmc/xmc4xxx.dtsi diff --git a/dts/arm/intel_socfpga_std/socfpga.dtsi b/dts/arm/intel_socfpga_std/socfpga.dtsi index 7e1f37267d5..ad36609bfa1 100644 --- a/dts/arm/intel_socfpga_std/socfpga.dtsi +++ b/dts/arm/intel_socfpga_std/socfpga.dtsi @@ -227,6 +227,11 @@ reg = <0xffb30000 0xffff>; interrupts = <0 127 4 IRQ_DEFAULT_PRIORITY>; interrupt-parent = <&intc>; + num-out-eps = <16>; + num-in-eps = <16>; + ghwcfg1 = <0x00000000>; + ghwcfg2 = <0x208ffc90>; + ghwcfg4 = <0xfe0f0020>; status = "disabled"; }; @@ -235,6 +240,11 @@ reg = <0xffb40000 0xffff>; interrupts = <0 128 4 IRQ_DEFAULT_PRIORITY>; interrupt-parent = <&intc>; + num-out-eps = <16>; + num-in-eps = <16>; + ghwcfg1 = <0x00000000>; + ghwcfg2 = <0x208ffc90>; + ghwcfg4 = <0xfe0f0020>; status = "okay"; }; diff --git a/dts/arm/microchip/mec172x/mec172x-vw-routing.dtsi b/dts/arm/microchip/mec172x/mec172x-vw-routing.dtsi index a9ed8e01d96..5c3dfddbd14 100644 --- a/dts/arm/microchip/mec172x/mec172x-vw-routing.dtsi +++ b/dts/arm/microchip/mec172x/mec172x-vw-routing.dtsi @@ -107,7 +107,7 @@ vw-reg = <0x04 SMVW 0 3>; status = "okay"; }; - vw_slave_boot_done: vw_slave_boot_done { + vw_target_boot_done: vw_target_boot_done { vw-reg = <0x05 SMVW 1 0>; status = "okay"; }; @@ -119,7 +119,7 @@ vw-reg = <0x05 SMVW 1 2>; status = "okay"; }; - vw_slave_boot_status: vw_slave_boot_status { + vw_target_boot_status: vw_target_boot_status { vw-reg = <0x05 SMVW 1 3>; status = "okay"; }; diff --git a/dts/arm/nordic/nrf54h20_cpurad.dtsi b/dts/arm/nordic/nrf54h20_cpurad.dtsi index e4a7469dac5..b426d660f3d 100644 --- a/dts/arm/nordic/nrf54h20_cpurad.dtsi +++ b/dts/arm/nordic/nrf54h20_cpurad.dtsi @@ -50,7 +50,7 @@ wdt011: &cpurad_wdt011 {}; }; &grtc { - owned-channels = <7 8 9 10 11 12 13 14>; + owned-channels = <7 8 9 10 11 12 13 14 15>; child-owned-channels = <8 9 10 11 12>; nonsecure-channels = <8 9 10 11 12>; interrupts = <109 NRF_DEFAULT_IRQ_PRIORITY>, diff --git a/dts/arm/nordic/nrf54l15_cpuapp.dtsi b/dts/arm/nordic/nrf54l15_cpuapp.dtsi index df4ccc52294..1ba55fd8d00 100644 --- a/dts/arm/nordic/nrf54l15_cpuapp.dtsi +++ b/dts/arm/nordic/nrf54l15_cpuapp.dtsi @@ -4,88 +4,49 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include -#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 = ; - }; - }; - }; +cpu: &cpuapp {}; +systick: &cpuapp_systick {}; +nvic: &cpuapp_nvic {}; +cpuflpr_vevif: &cpuflpr_vevif_remote {}; - clocks { - lfxo: lfxo { - compatible = "nordic,nrf-lfxo"; - #clock-cells = <0>; - clock-frequency = <32768>; - }; - - hfxo: hfxo { - compatible = "nordic,nrf-hfxo"; - #clock-cells = <0>; - clock-frequency = ; - }; - }; +/delete-node/ &cpuflpr; +/delete-node/ &cpuflpr_rram; +/delete-node/ &cpuflpr_sram; +/delete-node/ &cpuflpr_clic; +/ { soc { - uicr: uicr@ffd000 { - compatible = "nordic,nrf-uicr"; - reg = <0xffd000 0x1000>; - }; - - ficr: ficr@ffc000 { - compatible = "nordic,nrf-ficr"; - reg = <0xffc000 0x1000>; - #nordic,ficr-cells = <1>; - }; - - sram0: memory@20000000 { - compatible = "mmio-sram"; - reg = <0x20000000 DT_SIZE_K(256)>; - }; + compatible = "simple-bus"; + interrupt-parent = <&cpuapp_nvic>; + ranges; + }; - peripheral@50000000 { - #address-cells = <1>; - #size-cells = <1>; - ranges = <0x0 0x50000000 0x10000000>; + chosen { + zephyr,entropy = &psa_rng; + }; - /* Common nRF54L15 peripheral description */ - #include "nrf54l15_cpuapp_peripherals.dtsi" - }; + psa_rng: psa-rng { + compatible = "zephyr,psa-crypto-rng"; + status = "okay"; }; }; -&nvic { - arm,num-irq-priority-bits = <3>; +&cpuapp_ppb { + compatible = "simple-bus"; + ranges; }; -&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)>; - }; +&grtc { + interrupts = <228 NRF_DEFAULT_IRQ_PRIORITY>, + <229 NRF_DEFAULT_IRQ_PRIORITY>; /* reserved for Zero Latency IRQs */ +}; + +&gpiote20 { + interrupts = <219 NRF_DEFAULT_IRQ_PRIORITY>; }; -/* Disable by default to use GRTC */ -&systick { - status = "disabled"; +&gpiote30 { + interrupts = <269 NRF_DEFAULT_IRQ_PRIORITY>; }; diff --git a/dts/arm/nordic/nrf54l15_cpuapp_peripherals.dtsi b/dts/arm/nordic/nrf54l15_cpuapp_peripherals.dtsi deleted file mode 100644 index 3e4d3641069..00000000000 --- a/dts/arm/nordic/nrf54l15_cpuapp_peripherals.dtsi +++ /dev/null @@ -1,452 +0,0 @@ -/* - * 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>; - rx-delay-supported; - rx-delay = <1>; - 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>; - easydma-maxcnt-bits = <16>; - 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>; - rx-delay-supported; - rx-delay = <1>; - 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>; - easydma-maxcnt-bits = <16>; - 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>; - rx-delay-supported; - rx-delay = <1>; - 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>; - easydma-maxcnt-bits = <16>; - 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>; - rx-delay-supported; - rx-delay = <1>; - 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>; -}; - -pwm20: pwm@d2000 { - compatible = "nordic,nrf-pwm"; - status = "disabled"; - reg = <0xd2000 0x1000>; - interrupts = <210 NRF_DEFAULT_IRQ_PRIORITY>; - #pwm-cells = <3>; -}; - -pwm21: pwm@d3000 { - compatible = "nordic,nrf-pwm"; - status = "disabled"; - reg = <0xd3000 0x1000>; - interrupts = <211 NRF_DEFAULT_IRQ_PRIORITY>; - #pwm-cells = <3>; -}; - -pwm22: pwm@d4000 { - compatible = "nordic,nrf-pwm"; - status = "disabled"; - reg = <0xd4000 0x1000>; - interrupts = <212 NRF_DEFAULT_IRQ_PRIORITY>; - #pwm-cells = <3>; -}; - -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>; - child-owned-channels = <7 8 9 10 11>; - interrupts = <228 NRF_DEFAULT_IRQ_PRIORITY>, - <229 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>; - easydma-maxcnt-bits = <16>; - 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>; - rx-delay-supported; - rx-delay = <1>; - 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 deleted file mode 100644 index c537554b05b..00000000000 --- a/dts/arm/nordic/nrf54l_common.dtsi +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2024 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include - -/ { - soc { - rram_controller: rram-controller@5004b000 { - compatible = "nordic,rram-controller"; - reg = <0x5004b000 0x1000>; - #address-cells = <1>; - #size-cells = <1>; - interrupts = <75 NRF_DEFAULT_IRQ_PRIORITY>; - rram0: rram@0 { - compatible = "soc-nv-flash"; - erase-block-size = <4096>; - write-block-size = <16>; - }; - }; - }; - - chosen { - zephyr,flash-controller = &rram_controller; - zephyr,entropy = &psa_rng; - }; - - psa_rng: psa-rng { - compatible = "zephyr,psa-crypto-rng"; - status = "okay"; - }; - - sw_pwm: sw-pwm { - generator = <&timer21>; - }; -}; diff --git a/dts/arm/nuvoton/m2l31x.dtsi b/dts/arm/nuvoton/m2l31x.dtsi index 2edad5732b7..3485ea22b95 100644 --- a/dts/arm/nuvoton/m2l31x.dtsi +++ b/dts/arm/nuvoton/m2l31x.dtsi @@ -11,12 +11,17 @@ #include #include #include +#include / { chosen { zephyr,flash-controller = &rmc; }; + aliases { + rtc = &rtc; + }; + cpus { #address-cells = <1>; #size-cells = <0>; @@ -39,6 +44,7 @@ compatible = "nuvoton,numaker-scc"; reg = <0x40000200 0x100>; #clock-cells = <0>; + lxt = "enable"; clk-pclkdiv = <(NUMAKER_CLK_PCLKDIV_APB0DIV_DIV2 | NUMAKER_CLK_PCLKDIV_APB1DIV_DIV2)>; core-clock = ; @@ -306,6 +312,52 @@ #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(2)>; + channels = <31>; + status = "disabled"; + #io-channel-cells = <1>; + }; + + rtc: rtc@40041000 { + compatible = "nuvoton,numaker-rtc"; + reg = <0x40041000 0x138>; + interrupts = <6 0>; + oscillator = "lxt"; + clocks = <&pcc NUMAKER_RTC_MODULE 0 0>; + alarms-count = <1>; + }; + + epwm0: epwm@40058000 { + compatible = "nuvoton,numaker-pwm"; + reg = <0x40058000 0x37c>; + interrupts = <25 0>, <26 0>, <27 0>; + interrupt-names = "pair0", "pair1", "pair2"; + resets = <&rst NUMAKER_EPWM0_RST>; + prescaler = <19>; + clocks = <&pcc NUMAKER_EPWM0_MODULE NUMAKER_CLK_CLKSEL2_EPWM0SEL_PCLK0 0>; + #pwm-cells = <3>; + status = "disabled"; + }; + + epwm1: epwm@40059000 { + compatible = "nuvoton,numaker-pwm"; + reg = <0x40059000 0x37c>; + interrupts = <29 0>, <30 0>, <31 0>; + interrupt-names = "pair0", "pair1", "pair2"; + resets = <&rst NUMAKER_EPWM1_RST>; + prescaler = <19>; + clocks = <&pcc NUMAKER_EPWM1_MODULE NUMAKER_CLK_CLKSEL2_EPWM1SEL_PCLK1 0>; + #pwm-cells = <3>; + status = "disabled"; + }; }; }; diff --git a/dts/arm/nuvoton/m46x.dtsi b/dts/arm/nuvoton/m46x.dtsi index 1d0e15a61d4..f89523c6a81 100644 --- a/dts/arm/nuvoton/m46x.dtsi +++ b/dts/arm/nuvoton/m46x.dtsi @@ -18,6 +18,10 @@ zephyr,flash-controller = &fmc; }; + aliases { + rtc = &rtc; + }; + cpus { #address-cells = <1>; #size-cells = <0>; @@ -46,7 +50,7 @@ reg = <0x40000200 0x100>; #clock-cells = <0>; /* hxt = "enable"; */ - /* lxt = "enable"; */ + lxt = "enable"; clk-pclkdiv = <(NUMAKER_CLK_PCLKDIV_APB0DIV_DIV2 | NUMAKER_CLK_PCLKDIV_APB1DIV_DIV2)>; core-clock = <200000000>; @@ -616,6 +620,15 @@ clocks = <&pcc NUMAKER_WWDT_MODULE NUMAKER_CLK_CLKSEL1_WWDTSEL_LIRC 0>; status = "disabled"; }; + + rtc: rtc@40041000 { + compatible = "nuvoton,numaker-rtc"; + reg = <0x40041000 0x138>; + interrupts = <6 0>; + oscillator = "lxt"; + clocks = <&pcc NUMAKER_RTC_MODULE 0 0>; + alarms-count = <1>; + }; }; }; diff --git a/dts/arm/nuvoton/npcx/npcx4.dtsi b/dts/arm/nuvoton/npcx/npcx4.dtsi index 004ca5332af..c9be91140cd 100644 --- a/dts/arm/nuvoton/npcx/npcx4.dtsi +++ b/dts/arm/nuvoton/npcx/npcx4.dtsi @@ -14,6 +14,8 @@ #include "npcx4/npcx4-espi-vws-map.dtsi" /* npcx4 series low-voltage io controls mapping table */ #include "npcx4/npcx4-lvol-ctrl-map.dtsi" +/* npcx4 series reset mapping table */ +#include "zephyr/dt-bindings/reset/npcx4_reset.h" /* Device tree declarations of npcx soc family */ #include "npcx.dtsi" @@ -74,16 +76,20 @@ uart1: serial@400e0000 { compatible = "nuvoton,npcx-uart"; - reg = <0x400E0000 0x2000>; + /* Index 0: UART1 register, Index 1: MDMA1 register */ + reg = <0x400E0000 0x2000 0x40011100 0x100>; interrupts = <33 3>; - clocks = <&pcc NPCX_CLOCK_BUS_APB4 NPCX_PWDWN_CTL1 4>; + /* Index 0: UART1 clock, Index 1: MDMA1 clock */ + clocks = <&pcc NPCX_CLOCK_BUS_APB4 NPCX_PWDWN_CTL1 4 + &pcc NPCX_CLOCK_BUS_CORE NPCX_PWDWN_CTL9 0>; uart-rx = <&wui_cr_sin1>; status = "disabled"; }; uart2: serial@400e2000 { compatible = "nuvoton,npcx-uart"; - reg = <0x400E2000 0x2000>; + /* Index 0: UART2 register, Index 1: MDMA2 register */ + reg = <0x400E2000 0x2000 0x40011200 0x100>; interrupts = <32 3>; clocks = <&pcc NPCX_CLOCK_BUS_APB4 NPCX_PWDWN_CTL7 6>; uart-rx = <&wui_cr_sin2>; @@ -92,18 +98,24 @@ uart3: serial@400e4000 { compatible = "nuvoton,npcx-uart"; - reg = <0x400E4000 0x2000>; + /* Index 0: UART3 register, Index 1: MDMA3 register */ + reg = <0x400E4000 0x2000 0x40011300 0x100>; interrupts = <38 3>; - clocks = <&pcc NPCX_CLOCK_BUS_APB4 NPCX_PWDWN_CTL7 4>; + /* Index 0: UART3 clock, Index 1: MDMA3 clock */ + clocks = <&pcc NPCX_CLOCK_BUS_APB4 NPCX_PWDWN_CTL7 4 + &pcc NPCX_CLOCK_BUS_CORE NPCX_PWDWN_CTL9 2>; uart-rx = <&wui_cr_sin3>; status = "disabled"; }; uart4: serial@400e6000 { compatible = "nuvoton,npcx-uart"; - reg = <0x400E6000 0x2000>; + /* Index 0: UART4 register, Index 1: MDMA4 register */ + reg = <0x400E6000 0x2000 0x40011400 0x100>; interrupts = <39 3>; - clocks = <&pcc NPCX_CLOCK_BUS_APB4 NPCX_PWDWN_CTL7 3>; + /* Index 0: UART4 clock, Index 1: MDMA4 clock */ + clocks = <&pcc NPCX_CLOCK_BUS_APB4 NPCX_PWDWN_CTL7 3 + &pcc NPCX_CLOCK_BUS_CORE NPCX_PWDWN_CTL9 3>; uart-rx = <&wui_cr_sin4>; status = "disabled"; }; @@ -317,6 +329,88 @@ status = "disabled"; }; }; + + rctl: reset-controller@400c3100 { + compatible = "nuvoton,npcx-rst"; + reg = <0x400c3100 0x14>; + #reset-cells = <1>; + status = "disabled"; + }; + + i3c0: i3c@400f0000 { + compatible = "nuvoton,npcx-i3c"; + + /* reg[0]: I3C_1 register, reg[1]: MDMA5 register */ + reg-names = "i3c1", "mdma5"; + reg = <0x400f0000 0x2000>, + <0x40011500 0x100>; + + interrupts = <29 3>; + + /* Reset controller */ + resets = <&rctl NPCX_RESET_I3C_1>; + + /* clk[0]: I3C source clock, clk[1]: timeout reference clock */ + /* clk[2]: MDMA5 */ + clock-names = "mclkd", "apb4", "mdma5"; + clocks = <&pcc NPCX_CLOCK_BUS_MCLKD NPCX_PWDWN_CTL8 0>, + <&pcc NPCX_CLOCK_BUS_APB4 0 0>, + <&pcc NPCX_CLOCK_BUS_CORE NPCX_PWDWN_CTL9 4>; + + status = "disabled"; + #address-cells = <3>; + #size-cells = <0>; + }; + + i3c1: i3c@400f2000 { + compatible = "nuvoton,npcx-i3c"; + + /* reg[0]: I3C_2 register, reg[1]: MDMA6 register */ + reg-names = "i3c2", "mdma6"; + reg = <0x400f2000 0x2000>, + <0x40011600 0x100>; + + interrupts = <66 3>; + + /* Reset controller */ + resets = <&rctl NPCX_RESET_I3C_2>; + + /* clk[0]: I3C source clock, clk[1]: timeout reference clock */ + /* clk[2]: MDMA6 */ + clock-names = "mclkd", "apb4", "mdma6"; + clocks = <&pcc NPCX_CLOCK_BUS_MCLKD NPCX_PWDWN_CTL8 2>, + <&pcc NPCX_CLOCK_BUS_APB4 0 0>, + <&pcc NPCX_CLOCK_BUS_CORE NPCX_PWDWN_CTL9 5>; + + status = "disabled"; + #address-cells = <3>; + #size-cells = <0>; + }; + + i3c2: i3c@400f4000 { + compatible = "nuvoton,npcx-i3c"; + + /* reg[0]: I3C_3 register, reg[1]: MDMA7 register */ + reg-names = "i3c1", "mdma7"; + reg = <0x400f4000 0x2000>, + <0x40011700 0x100>; + + interrupts = <67 3>; + + /* Reset controller */ + resets = <&rctl NPCX_RESET_I3C_3>; + + /* clk[0]: I3C source clock, clk[1]: timeout reference clock */ + /* clk[2]: MDMA7 */ + clock-names = "mclkd", "apb4", "mdma7"; + clocks = <&pcc NPCX_CLOCK_BUS_MCLKD NPCX_PWDWN_CTL8 3>, + <&pcc NPCX_CLOCK_BUS_APB4 0 0>, + <&pcc NPCX_CLOCK_BUS_CORE NPCX_PWDWN_CTL9 6>; + + status = "disabled"; + #address-cells = <3>; + #size-cells = <0>; + }; }; soc-if { diff --git a/dts/arm/nuvoton/npcx/npcx4/npcx4-pinctrl.dtsi b/dts/arm/nuvoton/npcx/npcx4/npcx4-pinctrl.dtsi index af45fa59ddb..ec9979c7077 100644 --- a/dts/arm/nuvoton/npcx/npcx4/npcx4-pinctrl.dtsi +++ b/dts/arm/nuvoton/npcx/npcx4/npcx4-pinctrl.dtsi @@ -30,6 +30,22 @@ dev-ctl = <0x0 6 1 0x01>; }; + /omit-if-no-ref/ sio_clk_sel_96m: devctl3-sio-clk_sel-96m { + dev-ctl = <0x4 6 2 0x00>; + }; + + /omit-if-no-ref/ sio_clk_sel_100: devctl3-sio-clk_sel-100m { + dev-ctl = <0x4 6 2 0x01>; + }; + + /omit-if-no-ref/ sio_clk_sel_120m: devctl3-sio-clk_sel-120m { + dev-ctl = <0x4 6 2 0x02>; + }; + + /omit-if-no-ref/ sio_clk_sel_90m: devctl3-sio-clk_sel-90m { + dev-ctl = <0x4 6 2 0x03>; + }; + /* Prebuild nodes for peripheral device's pin-muxing and pad properties */ /* Flash Interface Unit (FIU) */ /omit-if-no-ref/ fiu_ext_io0_io1_clk_cs_gpa4_96_a2_a0: periph-fiu-ext { diff --git a/dts/arm/nuvoton/npcx/npcx7.dtsi b/dts/arm/nuvoton/npcx/npcx7.dtsi index be003127596..fb4001c177b 100644 --- a/dts/arm/nuvoton/npcx/npcx7.dtsi +++ b/dts/arm/nuvoton/npcx/npcx7.dtsi @@ -260,6 +260,13 @@ rx-plsize = <64>; tx-plsize = <16>; }; + + rctl: reset-controller@400c3100 { + compatible = "nuvoton,npcx-rst"; + reg = <0x400c3100 0x10>; + #reset-cells = <1>; + status = "disabled"; + }; }; soc-id { diff --git a/dts/arm/nuvoton/npcx/npcx7/npcx7-pinctrl.dtsi b/dts/arm/nuvoton/npcx/npcx7/npcx7-pinctrl.dtsi index 2b219c48ede..35a40411835 100644 --- a/dts/arm/nuvoton/npcx/npcx7/npcx7-pinctrl.dtsi +++ b/dts/arm/nuvoton/npcx/npcx7/npcx7-pinctrl.dtsi @@ -22,6 +22,14 @@ dev-ctl = <0x0 6 1 0x01>; }; + /omit-if-no-ref/ sio_full_ck48: devctl4-sio-full-ck48 { + dev-ctl = <0x6 3 1 0x00>; + }; + + /omit-if-no-ref/ sio_full_ck50: devctl4-sio-full-ck50 { + dev-ctl = <0x6 3 1 0x01>; + }; + /* Prebuild nodes for peripheral device's pin-muxing and pad properties */ /* Flash Interface Unit (FIU) */ /omit-if-no-ref/ fiu_ext_io0_io1_clk_cs_gpa4_96_a2_a0: periph-fiu-ext { diff --git a/dts/arm/nuvoton/npcx/npcx9.dtsi b/dts/arm/nuvoton/npcx/npcx9.dtsi index e3004ab879d..a246918ac8e 100644 --- a/dts/arm/nuvoton/npcx/npcx9.dtsi +++ b/dts/arm/nuvoton/npcx/npcx9.dtsi @@ -73,36 +73,48 @@ uart1: serial@400e0000 { compatible = "nuvoton,npcx-uart"; - reg = <0x400E0000 0x2000>; + /* Index 0: UART1 register, Index 1: MDMA1 register */ + reg = <0x400E0000 0x2000 0x40011100 0x100>; interrupts = <33 3>; - clocks = <&pcc NPCX_CLOCK_BUS_APB4 NPCX_PWDWN_CTL1 4>; + /* Index 0: UART1 clock, Index 1: MDMA1 clock */ + clocks = <&pcc NPCX_CLOCK_BUS_APB4 NPCX_PWDWN_CTL1 4 + &pcc NPCX_CLOCK_BUS_CORE NPCX_PWDWN_CTL9 0>; uart-rx = <&wui_cr_sin1>; status = "disabled"; }; uart2: serial@400e2000 { compatible = "nuvoton,npcx-uart"; - reg = <0x400E2000 0x2000>; + /* Index 0: UART2 register, Index 1: MDMA2 register */ + reg = <0x400E2000 0x2000 0x40011200 0x100>; interrupts = <32 3>; - clocks = <&pcc NPCX_CLOCK_BUS_APB4 NPCX_PWDWN_CTL7 6>; + /* Index 0: UART2 clock, Index 1: MDMA2 clock */ + clocks = <&pcc NPCX_CLOCK_BUS_APB4 NPCX_PWDWN_CTL7 6 + &pcc NPCX_CLOCK_BUS_CORE NPCX_PWDWN_CTL9 1>; uart-rx = <&wui_cr_sin2>; status = "disabled"; }; uart3: serial@400e4000 { compatible = "nuvoton,npcx-uart"; - reg = <0x400E4000 0x2000>; + /* Index 0: UART3 register, Index 1: MDMA3 register */ + reg = <0x400E4000 0x2000 0x40011300 0x100>; interrupts = <38 3>; - clocks = <&pcc NPCX_CLOCK_BUS_APB4 NPCX_PWDWN_CTL7 4>; + /* Index 0: UART3 clock, Index 1: MDMA3 clock */ + clocks = <&pcc NPCX_CLOCK_BUS_APB4 NPCX_PWDWN_CTL7 4 + &pcc NPCX_CLOCK_BUS_CORE NPCX_PWDWN_CTL9 2>; uart-rx = <&wui_cr_sin3>; status = "disabled"; }; uart4: serial@400e6000 { compatible = "nuvoton,npcx-uart"; - reg = <0x400E6000 0x2000>; + /* Index 0: UART4 register, Index 1: MDMA4 register */ + reg = <0x400E6000 0x2000 0x40011400 0x100>; interrupts = <39 3>; - clocks = <&pcc NPCX_CLOCK_BUS_APB4 NPCX_PWDWN_CTL7 3>; + /* Index 0: UART4 clock, Index 1: MDMA4 clock */ + clocks = <&pcc NPCX_CLOCK_BUS_APB4 NPCX_PWDWN_CTL7 3 + &pcc NPCX_CLOCK_BUS_CORE NPCX_PWDWN_CTL9 3>; uart-rx = <&wui_cr_sin4>; status = "disabled"; }; @@ -288,6 +300,13 @@ rx-plsize = <64>; tx-plsize = <16>; }; + + rctl: reset-controller@400c3100 { + compatible = "nuvoton,npcx-rst"; + reg = <0x400c3100 0x14>; + #reset-cells = <1>; + status = "disabled"; + }; }; soc-id { diff --git a/dts/arm/nuvoton/npcx/npcx9/npcx9-pinctrl.dtsi b/dts/arm/nuvoton/npcx/npcx9/npcx9-pinctrl.dtsi index 2ba0b78fdda..583b5352fad 100644 --- a/dts/arm/nuvoton/npcx/npcx9/npcx9-pinctrl.dtsi +++ b/dts/arm/nuvoton/npcx/npcx9/npcx9-pinctrl.dtsi @@ -23,6 +23,14 @@ dev-ctl = <0x0 6 1 0x01>; }; + /omit-if-no-ref/ sio_full_ck48: devctl4-sio-full-ck48 { + dev-ctl = <0x6 3 1 0x00>; + }; + + /omit-if-no-ref/ sio_full_ck50: devctl4-sio-full-ck50 { + dev-ctl = <0x6 3 1 0x01>; + }; + /* Prebuild nodes for peripheral device's pin-muxing and pad properties */ /* Flash Interface Unit (FIU) */ /omit-if-no-ref/ fiu_ext_io0_io1_clk_cs_gpa4_96_a2_a0: periph-fiu-ext { diff --git a/dts/arm/nxp/nxp_imx6sx_m4.dtsi b/dts/arm/nxp/nxp_imx6sx_m4.dtsi index 4a6d606c253..ce34a247b80 100644 --- a/dts/arm/nxp/nxp_imx6sx_m4.dtsi +++ b/dts/arm/nxp/nxp_imx6sx_m4.dtsi @@ -29,9 +29,10 @@ }; }; - tcml:memory@1fff8000 { + /* TCML 0x1fff8000 is aliased at 0 */ + tcml:memory@0 { compatible = "nxp,imx-itcm"; - reg = <0x1fff8000 DT_SIZE_K(32)>; + reg = <0x00000000 DT_SIZE_K(32)>; }; tcmu:memory@20000000 { diff --git a/dts/arm/nxp/nxp_imx7d_m4.dtsi b/dts/arm/nxp/nxp_imx7d_m4.dtsi index 9b7ed2aed5a..b127c8eda4f 100644 --- a/dts/arm/nxp/nxp_imx7d_m4.dtsi +++ b/dts/arm/nxp/nxp_imx7d_m4.dtsi @@ -56,9 +56,10 @@ reg = <0x20200000 DT_SIZE_K(128)>; }; - ocram_s_code: code@20180000 { + /* OCRAM_S 0x20180000 is aliased at 0 */ + ocram_s_code: code@0 { compatible = "nxp,imx-code-bus"; - reg = <0x20180000 DT_SIZE_K(32)>; + reg = <0x00000000 DT_SIZE_K(32)>; }; ocram_s_sys: memory@180000 { diff --git a/dts/arm/nxp/nxp_k6x.dtsi b/dts/arm/nxp/nxp_k6x.dtsi index 20f3d90e999..bd77e437487 100644 --- a/dts/arm/nxp/nxp_k6x.dtsi +++ b/dts/arm/nxp/nxp_k6x.dtsi @@ -475,18 +475,30 @@ }; enet: ethernet@400c0000 { - compatible = "nxp,kinetis-ethernet"; + compatible = "nxp,enet"; reg = <0x400c0000 0x620>; - interrupts = <83 0>, <84 0>, <85 0>; - interrupt-names = "TX", "RX", "ERR"; - status = "disabled"; - phy-addr = <0>; - clocks = <&sim KINETIS_SIM_CORESYS_CLK 0 0>; - ptp: ptp { - compatible = "nxp,kinetis-ptp"; + 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"; + clocks = <&sim KINETIS_SIM_ENET_1588_CLK 0 0>; + status = "disabled"; }; }; diff --git a/dts/arm/nxp/nxp_ke1xz.dtsi b/dts/arm/nxp/nxp_ke1xz.dtsi new file mode 100644 index 00000000000..5f6b08f5dc0 --- /dev/null +++ b/dts/arm/nxp/nxp_ke1xz.dtsi @@ -0,0 +1,235 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "armv6-m.dtsi" +#include +#include +#include + +/ { + chosen { + zephyr,flash-controller = &ftfe; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + compatible = "arm,cortex-m0+"; + clock-frequency = <48000000>; + reg = <0>; + }; + }; + + sram_l: memory@1fffe000 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x1FFFE000 DT_SIZE_K(8)>; + zephyr,memory-region = "SRAML"; + }; + + sram_u: memory@20000000 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x20000000 DT_SIZE_K(24)>; + zephyr,memory-region = "SRAMU"; + }; + + pinctrl: pinctrl { + compatible = "nxp,kinetis-pinctrl"; + }; + + soc { + scg: scg@40064000 { + sosc-mode = ; + compatible = "nxp,kinetis-scg"; + reg = <0x40064000 0x1000>; + #clock-cells = <1>; + + sirc_clk: sirc_clk { + compatible = "fixed-clock"; + clock-frequency = <8000000>; + #clock-cells = <0>; + }; + + firc_clk: firc_clk { + compatible = "fixed-clock"; + clock-frequency = <48000000>; + #clock-cells = <0>; + }; + + core_clk: core_clk { + compatible = "fixed-factor-clock"; + clocks = <&firc_clk>; + clock-div = <1>; + #clock-cells = <0>; + }; + + bus_clk: bus_clk { + compatible = "fixed-factor-clock"; + clocks = <&core_clk>; + clock-div = <4>; + #clock-cells = <0>; + }; + + sircdiv2_clk: sircdiv2_clk { + compatible = "fixed-factor-clock"; + clocks = <&sirc_clk>; + clock-div = <2>; + #clock-cells = <0>; + }; + + fircdiv2_clk: fircdiv2_clk { + compatible = "fixed-factor-clock"; + clocks = <&firc_clk>; + clock-div = <1>; + #clock-cells = <0>; + }; + }; + + pcc: pcc@40065000 { + compatible = "nxp,kinetis-pcc"; + reg = <0x40065000 0x1000>; + #clock-cells = <2>; + }; + + ftfe: flash-controller@40020000 { + compatible = "nxp,kinetis-ftfe"; + reg = <0x40020000 0x1000>; + interrupts = <5 0>; + interrupt-names = "command-complete"; + + #address-cells = <1>; + #size-cells = <1>; + + flash0: flash@0 { + compatible = "soc-nv-flash"; + reg = <0 DT_SIZE_K(256)>; + erase-block-size = ; + write-block-size = <8>; + }; + }; + + lpuart0: uart@4006a000 { + compatible = "nxp,kinetis-lpuart"; + reg = <0x4006a000 0x1000>; + interrupts = <12 0>; + clocks = <&pcc 0x1a8 KINETIS_PCC_SRC_FIRC_ASYNC>; + status = "disabled"; + }; + + lpuart1: uart@4006b000 { + compatible = "nxp,kinetis-lpuart"; + reg = <0x4006b000 0x1000>; + interrupts = <13 0>; + clocks = <&pcc 0x1ac KINETIS_PCC_SRC_FIRC_ASYNC>; + status = "disabled"; + }; + + lpuart2: uart@4006c000 { + compatible = "nxp,kinetis-lpuart"; + reg = <0x4006c000 0x1000>; + interrupts = <14 0>; + clocks = <&pcc 0x1b0 KINETIS_PCC_SRC_FIRC_ASYNC>; + status = "disabled"; + }; + + porta: pinmux@40049000 { + compatible = "nxp,kinetis-pinmux"; + reg = <0x40049000 0x1000>; + clocks = <&pcc 0x124 KINETIS_PCC_SRC_NONE_OR_EXT>; + }; + + portb: pinmux@4004a000 { + compatible = "nxp,kinetis-pinmux"; + reg = <0x4004a000 0x1000>; + clocks = <&pcc 0x128 KINETIS_PCC_SRC_NONE_OR_EXT>; + }; + + portc: pinmux@4004b000 { + compatible = "nxp,kinetis-pinmux"; + reg = <0x4004b000 0x1000>; + clocks = <&pcc 0x12c KINETIS_PCC_SRC_NONE_OR_EXT>; + }; + + portd: pinmux@4004c000 { + compatible = "nxp,kinetis-pinmux"; + reg = <0x4004c000 0x1000>; + clocks = <&pcc 0x130 KINETIS_PCC_SRC_NONE_OR_EXT>; + }; + + porte: pinmux@4004d000 { + compatible = "nxp,kinetis-pinmux"; + reg = <0x4004d000 0x1000>; + clocks = <&pcc 0x134 KINETIS_PCC_SRC_NONE_OR_EXT>; + }; + + gpios0: gpios0 { + compatible = "nxp,gpio-cluster"; + interrupts = <7 2>; + + #address-cells = <1>; + #size-cells = <1>; + + gpioa: gpio@400ff000 { + compatible = "nxp,kinetis-gpio"; + status = "disabled"; + reg = <0x400ff000 0x40>; + gpio-controller; + #gpio-cells = <2>; + nxp,kinetis-port = <&porta>; + }; + + gpioe: gpio@400ff100 { + compatible = "nxp,kinetis-gpio"; + status = "disabled"; + reg = <0x400ff100 0x40>; + gpio-controller; + #gpio-cells = <2>; + nxp,kinetis-port = <&porte>; + }; + }; + + gpios1: gpios1 { + compatible = "nxp,gpio-cluster"; + interrupts = <26 2>; + + #address-cells = <1>; + #size-cells = <1>; + + gpiob: gpio@400ff040 { + compatible = "nxp,kinetis-gpio"; + status = "disabled"; + reg = <0x400ff040 0x40>; + gpio-controller; + #gpio-cells = <2>; + nxp,kinetis-port = <&portb>; + }; + + gpioc: gpio@400ff080 { + compatible = "nxp,kinetis-gpio"; + status = "disabled"; + reg = <0x400ff080 0x40>; + gpio-controller; + #gpio-cells = <2>; + nxp,kinetis-port = <&portc>; + }; + + gpiod: gpio@400ff0c0 { + compatible = "nxp,kinetis-gpio"; + status = "disabled"; + reg = <0x400ff0c0 0x40>; + gpio-controller; + #gpio-cells = <2>; + nxp,kinetis-port = <&portd>; + }; + }; + }; +}; + +&nvic { + arm,num-irq-priority-bits = <2>; +}; diff --git a/dts/arm/nxp/nxp_lpc51u68.dtsi b/dts/arm/nxp/nxp_lpc51u68.dtsi index 964e863485b..3c69de8dd4a 100644 --- a/dts/arm/nxp/nxp_lpc51u68.dtsi +++ b/dts/arm/nxp/nxp_lpc51u68.dtsi @@ -9,6 +9,7 @@ #include #include #include +#include / { cpus { @@ -26,6 +27,10 @@ compatible = "nxp,lpc-syscon"; reg = <0x40000000 0x4000>; #clock-cells = <1>; + reset: reset { + compatible = "nxp,lpc-syscon-reset"; + #reset-cells = <1>; + }; }; sram0:memory@20000000 { @@ -88,6 +93,7 @@ reg = <0x40086000 0x1000>; interrupts = <14 0>; clocks = <&syscon MCUX_FLEXCOMM0_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 11)>; status = "disabled"; }; @@ -96,6 +102,7 @@ reg = <0x40087000 0x1000>; interrupts = <15 0>; clocks = <&syscon MCUX_FLEXCOMM1_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 12)>; status = "disabled"; }; @@ -104,6 +111,7 @@ reg = <0x40088000 0x1000>; interrupts = <16 0>; clocks = <&syscon MCUX_FLEXCOMM2_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 13)>; status = "disabled"; }; @@ -112,6 +120,7 @@ reg = <0x40089000 0x1000>; interrupts = <17 0>; clocks = <&syscon MCUX_FLEXCOMM3_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 14)>; status = "disabled"; }; @@ -120,6 +129,7 @@ reg = <0x4008a000 0x1000>; interrupts = <18 0>; clocks = <&syscon MCUX_FLEXCOMM4_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 15)>; status = "disabled"; }; @@ -128,6 +138,7 @@ reg = <0x40096000 0x1000>; interrupts = <19 0>; clocks = <&syscon MCUX_FLEXCOMM5_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 16)>; status = "disabled"; }; @@ -136,6 +147,7 @@ reg = <0x40097000 0x1000>; interrupts = <20 0>; clocks = <&syscon MCUX_FLEXCOMM6_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 17)>; status = "disabled"; }; @@ -144,6 +156,7 @@ reg = <0x40098000 0x1000>; interrupts = <21 0>; clocks = <&syscon MCUX_FLEXCOMM7_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 18)>; status = "disabled"; }; diff --git a/dts/arm/nxp/nxp_lpc54xxx.dtsi b/dts/arm/nxp/nxp_lpc54xxx.dtsi index a5befec1257..78ffb203a84 100644 --- a/dts/arm/nxp/nxp_lpc54xxx.dtsi +++ b/dts/arm/nxp/nxp_lpc54xxx.dtsi @@ -9,6 +9,7 @@ #include #include #include +#include / { aliases{ @@ -41,6 +42,10 @@ compatible = "nxp,lpc-syscon"; reg = <0x40000000 0x4000>; #clock-cells = <1>; + reset: reset { + compatible = "nxp,lpc-syscon-reset"; + #reset-cells = <1>; + }; }; /* @@ -151,6 +156,7 @@ reg = <0x40086000 0x1000>; interrupts = <14 0>; clocks = <&syscon MCUX_FLEXCOMM0_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 11)>; status = "disabled"; }; @@ -159,6 +165,7 @@ reg = <0x40087000 0x1000>; interrupts = <15 0>; clocks = <&syscon MCUX_FLEXCOMM1_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 12)>; status = "disabled"; }; @@ -167,6 +174,7 @@ reg = <0x40088000 0x1000>; interrupts = <16 0>; clocks = <&syscon MCUX_FLEXCOMM2_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 13)>; status = "disabled"; }; @@ -175,6 +183,7 @@ reg = <0x40089000 0x1000>; interrupts = <17 0>; clocks = <&syscon MCUX_FLEXCOMM3_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 14)>; status = "disabled"; }; @@ -183,6 +192,7 @@ reg = <0x4008a000 0x1000>; interrupts = <18 0>; clocks = <&syscon MCUX_FLEXCOMM4_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 15)>; status = "disabled"; }; @@ -191,6 +201,7 @@ reg = <0x40096000 0x1000>; interrupts = <19 0>; clocks = <&syscon MCUX_FLEXCOMM5_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 16)>; status = "disabled"; }; @@ -199,6 +210,7 @@ reg = <0x40097000 0x1000>; interrupts = <20 0>; clocks = <&syscon MCUX_FLEXCOMM6_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 17)>; status = "disabled"; }; @@ -207,6 +219,7 @@ reg = <0x40098000 0x1000>; interrupts = <21 0>; clocks = <&syscon MCUX_FLEXCOMM7_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 18)>; status = "disabled"; }; }; diff --git a/dts/arm/nxp/nxp_lpc55S0x_common.dtsi b/dts/arm/nxp/nxp_lpc55S0x_common.dtsi index c2f8295e575..4ffb014f281 100644 --- a/dts/arm/nxp/nxp_lpc55S0x_common.dtsi +++ b/dts/arm/nxp/nxp_lpc55S0x_common.dtsi @@ -8,6 +8,7 @@ #include #include #include +#include / { cpus { @@ -68,6 +69,10 @@ compatible = "nxp,lpc-syscon"; reg = <0x0 0x4000>; #clock-cells = <1>; + reset: reset { + compatible = "nxp,lpc-syscon-reset"; + #reset-cells = <1>; + }; }; iap: flash-controller@34000 { @@ -147,6 +152,7 @@ reg = <0x86000 0x1000>; interrupts = <14 0>; clocks = <&syscon MCUX_FLEXCOMM0_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 11)>; status = "disabled"; }; @@ -155,6 +161,7 @@ reg = <0x87000 0x1000>; interrupts = <15 0>; clocks = <&syscon MCUX_FLEXCOMM1_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 12)>; status = "disabled"; }; @@ -163,6 +170,7 @@ reg = <0x88000 0x1000>; interrupts = <16 0>; clocks = <&syscon MCUX_FLEXCOMM2_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 13)>; status = "disabled"; }; @@ -171,6 +179,7 @@ reg = <0x89000 0x1000>; interrupts = <17 0>; clocks = <&syscon MCUX_FLEXCOMM3_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 14)>; status = "disabled"; }; @@ -179,6 +188,7 @@ reg = <0x8a000 0x1000>; interrupts = <18 0>; clocks = <&syscon MCUX_FLEXCOMM4_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 15)>; status = "disabled"; }; @@ -187,6 +197,7 @@ reg = <0x96000 0x1000>; interrupts = <19 0>; clocks = <&syscon MCUX_FLEXCOMM5_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 16)>; status = "disabled"; }; @@ -195,6 +206,7 @@ reg = <0x97000 0x1000>; interrupts = <20 0>; clocks = <&syscon MCUX_FLEXCOMM6_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 17)>; status = "disabled"; }; @@ -203,6 +215,7 @@ reg = <0x98000 0x1000>; interrupts = <21 0>; clocks = <&syscon MCUX_FLEXCOMM7_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 18)>; status = "disabled"; }; @@ -211,6 +224,7 @@ reg = <0x9f000 0x1000>; interrupts = <59 0>; clocks = <&syscon MCUX_HS_SPI_CLK>; + resets = <&reset NXP_SYSCON_RESET(2, 28)>; status = "disabled"; #address-cells = <1>; #size-cells = <0>; @@ -222,6 +236,7 @@ interrupts = <43 0>, <44 0>; interrupt-names = "int0", "int1"; clocks = <&syscon MCUX_MCAN_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 7)>; bosch,mram-cfg = <0x0 15 15 8 8 0 15 15>; status = "disabled"; }; diff --git a/dts/arm/nxp/nxp_lpc55S1x_common.dtsi b/dts/arm/nxp/nxp_lpc55S1x_common.dtsi index 05ad85196be..c9b4b3ddb89 100644 --- a/dts/arm/nxp/nxp_lpc55S1x_common.dtsi +++ b/dts/arm/nxp/nxp_lpc55S1x_common.dtsi @@ -10,6 +10,7 @@ #include #include #include +#include / { cpus { @@ -73,6 +74,10 @@ compatible = "nxp,lpc-syscon"; reg = <0x0 0x4000>; #clock-cells = <1>; + reset: reset { + compatible = "nxp,lpc-syscon-reset"; + #reset-cells = <1>; + }; }; iap: flash-controller@34000 { @@ -152,6 +157,7 @@ reg = <0x86000 0x1000>; interrupts = <14 0>; clocks = <&syscon MCUX_FLEXCOMM0_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 11)>; status = "disabled"; }; @@ -160,6 +166,7 @@ reg = <0x87000 0x1000>; interrupts = <15 0>; clocks = <&syscon MCUX_FLEXCOMM1_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 12)>; status = "disabled"; }; @@ -168,6 +175,7 @@ reg = <0x88000 0x1000>; interrupts = <16 0>; clocks = <&syscon MCUX_FLEXCOMM2_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 13)>; status = "disabled"; }; @@ -176,6 +184,7 @@ reg = <0x89000 0x1000>; interrupts = <17 0>; clocks = <&syscon MCUX_FLEXCOMM3_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 14)>; status = "disabled"; }; @@ -184,6 +193,7 @@ reg = <0x8a000 0x1000>; interrupts = <18 0>; clocks = <&syscon MCUX_FLEXCOMM4_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 15)>; status = "disabled"; }; @@ -192,6 +202,7 @@ reg = <0x96000 0x1000>; interrupts = <19 0>; clocks = <&syscon MCUX_FLEXCOMM5_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 16)>; status = "disabled"; }; @@ -200,6 +211,7 @@ reg = <0x97000 0x1000>; interrupts = <20 0>; clocks = <&syscon MCUX_FLEXCOMM6_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 17)>; status = "disabled"; }; @@ -208,6 +220,7 @@ reg = <0x98000 0x1000>; interrupts = <21 0>; clocks = <&syscon MCUX_FLEXCOMM7_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 18)>; status = "disabled"; }; @@ -217,6 +230,7 @@ interrupts = <43 0>, <44 0>; interrupt-names = "int0", "int1"; clocks = <&syscon MCUX_MCAN_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 7)>; bosch,mram-cfg = <0x0 15 15 8 8 0 15 15>; status = "disabled"; }; @@ -226,6 +240,7 @@ reg = <0x9f000 0x1000>; interrupts = <59 0>; clocks = <&syscon MCUX_HS_SPI_CLK>; + resets = <&reset NXP_SYSCON_RESET(2, 28)>; status = "disabled"; #address-cells = <1>; #size-cells = <0>; diff --git a/dts/arm/nxp/nxp_lpc55S2x_common.dtsi b/dts/arm/nxp/nxp_lpc55S2x_common.dtsi index 6ec0240b2f1..a751693e201 100644 --- a/dts/arm/nxp/nxp_lpc55S2x_common.dtsi +++ b/dts/arm/nxp/nxp_lpc55S2x_common.dtsi @@ -1,5 +1,6 @@ /* * Copyright (c) 2020 Lemonbeat GmbH + * Copyright 2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -11,6 +12,7 @@ #include #include #include +#include / { aliases { @@ -87,6 +89,10 @@ compatible = "nxp,lpc-syscon"; reg = <0x0 0x1000>; #clock-cells = <1>; + reset: reset { + compatible = "nxp,lpc-syscon-reset"; + #reset-cells = <1>; + }; }; iap: flash-controller@34000 { @@ -178,6 +184,7 @@ reg = <0x86000 0x1000>; interrupts = <14 0>; clocks = <&syscon MCUX_FLEXCOMM0_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 11)>; status = "disabled"; }; @@ -186,6 +193,7 @@ reg = <0x87000 0x1000>; interrupts = <15 0>; clocks = <&syscon MCUX_FLEXCOMM1_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 12)>; status = "disabled"; }; @@ -194,6 +202,7 @@ reg = <0x88000 0x1000>; interrupts = <16 0>; clocks = <&syscon MCUX_FLEXCOMM2_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 13)>; status = "disabled"; }; @@ -202,6 +211,7 @@ reg = <0x89000 0x1000>; interrupts = <17 0>; clocks = <&syscon MCUX_FLEXCOMM3_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 14)>; status = "disabled"; }; @@ -210,6 +220,7 @@ reg = <0x8a000 0x1000>; interrupts = <18 0>; clocks = <&syscon MCUX_FLEXCOMM4_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 15)>; status = "disabled"; }; @@ -218,6 +229,7 @@ reg = <0x96000 0x1000>; interrupts = <19 0>; clocks = <&syscon MCUX_FLEXCOMM5_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 16)>; status = "disabled"; }; @@ -226,6 +238,7 @@ reg = <0x97000 0x1000>; interrupts = <20 0>; clocks = <&syscon MCUX_FLEXCOMM6_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 17)>; status = "disabled"; }; @@ -234,6 +247,7 @@ reg = <0x98000 0x1000>; interrupts = <21 0>; clocks = <&syscon MCUX_FLEXCOMM7_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 18)>; status = "disabled"; }; @@ -248,6 +262,7 @@ reg = <0x9f000 0x1000>; interrupts = <59 0>; clocks = <&syscon MCUX_HS_SPI_CLK>; + resets = <&reset NXP_SYSCON_RESET(2, 28)>; status = "disabled"; #address-cells = <1>; #size-cells = <0>; @@ -280,6 +295,7 @@ offset-value-a = <10>; offset-value-b = <10>; #io-channel-cells = <1>; + clocks = <&syscon MCUX_LPADC1_CLK>; }; usbhs: usbhs@144000 { diff --git a/dts/arm/nxp/nxp_lpc55S3x_common.dtsi b/dts/arm/nxp/nxp_lpc55S3x_common.dtsi index 328633f5163..6a5621d19b7 100644 --- a/dts/arm/nxp/nxp_lpc55S3x_common.dtsi +++ b/dts/arm/nxp/nxp_lpc55S3x_common.dtsi @@ -1,5 +1,5 @@ /* - * Copyright 2022 NXP + * Copyright 2022, 2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -11,6 +11,7 @@ #include #include #include +#include / { cpus { @@ -73,6 +74,10 @@ compatible = "nxp,lpc-syscon"; reg = <0x0 0x1000>; #clock-cells = <1>; + reset: reset { + compatible = "nxp,lpc-syscon-reset"; + #reset-cells = <1>; + }; }; iap: flash-controller@34000 { @@ -179,6 +184,7 @@ reg = <0x86000 0x1000>; interrupts = <14 0>; clocks = <&syscon MCUX_FLEXCOMM0_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 11)>; dmas = <&dma0 4>, <&dma0 5>; dma-names = "rx", "tx"; status = "disabled"; @@ -189,6 +195,7 @@ reg = <0x87000 0x1000>; interrupts = <15 0>; clocks = <&syscon MCUX_FLEXCOMM1_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 12)>; dmas = <&dma0 6>, <&dma0 7>; dma-names = "rx", "tx"; status = "disabled"; @@ -199,6 +206,7 @@ reg = <0x88000 0x1000>; interrupts = <16 0>; clocks = <&syscon MCUX_FLEXCOMM2_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 13)>; dmas = <&dma0 10>, <&dma0 11>; dma-names = "rx", "tx"; status = "disabled"; @@ -209,6 +217,7 @@ reg = <0x89000 0x1000>; interrupts = <17 0>; clocks = <&syscon MCUX_FLEXCOMM3_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 14)>; dmas = <&dma0 8>, <&dma0 9>; dma-names = "rx", "tx"; status = "disabled"; @@ -219,6 +228,7 @@ reg = <0x8a000 0x1000>; interrupts = <18 0>; clocks = <&syscon MCUX_FLEXCOMM4_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 15)>; dmas = <&dma0 12>, <&dma0 13>; dma-names = "rx", "tx"; status = "disabled"; @@ -229,6 +239,7 @@ reg = <0x96000 0x1000>; interrupts = <19 0>; clocks = <&syscon MCUX_FLEXCOMM5_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 16)>; dmas = <&dma0 14>, <&dma0 15>; dma-names = "rx", "tx"; status = "disabled"; @@ -239,6 +250,7 @@ reg = <0x97000 0x1000>; interrupts = <20 0>; clocks = <&syscon MCUX_FLEXCOMM6_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 17)>; dmas = <&dma0 16>, <&dma0 17>; dma-names = "rx", "tx"; status = "disabled"; @@ -249,6 +261,7 @@ reg = <0x98000 0x1000>; interrupts = <21 0>; clocks = <&syscon MCUX_FLEXCOMM7_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 18)>; dmas = <&dma0 18>, <&dma0 19>; dma-names = "rx", "tx"; status = "disabled"; @@ -259,6 +272,7 @@ reg = <0x9f000 0x1000>; interrupts = <59 0>; clocks = <&syscon MCUX_HS_SPI_CLK>; + resets = <&reset NXP_SYSCON_RESET(2, 28)>; dmas = <&dma0 2>, <&dma0 3>; dma-names = "rx", "tx"; status = "disabled"; @@ -282,6 +296,7 @@ dmas = <&dma0 21>, <&dma0 22>; dma-names = "adc0-dma0", "adc0-dma1"; nxp,reference-supply = <&vref0>; + clocks = <&syscon MCUX_LPADC1_CLK>; }; dac0: dac@b2000 { @@ -317,6 +332,7 @@ interrupts = <43 0>, <44 0>; interrupt-names = "int0", "int1"; clocks = <&syscon MCUX_MCAN_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 7)>; bosch,mram-cfg = <0x0 15 15 8 8 0 15 15>; status = "disabled"; }; diff --git a/dts/arm/nxp/nxp_lpc55S6x_common.dtsi b/dts/arm/nxp/nxp_lpc55S6x_common.dtsi index 107855d88d2..22ca5d6b0ec 100644 --- a/dts/arm/nxp/nxp_lpc55S6x_common.dtsi +++ b/dts/arm/nxp/nxp_lpc55S6x_common.dtsi @@ -1,5 +1,6 @@ /* * Copyright (c) 2020, Linaro Ltd. + * Copyright 2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -12,6 +13,7 @@ #include #include #include +#include / { aliases { @@ -112,6 +114,10 @@ compatible = "nxp,lpc-syscon"; reg = <0x0 0x1000>; #clock-cells = <1>; + reset: reset { + compatible = "nxp,lpc-syscon-reset"; + #reset-cells = <1>; + }; }; iap: flash-controller@34000 { @@ -213,6 +219,7 @@ compatible = "nxp,lpc-mailbox"; reg = <0x8b000 0xEC>; interrupts = <31 0>; + resets = <&reset NXP_SYSCON_RESET(0, 26)>; status = "disabled"; }; @@ -221,6 +228,7 @@ reg = <0x86000 0x1000>; interrupts = <14 0>; clocks = <&syscon MCUX_FLEXCOMM0_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 11)>; status = "disabled"; }; @@ -229,6 +237,7 @@ reg = <0x87000 0x1000>; interrupts = <15 0>; clocks = <&syscon MCUX_FLEXCOMM1_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 12)>; status = "disabled"; }; @@ -237,6 +246,7 @@ reg = <0x88000 0x1000>; interrupts = <16 0>; clocks = <&syscon MCUX_FLEXCOMM2_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 13)>; status = "disabled"; }; @@ -245,6 +255,7 @@ reg = <0x89000 0x1000>; interrupts = <17 0>; clocks = <&syscon MCUX_FLEXCOMM3_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 14)>; status = "disabled"; }; @@ -253,6 +264,7 @@ reg = <0x8a000 0x1000>; interrupts = <18 0>; clocks = <&syscon MCUX_FLEXCOMM4_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 15)>; status = "disabled"; }; @@ -261,6 +273,7 @@ reg = <0x96000 0x1000>; interrupts = <19 0>; clocks = <&syscon MCUX_FLEXCOMM5_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 16)>; status = "disabled"; }; @@ -269,6 +282,7 @@ reg = <0x97000 0x1000>; interrupts = <20 0>; clocks = <&syscon MCUX_FLEXCOMM6_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 17)>; status = "disabled"; }; @@ -277,6 +291,7 @@ reg = <0x98000 0x1000>; interrupts = <21 0>; clocks = <&syscon MCUX_FLEXCOMM7_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 18)>; status = "disabled"; }; @@ -299,6 +314,7 @@ reg = <0x9f000 0x1000>; interrupts = <59 0>; clocks = <&syscon MCUX_HS_SPI_CLK>; + resets = <&reset NXP_SYSCON_RESET(2, 28)>; status = "disabled"; #address-cells = <1>; #size-cells = <0>; @@ -331,6 +347,7 @@ offset-value-a = <10>; offset-value-b = <10>; #io-channel-cells = <1>; + clocks = <&syscon MCUX_LPADC1_CLK>; }; usbfs: usbfs@84000 { @@ -427,6 +444,7 @@ num-channels = <4>; num-bits = <24>; clocks = <&syscon MCUX_MRT_CLK>; + resets = <&reset NXP_SYSCON_RESET(1, 0)>; #address-cells = <1>; #size-cells = <0>; diff --git a/dts/arm/nxp/nxp_mcxn94x_common.dtsi b/dts/arm/nxp/nxp_mcxn94x_common.dtsi index ba9546bd961..1912d3cc26b 100644 --- a/dts/arm/nxp/nxp_mcxn94x_common.dtsi +++ b/dts/arm/nxp/nxp_mcxn94x_common.dtsi @@ -219,6 +219,9 @@ compatible = "nxp,kinetis-lpuart"; reg = <0x93000 0x1000>; clocks = <&syscon MCUX_FLEXCOMM1_CLK>; + /* DMA channels 0 and 1, muxed to LPUART1 RX and TX */ + dmas = <&edma0 0 71>, <&edma0 1 72>; + dma-names = "rx", "tx"; status = "disabled"; }; flexcomm1_lpspi1: lpspi@93000 { @@ -267,6 +270,9 @@ clocks = <&syscon MCUX_FLEXCOMM2_CLK>; #address-cells = <1>; #size-cells = <0>; + /* DMA channels 4 and 5, muxed to LPSPI2 RX and TX */ + dmas = <&edma0 4 73>, <&edma0 5 74>; + dma-names = "rx", "tx"; status = "disabled"; }; flexcomm2_lpi2c2: lpi2c@94800 { @@ -338,6 +344,9 @@ clocks = <&syscon MCUX_FLEXCOMM4_CLK>; #address-cells = <1>; #size-cells = <0>; + /* DMA channels 2 and 3, muxed to LPSPI4 RX and TX */ + dmas = <&edma0 2 77>, <&edma0 3 78>; + dma-names = "rx", "tx"; status = "disabled"; }; flexcomm4_lpi2c4: lpi2c@b4800 { @@ -563,7 +572,8 @@ compatible = "soc-nv-flash"; reg = <0 DT_SIZE_M(2)>; erase-block-size = <8192>; - write-block-size = <16>; + /* MCXN94x ROM Flash API supports writing of 128B pages. */ + write-block-size = <128>; }; }; @@ -618,6 +628,228 @@ clk-divider = <1>; }; + flexpwm0: flexpwm@ce000 { + compatible = "nxp,flexpwm"; + reg = <0xce000 0x1000>; + interrupt-names = "RELOAD-ERROR", "FAULT"; + interrupts = <112 0>, <113 0>; + flexpwm0_pwm0: pwm0 { + compatible = "nxp,imx-pwm"; + index = <0>; + interrupts = <114 0>; + #pwm-cells = <3>; + clocks = <&syscon MCUX_BUS_CLK>; + nxp,prescaler = <128>; + status = "disabled"; + run-in-wait; + }; + + flexpwm0_pwm1: pwm1 { + compatible = "nxp,imx-pwm"; + index = <1>; + interrupts = <115 0>; + #pwm-cells = <3>; + clocks = <&syscon MCUX_BUS_CLK>; + nxp,prescaler = <128>; + status = "disabled"; + run-in-wait; + }; + + flexpwm0_pwm2: pwm2 { + compatible = "nxp,imx-pwm"; + index = <2>; + interrupts = <116 0>; + #pwm-cells = <3>; + clocks = <&syscon MCUX_BUS_CLK>; + nxp,prescaler = <128>; + status = "disabled"; + run-in-wait; + }; + + flexpwm0_pwm3: pwm3 { + compatible = "nxp,imx-pwm"; + index = <3>; + interrupts = <117 0>; + #pwm-cells = <3>; + clocks = <&syscon MCUX_BUS_CLK>; + nxp,prescaler = <128>; + status = "disabled"; + run-in-wait; + }; + }; + + flexpwm1: flexpwm@d0000 { + compatible = "nxp,flexpwm"; + reg = <0xd0000 0x1000>; + interrupt-names = "RELOAD-ERROR", "FAULT"; + interrupts = <118 0>, <119 0>; + flexpwm1_pwm0: pwm0 { + compatible = "nxp,imx-pwm"; + index = <0>; + interrupts = <120 0>; + #pwm-cells = <3>; + clocks = <&syscon MCUX_BUS_CLK>; + nxp,prescaler = <128>; + status = "disabled"; + run-in-wait; + }; + + flexpwm1_pwm1: pwm1 { + compatible = "nxp,imx-pwm"; + index = <1>; + interrupts = <121 0>; + #pwm-cells = <3>; + clocks = <&syscon MCUX_BUS_CLK>; + nxp,prescaler = <128>; + status = "disabled"; + run-in-wait; + }; + + flexpwm1_pwm2: pwm2 { + compatible = "nxp,imx-pwm"; + index = <2>; + interrupts = <122 0>; + #pwm-cells = <3>; + clocks = <&syscon MCUX_BUS_CLK>; + nxp,prescaler = <128>; + status = "disabled"; + run-in-wait; + }; + + flexpwm1_pwm3: pwm3 { + compatible = "nxp,imx-pwm"; + index = <3>; + interrupts = <123 0>; + #pwm-cells = <3>; + clocks = <&syscon MCUX_BUS_CLK>; + nxp,prescaler = <128>; + status = "disabled"; + run-in-wait; + }; + }; + + ctimer0: ctimer@c000 { + compatible = "nxp,lpc-ctimer"; + reg = <0xc000 0x1000>; + interrupts = <31 0>; + status = "disabled"; + clk-source = <1>; + clocks = <&syscon MCUX_CTIMER0_CLK>; + mode = <0>; + input = <0>; + prescale = <0>; + }; + + ctimer1: ctimer@d000 { + compatible = "nxp,lpc-ctimer"; + reg = <0xd000 0x1000>; + interrupts = <32 0>; + status = "disabled"; + clk-source = <1>; + clocks = <&syscon MCUX_CTIMER1_CLK>; + mode = <0>; + input = <0>; + prescale = <0>; + }; + + ctimer2: ctimer@e000 { + compatible = "nxp,lpc-ctimer"; + reg = <0xe000 0x1000>; + interrupts = <34 0>; + status = "disabled"; + clk-source = <1>; + clocks = <&syscon MCUX_CTIMER2_CLK>; + mode = <0>; + input = <0>; + prescale = <0>; + }; + + ctimer3: ctimer@f000 { + compatible = "nxp,lpc-ctimer"; + reg = <0xf000 0x1000>; + interrupts = <55 0>; + status = "disabled"; + clk-source = <1>; + clocks = <&syscon MCUX_CTIMER3_CLK>; + mode = <0>; + input = <0>; + prescale = <0>; + }; + + ctimer4: ctimer@10000 { + compatible = "nxp,lpc-ctimer"; + reg = <0x10000 0x1000>; + interrupts = <56 0>; + status = "disabled"; + clk-source = <1>; + clocks = <&syscon MCUX_CTIMER4_CLK>; + mode = <0>; + input = <0>; + prescale = <0>; + }; + + usdhc0: usdhc@109000 { + compatible = "nxp,imx-usdhc"; + reg = <0x109000 0x1000>; + interrupts = <61 0>; + status = "disabled"; + clocks = <&syscon MCUX_USDHC1_CLK>; + max-bus-freq = <52000000>; + min-bus-freq = <400000>; + }; + + vref: vref@111000 { + compatible = "nxp,vref"; + regulator-name = "mcxn94x-vref"; + reg = <0x111000 0x14>; + status = "disabled"; + nxp,buffer-startup-delay-us = <400>; + nxp,bandgap-startup-time-us = <20>; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <2100000>; + }; + + lpadc0: lpadc@10d000 { + compatible = "nxp,lpc-lpadc"; + reg = <0x10d000 0x1000>; + interrupts = <45 0>; + status = "disabled"; + clk-divider = <1>; + clk-source = <0>; + voltage-ref= <1>; + calibration-average = <128>; + power-level = <0>; + offset-value-a = <0>; + offset-value-b = <0>; + #io-channel-cells = <1>; + clocks = <&syscon MCUX_LPADC1_CLK>; + nxp,reference-supply = <&vref>; + }; + + lpadc1: lpadc@10e000 { + compatible = "nxp,lpc-lpadc"; + reg = <0x10e000 0x1000>; + interrupts = <46 0>; + status = "disabled"; + clk-divider = <1>; + clk-source = <0>; + voltage-ref= <0>; + calibration-average = <128>; + power-level = <1>; + offset-value-a = <0>; + offset-value-b = <0>; + #io-channel-cells = <1>; + clocks = <&syscon MCUX_LPADC2_CLK>; + }; + + usb1: usbd@10b000 { + compatible = "nxp,ehci"; + reg = <0x10b000 0x1000>; + interrupts = <67 0>; + interrupt-names = "usb_otg"; + num-bidir-endpoints = <8>; + status = "disabled"; + }; }; &systick { diff --git a/dts/arm/nxp/nxp_rt1010.dtsi b/dts/arm/nxp/nxp_rt1010.dtsi index 97ae6aa95c0..00f124e8771 100644 --- a/dts/arm/nxp/nxp_rt1010.dtsi +++ b/dts/arm/nxp/nxp_rt1010.dtsi @@ -115,7 +115,7 @@ clocks = <&ccm IMX_CCM_FLEXSPI_CLK 0x0 0x0>; }; - /* Remove SEMC, it does'nt exist on RT1010 */ + /* Remove SEMC, it doesn't exist on RT1010 */ /delete-node/ semc0@402f0000; /* Fixup LPI2C1 and LPI2C2, they have different base addr on RT1010 */ @@ -238,8 +238,8 @@ /delete-node/ flexpwm@403e4000; /delete-node/ flexpwm@403e8000; - /* Remove Ethernet, it does'nt exist on RT1010 */ - /delete-node/ ethernet@402d8000; + /* Remove Ethernet, it doesn't exist on RT1010 */ + /delete-node/ enet@402d8000; /* Fixup USB it has different base addr and interrupt numbers on RT1010 */ /delete-node/ usbd@402e0000; @@ -253,14 +253,14 @@ status = "disabled"; }; - /* Remove USB2, it does'nt exist on RT1010 */ + /* Remove USB2, it doesn't exist on RT1010 */ /delete-node/ usbd@402e0200; /* Remove USDHC, they don't exist on RT1010 */ /delete-node/ usdhc@402c0000; /delete-node/ usdhc@402c4000; - /* Remove CSI, it does'nt exist on RT1010 */ + /* Remove CSI, it doesn't exist on RT1010 */ /delete-node/ csi@402bc000; /* Remove FLEXCAN, they don't exist on RT1010 */ @@ -268,7 +268,7 @@ /delete-node/ can@401d4000; /delete-node/ can@401d8000; - /* Remove WDOG2, it does'nt exist on RT1010 */ + /* Remove WDOG2, it doesn't exist on RT1010 */ /delete-node/ wdog@400d0000; /* Fix SAI1, 3, it has different base addr on RT1010 */ @@ -341,7 +341,7 @@ status = "disabled"; }; - /* Remove SAI2, it does'nt exist on RT1010 */ + /* Remove SAI2, it doesn't exist on RT1010 */ /delete-node/ sai@40388000; }; }; diff --git a/dts/arm/nxp/nxp_rt1015.dtsi b/dts/arm/nxp/nxp_rt1015.dtsi index bf905168e10..c6bd1f59689 100644 --- a/dts/arm/nxp/nxp_rt1015.dtsi +++ b/dts/arm/nxp/nxp_rt1015.dtsi @@ -61,6 +61,8 @@ /delete-node/ gpio@4200c000; /* RT1015 has only one flexSPI controller */ /delete-node/ spi@402a4000; + /* Remove Ethernet, it doesn't exist on RT1015 */ + /delete-node/ enet@402d8000; }; }; diff --git a/dts/arm/nxp/nxp_rt1040.dtsi b/dts/arm/nxp/nxp_rt1040.dtsi index 70dd0b0d4ad..888d4eb1bd9 100644 --- a/dts/arm/nxp/nxp_rt1040.dtsi +++ b/dts/arm/nxp/nxp_rt1040.dtsi @@ -11,7 +11,7 @@ }; &sysclk { - clock-frequency = <500000000>; + clock-frequency = <528000000>; }; &ccm { @@ -20,10 +20,13 @@ }; arm-podf { - clock-div = <2>; + clock-div = <1>; }; }; +&gpt2 { + gptfreq = <33000000>; +}; / { soc { diff --git a/dts/arm/nxp/nxp_rt1060.dtsi b/dts/arm/nxp/nxp_rt1060.dtsi index e6148094192..8d308a27509 100644 --- a/dts/arm/nxp/nxp_rt1060.dtsi +++ b/dts/arm/nxp/nxp_rt1060.dtsi @@ -49,16 +49,29 @@ soc { /* i.MX rt1060 has a second Ethernet controller. */ enet2: ethernet@402d4000 { - compatible = "nxp,kinetis-ethernet"; - reg = <0x402D4000 0x628>; - interrupts = <152 0>; - interrupt-names = "COMMON"; - status = "disabled"; - ptp { - compatible = "nxp,kinetis-ptp"; + compatible = "nxp,enet"; + reg = <0x402d4000 0x628>; + clocks = <&ccm IMX_CCM_ENET_CLK 0 0>; + enet2_mac: ethernet { + compatible = "nxp,enet-mac"; + interrupts = <152 0>; + interrupt-names = "COMMON"; + nxp,mdio = <&enet2_mdio>; + nxp,ptp-clock = <&enet_ptp_clock>; + status = "disabled"; + }; + enet2_mdio: mdio { + compatible = "nxp,enet-mdio"; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + enet2_ptp_clock: ptp_clock { + compatible = "nxp,enet-ptp-clock"; status = "disabled"; interrupts = <153 0>; interrupt-names = "IEEE1588_TMR"; + clocks = <&ccm IMX_CCM_ENET_PLL 0 0>; }; }; diff --git a/dts/arm/nxp/nxp_rt10xx.dtsi b/dts/arm/nxp/nxp_rt10xx.dtsi index 714b4a303bd..fdc50c2b3e6 100644 --- a/dts/arm/nxp/nxp_rt10xx.dtsi +++ b/dts/arm/nxp/nxp_rt10xx.dtsi @@ -297,6 +297,15 @@ #clock-cells = <0>; }; + sys-pll { + compatible = "nxp,imx-ccm-fnpll"; + loop-div = <22>; + numerator = <0>; + denominator = <1>; + src = <0>; + #clock-cells = <0>; + }; + #clock-cells = <3>; }; @@ -767,18 +776,29 @@ }; }; - enet: ethernet@402d8000 { - compatible = "nxp,kinetis-ethernet"; + enet: enet@402d8000 { + compatible = "nxp,enet"; reg = <0x402D8000 0x628>; - interrupts = <114 0>; - interrupt-names = "COMMON"; - status = "disabled"; - phy-addr = <0>; - ptp: ptp { - compatible = "nxp,kinetis-ptp"; + 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>; 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>; - interrupt-names = "IEEE1588_TMR"; + status = "disabled"; + clocks = <&ccm IMX_CCM_ENET_PLL 0 0>; }; }; diff --git a/dts/arm/nxp/nxp_rt11xx.dtsi b/dts/arm/nxp/nxp_rt11xx.dtsi index 92f95a194ff..fc0a1690800 100644 --- a/dts/arm/nxp/nxp_rt11xx.dtsi +++ b/dts/arm/nxp/nxp_rt11xx.dtsi @@ -1,5 +1,5 @@ /* - * Copyright 2021,2023 NXP + * Copyright 2021,2023-2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -707,17 +707,28 @@ }; enet: ethernet@40424000 { - compatible = "nxp,kinetis-ethernet"; + compatible = "nxp,enet"; reg = <0x40424000 0x628>; - interrupts = <137 0>; - interrupt-names = "COMMON"; - status = "disabled"; - phy-addr = <2>; - ptp: ptp { - compatible = "nxp,kinetis-ptp"; + 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>; - interrupt-names = "IEEE1588_TMR"; + status = "disabled"; + clocks = <&ccm IMX_CCM_ENET_PLL 0 0>; }; }; @@ -797,6 +808,35 @@ reg = <0x40800000 0x4000>; interrupts = <56 1>; status = "disabled"; + source = <&mipi_csi2rx>; + + port { + csi_ep_in: endpoint { + remote-endpoint = <&mipi_csi2rx_ep_out>; + }; + }; + }; + + mipi_csi2rx: mipi_csi2rx@40810000 { + compatible = "nxp,mipi-csi2rx"; + reg = <0x40810000 0x200>; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + mipi_csi2rx_ep_out: endpoint { + remote-endpoint = <&csi_ep_in>; + }; + }; + + port@1 { + reg = <1>; + }; + }; }; flexcan1: can@400c4000 { @@ -867,6 +907,7 @@ offset-value-a = <10>; offset-value-b = <10>; #io-channel-cells = <1>; + clocks = <&ccm IMX_CCM_LPADC1_CLK 0 0>; }; lpadc1: lpadc@40054000 { @@ -882,6 +923,7 @@ offset-value-a = <10>; offset-value-b = <10>; #io-channel-cells = <1>; + clocks = <&ccm IMX_CCM_LPADC2_CLK 0 0>; }; acmp1: cmp@401a4000 { diff --git a/dts/arm/nxp/nxp_rt5xx_common.dtsi b/dts/arm/nxp/nxp_rt5xx_common.dtsi index 867d30cc8ee..95af8ca3177 100644 --- a/dts/arm/nxp/nxp_rt5xx_common.dtsi +++ b/dts/arm/nxp/nxp_rt5xx_common.dtsi @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023, NXP + * Copyright 2022-2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -13,6 +13,7 @@ #include #include #include +#include / { chosen { @@ -115,6 +116,7 @@ */ clkctl0: clkctl@1000 { + /* FIXME This chip does NOT have a syscon */ compatible = "nxp,lpc-syscon"; reg = <0x1000 0x1000>; #clock-cells = <1>; @@ -129,11 +131,24 @@ }; clkctl1: clkctl@21000 { + /* FIXME This chip does NOT have a syscon */ compatible = "nxp,lpc-syscon"; reg = <0x21000 0x1000>; #clock-cells = <1>; }; + rstctl0: reset@0 { + compatible = "nxp,rstctl"; + reg = <0x0 0x80>; + #reset-cells = <1>; + }; + + rstctl1: reset@20000 { + compatible = "nxp,rstctl"; + reg = <0x20000 0x80>; + #reset-cells = <1>; + }; + uuid: uuid@2f50 { compatible = "nxp,lpc-uid"; reg = <0x2f50 0x10>; @@ -214,6 +229,7 @@ reg = <0x106000 0x1000>; interrupts = <14 0>; clocks = <&clkctl1 MCUX_FLEXCOMM0_CLK>; + resets = <&rstctl1 NXP_SYSCON_RESET(0, 8)>; status = "disabled"; }; @@ -222,6 +238,7 @@ reg = <0x107000 0x1000>; interrupts = <15 0>; clocks = <&clkctl1 MCUX_FLEXCOMM1_CLK>; + resets = <&rstctl1 NXP_SYSCON_RESET(0, 9)>; status = "disabled"; }; @@ -230,6 +247,7 @@ reg = <0x108000 0x1000>; interrupts = <16 0>; clocks = <&clkctl1 MCUX_FLEXCOMM2_CLK>; + resets = <&rstctl1 NXP_SYSCON_RESET(0, 10)>; status = "disabled"; }; @@ -238,6 +256,7 @@ reg = <0x109000 0x1000>; interrupts = <17 0>; clocks = <&clkctl1 MCUX_FLEXCOMM3_CLK>; + resets = <&rstctl1 NXP_SYSCON_RESET(0, 11)>; status = "disabled"; }; @@ -246,6 +265,7 @@ reg = <0x122000 0x1000>; interrupts = <18 0>; clocks = <&clkctl1 MCUX_FLEXCOMM4_CLK>; + resets = <&rstctl1 NXP_SYSCON_RESET(0, 12)>; status = "disabled"; }; @@ -254,6 +274,7 @@ reg = <0x123000 0x1000>; interrupts = <19 0>; clocks = <&clkctl1 MCUX_FLEXCOMM5_CLK>; + resets = <&rstctl1 NXP_SYSCON_RESET(0, 13)>; status = "disabled"; }; @@ -262,6 +283,7 @@ reg = <0x124000 0x1000>; interrupts = <43 0>; clocks = <&clkctl1 MCUX_FLEXCOMM6_CLK>; + resets = <&rstctl1 NXP_SYSCON_RESET(0, 14)>; status = "disabled"; }; @@ -270,6 +292,7 @@ reg = <0x125000 0x1000>; interrupts = <44 0>; clocks = <&clkctl1 MCUX_FLEXCOMM7_CLK>; + resets = <&rstctl1 NXP_SYSCON_RESET(0, 15)>; status = "disabled"; }; @@ -278,6 +301,7 @@ reg = <0x127000 0x1000>; interrupts = <21 0>; clocks = <&clkctl1 MCUX_PMIC_I2C_CLK>; + resets = <&rstctl1 NXP_SYSCON_RESET(0, 23)>; status = "disabled"; }; @@ -286,6 +310,7 @@ reg = <0x209000 0x1000>; interrupts = <60 0>; clocks = <&clkctl1 MCUX_FLEXCOMM8_CLK>; + resets = <&rstctl1 NXP_SYSCON_RESET(0, 16)>; status = "disabled"; }; @@ -294,6 +319,7 @@ reg = <0x20a000 0x1000>; interrupts = <61 0>; clocks = <&clkctl1 MCUX_FLEXCOMM9_CLK>; + resets = <&rstctl1 NXP_SYSCON_RESET(0, 17)>; status = "disabled"; }; @@ -302,6 +328,7 @@ reg = <0x20b000 0x1000>; interrupts = <62 0>; clocks = <&clkctl1 MCUX_FLEXCOMM10_CLK>; + resets = <&rstctl1 NXP_SYSCON_RESET(0, 18)>; status = "disabled"; }; @@ -310,6 +337,7 @@ reg = <0x20c000 0x1000>; interrupts = <63 0>; clocks = <&clkctl1 MCUX_FLEXCOMM11_CLK>; + resets = <&rstctl1 NXP_SYSCON_RESET(0, 19)>; status = "disabled"; }; @@ -318,6 +346,7 @@ reg = <0x20d000 0x1000>; interrupts = <64 0>; clocks = <&clkctl1 MCUX_FLEXCOMM12_CLK>; + resets = <&rstctl1 NXP_SYSCON_RESET(0, 20)>; status = "disabled"; }; @@ -326,6 +355,7 @@ reg = <0x20e000 0x1000>; interrupts = <65 0>; clocks = <&clkctl1 MCUX_FLEXCOMM13_CLK>; + resets = <&rstctl1 NXP_SYSCON_RESET(0, 21)>; status = "disabled"; }; @@ -349,6 +379,7 @@ reg = <0x126000 0x1000>; interrupts = <20 0>; clocks = <&clkctl1 MCUX_HS_SPI_CLK>; + resets = <&rstctl1 NXP_SYSCON_RESET(0, 22)>; status = "disabled"; #address-cells = <1>; #size-cells = <0>; @@ -359,6 +390,7 @@ reg = <0x128000 0x1000>; interrupts = <66 0>; clocks = <&clkctl1 MCUX_HS_SPI1_CLK>; + resets = <&rstctl1 NXP_SYSCON_RESET(0, 24)>; status = "disabled"; #address-cells = <1>; #size-cells = <0>; @@ -542,6 +574,7 @@ offset-value-a = <10>; offset-value-b = <10>; #io-channel-cells = <1>; + clocks = <&clkctl1 MCUX_LPADC1_CLK>; }; smartdma: dma@27020 { @@ -655,6 +688,7 @@ num-channels = <4>; num-bits = <24>; clocks = <&clkctl1 MCUX_MRT_CLK>; + resets = <&rstctl1 NXP_SYSCON_RESET(2, 8)>; #address-cells = <1>; #size-cells = <0>; diff --git a/dts/arm/nxp/nxp_rt6xx_common.dtsi b/dts/arm/nxp/nxp_rt6xx_common.dtsi index 170622b068c..47d4258ee8e 100644 --- a/dts/arm/nxp/nxp_rt6xx_common.dtsi +++ b/dts/arm/nxp/nxp_rt6xx_common.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, NXP + * Copyright 2020, 2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -11,6 +11,7 @@ #include #include #include +#include / { chosen { @@ -99,6 +100,7 @@ */ clkctl0: clkctl@1000 { + /* FIXME This chip does NOT have a syscon */ compatible = "nxp,lpc-syscon"; reg = <0x1000 0x1000>; #clock-cells = <1>; @@ -113,11 +115,24 @@ }; clkctl1: clkctl@21000 { + /* FIXME This chip does NOT have a syscon */ compatible = "nxp,lpc-syscon"; reg = <0x21000 0x1000>; #clock-cells = <1>; }; + rstctl0: reset@0 { + compatible = "nxp,rstctl"; + reg = <0x0 0x80>; + #reset-cells = <1>; + }; + + rstctl1: reset@20000 { + compatible = "nxp,rstctl"; + reg = <0x20000 0x80>; + #reset-cells = <1>; + }; + uuid: uuid@2f50 { compatible = "nxp,lpc-uid"; reg = <0x2f50 0x10>; @@ -190,6 +205,7 @@ reg = <0x106000 0x1000>; interrupts = <14 0>; clocks = <&clkctl1 MCUX_FLEXCOMM0_CLK>; + resets = <&rstctl1 NXP_SYSCON_RESET(0, 8)>; status = "disabled"; }; @@ -198,6 +214,7 @@ reg = <0x107000 0x1000>; interrupts = <15 0>; clocks = <&clkctl1 MCUX_FLEXCOMM1_CLK>; + resets = <&rstctl1 NXP_SYSCON_RESET(0, 9)>; status = "disabled"; }; @@ -206,6 +223,7 @@ reg = <0x108000 0x1000>; interrupts = <16 0>; clocks = <&clkctl1 MCUX_FLEXCOMM2_CLK>; + resets = <&rstctl1 NXP_SYSCON_RESET(0, 10)>; status = "disabled"; }; @@ -214,6 +232,7 @@ reg = <0x109000 0x1000>; interrupts = <17 0>; clocks = <&clkctl1 MCUX_FLEXCOMM3_CLK>; + resets = <&rstctl1 NXP_SYSCON_RESET(0, 11)>; status = "disabled"; }; @@ -222,6 +241,7 @@ reg = <0x122000 0x1000>; interrupts = <18 0>; clocks = <&clkctl1 MCUX_FLEXCOMM4_CLK>; + resets = <&rstctl1 NXP_SYSCON_RESET(0, 12)>; status = "disabled"; }; @@ -230,6 +250,7 @@ reg = <0x123000 0x1000>; interrupts = <19 0>; clocks = <&clkctl1 MCUX_FLEXCOMM5_CLK>; + resets = <&rstctl1 NXP_SYSCON_RESET(0, 13)>; status = "disabled"; }; @@ -238,6 +259,7 @@ reg = <0x124000 0x1000>; interrupts = <43 0>; clocks = <&clkctl1 MCUX_FLEXCOMM6_CLK>; + resets = <&rstctl1 NXP_SYSCON_RESET(0, 14)>; status = "disabled"; }; @@ -246,6 +268,7 @@ reg = <0x125000 0x1000>; interrupts = <44 0>; clocks = <&clkctl1 MCUX_FLEXCOMM7_CLK>; + resets = <&rstctl1 NXP_SYSCON_RESET(0, 15)>; status = "disabled"; }; @@ -254,6 +277,7 @@ reg = <0x127000 0x1000>; interrupts = <21 0>; clocks = <&clkctl1 MCUX_PMIC_I2C_CLK>; + resets = <&rstctl1 NXP_SYSCON_RESET(0, 23)>; status = "disabled"; }; @@ -276,6 +300,7 @@ reg = <0x126000 0x1000>; interrupts = <20 0>; clocks = <&clkctl1 MCUX_HS_SPI_CLK>; + resets = <&rstctl1 NXP_SYSCON_RESET(0, 22)>; status = "disabled"; #address-cells = <1>; #size-cells = <0>; @@ -387,6 +412,7 @@ offset-value-a = <10>; offset-value-b = <10>; #io-channel-cells = <1>; + clocks = <&clkctl1 MCUX_LPADC1_CLK>; }; ctimer0: ctimer@28000 { @@ -469,6 +495,7 @@ num-channels = <4>; num-bits = <24>; clocks = <&clkctl1 MCUX_MRT_CLK>; + resets = <&rstctl1 NXP_SYSCON_RESET(2, 8)>; #address-cells = <1>; #size-cells = <0>; diff --git a/dts/arm/nxp/nxp_rw6xx_common.dtsi b/dts/arm/nxp/nxp_rw6xx_common.dtsi index d78879e107a..b02f5fe2814 100644 --- a/dts/arm/nxp/nxp_rw6xx_common.dtsi +++ b/dts/arm/nxp/nxp_rw6xx_common.dtsi @@ -9,6 +9,8 @@ #include #include #include +#include +#include / { chosen { @@ -18,6 +20,7 @@ cpus { #address-cells = <1>; #size-cells = <0>; + cpu-power-states = <&idle &suspend>; cpu0: cpu@0 { compatible = "arm,cortex-m33f"; @@ -30,6 +33,28 @@ reg = <0xe000ed90 0x40>; }; }; + + power-states { + /* Idle mode maps to Power Mode 1 */ + idle: idle { + compatible = "zephyr,power-state"; + power-state-name = "runtime-idle"; + min-residency-us = <0>; + exit-latency-us = <0>; + }; + /* Suspend mode maps to Power Mode 2 */ + suspend: suspend { + compatible = "nxp,pdcfg-power", "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + min-residency-us = <500>; + exit-latency-us = <120>; + deep-sleep-config = <0x180000>, + <0x0>, + <0x4>, + <0x100>, + <0x0>; + }; + }; }; }; @@ -53,6 +78,7 @@ #size-cells = <1>; clkctl0: clkctl@1000 { + /* FIXME This chip does NOT have a syscon */ compatible = "nxp,lpc-syscon"; reg = <0x1000 0x1000>; #clock-cells = <1>; @@ -65,11 +91,24 @@ }; clkctl1: clkctl@21000 { + /* FIXME This chip does NOT have a syscon */ compatible = "nxp,lpc-syscon"; reg = <0x21000 0x1000>; #clock-cells = <1>; }; + rstctl0: reset@0 { + compatible = "nxp,rstctl"; + reg = <0x0 0x80>; + #reset-cells = <1>; + }; + + rstctl1: reset@20000 { + compatible = "nxp,rstctl"; + reg = <0x20000 0x80>; + #reset-cells = <1>; + }; + pmu: pmu@31000 { reg = <0x31000 0x130>; compatible = "nxp,rw-pmu"; @@ -122,6 +161,7 @@ reg = <0x106000 0x1000>; interrupts = <14 0>; clocks = <&clkctl1 MCUX_FLEXCOMM0_CLK>; + resets = <&rstctl1 NXP_SYSCON_RESET(0, 8)>; dmas = <&dma0 0>, <&dma0 1>; dma-names = "rx", "tx"; status = "disabled"; @@ -132,6 +172,7 @@ reg = <0x107000 0x1000>; interrupts = <15 0>; clocks = <&clkctl1 MCUX_FLEXCOMM1_CLK>; + resets = <&rstctl1 NXP_SYSCON_RESET(0, 9)>; dmas = <&dma0 2>, <&dma0 3>; dma-names = "rx", "tx"; status = "disabled"; @@ -142,6 +183,7 @@ reg = <0x108000 0x1000>; interrupts = <16 0>; clocks = <&clkctl1 MCUX_FLEXCOMM2_CLK>; + resets = <&rstctl1 NXP_SYSCON_RESET(0, 10)>; dmas = <&dma0 4>, <&dma0 5>; dma-names = "rx", "tx"; status = "disabled"; @@ -152,6 +194,7 @@ reg = <0x109000 0x1000>; interrupts = <17 0>; clocks = <&clkctl1 MCUX_FLEXCOMM3_CLK>; + resets = <&rstctl1 NXP_SYSCON_RESET(0, 11)>; dmas = <&dma0 6>, <&dma0 7>; dma-names = "rx", "tx"; status = "disabled"; @@ -162,6 +205,7 @@ reg = <0x126000 0x2000>; interrupts = <20 0>; clocks = <&clkctl1 MCUX_FLEXCOMM14_CLK>; + resets = <&rstctl1 NXP_SYSCON_RESET(0, 22)>; dmas = <&dma0 26>, <&dma0 27>; dma-names = "rx", "tx"; status = "disabled"; @@ -266,6 +310,7 @@ num-channels = <4>; num-bits = <24>; clocks = <&clkctl1 MCUX_MRT_CLK>; + resets = <&rstctl1 NXP_SYSCON_RESET(2, 8)>; #address-cells = <1>; #size-cells = <0>; @@ -298,6 +343,7 @@ num-channels = <4>; num-bits = <24>; clocks = <&clkctl1 MCUX_FREEMRT_CLK>; + resets = <&rstctl0 NXP_SYSCON_RESET(2, 26)>; #address-cells = <1>; #size-cells = <0>; @@ -361,6 +407,42 @@ }; }; + gau { + ranges = <>; + #address-cells = <1>; + #size-cells = <1>; + + adc0: gau_adc0@38000 { + compatible = "nxp,gau-adc"; + reg = <0x38000 0x100>; + interrupts = <112 0>; + status = "disabled"; + #io-channel-cells = <1>; + }; + + adc1: gau_adc1@38100 { + compatible = "nxp,gau-adc"; + reg = <0x38100 0x100>; + interrupts = <111 0>; + status = "disabled"; + #io-channel-cells = <1>; + }; + + dac0: dac@38200 { + compatible = "nxp,gau-dac"; + reg = <0x38200 0x30>; + interrupts = <108 0>; + status = "disabled"; + #io-channel-cells = <0>; + }; + }; + + os_timer: timers@13b000 { + compatible = "nxp,os-timer"; + reg = <0x13b000 0x1000>; + interrupts = <41 0>; + status = "disabled"; + }; }; &flexspi { diff --git a/dts/arm/nxp/nxp_s32k1xx.dtsi b/dts/arm/nxp/nxp_s32k1xx.dtsi index d6c63c5db5d..f7113332b5a 100644 --- a/dts/arm/nxp/nxp_s32k1xx.dtsi +++ b/dts/arm/nxp/nxp_s32k1xx.dtsi @@ -243,7 +243,7 @@ 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>; + clocks = <&clock NXP_S32_FTM0_CLK>; prescaler = <1>; status = "disabled"; }; @@ -253,7 +253,7 @@ 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>; + clocks = <&clock NXP_S32_FTM1_CLK>; prescaler = <1>; status = "disabled"; }; @@ -263,7 +263,7 @@ 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>; + clocks = <&clock NXP_S32_FTM2_CLK>; prescaler = <1>; status = "disabled"; }; @@ -273,7 +273,7 @@ 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>; + clocks = <&clock NXP_S32_FTM3_CLK>; prescaler = <1>; status = "disabled"; }; @@ -283,7 +283,7 @@ 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>; + clocks = <&clock NXP_S32_FTM4_CLK>; prescaler = <1>; status = "disabled"; }; @@ -293,7 +293,7 @@ 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>; + clocks = <&clock NXP_S32_FTM5_CLK>; prescaler = <1>; status = "disabled"; }; @@ -303,7 +303,6 @@ 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"; }; @@ -313,7 +312,6 @@ 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"; }; @@ -323,8 +321,8 @@ reg = <0x4003d000 0x1000>; interrupts = <46 0>, <47 0>; interrupt-names = "alarm", "seconds"; - clock-frequency = <32768>; - prescaler = <32768>; + clock-frequency = <32000>; + prescaler = <32000>; }; }; }; diff --git a/dts/arm/renesas/smartbond/da1469x.dtsi b/dts/arm/renesas/smartbond/da1469x.dtsi index ae523ae6719..fe589f52fb1 100644 --- a/dts/arm/renesas/smartbond/da1469x.dtsi +++ b/dts/arm/renesas/smartbond/da1469x.dtsi @@ -28,6 +28,16 @@ compatible = "arm,cortex-m33f"; reg = <0>; clock-frequency = <32000000>; + cpu-power-states = <&standby>; + }; + + power-states { + standby: standby { + compatible = "zephyr,power-state"; + power-state-name = "standby"; + min-residency-us = <500>; + exit-latency-us = <100>; + }; }; }; @@ -36,7 +46,6 @@ rc32k: rc32k { compatible = "renesas,smartbond-lp-osc"; clock-frequency = ; - calibration-interval = <1>; #clock-cells = <0>; status = "okay"; }; @@ -50,7 +59,6 @@ rcx: rcx { compatible = "renesas,smartbond-lp-osc"; clock-frequency = ; - calibration-interval = <1>; #clock-cells = <0>; status = "disabled"; }; @@ -143,6 +151,13 @@ compatible = "mmio-sram"; }; + psram: memory@32000000 { + compatible = "zephyr,memory-region"; + device_type = "memory"; + reg = <0x32000000 DT_SIZE_K(32768)>; + zephyr,memory-region = "PSRAM"; + }; + qspif: memory@16000000 { compatible = "zephyr,memory-region"; reg = <0x16000000 DT_SIZE_K(32768)>; @@ -262,6 +277,7 @@ reg = <0x50020100 0x100>; periph-clock-config = <0x02>; interrupts = <6 0>; + hw-flow-control-supported; status = "disabled"; }; @@ -270,6 +286,7 @@ reg = <0x50020200 0x100>; periph-clock-config = <0x08>; interrupts = <7 0>; + hw-flow-control-supported; status = "disabled"; }; @@ -370,6 +387,12 @@ block-count = <1>; #dma-cells = <0>; }; + + memc: qspic2@34000000 { + compatible = "renesas,smartbond-nor-psram"; + reg = <0x34000000 0x48>; + status = "disabled"; + }; }; }; diff --git a/dts/arm/silabs/efr32mg24-pinctrl.dtsi b/dts/arm/silabs/efr32mg24-pinctrl.dtsi index 3c4a69aa03f..c8f2e6c3c77 100644 --- a/dts/arm/silabs/efr32mg24-pinctrl.dtsi +++ b/dts/arm/silabs/efr32mg24-pinctrl.dtsi @@ -16,4 +16,13 @@ ; }; }; + + i2c0_default: i2c0_default { + group1 { + psels = , + , + , + ; + }; + }; }; diff --git a/dts/arm/silabs/efr32xg12p-pinctrl.dtsi b/dts/arm/silabs/efr32xg12p-pinctrl.dtsi deleted file mode 100644 index e500e3b18bd..00000000000 --- a/dts/arm/silabs/efr32xg12p-pinctrl.dtsi +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2022 Silicon Labs - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include - -&pinctrl { - /* configuration for uart0 device, default state */ - usart0_default: usart0_default { - group1 { - /* configure PA.1 as UART_RX */ - psels = , - ; - }; - group2 { - /* configure PA.0 as UART_TX */ - psels = , - ; - }; - }; -}; diff --git a/dts/arm/st/c0/stm32c0.dtsi b/dts/arm/st/c0/stm32c0.dtsi index fd37b14b5f9..f7e58c7b699 100644 --- a/dts/arm/st/c0/stm32c0.dtsi +++ b/dts/arm/st/c0/stm32c0.dtsi @@ -1,5 +1,6 @@ /* * Copyright (c) 2023 Benjamin Bjƶrnsson + * Copyright (c) 2024 STMicroelectronics * * SPDX-License-Identifier: Apache-2.0 */ @@ -154,6 +155,8 @@ interrupts = <2 0>; clocks = <&rcc STM32_CLOCK_BUS_APB1 0x00000400>; prescaler = <32768>; + alarms-count = <1>; + alrm-exti-line = <19>; status = "disabled"; }; diff --git a/dts/arm/st/c0/stm32c011.dtsi b/dts/arm/st/c0/stm32c011.dtsi new file mode 100644 index 00000000000..a3196138478 --- /dev/null +++ b/dts/arm/st/c0/stm32c011.dtsi @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2024 Kickmaker + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + soc { + compatible = "st,stm32c011", "st,stm32c0", "simple-bus"; + }; +}; diff --git a/dts/arm/st/c0/stm32c011X6.dtsi b/dts/arm/st/c0/stm32c011X6.dtsi new file mode 100644 index 00000000000..d5be6b7e7d8 --- /dev/null +++ b/dts/arm/st/c0/stm32c011X6.dtsi @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2024 Kickmaker + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + sram0: memory@20000000 { + reg = <0x20000000 DT_SIZE_K(6)>; + }; + + soc { + flash-controller@40022000 { + flash0: flash@8000000 { + reg = <0x08000000 DT_SIZE_K(32)>; + }; + }; + }; +}; diff --git a/dts/arm/st/f0/stm32f0.dtsi b/dts/arm/st/f0/stm32f0.dtsi index 0371ac75ac6..5f25181e657 100644 --- a/dts/arm/st/f0/stm32f0.dtsi +++ b/dts/arm/st/f0/stm32f0.dtsi @@ -1,6 +1,7 @@ /* * Copyright (c) 2017 RnDity Sp. z o.o. * Copyright (c) 2019 Centaur Analytics, Inc + * Copyright (c) 2024 STMicroelectronics * * SPDX-License-Identifier: Apache-2.0 */ @@ -210,6 +211,8 @@ clocks = <&rcc STM32_CLOCK_BUS_APB1 0x10000000>; interrupts = <2 0>; prescaler = <32768>; + alarms-count = <1>; + alrm-exti-line = <17>; status = "disabled"; }; diff --git a/dts/arm/st/f2/stm32f2.dtsi b/dts/arm/st/f2/stm32f2.dtsi index 9c913756919..8af21aaa468 100644 --- a/dts/arm/st/f2/stm32f2.dtsi +++ b/dts/arm/st/f2/stm32f2.dtsi @@ -1,6 +1,7 @@ /* * Copyright (c) 2018 qianfan Zhao * Copyright (c) 2019 Centaur Analytics, Inc + * Copyright (c) 2024 STMicroelectronics * * SPDX-License-Identifier: Apache-2.0 */ @@ -202,6 +203,8 @@ clocks = <&rcc STM32_CLOCK_BUS_APB1 0x10000000>; interrupts = <41 0>; prescaler = <32768>; + alarms-count = <2>; + alrm-exti-line = <17>; status = "disabled"; bbram: backup_regs { diff --git a/dts/arm/st/f3/stm32f3.dtsi b/dts/arm/st/f3/stm32f3.dtsi index 725ed0eacb6..07ed6f9dc26 100644 --- a/dts/arm/st/f3/stm32f3.dtsi +++ b/dts/arm/st/f3/stm32f3.dtsi @@ -1,6 +1,7 @@ /* * Copyright (c) 2017 I-SENSE group of ICCS * Copyright (c) 2019 Centaur Analytics, Inc + * Copyright (c) 2024 STMicroelectronics * * SPDX-License-Identifier: Apache-2.0 */ @@ -410,6 +411,8 @@ clocks = <&rcc STM32_CLOCK_BUS_APB1 0x10000000>; interrupts = <41 0>; prescaler = <32768>; + alarms-count = <2>; + alrm-exti-line = <17>; status = "disabled"; }; diff --git a/dts/arm/st/f4/stm32f4.dtsi b/dts/arm/st/f4/stm32f4.dtsi index 231c8b988f8..b69d32d6cf3 100644 --- a/dts/arm/st/f4/stm32f4.dtsi +++ b/dts/arm/st/f4/stm32f4.dtsi @@ -2,6 +2,7 @@ * Copyright (c) 2017 Linaro Limited * Copyright (c) 2019 Centaur Analytics, Inc * Copyright (c) 2022 Valerio Setti + * Copyright (c) 2024 STMicroelectronics * * SPDX-License-Identifier: Apache-2.0 */ @@ -515,6 +516,8 @@ interrupts = <41 0>; clocks = <&rcc STM32_CLOCK_BUS_APB1 0x10000000>; prescaler = <32768>; + alarms-count = <2>; + alrm-exti-line = <17>; status = "disabled"; bbram: backup_regs { diff --git a/dts/arm/st/f4/stm32f446.dtsi b/dts/arm/st/f4/stm32f446.dtsi index 2756b2abd80..f979a30ff66 100644 --- a/dts/arm/st/f4/stm32f446.dtsi +++ b/dts/arm/st/f4/stm32f446.dtsi @@ -106,6 +106,38 @@ status = "disabled"; }; + adc2: adc@40012100 { + compatible = "st,stm32-adc"; + reg = <0x40012100 0x050>; + clocks = <&rcc STM32_CLOCK_BUS_APB2 0x00000200>; + interrupts = <18 0>; + status = "disabled"; + #io-channel-cells = <1>; + resolutions = ; + sampling-times = <3 15 28 56 84 112 144 480>; + st,adc-clock-source = ; + st,adc-sequencer = ; + }; + + adc3: adc@40012200 { + compatible = "st,stm32-adc"; + reg = <0x40012200 0x050>; + clocks = <&rcc STM32_CLOCK_BUS_APB2 0x00000400>; + interrupts = <18 0>; + status = "disabled"; + #io-channel-cells = <1>; + resolutions = ; + sampling-times = <3 15 28 56 84 112 144 480>; + st,adc-clock-source = ; + st,adc-sequencer = ; + }; + dac1: dac@40007400 { compatible = "st,stm32-dac"; reg = <0x40007400 0x400>; diff --git a/dts/arm/st/f7/stm32f7.dtsi b/dts/arm/st/f7/stm32f7.dtsi index 600f959b4fd..439bc560a7d 100644 --- a/dts/arm/st/f7/stm32f7.dtsi +++ b/dts/arm/st/f7/stm32f7.dtsi @@ -1,6 +1,7 @@ /* * Copyright (c) 2018 Yurii Hamann * Copyright (c) 2019 Centaur Analytics, Inc + * Copyright (c) 2024 STMicroelectronics * * SPDX-License-Identifier: Apache-2.0 */ @@ -44,10 +45,10 @@ }; }; - quadspi_memory: memory@90000000 { + quadspi_memory: memory-placeholder@90000000 { compatible = "zephyr,memory-region", "mmio-sram"; reg = <0x90000000 DT_SIZE_M(256)>; - zephyr,memory-region = "QSPI"; + zephyr,memory-region = "QSPI_PLACEHOLDER"; zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_EXTMEM) )>; }; @@ -713,7 +714,8 @@ num-bidir-endpoints = <9>; ram-size = <4096>; maximum-speed = "full-speed"; - clocks = <&rcc STM32_CLOCK_BUS_AHB1 0x20000000>; + clocks = <&rcc STM32_CLOCK_BUS_AHB1 0x20000000>, + <&rcc STM32_SRC_PLL_Q CK48M_SEL(0)>; phys = <&otghs_fs_phy>; status = "disabled"; }; @@ -724,6 +726,8 @@ interrupts = <41 0>; clocks = <&rcc STM32_CLOCK_BUS_APB1 0x10000000>; prescaler = <32768>; + alarms-count = <2>; + alrm-exti-line = <17>; status = "disabled"; bbram: backup_regs { diff --git a/dts/arm/st/g0/stm32g0.dtsi b/dts/arm/st/g0/stm32g0.dtsi index bfa023d027d..89c6944e6a4 100644 --- a/dts/arm/st/g0/stm32g0.dtsi +++ b/dts/arm/st/g0/stm32g0.dtsi @@ -1,6 +1,6 @@ /* * Copyright (c) 2019 Philippe Retornaz - * Copyright (c) 2019 ST Microelectronics + * Copyright (c) 2019-2024 STMicroelectronics * Copyright (c) 2019 Centaur Analytics, Inc * Copyright (C) 2020 Framework Computer LLC * Copyright (c) 2021 G-Technologies Sdn. Bhd. @@ -189,6 +189,8 @@ interrupts = <2 0>; clocks = <&rcc STM32_CLOCK_BUS_APB1 0x00000400>; prescaler = <32768>; + alarms-count = <2>; + alrm-exti-line = <19>; status = "disabled"; }; diff --git a/dts/arm/st/g4/stm32g4.dtsi b/dts/arm/st/g4/stm32g4.dtsi index 1450efbee38..8cba3a58021 100644 --- a/dts/arm/st/g4/stm32g4.dtsi +++ b/dts/arm/st/g4/stm32g4.dtsi @@ -1,6 +1,7 @@ /* * Copyright (c) 2021 The Chromium OS Authors * Copyright (c) 2019 Richard Osterloh + * Copyright (c) 2024 STMicroelectronics * * SPDX-License-Identifier: Apache-2.0 */ @@ -598,6 +599,8 @@ interrupts = <41 0>; clocks = <&rcc STM32_CLOCK_BUS_APB1 0x00000400>; prescaler = <32768>; + alarms-count = <2>; + alrm-exti-line = <17>; status = "disabled"; }; diff --git a/dts/arm/st/h5/stm32h5.dtsi b/dts/arm/st/h5/stm32h5.dtsi index e154aa8d9de..64a2ac37fee 100644 --- a/dts/arm/st/h5/stm32h5.dtsi +++ b/dts/arm/st/h5/stm32h5.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 STMicroelectronics + * Copyright (c) 2023-2024 STMicroelectronics * * SPDX-License-Identifier: Apache-2.0 */ @@ -308,6 +308,8 @@ interrupts = <2 0>; clocks = <&rcc STM32_CLOCK_BUS_APB3 0x00200000>; prescaler = <32768>; + alarms-count = <2>; + alrm-exti-line = <17>; status = "disabled"; }; @@ -495,6 +497,13 @@ <&rcc STM32_CLOCK_BUS_AHB1 0x00100000>, <&rcc STM32_CLOCK_BUS_AHB1 0x00200000>; status = "disabled"; + + mdio: mdio { + compatible = "st,stm32-mdio"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; }; gpdma1: dma@40020000 { diff --git a/dts/arm/st/h5/stm32h562.dtsi b/dts/arm/st/h5/stm32h562.dtsi index a7c5ae93ff4..0a52c12fc0e 100644 --- a/dts/arm/st/h5/stm32h562.dtsi +++ b/dts/arm/st/h5/stm32h562.dtsi @@ -6,6 +6,8 @@ #include #include +/* keep both header files for compatibility */ +#include / { clocks { @@ -65,12 +67,12 @@ status = "disabled"; }; - lptim4: timers@44004C00 { + lptim4: timers@44004c00 { compatible = "st,stm32-lptim"; clocks = <&rcc STM32_CLOCK_BUS_APB3 0x2000>; #address-cells = <1>; #size-cells = <0>; - reg = <0x44004C00 0x400>; + reg = <0x44004c00 0x400>; interrupts = <128 1>; interrupt-names = "wakeup"; status = "disabled"; @@ -224,11 +226,11 @@ status = "disabled"; }; - octospi1: octospi@47001400 { - compatible = "st,stm32-ospi"; + xspi1: xspi@47001400 { + compatible = "st,stm32-xspi"; reg = <0x47001400 0x400>; interrupts = <78 0>; - clock-names = "ospix", "ospi-ker"; + clock-names = "xspix", "xspi-ker"; clocks = <&rcc STM32_CLOCK_BUS_AHB4 0x00100000>, <&rcc STM32_SRC_PLL1_Q OCTOSPI1_SEL(1)>; #address-cells = <1>; @@ -376,6 +378,16 @@ bosch,mram-cfg = <0x350 28 8 3 3 0 3 3>; status = "disabled"; }; + + sdmmc1: sdmmc@46008000 { + compatible = "st,stm32-sdmmc"; + reg = <0x46008000 0x400>; + clocks = <&rcc STM32_CLOCK_BUS_AHB4 0x00000800>, + <&rcc STM32_SRC_PLL1_Q SDMMC1_SEL(0)>; + resets = <&rctl STM32_RESET(AHB4, 11U)>; + interrupts = <79 0>; + status = "disabled"; + }; }; smbus3: smbus3 { diff --git a/dts/arm/st/h5/stm32h563.dtsi b/dts/arm/st/h5/stm32h563.dtsi index e8b2dadf2df..47479429973 100644 --- a/dts/arm/st/h5/stm32h563.dtsi +++ b/dts/arm/st/h5/stm32h563.dtsi @@ -9,5 +9,15 @@ / { soc { compatible = "st,stm32h563", "st,stm32h5", "simple-bus"; + + sdmmc2: sdmmc@46008c00 { + compatible = "st,stm32-sdmmc"; + reg = <0x46008c00 0x400>; + clocks = <&rcc STM32_CLOCK_BUS_AHB4 0x00001000>, + <&rcc STM32_SRC_PLL1_Q SDMMC2_SEL(0)>; + resets = <&rctl STM32_RESET(AHB4, 12U)>; + interrupts = <102 0>; + status = "disabled"; + }; }; }; diff --git a/dts/arm/st/h7/stm32h7.dtsi b/dts/arm/st/h7/stm32h7.dtsi index 95c5590a871..c9b8d5e4f96 100644 --- a/dts/arm/st/h7/stm32h7.dtsi +++ b/dts/arm/st/h7/stm32h7.dtsi @@ -2,6 +2,7 @@ * Copyright (c) 2019 Linaro Limited * Copyright (c) 2019 Centaur Analytics, Inc * Copyright (c) 2020 Teslabs Engineering S.L. + * Copyright (c) 2024 STMicroelectronics * * SPDX-License-Identifier: Apache-2.0 */ @@ -352,6 +353,8 @@ interrupts = <41 0>; clocks = <&rcc STM32_CLOCK_BUS_APB4 0x00010000>; prescaler = <32768>; + alarms-count = <2>; + alrm-exti-line = <17>; status = "disabled"; }; @@ -1015,6 +1018,13 @@ <&rcc STM32_CLOCK_BUS_AHB1 0x00010000>, <&rcc STM32_CLOCK_BUS_AHB1 0x00020000>; status = "disabled"; + + mdio: mdio { + compatible = "st,stm32-mdio"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; }; fmc: memory-controller@52004000 { @@ -1048,6 +1058,15 @@ clocks = <&rcc STM32_CLOCK_BUS_AHB3 0x00004000>; status = "disabled"; }; + + dcmi: dcmi@48020000 { + compatible = "st,stm32-dcmi"; + reg = <0x48020000 0x400>; + interrupts = <78 0>; + interrupt-names = "dcmi"; + clocks = <&rcc STM32_CLOCK_BUS_AHB2 0x00000001>; + status = "disabled"; + }; }; die_temp: dietemp { diff --git a/dts/arm/st/l0/stm32l0.dtsi b/dts/arm/st/l0/stm32l0.dtsi index 91d290d0d08..f515f9c3166 100644 --- a/dts/arm/st/l0/stm32l0.dtsi +++ b/dts/arm/st/l0/stm32l0.dtsi @@ -97,6 +97,8 @@ interrupts = <2 0>; clocks = <&rcc STM32_CLOCK_BUS_APB1 0x10000000>; prescaler = <32768>; + alarms-count = <2>; + alrm-exti-line = <17>; status = "disabled"; bbram: backup_regs { diff --git a/dts/arm/st/l1/stm32l1.dtsi b/dts/arm/st/l1/stm32l1.dtsi index 1f6f0644819..3816489f42f 100644 --- a/dts/arm/st/l1/stm32l1.dtsi +++ b/dts/arm/st/l1/stm32l1.dtsi @@ -1,6 +1,7 @@ /* * Copyright (c) 2019 Linaro Ltd. * Copyright (c) 2019 Centaur Analytics, Inc + * Copyright (c) 2024 STMicroelectronics * * SPDX-License-Identifier: Apache-2.0 */ @@ -118,6 +119,8 @@ interrupts = <41 0>; clocks = <&rcc STM32_CLOCK_BUS_APB1 0x10000000>; prescaler = <32768>; + alarms-count = <2>; + alrm-exti-line = <17>; status = "disabled"; }; diff --git a/dts/arm/st/l4/stm32l4.dtsi b/dts/arm/st/l4/stm32l4.dtsi index 7dcabdf877c..e6e87879b95 100644 --- a/dts/arm/st/l4/stm32l4.dtsi +++ b/dts/arm/st/l4/stm32l4.dtsi @@ -1,6 +1,7 @@ /* * Copyright (c) 2017 Linaro Limited * Copyright (c) 2019 Centaur Analytics, Inc + * Copyright (c) 2024 STMicroelectronics * * SPDX-License-Identifier: Apache-2.0 */ @@ -380,6 +381,8 @@ interrupts = <41 0>; clocks = <&rcc STM32_CLOCK_BUS_APB1 0x10000000>; prescaler = <32768>; + alarms-count = <2>; + alrm-exti-line = <18>; status = "disabled"; }; diff --git a/dts/arm/st/l4/stm32l475Xe.dtsi b/dts/arm/st/l4/stm32l475Xe.dtsi index 86442f8b762..0cb93cac5a7 100644 --- a/dts/arm/st/l4/stm32l475Xe.dtsi +++ b/dts/arm/st/l4/stm32l475Xe.dtsi @@ -8,7 +8,10 @@ / { sram0: memory@20000000 { - reg = <0x20000000 DT_SIZE_K(128)>; + reg = <0x20000000 DT_SIZE_K(96)>; + }; + sram1: memory@10000000 { + reg = <0x10000000 DT_SIZE_K(32)>; }; soc { diff --git a/dts/arm/st/l5/stm32l5.dtsi b/dts/arm/st/l5/stm32l5.dtsi index f9c37b33cd8..d4f7a7f000b 100644 --- a/dts/arm/st/l5/stm32l5.dtsi +++ b/dts/arm/st/l5/stm32l5.dtsi @@ -1,6 +1,7 @@ /* * Copyright (c) 2021 The Chromium OS Authors * Copyright (c) 2020 Linaro Limited + * Copyright (c) 2024 STMicroelectronics * * SPDX-License-Identifier: Apache-2.0 */ @@ -460,6 +461,8 @@ interrupts = <2 0>; clocks = <&rcc STM32_CLOCK_BUS_APB1 0x00000400>; prescaler = <32768>; + alarms-count = <2>; + alrm-exti-line = <17>; status = "disabled"; }; diff --git a/dts/arm/st/u5/stm32u5.dtsi b/dts/arm/st/u5/stm32u5.dtsi index bd9bb445858..642431a52ec 100644 --- a/dts/arm/st/u5/stm32u5.dtsi +++ b/dts/arm/st/u5/stm32u5.dtsi @@ -2,6 +2,7 @@ * Copyright (c) 2021 The Chromium OS Authors * Copyright (c) 2021 Linaro Limited * Copyright (c) 2023 PSICONTROL nv + * Copyright (c) 2024 STMicroelectronics * * SPDX-License-Identifier: Apache-2.0 */ @@ -475,6 +476,7 @@ interrupts = <2 0>; clocks = <&rcc STM32_CLOCK_BUS_APB3 0x00200000>; prescaler = <32768>; + alarms-count = <2>; status = "disabled"; }; diff --git a/dts/arm/st/wb/stm32wb.dtsi b/dts/arm/st/wb/stm32wb.dtsi index d76f2f243f7..acd8d3c0fd8 100644 --- a/dts/arm/st/wb/stm32wb.dtsi +++ b/dts/arm/st/wb/stm32wb.dtsi @@ -1,6 +1,7 @@ /* * Copyright (c) 2019 Linaro Limited * Copyright (c) 2019 Centaur Analytics, Inc + * Copyright (c) 2024 STMicroelectronics * * SPDX-License-Identifier: Apache-2.0 */ @@ -285,6 +286,8 @@ interrupts = <41 0>; clocks = <&rcc STM32_CLOCK_BUS_APB1 0x00000400>; prescaler = <32768>; + alarms-count = <2>; + alrm-exti-line = <17>; status = "disabled"; bbram: backup_regs { diff --git a/dts/arm/st/wba/stm32wba.dtsi b/dts/arm/st/wba/stm32wba.dtsi index 0039b1500a1..05efb0a9431 100644 --- a/dts/arm/st/wba/stm32wba.dtsi +++ b/dts/arm/st/wba/stm32wba.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 STMicroelectronics + * Copyright (c) 2023-2024 STMicroelectronics * * SPDX-License-Identifier: Apache-2.0 */ @@ -212,6 +212,7 @@ reg = <0x46007800 0x400>; interrupts = <2 0>; clocks = <&rcc STM32_CLOCK_BUS_APB7 0x00200000>; + alarms-count = <2>; status = "disabled"; }; @@ -447,9 +448,9 @@ status = "disabled"; }; - rng: rng@520c0800 { + rng: rng@420c0800 { compatible = "st,stm32-rng"; - reg = <0x520c0800 0x400>; + reg = <0x420c0800 0x400>; interrupts = <59 0>; clocks = <&rcc STM32_CLOCK_BUS_AHB2 0x00040000>, <&rcc STM32_SRC_HSI16 RNG_SEL(2)>; diff --git a/dts/arm/st/wl/stm32wl.dtsi b/dts/arm/st/wl/stm32wl.dtsi index 3dc4b3fcc3f..9ef2a41969a 100644 --- a/dts/arm/st/wl/stm32wl.dtsi +++ b/dts/arm/st/wl/stm32wl.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 STMicroelectronics + * Copyright (c) 2020-2024 STMicroelectronics * * SPDX-License-Identifier: Apache-2.0 */ @@ -29,7 +29,7 @@ cpu0: cpu@0 { device_type = "cpu"; - compatible = "arm,cortex-m4f"; + compatible = "arm,cortex-m4"; reg = <0>; cpu-power-states = <&stop0 &stop1 &stop2>; }; @@ -206,6 +206,8 @@ interrupts = <42 0>; clocks = <&rcc STM32_CLOCK_BUS_APB1 0x00000400>; prescaler = <32768>; + alarms-count = <2>; + alrm-exti-line = <17>; status = "disabled"; /* In STM32WL, the backup registers are defined as part of the TAMP @@ -333,7 +335,7 @@ compatible = "st,stm32wl-subghz-radio"; reg = <0>; interrupts = <50 0>; - spi-max-frequency = <12000000>; + spi-max-frequency = <8000000>; status = "disabled"; }; }; diff --git a/dts/arm/ti/am62x_m4.dtsi b/dts/arm/ti/am62x_m4.dtsi index 8d5e5a14c40..b310c19b170 100644 --- a/dts/arm/ti/am62x_m4.dtsi +++ b/dts/arm/ti/am62x_m4.dtsi @@ -35,7 +35,7 @@ sysclk: system-clock { compatible = "fixed-clock"; - clock-frequency = <400000000>; + clock-frequency = ; #clock-cells = <0>; }; @@ -50,7 +50,7 @@ reg = <0x04a00000 0x200>; interrupts = <24 4>; interrupt-parent = <&nvic>; - clock-frequency = <48000000>; + clock-frequency = ; current-speed = <115200>; reg-shift = <2>; status = "disabled"; @@ -59,7 +59,6 @@ gpio0: gpio@4201010 { compatible = "ti,davinci-gpio"; reg = <0x4201010 0x100>; - #address-cells = <2>; gpio-controller; #gpio-cells = <2>; ngpios = <24>; diff --git a/dts/arm/ti/am64x_m4.dtsi b/dts/arm/ti/am64x_m4.dtsi new file mode 100644 index 00000000000..d95fe49a90e --- /dev/null +++ b/dts/arm/ti/am64x_m4.dtsi @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2024 PHYTEC Messtechnik GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +/ { + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-m4f"; + reg = <0>; + }; + }; + + sram0: memory@0 { + compatible = "mmio-sram"; + reg = <0x0 DT_SIZE_K(192)>; /* 192 KB of SRAM (I-Code) */ + }; + + sram1: memory1@40000 { + compatible = "mmio-sram"; + reg = <0x40000 DT_SIZE_K(64)>; /* 64 KB of SRAM (D-Code) */ + }; + + sysclk: system-clock { + compatible = "fixed-clock"; + clock-frequency = ; + #clock-cells = <0>; + }; + + pinctrl: pinctrl@4084000 { + compatible = "ti,k3-pinctrl"; + reg = <0x04084000 0x88>; + status = "okay"; + }; + + uart0: serial@4a00000 { + compatible = "ns16550"; + reg = <0x04a00000 0x200>; + interrupts = <24 4>; + interrupt-parent = <&nvic>; + clock-frequency = ; + current-speed = <115200>; + reg-shift = <2>; + status = "disabled"; + }; + + uart1: serial@4a10000 { + compatible = "ns16550"; + reg = <0x04a10000 0x200>; + interrupts = <25 4>; + interrupt-parent = <&nvic>; + clock-frequency = ; + current-speed = <115200>; + reg-shift = <2>; + status = "disabled"; + }; + + gpio0: gpio@4201010 { + compatible = "ti,davinci-gpio"; + reg = <0x4201010 0x100>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <24>; + status = "disabled"; + }; +}; + +&nvic { + arm,num-irq-priority-bits = <3>; +}; + +&systick { + status = "okay"; +}; diff --git a/dts/arm64/broadcom/bcm2712.dtsi b/dts/arm64/broadcom/bcm2712.dtsi new file mode 100644 index 00000000000..9249cb3622c --- /dev/null +++ b/dts/arm64/broadcom/bcm2712.dtsi @@ -0,0 +1,90 @@ +/* + * Copyright 2024 Myeonghyeon Park + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a76"; + reg = <0>; + }; + }; + + interrupt-parent = <&gic>; + + timer { + compatible = "arm,armv8-timer"; + interrupts = , + , + , + ; + }; + + soc { + #address-cells = <2>; + #size-cells = <1>; + + sram0: memory@200000 { + device_type = "memory"; + compatible = "mmio-sram"; + reg = <0x0 0x200000 0x80000>; + }; + + gic: interrupt-controller@107fff9000 { + compatible = "arm,gic-v2", "arm,gic"; + reg = <0x10 0x7fff9000 0x1000>, + <0x10 0x7fffa000 0x2000>; + interrupt-controller; + #interrupt-cells = <4>; + status = "okay"; + }; + + gpio2@107d517c00 { + compatible = "simple-bus"; + reg = <0x10 0x7d517c00 0x40>; + + #address-cells = <1>; + #size-cells = <0>; + gio_aon: gpio@0 { + compatible = "brcm,brcmstb-gpio"; + reg = <0>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <17>; + status = "disabled"; + }; + }; + + uart10: serial@107d001000 { + compatible = "arm,pl011"; + reg = <0x10 0x7d001000 0x200>; + interrupts = ; + interrupt-names = "irq_121"; + clocks = <&clk_uart>; + status = "disabled"; + }; + + }; + + clocks { + clk_uart: clk_uart { + compatible = "fixed-clock"; + clock-frequency = <44236800>; + #clock-cells = <0>; + }; + }; +}; diff --git a/dts/arm64/broadcom/viper-a72.dtsi b/dts/arm64/broadcom/viper-a72.dtsi index 698bd915848..c4928496d7d 100644 --- a/dts/arm64/broadcom/viper-a72.dtsi +++ b/dts/arm64/broadcom/viper-a72.dtsi @@ -5,9 +5,9 @@ */ #include -#include +#include -#include "viper-common.dtsi" +#include / { cpus { diff --git a/dts/arm64/broadcom/viper-common.dtsi b/dts/arm64/broadcom/viper-common.dtsi deleted file mode 100644 index 2ea763e65a6..00000000000 --- a/dts/arm64/broadcom/viper-common.dtsi +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2020 Broadcom - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/ { - soc { - sram0: memory@400000 { - device_type = "memory"; - reg = <0x00400000 0x80000>; - }; - - uart0: uart@40020000 { - compatible = "ns16550"; - reg = <0x40020000 0x400>; - reg-shift = <2>; - clock-frequency = <25000000>; - status = "disabled"; - }; - - uart1: uart@48100000 { - compatible = "ns16550"; - reg = <0x48100000 0x400>; - reg-shift = <2>; - clock-frequency = <100000000>; - status = "disabled"; - }; - - pl330: pl330@48300000 { - compatible = "arm,dma-pl330"; - reg = <0x48300000 0x2000>, - <0x482f005c 0x20>; - reg-names = "pl330_regs", - "control_regs"; - microcode = <0x63b00000 0x1000>; - dma-channels = <8>; - #dma-cells = <1>; - }; - }; - - pcie { - #address-cells = <2>; - #size-cells = <2>; - - pcie0_ep: pcie@4e100000 { - compatible = "brcm,iproc-pcie-ep"; - reg = <0x0 0x4e100000 0x0 0x2100>, - <0x0 0x50000000 0x0 0x8000000>, - <0x4 0x0 0x0 0x8000000>; - reg-names = "iproc_pcie_regs", "map_lowmem", - "map_highmem"; - dmas = <&pl330 0>, <&pl330 1>; - dma-names = "txdma", "rxdma"; - }; - - paxdma: paxdma@4e100800 { - compatible = "brcm,iproc-pax-dma-v2"; - reg = <0x0 0x4e100800 0x0 0x2100>, - <0x0 0x4f000000 0x0 0x200000>, - <0x0 0x4f200000 0x0 0x10000>; - reg-names = "dme_regs", "rm_ring_regs", - "rm_comm_regs"; - dma-channels = <4>; - #dma-cells = <1>; - bd-memory = <0x63b00000 0x100000>; - scr-addr-loc = <0x200061f0>; - scr-size-loc = <0x200061f8>; - pcie-ep = <&pcie0_ep>; - }; - }; -}; diff --git a/dts/arm64/intel/intel_socfpga_agilex.dtsi b/dts/arm64/intel/intel_socfpga_agilex.dtsi index e3b3e9b17ca..7083e38c7de 100644 --- a/dts/arm64/intel/intel_socfpga_agilex.dtsi +++ b/dts/arm64/intel/intel_socfpga_agilex.dtsi @@ -99,6 +99,10 @@ reg = <0x10000000 0x200000>; }; + fpga0: bridges { + compatible = "altr,socfpga-agilex-bridge"; + }; + uart0: uart@ffc02000 { compatible = "ns16550"; reg-shift = <2>; diff --git a/dts/arm64/intel/intel_socfpga_agilex5.dtsi b/dts/arm64/intel/intel_socfpga_agilex5.dtsi index 21cf2e68ed0..b23830521bf 100644 --- a/dts/arm64/intel/intel_socfpga_agilex5.dtsi +++ b/dts/arm64/intel/intel_socfpga_agilex5.dtsi @@ -97,6 +97,10 @@ reg = <0x80100000 DT_SIZE_M(8)>; }; + fpga0: bridges { + compatible = "altr,socfpga-agilex-bridge"; + }; + uart0: uart@10c02000 { compatible = "ns16550"; reg-shift = <2>; diff --git a/dts/arm64/nxp/nxp_mimx93_a55.dtsi b/dts/arm64/nxp/nxp_mimx93_a55.dtsi index 3bf2071cc78..defcb2dc326 100644 --- a/dts/arm64/nxp/nxp_mimx93_a55.dtsi +++ b/dts/arm64/nxp/nxp_mimx93_a55.dtsi @@ -10,6 +10,7 @@ #include #include #include +#include #include / { @@ -346,6 +347,73 @@ dma-names = "tx", "rx"; status = "disabled"; }; + + tpm1: tpm@44310000 { + compatible = "nxp,tpm-timer"; + reg = <0x44310000 DT_SIZE_K(64)>; + interrupts = ; + interrupt-names = "irq_0"; + interrupt-parent = <&gic>; + clocks = <&ccm IMX_CCM_TPM1_CLK 0 0>; + prescaler = <1>; + status = "disabled"; + }; + + tpm2: tpm@44320000 { + compatible = "nxp,tpm-timer"; + reg = <0x44320000 DT_SIZE_K(64)>; + interrupts = ; + interrupt-names = "irq_0"; + interrupt-parent = <&gic>; + clocks = <&ccm IMX_CCM_TPM2_CLK 0 0>; + prescaler = <1>; + status = "disabled"; + }; + + tpm3: tpm@424e0000 { + compatible = "nxp,tpm-timer"; + reg = <0x424e0000 DT_SIZE_K(64)>; + interrupts = ; + interrupt-names = "irq_0"; + interrupt-parent = <&gic>; + clocks = <&ccm IMX_CCM_TPM3_CLK 0 0>; + prescaler = <1>; + status = "disabled"; + }; + + tpm4: tpm@424f0000 { + compatible = "nxp,tpm-timer"; + reg = <0x424f0000 DT_SIZE_K(64)>; + interrupts = ; + interrupt-names = "irq_0"; + interrupt-parent = <&gic>; + clocks = <&ccm IMX_CCM_TPM4_CLK 0 0>; + prescaler = <1>; + status = "disabled"; + }; + + tpm5: tpm@42500000 { + compatible = "nxp,tpm-timer"; + reg = <0x42500000 DT_SIZE_K(64)>; + interrupts = ; + interrupt-names = "irq_0"; + interrupt-parent = <&gic>; + clocks = <&ccm IMX_CCM_TPM5_CLK 0 0>; + prescaler = <1>; + status = "disabled"; + }; + + tpm6: tpm@42510000 { + compatible = "nxp,tpm-timer"; + reg = <0x42510000 DT_SIZE_K(64)>; + interrupts = ; + interrupt-names = "irq_0"; + interrupt-parent = <&gic>; + clocks = <&ccm IMX_CCM_TPM6_CLK 0 0>; + prescaler = <1>; + status = "disabled"; + }; + }; &gpio1{ diff --git a/dts/arm64/renesas/r8a779f0.dtsi b/dts/arm64/renesas/r8a779f0.dtsi new file mode 100644 index 00000000000..424ffc3105d --- /dev/null +++ b/dts/arm64/renesas/r8a779f0.dtsi @@ -0,0 +1,118 @@ +/* + * Device Tree Source for the R-Car S4 (R8A779F0) SoC + * + * Copyright (C) 2023 EPAM Systems. + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include + +/ { + compatible = "renesas,r8a779f0"; + #address-cells = <2>; + #size-cells = <2>; + interrupt-parent = <&gic>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + a55: cpu@0 { + compatible = "arm,armv8"; + reg = <0>; + device_type = "cpu"; + enable-method = "psci"; + }; + }; + + psci { + compatible = "arm,psci-0.2"; + method = "smc"; + }; + + arch_timer: timer { + compatible = "arm,armv8-timer"; + interrupt-parent = <&gic>; + interrupts = , + , + , + ; + }; + + reg_3p3v: regulator_3p3v { + compatible = "regulator-fixed"; + regulator-name = "reg_3p3v"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + regulator-boot-on; + status = "okay"; + }; + + reg_1p8v: regulator_1p8v { + compatible = "regulator-fixed"; + regulator-name = "reg_1p8v"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + regulator-boot-on; + status = "okay"; + }; + + soc: soc { + compatible = "simple-bus"; + interrupt-parent = <&gic>; + + #address-cells = <2>; + #size-cells = <2>; + ranges; + + gic: interrupt-controller@f1000000 { + compatible = "arm,gic-600", "arm,gic-v3", "arm,gic"; + #interrupt-cells = <4>; + #address-cells = <0>; + interrupt-controller; + reg = <0 0xf1000000 0 0x20000>, + <0 0xf1060000 0 0x110000>; + status = "okay"; + }; + + cpg: clock-controller@e6150000 { + compatible = "renesas,r8a779f0-cpg-mssr"; + reg = <0 0xe6150000 0 0x4000>; + #clock-cells = <2>; + #power-domain-cells = <0>; + #reset-cells = <1>; + }; + + mmc0: mmc@ee140000 { + compatible = "renesas,rcar-mmc"; + reg = <0 0xee140000 0 0x2000>; + vmmc-supply = <®_3p3v>; + vqmmc-supply = <®_1p8v>; + interrupts = ; + clocks = <&cpg CPG_MOD 706>, <&cpg CPG_CORE R8A779F0_CLK_SD0H>; + max-bus-freq = <200000000>; + status = "disabled"; + }; + + pfc: pin-controller@e6050000 { + compatible = "renesas,rcar-pfc"; + reg = <0 0xe6050000 0 0x16c>, <0 0xe6050800 0 0x16c>, + <0 0xe6051000 0 0x16c>, <0 0xe6051800 0 0x16c>, + <0 0xdfd90000 0 0x16c>, <0 0xdfd90800 0 0x16c>, + <0 0xdfd91000 0 0x16c>, <0 0xdfd91800 0 0x16c>; + }; + + hscif0: serial@e6540000 { + compatible = "renesas,rcar-hscif"; + reg = <0 0xe6540000 0 0x60>; + interrupts = ; + clocks = <&cpg CPG_MOD 514>, <&cpg CPG_CORE R8A779F0_CLK_SASYNCPERD1>; + status = "disabled"; + }; + }; +}; diff --git a/dts/arm64/renesas/rcar_gen3_ca57.dtsi b/dts/arm64/renesas/rcar_gen3_ca57.dtsi index 5c87c8accd3..d79a557a9cd 100644 --- a/dts/arm64/renesas/rcar_gen3_ca57.dtsi +++ b/dts/arm64/renesas/rcar_gen3_ca57.dtsi @@ -28,6 +28,26 @@ ; }; + reg_3p3v: regulator_3p3v { + compatible = "regulator-fixed"; + regulator-name = "reg_3p3v"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + regulator-boot-on; + status = "okay"; + }; + + reg_1p8v: regulator_1p8v { + compatible = "regulator-fixed"; + regulator-name = "reg_1p8v"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + regulator-boot-on; + status = "okay"; + }; + gic: interrupt-controller@f1010000 { compatible = "arm,gic-400", "arm,gic-v2", "arm,gic" ; #interrupt-cells = <4>; @@ -53,13 +73,36 @@ #reset-cells = <1>; }; + gpio5: gpio@e6055000 { + compatible = "renesas,rcar-gpio"; + reg = <0 0xe6055000 0 0x50>; + #gpio-cells = <2>; + gpio-controller; + interrupt-parent = <&gic>; + interrupts = ; + clocks = <&cpg CPG_MOD 907>; + status = "disabled"; + }; + + sd0: mmc@ee100000 { + compatible = "renesas,rcar-mmc"; + reg = <0 0xee100000 0 0x2000>; + interrupts = ; + clocks = <&cpg CPG_MOD 314>, <&cpg CPG_CORE R8A7795_CLK_SD0H>; + max-bus-freq = <200000000>; + status = "disabled"; + }; + emmc2: mmc@ee140000 { compatible = "renesas,rcar-mmc"; reg = <0 0xee140000 0 0x2000>; + vmmc-supply = <®_3p3v>; + vqmmc-supply = <®_1p8v>; interrupts = ; - clocks = <&cpg CPG_MOD 312>; - max-frequency = <200000000>; + clocks = <&cpg CPG_MOD 312>, <&cpg CPG_CORE R8A7795_CLK_SD2H>; + max-bus-freq = <200000000>; status = "disabled"; }; diff --git a/dts/bindings/adc/nxp,gau-adc.yaml b/dts/bindings/adc/nxp,gau-adc.yaml new file mode 100644 index 00000000000..7f5c5767d78 --- /dev/null +++ b/dts/bindings/adc/nxp,gau-adc.yaml @@ -0,0 +1,55 @@ +# Copyright 2022 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: | + NXP GAU GPADC. + +compatible: "nxp,gau-adc" + +include: + - name: base.yaml + - name: adc-controller.yaml + +properties: + reg: + required: true + + interrupts: + required: true + + nxp,clock-divider: + type: int + description: | + Clock divider from 1 to 32. + Default is 1 which is reset value. + default: 1 + + nxp,power-mode: + type: string + description: | + Current bias. + Default is "full-bias" because it is the reset value. + enum: + - "full-bias" + - "half-bias" + default: "full-bias" + + nxp,input-buffer: + type: boolean + description: Enable use of the input buffer + + nxp,calibration-voltage: + type: string + enum: + - "internal" + - "external" + default: "internal" + description: | + Use external calibration voltage. + Default is "internal" because it is the reset value. + + "#io-channel-cells": + const: 1 + +io-channel-cells: + - input diff --git a/dts/bindings/arm/nxp,lpc-flexcomm.yaml b/dts/bindings/arm/nxp,lpc-flexcomm.yaml index ffc27753c3d..57121b489ae 100644 --- a/dts/bindings/arm/nxp,lpc-flexcomm.yaml +++ b/dts/bindings/arm/nxp,lpc-flexcomm.yaml @@ -5,7 +5,7 @@ description: LPC Flexcomm node compatible: "nxp,lpc-flexcomm" -include: [base.yaml, pinctrl-device.yaml] +include: [base.yaml, pinctrl-device.yaml, reset-device.yaml] properties: reg: diff --git a/dts/bindings/auxdisplay/sparkfun,serlcd.yaml b/dts/bindings/auxdisplay/sparkfun,serlcd.yaml index 60c17fc7860..69c18e23476 100644 --- a/dts/bindings/auxdisplay/sparkfun,serlcd.yaml +++ b/dts/bindings/auxdisplay/sparkfun,serlcd.yaml @@ -11,8 +11,8 @@ description: | reg = <0x72>; columns = <16>; rows = <2>; - command-delay = <10>; - special-command-delay = <50>; + command-delay-ms = <10>; + special-command-delay-ms = <50>; }; }; diff --git a/dts/bindings/base/base.yaml b/dts/bindings/base/base.yaml index f1d1109a199..b2e670fb5d8 100644 --- a/dts/bindings/base/base.yaml +++ b/dts/bindings/base/base.yaml @@ -92,3 +92,9 @@ properties: mbox-names: type: string-array description: Provided names of mailbox / IPM channel specifiers + + zephyr,deferred-init: + type: boolean + description: | + Do not initialize device automatically on boot. Device should be manually + initialized using device_init(). diff --git a/dts/bindings/base/mutable.yaml b/dts/bindings/base/mutable.yaml index 0e2d1cad3b0..7f7aab7dbb7 100644 --- a/dts/bindings/base/mutable.yaml +++ b/dts/bindings/base/mutable.yaml @@ -7,7 +7,7 @@ properties: zephyr,mutable: type: boolean description: | - True iff the device structure may be mutated. + True if and only if 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/base/zephyr,memory-attr.yaml b/dts/bindings/base/zephyr,memory-attr.yaml deleted file mode 100644 index 1a5611b5258..00000000000 --- a/dts/bindings/base/zephyr,memory-attr.yaml +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright (c) 2023, Carlo Caione -# SPDX-License-Identifier: Apache-2.0 - -include: [base.yaml] - -properties: - zephyr,memory-region-mpu: - type: string - deprecated: true - description: | - Signify that this node should result in a dedicated MPU region. - Deprecated in favor of 'zephyr,memory-attr'. - - zephyr,memory-attr: - type: int - description: | - Attribute or set of attributes (bitmask) for the memory region. See - 'include/zephyr/dt-bindings/memory-attr/memory-attr.h' for a - comprehensive list with description of possible values. - - reg: - required: true diff --git a/dts/bindings/base/zephyr,memory-common.yaml b/dts/bindings/base/zephyr,memory-common.yaml new file mode 100644 index 00000000000..f2ccbdb3c41 --- /dev/null +++ b/dts/bindings/base/zephyr,memory-common.yaml @@ -0,0 +1,30 @@ +# Copyright (c) 2023, Carlo Caione +# SPDX-License-Identifier: Apache-2.0 + +include: [base.yaml] + +properties: + zephyr,memory-region: + type: string + description: | + Signify that this node should result in a dedicated linker script + memory region in the final executable. The region address and size + is taken from the property, while the name is the value of + this property. + + zephyr,memory-region-mpu: + type: string + deprecated: true + description: | + Signify that this node should result in a dedicated MPU region. + Deprecated in favor of 'zephyr,memory-attr'. + + zephyr,memory-attr: + type: int + description: | + Attribute or set of attributes (bitmask) for the memory region. See + 'include/zephyr/dt-bindings/memory-attr/memory-attr.h' for a + comprehensive list with description of possible values. + + reg: + required: true diff --git a/dts/bindings/base/zephyr,memory-region.yaml b/dts/bindings/base/zephyr,memory-region.yaml index 60308af7173..1d9486de8b3 100644 --- a/dts/bindings/base/zephyr,memory-region.yaml +++ b/dts/bindings/base/zephyr,memory-region.yaml @@ -5,14 +5,8 @@ description: Compatible for devices resulting in linker memory regions compatible: "zephyr,memory-region" -include: [base.yaml, "zephyr,memory-attr.yaml"] +include: [base.yaml, "zephyr,memory-common.yaml"] properties: zephyr,memory-region: - type: string required: true - description: | - Signify that this node should result in a dedicated linker script - memory region in the final executable. The region address and size - is taken from the property, while the name is the value of - this property. diff --git a/dts/bindings/bluetooth/infineon,cyw43xxx-bt-hci.yaml b/dts/bindings/bluetooth/infineon,cyw43xxx-bt-hci.yaml index 25213af3ecc..4dcc1f41873 100644 --- a/dts/bindings/bluetooth/infineon,cyw43xxx-bt-hci.yaml +++ b/dts/bindings/bluetooth/infineon,cyw43xxx-bt-hci.yaml @@ -18,6 +18,9 @@ description: | &p3_2_scb2_uart_rts &p3_3_scb2_uart_cts>; pinctrl-names = "default"; + /* HW Flow control must be enabled for HCI H4 */ + hw-flow-control; + bt-hci { status = "okay"; compatible = "infineon,cyw43xxx-bt-hci"; diff --git a/dts/bindings/cache/andestech,l2c.yaml b/dts/bindings/cache/andestech,l2c.yaml new file mode 100644 index 00000000000..6d9344ad7cd --- /dev/null +++ b/dts/bindings/cache/andestech,l2c.yaml @@ -0,0 +1,16 @@ +# +# Copyright (c) 2024, Andes Technology Corporation. +# +# SPDX-License-Identifier: Apache-2.0 +# + +description: + This is a representation of AndesTech L2 cache node + +compatible: "andestech,l2c" + +include: base.yaml + +properties: + reg: + required: true diff --git a/dts/bindings/can/can-controller.yaml b/dts/bindings/can/can-controller.yaml index adc738d7319..55322b50a21 100644 --- a/dts/bindings/can/can-controller.yaml +++ b/dts/bindings/can/can-controller.yaml @@ -5,9 +5,9 @@ include: base.yaml properties: bus-speed: type: int - required: true description: | - Initial bitrate in bit/s. + Initial bitrate in bit/s. If this is unset, the initial bitrate is set to + CONFIG_CAN_DEFAULT_BITRATE. sample-point: type: int description: | diff --git a/dts/bindings/can/can-fd-controller.yaml b/dts/bindings/can/can-fd-controller.yaml index 46fab559d2a..9efc7823f94 100644 --- a/dts/bindings/can/can-fd-controller.yaml +++ b/dts/bindings/can/can-fd-controller.yaml @@ -5,9 +5,9 @@ include: can-controller.yaml properties: bus-speed-data: type: int - required: true description: | - Initial data phase bitrate in bit/s. + Initial data phase bitrate in bit/s. If this is unset, the initial data phase bitrate is set + to CONFIG_CAN_DEFAULT_BITRATE_DATA. sample-point-data: type: int description: | diff --git a/dts/bindings/can/microchip,mcp251xfd.yaml b/dts/bindings/can/microchip,mcp251xfd.yaml index e4350760594..168314547ef 100644 --- a/dts/bindings/can/microchip,mcp251xfd.yaml +++ b/dts/bindings/can/microchip,mcp251xfd.yaml @@ -19,8 +19,6 @@ description: | reg = <0x0>; osc-freq = <40000000>; - bus-speed = <125000>; - bus-speed-data = <1000000>; }; }; diff --git a/dts/bindings/can/nxp,flexcan-fd.yaml b/dts/bindings/can/nxp,flexcan-fd.yaml index f55eb780c2d..ce651928123 100644 --- a/dts/bindings/can/nxp,flexcan-fd.yaml +++ b/dts/bindings/can/nxp,flexcan-fd.yaml @@ -15,8 +15,6 @@ description: | interrupt-names = "common"; clocks = <&ccm IMX_CCM_CAN_CLK 0x84 6>; clk-source = <2>; - bus-speed = <125000>; - bus-speed-data = <1000000>; pinctrl-0 = <&pinmux_flexcan3>; pinctrl-names = "default"; diff --git a/dts/bindings/can/nxp,flexcan.yaml b/dts/bindings/can/nxp,flexcan.yaml index 736382d68bd..045c09974fc 100644 --- a/dts/bindings/can/nxp,flexcan.yaml +++ b/dts/bindings/can/nxp,flexcan.yaml @@ -13,7 +13,6 @@ description: | interrupt-names = "warning", "error", "wake-up", "mb-0-15"; clocks = <&scg KINETIS_SCG_BUS_CLK>; clk-source = <1>; - bus-speed = <125000>; pinctrl-0 = <&pinmux_flexcan0>; pinctrl-names = "default"; diff --git a/dts/bindings/can/nxp,lpc-mcan.yaml b/dts/bindings/can/nxp,lpc-mcan.yaml index 48aef003139..bd735c88561 100644 --- a/dts/bindings/can/nxp,lpc-mcan.yaml +++ b/dts/bindings/can/nxp,lpc-mcan.yaml @@ -2,7 +2,7 @@ description: NXP LPC SoC series MCAN CAN FD controller compatible: "nxp,lpc-mcan" -include: ["bosch,m_can-base.yaml", pinctrl-device.yaml] +include: ["bosch,m_can-base.yaml", pinctrl-device.yaml, "reset-device.yaml"] properties: reg: diff --git a/dts/bindings/can/ti,tcan4x5x.yaml b/dts/bindings/can/ti,tcan4x5x.yaml index 5c74989093c..75b115d697c 100644 --- a/dts/bindings/can/ti,tcan4x5x.yaml +++ b/dts/bindings/can/ti,tcan4x5x.yaml @@ -16,8 +16,6 @@ description: | reset-gpios = <&gpio0 2 GPIO_ACTIVE_HIGH>; int-gpios = <&gpio0 3 GPIO_ACTIVE_LOW>; bosch,mram-cfg = <0x0 15 15 5 5 0 10 10>; - bus-speed = <125000>; - bus-speed-data = <1000000>; status = "okay"; can-transceiver { diff --git a/dts/bindings/charger/maxim,max20335-charger.yaml b/dts/bindings/charger/maxim,max20335-charger.yaml index 3fe44c92908..00fc9c41f11 100644 --- a/dts/bindings/charger/maxim,max20335-charger.yaml +++ b/dts/bindings/charger/maxim,max20335-charger.yaml @@ -1,5 +1,5 @@ # Copyright (c), 2023 Grinn -# SPDX -License-Identifier: Apache-2.0 +# SPDX-License-Identifier: Apache-2.0 description: Maxim MAX20335 battery charger diff --git a/dts/bindings/clock/nxp,imx-ccm-fnpll.yaml b/dts/bindings/clock/nxp,imx-ccm-fnpll.yaml new file mode 100644 index 00000000000..cd18246823c --- /dev/null +++ b/dts/bindings/clock/nxp,imx-ccm-fnpll.yaml @@ -0,0 +1,38 @@ +# Copyright 2024 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: | + i.MX CCM Fractional PLL. Output frequency is given by the following + formula: Fout = Fin * (loop-div + (numerator/denominator) + +compatible: "nxp,imx-ccm-fnpll" + +include: [clock-controller.yaml, base.yaml] + +properties: + "#clock-cells": + const: 0 + + loop-div: + type: int + required: true + description: | + Loop divider. Divides PLL feedback loop (effectively multiplying output + frequency) + + numerator: + type: int + required: true + description: | + Numerator of PLL multiplier fraction + + denominator: + type: int + required: true + description: | + Denominator of PLL multiplier fraction + + src: + type: int + required: true + description: Sets source for PLL input. SOC specific. diff --git a/dts/bindings/clock/renesas,smartbond-lp-osc.yaml b/dts/bindings/clock/renesas,smartbond-lp-osc.yaml index 0aa82f773e5..45c3c56e472 100644 --- a/dts/bindings/clock/renesas,smartbond-lp-osc.yaml +++ b/dts/bindings/clock/renesas,smartbond-lp-osc.yaml @@ -13,16 +13,6 @@ include: - clock-frequency properties: - calibration-interval: - type: int - default: 1 - description: | - Time in seconds between calibration of low power clock RCX or RC32K. - For XTAL32K this value is not used. - If set to 0 calibration will not be performed. This can be applied - when XTAL32K is enabled for low power clock and RCX or RC32K is used - for watchdog and strict timing is not required. - settle-time: type: int default: 8000 diff --git a/dts/bindings/counter/nxp,mrt.yaml b/dts/bindings/counter/nxp,mrt.yaml index e9e05b6c5b5..18e4543cfe3 100644 --- a/dts/bindings/counter/nxp,mrt.yaml +++ b/dts/bindings/counter/nxp,mrt.yaml @@ -5,7 +5,7 @@ description: NXP Multirate Timer compatible: "nxp,mrt" -include: base.yaml +include: [base.yaml, reset-device.yaml] properties: reg: diff --git a/dts/bindings/cpu/qemu,riscv-virt.yaml b/dts/bindings/cpu/qemu,riscv-virt.yaml new file mode 100644 index 00000000000..c4c5a8b174e --- /dev/null +++ b/dts/bindings/cpu/qemu,riscv-virt.yaml @@ -0,0 +1,9 @@ +# Copyright (c) 2024 Antmicro +# +# SPDX-License-Identifier: Apache-2.0 + +description: QEMU RISC-V virt machine CPU node + +compatible: "qemu,riscv-virt" + +include: riscv,cpus.yaml diff --git a/dts/bindings/crypto/ite,it8xxx2-sha-v2.yaml b/dts/bindings/crypto/ite,it8xxx2-sha-v2.yaml new file mode 100644 index 00000000000..94d9d664d9c --- /dev/null +++ b/dts/bindings/crypto/ite,it8xxx2-sha-v2.yaml @@ -0,0 +1,12 @@ +# Copyright (c) 2024, ITE Corporation +# SPDX-License-Identifier: Apache-2.0 + +description: ITE IT8XXX2 Crypto SHA accelerator V2. + +compatible: "ite,it8xxx2-sha-v2" + +include: base.yaml + +properties: + reg: + required: true diff --git a/dts/bindings/dac/adi,ad5691.yaml b/dts/bindings/dac/adi,ad5691.yaml new file mode 100644 index 00000000000..11cc67fbd47 --- /dev/null +++ b/dts/bindings/dac/adi,ad5691.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2024 Jan Kubiznak +# SPDX-License-Identifier: Apache-2.0 + +description: Driver for AD5691 (12-bit) DAC. + +compatible: "adi,ad5691" + +include: adi,ad569x-base.yaml diff --git a/dts/bindings/dac/adi,ad5692.yaml b/dts/bindings/dac/adi,ad5692.yaml new file mode 100644 index 00000000000..46ef4d624d0 --- /dev/null +++ b/dts/bindings/dac/adi,ad5692.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2024 Jan Kubiznak +# SPDX-License-Identifier: Apache-2.0 + +description: Driver for AD5692 (14-bit) DAC. + +compatible: "adi,ad5692" + +include: adi,ad569x-base.yaml diff --git a/dts/bindings/dac/adi,ad5693.yaml b/dts/bindings/dac/adi,ad5693.yaml new file mode 100644 index 00000000000..7d925524859 --- /dev/null +++ b/dts/bindings/dac/adi,ad5693.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2024 Jan Kubiznak +# SPDX-License-Identifier: Apache-2.0 + +description: Driver for AD5693 (16-bit) DAC. + +compatible: "adi,ad5693" + +include: adi,ad569x-base.yaml diff --git a/dts/bindings/dac/adi,ad569x-base.yaml b/dts/bindings/dac/adi,ad569x-base.yaml new file mode 100644 index 00000000000..52fa0e742f7 --- /dev/null +++ b/dts/bindings/dac/adi,ad569x-base.yaml @@ -0,0 +1,61 @@ +# Copyright (c) 2024 Jan Kubiznak +# SPDX-License-Identifier: Apache-2.0 + +include: [dac-controller.yaml] + +properties: + "#io-channel-cells": + const: 1 + + resolution: + type: int + required: true + description: DAC resolution. + + voltage-reference-mv: + type: int + required: true + description: DAC reference voltage in mV. + + voltage-reference: + type: string + default: "internal" + enum: + - "internal" + - "external" + description: | + DAC voltage reference select. + - Internal voltage reference - 2.5V (reg: 0). + - External voltage reference (reg: 1). + The default corresponds to the reset value of the register field. + + gain: + type: string + default: "gain-1" + enum: + - "gain-1" + - "gain-2" + description: | + Gain selection bit. + - Gain of 1 (reg: 0). + - Gain of 2 (reg: 1). + The default corresponds to the reset value of the register field. + + power-down-mode: + type: string + default: "normal" + enum: + - "normal" + - "power-down-1k" + - "power-down-100k" + - "power-down-3-state" + description: | + Power-down mode select. + - Normal mode (reg: 0). + - 1 kOhm output impedance (reg: 1). + - 100 kOhm output impedance (reg: 2). + - Three-state output impedance (reg: 3). + The default corresponds to the reset value of the register field. + +io-channel-cells: + - output diff --git a/dts/bindings/dac/nxp,gau-dac.yaml b/dts/bindings/dac/nxp,gau-dac.yaml new file mode 100644 index 00000000000..e151d2fdbe3 --- /dev/null +++ b/dts/bindings/dac/nxp,gau-dac.yaml @@ -0,0 +1,45 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP GAU DAC + +compatible: "nxp,gau-dac" + +include: dac-controller.yaml + +properties: + nxp,dac-reference: + type: string + enum: + - "internal" + - "external" + default: "internal" + description: | + DAC reference select. + Default is "internal" because that is the reset value. + + nxp,output-voltage-range: + type: string + enum: + - "small" + - "medium" + - "large" + default: "large" + description: | + See specific platform Reference Manual for equations describing the options. + Default is large because that is the reset value. + + nxp,conversion-rate: + type: string + enum: + - "62.5K" + - "125K" + - "250K" + - "500K" + default: "62.5K" + description: | + DAC conversion rate. + Default is "62.5K" because that is the reset value. + + "#io-channel-cells": + const: 0 diff --git a/dts/bindings/dac/ti,dacx0501.yaml b/dts/bindings/dac/ti,dacx0501.yaml new file mode 100644 index 00000000000..53251001271 --- /dev/null +++ b/dts/bindings/dac/ti,dacx0501.yaml @@ -0,0 +1,30 @@ +# Copyright (c) 2024 Google, LLC. +# SPDX-License-Identifier: Apache-2.0 + +include: base.yaml + +description: TI DACx0501 12 to 16 bit DAC series for DAC60501, DAC70501 and DAC80501 devices. + +compatible: "ti,dacx0501" + +properties: + voltage-reference: + type: string + required: true + enum: + - "internal" + - "external" + description: | + DAC voltage reference select: either internal (2.5 V) or external + + output-gain: + type: string + required: true + enum: + - "mul2" + - "mul1" + - "div2" + description: | + This setting can be used to control the output voltage range within the supported bit + resolution. mul2 will double the output range but lower the resolution, while div2 will + lower the range but double the resolution. diff --git a/dts/bindings/display/galaxycore,gc9x01x.yaml b/dts/bindings/display/galaxycore,gc9x01x.yaml index 37c4a5680a5..bc85c652b06 100644 --- a/dts/bindings/display/galaxycore,gc9x01x.yaml +++ b/dts/bindings/display/galaxycore,gc9x01x.yaml @@ -34,7 +34,6 @@ 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 diff --git a/dts/bindings/display/sitronix,st7735r.yaml b/dts/bindings/display/sitronix,st7735r.yaml index 90ead2b8731..bc94281e829 100644 --- a/dts/bindings/display/sitronix,st7735r.yaml +++ b/dts/bindings/display/sitronix,st7735r.yaml @@ -5,26 +5,9 @@ description: ST7735R/ST7735S 160x128 (max) display controller compatible: "sitronix,st7735r" -include: [spi-device.yaml, display-controller.yaml] +include: [mipi-dbi-spi-device.yaml, display-controller.yaml] properties: - reset-gpios: - type: phandle-array - description: RESET pin. - - The RESET pin of ST7735R is active low. - If connected directly the MCU pin should be configured - as active low. - - cmd-data-gpios: - type: phandle-array - required: true - description: D/CX pin. - - The D/CX pin of ST7735R is active low (transmission command byte). - If connected directly the MCU pin should be configured - as active low. - x-offset: type: int required: true diff --git a/dts/bindings/display/sitronix,st7789v.yaml b/dts/bindings/display/sitronix,st7789v.yaml index 1820bedb246..ec72e18d7f9 100644 --- a/dts/bindings/display/sitronix,st7789v.yaml +++ b/dts/bindings/display/sitronix,st7789v.yaml @@ -77,6 +77,10 @@ properties: required: true description: Gamma Setting + inversion-off: + type: boolean + description: Inversion Off + porch-param: type: uint8-array required: true diff --git a/dts/bindings/ethernet/adi,adin1100-phy.yaml b/dts/bindings/ethernet/adi,adin1100-phy.yaml new file mode 100644 index 00000000000..c8613bcb902 --- /dev/null +++ b/dts/bindings/ethernet/adi,adin1100-phy.yaml @@ -0,0 +1,9 @@ +# Copyright (c) 2024 Analog Devices, Inc. +# Copyright (c) 2024 BayLibre, SAS +# SPDX-License-Identifier: Apache-2.0 + +description: ADIN1100 PHY + +compatible: "adi,adin1100-phy" + +include: adi,adin2111-phy.yaml diff --git a/dts/bindings/ethernet/nxp,enet-mac.yaml b/dts/bindings/ethernet/nxp,enet-mac.yaml index bbcc2b49362..cf8ca151e46 100644 --- a/dts/bindings/ethernet/nxp,enet-mac.yaml +++ b/dts/bindings/ethernet/nxp,enet-mac.yaml @@ -22,3 +22,10 @@ properties: required: true description: | Corresponding ptp clock device + + nxp,unique-mac: + type: boolean + description: | + Use unique silicon ID to use UAA MAC. + This property will be overridden if the node has + zephyr,random-mac-address or local-mac-address also. diff --git a/dts/bindings/flash_controller/st,stm32-xspi-nor.yaml b/dts/bindings/flash_controller/st,stm32-xspi-nor.yaml new file mode 100644 index 00000000000..f2ade8c7689 --- /dev/null +++ b/dts/bindings/flash_controller/st,stm32-xspi-nor.yaml @@ -0,0 +1,53 @@ +# Copyright (c) 2021 - 2024 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +description: | + STM32 XSPI Flash controller supporting the JEDEC CFI interface + + Representation of a serial flash on a xspi bus: + + mx25lm51245: xspi-nor-flash@70000000 { + compatible = "st,stm32-xspi-nor"; + reg = <0x70000000 DT_SIZE_M(64)>; /* 512 Mbits */ + data-mode = ; /* access on 8 data lines */ + data-rate = ; /* access in DTR */ + ospi-max-frequency = ; + status = "okay"; + }; + +compatible: "st,stm32-xspi-nor" + +include: + - name: st,stm32-ospi-nor.yaml + property-blocklist: + - spi-bus-width + - data-rate +properties: + spi-bus-width: + type: int + required: true + description: | + The width of XSPI bus to which flash memory is connected. + + Possible values are : + - XSPI_SPI_MODE <1> = SPI mode on 1 data line + - XSPI_DUAL_MODE <2> = Dual mode on 2 data lines + - XSPI_QUAD_MODE <4> = Quad mode on 4 data lines + - XSPI_OCTO_MODE <8> = Octo mode on 8 data lines + enum: + - 1 + - 2 + - 4 + - 8 + data-rate: + type: int + required: true + description: | + The SPI data Rate is STR or DTR + + Possible values are : + - XSPI_STR_TRANSFER <1> = Single Rate Transfer + - XSPI_DTR_TRANSFER <2> = Dual Rate Transfer (only with XSPI_OCTO_MODE) + enum: + - 1 + - 2 diff --git a/dts/bindings/flash_controller/zephyr,sim-flash.yaml b/dts/bindings/flash_controller/zephyr,sim-flash.yaml index 532a326c2d1..21b78b75012 100644 --- a/dts/bindings/flash_controller/zephyr,sim-flash.yaml +++ b/dts/bindings/flash_controller/zephyr,sim-flash.yaml @@ -9,6 +9,7 @@ include: base.yaml properties: erase-value: type: int + enum: [0xff, 0x00] description: Value of erased flash cell memory-region: type: phandle diff --git a/dts/bindings/gnss/luatos,air530z.yaml b/dts/bindings/gnss/luatos,air530z.yaml new file mode 100644 index 00000000000..c70a96690f5 --- /dev/null +++ b/dts/bindings/gnss/luatos,air530z.yaml @@ -0,0 +1,15 @@ +# Copyright 2024 JerĆ³nimo AgullĆ³ +# SPDX-License-Identifier: Apache-2.0 + +description: AIR530Z Luatos GNSS modem + +compatible: "luatos,air530z" + +include: + - uart-device.yaml + +properties: + on-off-gpios: + type: phandle-array + description: | + Identifies the On-Off pin for entering into low-power mode. diff --git a/dts/bindings/gnss/zephyr,gnss-emul.yaml b/dts/bindings/gnss/zephyr,gnss-emul.yaml new file mode 100644 index 00000000000..eb7d9eec8ac --- /dev/null +++ b/dts/bindings/gnss/zephyr,gnss-emul.yaml @@ -0,0 +1,6 @@ +# Copyright (c) 2024 Trackunit Corporation +# SPDX-License-Identifier: Apache-2.0 + +description: Zephyr emulated GNSS device + +compatible: "zephyr,gnss-emul" diff --git a/dts/bindings/gpio/adi,adp5585-gpio.yaml b/dts/bindings/gpio/adi,adp5585-gpio.yaml new file mode 100644 index 00000000000..bb27d2facb6 --- /dev/null +++ b/dts/bindings/gpio/adi,adp5585-gpio.yaml @@ -0,0 +1,30 @@ +# Copyright 2024 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: ADP5585 GPIO Controller + +compatible: "adi,adp5585-gpio" + +include: gpio-controller.yaml + +properties: + "#gpio-cells": + const: 2 + + ngpios: + const: 13 + description: | + Number of GPIOs available on port expander. + + gpio-reserved-ranges: + required: true + const: [5, 3] + description: | + Ranges of GPIOs reserved unavailable on port expander. + The ADP5585 has 10 GPIO lines divided in 2 groups. GPIO number + 5, 6, 7 is reserved. That's to say, GPIO R0~R4 occupy line + number 0~4, GPIO C0~C4 occupy line number 8~12. + +gpio-cells: + - pin + - flags diff --git a/dts/bindings/gpio/adi,sdp-120.yaml b/dts/bindings/gpio/adi,sdp-120.yaml new file mode 100644 index 00000000000..02d1249cdd5 --- /dev/null +++ b/dts/bindings/gpio/adi,sdp-120.yaml @@ -0,0 +1,74 @@ +# Copyright (c) 2024 Analog Devices Inc. +# Copyright (c) 2024 Baylibre, SAS + +# SPDX-License-Identifier: Apache-2.0 + +description: | + GPIO pins exposed on a Analog devices SDP interface. + + 120-pin SDP interface: + + 1 VIN NC 120 + 2 NC NC 119 + 3 GND GND 118 + 4 GND GND 117 + 5 USB_VBUS VIO 116 + 6 GND GND 115 + 7 PAR_D23 PAR_D22 114 + 8 PAR_D21 PAR_D20 113 + 9 PAR_D19 PAR_D18 112 + 10 PAR_D17 PAR_D16 111 + 11 GND PAR_D15 110 + 12 PAR_D14 GND 109 + 13 PAR_D13 PAR_D12 108 + 14 PAR_D11 PAR_D10 107 + 15 PAR_D9 PAR_D8 106 + 16 PAR_D7 PAR_D6 105 + 17 GND GND 104 + 18 PAR_D5 PAR_D4 103 + 19 PAR_D3 PAR_D2 102 + 20 PAR_D1 PAR_D0 101 + 21 PAR_RD_N PAR_WR_N 100 + 22 PAR_CS_N PAR_INT 99 + 23 GND GND 98 + 24 PAR_A3 PAR_A2 97 + 25 PAR_A1 PAR_A0 96 + 26 PAR_FS3 PAR_FS2 95 + 27 PAR_FS1 PAR_CLK 94 + 28 GND GND 93 + 29 SPORT_TDV0 SPORT_RSCLK 92 + 30 SPORT_TDV1 SPORT_DR0 91 + 31 SPORT_DR1 SPORT_RFS 90 + 32 SPORT_DT1 SPORT_TFS 89 + 33 SPI_D2 SPORT_DT0 88 + 34 SPI_D3 SPORT_TSCLK 87 + 35 SERIAL_INT GND 86 + 36 GND SPI_SEL_A_N 85 + 37 SPI_SEL_B_N SPI_MOSI 84 + 38 SPI_SEL_C_N SPI_MISO 83 + 39 SPI_SEL1/SPI_SS_N SPI_CLK 82 + 40 GND GND 81 + 41 SDA_1 SDA_0 80 + 42 SCL_1 SCL_0 79 + 43 GPIO0 GPIO1 78 + 44 GPIO2 GPIO3 77 + 45 GPIO4 GPIO5 76 + 46 GND GND 75 + 47 GPIO6 GPIO7 74 + 48 TMR_A TMR_B 73 + 49 TMR_C TMR_D 72 + 50 NC CLKOUT 71 + 51 NC NC 70 + 52 GND GND 69 + 53 NC NC 68 + 54 NC NC 67 + 55 NC NC 66 + 56 EEPROM_A0 WAKE_N 65 + 57 RESET_OUT_N SLEEP_N 64 + 58 GND GND 63 + 59 UART_RX UART_TX 62 + 60 RESET_IN_N BMODE1 61 + +compatible: "adi,sdp-120" + +include: [gpio-nexus.yaml, base.yaml] diff --git a/dts/bindings/gpio/brcm,brcmstb-gpio.yaml b/dts/bindings/gpio/brcm,brcmstb-gpio.yaml new file mode 100644 index 00000000000..55f58a9f3fd --- /dev/null +++ b/dts/bindings/gpio/brcm,brcmstb-gpio.yaml @@ -0,0 +1,19 @@ +# Copyright (c) 2024 Junho Lee +# SPDX-License-Identifier: Apache-2.0 + +description: BRCMSTB GPIO + +compatible: "brcm,brcmstb-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/intel,gpio.yaml b/dts/bindings/gpio/intel,gpio.yaml index f702e57204b..f8c434cd0d2 100644 --- a/dts/bindings/gpio/intel,gpio.yaml +++ b/dts/bindings/gpio/intel,gpio.yaml @@ -5,26 +5,24 @@ description: Intel GPIO node compatible: "intel,gpio" -include: [gpio-controller.yaml, base.yaml] +include: [acpi.yaml, gpio-controller.yaml, base.yaml] properties: reg: - required: true + description: reg properties not required if acpi enumerated group-index: type: int description: Group number for this GPIO entry interrupts: - required: true + description: interrupts properties not required if acpi enumerated ngpios: - required: true description: Number of pins for this GPIO entry pin-offset: type: int - required: true description: Pin offset of this GPIO entry "#gpio-cells": diff --git a/dts/bindings/gpio/nxp,gpio-cluster.yaml b/dts/bindings/gpio/nxp,gpio-cluster.yaml new file mode 100644 index 00000000000..73f5de72ea2 --- /dev/null +++ b/dts/bindings/gpio/nxp,gpio-cluster.yaml @@ -0,0 +1,9 @@ +description: A group of GPIOs that share an interrupt. + +compatible: "nxp,gpio-cluster" + +include: [base.yaml] + +properties: + interrupts: + required: true diff --git a/dts/bindings/gpio/zephyr,gpio-emul.yaml b/dts/bindings/gpio/zephyr,gpio-emul.yaml index b1810ef2699..fc2b09cd839 100644 --- a/dts/bindings/gpio/zephyr,gpio-emul.yaml +++ b/dts/bindings/gpio/zephyr,gpio-emul.yaml @@ -8,9 +8,6 @@ compatible: "zephyr,gpio-emul" include: [gpio-controller.yaml, base.yaml] properties: - reg: - required: true - rising-edge: description: Enables support for rising edge interrupt detection type: boolean diff --git a/dts/bindings/i2c/silabs,gecko-i2c.yaml b/dts/bindings/i2c/silabs,gecko-i2c.yaml index 8d1e4d94ee7..ef694376ac9 100644 --- a/dts/bindings/i2c/silabs,gecko-i2c.yaml +++ b/dts/bindings/i2c/silabs,gecko-i2c.yaml @@ -5,7 +5,7 @@ description: Silabs Gecko I2C node compatible: "silabs,gecko-i2c" -include: i2c-controller.yaml +include: [i2c-controller.yaml, pinctrl-device.yaml] properties: reg: @@ -14,15 +14,8 @@ properties: interrupts: required: true - # Note: Not all SoC series support setting individual pin location. If this - # is a case all location-* properties need to have identical value. - - location-sda: - type: array + pinctrl-0: required: true - description: SDA pin configuration defined as - location-scl: - type: array + pinctrl-names: required: true - description: SCL pin configuration defined as diff --git a/dts/bindings/i2s/intel,ssp-dai.yaml b/dts/bindings/i2s/intel,ssp-dai.yaml index 59a778baa1f..8fc6f1a2e90 100644 --- a/dts/bindings/i2s/intel,ssp-dai.yaml +++ b/dts/bindings/i2s/intel,ssp-dai.yaml @@ -1,8 +1,7 @@ -# Copyright (c) 2022 Intel Corporation -# +# Copyright (c) 2024 Intel Corporation # SPDX-License-Identifier: Apache-2.0 -description: Intel SSP DAI controller +description: Intel SSP DAI node compatible: "intel,ssp-dai" @@ -11,18 +10,3 @@ include: base.yaml properties: reg: required: true - - interrupts: - required: true - - interrupt-parent: - required: true - - dmas: - required: true - - dma-names: - required: true - - i2svss: - type: array diff --git a/dts/bindings/i2s/intel,ssp.yaml b/dts/bindings/i2s/intel,ssp.yaml new file mode 100644 index 00000000000..76b59e7c2bc --- /dev/null +++ b/dts/bindings/i2s/intel,ssp.yaml @@ -0,0 +1,32 @@ +# Copyright (c) 2024 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +description: Intel SSP DAI controller + +compatible: "intel,ssp" + +include: base.yaml + +properties: + reg: + required: true + + interrupts: + required: true + + interrupt-parent: + required: true + + dmas: + required: true + + dma-names: + required: true + + i2svss: + type: array + + ssp-index: + type: int + required: true diff --git a/dts/bindings/i3c/nuvoton,npcx-i3c.yaml b/dts/bindings/i3c/nuvoton,npcx-i3c.yaml new file mode 100644 index 00000000000..0633da8e92a --- /dev/null +++ b/dts/bindings/i3c/nuvoton,npcx-i3c.yaml @@ -0,0 +1,52 @@ +# Copyright (c) 2024 Nuvoton Technology Corporation. +# SPDX-License-Identifier: Apache-2.0 + +description: | + Nuvoton I3C controller + + Representation: + + /* If CONFIG_I3C_NPCX is enabled, the suggested clock configuration is as follows: */ + &pcc { + clock-frequency = ; /* OFMCLK runs at 90MHz */ + core-prescaler = <3>; /* CORE_CLK runs at 30MHz */ + apb1-prescaler = <6>; /* APB1_CLK runs at 15MHz */ + apb2-prescaler = <6>; /* APB2_CLK runs at 15MHz */ + apb3-prescaler = <6>; /* APB3_CLK runs at 15MHz */ + apb4-prescaler = <3>; /* APB4_CLK runs at 30MHz */ + }; + + &rst { + status = "okay"; + }; + + &i3c0 { + status = "okay"; + + /* I3C clock frequency suggestion = */ + * Full speed = <12500000, 4170000> + * Normal speed = <7500000, 1500000> + */ + i3c-scl-hz = <12500000>; + i3c-od-scl-hz = <4170000>; + }; + +compatible: "nuvoton,npcx-i3c" + +include: [i3c-controller.yaml, pinctrl-device.yaml, reset-device.yaml] + +properties: + reg: + required: true + + interrupts: + required: true + + resets: + required: true + + i3c-od-scl-hz: + type: int + description: | + Open Drain Frequency for the I3C controller. When undefined, use + the controller default or as specified by the I3C specification. diff --git a/dts/bindings/input/pixart,paw32xx.yaml b/dts/bindings/input/pixart,paw32xx.yaml new file mode 100644 index 00000000000..0df4424a3cb --- /dev/null +++ b/dts/bindings/input/pixart,paw32xx.yaml @@ -0,0 +1,52 @@ +# Copyright 2024 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +description: PAW32xx ultra low power wireless mouse chip + +compatible: "pixart,paw32xx" + +include: spi-device.yaml + +properties: + motion-gpios: + type: phandle-array + required: true + description: + GPIO connected to the motion pin, active low. + + zephyr,axis-x: + type: int + required: true + description: | + The input code for the X axis to report for the device, typically any of + INPUT_REL_*. No report produced for the device X axis if unspecified. + + zephyr,axis-y: + type: int + required: true + description: | + The input code for the Y axis to report for the device, typically any of + INPUT_REL_*. No report produced for the device Y axis if unspecified. + + res-cpi: + type: int + description: | + CPI resolution for the sensor. This can also be changed in runtime using + the paw32xx_set_resolution() API. + + invert-x: + type: boolean + description: | + Invert X axis values. + + invert-y: + type: boolean + description: | + Invert Y axis values. + + force-awake: + type: boolean + description: | + Initialize the sensor in "force awake" mode. This can also be enabled or + disabled in runtime by the application using the paw32xx_force_awake() + API. diff --git a/dts/bindings/ipm/nxp,lpc-mailbox.yaml b/dts/bindings/ipm/nxp,lpc-mailbox.yaml index 12f99a83386..14e96d7e0db 100644 --- a/dts/bindings/ipm/nxp,lpc-mailbox.yaml +++ b/dts/bindings/ipm/nxp,lpc-mailbox.yaml @@ -5,7 +5,7 @@ description: LPC MAILBOX compatible: "nxp,lpc-mailbox" -include: base.yaml +include: [base.yaml, reset-device.yaml] properties: reg: diff --git a/dts/bindings/kscan/holtek,ht16k33-keyscan.yaml b/dts/bindings/kscan/holtek,ht16k33-keyscan.yaml deleted file mode 100644 index d39278fb66e..00000000000 --- a/dts/bindings/kscan/holtek,ht16k33-keyscan.yaml +++ /dev/null @@ -1,7 +0,0 @@ -description: Holtek HT16K33 keyscan - -compatible: "holtek,ht16k33-keyscan" - -include: base.yaml - -on-bus: ht16k33 diff --git a/dts/bindings/led_strip/apa,apa102.yaml b/dts/bindings/led_strip/apa,apa102.yaml index 0a6e6a00a0d..2d3b7b66529 100644 --- a/dts/bindings/led_strip/apa,apa102.yaml +++ b/dts/bindings/led_strip/apa,apa102.yaml @@ -2,4 +2,4 @@ description: APA102 SPI LED strip compatible: "apa,apa102" -include: spi-device.yaml +include: [spi-device.yaml, led-strip.yaml] diff --git a/dts/bindings/led_strip/greeled,lpd8803.yaml b/dts/bindings/led_strip/greeled,lpd8803.yaml index 6baca4898d6..7a7dc8158c2 100644 --- a/dts/bindings/led_strip/greeled,lpd8803.yaml +++ b/dts/bindings/led_strip/greeled,lpd8803.yaml @@ -5,4 +5,4 @@ description: GreeLed LPD8803 SPI LED strip compatible: "greeled,lpd8803" -include: spi-device.yaml +include: [spi-device.yaml, led-strip.yaml] diff --git a/dts/bindings/led_strip/greeled,lpd8806.yaml b/dts/bindings/led_strip/greeled,lpd8806.yaml index 0a0f0e9f6ee..971155b210d 100644 --- a/dts/bindings/led_strip/greeled,lpd8806.yaml +++ b/dts/bindings/led_strip/greeled,lpd8806.yaml @@ -5,4 +5,4 @@ description: GreeLed LPD8806 SPI LED strip compatible: "greeled,lpd8806" -include: spi-device.yaml +include: [spi-device.yaml, led-strip.yaml] diff --git a/dts/bindings/led_strip/led-strip.yaml b/dts/bindings/led_strip/led-strip.yaml new file mode 100644 index 00000000000..f8ffb62e683 --- /dev/null +++ b/dts/bindings/led_strip/led-strip.yaml @@ -0,0 +1,24 @@ +# Copyright (c) 2019, Linaro Limited +# Copyright (c) 2019, Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +# Common fields for LED strips + +properties: + chain-length: + type: int + required: true + description: | + The number of devices in the daisy-chain. + + color-mapping: + type: array + required: true + description: | + Channel to color mapping (or pixel order). + + For example a GRB channel to color mapping would be + + color-mapping = ; diff --git a/dts/bindings/led_strip/ti,tlc5971.yaml b/dts/bindings/led_strip/ti,tlc5971.yaml index 2da4f234e64..de66dd7d2af 100644 --- a/dts/bindings/led_strip/ti,tlc5971.yaml +++ b/dts/bindings/led_strip/ti,tlc5971.yaml @@ -6,7 +6,8 @@ description: | Driver bindings for daisy chains of a TLC5971 devices using a single device tree node. Length of daisy chains in pixels is defined by the chain-length - property. + property. Note: chain-length must be a multiple of 4. A single TLC5971 device + supports 4 RGB LEDs. The color order of the TLC5971 is BGR. Applications can provide custom mappings using the color-mapping property. @@ -28,23 +29,4 @@ description: | compatible: "ti,tlc5971" -include: spi-device.yaml - -properties: - chain-length: - type: int - required: true - description: | - The number of RGB LEDs in the daisy-chain. - Must be multiple of 4. A single TLC5971 device supports 4 RGB LEDs. - - color-mapping: - type: array - required: true - description: | - Channel to color mapping (or pixel order). - For example a BGR channel to color mapping would be - - color-mapping = ; +include: [spi-device.yaml, led-strip.yaml] diff --git a/dts/bindings/led_strip/ti,tlc59731.yaml b/dts/bindings/led_strip/ti,tlc59731.yaml new file mode 100644 index 00000000000..596bee98d16 --- /dev/null +++ b/dts/bindings/led_strip/ti,tlc59731.yaml @@ -0,0 +1,13 @@ +# Copyright (c) 2024 Javad Rahimipetroudi +# SPDX-License-Identifier: Apache-2.0 + +compatible: "ti,tlc59731" +description: TLC59731 RGB LED Controller +include: [led-strip.yaml] + +properties: + gpios: + required: true + type: phandle-array + description: | + GPIO to send command data to the controller. diff --git a/dts/bindings/led_strip/ws2812.yaml b/dts/bindings/led_strip/ws2812.yaml index ff594a862cd..6b8e59b7e9e 100644 --- a/dts/bindings/led_strip/ws2812.yaml +++ b/dts/bindings/led_strip/ws2812.yaml @@ -34,25 +34,9 @@ description: | property. The pixel order depends on the model and it can be configured using the color-mapping property. -properties: - chain-length: - type: int - required: true - description: | - The number of devices in the daisy-chain. - - color-mapping: - type: array - required: true - description: | - Channel to color mapping (or pixel order). - - For example a GRB channel to color mapping would be - - color-mapping = ; +include: led-strip.yaml +properties: reset-delay: type: int default: 8 diff --git a/dts/bindings/mdio/st,stm32-mdio.yaml b/dts/bindings/mdio/st,stm32-mdio.yaml new file mode 100644 index 00000000000..e536ed1c23a --- /dev/null +++ b/dts/bindings/mdio/st,stm32-mdio.yaml @@ -0,0 +1,24 @@ +# Copyright (c) 2024 BayLibre, SAS +# Copyright (c) 2024 Analog Devices Inc. +# SPDX-License-Identifier: Apache-2.0 + +description: ST MDIO Features + +compatible: "st,stm32-mdio" + +include: [mdio-controller.yaml, pinctrl-device.yaml] + +properties: + "#address-cells": + required: true + const: 1 + + "#size-cells": + required: true + const: 0 + + pinctrl-0: + required: true + + pinctrl-names: + required: true diff --git a/dts/bindings/memory-controllers/renesas,smartbond-nor-psram.yaml b/dts/bindings/memory-controllers/renesas,smartbond-nor-psram.yaml new file mode 100644 index 00000000000..f55e064683b --- /dev/null +++ b/dts/bindings/memory-controllers/renesas,smartbond-nor-psram.yaml @@ -0,0 +1,260 @@ +# Copyright (c) 2023 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +description: Renesas Smartbond(tm) NOR/PSRAM controller + +include: base.yaml + +compatible: "renesas,smartbond-nor-psram" + +properties: + reg: + required: true + + is-ram: + type: boolean + description: | + If present, the memory controller will be configured to drive PSRAM devices. + + dev-size: + type: int + required: true + description: | + Memory size/capacity in bits. + + dev-type: + type: int + required: true + description: | + Device type, part of device ID, used to verify the memory device used. + + dev-density: + type: int + required: true + description: | + Device density, part of device ID, used to verify the memory device used. + [7:0] should reflect the density value itself and [15:8] should reflect + the mask that should be applied to the returned device ID value. + This is because part of its byte value might contain invalid bits. + + dev-id: + type: int + required: true + description: | + Manufacturer ID, part of device ID, used to verify the memory device used. + + reset-delay-us: + type: int + required: true + description: | + Time in microseconds (us) the memory device can accept the next command following a SW reset. + + read-cs-idle-min-ns: + type: int + required: true + description: | + Min. time, in nanoseconds, the #CS line should remain inactive between + the transmission of two different instructions. + + erase-cs-idle-min-ns: + type: int + description: | + Min. time, in nanoseconds, the #CS line should remain inactive after the execution + of a write enable, erase, erase suspend or erase resume instruction. This setting + is not used if is-ram property is present. + + enter-qpi-cmd: + type: int + description: | + Command to enter the QPI mode supported by a memory device + (should be transmitted in single bus mode). + + exit-qpi-cmd: + type: int + description: | + Command to exit the QPI mode supported by a memory device + (should be transmitted in quad bus mode). + + enter-qpi-mode: + type: boolean + description: | + If present, the memory device will enter the QPI mode which typically reflects that + all bytes be sent in quad bus mode. It's a pre-requisite that read and write + commands, that should be read-cmd and write-cmd respectively, reflect the QPI mode. + + read-cmd: + type: int + default: 0x03 + description: | + Read command for single/burst read accesses in auto mode. Default value is the opcode + for single mode which is supported by all memory devices. + + write-cmd: + type: int + default: 0x02 + description: | + Write command for single/burst write accesses in auto mode. Default value is the opcode + for single mode which is supported by all memory devices. + + clock-mode: + type: string + enum: + - "spi-mode0" + - "spi-mode3" + default: "spi-mode0" + description: | + Clock mode when #CS is idle/inactive + + - Mode0: #CLK is low when #CS is inactive + - Mode3: #CLK is high when #CS is inactive + + Mode0 is selected by default as it should be supported by all memory devices. + + addr-range: + type: string + enum: + - "addr-range-24bit" + - "addr-range-32bit" + default: "addr-range-24bit" + description: | + Address size to use in auto mode. In 24-bit mode up to 16MB can be + accessed whilst in 32-bit mode up to 32MB can be accessed which is + the max. address space supported by QSPICx. Default value is 24-bit + mode which is supported by all memory devices. + + clock-div: + type: int + description: | + Clock divider for QSPIC2 controller. The clock path of + this block is always DIV1 which reflects the current + system clock. + + tcem-max-us: + type: int + description: | + If a non zero value is applied, then Tcem should be taken into + consideration by QSPIC2 so that it can split a burst read/write + access in case the total time exceeds the defined value + (at the cost of extra cycles required for re-sending the instruction, + address and dummy bytes, if any). This setting is meaningful only if + is-ram is present. This value reflects the max. time in microseconds + the #CS line can be driven low in a write/read burst access + (required for the auto-refresh mechanism, when supported). + + dummy-bytes-count: + type: string + required: true + enum: + - "dummy-bytes-count0" + - "dummy-bytes-count1" + - "dummy-bytes-count2" + - "dummy-bytes-count4" + description: | + Number of dummy bytes to send for single/burst read access in auto mode. + + extra-byte-enable: + type: boolean + description: | + If present, the extra byte will be sent after the dummy bytes, if any. + This should be useful if 3 dummy bytes are required. In such a case, + dummy-bytes-count should be set to 2. + + extra-byte: + type: int + description: | + Extra byte to be sent, if extra-byte-enable is present. + + rx-addr-mode: + type: string + enum: + - "single-spi" + - "dual-spi" + - "quad-spi" + default: "single-spi" + description: | + Describes the mode of SPI bus during the address phase for single/burst + read accesses in auto mode. Default value is single mode which should be + supported by all memory devices. + + rx-inst-mode: + type: string + enum: + - "single-spi" + - "dual-spi" + - "quad-spi" + default: "single-spi" + description: | + Describes the mode of SPI bus during the instruction phase for single/burst + read accesses in auto mode. Default value is single mode which should be + supported by all memory devices. + + rx-data-mode: + type: string + enum: + - "single-spi" + - "dual-spi" + - "quad-spi" + default: "single-spi" + description: | + Describes the mode of SPI bus during the data phase for single/burst + read accesses in auto mode. Default value is single mode which should + be supported by all memory devices. + + rx-dummy-mode: + type: string + enum: + - "single-spi" + - "dual-spi" + - "quad-spi" + default: "single-spi" + description: | + Describes the mode of SPI bus during the dummy bytes phase for single/burst + read accesses in auto mode. The single mode should be supported by all + memory devices. + + rx-extra-mode: + type: string + enum: + - "single-spi" + - "dual-spi" + - "quad-spi" + description: | + Describes the mode of SPI bus during the extra byte phase for single/burst + read accesses in auto mode. Default value is single mode which should be + supported by all memory devices. + + tx-addr-mode: + type: string + enum: + - "single-spi" + - "dual-spi" + - "quad-spi" + default: "single-spi" + description: | + Describes the mode of SPI bus during the address phase for single/burst + write accesses in auto mode. Default value is single mode which should + be supported by all memory devices. + + tx-inst-mode: + type: string + enum: + - "single-spi" + - "dual-spi" + - "quad-spi" + default: "single-spi" + description: | + Describes the mode of SPI bus during the instruction phase for single/burst + write accesses in auto mode. The single mode should be supported by all + memory devices. + + tx-data-mode: + type: string + enum: + - "single-spi" + - "dual-spi" + - "quad-spi" + default: "single-spi" + description: | + Describes the mode of SPI bus during the data phase for single/burst + write accesses in auto mode. Default value is single mode which should + be supported by all memory devices. diff --git a/dts/bindings/mfd/adi,adp5585.yaml b/dts/bindings/mfd/adi,adp5585.yaml new file mode 100644 index 00000000000..9d2456b6a83 --- /dev/null +++ b/dts/bindings/mfd/adi,adp5585.yaml @@ -0,0 +1,19 @@ +# Copyright 2024 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: Analog ADP5585 GPIO/keypad/PWM chip + +compatible: "adi,adp5585" + +include: i2c-device.yaml + +properties: + reset-gpios: + type: phandle-array + description: RESET pin + + nint-gpios: + type: phandle-array + description: | + Connection for the NINT signal. This signal is active-low when + produced by adp5585 GPIO node. diff --git a/dts/bindings/mipi-dbi/mipi-dbi-device.yaml b/dts/bindings/mipi-dbi/mipi-dbi-device.yaml index a24ce07bb48..4f68fadf731 100644 --- a/dts/bindings/mipi-dbi/mipi-dbi-device.yaml +++ b/dts/bindings/mipi-dbi/mipi-dbi-device.yaml @@ -11,3 +11,14 @@ properties: mipi-max-frequency: type: int description: Maximum clock frequency of device's MIPI interface in Hz + + mipi-mode: + type: int + description: | + MIPI DBI mode in use. Use the macros, not the actual enum value. Here is + the concordance list (see dt-bindings/mipi_dbi/mipi_dbi.h) + 1 MIPI_DBI_MODE_SPI_3WIRE + 2 MIPI_DBI_MODE_SPI_4WIRE + enum: + - 1 + - 2 diff --git a/dts/bindings/mmc/renesas,rcar-emmc.yaml b/dts/bindings/mmc/renesas,rcar-emmc.yaml new file mode 100644 index 00000000000..fe786d2e197 --- /dev/null +++ b/dts/bindings/mmc/renesas,rcar-emmc.yaml @@ -0,0 +1,63 @@ +description: Renesas R-Car eMMC + +compatible: "renesas,rcar-mmc" + +include: [sdhc.yaml, mmc.yaml, pinctrl-device.yaml, reset-device.yaml] + +properties: + clocks: + required: true + + reg: + required: true + + pinctrl-0: + required: true + + pinctrl-names: + required: true + + max-bus-freq: + required: true + + non-removable: + type: boolean + description: | + Non-removable slots (like eMMC), which are assumed to always be present, + will affect the `sdhc_card_present` call. This call will always return + true if this property exists for the node. + + mmc-sdr104-support: + type: boolean + + cd-gpios: + type: phandle-array + description: Card Detect pin + + pwr-gpios: + type: phandle-array + description: Power pin + + vmmc-supply: + type: phandle + description: | + Supply for the card power + + vqmmc-supply: + type: phandle + description: | + Supply for the bus IO line power, such as a level shifter. + If the level shifter is controlled by a GPIO line, this shall + be modeled as a "regulator-fixed" with a GPIO line for + switching the level shifter on/off. + + bus-width: + type: int + default: 1 + description: | + Bus width for SDMMC access, defaults to the minimum necessary + number of bus lines + enum: + - 1 + - 4 + - 8 diff --git a/dts/bindings/modem/sqn,gm02s.yaml b/dts/bindings/modem/sqn,gm02s.yaml new file mode 100644 index 00000000000..223b8c102a3 --- /dev/null +++ b/dts/bindings/modem/sqn,gm02s.yaml @@ -0,0 +1,13 @@ +# Copyright(c) 2024 DPTechnics bv +# SPDX-License-Identifier: Apache-2.0 + +description: Sequans Monarch 2 GM02S Modem + +compatible: "sqn,gm02s" + +include: uart-device.yaml + +properties: + mdm-reset-gpios: + type: phandle-array + required: true diff --git a/dts/bindings/mtd/nxp,imx-flexspi-is66wvq8m4.yaml b/dts/bindings/mtd/nxp,imx-flexspi-is66wvq8m4.yaml new file mode 100644 index 00000000000..4b2f2204adf --- /dev/null +++ b/dts/bindings/mtd/nxp,imx-flexspi-is66wvq8m4.yaml @@ -0,0 +1,8 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: ISSI IS66WVQ8M4 pSRAM on NXP FlexSPI bus + +compatible: "nxp,imx-flexspi-is66wvq8m4" + +include: nxp,imx-flexspi-device.yaml diff --git a/dts/bindings/ospi/st,stm32-ospi.yaml b/dts/bindings/ospi/st,stm32-ospi.yaml index aaac4141455..b1666d67d91 100644 --- a/dts/bindings/ospi/st,stm32-ospi.yaml +++ b/dts/bindings/ospi/st,stm32-ospi.yaml @@ -119,3 +119,48 @@ properties: Note: You might need to enable the OCTOSPI I/O manager clock to use the property. Please refer to Reference Manual. The clock can be enabled in the devicetree. + + clk-port: + type: int + enum: + - 1 + - 2 + description: | + Specifies which port of the OCTOSPI IO Manager is used for the clk pin. + + If absent, then n is used where `n` is the OSPI + instance number. + + Note: You might need to enable the OCTOSPI I/O manager clock to use the + property. Please refer to Reference Manual. + The clock can be enabled in the devicetree. + + dqs-port: + type: int + enum: + - 1 + - 2 + description: | + Specifies which port of the OCTOSPI IO Manager is used for the dqs pin. + + If absent, then n is used where `n` is the OSPI + instance number. + + Note: You might need to enable the OCTOSPI I/O manager clock to use the + property. Please refer to Reference Manual. + The clock can be enabled in the devicetree. + + ncs-port: + type: int + enum: + - 1 + - 2 + description: | + Specifies which port of the OCTOSPI IO Manager is used for the ncs pin. + + If absent, then n is used where `n` is the OSPI + instance number. + + Note: You might need to enable the OCTOSPI I/O manager clock to use the + property. Please refer to Reference Manual. + The clock can be enabled in the devicetree. diff --git a/dts/bindings/pinctrl/ambiq,apollo3-pinctrl.yaml b/dts/bindings/pinctrl/ambiq,apollo3-pinctrl.yaml new file mode 100644 index 00000000000..6035955af50 --- /dev/null +++ b/dts/bindings/pinctrl/ambiq,apollo3-pinctrl.yaml @@ -0,0 +1,127 @@ +# Copyright (c) 2023 Ambiq Micro Inc. +# SPDX-License-Identifier: Apache-2.0 + +description: | + The Ambiq Apollo3 pin controller is a node responsible for controlling + pin function selection and pin properties, such as routing a UART0 TX + to pin 60 and enabling the pullup resistor on that pin. + + 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: "ambiq,apollo3-pinctrl" + +include: base.yaml + +child-binding: + description: | + Definitions for a pinctrl state. + child-binding: + + include: + - name: pincfg-node.yaml + property-allowlist: + - input-enable + - drive-push-pull + - drive-open-drain + - bias-high-impedance + - bias-pull-up + - bias-pull-down + + 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: + - "0.1" + - "0.5" + - "0.75" + - "1.0" + default: "0.1" + description: | + The drive strength of a pin, relative to full-driver strength. + The default value is 0.1, which is the reset value of resigers + PADREGx.PADnSTRNG and ALTPADCFGx.PADn_DS1. + ambiq,pull-up-ohms: + type: int + enum: + - 1500 + - 6000 + - 12000 + - 24000 + default: 1500 + description: | + The 1.5K-24K pullup values are valid for select I2C enabled pads. + For Apollo3 these pins are 0-1,5-6,8-9,25,27,39-40,42-43,48-49. + The default value is 1500 ohms, which is the reset value of + register PADREGx.PADxRSEL. + ambiq,iom-nce-module: + type: int + default: 0 + description: | + IOM nCE module select, selects the SPI channel (CE) number (0-3). + The default value is 0, which is the reset value of + register CFGx.GPIOnOUTCFG. If the pin is not a CE, this + descriptor will be ignored. + ambiq,iom-mspi: + type: int + default: 0 + description: | + Indicates the module which uses specific CE pin, 1 if CE is IOM, 0 if MSPI. + User should check g_ui8NCEtable in am_hal_gpio.c for the mapping + information and config the pins accordingly, we give a default value + 0 here to make it be consistent with AM_HAL_GPIO_PINCFG_DEFAULT in + ambiq hal. If the pin is not a CE, this descriptor will be ignored. + ambiq,iom-num: + type: int + default: 0 + description: | + Indicates the instance which uses specific CE pin. + IOM number (0-5) or MSPI (0-2). + User should check g_ui8NCEtable in am_hal_gpio.c for the mapping + information and config the pins accordingly, we give a default value + 0 here to make it be consistent with AM_HAL_GPIO_PINCFG_DEFAULT in + ambiq hal. If the pin is not a CE, this descriptor will be ignored. diff --git a/dts/bindings/pinctrl/nuvoton,numaker-pinctrl.yaml b/dts/bindings/pinctrl/nuvoton,numaker-pinctrl.yaml index 4474f9b089f..3ff6200ee39 100644 --- a/dts/bindings/pinctrl/nuvoton,numaker-pinctrl.yaml +++ b/dts/bindings/pinctrl/nuvoton,numaker-pinctrl.yaml @@ -83,3 +83,6 @@ child-binding: Set the speed of a pin. This setting effectively limits the slew rate of the output signal. Hardware default configuration is low. Fast slew rate could support fast speed pins, like as SPI CLK up to 50MHz. + digital-path-disable: + type: boolean + description: disable digital path on a pin. diff --git a/dts/bindings/pinctrl/st,stm32-pinctrl.yaml b/dts/bindings/pinctrl/st,stm32-pinctrl.yaml index b412d5dfddb..a9f41602643 100644 --- a/dts/bindings/pinctrl/st,stm32-pinctrl.yaml +++ b/dts/bindings/pinctrl/st,stm32-pinctrl.yaml @@ -20,12 +20,12 @@ properties: remap-pa11: type: boolean description: Remaps the PA11 pin to operate as PA9 pin. - Use of this property is restricted to STM32G0 SoCs. + Use of this property is restricted to STM32G0 and STM32C0 SoCs. remap-pa12: type: boolean description: Remaps the PA12 pin to operate as PA10 pin. - Use of this property is restricted to STM32G0 SoCs. + Use of this property is restricted to STM32G0 and STM32C0 SoCs. remap-pa11-pa12: type: boolean diff --git a/dts/bindings/pwm/nxp,kinetis-ftm-pwm.yaml b/dts/bindings/pwm/nxp,kinetis-ftm-pwm.yaml index fd195c12086..48509b194f8 100644 --- a/dts/bindings/pwm/nxp,kinetis-ftm-pwm.yaml +++ b/dts/bindings/pwm/nxp,kinetis-ftm-pwm.yaml @@ -1,4 +1,4 @@ -# Copyright (c) 2017, NXP +# Copyright 2017, 2024 NXP # SPDX-License-Identifier: Apache-2.0 description: Kinetis FTM PWM @@ -14,6 +14,25 @@ properties: pinctrl-0: required: true + clock-source: + type: string + required: true + enum: + - "system" + - "fixed" + - "external" + description: | + Select one of three possible clock sources for the FTM counter: + * system: it's the bus interface clock driving the FTM module. Usually + provides higher timer resolution than the other two clock sources. + * fixed: it's a fixed clock defined by chip integration. + * external: it's a clock that can be accessed externally to the chip and + passes through a sychronizer clocked by the FTM bus interface clock. + + This clock source selection is independent of the bus interface clock + driving the FTM module. Refer to the chip specific documentation for + further information. + pwm-cells: - channel # period in terms of nanoseconds diff --git a/dts/bindings/regulator/adi,adp5360-regulator.yaml b/dts/bindings/regulator/adi,adp5360-regulator.yaml index e54a305e80f..05d17382602 100644 --- a/dts/bindings/regulator/adi,adp5360-regulator.yaml +++ b/dts/bindings/regulator/adi,adp5360-regulator.yaml @@ -1,5 +1,5 @@ # Copyright (c), 2023 Nordic Semiconductor ASA -# SPDX -License-Identifier: Apache-2.0 +# SPDX-License-Identifier: Apache-2.0 description: | Analog Devices ADP3560 PMIC diff --git a/dts/bindings/regulator/cirrus,cp9314.yaml b/dts/bindings/regulator/cirrus,cp9314.yaml index 228cbb8868a..9718c20b391 100644 --- a/dts/bindings/regulator/cirrus,cp9314.yaml +++ b/dts/bindings/regulator/cirrus,cp9314.yaml @@ -1,5 +1,5 @@ # Copyright (c) 2024 Cirrus Logic, Inc. -# SPDX -License-Identifier: Apache-2.0 +# SPDX-License-Identifier: Apache-2.0 description: | Cirrus CP9314 Buck Switched Cap DC/DC Converter @@ -27,6 +27,10 @@ properties: type: phandle-array description: GPIO tied to EN pin + cirrus,pgood-gpios: + type: phandle-array + description: GPIO tied to PGOOD pin + cirrus,initial-switched-capacitor-mode: type: string enum: diff --git a/dts/bindings/regulator/maxim,max20335-regulator.yaml b/dts/bindings/regulator/maxim,max20335-regulator.yaml index d23a1fdf1c1..90324568172 100644 --- a/dts/bindings/regulator/maxim,max20335-regulator.yaml +++ b/dts/bindings/regulator/maxim,max20335-regulator.yaml @@ -1,5 +1,5 @@ # Copyright (c), 2023 Grinn -# SPDX -License-Identifier: Apache-2.0 +# SPDX-License-Identifier: Apache-2.0 description: | Maxim MAX20335 PMIC diff --git a/dts/bindings/regulator/nordic,npm1100.yaml b/dts/bindings/regulator/nordic,npm1100.yaml index b70523cfadd..bf1a77a2ac8 100644 --- a/dts/bindings/regulator/nordic,npm1100.yaml +++ b/dts/bindings/regulator/nordic,npm1100.yaml @@ -1,5 +1,5 @@ # Copyright (c), 2023 Nordic Semiconductor ASA -# SPDX -License-Identifier: Apache-2.0 +# SPDX-License-Identifier: Apache-2.0 description: | Nordic nPM1100 PMIC diff --git a/dts/bindings/regulator/nordic,npm1300-regulator.yaml b/dts/bindings/regulator/nordic,npm1300-regulator.yaml index e0fc28ff8be..cdb0999b23a 100644 --- a/dts/bindings/regulator/nordic,npm1300-regulator.yaml +++ b/dts/bindings/regulator/nordic,npm1300-regulator.yaml @@ -1,5 +1,5 @@ # Copyright (c), 2023 Nordic Semiconductor ASA -# SPDX -License-Identifier: Apache-2.0 +# SPDX-License-Identifier: Apache-2.0 description: | Nordic nPM1300 PMIC diff --git a/dts/bindings/regulator/nordic,npm6001-regulator.yaml b/dts/bindings/regulator/nordic,npm6001-regulator.yaml index 378f6c0a8ec..731ebe828c3 100644 --- a/dts/bindings/regulator/nordic,npm6001-regulator.yaml +++ b/dts/bindings/regulator/nordic,npm6001-regulator.yaml @@ -1,5 +1,5 @@ # Copyright (c), 2022 Nordic Semiconductor ASA -# SPDX -License-Identifier: Apache-2.0 +# SPDX-License-Identifier: Apache-2.0 description: | Nordic nPM6001 PMIC diff --git a/dts/bindings/regulator/nxp,pca9420.yaml b/dts/bindings/regulator/nxp,pca9420.yaml index 2e4584d0a67..10e48a13348 100644 --- a/dts/bindings/regulator/nxp,pca9420.yaml +++ b/dts/bindings/regulator/nxp,pca9420.yaml @@ -1,5 +1,5 @@ # Copyright (c), 2021 NXP -# SPDX -License-Identifier: Apache-2.0 +# SPDX-License-Identifier: Apache-2.0 description: | NXP PCA9420 PMIC diff --git a/dts/bindings/regulator/nxp,vref.yaml b/dts/bindings/regulator/nxp,vref.yaml index e3466ad29d5..8d5acb1f2bc 100644 --- a/dts/bindings/regulator/nxp,vref.yaml +++ b/dts/bindings/regulator/nxp,vref.yaml @@ -1,4 +1,4 @@ -# Copyright 2023 NXP +# Copyright 2023-2024 NXP # SPDX-License-Identifier: Apache-2.0 description: NXP VREF SOC peripheral @@ -20,12 +20,6 @@ properties: reg: required: true - nxp,ground-select: - type: string - enum: - - "VREFL3V" # 0 - - "VSSA" # 1 - nxp,buffer-startup-delay-us: type: int required: true diff --git a/dts/bindings/regulator/raspberrypi,core-supply-regulator.yaml b/dts/bindings/regulator/raspberrypi,core-supply-regulator.yaml index 2034ccd2c0f..2dc1c7d0e89 100644 --- a/dts/bindings/regulator/raspberrypi,core-supply-regulator.yaml +++ b/dts/bindings/regulator/raspberrypi,core-supply-regulator.yaml @@ -1,5 +1,5 @@ # Copyright (c), 2023 TOKITA Hiroshi -# SPDX -License-Identifier: Apache-2.0 +# SPDX-License-Identifier: Apache-2.0 description: | RaspberryPi Pico core supply regurator diff --git a/dts/bindings/regulator/renesas,da1469x-regulator.yaml b/dts/bindings/regulator/renesas,da1469x-regulator.yaml index 2537b7e09d7..d8a064a179f 100644 --- a/dts/bindings/regulator/renesas,da1469x-regulator.yaml +++ b/dts/bindings/regulator/renesas,da1469x-regulator.yaml @@ -1,5 +1,5 @@ # Copyright (c), 2023 Renesas Electronics Corporation -# SPDX -License-Identifier: Apache-2.0 +# SPDX-License-Identifier: Apache-2.0 description: | Renesas Smartbond(tm) LDO and DCDC regulators diff --git a/dts/bindings/regulator/x-powers,axp192-regulator.yaml b/dts/bindings/regulator/x-powers,axp192-regulator.yaml index 9072e80727b..5fcbda2c847 100644 --- a/dts/bindings/regulator/x-powers,axp192-regulator.yaml +++ b/dts/bindings/regulator/x-powers,axp192-regulator.yaml @@ -1,6 +1,6 @@ # Copyright (c), 2021 NXP # Copyright (c), 2023 Martin Kiepfer -# SPDX -License-Identifier: Apache-2.0 +# SPDX-License-Identifier: Apache-2.0 description: | AXP192 PMIC diff --git a/dts/bindings/reset/nuvoton,npcx-rst.yaml b/dts/bindings/reset/nuvoton,npcx-rst.yaml new file mode 100644 index 00000000000..3efceb3ae93 --- /dev/null +++ b/dts/bindings/reset/nuvoton,npcx-rst.yaml @@ -0,0 +1,18 @@ +# Copyright (c) 2024 Nuvoton Technology Corporation. +# SPDX-License-Identifier: Apache-2.0 + +description: NPCX Reset Controller + +compatible: "nuvoton,npcx-rst" + +include: [reset-controller.yaml, base.yaml] + +properties: + reg: + required: true + + "#reset-cells": + const: 1 + +reset-cells: +- id diff --git a/dts/bindings/reset/nxp,lpc-syscon-reset.yaml b/dts/bindings/reset/nxp,lpc-syscon-reset.yaml new file mode 100644 index 00000000000..df4e01c2a2e --- /dev/null +++ b/dts/bindings/reset/nxp,lpc-syscon-reset.yaml @@ -0,0 +1,15 @@ +# Copyright 2024 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: LPC SYSCON Peripheral reset controller + +compatible: "nxp,lpc-syscon-reset" + +include: [reset-controller.yaml] + +properties: + "#reset-cells": + const: 1 + +reset-cells: + - id diff --git a/dts/bindings/reset/nxp,rstctl.yaml b/dts/bindings/reset/nxp,rstctl.yaml new file mode 100644 index 00000000000..04a1a48d043 --- /dev/null +++ b/dts/bindings/reset/nxp,rstctl.yaml @@ -0,0 +1,18 @@ +# Copyright 2024 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP RSTCTL Peripheral reset controller + +compatible: "nxp,rstctl" + +include: [reset-controller.yaml, base.yaml] + +properties: + reg: + required: true + + "#reset-cells": + const: 1 + +reset-cells: + - id diff --git a/dts/bindings/reset/reset-controller.yaml b/dts/bindings/reset/reset-controller.yaml index eddf52c376a..6a2cf5e10d3 100644 --- a/dts/bindings/reset/reset-controller.yaml +++ b/dts/bindings/reset/reset-controller.yaml @@ -7,4 +7,6 @@ properties: "#reset-cells": type: int required: true - description: Number of cells in reset property + description: | + Number of cells in reset property. There must be a cell + named "id" to use the reset_dt_spec macros. diff --git a/dts/bindings/rtc/nuvoton,numaker-rtc.yaml b/dts/bindings/rtc/nuvoton,numaker-rtc.yaml new file mode 100644 index 00000000000..720cff1ab54 --- /dev/null +++ b/dts/bindings/rtc/nuvoton,numaker-rtc.yaml @@ -0,0 +1,27 @@ +# Copyright (c) 2024 Nuvoton Technology Corporation. +# SPDX-License-Identifier: Apache-2.0 + +description: Nuvoton, NuMaker RTC controller + +compatible: "nuvoton,numaker-rtc" + +include: rtc-device.yaml + +properties: + reg: + required: true + + interrupts: + required: true + + clocks: + required: true + + oscillator: + type: string + description: | + Specify RTC oscillator source + enum: + - "lxt" + - "lirc" + - "lirc32k" diff --git a/dts/bindings/rtc/st,stm32-rtc.yaml b/dts/bindings/rtc/st,stm32-rtc.yaml index dcfd2a49276..d368410b6ee 100644 --- a/dts/bindings/rtc/st,stm32-rtc.yaml +++ b/dts/bindings/rtc/st,stm32-rtc.yaml @@ -1,11 +1,14 @@ # Copyright (c) 2018, Workaround GmbH +# Copyright (c) 2024 STMicroelectronics # SPDX-License-Identifier: Apache-2.0 description: STM32 RTC compatible: "st,stm32-rtc" -include: rtc.yaml +include: + - rtc.yaml + - rtc-device.yaml properties: reg: @@ -18,3 +21,19 @@ properties: enum: - 1 - 512 + + alarms-count: + description: | + Number of alarms supported by STM32 RTC device. + Most of STM32 MCU series have 2 RTC alarms, A & B. + Defaults to 0 when not declared in devicetree. + + alrm-exti-line: + type: int + description: | + Number of the Extended Interrupts and Event Controller (EXTI) interrupt + line connected to the RTC Alarm event. + Not required, since RTC Alarm interrupt could be routed directly to Nested + Vectored Interrupt Controller (NVIC) and to Power Control (PWR) wake-up + pins on some series. + Valid range: 0 - 31 diff --git a/dts/bindings/sdhc/espressif,esp32-sdhc-slot.yaml b/dts/bindings/sdhc/espressif,esp32-sdhc-slot.yaml new file mode 100644 index 00000000000..ff743a2ad2c --- /dev/null +++ b/dts/bindings/sdhc/espressif,esp32-sdhc-slot.yaml @@ -0,0 +1,76 @@ +# Copyright (c) 2024 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +description: Espressif ESP32 SDHC controller slot + +compatible: "espressif,esp32-sdhc-slot" + +include: [sdhc.yaml, pinctrl-device.yaml] + +properties: + reg: + required: true + + pinctrl-0: + required: true + + pinctrl-names: + required: true + + bus-width: + type: int + enum: + - 1 + - 4 + default: 4 + description: SD bus width in bits + + clk-pin: + type: int + description: | + Clock pin for ESP32 and SoC models with fixed pins for SDIO. + For devices with GPIO matrix support, configuration shall be done + using pin control (pinctrl-0 field). + + cmd-pin: + type: int + description: | + Command pin for ESP32 and SoC models with fixed pins for SDIO. + For devices with GPIO matrix support, configuration shall be done + using pin control (pinctrl-0 field). + + d0-pin: + type: int + description: | + Data 0 pin for ESP32 and SoC models with fixed pins for SDIO. + For devices with GPIO matrix support, configuration shall be done + using pin control (pinctrl-0 field). + + d1-pin: + type: int + description: | + Data 1 pin for ESP32 and SoC models with fixed pins for SDIO. + For devices with GPIO matrix support, configuration shall be done + using pin control (pinctrl-0 field). + + d2-pin: + type: int + description: | + Data 2 pin for ESP32 and SoC models with fixed pins for SDIO. + For devices with GPIO matrix support, configuration shall be done + using pin control (pinctrl-0 field). + + d3-pin: + type: int + description: | + Data 3 pin for ESP32 and SoC models with fixed pins for SDIO. + For devices with GPIO matrix support, configuration shall be done + using pin control (pinctrl-0 field). + + pwr-gpios: + type: phandle-array + description: | + Power pin + This is a configurable pin to deliver power supply to the SD card. + It is configured as a GPIO in order to execute power toggles and + reinitialize the SD slave when necessary. diff --git a/dts/bindings/sdhc/espressif,esp32-sdhc.yaml b/dts/bindings/sdhc/espressif,esp32-sdhc.yaml new file mode 100644 index 00000000000..b7cfabcdbbb --- /dev/null +++ b/dts/bindings/sdhc/espressif,esp32-sdhc.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2024 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +description: Espressif ESP32 SDHC controller + +compatible: "espressif,esp32-sdhc" + +include: [base.yaml] + +properties: + reg: + required: true + + interrupts: + required: true diff --git a/dts/bindings/sensor/festo,veaa-x-3.yaml b/dts/bindings/sensor/festo,veaa-x-3.yaml new file mode 100644 index 00000000000..38529ab240d --- /dev/null +++ b/dts/bindings/sensor/festo,veaa-x-3.yaml @@ -0,0 +1,40 @@ +# Copyright (c) 2024 Vitrolife A/S +# SPDX-License-Identifier: Apache-2.0 + +description: | + Festo VEAA proportional pressure regulator using 3/3-way valve. + Only voltage controlled valve is supported. + +compatible: "festo,veaa-x-3" + +include: sensor-device.yaml + +properties: + io-channels: + type: phandle-array + required: true + description: | + ADC used to get the actual value: + <&adc_node channel> + dac: + type: phandle + required: true + description: | + DAC used to set the setpoint value: + <&dac_node channel resolution buffered> + dac-channel-id: + type: int + required: true + dac-resolution: + type: int + required: true + pressure-range-type: + type: string + enum: ["D2", "D9", "D11"] + required: true + description: | + The device pressure range type. + | Type | Range [kPa] | + | D11 | 5-1000 | + | D9 | 3-600 | + | D2 | 1-200 | diff --git a/dts/bindings/sensor/ist,tsic-xx6.yaml b/dts/bindings/sensor/ist,tsic-xx6.yaml new file mode 100644 index 00000000000..d6ee88b8079 --- /dev/null +++ b/dts/bindings/sensor/ist,tsic-xx6.yaml @@ -0,0 +1,40 @@ +# Copyright (c) 2024, Vitrolife A/S +# SPDX-License-Identifier: Apache-2.0 + +description: | + TSic xx6 temperature sensor. + https://www.ist-ag.com/sites/default/files/downloads/ATTSic_E.pdf + + Example: + tsic_716: tsic_716 { + status = "okay"; + compatible = "ist,tsic-xx6"; + pwms = <&pwm2 1 PWM_USEC(5) PWM_POLARITY_NORMAL>; + data-bits = <14>; + lower-temperature-limit = <(-10)>; + higher-temperature-limit = <60>; + }; + +compatible: "ist,tsic-xx6" + +properties: + pwms: + required: true + type: phandle-array + description: Reference to a PWM instance with PWM capture support. + + lower-temperature-limit: + required: true + type: int + description: Lowest temperature supported by the device in celcius degrees. + + higher-temperature-limit: + required: true + type: int + description: Highest temperature supported by the device in celcius degrees. + + data-bits: + required: true + type: int + description: Data bits per reading. + enum: [11, 14] diff --git a/dts/bindings/sensor/maxim,ds18s20.yaml b/dts/bindings/sensor/maxim,ds18s20.yaml new file mode 100644 index 00000000000..1e42cd80a9d --- /dev/null +++ b/dts/bindings/sensor/maxim,ds18s20.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2024, Fredrik Gihl +# SPDX-License-Identifier: Apache-2.0 + +description: Maxim 1-Wire ds18s20 temperature sensor + +compatible: "maxim,ds18s20" + +include: [sensor-device.yaml, w1-slave.yaml] diff --git a/dts/bindings/sensor/murata,ncp15xh103.yaml b/dts/bindings/sensor/murata,ncp15xh103.yaml new file mode 100644 index 00000000000..7e53ed3da84 --- /dev/null +++ b/dts/bindings/sensor/murata,ncp15xh103.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2024 Silicom Connectivity Solutions Ltd. +# SPDX-License-Identifier: Apache-2.0 + +description: MURATA NCP15XH103 thermistor + +compatible: "murata,ncp15xh103" + +include: ntc-thermistor.yaml diff --git a/dts/bindings/sensor/nordic,nrf-temp-nrfs.yaml b/dts/bindings/sensor/nordic,nrf-temp-nrfs.yaml new file mode 100644 index 00000000000..2a77552b3bf --- /dev/null +++ b/dts/bindings/sensor/nordic,nrf-temp-nrfs.yaml @@ -0,0 +1,9 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: | + Nordic nRF family temperature sensor accessed via nRF Services (nrfs) + +compatible: "nordic,nrf-temp-nrfs" + +include: base.yaml diff --git a/dts/bindings/sensor/onnn,nct75.yaml b/dts/bindings/sensor/onnn,nct75.yaml new file mode 100644 index 00000000000..2ed14f6a55b --- /dev/null +++ b/dts/bindings/sensor/onnn,nct75.yaml @@ -0,0 +1,9 @@ +# Copyright (c) 2024 Benedikt Schmidt +# SPDX-License-Identifier: Apache-2.0 + +description: | + ON Semiconductor NCT75 temperature sensor with I2C interface + +compatible: "onnn,nct75" + +include: [sensor-device.yaml, i2c-device.yaml] diff --git a/dts/bindings/sensor/st,lis2dh-common.yaml b/dts/bindings/sensor/st,lis2dh-common.yaml index 1988a7c1deb..e4c41f586d5 100644 --- a/dts/bindings/sensor/st,lis2dh-common.yaml +++ b/dts/bindings/sensor/st,lis2dh-common.yaml @@ -34,7 +34,7 @@ properties: 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 + - 0 # LIS2DH_DT_GPIO_INT_EDGE_BOTH - 1 # LIS2DH_DT_GPIO_INT_EDGE_RISING - 2 # LIS2DH_DT_GPIO_INT_EDGE_FALLING - 3 # LIS2DH_DT_GPIO_INT_LEVEL_HIGH @@ -51,7 +51,7 @@ properties: 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 + - 0 # LIS2DH_DT_GPIO_INT_EDGE_BOTH - 1 # LIS2DH_DT_GPIO_INT_EDGE_RISING - 2 # LIS2DH_DT_GPIO_INT_EDGE_FALLING - 3 # LIS2DH_DT_GPIO_INT_LEVEL_HIGH diff --git a/dts/bindings/sensor/ti,ina226.yaml b/dts/bindings/sensor/ti,ina226.yaml new file mode 100644 index 00000000000..0752e2902d5 --- /dev/null +++ b/dts/bindings/sensor/ti,ina226.yaml @@ -0,0 +1,73 @@ +# Copyright 2024 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: | + TI INA226 Bidirectional Current and Power Monitor. + The file should be included in the + DeviceTree as it provides macros that can be used for initializing the + configuration registers. + +compatible: "ti,ina226" + +include: [sensor-device.yaml, i2c-device.yaml] + +properties: + avg-count: + type: int + description: | + Number of samples to average (applies to all inputs). + Default is the power-on reset value. + default: 1 + enum: [1, 4, 16, 64, 128, 256, 512, 1024] + + vbus-conversion-time-us: + type: int + description: | + Vbus conversion time in microseconds. + Default is the power-on reset value. + default: 1100 + enum: [140, 204, 332, 588, 1100, 2116, 4156, 8244] + + vshunt-conversion-time-us: + type: int + description: | + Vshunt conversion time in microseconds. + Default is the power-on reset value. + default: 1100 + enum: [140, 204, 332, 588, 1100, 2116, 4156, 8244] + + operating-mode: + type: string + description: | + Selects mode of operation. + Default is the power-on reset value. + default: "Shunt and Bus, Continuous" + enum: + - "Power-Down (or Shutdown)" + - "Shunt Voltage, Triggered" + - "Bus Voltage, Triggered" + - "Shunt and Bus, Triggered" + - "Power-Down (or Shutdown)" + - "Shunt Voltage, Continuous" + - "Bus Voltage, Continuous" + - "Shunt and Bus, Continuous" + + current-lsb-microamps: + type: int + required: true + description: | + Current LSB value in microAmpere. + This value gives the measurement resolution for current measurement. + Formula: current-lsb [Ī¼A] = maximum expected current [Ī¼A] / 2^15 + Higher resolution means lower range of current measurement, vice versa. + + For example, if maximum expected current is 15 [A]: + then, current-lsb [Ī¼A] = 15000000 [Ī¼A] / 2^15 ~= 457.763 [Ī¼A]. + + Note: rounded values may be used for convenience, e.g. 500uA/LSB. + + rshunt-micro-ohms: + type: int + required: true + description: | + Shunt resistor value in micro-ohms. diff --git a/dts/bindings/sensor/ti,tmp114.yaml b/dts/bindings/sensor/ti,tmp114.yaml new file mode 100644 index 00000000000..494df181098 --- /dev/null +++ b/dts/bindings/sensor/ti,tmp114.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2024 Fredrik Gihl +# SPDX-License-Identifier: Apache-2.0 + +description: Texas Instruments TMP114 temperature sensor + +compatible: "ti,tmp114" + +include: [sensor-device.yaml, i2c-device.yaml] diff --git a/dts/bindings/serial/espressif,esp32-uart.yaml b/dts/bindings/serial/espressif,esp32-uart.yaml index 313d9039a5b..ab3b88df83f 100644 --- a/dts/bindings/serial/espressif,esp32-uart.yaml +++ b/dts/bindings/serial/espressif,esp32-uart.yaml @@ -21,3 +21,15 @@ properties: Overrides hw-flow-control if both are set. Using this mode, the pin assigned to DTR is asserted during transmission. + + tx-invert: + type: boolean + description: | + Invert the binary logic of tx pin. When enabled, physical logic levels are inverted and + we use 1=Low, 0=High instead of 1=High, 0=Low. + + rx-invert: + type: boolean + description: | + Invert the binary logic of rx pin. When enabled, physical logic levels are inverted and + we use 1=Low, 0=High instead of 1=High, 0=Low. diff --git a/dts/bindings/serial/nordic,nrf-uart-common.yaml b/dts/bindings/serial/nordic,nrf-uart-common.yaml index fa68a195cd6..b985b7bc963 100644 --- a/dts/bindings/serial/nordic,nrf-uart-common.yaml +++ b/dts/bindings/serial/nordic,nrf-uart-common.yaml @@ -17,6 +17,7 @@ properties: if CONFIG_PINCTRL is enabled). current-speed: + required: true description: | Initial baud rate setting for UART. Only a fixed set of baud rates are selectable on these devices. diff --git a/dts/bindings/serial/nxp,kinetis-lpuart.yaml b/dts/bindings/serial/nxp,kinetis-lpuart.yaml index 1b8f5400722..4e06853323b 100644 --- a/dts/bindings/serial/nxp,kinetis-lpuart.yaml +++ b/dts/bindings/serial/nxp,kinetis-lpuart.yaml @@ -15,6 +15,26 @@ properties: disconnected, and transmitter output is internally connected to the receiver input. + single-wire: + type: boolean + description: | + Enable the single wire half-duplex communication. + Using this mode, TX and RX lines are internally connected and + only TX pin is used afterwards and should be configured. + RX/TX conflicts must be handled on user side. + + tx-invert: + type: boolean + description: | + Invert the binary logic of tx pin. When enabled, physical logic levels are inverted and + we use 1=Low, 0=High instead of 1=High, 0=Low. + + rx-invert: + type: boolean + description: | + Invert the binary logic of rx pin. When enabled, physical logic levels are inverted and + we use 1=Low, 0=High instead of 1=High, 0=Low. + nxp,rs485-mode: type: boolean description: | diff --git a/dts/bindings/serial/renesas,smartbond-uart.yaml b/dts/bindings/serial/renesas,smartbond-uart.yaml index 4b2a2b973c2..428eb0ca76e 100644 --- a/dts/bindings/serial/renesas,smartbond-uart.yaml +++ b/dts/bindings/serial/renesas,smartbond-uart.yaml @@ -38,3 +38,24 @@ properties: hw-flow-control-supported: type: boolean description: Set to indicate RTS/CTS flow control is supported. + + rx-wake-gpios: + type: phandle-array + description: GPIO configured as wake source + + rx-wake-timeout: + type: int + description: | + Time to prevent UART entering sleep mode after receiving data (ms) + + dtr-gpios: + type: phandle-array + description: | + DTR pin specification. DTR pin when active tells that the driver that there + is active client on the other side of serial line. + The device driver does not use DTR for hardware flow control. + When device is connected to computer serial converter usually asserts DTR + line when serial port is opened and ready for communication. + This line can be used in Smartbond(tm) driver to detect remote client presence. + If client is not present the device can disable UART, allowing for + power system management to enter more efficient power levels. diff --git a/dts/bindings/spi/nxp,imx-flexspi.yaml b/dts/bindings/spi/nxp,imx-flexspi.yaml index ebb8a08ba12..8a266a8a91d 100644 --- a/dts/bindings/spi/nxp,imx-flexspi.yaml +++ b/dts/bindings/spi/nxp,imx-flexspi.yaml @@ -61,6 +61,19 @@ properties: Source clock for flash read. See the RXCLKSRC field in register MCR0. The default corresponds to the reset value of the register field. + rx-clock-source-b: + type: int + default: 0 + enum: + - 0 # Loopback internally + - 1 # Loopback from DQS pad + - 2 # Loopback from SCK pad + - 3 # External input from DQS pad + description: | + Source clock for flash read on port B. Only supported by some instances + of this IP. See the RXCLKSRC_B field in register MCR2. + The default corresponds to the reset value of the register field. + rx-buffer-config: type: array description: | diff --git a/dts/bindings/spi/raspberrypi,pico-spi-pio.yaml b/dts/bindings/spi/raspberrypi,pico-spi-pio.yaml index a3df88f8995..07cc941aad9 100644 --- a/dts/bindings/spi/raspberrypi,pico-spi-pio.yaml +++ b/dts/bindings/spi/raspberrypi,pico-spi-pio.yaml @@ -24,5 +24,12 @@ properties: description: | Input pin for Master In Slave Out. + sio-gpios: + type: phandle-array + description: | + Single I/O gpio info + + GPIO input/output pin for 3-wire mode. + clocks: required: true diff --git a/dts/bindings/test/vnd,memory-attr.yaml b/dts/bindings/test/vnd,memory-attr.yaml index 0303d255c54..8696279859d 100644 --- a/dts/bindings/test/vnd,memory-attr.yaml +++ b/dts/bindings/test/vnd,memory-attr.yaml @@ -5,4 +5,4 @@ description: Test memory and memory attributes compatible: "vnd,memory-attr" -include: [base.yaml, "zephyr,memory-attr.yaml"] +include: [base.yaml, "zephyr,memory-common.yaml"] diff --git a/dts/bindings/timer/nordic,nrf-timer.yaml b/dts/bindings/timer/nordic,nrf-timer.yaml index 8a961f34f88..9f8395003a8 100644 --- a/dts/bindings/timer/nordic,nrf-timer.yaml +++ b/dts/bindings/timer/nordic,nrf-timer.yaml @@ -24,10 +24,20 @@ properties: interrupts: required: true + max-frequency: + type: int + default: 16000000 + description: | + Maximum timer frequency in Hz. + + The default value is 16MHz which was the maximum frequency for all nRF TIMER peripherals + up to the nRF54 series, and still remains the most typical maximum frequency for nRF54 + TIMERs. + prescaler: type: int required: true - description: Prescaler value determines frequency (base_frequency/2^prescaler) + description: Prescaler value determines frequency (max-frequency/2^prescaler) zli: type: boolean diff --git a/dts/bindings/timer/nxp,tpm-timer.yaml b/dts/bindings/timer/nxp,tpm-timer.yaml new file mode 100644 index 00000000000..53cc1ad9b2a --- /dev/null +++ b/dts/bindings/timer/nxp,tpm-timer.yaml @@ -0,0 +1,32 @@ +# Copyright 2023-2024 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP Timer/PWM Module (TPM) used as timer + +compatible: "nxp,tpm-timer" + +include: base.yaml + +properties: + reg: + required: true + + interrupts: + required: true + + clocks: + required: true + + prescaler: + type: int + required: true + enum: + - 1 + - 2 + - 4 + - 8 + - 16 + - 32 + - 64 + - 128 + description: Input clock prescaler diff --git a/dts/bindings/usb/snps,dwc2.yaml b/dts/bindings/usb/snps,dwc2.yaml index 8af55448780..d5b0167f26b 100644 --- a/dts/bindings/usb/snps,dwc2.yaml +++ b/dts/bindings/usb/snps,dwc2.yaml @@ -18,3 +18,36 @@ properties: phys: type: phandle + + num-in-eps: + type: int + required: true + description: | + Number of configured OUT endpoints including control endpoint. + + num-out-eps: + type: int + required: true + description: | + Number of configured IN endpoints including control endpoint. + + ghwcfg1: + type: int + required: true + description: | + Value of the GHWCFG1 register. It is used to determine available endpoint + types during driver pre-initialization. + + ghwcfg2: + type: int + required: true + description: | + Value of the GHWCFG2 register. It is used to determine available endpoint + types during driver pre-initialization. + + ghwcfg4: + type: int + required: true + description: | + Value of the GHWCFG4 register. It is used to determine available endpoint + types during driver pre-initialization. diff --git a/dts/bindings/usb/zephyr,hid-device.yaml b/dts/bindings/usb/zephyr,hid-device.yaml new file mode 100644 index 00000000000..03887acb0d8 --- /dev/null +++ b/dts/bindings/usb/zephyr,hid-device.yaml @@ -0,0 +1,58 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: Bindings for HID device + +compatible: "zephyr,hid-device" + +include: base.yaml + +properties: + interface-name: + type: string + description: | + HID device name. When this property is present, a USB device will use it + as the string descriptor of the interface. + + protocol-code: + type: string + description: | + This property corresponds to the protocol codes defined in Chapter 4.3 + of the HID specification. Only boot devices are required to set one of + the protocols, keyboard or mouse. For non-boot devices, this property is + not required or can be set to none. + - none: Device does not support the boot interface + - keyboard: Device supports boot interface and keyboard protocol + - mouse: Device supports boot interface and mouse protocol + enum: + - none + - keyboard + - mouse + + in-report-size: + type: int + required: true + description: | + The size of the longest input report that the HID device can generate. + This property is used to determine the buffer length used for transfers. + + in-polling-rate: + type: int + required: true + description: | + Input or output type reports polling rate in microseconds. For USB full + speed this could be clamped to 1ms or 255ms depending on the value. + + out-report-size: + type: int + description: | + The size of the longest output report that the HID device can generate. + When this property is present, a USB device will use out pipe for output + reports, otherwise control pipe will be used for output reports. + + out-polling-rate: + type: int + description: | + Output type reports polling rate in microseconds. For USB full + speed this could be clamped to 1ms or 255ms depending on the value. + This option is only effective if the out-report-size property is defined. diff --git a/dts/bindings/vendor-prefixes.txt b/dts/bindings/vendor-prefixes.txt index 63e7186781b..4cc0cae7e82 100644 --- a/dts/bindings/vendor-prefixes.txt +++ b/dts/bindings/vendor-prefixes.txt @@ -150,6 +150,7 @@ cortina Cortina Systems, Inc. cosmic Cosmic Circuits crane Crane Connectivity Solutions creative Creative Technology Ltd +croxel Croxel, Inc. crystalfontz Crystalfontz America, Inc. csky Hangzhou C-SKY Microsystems Co., Ltd csq Shenzen Chuangsiqi Technology Co.,Ltd. @@ -231,6 +232,7 @@ fastrax Fastrax Oy fcs Fairchild Semiconductor feixin Shenzhen Feixin Photoelectic Co., Ltd feiyang Shenzhen Fly Young Technology Co.,LTD. +festo Festo SE & Co. KG fii Foxconn Industrial Internet fintek Feature Integration Technology Inc. firefly Firefly @@ -320,6 +322,7 @@ isee ISEE 2007 S.L. isentek Isentek Inc. isil Intersil issi Integrated Silicon Solutions Inc. +ist Innovative Sensor Technology IST AG ite ITE Tech. Inc. itead ITEAD Intelligent Systems Co.Ltd ivo InfoVision Optoelectronics Kunshan Co. Ltd. @@ -496,7 +499,7 @@ pda Precision Design Associates, Inc. pericom Pericom Technology Inc. pervasive Pervasive Displays, Inc. phicomm PHICOMM Co., Ltd. -phytec PHYTEC Messtechnik GmbH +phytec PHYTEC picochip Picochip Ltd pine64 Pine64 pineriver Shenzhen PineRiver Designs Co., Ltd. diff --git a/dts/bindings/video/nxp,imx-csi.yaml b/dts/bindings/video/nxp,imx-csi.yaml index d2553d68911..bf7fd01eeaa 100644 --- a/dts/bindings/video/nxp,imx-csi.yaml +++ b/dts/bindings/video/nxp,imx-csi.yaml @@ -14,7 +14,8 @@ properties: interrupts: required: true - sensor: + source: required: true type: phandle - description: phandle of connected sensor device + description: the connected source device, + e.g., a mipi csi or a camera sensor diff --git a/dts/bindings/video/nxp,mipi-csi2rx.yaml b/dts/bindings/video/nxp,mipi-csi2rx.yaml new file mode 100644 index 00000000000..1726d63b329 --- /dev/null +++ b/dts/bindings/video/nxp,mipi-csi2rx.yaml @@ -0,0 +1,17 @@ +# +# Copyright 2024 NXP +# +# SPDX-License-Identifier: Apache-2.0 +# + +description: NXP MIPI CSI-2 Rx interface + +compatible: "nxp,mipi-csi2rx" + +include: [base.yaml] + +properties: + sensor: + required: true + type: phandle + description: the connected camera sensor diff --git a/dts/bindings/video/ovti,ov2640.yaml b/dts/bindings/video/ovti,ov2640.yaml index 796020e0699..1bc26fcaee8 100644 --- a/dts/bindings/video/ovti,ov2640.yaml +++ b/dts/bindings/video/ovti,ov2640.yaml @@ -12,4 +12,18 @@ properties: The RESETn pin is asserted to disable the sensor causing a hard reset. The sensor receives this as an active-low signal. + clock-rate-control: + type: int + default: 0x87 + description: | + Define the value to the Clock Rate Control register. By changing + the system clock divide ratio and PLL, the frame rate and pixel + rate will change together. + Bit[7] Internal frequency doublers ON/OFF selection. + 0: ON 1: OFF + Bit[6] Reserved + Bit[5:0] Clock divider. + + CLK = XVCLK /(decimal value of CLKRC[5:0] + 1) + include: i2c-device.yaml diff --git a/dts/bindings/video/ovti,ov5640.yaml b/dts/bindings/video/ovti,ov5640.yaml new file mode 100644 index 00000000000..eecb0e3d319 --- /dev/null +++ b/dts/bindings/video/ovti,ov5640.yaml @@ -0,0 +1,20 @@ +# Copyright 2024 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: OV5640 CMOS video sensor + +compatible: "ovti,ov5640" + +include: i2c-device.yaml + +properties: + reset-gpios: + type: phandle-array + description: | + The RESETB pin is asserted to cause a hard reset. The sensor + receives this as an active-low signal. + powerdown-gpios: + type: phandle-array + description: | + The PWDN pin is asserted to disable the sensor. The sensor + receives this as an active-high signal. diff --git a/dts/bindings/video/st,stm32-dcmi.yaml b/dts/bindings/video/st,stm32-dcmi.yaml new file mode 100644 index 00000000000..8381ae0acaf --- /dev/null +++ b/dts/bindings/video/st,stm32-dcmi.yaml @@ -0,0 +1,123 @@ +# +# Copyright (c) 2024 Charles Dias +# +# SPDX-License-Identifier: Apache-2.0 +# + +description: | + STMicroelectronics STM32 Digital Camera Memory Interface (DCMI). + Example of node configuration at board level: + + &dcmi { + status = "okay"; + sensor = <&ov2640>; + pinctrl-0 = <&dcmi_hsync_pa4 &dcmi_pixclk_pa6 &dcmi_vsync_pb7 + &dcmi_d0_pc6 &dcmi_d1_pc7 &dcmi_d2_pe0 &dcmi_d3_pe1 + &dcmi_d4_pe4 &dcmi_d5_pd3 &dcmi_d6_pe5 &dcmi_d7_pe6>; + pinctrl-names = "default"; + bus-width = <8>; + hsync-active = <0>; + vsync-active = <0>; + pixelclk-active = <1>; + capture-rate = <1>; + dmas = <&dma1 0 75 (STM32_DMA_PERIPH_TO_MEMORY | STM32_DMA_PERIPH_NO_INC | + STM32_DMA_MEM_INC | STM32_DMA_PERIPH_8BITS | STM32_DMA_MEM_32BITS | + STM32_DMA_PRIORITY_HIGH) STM32_DMA_FIFO_1_4>; + + port { + dcmi_ep_in: endpoint { + remote-endpoint = <&ov2640_ep_out>; + }; + }; + }; + +compatible: "st,stm32-dcmi" + +include: [base.yaml, pinctrl-device.yaml] + +properties: + interrupts: + required: true + + sensor: + required: true + type: phandle + description: phandle of connected sensor device + + bus-width: + type: int + required: true + enum: + - 8 + - 10 + - 12 + - 14 + default: 8 + description: | + Number of data lines actively used, valid for the parallel busses. + + hsync-active: + type: int + required: true + enum: + - 0 + - 1 + description: | + Polarity of horizontal synchronization (DCMI_HSYNC_Polarity). + 0 Horizontal synchronization active Low. + 1 Horizontal synchronization active High. + + For example, if DCMI_HSYNC_Polarity is programmed active high: + When HSYNC is low, the data is valid. + When HSYNC is high, the data is not valid (horizontal blanking). + + vsync-active: + type: int + required: true + enum: + - 0 + - 1 + description: | + Polarity of vertical synchronization (DCMI_VSYNC_Polarity). + 0 Vertical synchronization active Low. + 1 Vertical synchronization active High. + + For example, if DCMI_VSYNC_Polarity is programmed active high: + When VSYNC is low, the data is valid. + When VSYNC is high, the data is not valid (vertical blanking). + + pixelclk-active: + type: int + required: true + enum: + - 0 + - 1 + description: | + Polarity of pixel clock (DCMI_PIXCK_Polarity). + 0 Pixel clock active on Falling edge. + 1 Pixel clock active on Rising edge. + + capture-rate: + type: int + enum: + - 1 + - 2 + - 4 + default: 1 + description: | + The DCMI can capture all frames or alternate frames. If it is not specified, + the default is all frames. + 1 Capture all frames. + 2 Capture alternate frames. + 4 Capture one frame every 4 frames. + + dmas: + required: true + description: | + phandle of DMA controller. The DMA controller should be compatible with + DMA channel specifier. Specifies a phandle reference to the dma controller, + the channel number, the slot number, channel configuration and finally features. + + dmas = <&dma1 0 75 (STM32_DMA_PERIPH_TO_MEMORY | STM32_DMA_PERIPH_NO_INC | + STM32_DMA_MEM_INC | STM32_DMA_PERIPH_8BITS | STM32_DMA_MEM_32BITS | + STM32_DMA_PRIORITY_HIGH) STM32_DMA_FIFO_1_4>; diff --git a/dts/bindings/xspi/st,stm32-xspi.yaml b/dts/bindings/xspi/st,stm32-xspi.yaml new file mode 100644 index 00000000000..388c3d20bca --- /dev/null +++ b/dts/bindings/xspi/st,stm32-xspi.yaml @@ -0,0 +1,9 @@ +# Copyright (c) 2024 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +description: | + STM32 XSPI device representation. Enabling a stm32 xspi node in a board + +compatible: "st,stm32-xspi" + +include: st,stm32-ospi.yaml diff --git a/dts/arm/broadcom/viper-common.dtsi b/dts/common/broadcom/viper-common.dtsi similarity index 100% rename from dts/arm/broadcom/viper-common.dtsi rename to dts/common/broadcom/viper-common.dtsi diff --git a/dts/common/nordic/nrf54h20.dtsi b/dts/common/nordic/nrf54h20.dtsi index c894dab8edf..89405da6466 100644 --- a/dts/common/nordic/nrf54h20.dtsi +++ b/dts/common/nordic/nrf54h20.dtsi @@ -8,12 +8,8 @@ #include #include - -/* Domain IDs. Can be used to specify channel links in IPCT nodes. */ -#define NRF_DOMAIN_ID_APPLICATION 2 -#define NRF_DOMAIN_ID_RADIOCORE 3 -#define NRF_DOMAIN_ID_GLOBALFAST 12 -#define NRF_DOMAIN_ID_GLOBALSLOW 13 +#include +#include /delete-node/ &sw_pwm; @@ -187,6 +183,11 @@ interrupts = <21 NRF_DEFAULT_IRQ_PRIORITY>; }; + cpuapp_ieee802154: ieee802154 { + compatible = "nordic,nrf-ieee802154"; + status = "disabled"; + }; + cpuapp_resetinfo: resetinfo@1e000 { compatible = "nordic,nrf-resetinfo"; reg = <0x1e000 0x1000>; @@ -259,6 +260,7 @@ cc-num = <8>; interrupts = <40 NRF_DEFAULT_IRQ_PRIORITY>; max-bit-width = <32>; + max-frequency = ; prescaler = <0>; }; @@ -269,6 +271,7 @@ cc-num = <8>; interrupts = <41 NRF_DEFAULT_IRQ_PRIORITY>; max-bit-width = <32>; + max-frequency = ; prescaler = <0>; }; @@ -279,6 +282,7 @@ cc-num = <8>; interrupts = <42 NRF_DEFAULT_IRQ_PRIORITY>; max-bit-width = <32>; + max-frequency = ; prescaler = <0>; }; @@ -343,10 +347,15 @@ ranges = <0x0 0x5f000000 0x1000000>; usbhs: usbhs@86000 { - compatible = "snps,dwc2"; + compatible = "nordic,nrf-usbhs", "snps,dwc2"; reg = <0x86000 0x1000>, <0x2f700000 0x40000>; reg-names = "wrapper", "core"; interrupts = <134 NRF_DEFAULT_IRQ_PRIORITY>; + num-in-eps = <8>; + num-out-eps = <10>; + ghwcfg1 = <0xaa555000>; + ghwcfg2 = <0x22abfc72>; + ghwcfg4 = <0x1e10aa60>; status = "disabled"; }; @@ -411,6 +420,7 @@ cc-num = <6>; interrupts = <226 NRF_DEFAULT_IRQ_PRIORITY>; max-bit-width = <32>; + max-frequency = ; prescaler = <0>; }; @@ -421,6 +431,7 @@ cc-num = <6>; interrupts = <227 NRF_DEFAULT_IRQ_PRIORITY>; max-bit-width = <32>; + max-frequency = ; prescaler = <0>; }; @@ -1084,4 +1095,9 @@ #address-cells = <1>; }; }; + + temp_nrfs: temp { + compatible = "nordic,nrf-temp-nrfs"; + status = "disabled"; + }; }; diff --git a/dts/common/nordic/nrf54l15.dtsi b/dts/common/nordic/nrf54l15.dtsi new file mode 100644 index 00000000000..0b8eb1c549a --- /dev/null +++ b/dts/common/nordic/nrf54l15.dtsi @@ -0,0 +1,665 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/delete-node/ &sw_pwm; + +/* Domain IDs. Can be used to specify channel links in IPCT nodes. */ +#define NRF_DOMAIN_ID_APPLICATION 0 +#define NRF_DOMAIN_ID_FLPR 1 + +/ { + #address-cells = <1>; + #size-cells = <1>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpuapp: cpu@0 { + compatible = "arm,cortex-m33f"; + reg = <0>; + device_type = "cpu"; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <1>; + itm: itm@e0000000 { + compatible = "arm,armv8m-itm"; + reg = <0xe0000000 0x1000>; + swo-ref-frequency = ; + }; + }; + + cpuflpr: cpu@1 { + compatible = "nordic,vpr"; + reg = <1>; + device_type = "cpu"; + clock-frequency = ; + riscv,isa = "rv32emc"; + nordic,bus-width = <32>; + + cpuflpr_vevif_local: mailbox { + compatible = "nordic,nrf-vevif-local"; + status = "disabled"; + interrupt-parent = <&cpuflpr_clic>; + interrupts = <0 NRF_DEFAULT_IRQ_PRIORITY>, + <1 NRF_DEFAULT_IRQ_PRIORITY>, + <2 NRF_DEFAULT_IRQ_PRIORITY>, + <3 NRF_DEFAULT_IRQ_PRIORITY>, + <4 NRF_DEFAULT_IRQ_PRIORITY>, + <5 NRF_DEFAULT_IRQ_PRIORITY>, + <6 NRF_DEFAULT_IRQ_PRIORITY>, + <7 NRF_DEFAULT_IRQ_PRIORITY>, + <8 NRF_DEFAULT_IRQ_PRIORITY>, + <9 NRF_DEFAULT_IRQ_PRIORITY>, + <10 NRF_DEFAULT_IRQ_PRIORITY>, + <11 NRF_DEFAULT_IRQ_PRIORITY>, + <12 NRF_DEFAULT_IRQ_PRIORITY>, + <13 NRF_DEFAULT_IRQ_PRIORITY>, + <14 NRF_DEFAULT_IRQ_PRIORITY>, + <15 NRF_DEFAULT_IRQ_PRIORITY>, + <16 NRF_DEFAULT_IRQ_PRIORITY>, + <17 NRF_DEFAULT_IRQ_PRIORITY>, + <18 NRF_DEFAULT_IRQ_PRIORITY>, + <19 NRF_DEFAULT_IRQ_PRIORITY>, + <20 NRF_DEFAULT_IRQ_PRIORITY>, + <21 NRF_DEFAULT_IRQ_PRIORITY>, + <22 NRF_DEFAULT_IRQ_PRIORITY>, + <23 NRF_DEFAULT_IRQ_PRIORITY>, + <24 NRF_DEFAULT_IRQ_PRIORITY>, + <25 NRF_DEFAULT_IRQ_PRIORITY>, + <26 NRF_DEFAULT_IRQ_PRIORITY>, + <27 NRF_DEFAULT_IRQ_PRIORITY>, + <28 NRF_DEFAULT_IRQ_PRIORITY>, + <29 NRF_DEFAULT_IRQ_PRIORITY>, + <30 NRF_DEFAULT_IRQ_PRIORITY>, + <31 NRF_DEFAULT_IRQ_PRIORITY>; + #mbox-cells = <1>; + nordic,tasks = <18>; + nordic,tasks-mask = <0x007f0000>; + }; + }; + }; + + 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 { + #address-cells = <1>; + #size-cells = <1>; + +#ifdef USE_NON_SECURE_ADDRESS_MAP + /* intentionally empty because UICR is hardware fixed to Secure */ +#else + uicr: uicr@ffd000 { + compatible = "nordic,nrf-uicr"; + reg = <0xffd000 0x1000>; + }; +#endif + ficr: ficr@ffc000 { + compatible = "nordic,nrf-ficr"; + reg = <0xffc000 0x1000>; + #nordic,ficr-cells = <1>; + }; + + cpuapp_sram: memory@20000000 { + compatible = "mmio-sram"; + reg = <0x20000000 DT_SIZE_K(188)>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x20000000 0x2f000>; + }; + + cpuflpr_sram: memory@2002f000 { + compatible = "mmio-sram"; + reg = <0x2002f000 DT_SIZE_K(68)>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x2002f000 0x11000>; + }; + +#ifdef USE_NON_SECURE_ADDRESS_MAP + global_peripherals: peripheral@40000000 { + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x40000000 0x10000000>; +#else + global_peripherals: peripheral@50000000 { + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x50000000 0x10000000>; +#endif + + 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>; + rx-delay-supported; + rx-delay = <1>; + status = "disabled"; + }; + + uart00: uart@4a000 { + compatible = "nordic,nrf-uarte"; + reg = <0x4a000 0x1000>; + interrupts = <74 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; + }; + + cpuflpr_vpr: vpr@4c000 { + compatible = "nordic,nrf-vpr-coprocessor"; + reg = <0x4c000 0x1000>; + ranges = <0x0 0x4c000 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + status = "disabled"; + + cpuflpr_vevif_remote: mailbox@0 { + compatible = "nordic,nrf-vevif-remote"; + reg = <0x0 0x1000>; + #mbox-cells = <1>; + nordic,tasks = <18>; + nordic,tasks-mask = <0x007f0000>; + status = "disabled"; + }; + + cpuflpr_clic: interrupt-controller@f0000000 { + compatible = "nordic,nrf-clic"; + reg = <0xf0000000 0x1780>; + interrupt-controller; + #interrupt-cells = <2>; + #address-cells = <1>; + 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>; + max-frequency = ; + 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>; + max-frequency = ; + 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>; + easydma-maxcnt-bits = <16>; + 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>; + rx-delay-supported; + rx-delay = <1>; + 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>; + easydma-maxcnt-bits = <16>; + 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>; + rx-delay-supported; + rx-delay = <1>; + 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>; + easydma-maxcnt-bits = <16>; + 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>; + rx-delay-supported; + rx-delay = <1>; + 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>; + }; + + pwm20: pwm@d2000 { + compatible = "nordic,nrf-pwm"; + status = "disabled"; + reg = <0xd2000 0x1000>; + interrupts = <210 NRF_DEFAULT_IRQ_PRIORITY>; + #pwm-cells = <3>; + }; + + pwm21: pwm@d3000 { + compatible = "nordic,nrf-pwm"; + status = "disabled"; + reg = <0xd3000 0x1000>; + interrupts = <211 NRF_DEFAULT_IRQ_PRIORITY>; + #pwm-cells = <3>; + }; + + pwm22: pwm@d4000 { + compatible = "nordic,nrf-pwm"; + status = "disabled"; + reg = <0xd4000 0x1000>; + interrupts = <212 NRF_DEFAULT_IRQ_PRIORITY>; + #pwm-cells = <3>; + }; + + 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>; + 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>; + 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>; + easydma-maxcnt-bits = <16>; + 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>; + rx-delay-supported; + rx-delay = <1>; + status = "disabled"; + }; + + uart30: uart@104000 { + compatible = "nordic,nrf-uarte"; + reg = <0x104000 0x1000>; + interrupts = <260 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; + }; + +#ifdef USE_NON_SECURE_ADDRESS_MAP + /* intentionally empty because WDT30 is hardware fixed to Secure */ +#else + wdt30: watchdog@108000 { + compatible = "nordic,nrf-wdt"; + reg = <0x108000 0x620>; + interrupts = <264 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; + }; +#endif + + 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>; + status = "disabled"; + instance = <30>; + }; + + clock: clock@10e000 { + compatible = "nordic,nrf-clock"; + reg = <0x10e000 0x1000>; + interrupts = <270 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; + }; + }; + + rram_controller: rram-controller@5004b000 { + compatible = "nordic,rram-controller"; + reg = <0x5004b000 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + interrupts = <75 NRF_DEFAULT_IRQ_PRIORITY>; + + cpuapp_rram: rram@0 { + compatible = "soc-nv-flash"; + reg = <0x0 DT_SIZE_K(1428)>; + erase-block-size = <4096>; + write-block-size = <16>; + }; + cpuflpr_rram: rram@165000 { + compatible = "soc-nv-flash"; + reg = <0x165000 DT_SIZE_K(96)>; + erase-block-size = <4096>; + write-block-size = <16>; + }; + }; + + cpuapp_ppb: cpuapp-ppb-bus { + #address-cells = <1>; + #size-cells = <1>; + + cpuapp_nvic: interrupt-controller@e000e100 { + #address-cells = <1>; + compatible = "arm,v8m-nvic"; + reg = <0xe000e100 0xc00>; + arm,num-irq-priority-bits = <3>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + cpuapp_systick: timer@e000e010 { + compatible = "arm,armv8m-systick"; + reg = <0xe000e010 0x10>; + status = "disabled"; + }; + }; + }; +}; diff --git a/dts/riscv/andes/andes_v5_ae350.dtsi b/dts/riscv/andes/andes_v5_ae350.dtsi index 419aa712b73..c69a92581ad 100644 --- a/dts/riscv/andes/andes_v5_ae350.dtsi +++ b/dts/riscv/andes/andes_v5_ae350.dtsi @@ -205,7 +205,6 @@ l2_cache: cache-controller@e0500000 { compatible = "andestech,l2c"; reg = <0xe0500000 0x1000>; - cache-unified; status = "disabled"; }; diff --git a/dts/riscv/ite/it81202dx.dtsi b/dts/riscv/ite/it81202dx.dtsi new file mode 100644 index 00000000000..73f577d814a --- /dev/null +++ b/dts/riscv/ite/it81202dx.dtsi @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2024 ITE Corporation. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + soc { + sram0: memory@80100000 { + compatible = "mmio-sram"; + reg = <0x80100000 DT_SIZE_K(128)>; + }; + }; +}; diff --git a/dts/riscv/ite/it81302dx.dtsi b/dts/riscv/ite/it81302dx.dtsi new file mode 100644 index 00000000000..73f577d814a --- /dev/null +++ b/dts/riscv/ite/it81302dx.dtsi @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2024 ITE Corporation. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + soc { + sram0: memory@80100000 { + compatible = "mmio-sram"; + reg = <0x80100000 DT_SIZE_K(128)>; + }; + }; +}; diff --git a/dts/riscv/ite/it81xx2.dtsi b/dts/riscv/ite/it81xx2.dtsi index 32d47861ee7..252ddfe120b 100644 --- a/dts/riscv/ite/it81xx2.dtsi +++ b/dts/riscv/ite/it81xx2.dtsi @@ -608,6 +608,12 @@ IT8XXX2_IRQ_TIMER2 IRQ_TYPE_EDGE_RISING>; /* One shot timer */ interrupt-parent = <&intc>; }; + + sha0: sha@f0202d { + compatible = "ite,it8xxx2-sha"; + reg = <0x00f0202d 0x3>; + status = "disabled"; + }; }; }; diff --git a/dts/riscv/ite/it82xx2.dtsi b/dts/riscv/ite/it82xx2.dtsi index fde5906d065..a9ab8b206cf 100644 --- a/dts/riscv/ite/it82xx2.dtsi +++ b/dts/riscv/ite/it82xx2.dtsi @@ -467,10 +467,14 @@ pinctrlb: pinctrl@f01668 { compatible = "ite,it8xxx2-pinctrl-func"; reg = <0x00f01668 8>; /* GPCR */ - func3-gcr = <0xf03e15 0xf03e15 0xf03e16 NO_FUNC + func3-gcr = <0xf03e15 0xf03e15 0xf03e11 NO_FUNC + NO_FUNC 0xf03e11 NO_FUNC NO_FUNC>; + func3-en-mask = <0x01 0x02 0x20 0 + 0 0x20 0 0 >; + func3-ext = ; - func3-en-mask = <0x01 0x02 0x40 0 - 0 0x40 0 0 >; + func3-ext-mask = <0 0 0x40 0 + 0 0x40 0 0 >; func4-gcr = ; func4-en-mask = <0 0 0 0 @@ -994,5 +998,11 @@ num-in-endpoints = <10>; num-out-endpoints = <5>; }; + + sha0: crypto@f03c00 { + compatible = "ite,it8xxx2-sha-v2"; + reg = <0x00f03c00 0x5>; + status = "disabled"; + }; }; }; diff --git a/dts/riscv/ite/it8xxx2.dtsi b/dts/riscv/ite/it8xxx2.dtsi index faa16fbaefe..a780558e928 100644 --- a/dts/riscv/ite/it8xxx2.dtsi +++ b/dts/riscv/ite/it8xxx2.dtsi @@ -709,12 +709,6 @@ kso17-gpios = <&gpioc 5 (GPIO_OPEN_DRAIN | GPIO_PULL_UP)>; }; - sha0: sha@f0202d { - compatible = "ite,it8xxx2-sha"; - reg = <0x00f0202d 0x3>; - status = "disabled"; - }; - usbpd0: usbpd@f03700 { compatible = "ite,it8xxx2-usbpd"; reg = <0x00f03700 0x100>; diff --git a/dts/riscv/nordic/nrf54h20_cpuppr.dtsi b/dts/riscv/nordic/nrf54h20_cpuppr.dtsi index 6f90cbf3e6a..1f2900769dd 100644 --- a/dts/riscv/nordic/nrf54h20_cpuppr.dtsi +++ b/dts/riscv/nordic/nrf54h20_cpuppr.dtsi @@ -28,6 +28,10 @@ cpusys_vevif: &cpusys_vevif_remote {}; }; }; +&cpuppr_clic { + status = "okay"; +}; + &cpusec_bellboard { compatible = "nordic,nrf-bellboard-remote"; }; diff --git a/dts/riscv/nordic/nrf54l15_cpuflpr.dtsi b/dts/riscv/nordic/nrf54l15_cpuflpr.dtsi new file mode 100644 index 00000000000..14a92935f4a --- /dev/null +++ b/dts/riscv/nordic/nrf54l15_cpuflpr.dtsi @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +cpu: &cpuflpr {}; +clic: &cpuflpr_clic {}; +cpuflpr_vevif: &cpuflpr_vevif_local {}; + +/delete-node/ &cpuapp; +/delete-node/ &cpuapp_rram; +/delete-node/ &cpuapp_ppb; +/delete-node/ &cpuapp_sram; + +/ { + soc { + compatible = "simple-bus"; + interrupt-parent = <&cpuflpr_clic>; + ranges; + }; +}; + +&cpuflpr_clic { + status = "okay"; +}; + +&grtc { + interrupts = <226 NRF_DEFAULT_IRQ_PRIORITY>; +}; + +&gpiote20 { + interrupts = <218 NRF_DEFAULT_IRQ_PRIORITY>; +}; + +&gpiote30 { + interrupts = <268 NRF_DEFAULT_IRQ_PRIORITY>; +}; diff --git a/dts/riscv/qemu/virt-riscv.dtsi b/dts/riscv/qemu/virt-riscv.dtsi new file mode 100644 index 00000000000..8329a1ec62b --- /dev/null +++ b/dts/riscv/qemu/virt-riscv.dtsi @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2020 Cobham Gaisler AB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * This file is based on: + * qemu-system-riscv32 -machine virt,dumpdtb=virt.dtb -smp 8 -m 256 + * dtc virt.dtb > virt.dtsi + */ + +/dts-v1/; + +/ { + #address-cells = < 0x01 >; + #size-cells = < 0x01 >; + compatible = "riscv-virtio"; + model = "riscv-virtio,qemu"; + + flash@20000000 { + bank-width = < 0x04 >; + reg = < 0x20000000 0x2000000 0x22000000 0x2000000 >; + compatible = "cfi-flash"; + }; + + uart0: uart@10000000 { + interrupts = < 0x0a 1 >; + interrupt-parent = < &plic >; + clock-frequency = < 0x384000 >; + reg = < 0x10000000 0x100 >; + compatible = "ns16550"; + reg-shift = < 0 >; + }; + + cpus { + #address-cells = < 0x01 >; + #size-cells = < 0x00 >; + + cpu@0 { + device_type = "cpu"; + reg = < 0x00 >; + status = "okay"; + compatible = "qemu,riscv-virt", "riscv"; + + hlic0: interrupt-controller { + compatible = "riscv,cpu-intc"; + #address-cells = <0>; + #interrupt-cells = < 0x01 >; + interrupt-controller; + }; + }; + + cpu@1 { + device_type = "cpu"; + reg = < 0x01 >; + status = "okay"; + compatible = "qemu,riscv-virt", "riscv"; + + hlic1: interrupt-controller { + compatible = "riscv,cpu-intc"; + #address-cells = <0>; + #interrupt-cells = < 0x01 >; + interrupt-controller; + }; + }; + + cpu@2 { + device_type = "cpu"; + reg = < 0x02 >; + status = "okay"; + compatible = "qemu,riscv-virt", "riscv"; + + hlic2: interrupt-controller { + compatible = "riscv,cpu-intc"; + #address-cells = <0>; + #interrupt-cells = < 0x01 >; + interrupt-controller; + }; + }; + + cpu@3 { + device_type = "cpu"; + reg = < 0x03 >; + status = "okay"; + compatible = "qemu,riscv-virt", "riscv"; + + hlic3: interrupt-controller { + compatible = "riscv,cpu-intc"; + #address-cells = <0>; + #interrupt-cells = < 0x01 >; + interrupt-controller; + }; + }; + + cpu@4 { + device_type = "cpu"; + reg = < 0x04 >; + status = "okay"; + compatible = "qemu,riscv-virt", "riscv"; + + hlic4: interrupt-controller { + compatible = "riscv,cpu-intc"; + #address-cells = <0>; + #interrupt-cells = < 0x01 >; + interrupt-controller; + }; + }; + + cpu@5 { + device_type = "cpu"; + reg = < 0x05 >; + status = "okay"; + compatible = "qemu,riscv-virt", "riscv"; + + hlic5: interrupt-controller { + compatible = "riscv,cpu-intc"; + #address-cells = <0>; + #interrupt-cells = < 0x01 >; + interrupt-controller; + }; + }; + + cpu@6 { + device_type = "cpu"; + reg = < 0x06 >; + status = "okay"; + compatible = "qemu,riscv-virt", "riscv"; + + hlic6: interrupt-controller { + compatible = "riscv,cpu-intc"; + #address-cells = <0>; + #interrupt-cells = < 0x01 >; + interrupt-controller; + }; + }; + + cpu@7 { + device_type = "cpu"; + reg = < 0x07 >; + status = "okay"; + compatible = "qemu,riscv-virt", "riscv"; + + hlic7: interrupt-controller { + compatible = "riscv,cpu-intc"; + #address-cells = <0>; + #interrupt-cells = < 0x01 >; + interrupt-controller; + }; + }; + }; + + ram0: memory@80000000 { + device_type = "memory"; + reg = < 0x80000000 0x10000000 >; + }; + + soc { + #address-cells = < 0x01 >; + #size-cells = < 0x01 >; + compatible = "simple-bus"; + ranges; + + plic: interrupt-controller@c000000 { + riscv,max-priority = <7>; + riscv,ndev = < 1024 >; + reg = <0x0c000000 0x04000000>; + interrupts-extended = < + &hlic0 0x0b &hlic0 0x09 + &hlic1 0x0b &hlic1 0x09 + &hlic2 0x0b &hlic2 0x09 + &hlic3 0x0b &hlic3 0x09 + &hlic4 0x0b &hlic4 0x09 + &hlic5 0x0b &hlic5 0x09 + &hlic6 0x0b &hlic6 0x09 + &hlic7 0x0b &hlic7 0x09 + >; + interrupt-controller; + compatible = "sifive,plic-1.0.0"; + #address-cells = < 0x00 >; + #interrupt-cells = < 0x02 >; + }; + + clint@2000000 { + compatible = "sifive,clint0"; + reg = <0x2000000 0x10000>; + interrupts-extended = <&hlic0 0x03 &hlic0 0x07 + &hlic1 0x03 &hlic1 0x07 + &hlic2 0x03 &hlic2 0x07 + &hlic3 0x03 &hlic3 0x07 + &hlic4 0x03 &hlic4 0x07 + &hlic5 0x03 &hlic5 0x07 + &hlic6 0x03 &hlic6 0x07 + &hlic7 0x03 &hlic7 0x07>; + }; + }; +}; diff --git a/dts/riscv/qemu/virt-riscv32.dtsi b/dts/riscv/qemu/virt-riscv32.dtsi new file mode 100644 index 00000000000..25d769d5183 --- /dev/null +++ b/dts/riscv/qemu/virt-riscv32.dtsi @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2024 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include + +/ { + cpus { + cpu@0 { + riscv,isa = "rv32gc"; + }; + + cpu@1 { + riscv,isa = "rv32gc"; + }; + + cpu@2 { + riscv,isa = "rv32gc"; + }; + + cpu@3 { + riscv,isa = "rv32gc"; + }; + + cpu@4 { + riscv,isa = "rv32gc"; + }; + + cpu@5 { + riscv,isa = "rv32gc"; + }; + + cpu@6 { + riscv,isa = "rv32gc"; + }; + + cpu@7 { + riscv,isa = "rv32gc"; + }; + }; +}; diff --git a/dts/riscv/qemu/virt-riscv64.dtsi b/dts/riscv/qemu/virt-riscv64.dtsi new file mode 100644 index 00000000000..936f0a18815 --- /dev/null +++ b/dts/riscv/qemu/virt-riscv64.dtsi @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2024 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include + +/ { + cpus { + cpu@0 { + riscv,isa = "rv64gc"; + }; + + cpu@1 { + riscv,isa = "rv64gc"; + }; + + cpu@2 { + riscv,isa = "rv64gc"; + }; + + cpu@3 { + riscv,isa = "rv64gc"; + }; + + cpu@4 { + riscv,isa = "rv64gc"; + }; + + cpu@5 { + riscv,isa = "rv64gc"; + }; + + cpu@6 { + riscv,isa = "rv64gc"; + }; + + cpu@7 { + riscv,isa = "rv64gc"; + }; + }; +}; diff --git a/dts/riscv/sifive/riscv64-fu540.dtsi b/dts/riscv/sifive/riscv64-fu540.dtsi index 7ccd950129a..bc9c14ebb59 100644 --- a/dts/riscv/sifive/riscv64-fu540.dtsi +++ b/dts/riscv/sifive/riscv64-fu540.dtsi @@ -51,7 +51,7 @@ soc { #address-cells = <1>; #size-cells = <1>; - compatible = "simple-bus"; + compatible = "fu540-soc", "sifive-soc", "simple-bus"; ranges; modeselect: rom@1000 { diff --git a/dts/riscv/sifive/riscv64-fu740.dtsi b/dts/riscv/sifive/riscv64-fu740.dtsi index 61421cd557e..314cc175eed 100644 --- a/dts/riscv/sifive/riscv64-fu740.dtsi +++ b/dts/riscv/sifive/riscv64-fu740.dtsi @@ -102,7 +102,7 @@ soc { #address-cells = <2>; #size-cells = <2>; - compatible = "simple-bus"; + compatible = "fu740-soc", "sifive-soc", "simple-bus"; ranges; modeselect: rom@1000 { diff --git a/dts/riscv/virt.dtsi b/dts/riscv/virt.dtsi deleted file mode 100644 index 20873731c6e..00000000000 --- a/dts/riscv/virt.dtsi +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright (c) 2020 Cobham Gaisler AB - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/* - * This file is based on: - * qemu-system-riscv32 -machine virt,dumpdtb=virt.dtb -smp 8 -m 256 - * dtc virt.dtb > virt.dtsi - */ - -/dts-v1/; - -/ { - #address-cells = < 0x01 >; - #size-cells = < 0x01 >; - compatible = "riscv-virtio"; - model = "riscv-virtio,qemu"; - - flash@20000000 { - bank-width = < 0x04 >; - reg = < 0x20000000 0x2000000 0x22000000 0x2000000 >; - compatible = "cfi-flash"; - }; - - uart0: uart@10000000 { - interrupts = < 0x0a 1 >; - interrupt-parent = < &plic >; - clock-frequency = < 0x384000 >; - reg = < 0x10000000 0x100 >; - compatible = "ns16550"; - reg-shift = < 0 >; - }; - - cpus { - #address-cells = < 0x01 >; - #size-cells = < 0x00 >; - - cpu@0 { - device_type = "cpu"; - reg = < 0x00 >; - status = "okay"; - compatible = "riscv"; - - hlic0: interrupt-controller { - compatible = "riscv,cpu-intc"; - #address-cells = <0>; - #interrupt-cells = < 0x01 >; - interrupt-controller; - }; - }; - - cpu@1 { - device_type = "cpu"; - reg = < 0x01 >; - status = "okay"; - compatible = "riscv"; - - hlic1: interrupt-controller { - compatible = "riscv,cpu-intc"; - #address-cells = <0>; - #interrupt-cells = < 0x01 >; - interrupt-controller; - }; - }; - - cpu@2 { - device_type = "cpu"; - reg = < 0x02 >; - status = "okay"; - compatible = "riscv"; - - hlic2: interrupt-controller { - compatible = "riscv,cpu-intc"; - #address-cells = <0>; - #interrupt-cells = < 0x01 >; - interrupt-controller; - }; - }; - - cpu@3 { - device_type = "cpu"; - reg = < 0x03 >; - status = "okay"; - compatible = "riscv"; - - hlic3: interrupt-controller { - compatible = "riscv,cpu-intc"; - #address-cells = <0>; - #interrupt-cells = < 0x01 >; - interrupt-controller; - }; - }; - - cpu@4 { - device_type = "cpu"; - reg = < 0x04 >; - status = "okay"; - compatible = "riscv"; - - hlic4: interrupt-controller { - compatible = "riscv,cpu-intc"; - #address-cells = <0>; - #interrupt-cells = < 0x01 >; - interrupt-controller; - }; - }; - - cpu@5 { - device_type = "cpu"; - reg = < 0x05 >; - status = "okay"; - compatible = "riscv"; - - hlic5: interrupt-controller { - compatible = "riscv,cpu-intc"; - #address-cells = <0>; - #interrupt-cells = < 0x01 >; - interrupt-controller; - }; - }; - - cpu@6 { - device_type = "cpu"; - reg = < 0x06 >; - status = "okay"; - compatible = "riscv"; - - hlic6: interrupt-controller { - compatible = "riscv,cpu-intc"; - #address-cells = <0>; - #interrupt-cells = < 0x01 >; - interrupt-controller; - }; - }; - - cpu@7 { - device_type = "cpu"; - reg = < 0x07 >; - status = "okay"; - compatible = "riscv"; - - hlic7: interrupt-controller { - compatible = "riscv,cpu-intc"; - #address-cells = <0>; - #interrupt-cells = < 0x01 >; - interrupt-controller; - }; - }; - }; - - ram0: memory@80000000 { - device_type = "memory"; - reg = < 0x80000000 0x10000000 >; - }; - - soc { - #address-cells = < 0x01 >; - #size-cells = < 0x01 >; - compatible = "simple-bus"; - ranges; - - plic: interrupt-controller@c000000 { - riscv,max-priority = <7>; - riscv,ndev = < 1024 >; - reg = <0x0c000000 0x04000000>; - interrupts-extended = < - &hlic0 0x0b &hlic0 0x09 - &hlic1 0x0b &hlic1 0x09 - &hlic2 0x0b &hlic2 0x09 - &hlic3 0x0b &hlic3 0x09 - &hlic4 0x0b &hlic4 0x09 - &hlic5 0x0b &hlic5 0x09 - &hlic6 0x0b &hlic6 0x09 - &hlic7 0x0b &hlic7 0x09 - >; - interrupt-controller; - compatible = "sifive,plic-1.0.0"; - #address-cells = < 0x00 >; - #interrupt-cells = < 0x02 >; - }; - - clint@2000000 { - compatible = "sifive,clint0"; - reg = <0x2000000 0x10000>; - interrupts-extended = <&hlic0 0x03 &hlic0 0x07 - &hlic1 0x03 &hlic1 0x07 - &hlic2 0x03 &hlic2 0x07 - &hlic3 0x03 &hlic3 0x07 - &hlic4 0x03 &hlic4 0x07 - &hlic5 0x03 &hlic5 0x07 - &hlic6 0x03 &hlic6 0x07 - &hlic7 0x03 &hlic7 0x07>; - }; - }; -}; diff --git a/dts/x86/intel/alder_lake.dtsi b/dts/x86/intel/alder_lake.dtsi index 968ca3ab1cf..b847278b24f 100644 --- a/dts/x86/intel/alder_lake.dtsi +++ b/dts/x86/intel/alder_lake.dtsi @@ -9,6 +9,7 @@ #include #include #include +#include "gpio_common.dtsi" / { cpus { @@ -45,6 +46,92 @@ #address-cells = <1>; }; + acpi { + gpio_a: gpio_a { + acpi-hid = "INTC1057"; + acpi-uid = "2"; + group-index = <0x02>; + status = "okay"; + }; + + gpio_b: gpio_b { + acpi-hid = "INTC1057"; + acpi-uid = "0"; + group-index = <0x0>; + status = "okay"; + }; + + gpio_c: gpio_c { + acpi-hid = "INTC1057"; + acpi-uid = "0"; + group-index = <0x0B>; + status = "okay"; + }; + + gpio_d: gpio_d { + acpi-hid = "INTC1057"; + acpi-uid = "0"; + group-index = <0x8>; + status = "okay"; + }; + + gpio_e: gpio_e { + acpi-hid = "INTC1057"; + acpi-uid = "0"; + group-index = <0xE>; + status = "okay"; + }; + + gpio_f: gpio_f { + acpi-hid = "INTC1057"; + acpi-uid = "0"; + group-index = <0xC>; + status = "okay"; + }; + + gpio_h: gpio_h { + acpi-hid = "INTC1057"; + acpi-uid = "0"; + group-index = <0x7>; + status = "okay"; + }; + + gpio_i: gpio_i { + acpi-hid = "INTC1057"; + acpi-uid = "0"; + group-index = <0x9>; + status = "okay"; + }; + + gpio_s: gpio_s { + acpi-hid = "INTC1057"; + acpi-uid = "0"; + group-index = <0x6>; + status = "okay"; + }; + + gpio_r: gpio_r { + acpi-hid = "INTC1057"; + acpi-uid = "0"; + group-index = <0x3>; + status = "okay"; + }; + + gpio_t: gpio_t { + acpi-hid = "INTC1057"; + acpi-uid = "0"; + group-index = <0x1>; + status = "okay"; + }; + + gpio_v: gpio_v { + acpi-hid = "INTC1057"; + acpi-uid = "0"; + group-index = <0xA>; + status = "okay"; + }; + }; + pcie0: pcie0 { #address-cells = <1>; #size-cells = <1>; @@ -207,7 +294,7 @@ pw,cs-mode = <0>; pw,cs-output = <0>; pw,fifo-depth = <64>; - cs-gpios = <&gpio_4_e 10 GPIO_ACTIVE_LOW>; + cs-gpios = <&gpio_e 10 GPIO_ACTIVE_LOW>; clock-frequency = <100000000>; interrupts = ; interrupt-parent = <&intc>; @@ -223,7 +310,7 @@ pw,cs-mode = <0>; pw,cs-output = <0>; pw,fifo-depth = <64>; - cs-gpios = <&gpio_4_f 16 GPIO_ACTIVE_LOW>; + cs-gpios = <&gpio_f 16 GPIO_ACTIVE_LOW>; clock-frequency = <100000000>; interrupts = ; interrupt-parent = <&intc>; @@ -239,7 +326,7 @@ pw,cs-mode = <0>; pw,cs-output = <0>; pw,fifo-depth = <64>; - cs-gpios = <&gpio_1_d 9 GPIO_ACTIVE_LOW>; + cs-gpios = <&gpio_d 9 GPIO_ACTIVE_LOW>; clock-frequency = <100000000>; interrupts = ; interrupt-parent = <&intc>; @@ -292,167 +379,6 @@ status = "okay"; }; - 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_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_i: 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 = <19>; - pin-offset = <8>; - - status = "okay"; - }; - - - gpio_1_h: gpio@fd6d08c0 { - compatible = "intel,gpio"; - reg = <0xfd6d08c0 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_1_d: gpio@fd6d0a40 { - compatible = "intel,gpio"; - reg = <0xfd6d0a40 0x1000>; - interrupts = <14 IRQ_TYPE_LOWEST_LEVEL_LOW 3>; - interrupt-parent = <&intc>; - - group-index = <0x3>; - gpio-controller; - #gpio-cells = <2>; - - ngpios = <20>; - pin-offset = <49>; - - 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 = <8>; - 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>; diff --git a/dts/x86/intel/gpio_common.dtsi b/dts/x86/intel/gpio_common.dtsi new file mode 100644 index 00000000000..7c122f72f78 --- /dev/null +++ b/dts/x86/intel/gpio_common.dtsi @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2024 Intel Corporation. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "skeleton.dtsi" +#include +#include +#include + +/ { + acpi { + gpio_a: gpio_a { + compatible = "intel,gpio"; + interrupt-parent = <&intc>; + interrupts = ; + gpio-controller; + #gpio-cells = <2>; + status = "disabled"; + }; + + gpio_b: gpio_b { + compatible = "intel,gpio"; + interrupt-parent = <&intc>; + interrupts = ; + gpio-controller; + #gpio-cells = <2>; + status = "disabled"; + }; + + gpio_c: gpio_c { + compatible = "intel,gpio"; + interrupt-parent = <&intc>; + interrupts = ; + gpio-controller; + #gpio-cells = <2>; + status = "disabled"; + }; + + gpio_d: gpio_d { + compatible = "intel,gpio"; + interrupt-parent = <&intc>; + interrupts = ; + gpio-controller; + #gpio-cells = <2>; + status = "disabled"; + }; + + gpio_e: gpio_e { + compatible = "intel,gpio"; + interrupt-parent = <&intc>; + interrupts = ; + gpio-controller; + #gpio-cells = <2>; + status = "disabled"; + }; + + gpio_f: gpio_f { + compatible = "intel,gpio"; + interrupt-parent = <&intc>; + interrupts = ; + gpio-controller; + #gpio-cells = <2>; + status = "disabled"; + }; + + gpio_g: gpio_g { + compatible = "intel,gpio"; + interrupt-parent = <&intc>; + interrupts = ; + gpio-controller; + #gpio-cells = <2>; + status = "disabled"; + }; + + gpio_h: gpio_h { + compatible = "intel,gpio"; + interrupt-parent = <&intc>; + interrupts = ; + gpio-controller; + #gpio-cells = <2>; + status = "disabled"; + }; + + gpio_i: gpio_i { + compatible = "intel,gpio"; + interrupt-parent = <&intc>; + interrupts = ; + gpio-controller; + #gpio-cells = <2>; + status = "disabled"; + }; + + gpio_j: gpio_j { + compatible = "intel,gpio"; + interrupt-parent = <&intc>; + interrupts = ; + gpio-controller; + #gpio-cells = <2>; + status = "disabled"; + }; + + gpio_k: gpio_k { + compatible = "intel,gpio"; + interrupt-parent = <&intc>; + interrupts = ; + gpio-controller; + #gpio-cells = <2>; + status = "disabled"; + }; + + gpio_s: gpio_s { + compatible = "intel,gpio"; + interrupt-parent = <&intc>; + interrupts = ; + gpio-controller; + #gpio-cells = <2>; + status = "disabled"; + }; + + gpio_r: gpio_r { + compatible = "intel,gpio"; + interrupt-parent = <&intc>; + interrupts = ; + gpio-controller; + #gpio-cells = <2>; + status = "disabled"; + }; + + gpio_t: gpio_t { + compatible = "intel,gpio"; + interrupt-parent = <&intc>; + interrupts = ; + gpio-controller; + #gpio-cells = <2>; + status = "disabled"; + }; + + gpio_u: gpio_u { + compatible = "intel,gpio"; + interrupt-parent = <&intc>; + interrupts = ; + gpio-controller; + #gpio-cells = <2>; + status = "disabled"; + }; + + vgpio: vgpio { + compatible = "intel,gpio"; + interrupt-parent = <&intc>; + interrupts = ; + gpio-controller; + #gpio-cells = <2>; + status = "disabled"; + }; + }; +}; diff --git a/dts/xtensa/espressif/esp32/esp32_common.dtsi b/dts/xtensa/espressif/esp32/esp32_common.dtsi index 6fff7be912a..82a92ed00a8 100644 --- a/dts/xtensa/espressif/esp32/esp32_common.dtsi +++ b/dts/xtensa/espressif/esp32/esp32_common.dtsi @@ -425,5 +425,26 @@ status = "disabled"; }; + sdhc: sdhc@3ff68000 { + compatible = "espressif,esp32-sdhc"; + reg = <0x3ff68000 0x1000>; + interrupts = ; + interrupt-parent = <&intc>; + clocks = <&rtc ESP32_SDMMC_MODULE>; + #address-cells = <1>; + #size-cells = <0>; + + sdhc0: sdhc@0 { + compatible = "espressif,esp32-sdhc-slot"; + reg = <0>; + status = "disabled"; + }; + + sdhc1: sdhc@1 { + compatible = "espressif,esp32-sdhc-slot"; + reg = <1>; + status = "disabled"; + }; + }; }; }; diff --git a/dts/xtensa/intel/intel_adsp_ace15_mtpm.dtsi b/dts/xtensa/intel/intel_adsp_ace15_mtpm.dtsi index 352e119b3aa..d9595311a97 100644 --- a/dts/xtensa/intel/intel_adsp_ace15_mtpm.dtsi +++ b/dts/xtensa/intel/intel_adsp_ace15_mtpm.dtsi @@ -110,6 +110,17 @@ }; soc { + + lsbpm: lsbpm@71d80 { + compatible = "intel,adsp-lsbpm"; + reg = <0x71d80 0x0008>; + }; + + hsbpm: hsbpm@17a800 { + compatible = "intel,adsp-hsbpm"; + reg = <0x17a800 0x0008>; + }; + core_intc: core_intc@0 { compatible = "cdns,xtensa-core-intc"; reg = <0x00 0x400>; @@ -243,10 +254,15 @@ status = "okay"; }; + sspbase: ssp_base@28800 { + compatible = "intel,ssp-sspbase"; + reg = <0x28800 0x1000>; + }; + ssp0: ssp@28000 { - compatible = "intel,ssp-dai"; #address-cells = <1>; #size-cells = <0>; + compatible = "intel,ssp"; reg = <0x00028000 0x1000 0x00079C00 0x200>; interrupts = <0x00 0 0>; @@ -255,16 +271,18 @@ &lpgpdma0 3>; dma-names = "tx", "rx"; power-domain = <&io0_domain>; + ssp-index = <0>; status = "okay"; - }; - sspbase: ssp_base@28800 { - compatible = "intel,ssp-sspbase"; - reg = <0x28800 0x1000>; + ssp00: ssp@0 { + compatible = "intel,ssp-dai"; + status = "okay"; + reg = <0x0>; + }; }; ssp1: ssp@29000 { - compatible = "intel,ssp-dai"; + compatible = "intel,ssp"; #address-cells = <1>; #size-cells = <0>; reg = <0x00029000 0x1000 @@ -275,11 +293,18 @@ &lpgpdma0 5>; dma-names = "tx", "rx"; power-domain = <&io0_domain>; + ssp-index = <1>; status = "okay"; + + ssp10: ssp@10 { + compatible = "intel,ssp-dai"; + status = "okay"; + reg = <0x10>; + }; }; ssp2: ssp@2a000 { - compatible = "intel,ssp-dai"; + compatible = "intel,ssp"; #address-cells = <1>; #size-cells = <0>; reg = <0x0002a000 0x1000 @@ -290,52 +315,14 @@ &lpgpdma0 7>; dma-names = "tx", "rx"; power-domain = <&io0_domain>; + ssp-index = <2>; status = "okay"; - }; - - ssp3: ssp@2b000 { - compatible = "intel,ssp-dai"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x0002b000 0x1000 - 0x00079C00 0x200>; - interrupts = <0x03 0 0>; - interrupt-parent = <&ace_intc>; - dmas = <&lpgpdma0 8 - &lpgpdma0 9>; - dma-names = "tx", "rx"; - power-domain = <&io0_domain>; - status = "okay"; - }; - - ssp4: ssp@2c000 { - compatible = "intel,ssp-dai"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x0002c000 0x1000 - 0x00079C00 0x200>; - interrupts = <0x04 0 0>; - interrupt-parent = <&ace_intc>; - dmas = <&lpgpdma0 10 - &lpgpdma0 11>; - dma-names = "tx", "rx"; - power-domain = <&io0_domain>; - status = "okay"; - }; - ssp5: ssp@2d000 { - compatible = "intel,ssp-dai"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x0002d000 0x1000 - 0x00079C00 0x200>; - interrupts = <0x04 0 0>; - interrupt-parent = <&ace_intc>; - dmas = <&lpgpdma0 12 - &lpgpdma0 13>; - dma-names = "tx", "rx"; - power-domain = <&io0_domain>; - status = "okay"; + ssp20: ssp@20 { + compatible = "intel,ssp-dai"; + status = "okay"; + reg = <0x20>; + }; }; mem_window0: mem_window@70200 { diff --git a/dts/xtensa/intel/intel_adsp_ace20_lnl.dtsi b/dts/xtensa/intel/intel_adsp_ace20_lnl.dtsi index d89dcb9c7f6..e3462c834d1 100644 --- a/dts/xtensa/intel/intel_adsp_ace20_lnl.dtsi +++ b/dts/xtensa/intel/intel_adsp_ace20_lnl.dtsi @@ -129,6 +129,17 @@ }; soc { + + lsbpm: lsbpm@71d80 { + compatible = "intel,adsp-lsbpm"; + reg = <0x71d80 0x0008>; + }; + + hsbpm: hsbpm@17a800 { + compatible = "intel,adsp-hsbpm"; + reg = <0x17a800 0x0008>; + }; + core_intc: core_intc@0 { compatible = "cdns,xtensa-core-intc"; reg = <0x00 0x400>; @@ -178,7 +189,7 @@ }; ssp0: ssp@28100 { - compatible = "intel,ssp-dai"; + compatible = "intel,ssp"; #address-cells = <1>; #size-cells = <0>; reg = <0x00028100 0x1000 @@ -190,11 +201,18 @@ &hda_link_in 1>; dma-names = "tx", "rx"; power-domain = <&io0_domain>; + ssp-index = <0>; status = "okay"; + + ssp00: ssp@0 { + compatible = "intel,ssp-dai"; + status = "okay"; + reg = <0x0>; + }; }; ssp1: ssp@29100 { - compatible = "intel,ssp-dai"; + compatible = "intel,ssp"; #address-cells = <1>; #size-cells = <0>; reg = <0x00029100 0x1000 @@ -206,11 +224,18 @@ &hda_link_in 2>; dma-names = "tx", "rx"; power-domain = <&io0_domain>; + ssp-index = <1>; status = "okay"; + + ssp10: ssp@10 { + compatible = "intel,ssp-dai"; + status = "okay"; + reg = <0x10>; + }; }; ssp2: ssp@2a100 { - compatible = "intel,ssp-dai"; + compatible = "intel,ssp"; #address-cells = <1>; #size-cells = <0>; reg = <0x0002a100 0x1000 @@ -222,55 +247,14 @@ &hda_link_in 3>; dma-names = "tx", "rx"; power-domain = <&io0_domain>; + ssp-index = <2>; status = "okay"; - }; - - ssp3: ssp@2b100 { - compatible = "intel,ssp-dai"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x0002b100 0x1000 - 0x00079C00 0x200>; - i2svss = <0x0002BC00 0x1000>; - interrupts = <0x03 0 0>; - interrupt-parent = <&ace_intc>; - dmas = <&hda_link_out 4 - &hda_link_in 4>; - dma-names = "tx", "rx"; - power-domain = <&io0_domain>; - status = "okay"; - }; - - ssp4: ssp@2c100 { - compatible = "intel,ssp-dai"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x0002c100 0x1000 - 0x00079C00 0x200>; - i2svss = <0x0002CC00 0x1000>; - interrupts = <0x04 0 0>; - interrupt-parent = <&ace_intc>; - dmas = <&hda_link_out 5 - &hda_link_in 5>; - dma-names = "tx", "rx"; - power-domain = <&io0_domain>; - status = "okay"; - }; - ssp5: ssp@2d100 { - compatible = "intel,ssp-dai"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x0002d100 0x1000 - 0x00079C00 0x200>; - i2svss = <0x0002DC00 0x1000>; - interrupts = <0x04 0 0>; - interrupt-parent = <&ace_intc>; - dmas = <&hda_link_out 6 - &hda_link_in 6>; - dma-names = "tx", "rx"; - power-domain = <&io0_domain>; - status = "okay"; + ssp20: ssp@20 { + compatible = "intel,ssp-dai"; + status = "okay"; + reg = <0x20>; + }; }; mem_window0: mem_window@70200 { diff --git a/dts/xtensa/intel/intel_adsp_cavs25.dtsi b/dts/xtensa/intel/intel_adsp_cavs25.dtsi index 36ad7afa218..552d6cf9359 100644 --- a/dts/xtensa/intel/intel_adsp_cavs25.dtsi +++ b/dts/xtensa/intel/intel_adsp_cavs25.dtsi @@ -106,6 +106,16 @@ }; soc { + lsbpm: lsbpm@71d50 { + compatible = "intel,adsp-lsbpm"; + reg = <0x71d50 0x10>; + }; + + hsbpm: hsbpm@71d10 { + compatible = "intel,adsp-hsbpm"; + reg = <0x71d10 0x10>; + }; + shim: shim@71f00 { compatible = "intel,adsp-shim"; reg = <0x71f00 0x100>; @@ -217,7 +227,7 @@ }; ssp0: ssp@77000 { - compatible = "intel,ssp-dai"; + compatible = "intel,ssp"; #address-cells = <1>; #size-cells = <0>; reg = <0x00077000 0x200 @@ -227,12 +237,18 @@ dmas = <&lpgpdma0 2 &lpgpdma0 3>; dma-names = "tx", "rx"; - + ssp-index = <0>; status = "okay"; + + ssp00: ssp@0 { + compatible = "intel,ssp-dai"; + reg = <0x0>; + status = "okay"; + }; }; ssp1: ssp@77200 { - compatible = "intel,ssp-dai"; + compatible = "intel,ssp"; #address-cells = <1>; #size-cells = <0>; reg = <0x00077200 0x200 @@ -242,12 +258,18 @@ dmas = <&lpgpdma0 4 &lpgpdma0 5>; dma-names = "tx", "rx"; - + ssp-index = <1>; status = "okay"; + + ssp10: ssp@10 { + compatible = "intel,ssp-dai"; + reg = <0x10>; + status = "okay"; + }; }; ssp2: ssp@77400 { - compatible = "intel,ssp-dai"; + compatible = "intel,ssp"; #address-cells = <1>; #size-cells = <0>; reg = <0x00077400 0x200 @@ -257,12 +279,18 @@ dmas = <&lpgpdma0 6 &lpgpdma0 7>; dma-names = "tx", "rx"; - + ssp-index = <2>; status = "okay"; + + ssp20: ssp@20 { + compatible = "intel,ssp-dai"; + reg = <0x20>; + status = "okay"; + }; }; ssp3: ssp@77600 { - compatible = "intel,ssp-dai"; + compatible = "intel,ssp"; #address-cells = <1>; #size-cells = <0>; reg = <0x00077600 0x200 @@ -272,12 +300,18 @@ dmas = <&lpgpdma0 8 &lpgpdma0 9>; dma-names = "tx", "rx"; - + ssp-index = <3>; status = "okay"; + + ssp30: ssp@30 { + compatible = "intel,ssp-dai"; + reg = <0x30>; + status = "okay"; + }; }; ssp4: ssp@77800 { - compatible = "intel,ssp-dai"; + compatible = "intel,ssp"; #address-cells = <1>; #size-cells = <0>; reg = <0x00077800 0x200 @@ -287,12 +321,18 @@ dmas = <&lpgpdma0 10 &lpgpdma0 11>; dma-names = "tx", "rx"; - + ssp-index = <4>; status = "okay"; + + ssp40: ssp@40 { + compatible = "intel,ssp-dai"; + reg = <0x40>; + status = "okay"; + }; }; ssp5: ssp@77a00 { - compatible = "intel,ssp-dai"; + compatible = "intel,ssp"; #address-cells = <1>; #size-cells = <0>; reg = <0x00077A00 0x200 @@ -302,8 +342,14 @@ dmas = <&lpgpdma0 12 &lpgpdma0 13>; dma-names = "tx", "rx"; - + ssp-index = <5>; status = "okay"; + + ssp50: ssp@50 { + compatible = "intel,ssp-dai"; + reg = <0x50>; + status = "okay"; + }; }; /* diff --git a/dts/xtensa/intel/intel_adsp_cavs25_tgph.dtsi b/dts/xtensa/intel/intel_adsp_cavs25_tgph.dtsi index facb914904c..7ea35568fcd 100644 --- a/dts/xtensa/intel/intel_adsp_cavs25_tgph.dtsi +++ b/dts/xtensa/intel/intel_adsp_cavs25_tgph.dtsi @@ -92,6 +92,16 @@ }; soc { + lsbpm: lsbpm@71d50 { + compatible = "intel,adsp-lsbpm"; + reg = <0x71d50 0x10>; + }; + + hsbpm: hsbpm@71d10 { + compatible = "intel,adsp-hsbpm"; + reg = <0x71d10 0x10>; + }; + shim: shim@71f00 { compatible = "intel,adsp-shim"; reg = <0x71f00 0x100>; @@ -242,7 +252,7 @@ }; ssp0: ssp@77000 { - compatible = "intel,ssp-dai"; + compatible = "intel,ssp"; #address-cells = <1>; #size-cells = <0>; reg = <0x00077000 0x200 @@ -252,12 +262,18 @@ dmas = <&lpgpdma0 2 &lpgpdma0 3>; dma-names = "tx", "rx"; - + ssp-index = <0>; status = "okay"; + + ssp00: ssp@0 { + compatible = "intel,ssp-dai"; + reg = <0x0>; + status = "okay"; + }; }; ssp1: ssp@77200 { - compatible = "intel,ssp-dai"; + compatible = "intel,ssp"; #address-cells = <1>; #size-cells = <0>; reg = <0x00077200 0x200 @@ -267,12 +283,18 @@ dmas = <&lpgpdma0 4 &lpgpdma0 5>; dma-names = "tx", "rx"; - + ssp-index = <1>; status = "okay"; + + ssp10: ssp@10 { + compatible = "intel,ssp-dai"; + reg = <0x10>; + status = "okay"; + }; }; ssp2: ssp@77400 { - compatible = "intel,ssp-dai"; + compatible = "intel,ssp"; #address-cells = <1>; #size-cells = <0>; reg = <0x00077400 0x200 @@ -282,53 +304,14 @@ dmas = <&lpgpdma0 6 &lpgpdma0 7>; dma-names = "tx", "rx"; - - status = "okay"; - }; - - ssp3: ssp@77600 { - compatible = "intel,ssp-dai"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x00077600 0x200 - 0x00078C00 0x008>; - interrupts = <0x03 0 0>; - interrupt-parent = <&cavs_intc3>; - dmas = <&lpgpdma0 8 - &lpgpdma0 9>; - dma-names = "tx", "rx"; - + ssp-index = <2>; status = "okay"; - }; - - ssp4: ssp@77800 { - compatible = "intel,ssp-dai"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x00077800 0x200 - 0x00078C00 0x008>; - interrupts = <0x03 0 0>; - interrupt-parent = <&cavs_intc3>; - dmas = <&lpgpdma0 10 - &lpgpdma0 11>; - dma-names = "tx", "rx"; - status = "okay"; - }; - - ssp5: ssp@77a00 { - compatible = "intel,ssp-dai"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x00077A00 0x200 - 0x00078C00 0x008>; - interrupts = <0x03 0 0>; - interrupt-parent = <&cavs_intc3>; - dmas = <&lpgpdma0 12 - &lpgpdma0 13>; - dma-names = "tx", "rx"; - - status = "okay"; + ssp20: ssp@20 { + compatible = "intel,ssp-dai"; + reg = <0x20>; + status = "okay"; + }; }; }; diff --git a/dts/xtensa/nxp/nxp_imx8ulp.dtsi b/dts/xtensa/nxp/nxp_imx8ulp.dtsi index 2b4460aff5a..1dafde51fd1 100644 --- a/dts/xtensa/nxp/nxp_imx8ulp.dtsi +++ b/dts/xtensa/nxp/nxp_imx8ulp.dtsi @@ -18,6 +18,16 @@ compatible = "cdns,tensilica-xtensa-lx7"; reg = <0>; }; + + #address-cells = <1>; + #size-cells = <0>; + + clic: interrupt-controller@0 { + compatible = "cdns,xtensa-core-intc"; + reg = <0>; + interrupt-controller; + #interrupt-cells = <3>; + }; }; sram0: memory@8e000000 { @@ -45,4 +55,47 @@ compatible = "nxp,imx8ulp-pinctrl"; }; }; + + /* note: this was intentionally left without an interrupt + * property because HIFI4 DSP doesn't receive interrupts + * from LPUART7. + */ + lpuart7: serial@29870000 { + compatible = "nxp,kinetis-lpuart"; + reg = <0x29870000 DT_SIZE_K(4)>; + clocks = <&pcc4 IMX8ULP_CLOCK_LPUART7 0x0>; + status = "disabled"; + }; + + edma2: dma@2d800000 { + compatible = "nxp,edma"; + reg = <0x2d800000 (DT_SIZE_K(64) * 32)>; + valid-channels = <0>, <1>, <2>, <3>; + interrupt-parent = <&clic>; + interrupts = <6 0 0>, <7 0 0>, <8 0 0>, <9 0 0>; + #dma-cells = <2>; + status = "disabled"; + }; + + sai5: dai@29890000 { + compatible = "nxp,dai-sai"; + reg = <0x29890000 DT_SIZE_K(4)>; + interrupt-parent = <&clic>; + interrupts = <23 0 0>; + dmas = <&edma2 2 70>, <&edma2 3 69>; + dma-names = "tx", "rx"; + dai-index = <5>; + status = "disabled"; + }; + + sai6: dai@2da90000 { + compatible = "nxp,dai-sai"; + reg = <0x2da90000 DT_SIZE_K(4)>; + interrupt-parent = <&clic>; + interrupts = <24 0 0>; + dmas = <&edma2 0 72>, <&edma2 1 71>; + dma-names = "tx", "rx"; + dai-index = <6>; + status = "disabled"; + }; }; diff --git a/include/zephyr/app_memory/mem_domain.h b/include/zephyr/app_memory/mem_domain.h index ece13e3bdc2..8fe75eb33d9 100644 --- a/include/zephyr/app_memory/mem_domain.h +++ b/include/zephyr/app_memory/mem_domain.h @@ -126,7 +126,7 @@ struct k_mem_partition; * @retval -EINVAL if invalid parameters supplied * @retval -ENOMEM if insufficient memory */ -extern int k_mem_domain_init(struct k_mem_domain *domain, uint8_t num_parts, +int k_mem_domain_init(struct k_mem_domain *domain, uint8_t num_parts, struct k_mem_partition *parts[]); /** @@ -156,7 +156,7 @@ extern int k_mem_domain_init(struct k_mem_domain *domain, uint8_t num_parts, * @retval -EINVAL if invalid parameters supplied * @retval -ENOSPC if no free partition slots available */ -extern int k_mem_domain_add_partition(struct k_mem_domain *domain, +int k_mem_domain_add_partition(struct k_mem_domain *domain, struct k_mem_partition *part); /** @@ -171,7 +171,7 @@ extern int k_mem_domain_add_partition(struct k_mem_domain *domain, * @retval -EINVAL if invalid parameters supplied * @retval -ENOENT if no matching partition found */ -extern int k_mem_domain_remove_partition(struct k_mem_domain *domain, +int k_mem_domain_remove_partition(struct k_mem_domain *domain, struct k_mem_partition *part); /** @@ -185,7 +185,7 @@ extern int k_mem_domain_remove_partition(struct k_mem_domain *domain, * * @return 0 if successful, fails otherwise. */ -extern int k_mem_domain_add_thread(struct k_mem_domain *domain, +int k_mem_domain_add_thread(struct k_mem_domain *domain, k_tid_t thread); #ifdef __cplusplus diff --git a/include/zephyr/arch/arc/v2/arcv2_irq_unit.h b/include/zephyr/arch/arc/v2/arcv2_irq_unit.h index c78de9dd49b..18cb0fa2a47 100644 --- a/include/zephyr/arch/arc/v2/arcv2_irq_unit.h +++ b/include/zephyr/arch/arc/v2/arcv2_irq_unit.h @@ -41,6 +41,8 @@ extern "C" { * @brief Enable/disable interrupt * * Enables or disables the specified interrupt + * @param irq IRQ line number + * @param enable 1 to enable, 0 to disable */ static ALWAYS_INLINE diff --git a/include/zephyr/arch/arc/v2/mpu/arc_core_mpu.h b/include/zephyr/arch/arc/v2/mpu/arc_core_mpu.h index ad36a22eb77..8e3e02a67ce 100644 --- a/include/zephyr/arch/arc/v2/mpu/arc_core_mpu.h +++ b/include/zephyr/arch/arc/v2/mpu/arc_core_mpu.h @@ -88,7 +88,7 @@ void arc_core_mpu_remove_mem_domain(struct k_mem_domain *mem_domain); void arc_core_mpu_remove_mem_partition(struct k_mem_domain *domain, uint32_t partition_id); int arc_core_mpu_get_max_domain_partition_regions(void); -int arc_core_mpu_buffer_validate(void *addr, size_t size, int write); +int arc_core_mpu_buffer_validate(const void *addr, size_t size, int write); #endif diff --git a/include/zephyr/arch/arch_interface.h b/include/zephyr/arch/arch_interface.h index d7ff2f2cad2..04aef815755 100644 --- a/include/zephyr/arch/arch_interface.h +++ b/include/zephyr/arch/arch_interface.h @@ -783,7 +783,7 @@ int arch_mem_domain_partition_add(struct k_mem_domain *domain, * * @return nonzero if the permissions don't match. */ -int arch_buffer_validate(void *addr, size_t size, int write); +int arch_buffer_validate(const void *addr, size_t size, int write); /** * Get the optimal virtual region alignment to optimize the MMU table layout diff --git a/include/zephyr/arch/arm/asm_inline_gcc.h b/include/zephyr/arch/arm/asm_inline_gcc.h index 77729149e36..cb8653999f4 100644 --- a/include/zephyr/arch/arm/asm_inline_gcc.h +++ b/include/zephyr/arch/arm/asm_inline_gcc.h @@ -21,6 +21,7 @@ #include #include #include +#include #if defined(CONFIG_CPU_AARCH32_CORTEX_R) || defined(CONFIG_CPU_AARCH32_CORTEX_A) #include @@ -46,25 +47,15 @@ static ALWAYS_INLINE unsigned int arch_irq_lock(void) #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) - : - : "memory"); + key = __get_PRIMASK(); + __disable_irq(); #else #error "Cortex-M0 and Cortex-M0+ require SoC specific support for cross core synchronisation." #endif #elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) - unsigned int tmp; - - __asm__ volatile( - "mov %1, %2;" - "mrs %0, BASEPRI;" - "msr BASEPRI_MAX, %1;" - "isb;" - : "=r"(key), "=r"(tmp) - : "i"(_EXC_IRQ_DEFAULT_PRIO) - : "memory"); + key = __get_BASEPRI(); + __set_BASEPRI_MAX(_EXC_IRQ_DEFAULT_PRIO); + __ISB(); #elif defined(CONFIG_ARMV7_R) || defined(CONFIG_AARCH32_ARMV8_R) \ || defined(CONFIG_ARMV7_A) __asm__ volatile( @@ -92,23 +83,17 @@ static ALWAYS_INLINE void arch_irq_unlock(unsigned int key) if (key != 0U) { return; } - __asm__ volatile( - "cpsie i;" - "isb" - : : : "memory"); + __enable_irq(); + __ISB(); #elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) - __asm__ volatile( - "msr BASEPRI, %0;" - "isb;" - : : "r"(key) : "memory"); + __set_BASEPRI(key); + __ISB(); #elif defined(CONFIG_ARMV7_R) || defined(CONFIG_AARCH32_ARMV8_R) \ || defined(CONFIG_ARMV7_A) if (key != 0U) { return; } - __asm__ volatile( - "cpsie i;" - : : : "memory", "cc"); + __enable_irq(); #else #error Unknown ARM architecture #endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */ diff --git a/include/zephyr/arch/arm/cortex_m/scripts/linker.ld b/include/zephyr/arch/arm/cortex_m/scripts/linker.ld index 14eb78f3e70..7c766ffecc5 100644 --- a/include/zephyr/arch/arm/cortex_m/scripts/linker.ld +++ b/include/zephyr/arch/arm/cortex_m/scripts/linker.ld @@ -26,6 +26,14 @@ #endif #define RAMABLE_REGION RAM +/* Region of the irq vectors and boot-vector SP/PC */ +#if defined(CONFIG_ROMSTART_RELOCATION_ROM) +#define ROMSTART_ADDR CONFIG_ROMSTART_REGION_ADDRESS +#define ROMSTART_SIZE (CONFIG_ROMSTART_REGION_SIZE * 1K) +#else +#define ROMSTART_REGION ROMABLE_REGION +#endif + #if USE_PARTITION_MANAGER #include @@ -131,6 +139,9 @@ _region_min_align = 4; MEMORY { +#if defined(CONFIG_ROMSTART_RELOCATION_ROM) + ROMSTART_REGION (rx) : ORIGIN = ROMSTART_ADDR, LENGTH = ROMSTART_SIZE +#endif FLASH (rx) : ORIGIN = ROM_ADDR, LENGTH = ROM_SIZE RAM (wx) : ORIGIN = RAM_ADDR, LENGTH = RAM_SIZE #if defined(CONFIG_LINKER_DEVNULL_MEMORY) @@ -175,7 +186,7 @@ SECTIONS */ #include - } GROUP_LINK_IN(ROMABLE_REGION) + } GROUP_LINK_IN(ROMSTART_REGION) #ifdef CONFIG_CODE_DATA_RELOCATION @@ -224,7 +235,7 @@ SECTIONS * section overlap. */ __exidx_start = .; -#if defined (__GCC_LINKER_CMD__) +#if defined (__GCC_LINKER_CMD__) || defined (__LLD_LINKER_CMD__) *(.ARM.exidx* gnu.linkonce.armexidx.*) #endif __exidx_end = .; @@ -515,6 +526,15 @@ GROUP_END(DTCM) KEEP(*(.gnu.attributes)) } +/* Output section descriptions are needed for these sections to suppress + * warnings when "--orphan-handling=warn" is set for lld. + */ +#if defined(CONFIG_LLVM_USE_LLD) + SECTION_PROLOGUE(.symtab, 0,) { *(.symtab) } + SECTION_PROLOGUE(.strtab, 0,) { *(.strtab) } + SECTION_PROLOGUE(.shstrtab, 0,) { *(.shstrtab) } +#endif + /* Sections generated from 'zephyr,memory-region' nodes */ LINKER_DT_SECTIONS() diff --git a/include/zephyr/arch/arm/error.h b/include/zephyr/arch/arm/error.h index a30c674c4ff..2a158959b80 100644 --- a/include/zephyr/arch/arm/error.h +++ b/include/zephyr/arch/arm/error.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2013-2014 Wind River Systems, Inc. + * Copyright (c) 2023 Arm Limited * * SPDX-License-Identifier: Apache-2.0 */ @@ -23,7 +24,7 @@ extern "C" { #endif -#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) +#if defined(CONFIG_CPU_CORTEX_M) /* ARMv6 will hard-fault if SVC is called with interrupts locked. Just * force them unlocked, the thread is in an undefined state anyway * @@ -33,25 +34,13 @@ extern "C" { * Force them unlocked as well. */ #define ARCH_EXCEPT(reason_p) \ -register uint32_t r0 __asm__("r0") = reason_p; \ -do { \ - __asm__ volatile ( \ - "cpsie i\n\t" \ - "svc %[id]\n\t" \ - : \ - : "r" (r0), [id] "i" (_SVC_CALL_RUNTIME_EXCEPT) \ - : "memory"); \ -} while (false) -#elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) -#define ARCH_EXCEPT(reason_p) do { \ - __asm__ volatile ( \ - "eors.n r0, r0\n\t" \ - "msr BASEPRI, r0\n\t" \ - "mov r0, %[reason]\n\t" \ - "svc %[id]\n\t" \ - : \ - : [reason] "i" (reason_p), [id] "i" (_SVC_CALL_RUNTIME_EXCEPT) \ - : "memory"); \ +do {\ + arch_irq_unlock(0); \ + __asm__ volatile( \ + "mov r0, %[_reason]\n" \ + "svc %[id]\n" \ + :: [_reason] "r" (reason_p), [id] "i" (_SVC_CALL_RUNTIME_EXCEPT) \ + : "r0", "memory"); \ } while (false) #elif defined(CONFIG_ARMV7_R) || defined(CONFIG_AARCH32_ARMV8_R) \ || defined(CONFIG_ARMV7_A) diff --git a/include/zephyr/arch/arm/irq.h b/include/zephyr/arch/arm/irq.h index 31cfce1e667..34bf2dd8fde 100644 --- a/include/zephyr/arch/arm/irq.h +++ b/include/zephyr/arch/arm/irq.h @@ -166,10 +166,24 @@ static inline void arch_isr_direct_footer(int maybe_swap) } } +#if defined(__clang__) +#define ARCH_ISR_DIAG_OFF \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wextra\"") +#define ARCH_ISR_DIAG_ON _Pragma("clang diagnostic pop") +#elif defined(__GNUC__) +#define ARCH_ISR_DIAG_OFF \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wattributes\"") +#define ARCH_ISR_DIAG_ON _Pragma("GCC diagnostic pop") +#else +#define ARCH_ISR_DIAG_OFF +#define ARCH_ISR_DIAG_ON +#endif + #define ARCH_ISR_DIRECT_DECLARE(name) \ static inline int name##_body(void); \ - _Pragma("GCC diagnostic push") \ - _Pragma("GCC diagnostic ignored \"-Wattributes\"") \ + ARCH_ISR_DIAG_OFF \ __attribute__ ((interrupt ("IRQ"))) void name(void) \ { \ int check_reschedule; \ @@ -177,7 +191,7 @@ static inline void arch_isr_direct_footer(int maybe_swap) check_reschedule = name##_body(); \ ISR_DIRECT_FOOTER(check_reschedule); \ } \ - _Pragma("GCC diagnostic pop") \ + ARCH_ISR_DIAG_ON \ static inline int name##_body(void) #if defined(CONFIG_DYNAMIC_DIRECT_INTERRUPTS) diff --git a/include/zephyr/arch/arm64/lib_helpers.h b/include/zephyr/arch/arm64/lib_helpers.h index 56dfa1f9365..0f3d9d563ab 100644 --- a/include/zephyr/arch/arm64/lib_helpers.h +++ b/include/zephyr/arch/arm64/lib_helpers.h @@ -70,8 +70,10 @@ MAKE_REG_HELPER(hcr_el2); MAKE_REG_HELPER(id_aa64pfr0_el1); MAKE_REG_HELPER(id_aa64mmfr0_el1); MAKE_REG_HELPER(mpidr_el1); -MAKE_REG_HELPER(par_el1) +MAKE_REG_HELPER(par_el1); +#if !defined(CONFIG_ARMV8_R) MAKE_REG_HELPER(scr_el3); +#endif /* CONFIG_ARMV8_R */ MAKE_REG_HELPER(tpidrro_el0); MAKE_REG_HELPER(vmpidr_el2); MAKE_REG_HELPER(sp_el0); diff --git a/include/zephyr/arch/common/pm_s2ram.h b/include/zephyr/arch/common/pm_s2ram.h index 16443f2d105..451794a53a2 100644 --- a/include/zephyr/arch/common/pm_s2ram.h +++ b/include/zephyr/arch/common/pm_s2ram.h @@ -7,7 +7,6 @@ * * @brief public S2RAM APIs. * @defgroup pm_s2ram S2RAM APIs - * @ingroup subsys_pm * @{ */ @@ -57,6 +56,30 @@ typedef int (*pm_s2ram_system_off_fn_t)(void); */ int arch_pm_s2ram_suspend(pm_s2ram_system_off_fn_t system_off); +/** + * @brief Mark that core is entering suspend-to-RAM state. + * + * Function is called when system state is stored to RAM, just before going to system + * off. + * + * Default implementation is setting a magic word in RAM. CONFIG_PM_S2RAM_CUSTOM_MARKING + * allows custom implementation. + */ +void pm_s2ram_mark_set(void); + +/** + * @brief Check suspend-to-RAM marking and clear its state. + * + * Function is used to determine if resuming after suspend-to-RAM shall be performed + * or standard boot code shall be executed. + * + * Default implementation is checking a magic word in RAM. CONFIG_PM_S2RAM_CUSTOM_MARKING + * allows custom implementation. + * + * @retval true if marking is found which indicates resuming after suspend-to-RAM. + * @retval false if marking is not found which indicates standard boot. + */ +bool pm_s2ram_mark_check_and_clear(void); /** * @} */ diff --git a/include/zephyr/arch/x86/arch.h b/include/zephyr/arch/x86/arch.h index f7e75b3aab6..61036288671 100644 --- a/include/zephyr/arch/x86/arch.h +++ b/include/zephyr/arch/x86/arch.h @@ -219,7 +219,7 @@ static ALWAYS_INLINE int sys_test_and_clear_bit(mem_addr_t addr, extern unsigned char _irq_to_interrupt_vector[]; #define Z_IRQ_TO_INTERRUPT_VECTOR(irq) \ - ((unsigned int) _irq_to_interrupt_vector[irq]) + ((unsigned int) _irq_to_interrupt_vector[(irq)]) #endif /* _ASMLANGUAGE */ @@ -244,10 +244,10 @@ extern "C" { #ifndef _ASMLANGUAGE -extern void arch_irq_enable(unsigned int irq); -extern void arch_irq_disable(unsigned int irq); +void arch_irq_enable(unsigned int irq); +void arch_irq_disable(unsigned int irq); -extern uint32_t sys_clock_cycle_get_32(void); +uint32_t sys_clock_cycle_get_32(void); __pinned_func static inline uint32_t arch_k_cycle_get_32(void) @@ -255,7 +255,7 @@ 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); +uint64_t sys_clock_cycle_get_64(void); __pinned_func static inline uint64_t arch_k_cycle_get_64(void) diff --git a/include/zephyr/arch/x86/ia32/arch.h b/include/zephyr/arch/x86/ia32/arch.h index 8e85ccaea11..e39e6c0cd65 100644 --- a/include/zephyr/arch/x86/ia32/arch.h +++ b/include/zephyr/arch/x86/ia32/arch.h @@ -266,8 +266,8 @@ static inline void arch_irq_direct_pm(void) * tracing/tracing.h cannot be included here due to circular dependency */ #if defined(CONFIG_TRACING) -extern void sys_trace_isr_enter(void); -extern void sys_trace_isr_exit(void); +void sys_trace_isr_enter(void); +void sys_trace_isr_exit(void); #endif static inline void arch_isr_direct_header(void) @@ -287,7 +287,7 @@ static inline void arch_isr_direct_header(void) * cannot be referenced from a public header, so we move it to an * external function. */ -extern void arch_isr_direct_footer_swap(unsigned int key); +void arch_isr_direct_footer_swap(unsigned int key); static inline void arch_isr_direct_footer(int swap) { diff --git a/include/zephyr/arch/x86/ia32/linker.ld b/include/zephyr/arch/x86/ia32/linker.ld index a0e2f5c6732..0d1e67147c4 100644 --- a/include/zephyr/arch/x86/ia32/linker.ld +++ b/include/zephyr/arch/x86/ia32/linker.ld @@ -417,43 +417,10 @@ SECTIONS _app_smem_num_words = _app_smem_size >> 2; #endif /* CONFIG_USERSPACE */ - SECTION_PROLOGUE(_BSS_SECTION_NAME, (NOLOAD),) - { - MMU_PAGE_ALIGN_PERM -#if !defined(CONFIG_USERSPACE) - _image_ram_start = .; -#endif - /* - * For performance, BSS section is forced to be both 4 byte aligned and - * a multiple of 4 bytes. - */ - . = ALIGN(4); - __kernel_ram_start = .; - __bss_start = .; - - *(.bss) - *(".bss.*") - *(COMMON) - *(".kernel_bss.*") - - /* - * 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. - */ - . = ALIGN(4); - __bss_end = .; - } GROUP_NOLOAD_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) - - __bss_num_words = (__bss_end - __bss_start) >> 2; - -#include - - MMU_PAGE_ALIGN_PERM - - SECTION_DATA_PROLOGUE(_DATA_SECTION_NAME,,) { + MMU_PAGE_ALIGN_PERM __data_region_start = .; __data_start = .; @@ -503,6 +470,39 @@ SECTIONS MMU_PAGE_ALIGN __data_region_end = .; + SECTION_PROLOGUE(_BSS_SECTION_NAME, (NOLOAD),) + { + MMU_PAGE_ALIGN_PERM +#if !defined(CONFIG_USERSPACE) + _image_ram_start = .; +#endif + /* + * For performance, BSS section is forced to be both 4 byte aligned and + * a multiple of 4 bytes. + */ + . = ALIGN(4); + __kernel_ram_start = .; + __bss_start = .; + + *(.bss) + *(".bss.*") + *(COMMON) + *(".kernel_bss.*") + + /* + * 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. + */ + . = ALIGN(4); + __bss_end = .; + } GROUP_NOLOAD_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) + + __bss_num_words = (__bss_end - __bss_start) >> 2; + +#include + + MMU_PAGE_ALIGN_PERM + /* All unused memory also owned by the kernel for heaps */ __kernel_ram_end = KERNEL_BASE_ADDR + KERNEL_RAM_SIZE; __kernel_ram_size = __kernel_ram_end - __kernel_ram_start; diff --git a/include/zephyr/arch/x86/multiboot.h b/include/zephyr/arch/x86/multiboot.h index 9a951a0150f..66c312e48e2 100644 --- a/include/zephyr/arch/x86/multiboot.h +++ b/include/zephyr/arch/x86/multiboot.h @@ -40,7 +40,7 @@ extern struct multiboot_info multiboot_info; #ifdef CONFIG_MULTIBOOT_INFO -extern void z_multiboot_init(struct multiboot_info *info_pa); +void z_multiboot_init(struct multiboot_info *info_pa); #else diff --git a/include/zephyr/arch/xtensa/arch.h b/include/zephyr/arch/xtensa/arch.h index 0b29df511b7..b5638870b4a 100644 --- a/include/zephyr/arch/xtensa/arch.h +++ b/include/zephyr/arch/xtensa/arch.h @@ -79,7 +79,7 @@ struct arch_mem_domain { * * @param reason_p Reason for exception. */ -extern void xtensa_arch_except(int reason_p); +void xtensa_arch_except(int reason_p); /** * @brief Generate kernel oops. @@ -89,7 +89,7 @@ extern void xtensa_arch_except(int reason_p); * @param reason_p Reason for exception. * @param ssf Stack pointer. */ -extern void xtensa_arch_kernel_oops(int reason_p, void *ssf); +void xtensa_arch_kernel_oops(int reason_p, void *ssf); #ifdef CONFIG_USERSPACE @@ -117,7 +117,7 @@ __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); +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) \ { \ @@ -237,7 +237,7 @@ static inline bool arch_mem_coherent(void *ptr) * @param is_core0 True if this is called while executing on * CPU core #0. */ -extern void arch_xtensa_mmu_post_init(bool is_core0); +void arch_xtensa_mmu_post_init(bool is_core0); #endif #ifdef __cplusplus diff --git a/include/zephyr/arch/xtensa/irq.h b/include/zephyr/arch/xtensa/irq.h index 938ab7b2303..3df8639ac73 100644 --- a/include/zephyr/arch/xtensa/irq.h +++ b/include/zephyr/arch/xtensa/irq.h @@ -160,7 +160,7 @@ static ALWAYS_INLINE bool arch_irq_unlocked(unsigned int key) * * @return True if interrupt is enabled, false otherwise. */ -extern int xtensa_irq_is_enabled(unsigned int irq); +int xtensa_irq_is_enabled(unsigned int irq); #include diff --git a/include/zephyr/bluetooth/addr.h b/include/zephyr/bluetooth/addr.h index 3afb5f4a903..794e2acbaf6 100644 --- a/include/zephyr/bluetooth/addr.h +++ b/include/zephyr/bluetooth/addr.h @@ -108,8 +108,8 @@ static inline int bt_addr_le_cmp(const bt_addr_le_t *a, const bt_addr_le_t *b) /** @brief Determine equality of two Bluetooth LE device addresses. * - * The Bluetooth LE addresses are equal iff both the types and the 48-bit - * addresses are numerically equal. + * The Bluetooth LE addresses are equal if and only if both the types and + * the 48-bit addresses are numerically equal. * * @retval #true if the two addresses are equal * @retval #false otherwise diff --git a/include/zephyr/bluetooth/audio/aics.h b/include/zephyr/bluetooth/audio/aics.h index dbaf7383e65..55f2eab2f93 100644 --- a/include/zephyr/bluetooth/audio/aics.h +++ b/include/zephyr/bluetooth/audio/aics.h @@ -12,6 +12,9 @@ * * @defgroup bt_gatt_aics Audio Input Control Service (AICS) * + * @since 2.6 + * @version 0.8.0 + * * @ingroup bluetooth * @{ * @@ -23,7 +26,6 @@ * automatically handle any changes to that. If out of date, the client implementation will * autonomously read the change counter value when executing a write request. * - * [Experimental] Users should note that the APIs can change as a part of ongoing development. */ #include diff --git a/include/zephyr/bluetooth/audio/bap.h b/include/zephyr/bluetooth/audio/bap.h index 08a2a642eb0..cc961412131 100644 --- a/include/zephyr/bluetooth/audio/bap.h +++ b/include/zephyr/bluetooth/audio/bap.h @@ -2101,11 +2101,9 @@ struct bt_bap_broadcast_assistant_cb { * @brief Callback function for when a receive state is removed. * * @param conn The connection to the Broadcast Audio Scan Service server. - * @param err Error value. 0 on success, GATT error on fail. * @param src_id The receive state. */ - void (*recv_state_removed)(struct bt_conn *conn, int err, - uint8_t src_id); + void (*recv_state_removed)(struct bt_conn *conn, uint8_t src_id); /** * @brief Callback function for bt_bap_broadcast_assistant_scan_start(). diff --git a/include/zephyr/bluetooth/audio/cap.h b/include/zephyr/bluetooth/audio/cap.h index 8119c0e2e9e..6bf5e1b018e 100644 --- a/include/zephyr/bluetooth/audio/cap.h +++ b/include/zephyr/bluetooth/audio/cap.h @@ -12,11 +12,11 @@ * * @defgroup bt_cap Common Audio Profile (CAP) * + * @since 3.2 + * @version 0.8.0 + * * @ingroup bluetooth * @{ - * - * [Experimental] Users should note that the APIs can change - * as a part of ongoing development. */ #include @@ -63,14 +63,16 @@ struct bt_cap_initiator_cb { * @param conn The connection pointer supplied to * bt_cap_initiator_unicast_discover(). * @param err 0 if Common Audio Service was found else -ENODATA. + * @param member Pointer to the set member. NULL if err != 0. * @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. + * Coordinated Set Identification Service. NULL if err != 0. */ void (*unicast_discovery_complete)( struct bt_conn *conn, int err, + const struct bt_csip_set_coordinator_set_member *member, const struct bt_csip_set_coordinator_csis_inst *csis_inst); /** @@ -676,13 +678,15 @@ struct bt_cap_commander_cb { * @param conn The connection pointer supplied to * bt_cap_initiator_unicast_discover(). * @param err 0 if Common Audio Service was found else -ENODATA. + * @param member Pointer to the set member. NULL if err != 0. * @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. + * Coordinated Set Identification Service. NULL if err != 0. */ void (*discovery_complete)(struct bt_conn *conn, int err, + const struct bt_csip_set_coordinator_set_member *member, const struct bt_csip_set_coordinator_csis_inst *csis_inst); #if defined(CONFIG_BT_VCP_VOL_CTLR) @@ -750,6 +754,20 @@ struct bt_cap_commander_cb { void (*microphone_gain_changed)(struct bt_conn *conn, int err); #endif /* CONFIG_BT_MICP_MIC_CTLR_AICS */ #endif /* CONFIG_BT_MICP_MIC_CTLR */ + +#if defined(CONFIG_BT_BAP_BROADCAST_ASSISTANT) + /** + * @brief Callback for bt_cap_commander_broadcast_reception_start(). + * + * @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 (*broadcast_reception_start)(struct bt_conn *conn, int err); +#endif /* CONFIG_BT_BAP_BROADCAST_ASSISTANT */ }; /** @@ -842,7 +860,7 @@ struct bt_cap_commander_broadcast_reception_start_member_param { * * At least one bit in one of the subgroups bis_sync parameters shall be set. */ - struct bt_bap_bass_subgroup *subgroups; + struct bt_bap_bass_subgroup subgroups[CONFIG_BT_BAP_BASS_MAX_SUBGROUPS]; /** Number of subgroups */ size_t num_subgroups; diff --git a/include/zephyr/bluetooth/audio/csip.h b/include/zephyr/bluetooth/audio/csip.h index a302a698867..1981a23458f 100644 --- a/include/zephyr/bluetooth/audio/csip.h +++ b/include/zephyr/bluetooth/audio/csip.h @@ -12,10 +12,11 @@ * * @defgroup bt_gatt_csip Coordinated Set Identification Profile (CSIP) * + * @since 3.0 + * @version 0.8.0 + * * @ingroup bluetooth * @{ - * * - * [Experimental] Users should note that the APIs can change as a part of ongoing development. */ #include diff --git a/include/zephyr/bluetooth/audio/has.h b/include/zephyr/bluetooth/audio/has.h index 46be03e72ef..0e5c1652902 100644 --- a/include/zephyr/bluetooth/audio/has.h +++ b/include/zephyr/bluetooth/audio/has.h @@ -12,14 +12,14 @@ * * @defgroup bt_has Hearing Access Service (HAS) * + * @since 3.1 + * @version 0.8.0 + * * @ingroup bluetooth * @{ * * The Hearing Access Service is used to identify a hearing aid and optionally * to control hearing aid presets. - * - * [Experimental] Users should note that the APIs can change as a part of - * ongoing development. */ #include diff --git a/include/zephyr/bluetooth/audio/mcc.h b/include/zephyr/bluetooth/audio/mcc.h index f67eb768318..14dba829225 100644 --- a/include/zephyr/bluetooth/audio/mcc.h +++ b/include/zephyr/bluetooth/audio/mcc.h @@ -5,11 +5,11 @@ * * @defgroup bt_gatt_mcc Media Control Client (MCC) * + * @since 3.0 + * @version 0.8.0 + * * @ingroup bluetooth * @{ - * - * [Experimental] Users should note that the APIs can change - * as a part of ongoing development. */ /* diff --git a/include/zephyr/bluetooth/audio/mcs.h b/include/zephyr/bluetooth/audio/mcs.h index b234131281e..7d9491944ef 100644 --- a/include/zephyr/bluetooth/audio/mcs.h +++ b/include/zephyr/bluetooth/audio/mcs.h @@ -12,12 +12,12 @@ * * @defgroup bt_mcs Media Control Service (MCS) * + * @since 3.0 + * @version 0.8.0 + * * @ingroup bluetooth * @{ * - * [Experimental] Users should note that the APIs can change - * as a part of ongoing development. - * * Definitions and types related to the Media Control Service and Media Control * Profile specifications. */ diff --git a/include/zephyr/bluetooth/audio/media_proxy.h b/include/zephyr/bluetooth/audio/media_proxy.h index 34e3e7126f6..0e236a1fd4a 100644 --- a/include/zephyr/bluetooth/audio/media_proxy.h +++ b/include/zephyr/bluetooth/audio/media_proxy.h @@ -11,6 +11,9 @@ * * @defgroup bt_media_proxy Media Proxy * + * @since 3.0 + * @version 0.8.0 + * * @ingroup bluetooth * @{ * @@ -31,9 +34,6 @@ * application, or it may be a Media Control Service relaying requests * from a remote Media Control Client. There may be either local or * remote control, or both, or even multiple instances of each. - * - * [Experimental] Users should note that the APIs can change - * as a part of ongoing development. */ #include diff --git a/include/zephyr/bluetooth/audio/micp.h b/include/zephyr/bluetooth/audio/micp.h index 27359ca7ffa..500eb204839 100644 --- a/include/zephyr/bluetooth/audio/micp.h +++ b/include/zephyr/bluetooth/audio/micp.h @@ -12,11 +12,11 @@ * * @defgroup bt_gatt_micp Microphone Control Profile (MICP) * + * @since 2.7 + * @version 0.8.0 + * * @ingroup bluetooth * @{ - * - * [Experimental] Users should note that the APIs can change - * as a part of ongoing development. */ #include diff --git a/include/zephyr/bluetooth/audio/pbp.h b/include/zephyr/bluetooth/audio/pbp.h index acc53adb5ad..71d7d107b4e 100644 --- a/include/zephyr/bluetooth/audio/pbp.h +++ b/include/zephyr/bluetooth/audio/pbp.h @@ -12,11 +12,11 @@ * * @defgroup bt_pbp Public Broadcast Profile (PBP) * + * @since 3.5 + * @version 0.8.0 + * * @ingroup bluetooth * @{ - * - * [Experimental] Users should note that the APIs can change - * as a part of ongoing development. */ #include diff --git a/include/zephyr/bluetooth/audio/vcp.h b/include/zephyr/bluetooth/audio/vcp.h index 15d91fae330..1128bf18d1e 100644 --- a/include/zephyr/bluetooth/audio/vcp.h +++ b/include/zephyr/bluetooth/audio/vcp.h @@ -12,11 +12,11 @@ * * @defgroup bt_gatt_vcp Volume Control Profile (VCP) * + * @since 2.7 + * @version 0.8.0 + * * @ingroup bluetooth * @{ - * - * [Experimental] Users should note that the APIs can change - * as a part of ongoing development. */ #include diff --git a/include/zephyr/bluetooth/audio/vocs.h b/include/zephyr/bluetooth/audio/vocs.h index d34e6bcd16e..8b6a51d8d64 100644 --- a/include/zephyr/bluetooth/audio/vocs.h +++ b/include/zephyr/bluetooth/audio/vocs.h @@ -12,6 +12,9 @@ * * @defgroup bt_gatt_vocs Volume Offset Control Service (VOCS) * + * @since 2.6 + * @version 0.8.0 + * * @ingroup bluetooth * @{ * @@ -22,8 +25,6 @@ * Note that the API abstracts away the change counter in the volume offset control state and will * automatically handle any changes to that. If out of date, the client implementation will * autonomously read the change counter value when executing a write request. - * - * [Experimental] Users should note that the APIs can change as a part of ongoing development. */ #include diff --git a/include/zephyr/bluetooth/bluetooth.h b/include/zephyr/bluetooth/bluetooth.h index e9be94518ca..59689974b87 100644 --- a/include/zephyr/bluetooth/bluetooth.h +++ b/include/zephyr/bluetooth/bluetooth.h @@ -549,25 +549,29 @@ enum { */ BT_LE_ADV_OPT_USE_IDENTITY = BIT(2), - /** Advertise using GAP device name. - * - * Include the GAP device name automatically when advertising. - * By default the GAP device name is put at the end of the scan - * response data. - * When advertising using @ref BT_LE_ADV_OPT_EXT_ADV and not - * @ref BT_LE_ADV_OPT_SCANNABLE then it will be put at the end of the - * advertising data. - * If the GAP device name does not fit into advertising data it will be - * converted to a shortened name if possible. - * @ref BT_LE_ADV_OPT_FORCE_NAME_IN_AD can be used to force the device - * name to appear in the advertising data of an advert with scan - * response data. - * - * The application can set the device name itself by including the - * following in the advertising data. - * @code - * BT_DATA(BT_DATA_NAME_COMPLETE, name, sizeof(name) - 1) - * @endcode + /** + * @deprecated This option will be removed in the near future, see + * https://github.com/zephyrproject-rtos/zephyr/issues/71686 + * + * @brief Advertise using GAP device name. + * + * Include the GAP device name automatically when advertising. + * By default the GAP device name is put at the end of the scan + * response data. + * When advertising using @ref BT_LE_ADV_OPT_EXT_ADV and not + * @ref BT_LE_ADV_OPT_SCANNABLE then it will be put at the end of the + * advertising data. + * If the GAP device name does not fit into advertising data it will be + * converted to a shortened name if possible. + * @ref BT_LE_ADV_OPT_FORCE_NAME_IN_AD can be used to force the device + * name to appear in the advertising data of an advert with scan + * response data. + * + * The application can set the device name itself by including the + * following in the advertising data. + * @code + * BT_DATA(BT_DATA_NAME_COMPLETE, name, sizeof(name) - 1) + * @endcode */ BT_LE_ADV_OPT_USE_NAME = BIT(3), @@ -691,10 +695,13 @@ enum { BT_LE_ADV_OPT_DISABLE_CHAN_39 = BIT(17), /** + * @deprecated This option will be removed in the near future, see + * https://github.com/zephyrproject-rtos/zephyr/issues/71686 + * * @brief Put GAP device name into advert data * - * Will place the GAP device name into the advertising data rather - * than the scan response data. + * Will place the GAP device name into the advertising data rather than + * the scan response data. * * @note Requires @ref BT_LE_ADV_OPT_USE_NAME */ @@ -905,16 +912,32 @@ struct bt_le_per_adv_param { BT_GAP_ADV_FAST_INT_MIN_2, \ BT_GAP_ADV_FAST_INT_MAX_2, NULL) +/** This is the recommended default for connectable advertisers. + */ +#define BT_LE_ADV_CONN_ONE_TIME \ + BT_LE_ADV_PARAM(BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_ONE_TIME, \ + BT_GAP_ADV_FAST_INT_MIN_2, BT_GAP_ADV_FAST_INT_MAX_2, NULL) + +/** + * @deprecated This macro will be removed in the near future, see + * https://github.com/zephyrproject-rtos/zephyr/issues/71686 + */ #define BT_LE_ADV_CONN_NAME BT_LE_ADV_PARAM(BT_LE_ADV_OPT_CONNECTABLE | \ BT_LE_ADV_OPT_USE_NAME, \ BT_GAP_ADV_FAST_INT_MIN_2, \ - BT_GAP_ADV_FAST_INT_MAX_2, NULL) + BT_GAP_ADV_FAST_INT_MAX_2, NULL) \ + __DEPRECATED_MACRO +/** + * @deprecated This macro will be removed in the near future, see + * https://github.com/zephyrproject-rtos/zephyr/issues/71686 + */ #define BT_LE_ADV_CONN_NAME_AD BT_LE_ADV_PARAM(BT_LE_ADV_OPT_CONNECTABLE | \ BT_LE_ADV_OPT_USE_NAME | \ BT_LE_ADV_OPT_FORCE_NAME_IN_AD, \ BT_GAP_ADV_FAST_INT_MIN_2, \ - BT_GAP_ADV_FAST_INT_MAX_2, NULL) + BT_GAP_ADV_FAST_INT_MAX_2, NULL) \ + __DEPRECATED_MACRO #define BT_LE_ADV_CONN_DIR_LOW_DUTY(_peer) \ BT_LE_ADV_PARAM(BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_ONE_TIME | \ @@ -926,10 +949,16 @@ struct bt_le_per_adv_param { #define BT_LE_ADV_NCONN BT_LE_ADV_PARAM(0, BT_GAP_ADV_FAST_INT_MIN_2, \ BT_GAP_ADV_FAST_INT_MAX_2, NULL) -/** Non-connectable advertising with @ref BT_LE_ADV_OPT_USE_NAME */ +/** + * @deprecated This macro will be removed in the near future, see + * https://github.com/zephyrproject-rtos/zephyr/issues/71686 + * + * Non-connectable advertising with @ref BT_LE_ADV_OPT_USE_NAME + */ #define BT_LE_ADV_NCONN_NAME BT_LE_ADV_PARAM(BT_LE_ADV_OPT_USE_NAME, \ BT_GAP_ADV_FAST_INT_MIN_2, \ - BT_GAP_ADV_FAST_INT_MAX_2, NULL) + BT_GAP_ADV_FAST_INT_MAX_2, NULL) \ + __DEPRECATED_MACRO /** Non-connectable advertising with @ref BT_LE_ADV_OPT_USE_IDENTITY */ #define BT_LE_ADV_NCONN_IDENTITY BT_LE_ADV_PARAM(BT_LE_ADV_OPT_USE_IDENTITY, \ @@ -937,33 +966,65 @@ struct bt_le_per_adv_param { BT_GAP_ADV_FAST_INT_MAX_2, \ NULL) -/** Connectable extended advertising with @ref BT_LE_ADV_OPT_USE_NAME */ +/** Connectable extended advertising */ +#define BT_LE_EXT_ADV_CONN BT_LE_ADV_PARAM(BT_LE_ADV_OPT_EXT_ADV | \ + BT_LE_ADV_OPT_CONNECTABLE, \ + BT_GAP_ADV_FAST_INT_MIN_2, \ + BT_GAP_ADV_FAST_INT_MAX_2, \ + NULL) + +/** + * @deprecated This macro will be removed in the near future, see + * https://github.com/zephyrproject-rtos/zephyr/issues/71686 + * + * Connectable extended advertising with @ref BT_LE_ADV_OPT_USE_NAME + */ #define BT_LE_EXT_ADV_CONN_NAME BT_LE_ADV_PARAM(BT_LE_ADV_OPT_EXT_ADV | \ BT_LE_ADV_OPT_CONNECTABLE | \ BT_LE_ADV_OPT_USE_NAME, \ BT_GAP_ADV_FAST_INT_MIN_2, \ BT_GAP_ADV_FAST_INT_MAX_2, \ - NULL) + NULL) \ + __DEPRECATED_MACRO -/** Scannable extended advertising with @ref BT_LE_ADV_OPT_USE_NAME */ +/** Scannable extended advertising */ +#define BT_LE_EXT_ADV_SCAN BT_LE_ADV_PARAM(BT_LE_ADV_OPT_EXT_ADV | \ + BT_LE_ADV_OPT_SCANNABLE, \ + BT_GAP_ADV_FAST_INT_MIN_2, \ + BT_GAP_ADV_FAST_INT_MAX_2, \ + NULL) + +/** + * @deprecated This macro will be removed in the near future, see + * https://github.com/zephyrproject-rtos/zephyr/issues/71686 + * + * Scannable extended advertising with @ref BT_LE_ADV_OPT_USE_NAME + */ #define BT_LE_EXT_ADV_SCAN_NAME BT_LE_ADV_PARAM(BT_LE_ADV_OPT_EXT_ADV | \ BT_LE_ADV_OPT_SCANNABLE | \ BT_LE_ADV_OPT_USE_NAME, \ BT_GAP_ADV_FAST_INT_MIN_2, \ BT_GAP_ADV_FAST_INT_MAX_2, \ - NULL) + NULL) \ + __DEPRECATED_MACRO /** Non-connectable extended advertising with private address */ #define BT_LE_EXT_ADV_NCONN BT_LE_ADV_PARAM(BT_LE_ADV_OPT_EXT_ADV, \ BT_GAP_ADV_FAST_INT_MIN_2, \ BT_GAP_ADV_FAST_INT_MAX_2, NULL) -/** Non-connectable extended advertising with @ref BT_LE_ADV_OPT_USE_NAME */ +/** + * @deprecated This macro will be removed in the near future, see + * https://github.com/zephyrproject-rtos/zephyr/issues/71686 + * + * Non-connectable extended advertising with @ref BT_LE_ADV_OPT_USE_NAME + */ #define BT_LE_EXT_ADV_NCONN_NAME BT_LE_ADV_PARAM(BT_LE_ADV_OPT_EXT_ADV | \ BT_LE_ADV_OPT_USE_NAME, \ BT_GAP_ADV_FAST_INT_MIN_2, \ BT_GAP_ADV_FAST_INT_MAX_2, \ - NULL) + NULL) \ + __DEPRECATED_MACRO /** Non-connectable extended advertising with @ref BT_LE_ADV_OPT_USE_IDENTITY */ #define BT_LE_EXT_ADV_NCONN_IDENTITY \ @@ -979,14 +1040,19 @@ struct bt_le_per_adv_param { BT_GAP_ADV_FAST_INT_MAX_2, \ NULL) -/** Non-connectable extended advertising on coded PHY with - * @ref BT_LE_ADV_OPT_USE_NAME +/** + * @deprecated This macro will be removed in the near future, see + * https://github.com/zephyrproject-rtos/zephyr/issues/71686 + * + * Non-connectable extended advertising on coded PHY with + * @ref BT_LE_ADV_OPT_USE_NAME */ #define BT_LE_EXT_ADV_CODED_NCONN_NAME \ BT_LE_ADV_PARAM(BT_LE_ADV_OPT_EXT_ADV | BT_LE_ADV_OPT_CODED | \ BT_LE_ADV_OPT_USE_NAME, \ BT_GAP_ADV_FAST_INT_MIN_2, \ - BT_GAP_ADV_FAST_INT_MAX_2, NULL) + BT_GAP_ADV_FAST_INT_MAX_2, NULL) \ + __DEPRECATED_MACRO /** Non-connectable extended advertising on coded PHY with * @ref BT_LE_ADV_OPT_USE_IDENTITY @@ -1470,7 +1536,7 @@ struct bt_le_per_adv_sync_recv_info { /** The value of the event counter where the subevent indication was received. */ uint16_t periodic_event_counter; - /** The subevent where the subevend indication was received. */ + /** The subevent where the subevent indication was received. */ uint8_t subevent; #endif /* CONFIG_BT_PER_ADV_SYNC_RSP */ }; @@ -2058,7 +2124,7 @@ struct bt_le_scan_recv_info { uint16_t adv_props; /** - * @brief Periodic advertising interval. + * @brief Periodic advertising interval (N * 1.25 ms). * * If 0 there is no periodic advertising. */ diff --git a/include/zephyr/bluetooth/buf.h b/include/zephyr/bluetooth/buf.h index 6415b987257..b373ab5bd91 100644 --- a/include/zephyr/bluetooth/buf.h +++ b/include/zephyr/bluetooth/buf.h @@ -51,11 +51,8 @@ struct bt_buf_data { uint8_t type; }; -#if defined(CONFIG_BT_HCI_RAW) -#define BT_BUF_RESERVE MAX(CONFIG_BT_HCI_RESERVE, CONFIG_BT_HCI_RAW_RESERVE) -#else -#define BT_BUF_RESERVE CONFIG_BT_HCI_RESERVE -#endif +/* Headroom reserved in buffers, primarily for HCI transport encoding purposes */ +#define BT_BUF_RESERVE 1 /** Helper to include reserved HCI data in buffer calculations */ #define BT_BUF_SIZE(size) (BT_BUF_RESERVE + (size)) @@ -71,7 +68,7 @@ struct bt_buf_data { /** Helper to calculate needed buffer size for HCI ISO packets. */ #define BT_BUF_ISO_SIZE(size) BT_BUF_SIZE(BT_HCI_ISO_HDR_SIZE + \ - BT_HCI_ISO_TS_DATA_HDR_SIZE + \ + BT_HCI_ISO_SDU_TS_HDR_SIZE + \ (size)) /** Data size needed for HCI ACL RX buffers */ diff --git a/include/zephyr/bluetooth/classic/hfp_ag.h b/include/zephyr/bluetooth/classic/hfp_ag.h new file mode 100644 index 00000000000..6e5173d9fa4 --- /dev/null +++ b/include/zephyr/bluetooth/classic/hfp_ag.h @@ -0,0 +1,298 @@ +/** @file + * @brief Handsfree Profile Audio Gateway handling. + */ + +/* + * Copyright (c) 2015-2016 Intel Corporation + * Copyright 2023-2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_HFP_AG_H_ +#define ZEPHYR_INCLUDE_BLUETOOTH_HFP_AG_H_ + +/** + * @brief Hands Free Profile - Audio Gateway (HFP-AG) + * @defgroup bt_hfp_ag Hands Free Profile - Audio Gateway (HFP-AG) + * @ingroup bluetooth + * @{ + */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* HFP AG Indicators */ +enum bt_hfp_ag_indicator { + BT_HFP_AG_SERVICE_IND = 0, /* Service availability indicator */ + BT_HFP_AG_CALL_IND = 1, /* call status indicator */ + BT_HFP_AG_CALL_SETUP_IND = 2, /* Call set up status indicator */ + BT_HFP_AG_CALL_HELD_IND = 3, /* Call hold status indicator */ + BT_HFP_AG_SIGNAL_IND = 4, /* Signal strength indicator */ + BT_HFP_AG_ROAM_IND = 5, /* Roaming status indicator */ + BT_HFP_AG_BATTERY_IND = 6, /* Battery change indicator */ + BT_HFP_AG_IND_MAX /* Indicator MAX value */ +}; + +/* HFP CODEC */ +#define BT_HFP_AG_CODEC_CVSD 0x01 +#define BT_HFP_AG_CODEC_MSBC 0x02 +#define BT_HFP_AG_CODEC_LC3_SWB 0x03 + +struct bt_hfp_ag; + +/** @brief HFP profile AG application callback */ +struct bt_hfp_ag_cb { + /** HF AG connected callback to application + * + * If this callback is provided it will be called whenever the + * AG connection completes. + * + * @param ag HFP AG object. + */ + void (*connected)(struct bt_hfp_ag *ag); + /** HF disconnected callback to application + * + * If this callback is provided it will be called whenever the + * connection gets disconnected, including when a connection gets + * rejected or cancelled or any error in SLC establishment. + * + * @param ag HFP AG object. + */ + void (*disconnected)(struct bt_hfp_ag *ag); + /** HF SCO/eSCO connected Callback + * + * If this callback is provided it will be called whenever the + * SCO/eSCO connection completes. + * + * @param ag HFP AG object. + * @param sco_conn SCO/eSCO Connection object. + */ + void (*sco_connected)(struct bt_hfp_ag *ag, struct bt_conn *sco_conn); + /** HF SCO/eSCO disconnected Callback + * + * If this callback is provided it will be called whenever the + * SCO/eSCO connection gets disconnected. + * + * @param ag HFP AG object. + * @param sco_conn SCO/eSCO Connection object. + */ + void (*sco_disconnected)(struct bt_hfp_ag *ag); + + /** HF memory dialing request Callback + * + * If this callback is provided it will be called whenever a + * new call is requested with memory dialing from HFP unit. + * Get the phone number according to the given AG memory location. + * + * @param ag HFP AG object. + * @param location AG memory location + * @param number Dailing number + * + * @return 0 in case of success or negative value in case of error. + */ + int (*memory_dial)(struct bt_hfp_ag *ag, const char *location, char **number); + + /** HF outgoing Callback + * + * If this callback is provided it will be called whenever a + * new call is outgoing. + * + * @param ag HFP AG object. + * @param number Dailing number + */ + void (*outgoing)(struct bt_hfp_ag *ag, const char *number); + + /** HF incoming Callback + * + * If this callback is provided it will be called whenever a + * new call is incoming. + * + * @param ag HFP AG object. + * @param number Incoming number + */ + void (*incoming)(struct bt_hfp_ag *ag, const char *number); + + /** HF ringing Callback + * + * If this callback is provided it will be called whenever the + * call is in the ringing + * + * @param ag HFP AG object. + * @param in_bond true - in-bond ringing, false - No in-bond ringing + */ + void (*ringing)(struct bt_hfp_ag *ag, bool in_band); + + /** HF call accept Callback + * + * If this callback is provided it will be called whenever the + * call is accepted. + * + * @param ag HFP AG object. + */ + void (*accept)(struct bt_hfp_ag *ag); + + /** HF call reject Callback + * + * If this callback is provided it will be called whenever the + * call is rejected. + * + * @param ag HFP AG object. + */ + void (*reject)(struct bt_hfp_ag *ag); + + /** HF call terminate Callback + * + * If this callback is provided it will be called whenever the + * call is terminated. + * + * @param ag HFP AG object. + */ + void (*terminate)(struct bt_hfp_ag *ag); + + /** Supported codec Ids callback + * + * If this callback is provided it will be called whenever the + * supported codec ids are updated. + * + * @param ag HFP AG object. + */ + void (*codec)(struct bt_hfp_ag *ag, uint32_t ids); +}; + +/** @brief Register HFP AG profile + * + * Register Handsfree profile AG callbacks to monitor the state and get the + * required HFP details to display. + * + * @param cb callback structure. + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_hfp_ag_register(struct bt_hfp_ag_cb *cb); + +/** @brief Create the hfp ag session + * + * Create the hfp ag session + * + * @param conn ACL connection object. + * @param ag Created HFP AG object. + * @param channel Peer rfcomm channel to be connected. + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_hfp_ag_connect(struct bt_conn *conn, struct bt_hfp_ag **ag, uint8_t channel); + +/** @brief Disconnect the hfp ag session + * + * Disconnect the hfp ag session + * + * @param ag HFP AG object. + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_hfp_ag_disconnect(struct bt_hfp_ag *ag); + +/** @brief Notify HFP Unit of an incoming call + * + * Notify HFP Unit of an incoming call. + * + * @param ag HFP AG object. + * @param number Dailing number. + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_hfp_ag_remote_incoming(struct bt_hfp_ag *ag, const char *number); + +/** @brief Reject the incoming call + * + * Reject the incoming call. + * + * @param ag HFP AG object. + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_hfp_ag_reject(struct bt_hfp_ag *ag); + +/** @brief Accept the incoming call + * + * Accept the incoming call. + * + * @param ag HFP AG object. + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_hfp_ag_accept(struct bt_hfp_ag *ag); + +/** @brief Terminate the active/hold call + * + * Terminate the active/hold call. + * + * @param ag HFP AG object. + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_hfp_ag_terminate(struct bt_hfp_ag *ag); + +/** @brief Dial a call + * + * Dial a call. + * + * @param ag HFP AG object. + * @param number Dailing number. + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_hfp_ag_outgoing(struct bt_hfp_ag *ag, const char *number); + +/** @brief Notify HFP Unit that the remote starts ringing + * + * Notify HFP Unit that the remote starts ringing. + * + * @param ag HFP AG object. + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_hfp_ag_remote_ringing(struct bt_hfp_ag *ag); + +/** @brief Notify HFP Unit that the remote rejects the call + * + * Notify HFP Unit that the remote rejects the call. + * + * @param ag HFP AG object. + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_hfp_ag_remote_reject(struct bt_hfp_ag *ag); + +/** @brief Notify HFP Unit that the remote accepts the call + * + * Notify HFP Unit that the remote accepts the call. + * + * @param ag HFP AG object. + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_hfp_ag_remote_accept(struct bt_hfp_ag *ag); + +/** @brief Notify HFP Unit that the remote terminates the active/hold call + * + * Notify HFP Unit that the remote terminates the active/hold call. + * + * @param ag HFP AG object. + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_hfp_ag_remote_terminate(struct bt_hfp_ag *ag); + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_HFP_HF_H_ */ diff --git a/include/zephyr/bluetooth/classic/rfcomm.h b/include/zephyr/bluetooth/classic/rfcomm.h index 5664506931c..3b4f7f44ddb 100644 --- a/include/zephyr/bluetooth/classic/rfcomm.h +++ b/include/zephyr/bluetooth/classic/rfcomm.h @@ -104,7 +104,9 @@ struct bt_rfcomm_dlc { /* Stack & kernel data for TX thread */ struct k_thread tx_thread; - K_KERNEL_STACK_MEMBER(stack, 256); +#if defined(CONFIG_BT_RFCOMM_DLC_STACK_SIZE) + K_KERNEL_STACK_MEMBER(stack, CONFIG_BT_RFCOMM_DLC_STACK_SIZE); +#endif /* CONFIG_BT_RFCOMM_DLC_STACK_SIZE */ }; struct bt_rfcomm_server { diff --git a/include/zephyr/bluetooth/hci_types.h b/include/zephyr/bluetooth/hci_types.h index 98ab1db7190..2e91eda5c13 100644 --- a/include/zephyr/bluetooth/hci_types.h +++ b/include/zephyr/bluetooth/hci_types.h @@ -22,20 +22,31 @@ extern "C" { #endif +/* Bluetooth spec v5.4 Vol 4, Part A Table 2.1: HCI packet indicators + * The following definitions are intended for use with the UART Transport Layer and + * may be reused with other transport layers if desired. + */ +#define BT_HCI_H4_NONE 0x00 /* None of the known packet types */ +#define BT_HCI_H4_CMD 0x01 /* HCI Command packet */ +#define BT_HCI_H4_ACL 0x02 /* HCI ACL Data packet */ +#define BT_HCI_H4_SCO 0x03 /* HCI Synchronous Data packet */ +#define BT_HCI_H4_EVT 0x04 /* HCI Event packet */ +#define BT_HCI_H4_ISO 0x05 /* HCI ISO Data packet */ + /* Special own address types for LL privacy (used in adv & scan parameters) */ -#define BT_HCI_OWN_ADDR_RPA_OR_PUBLIC 0x02 -#define BT_HCI_OWN_ADDR_RPA_OR_RANDOM 0x03 -#define BT_HCI_OWN_ADDR_RPA_MASK 0x02 +#define BT_HCI_OWN_ADDR_RPA_OR_PUBLIC 0x02 +#define BT_HCI_OWN_ADDR_RPA_OR_RANDOM 0x03 +#define BT_HCI_OWN_ADDR_RPA_MASK 0x02 #define BT_HCI_PEER_ADDR_RPA_UNRESOLVED 0xfe #define BT_HCI_PEER_ADDR_ANONYMOUS 0xff -#define BT_ENC_KEY_SIZE_MIN 0x07 -#define BT_ENC_KEY_SIZE_MAX 0x10 +#define BT_ENC_KEY_SIZE_MIN 0x07 +#define BT_ENC_KEY_SIZE_MAX 0x10 -#define BT_HCI_ADV_HANDLE_INVALID 0xff -#define BT_HCI_SYNC_HANDLE_INVALID 0xffff -#define BT_HCI_PAWR_SUBEVENT_MAX 128 +#define BT_HCI_ADV_HANDLE_INVALID 0xff +#define BT_HCI_SYNC_HANDLE_INVALID 0xffff +#define BT_HCI_PAWR_SUBEVENT_MAX 128 /* Bluetooth spec v5.4 Vol 4, Part E - 5.4.3 HCI Synchronous Data Packets */ struct bt_hci_sco_hdr { @@ -97,17 +108,17 @@ struct bt_hci_acl_hdr { #define bt_iso_pkt_flags(h) ((h) >> 14) #define bt_iso_pkt_len_pack(h, f) (((h) & BIT_MASK(12)) | ((f) << 14)) -struct bt_hci_iso_data_hdr { +struct bt_hci_iso_sdu_hdr { uint16_t sn; uint16_t slen; /* 12 bit len, 2 bit RFU, 2 bit packet status */ } __packed; -#define BT_HCI_ISO_DATA_HDR_SIZE 4 +#define BT_HCI_ISO_SDU_HDR_SIZE 4 -struct bt_hci_iso_ts_data_hdr { +struct bt_hci_iso_sdu_ts_hdr { uint32_t ts; - struct bt_hci_iso_data_hdr data; + struct bt_hci_iso_sdu_hdr sdu; } __packed; -#define BT_HCI_ISO_TS_DATA_HDR_SIZE 8 +#define BT_HCI_ISO_SDU_TS_HDR_SIZE 8 /* Bluetooth spec v5.4 Vol 4, Part E - 5.4.5 HCI ISO Data Packets */ struct bt_hci_iso_hdr { @@ -556,6 +567,66 @@ struct bt_hci_rp_write_conn_accept_timeout { #define BT_BREDR_SCAN_INQUIRY 0x01 #define BT_BREDR_SCAN_PAGE 0x02 +#define BT_COD(major_service, major_device, minor_device) \ + (((uint32_t)major_service << 13) | ((uint32_t)major_device << 8) | \ + ((uint32_t)minor_device << 2)) +#define BT_COD_VALID(cod) ((0 == (cod[0] & (BIT(0) | BIT(1)))) ? true : false) +#define BT_COD_MAJOR_SERVICE_CLASSES(cod) \ + ((((uint32_t)cod[2] & 0xFF) >> 5) | (((uint32_t)cod[1] & 0xD0) >> 5)) +#define BT_COD_MAJOR_DEVICE_CLASS(cod) ((((uint32_t)cod[1]) & 0x1FUL)) +#define BT_COD_MINOR_DEVICE_CLASS(cod) (((((uint32_t)cod[0]) & 0xFF) >> 2)) + +#define BT_COD_MAJOR_MISC 0x00 +#define BT_COD_MAJOR_COMPUTER 0x01 +#define BT_COD_MAJOR_PHONE 0x02 +#define BT_COD_MAJOR_LAN_NETWORK_AP 0x03 +#define BT_COD_MAJOR_AUDIO_VIDEO 0x04 +#define BT_COD_MAJOR_PERIPHERAL 0x05 +#define BT_COD_MAJOR_IMAGING 0x06 +#define BT_COD_MAJOR_WEARABLE 0x07 +#define BT_COD_MAJOR_TOY 0x08 +#define BT_COD_MAJOR_HEALTH 0x09 +#define BT_COD_MAJOR_UNCATEGORIZED 0x1F + +/* Minor Device Class field - Computer Major Class */ +#define BT_COD_MAJOR_COMPUTER_MINOR_UNCATEGORIZED 0x00 +#define BT_COD_MAJOR_COMPUTER_MINOR_DESKTOP 0x01 +#define BT_COD_MAJOR_COMPUTER_MINOR_SERVER_CLASS_COMPUTER 0x02 +#define BT_COD_MAJOR_COMPUTER_MINOR_LAPTOP 0x03 +#define BT_COD_MAJOR_COMPUTER_MINOR_HANDHELD_PC_PDA 0x04 +#define BT_COD_MAJOR_COMPUTER_MINOR_PALM_SIZE_PC_PDA 0x05 +#define BT_COD_MAJOR_COMPUTER_MINOR_WEARABLE_COMPUTER 0x06 +#define BT_COD_MAJOR_COMPUTER_MINOR_TABLET 0x07 + +/* Minor Device Class field - Phone Major Class */ +#define BT_COD_MAJOR_PHONE_MINOR_UNCATEGORIZED 0x00 +#define BT_COD_MAJOR_PHONE_MINOR_CELLULAR 0x01 +#define BT_COD_MAJOR_PHONE_MINOR_CORDLESS 0x02 +#define BT_COD_MAJOR_PHONE_MINOR_SMARTPHONE 0x03 +#define BT_COD_MAJOR_PHONE_MINOR_WIRED_MODEM_VOICE_GATEWAY 0x04 +#define BT_COD_MAJOR_PHONE_MINOR_ISDN 0x05 + +/* Minor Device Class field - Audio/Video Major Class */ +#define BT_COD_MAJOR_AUDIO_VIDEO_MINOR_UNCATEGORIZED 0x00 +#define BT_COD_MAJOR_AUDIO_VIDEO_MINOR_WEARABLE_HEADSET 0x01 +#define BT_COD_MAJOR_AUDIO_VIDEO_MINOR_HANDS_FREE 0x02 +#define BT_COD_MAJOR_AUDIO_VIDEO_MINOR_RFU 0x03 +#define BT_COD_MAJOR_AUDIO_VIDEO_MINOR_MICROPHONE 0x04 +#define BT_COD_MAJOR_AUDIO_VIDEO_MINOR_LOUDSPEAKER 0x05 +#define BT_COD_MAJOR_AUDIO_VIDEO_MINOR_HEADPHONES 0x06 +#define BT_COD_MAJOR_AUDIO_VIDEO_MINOR_PORTABLE_AUDIO 0x07 +#define BT_COD_MAJOR_AUDIO_VIDEO_MINOR_CAR_AUDIO 0x08 +#define BT_COD_MAJOR_AUDIO_VIDEO_MINOR_SET_TOP_BOX 0x09 +#define BT_COD_MAJOR_AUDIO_VIDEO_MINOR_HIFI_AUDIO 0x0A +#define BT_COD_MAJOR_AUDIO_VIDEO_MINOR_VCR 0x0B +#define BT_COD_MAJOR_AUDIO_VIDEO_MINOR_VIDEO_CAMERA 0x0C +#define BT_COD_MAJOR_AUDIO_VIDEO_MINOR_CAMCORDER 0x0D +#define BT_COD_MAJOR_AUDIO_VIDEO_MINOR_VIDEO_MONITOR 0x0E +#define BT_COD_MAJOR_AUDIO_VIDEO_MINOR_VIDEO_DISPLAY_LOUDSPEAKER 0x0F +#define BT_COD_MAJOR_AUDIO_VIDEO_MINOR_VIDEO_CONFERENCING 0x10 +#define BT_COD_MAJOR_AUDIO_VIDEO_MINOR_RFU2 0x11 +#define BT_COD_MAJOR_AUDIO_VIDEO_MINOR_GAME_TOY 0x12 + #define BT_HCI_OP_WRITE_CLASS_OF_DEVICE BT_OP(BT_OGF_BASEBAND, 0x0024) /* 0x0c24 */ struct bt_hci_cp_write_class_of_device { uint8_t class_of_device[3]; diff --git a/include/zephyr/bluetooth/iso.h b/include/zephyr/bluetooth/iso.h index f7bb3900e76..a8166a56051 100644 --- a/include/zephyr/bluetooth/iso.h +++ b/include/zephyr/bluetooth/iso.h @@ -14,6 +14,10 @@ /** * @brief Isochronous channels (ISO) * @defgroup bt_iso Isochronous channels (ISO) + * + * @since 2.3 + * @version 0.8.0 + * * @ingroup bluetooth * @{ */ @@ -156,7 +160,7 @@ struct bt_iso_chan { struct bt_iso_chan_qos *qos; /** Channel state */ enum bt_iso_state state; -#if defined(CONFIG_BT_SMP) || defined(__DOXYGEN__) +#if (defined(CONFIG_BT_SMP) && defined(CONFIG_BT_ISO_UNICAST)) || defined(__DOXYGEN__) /** @brief The required security level of the channel * * This value can be set as the central before connecting a CIS @@ -167,7 +171,7 @@ struct bt_iso_chan { * Only available when @kconfig{CONFIG_BT_SMP} is enabled. */ bt_security_t required_sec_level; -#endif /* CONFIG_BT_SMP */ +#endif /* CONFIG_BT_SMP && CONFIG_BT_ISO_UNICAST */ /** Node used internally by the stack */ sys_snode_t node; }; diff --git a/include/zephyr/bluetooth/l2cap.h b/include/zephyr/bluetooth/l2cap.h index dfd01dcc455..4ba0610b77d 100644 --- a/include/zephyr/bluetooth/l2cap.h +++ b/include/zephyr/bluetooth/l2cap.h @@ -157,8 +157,6 @@ struct bt_l2cap_le_endpoint { uint16_t mtu; /** Endpoint Maximum PDU payload Size */ uint16_t mps; - /** Endpoint initial credits */ - uint16_t init_credits; /** Endpoint credits */ atomic_t credits; }; @@ -171,7 +169,7 @@ struct bt_l2cap_le_chan { * * If the application has set an alloc_buf channel callback for the * channel to support receiving segmented L2CAP SDUs the application - * should inititalize the MTU of the Receiving Endpoint. Otherwise the + * should initialize the MTU of the Receiving Endpoint. Otherwise the * MTU of the receiving endpoint will be initialized to * @ref BT_L2CAP_SDU_RX_MTU by the stack. * @@ -572,6 +570,8 @@ int bt_l2cap_chan_disconnect(struct bt_l2cap_chan *chan); * Regarding to first input parameter, to get details see reference description * to bt_l2cap_chan_connect() API above. * + * Network buffer fragments (ie `buf->frags`) are not supported. + * * When sending L2CAP data over an BR/EDR connection the application is sending * L2CAP PDUs. The application is required to have reserved * @ref BT_L2CAP_CHAN_SEND_RESERVE bytes in the buffer before sending. diff --git a/include/zephyr/bluetooth/mesh/access.h b/include/zephyr/bluetooth/mesh/access.h index 5d2d661710e..f1fca02783e 100644 --- a/include/zephyr/bluetooth/mesh/access.h +++ b/include/zephyr/bluetooth/mesh/access.h @@ -506,7 +506,8 @@ struct bt_mesh_model_op { * @param _pub Model publish parameters. * @param _user_data User data for the model. * @param _cb Callback structure, or NULL to keep no callbacks. - * @param _metadata Metadata structure. + * @param _metadata Metadata structure. Used if @kconfig{CONFIG_BT_MESH_LARGE_COMP_DATA_SRV} + * is enabled. */ #if defined(CONFIG_BT_MESH_LARGE_COMP_DATA_SRV) #define BT_MESH_MODEL_METADATA_CB(_id, _op, _pub, _user_data, _cb, _metadata) \ @@ -560,8 +561,10 @@ struct bt_mesh_model_op { * @param _pub Model publish parameters. * @param _user_data User data for the model. * @param _cb Callback structure, or NULL to keep no callbacks. - * @param _metadata Metadata structure. + * @param _metadata Metadata structure. Used if @kconfig{CONFIG_BT_MESH_LARGE_COMP_DATA_SRV} + * is enabled. */ +#if defined(CONFIG_BT_MESH_LARGE_COMP_DATA_SRV) #define BT_MESH_MODEL_VND_METADATA_CB(_company, _id, _op, _pub, _user_data, _cb, _metadata) \ { \ .vnd.company = (_company), \ @@ -577,7 +580,10 @@ struct bt_mesh_model_op { .cb = _cb, \ .metadata = _metadata, \ } - +#else +#define BT_MESH_MODEL_VND_METADATA_CB(_company, _id, _op, _pub, _user_data, _cb, _metadata) \ + BT_MESH_MODEL_VND_CB(_company, _id, _op, _pub, _user_data, _cb) +#endif /** * @brief Composition data SIG model entry. * @@ -924,7 +930,7 @@ struct bt_mesh_model { #if defined(CONFIG_BT_MESH_LARGE_COMP_DATA_SRV) || defined(__DOXYGEN__) /* Pointer to the array of model metadata entries. */ - const struct bt_mesh_models_metadata_entry * const * const metadata; + const struct bt_mesh_models_metadata_entry * const metadata; #endif }; diff --git a/include/zephyr/bluetooth/mesh/health_srv.h b/include/zephyr/bluetooth/mesh/health_srv.h index 9eb4008b846..3833c750e2b 100644 --- a/include/zephyr/bluetooth/mesh/health_srv.h +++ b/include/zephyr/bluetooth/mesh/health_srv.h @@ -156,11 +156,6 @@ struct bt_mesh_health_srv { /** Attention Timer state */ struct k_work_delayable attn_timer; - -#ifdef CONFIG_BT_MESH_LARGE_COMP_DATA_SRV - /** Pointer to the array with Health Test Info Metadata */ - const struct bt_mesh_models_metadata_entry *metadata; -#endif }; /** @@ -171,18 +166,18 @@ struct bt_mesh_health_srv { * * @param srv Pointer to a unique struct bt_mesh_health_srv. * @param pub Pointer to a unique struct bt_mesh_model_pub. + * @param ... Optional Health Server metadata if application is compiled with + * Large Composition Data Server support, otherwise this parameter + * is ignored. * * @return New mesh model instance. */ -#ifdef CONFIG_BT_MESH_LARGE_COMP_DATA_SRV -#define BT_MESH_MODEL_HEALTH_SRV(srv, pub) \ - BT_MESH_MODEL_METADATA_CB(BT_MESH_MODEL_ID_HEALTH_SRV, bt_mesh_health_srv_op, \ - pub, srv, &bt_mesh_health_srv_cb, &(srv)->metadata) -#else -#define BT_MESH_MODEL_HEALTH_SRV(srv, pub) \ - BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_HEALTH_SRV, bt_mesh_health_srv_op, \ - pub, srv, &bt_mesh_health_srv_cb) -#endif +#define BT_MESH_MODEL_HEALTH_SRV(srv, pub, ...) \ + BT_MESH_MODEL_METADATA_CB(BT_MESH_MODEL_ID_HEALTH_SRV, \ + bt_mesh_health_srv_op, \ + pub, \ + srv, \ + &bt_mesh_health_srv_cb, __VA_ARGS__) /** * diff --git a/include/zephyr/bluetooth/mesh/shell.h b/include/zephyr/bluetooth/mesh/shell.h index 1c396407521..27879cdfad0 100644 --- a/include/zephyr/bluetooth/mesh/shell.h +++ b/include/zephyr/bluetooth/mesh/shell.h @@ -38,6 +38,9 @@ struct bt_mesh_shell_target { /** @brief External reference to health server */ extern struct bt_mesh_health_srv bt_mesh_shell_health_srv; +/** @brief External reference to health server metadata */ +extern const struct bt_mesh_models_metadata_entry health_srv_meta[]; + /** @brief External reference to health client */ extern struct bt_mesh_health_cli bt_mesh_shell_health_cli; diff --git a/include/zephyr/bluetooth/uuid.h b/include/zephyr/bluetooth/uuid.h index 16943f89e63..f430fc7edf5 100644 --- a/include/zephyr/bluetooth/uuid.h +++ b/include/zephyr/bluetooth/uuid.h @@ -432,7 +432,7 @@ struct bt_uuid_128 { #define BT_UUID_CSC \ BT_UUID_DECLARE_16(BT_UUID_CSC_VAL) /** - * @brief Cyclicg Power Service UUID value + * @brief Cycling Power Service UUID value */ #define BT_UUID_CPS_VAL 0x1818 /** @@ -620,7 +620,7 @@ struct bt_uuid_128 { */ #define BT_UUID_ECS_VAL 0x183c /** - * @brief Energency Configuration Service + * @brief Emergency Configuration Service */ #define BT_UUID_ECS \ BT_UUID_DECLARE_16(BT_UUID_ECS_VAL) @@ -1003,11 +1003,11 @@ struct bt_uuid_128 { #define BT_UUID_GAP_APPEARANCE \ BT_UUID_DECLARE_16(BT_UUID_GAP_APPEARANCE_VAL) /** - * @brief GAP Characteristic Peripheal Privacy Flag UUID value + * @brief GAP Characteristic Peripheral Privacy Flag UUID value */ #define BT_UUID_GAP_PPF_VAL 0x2a02 /** - * @brief GAP Characteristic Peripheal Privacy Flag + * @brief GAP Characteristic Peripheral Privacy Flag */ #define BT_UUID_GAP_PPF \ BT_UUID_DECLARE_16(BT_UUID_GAP_PPF_VAL) @@ -3546,7 +3546,7 @@ struct bt_uuid_128 { */ #define BT_UUID_GATT_RCCP_VAL 0x2b1f /** - * @brief GATT Characteristic Reconnection Configurationn Control Point + * @brief GATT Characteristic Reconnection Configuration Control Point */ #define BT_UUID_GATT_RCCP \ BT_UUID_DECLARE_16(BT_UUID_GATT_RCCP_VAL) @@ -3569,11 +3569,11 @@ struct bt_uuid_128 { #define BT_UUID_GATT_IDD_S \ BT_UUID_DECLARE_16(BT_UUID_GATT_IDD_S_VAL) /** - * @brief GATT Characteristic IDD Announciation Status UUID Value + * @brief GATT Characteristic IDD Annunciation Status UUID Value */ #define BT_UUID_GATT_IDD_AS_VAL 0x2b22 /** - * @brief GATT Characteristic IDD Announciation Status + * @brief GATT Characteristic IDD Annunciation Status */ #define BT_UUID_GATT_IDD_AS \ BT_UUID_DECLARE_16(BT_UUID_GATT_IDD_AS_VAL) @@ -3857,7 +3857,7 @@ struct bt_uuid_128 { #define BT_UUID_GATT_SLP_AID \ BT_UUID_DECLARE_16(BT_UUID_GATT_SLP_AID_VAL) /** - * @brief GATT Characteristic Sleep Actiity Summary Data UUID Value + * @brief GATT Characteristic Sleep Activity Summary Data UUID Value */ #define BT_UUID_GATT_SLP_ASD_VAL 0x2b42 /** diff --git a/include/zephyr/data/json.h b/include/zephyr/data/json.h index b8b386d968a..7534b3674f6 100644 --- a/include/zephyr/data/json.h +++ b/include/zephyr/data/json.h @@ -191,11 +191,9 @@ typedef int (*json_append_bytes_t)(const char *bytes, size_t len, .field_name_len = (sizeof(#field_name_) - 1), \ .type = JSON_TOK_OBJECT_START, \ .offset = offsetof(struct_, field_name_), \ - { \ - .object = { \ - .sub_descr = sub_descr_, \ - .sub_descr_len = ARRAY_SIZE(sub_descr_), \ - }, \ + .object = { \ + .sub_descr = sub_descr_, \ + .sub_descr_len = ARRAY_SIZE(sub_descr_), \ }, \ } @@ -277,12 +275,10 @@ typedef int (*json_append_bytes_t)(const char *bytes, size_t len, .field_name_len = sizeof(#field_name_) - 1, \ .type = JSON_TOK_ARRAY_START, \ .offset = offsetof(struct_, field_name_), \ - { \ - .array = { \ - .element_descr = Z_JSON_ELEMENT_DESCR(struct_, len_field_, \ - elem_type_,), \ - .n_elements = (max_len_), \ - }, \ + .array = { \ + .element_descr = Z_JSON_ELEMENT_DESCR(struct_, len_field_, \ + elem_type_,), \ + .n_elements = (max_len_), \ }, \ } @@ -328,13 +324,11 @@ typedef int (*json_append_bytes_t)(const char *bytes, size_t len, .field_name_len = sizeof(#field_name_) - 1, \ .type = JSON_TOK_ARRAY_START, \ .offset = offsetof(struct_, field_name_), \ - { \ - .array = { \ - .element_descr = Z_JSON_ELEMENT_DESCR(struct_, len_field_, \ - JSON_TOK_OBJECT_START, \ - Z_JSON_DESCR_OBJ(elem_descr_, elem_descr_len_)), \ - .n_elements = (max_len_), \ - }, \ + .array = { \ + .element_descr = Z_JSON_ELEMENT_DESCR(struct_, len_field_, \ + JSON_TOK_OBJECT_START, \ + Z_JSON_DESCR_OBJ(elem_descr_, elem_descr_len_)), \ + .n_elements = (max_len_), \ }, \ } @@ -389,15 +383,13 @@ typedef int (*json_append_bytes_t)(const char *bytes, size_t len, .field_name_len = sizeof(#field_name_) - 1, \ .type = JSON_TOK_ARRAY_START, \ .offset = offsetof(struct_, field_name_), \ - { \ - .array = { \ - .element_descr = Z_JSON_ELEMENT_DESCR( \ - struct_, len_field_, JSON_TOK_ARRAY_START, \ - Z_JSON_DESCR_ARRAY( \ - elem_descr_, \ - 1 + ZERO_OR_COMPILE_ERROR(elem_descr_len_ == 1))), \ - .n_elements = (max_len_), \ - }, \ + .array = { \ + .element_descr = Z_JSON_ELEMENT_DESCR( \ + struct_, len_field_, JSON_TOK_ARRAY_START, \ + Z_JSON_DESCR_ARRAY( \ + elem_descr_, \ + 1 + ZERO_OR_COMPILE_ERROR(elem_descr_len_ == 1))), \ + .n_elements = (max_len_), \ }, \ } @@ -426,15 +418,13 @@ typedef int (*json_append_bytes_t)(const char *bytes, size_t len, .field_name_len = sizeof(#json_field_name_) - 1, \ .type = JSON_TOK_ARRAY_START, \ .offset = offsetof(struct_, struct_field_name_), \ - { \ - .array = { \ - .element_descr = Z_JSON_ELEMENT_DESCR( \ - struct_, len_field_, JSON_TOK_ARRAY_START, \ - Z_JSON_DESCR_ARRAY( \ - elem_descr_, \ - 1 + ZERO_OR_COMPILE_ERROR(elem_descr_len_ == 1))), \ - .n_elements = (max_len_), \ - }, \ + .array = { \ + .element_descr = Z_JSON_ELEMENT_DESCR( \ + struct_, len_field_, JSON_TOK_ARRAY_START, \ + Z_JSON_DESCR_ARRAY( \ + elem_descr_, \ + 1 + ZERO_OR_COMPILE_ERROR(elem_descr_len_ == 1))), \ + .n_elements = (max_len_), \ }, \ } @@ -483,11 +473,9 @@ typedef int (*json_append_bytes_t)(const char *bytes, size_t len, .field_name_len = (sizeof(json_field_name_) - 1), \ .type = JSON_TOK_OBJECT_START, \ .offset = offsetof(struct_, struct_field_name_), \ - { \ - .object = { \ - .sub_descr = sub_descr_, \ - .sub_descr_len = ARRAY_SIZE(sub_descr_), \ - }, \ + .object = { \ + .sub_descr = sub_descr_, \ + .sub_descr_len = ARRAY_SIZE(sub_descr_), \ }, \ } @@ -516,12 +504,10 @@ typedef int (*json_append_bytes_t)(const char *bytes, size_t len, .field_name_len = sizeof(json_field_name_) - 1, \ .type = JSON_TOK_ARRAY_START, \ .offset = offsetof(struct_, struct_field_name_), \ - { \ - .array = { \ - .element_descr = \ - Z_JSON_ELEMENT_DESCR(struct_, len_field_, elem_type_,), \ - .n_elements = (max_len_), \ - }, \ + .array = { \ + .element_descr = \ + Z_JSON_ELEMENT_DESCR(struct_, len_field_, elem_type_,), \ + .n_elements = (max_len_), \ }, \ } @@ -575,13 +561,11 @@ typedef int (*json_append_bytes_t)(const char *bytes, size_t len, .field_name_len = sizeof(json_field_name_) - 1, \ .type = JSON_TOK_ARRAY_START, \ .offset = offsetof(struct_, struct_field_name_), \ - { \ - .array = { \ - .element_descr = Z_JSON_ELEMENT_DESCR(struct_, len_field_, \ - JSON_TOK_OBJECT_START, \ - Z_JSON_DESCR_OBJ(elem_descr_, elem_descr_len_)), \ - .n_elements = (max_len_), \ - }, \ + .array = { \ + .element_descr = Z_JSON_ELEMENT_DESCR(struct_, len_field_, \ + JSON_TOK_OBJECT_START, \ + Z_JSON_DESCR_OBJ(elem_descr_, elem_descr_len_)), \ + .n_elements = (max_len_), \ }, \ } diff --git a/include/zephyr/debug/mipi_stp_decoder.h b/include/zephyr/debug/mipi_stp_decoder.h new file mode 100644 index 00000000000..85b08af6419 --- /dev/null +++ b/include/zephyr/debug/mipi_stp_decoder.h @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DEBUG_MIPI_STP_DECODER_H__ +#define ZEPHYR_INCLUDE_DEBUG_MIPI_STP_DECODER_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup mipi_stp_decoder_apis STP Decoder API + * @ingroup coresight_apis + * @{ + */ + +/** @brief STPv2 opcodes. */ +enum mipi_stp_decoder_ctrl_type { + STP_DATA4 = 1, + STP_DATA8 = 2, + STP_DATA16 = 4, + STP_DATA32 = 8, + STP_DATA64 = 16, + STP_DECODER_NULL = 128, + STP_DECODER_MASTER, + STP_DECODER_MERROR, + STP_DECODER_CHANNEL, + STP_DECODER_VERSION, + STP_DECODER_FREQ, + STP_DECODER_GERROR, + STP_DECODER_FLAG, + STP_DECODER_ASYNC, + STP_DECODER_NOT_SUPPORTED, +}; + +/** @brief Convert type to a string literal. + * + * @param _type type + * @return String literal. + */ +#define STP_DECODER_TYPE2STR(_type) \ + _type == STP_DATA4 ? "DATA4" : (\ + _type == STP_DATA8 ? "DATA8" : (\ + _type == STP_DATA16 ? "DATA16" : (\ + _type == STP_DATA32 ? "DATA32" : (\ + _type == STP_DATA64 ? "DATA64" : (\ + _type == STP_DECODER_NULL ? "NULL" : (\ + _type == STP_DECODER_MASTER ? "MASTER" : (\ + _type == STP_DECODER_MERROR ? "MERROR" : (\ + _type == STP_DECODER_CHANNEL ? "CHANNEL" : (\ + _type == STP_DECODER_VERSION ? "VERSION" : (\ + _type == STP_DECODER_FREQ ? "FREQ" : (\ + _type == STP_DECODER_GERROR ? "GERROR" : (\ + _type == STP_DECODER_FLAG ? "FLAG" : (\ + _type == STP_DECODER_ASYNC ? "ASYNC" : (\ + "Unknown")))))))))))))) + +/** @brief Union with data associated with a given STP opcode. */ +union mipi_stp_decoder_data { + /** ID - used for master and channel. */ + uint16_t id; + + /** Frequency. */ + uint64_t freq; + + /** Version. */ + uint32_t ver; + + /** Error code. */ + uint32_t err; + + /** Dummy. */ + uint32_t dummy; + + /** Data. */ + uint64_t data; +}; + +/** @brief Callback signature. + * + * Callback is called whenever an element from STPv2 stream is decoded. + * + * @note Callback is called with interrupts locked. + * + * @param type Type. See @ref mipi_stp_decoder_ctrl_type. + * @param data Data. Data associated with a given @p type. + * @param ts Timestamp. Present if not NULL. + * @param marked Set to true if opcode was marked. + */ +typedef void (*mipi_stp_decoder_cb)(enum mipi_stp_decoder_ctrl_type type, + union mipi_stp_decoder_data data, + uint64_t *ts, bool marked); + +/** @brief Decoder configuration. */ +struct mipi_stp_decoder_config { + /** Indicates that decoder start in out of sync state. */ + bool start_out_of_sync; + + /** Callback. */ + mipi_stp_decoder_cb cb; +}; + +/** @brief Initialize the decoder. + * + * @param config Configuration. + * + * @retval 0 On successful initialization. + * @retval negative On failure. + */ +int mipi_stp_decoder_init(const struct mipi_stp_decoder_config *config); + +/** @brief Decode STPv2 stream. + * + * Function decodes the stream and calls the callback for every decoded element. + * + * @param data Data. + * @param len Data length. + * + * @retval 0 On successful decoding. + * @retval negative On failure. + */ +int mipi_stp_decoder_decode(const uint8_t *data, size_t len); + +/** @brief Indicate synchronization loss. + * + * If detected, then decoder starts to look for ASYNC marker and drops all data + * until ASYNC is found. Synchronization can be lost when there is data loss (e.g. + * due to overflow). + */ +void mipi_stp_decoder_sync_loss(void); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_DEBUG_MIPI_STP_DECODER_H__ */ diff --git a/include/zephyr/debug/stack.h b/include/zephyr/debug/stack.h index 9053dfb8d62..365560a0624 100644 --- a/include/zephyr/debug/stack.h +++ b/include/zephyr/debug/stack.h @@ -38,6 +38,8 @@ static inline void log_stack_usage(const struct k_thread *thread) thread, tname, unused, size - unused, size, pcnt); } +#else + ARG_UNUSED(thread); #endif } #endif /* ZEPHYR_INCLUDE_DEBUG_STACK_H_ */ diff --git a/include/zephyr/device.h b/include/zephyr/device.h index 607cd76f6f2..d2f2244cc0b 100644 --- a/include/zephyr/device.h +++ b/include/zephyr/device.h @@ -151,6 +151,16 @@ typedef int16_t device_handle_t; #define DEVICE_DT_NAME(node_id) \ DT_PROP_OR(node_id, label, DT_NODE_FULL_NAME(node_id)) +/** + * @brief Determine if a devicetree node initialization should be deferred. + * + * @param node_id The devicetree node identifier. + * + * @return Boolean stating if node initialization should be deferred. + */ +#define DEVICE_DT_DEFER(node_id) \ + DT_PROP(node_id, zephyr_deferred_init) + /** * @brief Create a device object from a devicetree node identifier and set it up * for boot time initialization. @@ -758,6 +768,22 @@ static inline bool z_impl_device_is_ready(const struct device *dev) return z_device_is_ready(dev); } +/** + * @brief Initialize a device. + * + * A device whose initialization was deferred (by marking it as + * ``zephyr,deferred-init`` on devicetree) needs to be initialized manually via + * this call. Note that only devices whose initialization was deferred can be + * initialized via this call - one can not try to initialize a non + * initialization deferred device that failed initialization with this call. + * + * @param dev device to be initialized. + * + * @retval -ENOENT If device was not found - or isn't a deferred one. + * @retval -errno For other errors. + */ +__syscall int device_init(const struct device *dev); + /** * @} */ @@ -908,7 +934,7 @@ static inline bool z_impl_device_is_ready(const struct device *dev) .state = (state_), \ .data = (data_), \ IF_ENABLED(CONFIG_DEVICE_DEPS, (.deps = (deps_),)) /**/ \ - IF_ENABLED(CONFIG_PM_DEVICE, ({ .pm_base = (pm_),)}) /**/ \ + IF_ENABLED(CONFIG_PM_DEVICE, ({ .pm_base = (pm_),})) /**/ \ } /** @@ -988,6 +1014,18 @@ static inline bool z_impl_device_is_ready(const struct device *dev) }, \ } +#define Z_DEFER_DEVICE_INIT_ENTRY_DEFINE(node_id, dev_id, init_fn_) \ + static const Z_DECL_ALIGN(struct init_entry) __used __noasan \ + __attribute__((__section__(".z_deferred_init"))) \ + 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), \ + }, \ + } + /** * @brief Define a @ref device and all other required objects. * @@ -1019,7 +1057,11 @@ static inline bool z_impl_device_is_ready(const struct device *dev) Z_DEVICE_BASE_DEFINE(node_id, dev_id, name, pm, data, config, level, \ prio, api, state, Z_DEVICE_DEPS_NAME(dev_id)); \ \ - Z_DEVICE_INIT_ENTRY_DEFINE(node_id, dev_id, init_fn, level, prio) + COND_CODE_1(DEVICE_DT_DEFER(node_id), \ + (Z_DEFER_DEVICE_INIT_ENTRY_DEFINE(node_id, dev_id, \ + init_fn)), \ + (Z_DEVICE_INIT_ENTRY_DEFINE(node_id, dev_id, init_fn, \ + level, prio))); /** * @brief Declare a device for each status "okay" devicetree node. diff --git a/include/zephyr/devicetree.h b/include/zephyr/devicetree.h index b6a8756c9ca..eb28dea874a 100644 --- a/include/zephyr/devicetree.h +++ b/include/zephyr/devicetree.h @@ -551,6 +551,25 @@ */ #define DT_NODE_CHILD_IDX(node_id) DT_CAT(node_id, _CHILD_IDX) +/** + * @brief Get the number of child nodes of a given node + * + * @param node_id a node identifier + * @return Number of child nodes + */ +#define DT_CHILD_NUM(node_id) DT_CAT(node_id, _CHILD_NUM) + + +/** + * @brief Get the number of child nodes of a given node + * which child nodes' status are okay + * + * @param node_id a node identifier + * @return Number of child nodes which status are okay + */ +#define DT_CHILD_NUM_STATUS_OKAY(node_id) \ + DT_CAT(node_id, _CHILD_NUM_STATUS_OKAY) + /** * @brief Do @p node_id1 and @p node_id2 refer to the same node? * @@ -3442,6 +3461,29 @@ #define DT_INST_CHILD(inst, child) \ DT_CHILD(DT_DRV_INST(inst), child) +/** + * @brief Get the number of child nodes of a given node + * + * This is equivalent to @see + * DT_CHILD_NUM(DT_DRV_INST(inst)). + * + * @param inst Devicetree instance number + * @return Number of child nodes + */ +#define DT_INST_CHILD_NUM(inst) DT_CHILD_NUM(DT_DRV_INST(inst)) + +/** + * @brief Get the number of child nodes of a given node + * + * This is equivalent to @see + * DT_CHILD_NUM_STATUS_OKAY(DT_DRV_INST(inst)). + * + * @param inst Devicetree instance number + * @return Number of child nodes which status are okay + */ +#define DT_INST_CHILD_NUM_STATUS_OKAY(inst) \ + DT_CHILD_NUM_STATUS_OKAY(DT_DRV_INST(inst)) + /** * @brief Call @p fn on all child nodes of DT_DRV_INST(inst). * @@ -4357,6 +4399,15 @@ #define DT_INST_NODE_HAS_PROP(inst, prop) \ DT_NODE_HAS_PROP(DT_DRV_INST(inst), prop) +/** + * @brief Does a DT_DRV_COMPAT instance have the compatible? + * @param inst instance number + * @param compat lowercase-and-underscores compatible, without quotes + * @return 1 if the instance matches the compatible, 0 otherwise. + */ +#define DT_INST_NODE_HAS_COMPAT(inst, compat) \ + DT_NODE_HAS_COMPAT(DT_DRV_INST(inst), compat) + /** * @brief Does a phandle array have a named cell specifier at an index * for a `DT_DRV_COMPAT` instance? diff --git a/include/zephyr/drivers/bluetooth/hci_driver.h b/include/zephyr/drivers/bluetooth/hci_driver.h index e611c8b089f..08aacc853f3 100644 --- a/include/zephyr/drivers/bluetooth/hci_driver.h +++ b/include/zephyr/drivers/bluetooth/hci_driver.h @@ -46,23 +46,12 @@ enum { * host with data from the controller. The buffer needs to have its type * set with the help of bt_buf_set_type() before calling this API. * - * @note This function must only be called from a cooperative thread. - * * @param buf Network buffer containing data from the controller. * * @return 0 on success or negative error number on failure. */ int bt_recv(struct net_buf *buf); -/** @brief Read static addresses from the controller. - * - * @param addrs Random static address and Identity Root (IR) array. - * @param size Size of array. - * - * @return Number of addresses read. - */ -uint8_t bt_read_static_addr(struct bt_hci_vs_static_addr addrs[], uint8_t size); - /** Possible values for the 'bus' member of the bt_hci_driver struct */ enum bt_hci_driver_bus { BT_HCI_DRIVER_BUS_VIRTUAL = 0, diff --git a/include/zephyr/drivers/can.h b/include/zephyr/drivers/can.h index d677d8a9263..3b0e323dff9 100644 --- a/include/zephyr/drivers/can.h +++ b/include/zephyr/drivers/can.h @@ -31,7 +31,7 @@ extern "C" { * @brief CAN Interface * @defgroup can_interface CAN Interface * @since 1.12 - * @version 1.0.0 + * @version 1.1.0 * @ingroup io_interfaces * @{ */ @@ -171,10 +171,7 @@ enum can_state { */ struct can_frame { /** Standard (11-bit) or extended (29-bit) CAN identifier. */ - uint32_t id : 29; - /** @cond INTERNAL_HIDDEN */ - uint8_t res0 : 3; /* reserved/padding. */ - /** @endcond */ + uint32_t id; /** Data Length Code (DLC) indicating data length in bytes. */ uint8_t dlc; /** Flags. @see @ref CAN_FRAME_FLAGS. */ @@ -190,7 +187,8 @@ struct can_frame { uint16_t timestamp; #else /** @cond INTERNAL_HIDDEN */ - uint16_t res1; /* reserved/padding. */ + /** Padding. */ + uint16_t reserved; /** @endcond */ #endif /** The frame payload data. */ @@ -212,7 +210,6 @@ struct can_frame { /** Filter matches frames with extended (29-bit) CAN IDs */ #define CAN_FILTER_IDE BIT(0) - /** @} */ /** @@ -220,14 +217,11 @@ struct can_frame { */ struct can_filter { /** CAN identifier to match. */ - uint32_t id : 29; - /** @cond INTERNAL_HIDDEN */ - uint32_t res0 : 3; - /** @endcond */ + uint32_t id; /** CAN identifier matching mask. If a bit in this mask is 0, the value * of the corresponding bit in the ``id`` field is ignored by the filter. */ - uint32_t mask : 29; + uint32_t mask; /** Flags. @see @ref CAN_FILTER_FLAGS. */ uint8_t flags; }; @@ -380,10 +374,11 @@ struct can_driver_config { .phy = DEVICE_DT_GET_OR_NULL(DT_PHANDLE(node_id, phys)), \ .min_bitrate = DT_CAN_TRANSCEIVER_MIN_BITRATE(node_id, _min_bitrate), \ .max_bitrate = DT_CAN_TRANSCEIVER_MAX_BITRATE(node_id, _max_bitrate), \ - .bus_speed = DT_PROP(node_id, bus_speed), \ + .bus_speed = DT_PROP_OR(node_id, bus_speed, CONFIG_CAN_DEFAULT_BITRATE), \ .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), \ + (.bus_speed_data = DT_PROP_OR(node_id, bus_speed_data, \ + CONFIG_CAN_DEFAULT_BITRATE_DATA), \ .sample_point_data = DT_PROP_OR(node_id, sample_point_data, 0),)) \ } @@ -840,20 +835,52 @@ static inline int z_impl_can_get_core_clock(const struct device *dev, uint32_t * * Get the minimum supported bitrate for the CAN controller/transceiver combination. * * @param dev Pointer to the device structure for the driver instance. + * @return Minimum supported bitrate in bits/s + */ +__syscall uint32_t can_get_bitrate_min(const struct device *dev); + +static inline uint32_t z_impl_can_get_bitrate_min(const struct device *dev) +{ + const struct can_driver_config *common = (const struct can_driver_config *)dev->config; + + return common->min_bitrate; +} + +/** + * @brief Get minimum supported bitrate + * + * Get the minimum supported bitrate for the CAN controller/transceiver combination. + * + * @deprecated Use @a can_get_bitrate_min() instead. + * + * @param dev Pointer to the device structure for the driver instance. * @param[out] min_bitrate Minimum supported bitrate in bits/s * * @retval -EIO General input/output error. * @retval -ENOSYS If this function is not implemented by the driver. */ -__syscall int can_get_min_bitrate(const struct device *dev, uint32_t *min_bitrate); +__deprecated static inline int can_get_min_bitrate(const struct device *dev, uint32_t *min_bitrate) +{ + *min_bitrate = can_get_bitrate_min(dev); + + return 0; +} + +/** + * @brief Get maximum supported bitrate + * + * Get the maximum supported bitrate for the CAN controller/transceiver combination. + * + * @param dev Pointer to the device structure for the driver instance. + * @return Maximum supported bitrate in bits/s + */ +__syscall uint32_t can_get_bitrate_max(const struct device *dev); -static inline int z_impl_can_get_min_bitrate(const struct device *dev, uint32_t *min_bitrate) +static inline uint32_t z_impl_can_get_bitrate_max(const struct device *dev) { const struct can_driver_config *common = (const struct can_driver_config *)dev->config; - *min_bitrate = common->min_bitrate; - - return 0; + return common->max_bitrate; } /** @@ -861,6 +888,8 @@ static inline int z_impl_can_get_min_bitrate(const struct device *dev, uint32_t * * Get the maximum supported bitrate for the CAN controller/transceiver combination. * + * @deprecated Use @a can_get_bitrate_max() instead. + * * @param dev Pointer to the device structure for the driver instance. * @param[out] max_bitrate Maximum supported bitrate in bits/s * @@ -868,17 +897,9 @@ static inline int z_impl_can_get_min_bitrate(const struct device *dev, uint32_t * @retval -EIO General input/output error. * @retval -ENOSYS If this function is not implemented by the driver. */ -__syscall int can_get_max_bitrate(const struct device *dev, uint32_t *max_bitrate); - -static inline int z_impl_can_get_max_bitrate(const struct device *dev, uint32_t *max_bitrate) +__deprecated static inline int can_get_max_bitrate(const struct device *dev, uint32_t *max_bitrate) { - const struct can_driver_config *common = (const struct can_driver_config *)dev->config; - - if (common->max_bitrate == 0U) { - return -ENOSYS; - } - - *max_bitrate = common->max_bitrate; + *max_bitrate = can_get_bitrate_max(dev); return 0; } @@ -1343,17 +1364,8 @@ __syscall int can_send(const struct device *dev, const struct can_frame *frame, * @retval -EINVAL if the requested filter type is invalid. * @retval -ENOTSUP if the requested filter type is not supported. */ -static inline int can_add_rx_filter(const struct device *dev, can_rx_callback_t callback, - void *user_data, const struct can_filter *filter) -{ - const struct can_driver_api *api = (const struct can_driver_api *)dev->api; - - if (filter == NULL) { - return -EINVAL; - } - - return api->add_rx_filter(dev, callback, user_data, filter); -} +int can_add_rx_filter(const struct device *dev, can_rx_callback_t callback, + void *user_data, const struct can_filter *filter); /** * @brief Statically define and initialize a CAN RX message queue. diff --git a/include/zephyr/drivers/clock_control.h b/include/zephyr/drivers/clock_control.h index d0806163769..27d65fe3079 100644 --- a/include/zephyr/drivers/clock_control.h +++ b/include/zephyr/drivers/clock_control.h @@ -99,7 +99,7 @@ typedef int (*clock_control_configure_fn)(const struct device *dev, clock_control_subsys_t sys, void *data); -struct clock_control_driver_api { +__subsystem struct clock_control_driver_api { clock_control on; clock_control off; clock_control_async_on_fn async_on; diff --git a/include/zephyr/drivers/clock_control/nrf_clock_control.h b/include/zephyr/drivers/clock_control/nrf_clock_control.h index e60c157f932..5ec409770e0 100644 --- a/include/zephyr/drivers/clock_control/nrf_clock_control.h +++ b/include/zephyr/drivers/clock_control/nrf_clock_control.h @@ -99,7 +99,7 @@ void z_nrf_clock_calibration_force_start(void); /** @brief Return number of calibrations performed. * - * Valid when @ref CONFIG_CLOCK_CONTROL_NRF_CALIBRATION_DEBUG is set. + * Valid when @kconfig{CONFIG_CLOCK_CONTROL_NRF_CALIBRATION_DEBUG} is set. * * @return Number of calibrations or -1 if feature is disabled. */ @@ -107,7 +107,7 @@ int z_nrf_clock_calibration_count(void); /** @brief Return number of attempts when calibration was skipped. * - * Valid when @ref CONFIG_CLOCK_CONTROL_NRF_CALIBRATION_DEBUG is set. + * Valid when @kconfig{CONFIG_CLOCK_CONTROL_NRF_CALIBRATION_DEBUG} is set. * * @return Number of calibrations or -1 if feature is disabled. */ diff --git a/include/zephyr/drivers/display.h b/include/zephyr/drivers/display.h index 854c728148a..067d441d455 100644 --- a/include/zephyr/drivers/display.h +++ b/include/zephyr/drivers/display.h @@ -217,7 +217,7 @@ typedef int (*display_set_orientation_api)(const struct device *dev, * @brief Display driver API * API which a display driver should expose */ -struct display_driver_api { +__subsystem struct display_driver_api { display_blanking_on_api blanking_on; display_blanking_off_api blanking_off; display_write_api write; diff --git a/include/zephyr/drivers/dma.h b/include/zephyr/drivers/dma.h index 25e524c1e4f..36a5916b080 100644 --- a/include/zephyr/drivers/dma.h +++ b/include/zephyr/drivers/dma.h @@ -217,12 +217,12 @@ struct dma_config { */ uint32_t complete_callback_en : 1; /** - * Error callback enable + * Error callback disable * * - 0b0 error callback enabled * - 0b1 error callback disabled */ - uint32_t error_callback_en : 1; + uint32_t error_callback_dis : 1; /** * Source handshake, HW specific * diff --git a/include/zephyr/drivers/emul_bbram.h b/include/zephyr/drivers/emul_bbram.h index 441f101c934..ee9edab8846 100644 --- a/include/zephyr/drivers/emul_bbram.h +++ b/include/zephyr/drivers/emul_bbram.h @@ -23,7 +23,7 @@ * These are for internal use only, so skip these in public documentation. */ -__subsystem struct emul_bbram_backend_api { +__subsystem struct emul_bbram_driver_api { /** Sets the data */ int (*set_data)(const struct emul *target, size_t offset, size_t count, const uint8_t *data); @@ -53,7 +53,7 @@ static inline int emul_bbram_backend_set_data(const struct emul *target, size_t return -ENOTSUP; } - struct emul_bbram_backend_api *api = (struct emul_bbram_backend_api *)target->backend_api; + struct emul_bbram_driver_api *api = (struct emul_bbram_driver_api *)target->backend_api; if (api->set_data == NULL) { return -ENOTSUP; @@ -80,7 +80,7 @@ static inline int emul_bbram_backend_get_data(const struct emul *target, size_t return -ENOTSUP; } - struct emul_bbram_backend_api *api = (struct emul_bbram_backend_api *)target->backend_api; + struct emul_bbram_driver_api *api = (struct emul_bbram_driver_api *)target->backend_api; if (api->get_data == NULL) { return -ENOTSUP; diff --git a/include/zephyr/drivers/emul_sensor.h b/include/zephyr/drivers/emul_sensor.h index 30345cc6a0b..265505d5e5a 100644 --- a/include/zephyr/drivers/emul_sensor.h +++ b/include/zephyr/drivers/emul_sensor.h @@ -25,18 +25,18 @@ /** * @brief Collection of function pointers implementing a common backend API for sensor emulators */ -__subsystem struct emul_sensor_backend_api { +__subsystem struct emul_sensor_driver_api { /** Sets a given fractional value for a given sensor channel. */ - int (*set_channel)(const struct emul *target, enum sensor_channel ch, const q31_t *value, - int8_t shift); + int (*set_channel)(const struct emul *target, struct sensor_chan_spec 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, + int (*get_sample_range)(const struct emul *target, struct sensor_chan_spec 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, + int (*set_attribute)(const struct emul *target, struct sensor_chan_spec 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, + int (*get_attribute_metadata)(const struct emul *target, struct sensor_chan_spec ch, enum sensor_attribute attribute, q31_t *min, q31_t *max, q31_t *increment, int8_t *shift); }; @@ -68,14 +68,15 @@ static inline bool emul_sensor_backend_is_supported(const struct emul *target) * @return -ENOTSUP if no backend API or if channel not supported by emul * @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, - const q31_t *value, int8_t shift) +static inline int emul_sensor_backend_set_channel(const struct emul *target, + struct sensor_chan_spec ch, const q31_t *value, + int8_t shift) { if (!target || !target->backend_api) { return -ENOTSUP; } - struct emul_sensor_backend_api *api = (struct emul_sensor_backend_api *)target->backend_api; + struct emul_sensor_driver_api *api = (struct emul_sensor_driver_api *)target->backend_api; if (api->set_channel) { return api->set_channel(target, ch, value, shift); @@ -101,14 +102,14 @@ static inline int emul_sensor_backend_set_channel(const struct emul *target, enu * */ static inline int emul_sensor_backend_get_sample_range(const struct emul *target, - enum sensor_channel ch, q31_t *lower, + struct sensor_chan_spec ch, q31_t *lower, q31_t *upper, q31_t *epsilon, int8_t *shift) { if (!target || !target->backend_api) { return -ENOTSUP; } - struct emul_sensor_backend_api *api = (struct emul_sensor_backend_api *)target->backend_api; + struct emul_sensor_driver_api *api = (struct emul_sensor_driver_api *)target->backend_api; if (api->get_sample_range) { return api->get_sample_range(target, ch, lower, upper, epsilon, shift); @@ -127,7 +128,7 @@ static inline int emul_sensor_backend_get_sample_range(const struct emul *target * @return < 0 on error */ static inline int emul_sensor_backend_set_attribute(const struct emul *target, - enum sensor_channel ch, + struct sensor_chan_spec ch, enum sensor_attribute attribute, const void *value) { @@ -135,7 +136,7 @@ static inline int emul_sensor_backend_set_attribute(const struct emul *target, return -ENOTSUP; } - struct emul_sensor_backend_api *api = (struct emul_sensor_backend_api *)target->backend_api; + struct emul_sensor_driver_api *api = (struct emul_sensor_driver_api *)target->backend_api; if (api->set_attribute == NULL) { return -ENOTSUP; @@ -161,7 +162,7 @@ static inline int emul_sensor_backend_set_attribute(const struct emul *target, * @return < 0 on error */ static inline int emul_sensor_backend_get_attribute_metadata(const struct emul *target, - enum sensor_channel ch, + struct sensor_chan_spec ch, enum sensor_attribute attribute, q31_t *min, q31_t *max, q31_t *increment, int8_t *shift) @@ -170,7 +171,7 @@ static inline int emul_sensor_backend_get_attribute_metadata(const struct emul * return -ENOTSUP; } - struct emul_sensor_backend_api *api = (struct emul_sensor_backend_api *)target->backend_api; + struct emul_sensor_driver_api *api = (struct emul_sensor_driver_api *)target->backend_api; if (api->get_attribute_metadata == NULL) { return -ENOTSUP; diff --git a/include/zephyr/drivers/espi.h b/include/zephyr/drivers/espi.h index d2f77622fc5..d2e64d9c5e4 100644 --- a/include/zephyr/drivers/espi.h +++ b/include/zephyr/drivers/espi.h @@ -43,7 +43,7 @@ enum espi_io_mode { * @code *+----------------------------------------------------------------------+ *| | - *| eSPI host +-------------+ | + *| eSPI controller +-------------+ | *| +-----------+ | Power | +----------+ | *| |Out of band| | management | | GPIO | | *| +------------+ |processor | | controller | | sources | | @@ -81,7 +81,7 @@ enum espi_io_mode { * +-----------------+ * | *+-----------------------------------------------------------------------+ - *| eSPI slave | + *| eSPI target | *| | *| CH0 | CH1 | CH2 | CH3 | *| eSPI endpoint | VWIRE | OOB | Flash | @@ -138,8 +138,8 @@ enum espi_pc_event { #define ESPI_PERIPHERAL_INDEX_1 1ul #define ESPI_PERIPHERAL_INDEX_2 2ul -#define ESPI_SLAVE_TO_MASTER 0ul -#define ESPI_MASTER_TO_SLAVE 1ul +#define ESPI_TARGET_TO_CONTROLLER 0ul +#define ESPI_CONTROLLER_TO_TARGET 1ul #define ESPI_VWIRE_SRC_ID0 0ul #define ESPI_VWIRE_SRC_ID1 1ul @@ -197,7 +197,7 @@ enum espi_cycle_type { * virtual wire channel */ enum espi_vwire_signal { - /* Virtual wires that can only be send from master to slave */ + /* Virtual wires that can only be send from controller to target */ ESPI_VWIRE_SIGNAL_SLP_S3, ESPI_VWIRE_SIGNAL_SLP_S4, ESPI_VWIRE_SIGNAL_SLP_S5, @@ -214,14 +214,14 @@ enum espi_vwire_signal { ESPI_VWIRE_SIGNAL_SLP_LAN, ESPI_VWIRE_SIGNAL_HOST_C10, ESPI_VWIRE_SIGNAL_DNX_WARN, - /* Virtual wires that can only be sent from slave to master */ + /* Virtual wires that can only be sent from target to controller */ ESPI_VWIRE_SIGNAL_PME, ESPI_VWIRE_SIGNAL_WAKE, ESPI_VWIRE_SIGNAL_OOB_RST_ACK, - ESPI_VWIRE_SIGNAL_SLV_BOOT_STS, + ESPI_VWIRE_SIGNAL_TARGET_BOOT_STS, ESPI_VWIRE_SIGNAL_ERR_NON_FATAL, ESPI_VWIRE_SIGNAL_ERR_FATAL, - ESPI_VWIRE_SIGNAL_SLV_BOOT_DONE, + ESPI_VWIRE_SIGNAL_TARGET_BOOT_DONE, ESPI_VWIRE_SIGNAL_HOST_RST_ACK, ESPI_VWIRE_SIGNAL_RST_CPU_INIT, /* System management interrupt */ @@ -231,31 +231,31 @@ enum espi_vwire_signal { ESPI_VWIRE_SIGNAL_DNX_ACK, ESPI_VWIRE_SIGNAL_SUS_ACK, /* - * Virtual wire GPIOs that can be sent from slave to master for + * Virtual wire GPIOs that can be sent from target to controller for * platform specific usage. */ - ESPI_VWIRE_SIGNAL_SLV_GPIO_0, - ESPI_VWIRE_SIGNAL_SLV_GPIO_1, - ESPI_VWIRE_SIGNAL_SLV_GPIO_2, - ESPI_VWIRE_SIGNAL_SLV_GPIO_3, - ESPI_VWIRE_SIGNAL_SLV_GPIO_4, - ESPI_VWIRE_SIGNAL_SLV_GPIO_5, - ESPI_VWIRE_SIGNAL_SLV_GPIO_6, - ESPI_VWIRE_SIGNAL_SLV_GPIO_7, - ESPI_VWIRE_SIGNAL_SLV_GPIO_8, - ESPI_VWIRE_SIGNAL_SLV_GPIO_9, - ESPI_VWIRE_SIGNAL_SLV_GPIO_10, - ESPI_VWIRE_SIGNAL_SLV_GPIO_11, + ESPI_VWIRE_SIGNAL_TARGET_GPIO_0, + ESPI_VWIRE_SIGNAL_TARGET_GPIO_1, + ESPI_VWIRE_SIGNAL_TARGET_GPIO_2, + ESPI_VWIRE_SIGNAL_TARGET_GPIO_3, + ESPI_VWIRE_SIGNAL_TARGET_GPIO_4, + ESPI_VWIRE_SIGNAL_TARGET_GPIO_5, + ESPI_VWIRE_SIGNAL_TARGET_GPIO_6, + ESPI_VWIRE_SIGNAL_TARGET_GPIO_7, + ESPI_VWIRE_SIGNAL_TARGET_GPIO_8, + ESPI_VWIRE_SIGNAL_TARGET_GPIO_9, + ESPI_VWIRE_SIGNAL_TARGET_GPIO_10, + ESPI_VWIRE_SIGNAL_TARGET_GPIO_11, /* Number of Virtual Wires */ ESPI_VWIRE_SIGNAL_COUNT }; /* USB-C port over current */ -#define ESPI_VWIRE_SIGNAL_OCB_0 ESPI_VWIRE_SIGNAL_SLV_GPIO_0 -#define ESPI_VWIRE_SIGNAL_OCB_1 ESPI_VWIRE_SIGNAL_SLV_GPIO_1 -#define ESPI_VWIRE_SIGNAL_OCB_2 ESPI_VWIRE_SIGNAL_SLV_GPIO_2 -#define ESPI_VWIRE_SIGNAL_OCB_3 ESPI_VWIRE_SIGNAL_SLV_GPIO_3 +#define ESPI_VWIRE_SIGNAL_OCB_0 ESPI_VWIRE_SIGNAL_TARGET_GPIO_0 +#define ESPI_VWIRE_SIGNAL_OCB_1 ESPI_VWIRE_SIGNAL_TARGET_GPIO_1 +#define ESPI_VWIRE_SIGNAL_OCB_2 ESPI_VWIRE_SIGNAL_TARGET_GPIO_2 +#define ESPI_VWIRE_SIGNAL_OCB_3 ESPI_VWIRE_SIGNAL_TARGET_GPIO_3 /* eSPI LPC peripherals. */ enum lpc_peripheral_opcode { @@ -482,18 +482,18 @@ __subsystem struct espi_driver_api { * This routine provides a generic interface to override eSPI controller * capabilities. * - * If this eSPI controller is acting as slave, the values set here + * If this eSPI controller is acting as target, the values set here * will be discovered as part through the GET_CONFIGURATION command - * issued by the eSPI master during initialization. + * issued by the eSPI controller during initialization. * - * If this eSPI controller is acting as master, the values set here - * will be used by eSPI master to determine minimum common capabilities with - * eSPI slave then send via SET_CONFIGURATION command. + * If this eSPI controller is acting as controller, the values set here + * will be used by eSPI controller to determine minimum common capabilities with + * eSPI target then send via SET_CONFIGURATION command. * * @code - * +--------+ +---------+ +------+ +---------+ +---------+ - * | eSPI | | eSPI | | eSPI | | eSPI | | eSPI | - * | slave | | driver | | bus | | driver | | host | + * +---------+ +---------+ +------+ +---------+ +---------+ + * | eSPI | | eSPI | | eSPI | | eSPI | | eSPI | + * | target | | driver | | bus | | driver | | host | * +--------+ +---------+ +------+ +---------+ +---------+ * | | | | | * | espi_config | Set eSPI | Set eSPI | espi_config | @@ -522,7 +522,7 @@ __subsystem struct espi_driver_api { * @retval 0 If successful. * @retval -EIO General input / output error, failed to configure device. * @retval -EINVAL invalid capabilities, failed to configure device. - * @retval -ENOTSUP capability not supported by eSPI slave. + * @retval -ENOTSUP capability not supported by eSPI target. */ __syscall int espi_config(const struct device *dev, struct espi_cfg *cfg); @@ -690,10 +690,10 @@ static inline int z_impl_espi_write_lpc_request(const struct device *dev, * @brief Sends system/platform signal as a virtual wire packet. * * This routines provides a generic interface to send a virtual wire packet - * from slave to master. + * from target to controller. * * @param dev Pointer to the device structure for the driver instance. - * @param signal The signal to be send to eSPI master. + * @param signal The signal to be send to eSPI controller. * @param level The level of signal requested LOW or HIGH. * * @retval 0 If successful. @@ -717,13 +717,13 @@ static inline int z_impl_espi_send_vwire(const struct device *dev, * @brief Retrieves level status for a signal encapsulated in a virtual wire. * * This routines provides a generic interface to request a virtual wire packet - * from eSPI master and retrieve the signal level. + * from eSPI controller and retrieve the signal level. * * @param dev Pointer to the device structure for the driver instance. - * @param signal the signal to be requested from eSPI master. + * @param signal the signal to be requested from eSPI controller. * @param level the level of signal requested 0b LOW, 1b HIGH. * - * @retval -EIO General input / output error, failed request to master. + * @retval -EIO General input / output error, failed request to controller. */ __syscall int espi_receive_vwire(const struct device *dev, enum espi_vwire_signal signal, @@ -748,7 +748,7 @@ static inline int z_impl_espi_receive_vwire(const struct device *dev, * @param dev Pointer to the device structure for the driver instance. * @param pckt Address of the packet representation of SMBus transaction. * - * @retval -EIO General input / output error, failed request to master. + * @retval -EIO General input / output error, failed request to controller. */ __syscall int espi_send_oob(const struct device *dev, struct espi_oob_packet *pckt); @@ -775,7 +775,7 @@ static inline int z_impl_espi_send_oob(const struct device *dev, * @param dev Pointer to the device structure for the driver instance. * @param pckt Address of the packet representation of SMBus transaction. * - * @retval -EIO General input / output error, failed request to master. + * @retval -EIO General input / output error, failed request to controller. */ __syscall int espi_receive_oob(const struct device *dev, struct espi_oob_packet *pckt); @@ -797,14 +797,14 @@ static inline int z_impl_espi_receive_oob(const struct device *dev, * @brief Sends a read request packet for shared flash. * * This routines provides an interface to send a request to read the flash - * component shared between the eSPI master and eSPI slaves. + * component shared between the eSPI controller and eSPI targets. * * @param dev Pointer to the device structure for the driver instance. * @param pckt Address of the representation of read 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. + * @retval -EBUSY eSPI flash channel is not ready or disabled by controller. + * @retval -EIO General input / output error, failed request to controller. */ __syscall int espi_read_flash(const struct device *dev, struct espi_flash_packet *pckt); @@ -826,14 +826,14 @@ static inline int z_impl_espi_read_flash(const struct device *dev, * @brief Sends a write request packet for shared flash. * * This routines provides an interface to send a request to write to the flash - * components shared between the eSPI master and eSPI slaves. + * components shared between the eSPI controller and eSPI targets. * * @param dev Pointer to the device structure for the driver instance. * @param pckt Address of the representation of write 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. + * @retval -EBUSY eSPI flash channel is not ready or disabled by controller. + * @retval -EIO General input / output error, failed request to controller. */ __syscall int espi_write_flash(const struct device *dev, struct espi_flash_packet *pckt); @@ -855,14 +855,14 @@ static inline int z_impl_espi_write_flash(const struct device *dev, * @brief Sends a write request packet for shared flash. * * This routines provides an interface to send a request to write to the flash - * components shared between the eSPI master and eSPI slaves. + * components shared between the eSPI controller and eSPI targets. * * @param dev Pointer to the device structure for the driver instance. * @param pckt Address of the representation of write 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. + * @retval -EBUSY eSPI flash channel is not ready or disabled by controller. + * @retval -EIO General input / output error, failed request to controller. */ __syscall int espi_flash_erase(const struct device *dev, struct espi_flash_packet *pckt); diff --git a/include/zephyr/drivers/fpga.h b/include/zephyr/drivers/fpga.h index 27dcb69f600..61e9c1cf0dd 100644 --- a/include/zephyr/drivers/fpga.h +++ b/include/zephyr/drivers/fpga.h @@ -58,6 +58,13 @@ static inline enum FPGA_status fpga_get_status(const struct device *dev) const struct fpga_driver_api *api = (const struct fpga_driver_api *)dev->api; + if (api->get_status == NULL) { + /* assume it can never be reprogrammed if it + * doesn't support the get_status callback + */ + return FPGA_STATUS_INACTIVE; + } + return api->get_status(dev); } @@ -74,6 +81,10 @@ static inline int fpga_reset(const struct device *dev) const struct fpga_driver_api *api = (const struct fpga_driver_api *)dev->api; + if (api->reset == NULL) { + return -ENOTSUP; + } + return api->reset(dev); } @@ -93,6 +104,10 @@ static inline int fpga_load(const struct device *dev, uint32_t *image_ptr, const struct fpga_driver_api *api = (const struct fpga_driver_api *)dev->api; + if (api->load == NULL) { + return -ENOTSUP; + } + return api->load(dev, image_ptr, img_size); } @@ -116,6 +131,8 @@ static inline int fpga_on(const struct device *dev) return api->on(dev); } +#define FPGA_GET_INFO_DEFAULT "n/a" + /** * @brief Returns information about the FPGA. * @@ -128,6 +145,10 @@ static inline const char *fpga_get_info(const struct device *dev) const struct fpga_driver_api *api = (const struct fpga_driver_api *)dev->api; + if (api->get_info == NULL) { + return FPGA_GET_INFO_DEFAULT; + } + return api->get_info(dev); } diff --git a/include/zephyr/drivers/gpio/gpio_intel.h b/include/zephyr/drivers/gpio/gpio_intel.h new file mode 100644 index 00000000000..b20c3e60d97 --- /dev/null +++ b/include/zephyr/drivers/gpio/gpio_intel.h @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2023 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +struct gpio_acpi_res { + uint8_t num_pins; + uint32_t pad_base; + uint32_t host_owner_reg; + uint32_t pad_owner_reg; + uint32_t intr_stat_reg; + uint16_t base_num; + uintptr_t reg_base; +}; diff --git a/include/zephyr/drivers/hwinfo.h b/include/zephyr/drivers/hwinfo.h index df412cdf29d..468356284be 100644 --- a/include/zephyr/drivers/hwinfo.h +++ b/include/zephyr/drivers/hwinfo.h @@ -95,6 +95,22 @@ __syscall ssize_t hwinfo_get_device_id(uint8_t *buffer, size_t length); ssize_t z_impl_hwinfo_get_device_id(uint8_t *buffer, size_t length); +/** + * @brief Copy the device EUI64 to a buffer + * + * This routine copies the device EUI64 (8 bytes) to the buffer. + * The EUI64 depends on the hardware and is guaranteed unique. + * + * @param buffer Buffer of 8 bytes to write the ID to. + * + * @retval zero if successful. + * @retval -ENOSYS if there is no implementation for the particular device. + * @retval any negative value on driver specific errors. + */ +__syscall int hwinfo_get_device_eui64(uint8_t *buffer); + +int z_impl_hwinfo_get_device_eui64(uint8_t *buffer); + /** * @brief Retrieve cause of device reset. * diff --git a/include/zephyr/drivers/i2c.h b/include/zephyr/drivers/i2c.h index 6135fbf1390..04b7d02ce15 100644 --- a/include/zephyr/drivers/i2c.h +++ b/include/zephyr/drivers/i2c.h @@ -259,7 +259,7 @@ __subsystem struct i2c_driver_api { typedef int (*i2c_target_api_register_t)(const struct device *dev); typedef int (*i2c_target_api_unregister_t)(const struct device *dev); -struct i2c_target_driver_api { +__subsystem struct i2c_target_driver_api { i2c_target_api_register_t driver_register; i2c_target_api_unregister_t driver_unregister; }; diff --git a/include/zephyr/drivers/i2c/rtio.h b/include/zephyr/drivers/i2c/rtio.h index c98aec4586f..d4dc6c32ae2 100644 --- a/include/zephyr/drivers/i2c/rtio.h +++ b/include/zephyr/drivers/i2c/rtio.h @@ -36,10 +36,10 @@ struct i2c_rtio { * @param _sq_sz Submission queue entry pool size * @param _cq_sz Completeion queue entry pool size */ -#define I2C_RTIO_DEFINE(_name, _sq_sz, _cq_sz) \ - RTIO_DEFINE(_name##_r, _sq_sz, _cq_sz); \ - static struct i2c_rtio _name = { \ - .r = &_name##_r, \ +#define I2C_RTIO_DEFINE(_name, _sq_sz, _cq_sz) \ + RTIO_DEFINE(CONCAT(_name, _r), _sq_sz, _cq_sz); \ + static struct i2c_rtio _name = { \ + .r = &CONCAT(_name, _r), \ }; /** diff --git a/include/zephyr/drivers/i3c.h b/include/zephyr/drivers/i3c.h index b5411dcd9a3..7233143fc70 100644 --- a/include/zephyr/drivers/i3c.h +++ b/include/zephyr/drivers/i3c.h @@ -1040,6 +1040,58 @@ struct i3c_device_desc { uint8_t max_ibi; } data_length; + /** Describes advanced (Target) capabilities and features */ + struct { + union { + /** + * I3C v1.0 HDR Capabilities (@c I3C_CCC_GETCAPS1_*) + * - Bit[0]: HDR-DDR + * - Bit[1]: HDR-TSP + * - Bit[2]: HDR-TSL + * - Bit[7:3]: Reserved + */ + uint8_t gethdrcap; + + /** + * I3C v1.1+ GETCAPS1 (@c I3C_CCC_GETCAPS1_*) + * - Bit[0]: HDR-DDR + * - Bit[1]: HDR-TSP + * - Bit[2]: HDR-TSL + * - Bit[3]: HDR-BT + * - Bit[7:4]: Reserved + */ + uint8_t getcap1; + }; + + /** + * GETCAPS2 (@c I3C_CCC_GETCAPS2_*) + * - Bit[3:0]: I3C 1.x Specification Version + * - Bit[5:4]: Group Address Capabilities + * - Bit[6]: HDR-DDR Write Abort + * - Bit[7]: HDR-DDR Abort CRC + */ + uint8_t getcap2; + + /** + * GETCAPS3 (@c I3C_CCC_GETCAPS3_*) + * - Bit[0]: Multi-Lane (ML) Data Transfer Support + * - Bit[1]: Device to Device Transfer (D2DXFER) Support + * - Bit[2]: Device to Device Transfer (D2DXFER) IBI Capable + * - Bit[3]: Defining Byte Support in GETCAPS + * - Bit[4]: Defining Byte Support in GETSTATUS + * - Bit[5]: HDR-BT CRC-32 Support + * - Bit[6]: IBI MDB Support for Pending Read Notification + * - Bit[7]: Reserved + */ + uint8_t getcap3; + + /** + * GETCAPS4 + * - Bit[7:0]: Reserved + */ + uint8_t getcap4; + } getcaps; + /** * Private data by the controller to aid in transactions. Do not modify. * diff --git a/include/zephyr/drivers/i3c/ccc.h b/include/zephyr/drivers/i3c/ccc.h index 116750bcac5..767d922086c 100644 --- a/include/zephyr/drivers/i3c/ccc.h +++ b/include/zephyr/drivers/i3c/ccc.h @@ -761,7 +761,7 @@ union i3c_ccc_getmxds { /** Get Max Data Speed (GETMXDS) - Max Sustained Data Rate bitmask. */ #define I3C_CCC_GETMXDS_MAXWR_MAX_SDR_FSCL_MASK \ - (0x07U << I3C_CCC_GET_MXDS_MAXWR_MAX_SDR_FSCL_SHIFT) + (0x07U << I3C_CCC_GETMXDS_MAXWR_MAX_SDR_FSCL_SHIFT) /** * @brief Get Max Data Speed (GETMXDS) - maxWr - Max Sustained Data Rate @@ -803,7 +803,7 @@ union i3c_ccc_getmxds { /** Get Max Data Speed (GETMXDS) - maxRd - Max Sustained Data Rate bitmask. */ #define I3C_CCC_GETMXDS_MAXRD_MAX_SDR_FSCL_MASK \ - (0x07U << I3C_CCC_GET_MXDS_MAXRD_MAX_SDR_FSCL_SHIFT) + (0x07U << I3C_CCC_GETMXDS_MAXRD_MAX_SDR_FSCL_SHIFT) /** * @brief Get Max Data Speed (GETMXDS) - maxRd - Max Sustained Data Rate @@ -826,7 +826,7 @@ union i3c_ccc_getmxds { /** Get Max Data Speed (GETMXDS) - CRDHLY1 - Controller Handoff Activity State bitmask. */ #define I3C_CCC_GETMXDS_CRDHLY1_CTRL_HANDOFF_ACT_STATE_MASK \ - (0x03U << I3C_CCC_GETMXDS_CRDHLY1_SET_BUS_ACT_STATE_SHIFT) + (0x03U << I3C_CCC_GETMXDS_CRDHLY1_CTRL_HANDOFF_ACT_STATE_SHIFT) /** * @brief Get Max Data Speed (GETMXDS) - CRDHLY1 - Controller Handoff Activity State @@ -838,29 +838,147 @@ union i3c_ccc_getmxds { */ #define I3C_CCC_GETMXDS_CRDHLY1_CTRL_HANDOFF_ACT_STATE(crhdly1) \ (((crhdly1) & \ - I3C_CCC_GETMXDS_CRDHLY1_SET_BUS_ACT_STATE_MASK) \ - >> I3C_CCC_GETMXDS_CRDHLY1_SET_BUS_ACT_STATE_SHIFT) + I3C_CCC_GETMXDS_CRDHLY1_CTRL_HANDOFF_ACT_STATE_MASK) \ + >> I3C_CCC_GETMXDS_CRDHLY1_CTRL_HANDOFF_ACT_STATE_SHIFT) + +/** + * @brief Indicate which format of GETCAPS to use. + */ +enum i3c_ccc_getcaps_fmt { + /** GETCAPS Format 1 */ + GETCAPS_FORMAT_1, + + /** GETCAPS Format 2 */ + GETCAPS_FORMAT_2, +}; + +/** + * @brief Enum for I3C Get Capabilities (GETCAPS) Format 2 Defining Byte Values. + */ +enum i3c_ccc_getcaps_defbyte { + /** Standard Target capabilities and features. */ + GETCAPS_FORMAT_2_TGTCAPS = 0x00U, + + /** Fixed 32b test pattern. */ + GETCAPS_FORMAT_2_TESTPAT = 0x5AU, + + /** Controller handoff capabilities and features. */ + GETCAPS_FORMAT_2_CRCAPS = 0x91U, + + /** Virtual Target capabilities and features. */ + GETCAPS_FORMAT_2_VTCAPS = 0x93U, + + /** Debug-capable Device capabilities and features. */ + GETCAPS_FORMAT_2_DBGCAPS = 0xD7U, + + /** Invalid defining byte. */ + GETCAPS_FORMAT_2_INVALID = 0x100, +}; /** * @brief Payload for GETCAPS CCC (Get Optional Feature Capabilities). * - * @note Only support GETCAPS Format 1. + * @note Only supports GETCAPS Format 1 and Format 2. In I3C v1.0 this was + * GETHDRCAP which only returned a single byte which is the same as the + * GETCAPS1 byte. */ -struct i3c_ccc_getcaps { - /** - * GETCAP[1-4] bytes. - */ - uint8_t getcaps[4]; +union i3c_ccc_getcaps { + union { + /** + * I3C v1.0 HDR Capabilities + * - Bit[0]: HDR-DDR + * - Bit[1]: HDR-TSP + * - Bit[2]: HDR-TSL + * - Bit[7:3]: Reserved + */ + uint8_t gethdrcap; + + /** + * I3C v1.1+ Device Capabilities + * Byte 1 GETCAPS1 + * - Bit[0]: HDR-DDR + * - Bit[1]: HDR-TSP + * - Bit[2]: HDR-TSL + * - Bit[3]: HDR-BT + * - Bit[7:4]: Reserved + * Byte 2 GETCAPS2 + * - Bit[3:0]: I3C 1.x Specification Version + * - Bit[5:4]: Group Address Capabilities + * - Bit[6]: HDR-DDR Write Abort + * - Bit[7]: HDR-DDR Abort CRC + * Byte 3 GETCAPS3 + * - Bit[0]: Multi-Lane (ML) Data Transfer Support + * - Bit[1]: Device to Device Transfer (D2DXFER) Support + * - Bit[2]: Device to Device Transfer (D2DXFER) IBI Capable + * - Bit[3]: Defining Byte Support in GETCAPS + * - Bit[4]: Defining Byte Support in GETSTATUS + * - Bit[5]: HDR-BT CRC-32 Support + * - Bit[6]: IBI MDB Support for Pending Read Notification + * - Bit[7]: Reserved + * Byte 4 GETCAPS4 + * - Bit[7:0]: Reserved + */ + uint8_t getcaps[4]; + } fmt1; + + union { + /** + * Defining Byte 0x00: TGTCAPS + * + * @see i3c_ccc_getcaps::fmt1::getcaps + */ + uint8_t tgtcaps[4]; + + /** + * Defining Byte 0x5A: TESTPAT + * + * @note should always be 0xA55AA55A in big endian + */ + uint32_t testpat; + + /** + * Defining Byte 0x91: CRCAPS + * Byte 1 CRCAPS1 + * - Bit[0]: Hot-Join Support + * - Bit[1]: Group Management Support + * - Bit[2]: Multi-Lane Support + * Byte 2 CRCAPS2 + * - Bit[0]: In-Band Interrupt Support + * - Bit[1]: Controller Pass-Back + * - Bit[2]: Deep Sleep Capable + * - Bit[3]: Delayed Controller Handoff + */ + uint8_t crcaps[2]; + + /** + * Defining Byte 0x93: VTCAPS + * Byte 1 VTCAPS1 + * - Bit[2:0]: Virtual Target Type + * - Bit[4]: Side Effects + * - Bit[5]: Shared Peripheral Detect + * Byte 2 VTCAPS2 + * - Bit[1:0]: Interrupt Requests + * - Bit[2]: Address Remapping + * - Bit[4:3]: Bus Context and Conditions + */ + uint8_t vtcaps[2]; + } fmt2; } __packed; -/** Get Optional Feature Capabilities (GETCAPS) Format 1 - HDR-DDR mode bit. */ +/** Get Optional Feature Capabilities Byte 1 (GETCAPS) Format 1 - HDR-DDR mode bit. */ #define I3C_CCC_GETCAPS1_HDR_DDR BIT(0) -/** Get Optional Feature Capabilities (GETCAPS) Format 1 - HDR-BT mode bit. */ +/** Get Optional Feature Capabilities Byte 1 (GETCAPS) Format 1 - HDR-TSP mode bit. */ +#define I3C_CCC_GETCAPS1_HDR_TSP BIT(1) + +/** Get Optional Feature Capabilities Byte 1 (GETCAPS) Format 1 - HDR-TSL mode bit. */ +#define I3C_CCC_GETCAPS1_HDR_TSL BIT(2) + +/** Get Optional Feature Capabilities Byte 1 (GETCAPS) Format 1 - HDR-BT mode bit. */ #define I3C_CCC_GETCAPS1_HDR_BT BIT(3) /** - * @brief Get Optional Feature Capabilities (GETCAPS) - HDR Mode + * @brief Get Optional Feature Capabilities Byte 1 (GETCAPS) - HDR Mode * * Get the bit corresponding to HDR mode. * @@ -868,53 +986,53 @@ struct i3c_ccc_getcaps { */ #define I3C_CCC_GETCAPS1_HDR_MODE(x) BIT(x) -/** Get Optional Feature Capabilities (GETCAPS) Format 1 - HDR Mode 0. */ +/** Get Optional Feature Capabilities Byte 1 (GETCAPS) Format 1 - HDR Mode 0. */ #define I3C_CCC_GETCAPS1_HDR_MODE0 BIT(0) -/** Get Optional Feature Capabilities (GETCAPS) Format 1 - HDR Mode 1. */ +/** Get Optional Feature Capabilities Byte 1 (GETCAPS) Format 1 - HDR Mode 1. */ #define I3C_CCC_GETCAPS1_HDR_MODE1 BIT(1) -/** Get Optional Feature Capabilities (GETCAPS) Format 1 - HDR Mode 2. */ +/** Get Optional Feature Capabilities Byte 1 (GETCAPS) Format 1 - HDR Mode 2. */ #define I3C_CCC_GETCAPS1_HDR_MODE2 BIT(2) -/** Get Optional Feature Capabilities (GETCAPS) Format 1 - HDR Mode 3. */ +/** Get Optional Feature Capabilities Byte 1 (GETCAPS) Format 1 - HDR Mode 3. */ #define I3C_CCC_GETCAPS1_HDR_MODE3 BIT(3) -/** Get Optional Feature Capabilities (GETCAPS) Format 1 - HDR Mode 4. */ +/** Get Optional Feature Capabilities Byte 1 (GETCAPS) Format 1 - HDR Mode 4. */ #define I3C_CCC_GETCAPS1_HDR_MODE4 BIT(4) -/** Get Optional Feature Capabilities (GETCAPS) Format 1 - HDR Mode 5. */ +/** Get Optional Feature Capabilities Byte 1 (GETCAPS) Format 1 - HDR Mode 5. */ #define I3C_CCC_GETCAPS1_HDR_MODE5 BIT(5) -/** Get Optional Feature Capabilities (GETCAPS) Format 1 - HDR Mode 6. */ +/** Get Optional Feature Capabilities Byte 1 (GETCAPS) Format 1 - HDR Mode 6. */ #define I3C_CCC_GETCAPS1_HDR_MODE6 BIT(6) -/** Get Optional Feature Capabilities (GETCAPS) Format 1 - HDR Mode 7. */ +/** Get Optional Feature Capabilities Byte 1 (GETCAPS) Format 1 - HDR Mode 7. */ #define I3C_CCC_GETCAPS1_HDR_MODE7 BIT(7) -/** Get Optional Feature Capabilities (GETCAPS) Format 2 - HDR-DDR Write Abort bit. */ +/** Get Optional Feature Capabilities Byte 2 (GETCAPS) Format 1 - HDR-DDR Write Abort bit. */ #define I3C_CCC_GETCAPS2_HDRDDR_WRITE_ABORT BIT(6) -/** Get Optional Feature Capabilities (GETCAPS) Format 2 - HDR-DDR Abort CRC bit. */ +/** Get Optional Feature Capabilities Byte 2 (GETCAPS) Format 1 - HDR-DDR Abort CRC bit. */ #define I3C_CCC_GETCAPS2_HDRDDR_ABORT_CRC BIT(7) /** - * @brief Get Optional Feature Capabilities (GETCAPS) Format 2 - + * @brief Get Optional Feature Capabilities Byte 2 (GETCAPS) Format 1 - * Group Address Capabilities bit shift value. */ #define I3C_CCC_GETCAPS2_GRPADDR_CAP_SHIFT 4 /** - * @brief Get Optional Feature Capabilities (GETCAPS) Format 2 - + * @brief Get Optional Feature Capabilities Byte 2 (GETCAPS) Format 1 - * Group Address Capabilities bitmask. */ #define I3C_CCC_GETCAPS2_GRPADDR_CAP_MASK \ (0x03U << I3C_CCC_GETCAPS2_GRPADDR_CAP_SHIFT) /** - * @brief Get Optional Feature Capabilities (GETCAPS) Format 2 - Group Address Capabilities. + * @brief Get Optional Feature Capabilities Byte 2 (GETCAPS) Format 1 - Group Address Capabilities. * - * Obtain Group Address Capabilities value from GETCAPS Format 2 value + * Obtain Group Address Capabilities value from GETCAPS Format 1 value * obtained via GETCAPS. * * @param getcaps2 GETCAPS2 value. @@ -925,23 +1043,23 @@ struct i3c_ccc_getcaps { >> I3C_CCC_GETCAPS_GRPADDR_CAP_SHIFT) /** - * @brief Get Optional Feature Capabilities (GETCAPS) Format 2 - + * @brief Get Optional Feature Capabilities Byte 2 (GETCAPS) Format 1 - * I3C 1.x Specification Version bit shift value. */ #define I3C_CCC_GETCAPS2_SPEC_VER_SHIFT 0 /** - * @brief Get Optional Feature Capabilities (GETCAPS) Format 2 - + * @brief Get Optional Feature Capabilities Byte 2 (GETCAPS) Format 1 - * I3C 1.x Specification Version bitmask. */ #define I3C_CCC_GETCAPS2_SPEC_VER_MASK \ (0x0FU << I3C_CCC_GETCAPS2_SPEC_VER_SHIFT) /** - * @brief Get Optional Feature Capabilities (GETCAPS) Format 2 - + * @brief Get Optional Feature Capabilities Byte 2 (GETCAPS) Format 1 - * I3C 1.x Specification Version. * - * Obtain I3C 1.x Specification Version value from GETCAPS Format 2 value + * Obtain I3C 1.x Specification Version value from GETCAPS Format 1 value * obtained via GETCAPS. * * @param getcaps2 GETCAPS2 value. @@ -952,47 +1070,197 @@ struct i3c_ccc_getcaps { >> I3C_CCC_GETCAPS_SPEC_VER_SHIFT) /** - * @brief Get Optional Feature Capabilities (GETCAPS) Format 3 - + * @brief Get Optional Feature Capabilities Byte 3 (GETCAPS) Format 1 - * Multi-Lane Data Transfer Support bit. */ #define I3C_CCC_GETCAPS3_MLANE_SUPPORT BIT(0) /** - * @brief Get Optional Feature Capabilities (GETCAPS) Format 3 - + * @brief Get Optional Feature Capabilities Byte 3 (GETCAPS) Format 1 - * Device to Device Transfer (D2DXFER) Support bit. */ #define I3C_CCC_GETCAPS3_D2DXFER_SUPPORT BIT(1) /** - * @brief Get Optional Feature Capabilities (GETCAPS) Format 3 - + * @brief Get Optional Feature Capabilities Byte 3 (GETCAPS) Format 1 - * Device to Device Transfer (D2DXFER) IBI Capable bit. */ #define I3C_CCC_GETCAPS3_D2DXFER_IBI_CAPABLE BIT(2) /** - * @brief Get Optional Feature Capabilities (GETCAPS) Format 3 - + * @brief Get Optional Feature Capabilities Byte 3 (GETCAPS) Format 1 - * Defining Byte Support in GETCAPS bit. */ #define I3C_CCC_GETCAPS3_GETCAPS_DEFINING_BYTE_SUPPORT BIT(3) /** - * @brief Get Optional Feature Capabilities (GETCAPS) Format 3 - + * @brief Get Optional Feature Capabilities Byte 3 (GETCAPS) Format 1 - * Defining Byte Support in GETSTATUS bit. */ #define I3C_CCC_GETCAPS3_GETSTATUS_DEFINING_BYTE_SUPPORT BIT(4) /** - * @brief Get Optional Feature Capabilities (GETCAPS) Format 3 - + * @brief Get Optional Feature Capabilities Byte 3 (GETCAPS) Format 1 - * HDR-BT CRC-32 Support bit. */ #define I3C_CCC_GETCAPS3_HDRBT_CRC32_SUPPORT BIT(5) /** - * @brief Get Optional Feature Capabilities (GETCAPS) Format 3 - + * @brief Get Optional Feature Capabilities Byte 3 (GETCAPS) Format 1 - * IBI MDB Support for Pending Read Notification bit. */ #define I3C_CCC_GETCAPS3_IBI_MDR_PENDING_READ_NOTIFICATION BIT(6) +/** + * @brief Get Fixed Test Pattern (GETCAPS) Format 2 - + * Fixed Test Pattern Byte 1. + */ +#define I3C_CCC_GETCAPS_TESTPAT1 0xA5 + +/** + * @brief Get Fixed Test Pattern (GETCAPS) Format 2 - + * Fixed Test Pattern Byte 2. + */ +#define I3C_CCC_GETCAPS_TESTPAT2 0x5A + +/** + * @brief Get Fixed Test Pattern (GETCAPS) Format 2 - + * Fixed Test Pattern Byte 3. + */ +#define I3C_CCC_GETCAPS_TESTPAT3 0xA5 + +/** + * @brief Get Fixed Test Pattern (GETCAPS) Format 2 - + * Fixed Test Pattern Byte 4. + */ +#define I3C_CCC_GETCAPS_TESTPAT4 0x5A + +/** + * @brief Get Fixed Test Pattern (GETCAPS) Format 2 - + * Fixed Test Pattern Word in Big Endian. + */ +#define I3C_CCC_GETCAPS_TESTPAT 0xA55AA55A + +/** + * @brief Get Controller Handoff Capabilities Byte 1 (GETCAPS) Format 2 - + * Hot-Join Support. + */ +#define I3C_CCC_GETCAPS_CRCAPS1_HJ_SUPPORT BIT(0) + +/** + * @brief Get Controller Handoff Capabilities Byte 1 (GETCAPS) Format 2 - + * Group Management Support. + */ +#define I3C_CCC_GETCAPS_CRCAPS1_GRP_MANAGEMENT_SUPPORT BIT(1) + +/** + * @brief Get Controller Handoff Capabilities Byte 1 (GETCAPS) Format 2 - + * Multi-Lane Support. + */ +#define I3C_CCC_GETCAPS_CRCAPS1_ML_SUPPORT BIT(2) + +/** + * @brief Get Controller Handoff Capabilities Byte 2 (GETCAPS) Format 2 - + * In-Band Interrupt Support. + */ +#define I3C_CCC_GETCAPS_CRCAPS2_IBI_TIR_SUPPORT BIT(0) + +/** + * @brief Get Controller Handoff Capabilities Byte 2 (GETCAPS) Format 2 - + * Controller Pass-Back. + */ +#define I3C_CCC_GETCAPS_CRCAPS2_CONTROLLER_PASSBACK BIT(1) + +/** + * @brief Get Controller Handoff Capabilities Byte 2 (GETCAPS) Format 2 - + * Deep Sleep Capable. + */ +#define I3C_CCC_GETCAPS_CRCAPS2_DEEP_SLEEP_CAPABLE BIT(2) + +/** + * @brief Get Controller Handoff Capabilities Byte 2 (GETCAPS) Format 2 - + * Deep Sleep Capable. + */ +#define I3C_CCC_GETCAPS_CRCAPS2_DELAYED_CONTROLLER_HANDOFF BIT(3) + +/** Get Capabilities (GETCAPS) - VTCAP1 - Virtual Target Type bit shift value. */ +#define I3C_CCC_GETCAPS_VTCAP1_VITRUAL_TARGET_TYPE_SHIFT 0 + +/** Get Capabilities (GETCAPS) - VTCAP1 - Virtual Target Type bitmask. */ +#define I3C_CCC_GETCAPS_VTCAP1_VITRUAL_TARGET_TYPE_MASK \ + (0x07U << I3C_CCC_GETCAPS_VTCAP1_VITRUAL_TARGET_TYPE_SHIFT) + +/** + * @brief Get Capabilities (GETCAPS) - VTCAP1 - Virtual Target Type + * + * Obtain Virtual Target Type value from VTCAP1 value + * obtained via GETCAPS format 2 VTCAP def byte. + * + * @param vtcap1 VTCAP1 value. + */ +#define I3C_CCC_GETCAPS_VTCAP1_VITRUAL_TARGET_TYPE(vtcap1) \ + (((vtcap1) & \ + I3C_CCC_GETCAPS_VTCAP1_VITRUAL_TARGET_TYPE_MASK) \ + >> I3C_CCC_GETCAPS_VTCAP1_VITRUAL_TARGET_TYPE_SHIFT) + +/** + * @brief Get Virtual Target Capabilities Byte 1 (GETCAPS) Format 2 - + * Side Effects. + */ +#define I3C_CCC_GETCAPS_VTCAP1_SIDE_EFFECTS BIT(4) + +/** + * @brief Get Virtual Target Capabilities Byte 1 (GETCAPS) Format 2 - + * Shared Peripheral Detect. + */ +#define I3C_CCC_GETCAPS_VTCAP1_SHARED_PERIPH_DETECT BIT(5) + +/** Get Capabilities (GETCAPS) - VTCAP2 - Interrupt Requests bit shift value. */ +#define I3C_CCC_GETCAPS_VTCAP2_INTERRUPT_REQUESTS_SHIFT 0 + +/** Get Capabilities (GETCAPS) - VTCAP2 - Interrupt Requests bitmask. */ +#define I3C_CCC_GETCAPS_VTCAP2_INTERRUPT_REQUESTS_MASK \ + (0x03U << I3C_CCC_GETCAPS_VTCAP2_INTERRUPT_REQUESTS_SHIFT) + +/** + * @brief Get Capabilities (GETCAPS) - VTCAP2 - Interrupt Requests + * + * Obtain Interrupt Requests value from VTCAP2 value + * obtained via GETCAPS format 2 VTCAP def byte. + * + * @param vtcap2 VTCAP2 value. + */ +#define I3C_CCC_GETCAPS_VTCAP2_INTERRUPT_REQUESTS(vtcap2) \ + (((vtcap2) & \ + I3C_CCC_GETCAPS_VTCAP2_INTERRUPT_REQUESTS_MASK) \ + >> I3C_CCC_GETCAPS_VTCAP2_INTERRUPT_REQUESTS_SHIFT) + +/** + * @brief Get Virtual Target Capabilities Byte 2 (GETCAPS) Format 2 - + * Address Remapping. + */ +#define I3C_CCC_GETCAPS_VTCAP2_ADDRESS_REMAPPING BIT(2) + +/** Get Capabilities (GETCAPS) - VTCAP2 - Bus Context and Condition bit shift value. */ +#define I3C_CCC_GETCAPS_VTCAP2_BUS_CONTEXT_AND_COND_SHIFT 3 + +/** Get Capabilities (GETCAPS) - VTCAP2 - Bus Context and Condition bitmask. */ +#define I3C_CCC_GETCAPS_VTCAP2_BUS_CONTEXT_AND_COND_MASK \ + (0x03U << I3C_CCC_GETCAPS_VTCAP2_BUS_CONTEXT_AND_COND_SHIFT) + +/** + * @brief Get Capabilities (GETCAPS) - VTCAP2 - Bus Context and Condition + * + * Obtain Bus Context and Condition value from VTCAP2 value + * obtained via GETCAPS format 2 VTCAP def byte. + * + * @param vtcap2 VTCAP2 value. + */ +#define I3C_CCC_GETCAPS_VTCAP2_BUS_CONTEXT_AND_COND(vtcap2) \ + (((vtcap2) & \ + I3C_CCC_GETCAPS_VTCAP2_BUS_CONTEXT_AND_COND_MASK) \ + >> I3C_CCC_GETCAPS_VTCAP2_BUS_CONTEXT_AND_COND_SHIFT) + /** * @brief Enum for I3C Reset Action (RSTACT) Defining Byte Values. */ @@ -1309,6 +1577,65 @@ static inline int i3c_ccc_do_getstatus_fmt2(const struct i3c_device_desc *target GETSTATUS_FORMAT_2, defbyte); } +/** + * @brief Single target GETCAPS to Get Target Status. + * + * Helper function to do GETCAPS (Get Capabilities) of + * one target. + * + * This should only be supported if Advanced Capabilities Bit of + * the BCR is set + * + * @param[in] target Pointer to the target device descriptor. + * @param[out] caps Pointer to GETCAPS payload. + * @param[in] fmt Which GETCAPS to use. + * @param[in] defbyte Defining Byte if using format 2. + * + * @return @see i3c_do_ccc + */ +int i3c_ccc_do_getcaps(const struct i3c_device_desc *target, + union i3c_ccc_getcaps *caps, + enum i3c_ccc_getcaps_fmt fmt, + enum i3c_ccc_getcaps_defbyte defbyte); + +/** + * @brief Single target GETCAPS to Get Capabilities (Format 1). + * + * Helper function to do GETCAPS (Get Capabilities, format 1) of + * one target. + * + * @param[in] target Pointer to the target device descriptor. + * @param[out] caps Pointer to GETCAPS payload. + * + * @return @see i3c_do_ccc + */ +static inline int i3c_ccc_do_getcaps_fmt1(const struct i3c_device_desc *target, + union i3c_ccc_getcaps *caps) +{ + return i3c_ccc_do_getcaps(target, caps, + GETCAPS_FORMAT_1, + GETCAPS_FORMAT_2_INVALID); +} + +/** + * @brief Single target GETCAPS to Get Capabilities (Format 2). + * + * Helper function to do GETCAPS (Get Capabilities, format 2) of + * one target. + * + * @param[in] target Pointer to the target device descriptor. + * @param[out] caps Pointer to GETCAPS payload. + * @param[in] defbyte Defining Byte for GETCAPS format 2. + * + * @return @see i3c_do_ccc + */ +static inline int i3c_ccc_do_getcaps_fmt2(const struct i3c_device_desc *target, + union i3c_ccc_getcaps *caps, + enum i3c_ccc_getcaps_defbyte defbyte) +{ + return i3c_ccc_do_getcaps(target, caps, + GETCAPS_FORMAT_2, defbyte); +} #ifdef __cplusplus } diff --git a/include/zephyr/drivers/i3c/target_device.h b/include/zephyr/drivers/i3c/target_device.h index ca699814078..1f4df8409ad 100644 --- a/include/zephyr/drivers/i3c/target_device.h +++ b/include/zephyr/drivers/i3c/target_device.h @@ -211,7 +211,7 @@ struct i3c_target_callbacks { int (*stop_cb)(struct i3c_target_config *config); }; -struct i3c_target_driver_api { +__subsystem struct i3c_target_driver_api { int (*driver_register)(const struct device *dev); int (*driver_unregister)(const struct device *dev); }; diff --git a/include/zephyr/drivers/interrupt_controller/intel_vtd.h b/include/zephyr/drivers/interrupt_controller/intel_vtd.h index 5e6044d829e..b91834c74a8 100644 --- a/include/zephyr/drivers/interrupt_controller/intel_vtd.h +++ b/include/zephyr/drivers/interrupt_controller/intel_vtd.h @@ -45,7 +45,7 @@ typedef void (*vtd_set_irte_msi_f)(const struct device *dev, typedef bool (*vtd_irte_is_msi_f)(const struct device *dev, uint8_t irte_idx); -struct vtd_driver_api { +__subsystem struct vtd_driver_api { vtd_alloc_entries_f allocate_entries; vtd_remap_msi_f remap_msi; vtd_remap_f remap; diff --git a/include/zephyr/drivers/interrupt_controller/loapic.h b/include/zephyr/drivers/interrupt_controller/loapic.h index 564355dfefa..75a47955bc6 100644 --- a/include/zephyr/drivers/interrupt_controller/loapic.h +++ b/include/zephyr/drivers/interrupt_controller/loapic.h @@ -60,11 +60,11 @@ extern "C" { DEVICE_MMIO_TOPLEVEL_DECLARE(LOAPIC_REGS_STR); -extern uint32_t z_loapic_irq_base(void); -extern void z_loapic_enable(unsigned char cpu_number); -extern void z_loapic_int_vec_set(unsigned int irq, unsigned int vector); -extern void z_loapic_irq_enable(unsigned int irq); -extern void z_loapic_irq_disable(unsigned int irq); +uint32_t z_loapic_irq_base(void); +void z_loapic_enable(unsigned char cpu_number); +void z_loapic_int_vec_set(unsigned int irq, unsigned int vector); +void z_loapic_irq_enable(unsigned int irq); +void z_loapic_irq_disable(unsigned int irq); /** * @brief Read 64-bit value from the local APIC in x2APIC mode. diff --git a/include/zephyr/drivers/led/ht16k33.h b/include/zephyr/drivers/led/ht16k33.h deleted file mode 100644 index bc43b52a4be..00000000000 --- a/include/zephyr/drivers/led/ht16k33.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2019 Henrik Brix Andersen - * - * SPDX-License-Identifier: Apache-2.0 - */ - - -#ifndef ZEPHYR_INCLUDE_DRIVERS_LED_HT16K33_H_ -#define ZEPHYR_INCLUDE_DRIVERS_LED_HT16K33_H_ - -#include - -/** - * Register a HT16K33 keyscan device to be notified of relevant - * keyscan events by the keyscan interrupt thread in the HT16K33 - * parent driver. - * - * @param parent HT16K33 parent device. - * @param child HT16K33 child device. - * @param callback Keyscan callback function. - * @return 0 if successful, negative errno code on failure. - */ -int ht16k33_register_keyscan_callback(const struct device *parent, - const struct device *child, - kscan_callback_t callback); - -#endif /* ZEPHYR_INCLUDE_DRIVERS_LED_HT16K33_H_ */ diff --git a/include/zephyr/drivers/led_strip.h b/include/zephyr/drivers/led_strip.h index 210af850aed..7c297cbc6cd 100644 --- a/include/zephyr/drivers/led_strip.h +++ b/include/zephyr/drivers/led_strip.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2017 Linaro Limited + * Copyright (c) 2024 Jamie McCrae * * SPDX-License-Identifier: Apache-2.0 */ @@ -22,6 +23,7 @@ * @{ */ +#include #include #include @@ -71,66 +73,101 @@ typedef int (*led_api_update_channels)(const struct device *dev, uint8_t *channels, size_t num_channels); +/** + * @typedef led_api_length + * @brief Callback API for getting length of an LED strip. + * + * @see led_strip_length() for argument descriptions. + */ +typedef size_t (*led_api_length)(const struct device *dev); + /** * @brief LED strip driver API * * This is the mandatory API any LED strip driver needs to expose. */ -struct led_strip_driver_api { +__subsystem struct led_strip_driver_api { led_api_update_rgb update_rgb; led_api_update_channels update_channels; + led_api_length length; }; /** - * @brief Update an LED strip made of RGB pixels + * @brief Mandatory function to update an LED strip with the given RGB array. * - * Important: - * This routine may overwrite @a pixels. + * @param dev LED strip device. + * @param pixels Array of pixel data. + * @param num_pixels Length of pixels array. * - * This routine immediately updates the strip display according to the - * given pixels array. + * @retval 0 on success. + * @retval -errno negative errno code on failure. * - * @param dev LED strip device - * @param pixels Array of pixel data - * @param num_pixels Length of pixels array - * @return 0 on success, negative on error - * @warning May overwrite @a pixels + * @warning This routine may overwrite @a pixels. */ static inline int led_strip_update_rgb(const struct device *dev, struct led_rgb *pixels, - size_t num_pixels) { + size_t num_pixels) +{ const struct led_strip_driver_api *api = (const struct led_strip_driver_api *)dev->api; + /* Allow for out-of-tree drivers that do not have this function for 2 Zephyr releases + * until making it mandatory, function added after Zephyr 3.6 + */ + if (api->length != NULL) { + /* Ensure supplied pixel size is valid for this device */ + if (api->length(dev) < num_pixels) { + return -ERANGE; + } + } + return api->update_rgb(dev, pixels, num_pixels); } /** - * @brief Update an LED strip on a per-channel basis. + * @brief Optional function to update an LED strip with the given channel array + * (each channel byte corresponding to an individually addressable color + * channel or LED. Channels are updated linearly in strip order. * - * Important: - * This routine may overwrite @a channels. + * @param dev LED strip device. + * @param channels Array of per-channel data. + * @param num_channels Length of channels array. * - * This routine immediately updates the strip display according to the - * given channels array. Each channel byte corresponds to an - * individually addressable color channel or LED. Channels - * are updated linearly in strip order. + * @retval 0 on success. + * @retval -ENOSYS if not implemented. + * @retval -errno negative errno code on other failure. * - * @param dev LED strip device - * @param channels Array of per-channel data - * @param num_channels Length of channels array - * @return 0 on success, negative on error - * @warning May overwrite @a channels + * @warning This routine may overwrite @a channels. */ static inline int led_strip_update_channels(const struct device *dev, uint8_t *channels, - size_t num_channels) { + size_t num_channels) +{ const struct led_strip_driver_api *api = (const struct led_strip_driver_api *)dev->api; + if (api->update_channels == NULL) { + return -ENOSYS; + } + return api->update_channels(dev, channels, num_channels); } +/** + * @brief Mandatory function to get chain length (in pixels) of an LED strip device. + * + * @param dev LED strip device. + * + * @retval Length of LED strip device. + */ +static inline size_t led_strip_length(const struct device *dev) +{ + const struct led_strip_driver_api *api = + (const struct led_strip_driver_api *)dev->api; + + return api->length(dev); +} + #ifdef __cplusplus } #endif diff --git a/include/zephyr/drivers/loopback_disk.h b/include/zephyr/drivers/loopback_disk.h new file mode 100644 index 00000000000..56bc2393d94 --- /dev/null +++ b/include/zephyr/drivers/loopback_disk.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2023 Embedded Solutions GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_LOOPBACK_DISK_ACCESS_H_ +#define ZEPHYR_INCLUDE_DRIVERS_LOOPBACK_DISK_ACCESS_H_ + +#include +#include + +/** + * @brief Context object for an active loopback disk device + */ +struct loopback_disk_access { + struct disk_info info; + const char *file_path; + struct fs_file_t file; + size_t num_sectors; +}; + +/** + * @brief Register a loopback disk device + * + * Registers a new loopback disk deviced backed by a file at the specified path. + * + * @details + * @p All parameters (ctx, file_path and disk_access_name) must point to data that will remain valid + * until the disk access is unregistered. This is trivially true for file_path and disk_access_name + * if they are string literals, but care must be taken for ctx, as well as for file_path and + * disk_access_name if they are constructed dynamically. + * + * @param ctx Preallocated context structure + * @param file_path Path to backing file + * @param disk_access_name Name of the created disk access (for disk_access_*() functions) + * + * @retval 0 on success; + * @retval <0 negative errno code, depending on file system of the backing file. + */ +int loopback_disk_access_register(struct loopback_disk_access *ctx, const char *file_path, + const char *disk_access_name); + +/** + * @brief Unregister a previously registered loopback disk device + * + * Cleans up resources used by the disk access. + * + * @param ctx Context structure previously passed to a successful invocation of + * loopback_disk_access_register() + * + * @retval 0 on success; + * @retval <0 negative errno code, depending on file system of the backing file. + */ +int loopback_disk_access_unregister(struct loopback_disk_access *ctx); + +#endif /* ZEPHYR_INCLUDE_DRIVERS_LOOPBACK_DISK_ACCESS_H_ */ diff --git a/include/zephyr/drivers/lora.h b/include/zephyr/drivers/lora.h index a96ca885496..90706595a80 100644 --- a/include/zephyr/drivers/lora.h +++ b/include/zephyr/drivers/lora.h @@ -179,7 +179,7 @@ typedef int (*lora_api_recv_async)(const struct device *dev, lora_recv_cb cb); typedef int (*lora_api_test_cw)(const struct device *dev, uint32_t frequency, int8_t tx_power, uint16_t duration); -struct lora_driver_api { +__subsystem struct lora_driver_api { lora_api_config config; lora_api_send send; lora_api_send_async send_async; diff --git a/include/zephyr/drivers/mdio.h b/include/zephyr/drivers/mdio.h index 687064acae3..fe165bcb991 100644 --- a/include/zephyr/drivers/mdio.h +++ b/include/zephyr/drivers/mdio.h @@ -73,7 +73,9 @@ static inline void z_impl_mdio_bus_enable(const struct device *dev) const struct mdio_driver_api *api = (const struct mdio_driver_api *)dev->api; - api->bus_enable(dev); + if (api->bus_enable != NULL) { + api->bus_enable(dev); + } } /** @@ -89,7 +91,9 @@ static inline void z_impl_mdio_bus_disable(const struct device *dev) const struct mdio_driver_api *api = (const struct mdio_driver_api *)dev->api; - api->bus_disable(dev); + if (api->bus_disable != NULL) { + api->bus_disable(dev); + } } /** diff --git a/include/zephyr/drivers/mfd/adp5585.h b/include/zephyr/drivers/mfd/adp5585.h new file mode 100644 index 00000000000..abac20bcd51 --- /dev/null +++ b/include/zephyr/drivers/mfd/adp5585.h @@ -0,0 +1,126 @@ +/* + * Copyright 2024 NXP + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_MFD_ADP5585_H_ +#define ZEPHYR_INCLUDE_DRIVERS_MFD_ADP5585_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#define ADP5585_ID 0x00 +#define ADP5585_INT_STATUS 0x01 +#define ADP5585_STATUS 0x02 +#define ADP5585_FIFO_1 0x03 +#define ADP5585_FIFO_2 0x04 +#define ADP5585_FIFO_3 0x05 +#define ADP5585_FIFO_4 0x06 +#define ADP5585_FIFO_5 0x07 +#define ADP5585_FIFO_6 0x08 +#define ADP5585_FIFO_7 0x09 +#define ADP5585_FIFO_8 0x0A +#define ADP5585_FIFO_9 0x0B +#define ADP5585_FIFO_10 0x0C +#define ADP5585_FIFO_11 0x0D +#define ADP5585_FIFO_12 0x0E +#define ADP5585_FIFO_13 0x0F +#define ADP5585_FIFO_14 0x10 +#define ADP5585_FIFO_15 0x11 +#define ADP5585_FIFO_16 0x12 +#define ADP5585_GPI_INT_STAT_A 0x13 +#define ADP5585_GPI_INT_STAT_B 0x14 +#define ADP5585_GPI_STATUS_A 0x15 +#define ADP5585_GPI_STATUS_B 0x16 +#define ADP5585_RPULL_CONFIG_A 0x17 +#define ADP5585_RPULL_CONFIG_B 0x18 +#define ADP5585_RPULL_CONFIG_C 0x19 +#define ADP5585_RPULL_CONFIG_D 0x1A +#define ADP5585_GPI_INT_LEVEL_A 0x1B +#define ADP5585_GPI_INT_LEVEL_B 0x1C +#define ADP5585_GPI_EVENT_EN_A 0x1D +#define ADP5585_GPI_EVENT_EN_B 0x1E +#define ADP5585_GPI_INTERRUPT_EN_A 0x1F +#define ADP5585_GPI_INTERRUPT_EN_B 0x20 +#define ADP5585_DEBOUNCE_DIS_A 0x21 +#define ADP5585_DEBOUNCE_DIS_B 0x22 +#define ADP5585_GPO_DATA_OUT_A 0x23 +#define ADP5585_GPO_DATA_OUT_B 0x24 +#define ADP5585_GPO_OUT_MODE_A 0x25 +#define ADP5585_GPO_OUT_MODE_B 0x26 +#define ADP5585_GPIO_DIRECTION_A 0x27 +#define ADP5585_GPIO_DIRECTION_B 0x28 +#define ADP5585_RESET1_EVENT_A 0x29 +#define ADP5585_RESET1_EVENT_B 0x2A +#define ADP5585_RESET1_EVENT_C 0x2B +#define ADP5585_RESET2_EVENT_A 0x2C +#define ADP5585_RESET2_EVENT_B 0x2D +#define ADP5585_RESET_CFG 0x2E +#define ADP5585_PWM_OFFT_LOW 0x2F +#define ADP5585_PWM_OFFT_HIGH 0x30 +#define ADP5585_PWM_ONT_LOW 0x31 +#define ADP5585_PWM_ONT_HIGH 0x32 +#define ADP5585_PWM_CFG 0x33 +#define ADP5585_LOGIC_CFG 0x34 +#define ADP5585_LOGIC_FF_CFG 0x35 +#define ADP5585_LOGIC_INT_EVENT_EN 0x36 +#define ADP5585_POLL_PTIME_CFG 0x37 +#define ADP5585_PIN_CONFIG_A 0x38 +#define ADP5585_PIN_CONFIG_B 0x39 +#define ADP5585_PIN_CONFIG_C 0x3A +#define ADP5585_GENERAL_CFG 0x3B +#define ADP5585_INT_EN 0x3C + +/* ID Register */ +#define ADP5585_DEVICE_ID_MASK 0xF +#define ADP5585_MAN_ID_MASK 0xF +#define ADP5585_MAN_ID_SHIFT 4 +#define ADP5585_MAN_ID 0x02 + +#define ADP5585_PWM_CFG_EN 0x1 +#define ADP5585_PWM_CFG_MODE 0x2 +#define ADP5585_PIN_CONFIG_R3_PWM 0x8 +#define ADP5585_PIN_CONFIG_R3_MASK 0xC +#define ADP5585_GENERAL_CFG_OSC_EN 0x80 + +/* INT_EN and INT_STATUS Register */ +#define ADP5585_INT_EVENT (1U << 0) +#define ADP5585_INT_GPI (1U << 1) +#define ADP5585_INT_OVERFLOW (1U << 2) +#define ADP5585_INT_LOGIC (1U << 4) + +#define ADP5585_REG_MASK 0xFF + +struct mfd_adp5585_config { + struct gpio_dt_spec reset_gpio; + struct gpio_dt_spec nint_gpio; + struct i2c_dt_spec i2c_bus; +}; + +struct mfd_adp5585_data { + struct k_work work; + struct k_sem lock; + const struct device *dev; + struct { +#ifdef CONFIG_GPIO_ADP5585 + const struct device *gpio_dev; +#endif /* CONFIG_GPIO_ADP5585 */ + } child; + struct gpio_callback int_gpio_cb; +}; + +/** + * @brief Forward declaration of child device interrupt + * handler + */ +#ifdef CONFIG_GPIO_ADP5585 +void gpio_adp5585_irq_handler(const struct device *dev); +#endif /* CONFIG_GPIO_ADP5585 */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_DRIVERS_MFD_AD5952_H_ */ diff --git a/include/zephyr/drivers/mipi_dbi.h b/include/zephyr/drivers/mipi_dbi.h index d0a75e18058..d6ffcaf335d 100644 --- a/include/zephyr/drivers/mipi_dbi.h +++ b/include/zephyr/drivers/mipi_dbi.h @@ -34,51 +34,12 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { #endif -/** - * SPI 3 wire (Type C1). Uses 9 write clocks to send a byte of data. - * The bit sent on the 9th clock indicates whether the byte is a - * command or data byte - * - * - * .---. .---. .---. .---. .---. .---. .---. .---. - * SCK -' '---' '---' '---' '---' '---' '---' '---' '--- - * - * -.---.---.---.---.---.---.---.---.---.---.---.---.---.---.---. - * DOUT |D/C| D7| D6| D5| D4| D3| D2| D1| D0|D/C| D7| D6| D5| D4|...| - * -'---'---'---'---'---'---'---'---'---'---'---'---'---'---'---' - * | Word 1 | Word n - * - * -. .-- - * CS '-----------------------------------------------------------' - */ -#define MIPI_DBI_MODE_SPI_3WIRE 0x1 -/** - * SPI 4 wire (Type C3). Uses 8 write clocks to send a byte of data. - * an additional C/D pin will be use to indicate whether the byte is a - * command or data byte - * - * .---. .---. .---. .---. .---. .---. .---. .---. - * SCK -' '---' '---' '---' '---' '---' '---' '---' '--- - * - * -.---.---.---.---.---.---.---.---.---.---.---.---.---.---.---.---. - * DOUT | D7| D6| D5| D4| D3| D2| D1| D0| D7| D6| D5| D4| D3| D2| D1| D0| - * -'---'---'---'---'---'---'---'---'---'---'---'---'---'---'---'---' - * | Word 1 | Word n - * - * -. .-- - * CS '---------------------------------------------------------------' - * - * -.-------------------------------.-------------------------------.- - * CD | D/C | D/C | - * -'-------------------------------'-------------------------------'- - */ -#define MIPI_DBI_MODE_SPI_4WIRE 0x2 - /** * @brief initialize a MIPI DBI SPI configuration struct from devicetree * @@ -94,7 +55,7 @@ extern "C" { { \ .frequency = DT_PROP(node_id, mipi_max_frequency), \ .operation = (operation_) | \ - DT_PROP(node_id, duplex) | \ + DT_PROP_OR(node_id, duplex, 0) | \ COND_CODE_1(DT_PROP(node_id, mipi_cpol), SPI_MODE_CPOL, (0)) | \ COND_CODE_1(DT_PROP(node_id, mipi_cpha), SPI_MODE_CPHA, (0)) | \ COND_CODE_1(DT_PROP(node_id, mipi_hold_cs), SPI_HOLD_ON_CS, (0)), \ @@ -108,6 +69,49 @@ extern "C" { }, \ } +/** + * @brief Initialize a MIPI DBI SPI configuration from devicetree instance + * + * This helper initializes a MIPI DBI SPI configuration from a devicetree + * instance. It is equivalent to MIPI_DBI_SPI_CONFIG_DT(DT_DRV_INST(inst)) + * @param inst Instance number to initialize configuration from + * @param operation_ the desired operation field in the struct spi_config + * @param delay_ the desired delay field in the struct spi_config's + * spi_cs_control, if there is one + */ +#define MIPI_DBI_SPI_CONFIG_DT_INST(inst, operation_, delay_) \ + MIPI_DBI_SPI_CONFIG_DT(DT_DRV_INST(inst), operation_, delay_) + +/** + * @brief Initialize a MIPI DBI configuration from devicetree + * + * This helper allows drivers to initialize a MIPI DBI configuration + * structure from devicetree. It sets the MIPI DBI mode, as well + * as configuration fields in the SPI configuration structure + * @param node_id Devicetree node identifier for the MIPI DBI device to + * initialize + * @param operation_ the desired operation field in the struct spi_config + * @param delay_ the desired delay field in the struct spi_config's + * spi_cs_control, if there is one + */ +#define MIPI_DBI_CONFIG_DT(node_id, operation_, delay_) \ + { \ + .mode = DT_PROP(node_id, mipi_mode), \ + .config = MIPI_DBI_SPI_CONFIG_DT(node_id, operation_, delay_), \ + } + +/** + * @brief Initialize a MIPI DBI configuration from device instance + * + * Equivalent to MIPI_DBI_CONFIG_DT(DT_DRV_INST(inst), operation_, delay_) + * @param inst Instance of the device to initialize a MIPI DBI configuration for + * @param operation_ the desired operation field in the struct spi_config + * @param delay_ the desired delay field in the struct spi_config's + * spi_cs_control, if there is one + */ +#define MIPI_DBI_CONFIG_DT_INST(inst, operation_, delay_) \ + MIPI_DBI_CONFIG_DT(DT_DRV_INST(inst), operation_, delay_) + /** * @brief MIPI DBI controller configuration * @@ -135,6 +139,8 @@ __subsystem struct mipi_dbi_driver_api { struct display_buffer_descriptor *desc, enum display_pixel_format pixfmt); int (*reset)(const struct device *dev, uint32_t delay); + int (*release)(const struct device *dev, + const struct mipi_dbi_config *config); }; /** @@ -142,7 +148,9 @@ __subsystem struct mipi_dbi_driver_api { * * Writes a command, along with an optional data buffer to the display. * If data buffer and buffer length are NULL and 0 respectively, then - * only a command will be sent. + * only a command will be sent. Note that if the SPI configuration passed + * to this function locks the SPI bus, it is the caller's responsibility + * to release it with mipi_dbi_release() * * @param dev mipi dbi controller * @param config MIPI DBI configuration @@ -256,6 +264,35 @@ static inline int mipi_dbi_reset(const struct device *dev, uint32_t delay) return api->reset(dev, delay); } +/** + * @brief Releases a locked MIPI DBI device. + * + * Releases a lock on a MIPI DBI device and/or the device's CS line if and + * only if the given config parameter was the last one to be used in any + * of the above functions, and if it has the SPI_LOCK_ON bit set and/or + * the SPI_HOLD_ON_CS bit set into its operation bits field. + * This lock functions exactly like the SPI lock, and can be used if the caller + * needs to keep CS asserted for multiple transactions, or the MIPI DBI device + * locked. + * @param dev mipi dbi controller + * @param config MIPI DBI configuration + * @retval 0 reset succeeded + * @retval -EIO I/O error + * @retval -ENOSYS not implemented + * @retval -ENOTSUP not supported + */ +static inline int mipi_dbi_release(const struct device *dev, + const struct mipi_dbi_config *config) +{ + const struct mipi_dbi_driver_api *api = + (const struct mipi_dbi_driver_api *)dev->api; + + if (api->release == NULL) { + return -ENOSYS; + } + return api->release(dev, config); +} + #ifdef __cplusplus } #endif diff --git a/include/zephyr/drivers/mm/system_mm.h b/include/zephyr/drivers/mm/system_mm.h index d523b706723..5fd5322ba3f 100644 --- a/include/zephyr/drivers/mm/system_mm.h +++ b/include/zephyr/drivers/mm/system_mm.h @@ -200,7 +200,7 @@ int sys_mm_drv_unmap_page(void *virt); * * @retval 0 if successful * @retval -EINVAL if invalid arguments are provided - * @retval -EFAULT if virtual addresses have already been mapped + * @retval -EFAULT if virtual address is not mapped */ int sys_mm_drv_unmap_region(void *virt, size_t size); diff --git a/include/zephyr/drivers/pcie/endpoint/pcie_ep.h b/include/zephyr/drivers/pcie/endpoint/pcie_ep.h index 43f201ec7b9..ca4316a6672 100644 --- a/include/zephyr/drivers/pcie/endpoint/pcie_ep.h +++ b/include/zephyr/drivers/pcie/endpoint/pcie_ep.h @@ -56,7 +56,7 @@ enum pcie_reset { typedef void (*pcie_ep_reset_callback_t)(void *arg); -struct pcie_ep_driver_api { +__subsystem struct pcie_ep_driver_api { int (*conf_read)(const struct device *dev, uint32_t offset, uint32_t *data); void (*conf_write)(const struct device *dev, uint32_t offset, diff --git a/include/zephyr/drivers/pcie/pcie.h b/include/zephyr/drivers/pcie/pcie.h index ff3cb078064..cb55dffd5b8 100644 --- a/include/zephyr/drivers/pcie/pcie.h +++ b/include/zephyr/drivers/pcie/pcie.h @@ -158,20 +158,6 @@ struct pcie_bar { * These functions are arch-, board-, or SoC-specific. */ -/** - * @brief Look up the BDF based on PCI(e) vendor & device ID - * - * This function is used to look up the BDF for a device given its - * vendor and device ID. - * - * @deprecated - * @see DEVICE_PCIE_DECLARE - * - * @param id PCI(e) vendor & device ID encoded using PCIE_ID() - * @return The BDF for the device, or PCIE_BDF_NONE if it was not found - */ -__deprecated extern pcie_bdf_t pcie_bdf_lookup(pcie_id_t id); - /** * @brief Read a 32-bit word from an endpoint's configuration space. * @@ -235,18 +221,6 @@ struct pcie_scan_opt { */ int pcie_scan(const struct pcie_scan_opt *opt); -/** - * @brief Probe for the presence of a PCI(e) endpoint. - * - * @deprecated - * @see DEVICE_PCIE_DECLARE - * - * @param bdf the endpoint to probe - * @param id the endpoint ID to expect, or PCIE_ID_NONE for "any device" - * @return true if the device is present, false otherwise - */ -__deprecated extern bool pcie_probe(pcie_bdf_t bdf, pcie_id_t id); - /** * @brief Get the MBAR at a specific BAR index * @param bdf the PCI(e) endpoint diff --git a/include/zephyr/drivers/reset.h b/include/zephyr/drivers/reset.h index 4e601ea8f9d..c892b530076 100644 --- a/include/zephyr/drivers/reset.h +++ b/include/zephyr/drivers/reset.h @@ -16,7 +16,7 @@ * @brief Reset Controller Interface * @defgroup reset_controller_interface Reset Controller Interface * @since 3.1 - * @version 0.1.0 + * @version 0.2.0 * @ingroup io_interfaces * @{ */ @@ -74,6 +74,27 @@ struct reset_dt_spec { .id = DT_RESET_ID_BY_IDX(node_id, idx) \ } +/** + * @brief Like RESET_DT_SPEC_GET_BY_IDX(), with a fallback to a default value + * + * If the devicetree node identifier 'node_id' refers to a node with a + * 'resets' property, this expands to + * RESET_DT_SPEC_GET_BY_IDX(node_id, idx). The @p + * default_value parameter is not expanded in this case. + * + * Otherwise, this expands to @p default_value. + * + * @param node_id devicetree node identifier + * @param idx logical index into the 'resets' property + * @param default_value fallback value to expand to + * @return static initializer for a struct reset_dt_spec for the property, + * or default_value if the node or property do not exist + */ +#define RESET_DT_SPEC_GET_BY_IDX_OR(node_id, idx, default_value) \ + COND_CODE_1(DT_NODE_HAS_PROP(node_id, resets), \ + (RESET_DT_SPEC_GET_BY_IDX(node_id, idx)), \ + (default_value)) + /** * @brief Equivalent to RESET_DT_SPEC_GET_BY_IDX(node_id, 0). * @@ -84,6 +105,18 @@ struct reset_dt_spec { #define RESET_DT_SPEC_GET(node_id) \ RESET_DT_SPEC_GET_BY_IDX(node_id, 0) +/** + * @brief Equivalent to + * RESET_DT_SPEC_GET_BY_IDX_OR(node_id, 0, default_value). + * + * @param node_id devicetree node identifier + * @param default_value fallback value to expand to + * @return static initializer for a struct reset_dt_spec for the property, + * or default_value if the node or property do not exist + */ +#define RESET_DT_SPEC_GET_OR(node_id, default_value) \ + RESET_DT_SPEC_GET_BY_IDX_OR(node_id, 0, default_value) + /** * @brief Static initializer for a @p reset_dt_spec from a DT_DRV_COMPAT * instance's Reset Controller property at an index. @@ -96,6 +129,21 @@ struct reset_dt_spec { #define RESET_DT_SPEC_INST_GET_BY_IDX(inst, idx) \ RESET_DT_SPEC_GET_BY_IDX(DT_DRV_INST(inst), idx) +/** + * @brief Static initializer for a @p reset_dt_spec from a DT_DRV_COMPAT + * instance's 'resets' property at an index, with fallback + * + * @param inst DT_DRV_COMPAT instance number + * @param idx logical index into the 'resets' property + * @param default_value fallback value to expand to + * @return static initializer for a struct reset_dt_spec for the property, + * or default_value if the node or property do not exist + */ +#define RESET_DT_SPEC_INST_GET_BY_IDX_OR(inst, idx, default_value) \ + COND_CODE_1(DT_PROP_HAS_IDX(DT_DRV_INST(inst), resets, idx), \ + (RESET_DT_SPEC_GET_BY_IDX(DT_DRV_INST(inst), idx)), \ + (default_value)) + /** * @brief Equivalent to RESET_DT_SPEC_INST_GET_BY_IDX(inst, 0). * @@ -106,6 +154,18 @@ struct reset_dt_spec { #define RESET_DT_SPEC_INST_GET(inst) \ RESET_DT_SPEC_INST_GET_BY_IDX(inst, 0) +/** + * @brief Equivalent to + * RESET_DT_SPEC_INST_GET_BY_IDX_OR(node_id, 0, default_value). + * + * @param inst DT_DRV_COMPAT instance number + * @param default_value fallback value to expand to + * @return static initializer for a struct reset_dt_spec for the property, + * or default_value if the node or property do not exist + */ +#define RESET_DT_SPEC_INST_GET_OR(inst, default_value) \ + RESET_DT_SPEC_INST_GET_BY_IDX_OR(inst, 0, default_value) + /** @cond INTERNAL_HIDDEN */ /** diff --git a/include/zephyr/drivers/sensor.h b/include/zephyr/drivers/sensor.h index f110a479896..2bd6b5c5b89 100644 --- a/include/zephyr/drivers/sensor.h +++ b/include/zephyr/drivers/sensor.h @@ -418,6 +418,40 @@ typedef int (*sensor_channel_get_t)(const struct device *dev, enum sensor_channel chan, struct sensor_value *val); +/** + * @brief Sensor Channel Specification + * + * A sensor channel specification is a unique identifier per sensor device describing + * a measurement channel. + * + * @note Typically passed by value as the size of a sensor_chan_spec is a single word. + */ +struct sensor_chan_spec { + uint16_t chan_type; /**< A sensor channel type */ + uint16_t chan_idx; /**< A sensor channel index */ +}; + +/** @cond INTERNAL_HIDDEN */ +/* Ensure sensor_chan_spec is sensibly sized to pass by value */ +BUILD_ASSERT(sizeof(struct sensor_chan_spec) <= sizeof(uintptr_t), + "sensor_chan_spec size should be equal or less than the size of a machine word"); +/** @endcond */ + +/** + * @brief Check if channel specs are equivalent + * + * @param chan_spec0 First chan spec + * @param chan_spec1 Second chan spec + * @retval true If equivalent + * @retval false If not equivalent + */ +static inline bool sensor_chan_spec_eq(struct sensor_chan_spec chan_spec0, + struct sensor_chan_spec chan_spec1) +{ + return chan_spec0.chan_type == chan_spec1.chan_type && + chan_spec0.chan_idx == chan_spec1.chan_idx; +} + /** * @brief Decodes a single raw data buffer * @@ -430,13 +464,12 @@ struct sensor_decoder_api { * * @param[in] buffer The buffer provided on the @ref rtio context. * @param[in] channel The channel to get the count for - * @param[in] channel_idx The index of the channel * @param[out] frame_count The number of frames on the buffer (at least 1) * @return 0 on success * @return -ENOTSUP if the channel/channel_idx aren't found */ - int (*get_frame_count)(const uint8_t *buffer, enum sensor_channel channel, - size_t channel_idx, uint16_t *frame_count); + int (*get_frame_count)(const uint8_t *buffer, struct sensor_chan_spec channel, + uint16_t *frame_count); /** * @brief Get the size required to decode a given channel @@ -450,7 +483,8 @@ struct sensor_decoder_api { * @return 0 on success * @return -ENOTSUP if the channel is not supported */ - int (*get_size_info)(enum sensor_channel channel, size_t *base_size, size_t *frame_size); + int (*get_size_info)(struct sensor_chan_spec channel, size_t *base_size, + size_t *frame_size); /** * @brief Decode up to @p max_count samples from the buffer @@ -470,7 +504,6 @@ struct sensor_decoder_api { * * @param[in] buffer The buffer provided on the @ref rtio context * @param[in] channel The channel to decode - * @param[in] channel_idx The index of the channel * @param[in,out] fit The current frame iterator * @param[in] max_count The maximum number of channels to decode. * @param[out] data_out The decoded data @@ -478,8 +511,8 @@ struct sensor_decoder_api { * @return >0 the number of decoded frames * @return <0 on error */ - int (*decode)(const uint8_t *buffer, enum sensor_channel channel, size_t channel_idx, - uint32_t *fit, uint16_t max_count, void *data_out); + int (*decode)(const uint8_t *buffer, struct sensor_chan_spec channel, uint32_t *fit, + uint16_t max_count, void *data_out); /** * @brief Check if the given trigger type is present @@ -518,20 +551,18 @@ struct sensor_decoder_api { struct sensor_decode_context { const struct sensor_decoder_api *decoder; const uint8_t *buffer; - enum sensor_channel channel; - size_t channel_idx; + struct sensor_chan_spec channel; uint32_t fit; }; /** * @brief Initialize a sensor_decode_context */ -#define SENSOR_DECODE_CONTEXT_INIT(decoder_, buffer_, channel_, channel_index_) \ +#define SENSOR_DECODE_CONTEXT_INIT(decoder_, buffer_, channel_type_, channel_index_) \ { \ .decoder = (decoder_), \ .buffer = (buffer_), \ - .channel = (channel_), \ - .channel_idx = (channel_index_), \ + .channel = {.chan_type = (channel_type_), .chan_idx = (channel_index_)}, \ .fit = 0, \ } @@ -545,11 +576,10 @@ struct sensor_decode_context { */ static inline int sensor_decode(struct sensor_decode_context *ctx, void *out, uint16_t max_count) { - return ctx->decoder->decode(ctx->buffer, ctx->channel, ctx->channel_idx, &ctx->fit, - max_count, out); + return ctx->decoder->decode(ctx->buffer, ctx->channel, &ctx->fit, max_count, out); } -int sensor_natively_supported_channel_size_info(enum sensor_channel channel, size_t *base_size, +int sensor_natively_supported_channel_size_info(struct sensor_chan_spec channel, size_t *base_size, size_t *frame_size); /** @@ -582,6 +612,7 @@ struct sensor_stream_trigger { { \ .trigger = (_trigger), .opt = (_opt), \ } + /* * Internal data structure used to store information about the IODevice for async reading and * streaming sensor data. @@ -590,7 +621,7 @@ struct sensor_read_config { const struct device *sensor; const bool is_streaming; union { - enum sensor_channel *const channels; + struct sensor_chan_spec *const channels; struct sensor_stream_trigger *const triggers; }; size_t count; @@ -604,7 +635,8 @@ struct sensor_read_config { * * @code(.c) * SENSOR_DT_READ_IODEV(icm42688_accelgyro, DT_NODELABEL(icm42688), - * SENSOR_CHAN_ACCEL_XYZ, SENSOR_CHAN_GYRO_XYZ); + * { SENSOR_CHAN_ACCEL_XYZ, 0 }, + * { SENSOR_CHAN_GYRO_XYZ, 0 }); * * int main(void) { * sensor_read(&icm42688_accelgyro, &rtio); @@ -612,7 +644,7 @@ struct sensor_read_config { * @endcode */ #define SENSOR_DT_READ_IODEV(name, dt_node, ...) \ - static enum sensor_channel _CONCAT(__channel_array_, name)[] = {__VA_ARGS__}; \ + static struct sensor_chan_spec _CONCAT(__channel_array_, name)[] = {__VA_ARGS__}; \ static struct sensor_read_config _CONCAT(__sensor_read_config_, name) = { \ .sensor = DEVICE_DT_GET(dt_node), \ .is_streaming = false, \ @@ -886,10 +918,10 @@ struct __attribute__((__packed__)) sensor_data_generic_header { int8_t shift; /* This padding is needed to make sure that the 'channels' field is aligned */ - int8_t _padding[sizeof(enum sensor_channel) - 1]; + int8_t _padding[sizeof(struct sensor_chan_spec) - 1]; /* Channels present in the frame */ - enum sensor_channel channels[0]; + struct sensor_chan_spec channels[0]; }; /** @@ -949,12 +981,12 @@ static inline int z_impl_sensor_get_decoder(const struct device *dev, * @return < 0 on error */ __syscall int sensor_reconfigure_read_iodev(struct rtio_iodev *iodev, const struct device *sensor, - const enum sensor_channel *channels, + const struct sensor_chan_spec *channels, size_t num_channels); static inline int z_impl_sensor_reconfigure_read_iodev(struct rtio_iodev *iodev, const struct device *sensor, - const enum sensor_channel *channels, + const struct sensor_chan_spec *channels, size_t num_channels) { struct sensor_read_config *cfg = (struct sensor_read_config *)iodev->data; @@ -964,7 +996,7 @@ static inline int z_impl_sensor_reconfigure_read_iodev(struct rtio_iodev *iodev, } cfg->sensor = sensor; - memcpy(cfg->channels, channels, num_channels * sizeof(enum sensor_channel)); + memcpy(cfg->channels, channels, num_channels * sizeof(struct sensor_chan_spec)); cfg->count = num_channels; return 0; } diff --git a/include/zephyr/drivers/sensor/grow_r502a.h b/include/zephyr/drivers/sensor/grow_r502a.h index 8b0db47188d..81ee68ca714 100644 --- a/include/zephyr/drivers/sensor/grow_r502a.h +++ b/include/zephyr/drivers/sensor/grow_r502a.h @@ -13,6 +13,54 @@ extern "C" { #include +/*LED color code*/ +enum r502a_led_color_idx { + R502A_LED_COLOR_RED = 0x01, + R502A_LED_COLOR_BLUE, + R502A_LED_COLOR_PURPLE, +}; + +#define R502A_BAUD_9600 1 +#define R502A_BAUD_19200 2 +#define R502A_BAUD_38400 4 +#define R502A_BAUD_57600 6 +#define R502A_BAUD_115200 12 + +enum r502a_sec_level { + R502A_SEC_LEVEL_1 = 1, + R502A_SEC_LEVEL_2, + R502A_SEC_LEVEL_3, + R502A_SEC_LEVEL_4, + R502A_SEC_LEVEL_5 +}; + +enum r502a_data_len { + R502A_PKG_LEN_32, + R502A_PKG_LEN_64, + R502A_PKG_LEN_128, + R502A_PKG_LEN_256 +}; + +enum r502a_sys_param_set { + R502A_BAUD_RATE = 4, + R502A_SECURITY_LEVEL, + R502A_DATA_PKG_LEN +}; + +struct r502a_sys_param { + uint16_t status_reg; + uint16_t system_id; + uint16_t lib_size; + uint16_t sec_level; + uint32_t addr; + uint16_t data_pkt_size; + uint32_t baud; +} __packed; + +struct r502a_template { + uint8_t *data; + size_t len; +}; enum sensor_channel_grow_r502a { /** Fingerprint template count, ID number for enrolling and searching*/ SENSOR_CHAN_FINGERPRINT = SENSOR_CHAN_PRIV_START, @@ -24,18 +72,69 @@ enum sensor_trigger_type_grow_r502a { }; enum sensor_attribute_grow_r502a { - /** Add values to the sensor which are having record storage facility */ - SENSOR_ATTR_R502A_RECORD_ADD = SENSOR_ATTR_PRIV_START, + /** To capture finger and store as feature file in + * RAM buffers char_buf_1 and char_buf_2. + */ + SENSOR_ATTR_R502A_CAPTURE = SENSOR_ATTR_PRIV_START, + /** create template from feature files at RAM buffers + * char_buf_1 & char_buf_2 and store a template data + * back in both RAM buffers char_buf_1 and char_buf_2. + */ + SENSOR_ATTR_R502A_TEMPLATE_CREATE, + /** Add template to the sensor record storage */ + /** + * @param val->val1 record index for template to be + * stored in the sensor device's flash + * library. + */ + SENSOR_ATTR_R502A_RECORD_ADD, /** To find requested data in record storage */ + /** + * @result val->val1 matched record index. + * val->val2 matching score. + */ SENSOR_ATTR_R502A_RECORD_FIND, /** To delete mentioned data from record storage */ + /** + * @param val->val1 record start index to be deleted. + * @param val->val2 number of records to be deleted. + */ SENSOR_ATTR_R502A_RECORD_DEL, /** To get available position to store data on record storage */ SENSOR_ATTR_R502A_RECORD_FREE_IDX, /** To empty the storage record*/ SENSOR_ATTR_R502A_RECORD_EMPTY, + /** To load template from storage to RAM buffer of sensor*/ + /** + * @param val->val1 record start index to be loaded in + * device internal RAM buffer. + */ + SENSOR_ATTR_R502A_RECORD_LOAD, + /** To template data stored in sensor's RAM buffer*/ + /** + * @result + * val->val1 match result. + * [R502A_FINGER_MATCH_FOUND or + * R502A_FINGER_MATCH_NOT_FOUND] + * val->val2 matching score. + */ + SENSOR_ATTR_R502A_COMPARE, + /** To read and write device's system parameters */ + /** sensor_attr_set + * @param val->val1 parameter number from enum r502a_sys_param_set. + * @param val->val2 content to be written for the respective parameter. + */ + /** sensor_attr_get + * @result val->ex.data buffer holds the system parameter values. + */ + SENSOR_ATTR_R502A_SYS_PARAM, }; +int r502a_read_sys_param(const struct device *dev, struct r502a_sys_param *val); +int fps_upload_char_buf(const struct device *dev, struct r502a_template *temp); +int fps_download_char_buf(const struct device *dev, uint8_t char_buf_id, + const struct r502a_template *temp); + #ifdef __cplusplus } #endif diff --git a/include/zephyr/drivers/sensor/veaa_x_3.h b/include/zephyr/drivers/sensor/veaa_x_3.h new file mode 100644 index 00000000000..de08f07aedc --- /dev/null +++ b/include/zephyr/drivers/sensor/veaa_x_3.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2024, Vitrolife A/S + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_SENSOR_VEAA_X_3_H_ +#define ZEPHYR_INCLUDE_DRIVERS_SENSOR_VEAA_X_3_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +enum sensor_attribute_veaa_x_3 { + /* Set pressure setpoint value in kPa. */ + SENSOR_ATTR_VEAA_X_3_SETPOINT = SENSOR_ATTR_PRIV_START, + /* Supported pressure range in kPa. val1 is minimum and val2 is maximum */ + SENSOR_ATTR_VEAA_X_3_RANGE, +}; + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_DRIVERS_SENSOR_VEAA_X_3_H_ */ diff --git a/include/zephyr/drivers/spi.h b/include/zephyr/drivers/spi.h index 067d3419de5..be4e983990b 100644 --- a/include/zephyr/drivers/spi.h +++ b/include/zephyr/drivers/spi.h @@ -389,9 +389,8 @@ struct spi_dt_spec { * data from the devicetree. * * Important: multiple fields are automatically constructed by this macro - * which must be checked before use. @ref spi_is_ready performs the required + * which must be checked before use. @ref spi_is_ready_dt performs the required * @ref device_is_ready checks. - * @deprecated Use @ref spi_is_ready_dt instead. * * @param node_id Devicetree node identifier for the SPI device whose * struct spi_dt_spec to create an initializer for @@ -683,29 +682,6 @@ static inline bool spi_cs_is_gpio_dt(const struct spi_dt_spec *spec) return spi_cs_is_gpio(&spec->config); } -/** - * @brief Validate that SPI bus is ready. - * - * @param spec SPI specification from devicetree - * - * @retval true if the SPI bus is ready for use. - * @retval false if the SPI bus is not ready for use. - */ -__deprecated -static inline bool spi_is_ready(const struct spi_dt_spec *spec) -{ - /* Validate bus is ready */ - if (!device_is_ready(spec->bus)) { - return false; - } - /* Validate CS gpio port is ready, if it is used */ - if (spi_cs_is_gpio_dt(spec) && - !gpio_is_ready_dt(&spec->config.cs.gpio)) { - return false; - } - return true; -} - /** * @brief Validate that SPI bus (and CS gpio if defined) is ready. * diff --git a/include/zephyr/drivers/timer/nrf_grtc_timer.h b/include/zephyr/drivers/timer/nrf_grtc_timer.h index 1814202a097..f8b69d7ddf0 100644 --- a/include/zephyr/drivers/timer/nrf_grtc_timer.h +++ b/include/zephyr/drivers/timer/nrf_grtc_timer.h @@ -101,11 +101,13 @@ void z_nrf_grtc_timer_compare_int_unlock(int32_t chan, bool key); * * @param chan Channel ID. * - * @retval >=0 Positive is a Value set in the compare register + * @param val Pointer to store the value. + * + * @retval 0 if the compare register was read successfully. * @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); +int z_nrf_grtc_timer_compare_read(int32_t chan, uint64_t *val); /** @brief Set compare channel to given value. * diff --git a/include/zephyr/drivers/timer/nrf_rtc_timer.h b/include/zephyr/drivers/timer/nrf_rtc_timer.h index c5992bee4bd..57340098c23 100644 --- a/include/zephyr/drivers/timer/nrf_rtc_timer.h +++ b/include/zephyr/drivers/timer/nrf_rtc_timer.h @@ -59,7 +59,7 @@ uint64_t z_nrf_rtc_timer_read(void); * * Address can be used for (D)PPI. * - * @param chan Channel ID between 0 and CONFIG_NRF_RTC_TIMER_USER_CHAN_COUNT. + * @param chan Channel ID between 0 and @kconfig{CONFIG_NRF_RTC_TIMER_USER_CHAN_COUNT}. * * @return Register address. */ @@ -71,7 +71,7 @@ uint32_t z_nrf_rtc_timer_compare_evt_address_get(int32_t chan); * * @note Not all platforms have CAPTURE task. * - * @param chan Channel ID between 1 and CONFIG_NRF_RTC_TIMER_USER_CHAN_COUNT. + * @param chan Channel ID between 1 and @kconfig{CONFIG_NRF_RTC_TIMER_USER_CHAN_COUNT}. * * @return Register address. */ @@ -81,7 +81,7 @@ uint32_t z_nrf_rtc_timer_capture_task_address_get(int32_t chan); * * Function returns key indicating whether interrupt was already disabled. * - * @param chan Channel ID between 1 and CONFIG_NRF_RTC_TIMER_USER_CHAN_COUNT. + * @param chan Channel ID between 1 and @kconfig{CONFIG_NRF_RTC_TIMER_USER_CHAN_COUNT}. * * @return key passed to @ref z_nrf_rtc_timer_compare_int_unlock. */ @@ -91,7 +91,7 @@ bool z_nrf_rtc_timer_compare_int_lock(int32_t chan); * * Event interrupt is conditionally enabled based on @p key. * - * @param chan Channel ID between 1 and CONFIG_NRF_RTC_TIMER_USER_CHAN_COUNT. + * @param chan Channel ID between 1 and @kconfig{CONFIG_NRF_RTC_TIMER_USER_CHAN_COUNT}. * * @param key Key returned by @ref z_nrf_rtc_timer_compare_int_lock. */ @@ -99,7 +99,7 @@ void z_nrf_rtc_timer_compare_int_unlock(int32_t chan, bool key); /** @brief Read compare register value. * - * @param chan Channel ID between 0 and CONFIG_NRF_RTC_TIMER_USER_CHAN_COUNT. + * @param chan Channel ID between 0 and @kconfig{CONFIG_NRF_RTC_TIMER_USER_CHAN_COUNT}. * * @return Value set in the compare register. */ @@ -116,7 +116,7 @@ uint32_t z_nrf_rtc_timer_compare_read(int32_t chan); * 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. + * @param chan Channel ID between 1 and @kconfig{CONFIG_NRF_RTC_TIMER_USER_CHAN_COUNT}. * * @param target_time Absolute target time in ticks. * @@ -144,7 +144,7 @@ int z_nrf_rtc_timer_set(int32_t chan, uint64_t target_time, * value (as would @ref z_nrf_rtc_timer_set function do), neither the hardware * event nor interrupt will be generated and the function fails. * - * @param chan Channel ID between 1 and CONFIG_NRF_RTC_TIMER_USER_CHAN_COUNT. + * @param chan Channel ID between 1 and @kconfig{CONFIG_NRF_RTC_TIMER_USER_CHAN_COUNT}. * * @param target_time Absolute target time in ticks. * @@ -171,7 +171,7 @@ int z_nrf_rtc_timer_exact_set(int32_t chan, uint64_t target_time, * 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. + * @param chan Channel ID between 1 and @kconfig{CONFIG_NRF_RTC_TIMER_USER_CHAN_COUNT}. */ void z_nrf_rtc_timer_abort(int32_t chan); @@ -190,7 +190,7 @@ uint64_t z_nrf_rtc_timer_get_ticks(k_timeout_t t); * * Returned value added to the current system tick on network cpu gives current * application cpu system tick. Function can only be used on network cpu. It - * requires @ref CONFIG_NRF53_SYNC_RTC being enabled. + * requires @kconfig{CONFIG_NRF53_SYNC_RTC} being enabled. * * @retval Non-negative offset given in RTC ticks. * @retval -ENOSYS if operation is not supported. diff --git a/include/zephyr/drivers/timer/system_timer.h b/include/zephyr/drivers/timer/system_timer.h index 654df387459..55f99ad3e28 100644 --- a/include/zephyr/drivers/timer/system_timer.h +++ b/include/zephyr/drivers/timer/system_timer.h @@ -70,7 +70,7 @@ extern "C" { * @param idle Hint to the driver that the system is about to enter * the idle state immediately after setting the timeout */ -extern void sys_clock_set_timeout(int32_t ticks, bool idle); +void sys_clock_set_timeout(int32_t ticks, bool idle); /** * @brief Timer idle exit notification @@ -84,7 +84,7 @@ extern void sys_clock_set_timeout(int32_t ticks, bool idle); * This is allowed for compatibility, but not recommended. The kernel * will figure that out on its own. */ -extern void sys_clock_idle_exit(void); +void sys_clock_idle_exit(void); /** * @brief Announce time progress to the kernel @@ -97,7 +97,7 @@ extern void sys_clock_idle_exit(void); * * @param ticks Elapsed time, in ticks */ -extern void sys_clock_announce(int32_t ticks); +void sys_clock_announce(int32_t ticks); /** * @brief Ticks elapsed since last sys_clock_announce() call @@ -107,7 +107,7 @@ extern void sys_clock_announce(int32_t ticks); * this with appropriate locking, the driver needs only provide an * instantaneous answer. */ -extern uint32_t sys_clock_elapsed(void); +uint32_t sys_clock_elapsed(void); /** * @brief Disable system timer. @@ -116,7 +116,7 @@ extern uint32_t sys_clock_elapsed(void); * The config @kconfig{CONFIG_SYSTEM_TIMER_HAS_DISABLE_SUPPORT} can be used to * check if the system timer has the capability of being disabled. */ -extern void sys_clock_disable(void); +void sys_clock_disable(void); /** * @brief Hardware cycle counter diff --git a/include/zephyr/drivers/usb/udc.h b/include/zephyr/drivers/usb/udc.h index 7e13d565a73..2e4d4dbcf32 100644 --- a/include/zephyr/drivers/usb/udc.h +++ b/include/zephyr/drivers/usb/udc.h @@ -42,6 +42,8 @@ struct udc_device_caps { uint32_t out_ack : 1; /** Controller expects device address to be set before status stage */ uint32_t addr_before_status : 1; + /** Controller can detect the state change of USB supply VBUS.*/ + uint32_t can_detect_vbus : 1; /** Maximum packet size for control endpoint */ enum udc_mps0 mps0 : 2; }; diff --git a/include/zephyr/drivers/usb_c/usbc_ppc.h b/include/zephyr/drivers/usb_c/usbc_ppc.h index c8f76c9227f..6d7f2440f5a 100644 --- a/include/zephyr/drivers/usb_c/usbc_ppc.h +++ b/include/zephyr/drivers/usb_c/usbc_ppc.h @@ -50,7 +50,7 @@ enum usbc_ppc_event { 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 { +__subsystem struct usbc_ppc_driver_api { 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); @@ -78,7 +78,7 @@ __subsystem struct usbc_ppc_drv { */ 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; + const struct usbc_ppc_driver_api *api = (const struct usbc_ppc_driver_api *)dev->api; if (api->is_dead_battery_mode == NULL) { return -ENOSYS; @@ -101,7 +101,7 @@ static inline int ppc_is_dead_battery_mode(const struct device *dev) */ 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; + const struct usbc_ppc_driver_api *api = (const struct usbc_ppc_driver_api *)dev->api; if (api->exit_dead_battery_mode == NULL) { return -ENOSYS; @@ -121,7 +121,7 @@ static inline int ppc_exit_dead_battery_mode(const struct device *dev) */ static inline int ppc_is_vbus_source(const struct device *dev) { - const struct usbc_ppc_drv *api = (const struct usbc_ppc_drv *)dev->api; + const struct usbc_ppc_driver_api *api = (const struct usbc_ppc_driver_api *)dev->api; if (api->is_vbus_source == NULL) { return -ENOSYS; @@ -141,7 +141,7 @@ static inline int ppc_is_vbus_source(const struct device *dev) */ static inline int ppc_is_vbus_sink(const struct device *dev) { - const struct usbc_ppc_drv *api = (const struct usbc_ppc_drv *)dev->api; + const struct usbc_ppc_driver_api *api = (const struct usbc_ppc_driver_api *)dev->api; if (api->is_vbus_sink == NULL) { return -ENOSYS; @@ -161,7 +161,7 @@ static inline int ppc_is_vbus_sink(const struct device *dev) */ 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; + const struct usbc_ppc_driver_api *api = (const struct usbc_ppc_driver_api *)dev->api; if (api->set_snk_ctrl == NULL) { return -ENOSYS; @@ -181,7 +181,7 @@ static inline int ppc_set_snk_ctrl(const struct device *dev, bool enable) */ 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; + const struct usbc_ppc_driver_api *api = (const struct usbc_ppc_driver_api *)dev->api; if (api->set_src_ctrl == NULL) { return -ENOSYS; @@ -201,7 +201,7 @@ static inline int ppc_set_src_ctrl(const struct device *dev, bool enable) */ 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; + const struct usbc_ppc_driver_api *api = (const struct usbc_ppc_driver_api *)dev->api; if (api->set_vbus_discharge == NULL) { return -ENOSYS; @@ -221,7 +221,7 @@ static inline int ppc_set_vbus_discharge(const struct device *dev, bool enable) */ static inline int ppc_is_vbus_present(const struct device *dev) { - const struct usbc_ppc_drv *api = (const struct usbc_ppc_drv *)dev->api; + const struct usbc_ppc_driver_api *api = (const struct usbc_ppc_driver_api *)dev->api; if (api->is_vbus_present == NULL) { return -ENOSYS; @@ -242,7 +242,7 @@ static inline int ppc_is_vbus_present(const struct device *dev) 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; + const struct usbc_ppc_driver_api *api = (const struct usbc_ppc_driver_api *)dev->api; if (api->set_event_handler == NULL) { return -ENOSYS; @@ -261,7 +261,7 @@ static inline int ppc_set_event_handler(const struct device *dev, */ static inline int ppc_dump_regs(const struct device *dev) { - const struct usbc_ppc_drv *api = (const struct usbc_ppc_drv *)dev->api; + const struct usbc_ppc_driver_api *api = (const struct usbc_ppc_driver_api *)dev->api; if (api->dump_regs == NULL) { return -ENOSYS; diff --git a/include/zephyr/drivers/usb_c/usbc_vbus.h b/include/zephyr/drivers/usb_c/usbc_vbus.h index eb159d7c509..a5421bf9389 100644 --- a/include/zephyr/drivers/usb_c/usbc_vbus.h +++ b/include/zephyr/drivers/usb_c/usbc_vbus.h @@ -32,7 +32,7 @@ extern "C" { #endif -struct usbc_vbus_driver_api { +__subsystem struct usbc_vbus_driver_api { bool (*check_level)(const struct device *dev, enum tc_vbus_level level); int (*measure)(const struct device *dev, int *vbus_meas); int (*discharge)(const struct device *dev, bool enable); diff --git a/include/zephyr/drivers/video.h b/include/zephyr/drivers/video.h index d1a41b7d176..84b5558390e 100644 --- a/include/zephyr/drivers/video.h +++ b/include/zephyr/drivers/video.h @@ -249,7 +249,7 @@ typedef int (*video_api_set_signal_t)(const struct device *dev, enum video_endpoint_id ep, struct k_poll_signal *signal); -struct video_driver_api { +__subsystem struct video_driver_api { /* mandatory callbacks */ video_api_set_format_t set_format; video_api_get_format_t get_format; @@ -560,10 +560,20 @@ static inline int video_set_signal(const struct device *dev, return api->set_signal(dev, ep, signal); } +/** + * @brief Allocate aligned video buffer. + * + * @param size Size of the video buffer (in bytes). + * @param align Alignment of the requested memory, must be a power of two. + * + * @retval pointer to allocated video buffer + */ +struct video_buffer *video_buffer_aligned_alloc(size_t size, size_t align); + /** * @brief Allocate video buffer. * - * @param size Size of the video buffer. + * @param size Size of the video buffer (in bytes). * * @retval pointer to allocated video buffer */ @@ -628,6 +638,9 @@ void video_buffer_release(struct video_buffer *buf); /** YUYV pixel format */ #define VIDEO_PIX_FMT_YUYV video_fourcc('Y', 'U', 'Y', 'V') /* 16 Y0-Cb0 Y1-Cr0 */ +/** XYUV32 pixel format */ +#define VIDEO_PIX_FMT_XYUV32 video_fourcc('X', 'Y', 'U', 'V') /* 32 XYUV-8-8-8-8 */ + /** * * @} diff --git a/include/zephyr/dt-bindings/acpi/acpi.h b/include/zephyr/dt-bindings/acpi/acpi.h new file mode 100644 index 00000000000..6084aebb7a8 --- /dev/null +++ b/include/zephyr/dt-bindings/acpi/acpi.h @@ -0,0 +1,8 @@ +/* + * Copyright (c) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define ACPI_IRQ_DETECT 0xFFFFFFFU +#define ACPI_IRQ_FLAG_DETECT 0xFFFFFFFU diff --git a/include/zephyr/dt-bindings/adc/adc.h b/include/zephyr/dt-bindings/adc/adc.h index fafadb163b6..fcbb21e7875 100644 --- a/include/zephyr/dt-bindings/adc/adc.h +++ b/include/zephyr/dt-bindings/adc/adc.h @@ -6,13 +6,7 @@ #ifndef ZEPHYR_INCLUDE_DT_BINDINGS_ADC_ADC_H_ #define ZEPHYR_INCLUDE_DT_BINDINGS_ADC_ADC_H_ -/* - * Provide the BIT_MASK() macro for when this file is included from - * devicetrees. - */ -#ifndef BIT_MASK -#define BIT_MASK(n) ((1 << (n)) - 1) -#endif +#include /** Acquisition time is expressed in microseconds. */ #define ADC_ACQ_TIME_MICROSECONDS (1) diff --git a/include/zephyr/dt-bindings/adc/nxp,gau-adc.h b/include/zephyr/dt-bindings/adc/nxp,gau-adc.h new file mode 100644 index 00000000000..712a342eedc --- /dev/null +++ b/include/zephyr/dt-bindings/adc/nxp,gau-adc.h @@ -0,0 +1,27 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2022 NXP + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_ADC_NXP_GAU_ADC_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_ADC_NXP_GAU_ADC_H_ + +#include + +/* Channel Sources */ +#define GAU_ADC_CH0 0 +#define GAU_ADC_CH1 1 +#define GAU_ADC_CH2 2 +#define GAU_ADC_CH3 3 +#define GAU_ADC_CH4 4 +#define GAU_ADC_CH5 5 +#define GAU_ADC_CH6 6 +#define GAU_ADC_CH7 7 +#define GAU_ADC_VBATS 8 +#define GAU_ADC_VREF 9 +#define GAU_ADC_DACA 10 +#define GAU_ADC_DACB 11 +#define GAU_ADC_VSSA 12 +#define GAU_ADC_TEMPP 15 + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_ADC_NXP_GAU_ADC_H_ */ diff --git a/include/zephyr/dt-bindings/clock/imx_ccm_rev2.h b/include/zephyr/dt-bindings/clock/imx_ccm_rev2.h index 0ea1019a75f..f21844a1490 100644 --- a/include/zephyr/dt-bindings/clock/imx_ccm_rev2.h +++ b/include/zephyr/dt-bindings/clock/imx_ccm_rev2.h @@ -13,90 +13,105 @@ * Instance: * range: 0 - 0xFF, starting from 0 */ -#define IMX_CCM_PERIPHERAL_MASK 0xFF00UL -#define IMX_CCM_INSTANCE_MASK 0xFFUL +#define IMX_CCM_PERIPHERAL_MASK 0xFF00UL +#define IMX_CCM_INSTANCE_MASK 0xFFUL + +#define IMX_CCM_CORESYS_CLK 0 +#define IMX_CCM_PLATFORM_CLK 0x1UL +#define IMX_CCM_BUS_CLK 0x2UL -#define IMX_CCM_CORESYS_CLK 0 -#define IMX_CCM_PLATFORM_CLK 0x1UL -#define IMX_CCM_BUS_CLK 0x2UL /* LPUART */ -#define IMX_CCM_LPUART_CLK 0x300UL -#define IMX_CCM_LPUART1_CLK 0x300UL -#define IMX_CCM_LPUART2_CLK 0x301UL -#define IMX_CCM_LPUART3_CLK 0x302UL -#define IMX_CCM_LPUART4_CLK 0x303UL -#define IMX_CCM_LPUART5_CLK 0x304UL -#define IMX_CCM_LPUART6_CLK 0x305UL -#define IMX_CCM_LPUART7_CLK 0x306UL -#define IMX_CCM_LPUART8_CLK 0x307UL -#define IMX_CCM_LPUART9_CLK 0x308UL -#define IMX_CCM_LPUART10_CLK 0x309UL -#define IMX_CCM_LPUART11_CLK 0x30aUL -#define IMX_CCM_LPUART12_CLK 0x30bUL +#define IMX_CCM_LPUART_CLK 0x300UL +#define IMX_CCM_LPUART1_CLK 0x300UL +#define IMX_CCM_LPUART2_CLK 0x301UL +#define IMX_CCM_LPUART3_CLK 0x302UL +#define IMX_CCM_LPUART4_CLK 0x303UL +#define IMX_CCM_LPUART5_CLK 0x304UL +#define IMX_CCM_LPUART6_CLK 0x305UL +#define IMX_CCM_LPUART7_CLK 0x306UL +#define IMX_CCM_LPUART8_CLK 0x307UL +#define IMX_CCM_LPUART9_CLK 0x308UL +#define IMX_CCM_LPUART10_CLK 0x309UL +#define IMX_CCM_LPUART11_CLK 0x30aUL +#define IMX_CCM_LPUART12_CLK 0x30bUL /* LPI2C */ -#define IMX_CCM_LPI2C_CLK 0x400UL -#define IMX_CCM_LPI2C1_CLK 0x400UL -#define IMX_CCM_LPI2C2_CLK 0x401UL -#define IMX_CCM_LPI2C3_CLK 0x402UL -#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 +#define IMX_CCM_LPI2C_CLK 0x400UL +#define IMX_CCM_LPI2C1_CLK 0x400UL +#define IMX_CCM_LPI2C2_CLK 0x401UL +#define IMX_CCM_LPI2C3_CLK 0x402UL +#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 -#define IMX_CCM_LPSPI1_CLK 0x500UL -#define IMX_CCM_LPSPI2_CLK 0x501UL -#define IMX_CCM_LPSPI3_CLK 0x502UL -#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 +#define IMX_CCM_LPSPI_CLK 0x500UL +#define IMX_CCM_LPSPI1_CLK 0x500UL +#define IMX_CCM_LPSPI2_CLK 0x501UL +#define IMX_CCM_LPSPI3_CLK 0x502UL +#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 -#define IMX_CCM_USDHC2_CLK 0x601UL +#define IMX_CCM_USDHC1_CLK 0x600UL +#define IMX_CCM_USDHC2_CLK 0x601UL /* DMA */ -#define IMX_CCM_EDMA_CLK 0x700UL -#define IMX_CCM_EDMA_LPSR_CLK 0x701UL +#define IMX_CCM_EDMA_CLK 0x700UL +#define IMX_CCM_EDMA_LPSR_CLK 0x701UL /* PWM */ -#define IMX_CCM_PWM_CLK 0x800UL +#define IMX_CCM_PWM_CLK 0x800UL /* CAN */ -#define IMX_CCM_CAN_CLK 0x900UL -#define IMX_CCM_CAN1_CLK 0x900UL -#define IMX_CCM_CAN2_CLK 0x901UL -#define IMX_CCM_CAN3_CLK 0x902UL +#define IMX_CCM_CAN_CLK 0x900UL +#define IMX_CCM_CAN1_CLK 0x900UL +#define IMX_CCM_CAN2_CLK 0x901UL +#define IMX_CCM_CAN3_CLK 0x902UL /* GPT */ -#define IMX_CCM_GPT_CLK 0x1000UL -#define IMX_CCM_GPT1_CLK 0x1000UL -#define IMX_CCM_GPT2_CLK 0x1001UL -#define IMX_CCM_GPT3_CLK 0x1002UL -#define IMX_CCM_GPT4_CLK 0x1003UL -#define IMX_CCM_GPT5_CLK 0x1004UL -#define IMX_CCM_GPT6_CLK 0x1005UL +#define IMX_CCM_GPT_CLK 0x1000UL +#define IMX_CCM_GPT1_CLK 0x1000UL +#define IMX_CCM_GPT2_CLK 0x1001UL +#define IMX_CCM_GPT3_CLK 0x1002UL +#define IMX_CCM_GPT4_CLK 0x1003UL +#define IMX_CCM_GPT5_CLK 0x1004UL +#define IMX_CCM_GPT6_CLK 0x1005UL /* SAI */ -#define IMX_CCM_SAI1_CLK 0x2000UL -#define IMX_CCM_SAI2_CLK 0x2001UL -#define IMX_CCM_SAI3_CLK 0x2002UL -#define IMX_CCM_SAI4_CLK 0x2003UL +#define IMX_CCM_SAI1_CLK 0x1100UL +#define IMX_CCM_SAI2_CLK 0x1101UL +#define IMX_CCM_SAI3_CLK 0x1102UL +#define IMX_CCM_SAI4_CLK 0x1103UL /* ENET */ -#define IMX_CCM_ENET_CLK 0x3000UL -#define IMX_CCM_ENET_PLL 0x3001UL +#define IMX_CCM_ENET_CLK 0x1200UL +#define IMX_CCM_ENET_PLL 0x1201UL /* FLEXSPI */ -#define IMX_CCM_FLEXSPI_CLK 0x4000UL -#define IMX_CCM_FLEXSPI2_CLK 0x4001UL +#define IMX_CCM_FLEXSPI_CLK 0x1300UL +#define IMX_CCM_FLEXSPI2_CLK 0x1301UL + /* PIT */ -#define IMX_CCM_PIT_CLK 0x5000UL -#define IMX_CCM_PIT1_CLK 0x5001UL +#define IMX_CCM_PIT_CLK 0x1400UL +#define IMX_CCM_PIT1_CLK 0x1401UL + +/* ADC */ +#define IMX_CCM_LPADC1_CLK 0x1500UL +#define IMX_CCM_LPADC2_CLK 0x1501UL + +/* TPM */ +#define IMX_CCM_TPM_CLK 0x1600UL +#define IMX_CCM_TPM1_CLK 0x1600UL +#define IMX_CCM_TPM2_CLK 0x1601UL +#define IMX_CCM_TPM3_CLK 0x1602UL +#define IMX_CCM_TPM4_CLK 0x1603UL +#define IMX_CCM_TPM5_CLK 0x1604UL +#define IMX_CCM_TPM6_CLK 0x1605UL #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 8395a05b483..75e8179133d 100644 --- a/include/zephyr/dt-bindings/clock/kinetis_sim.h +++ b/include/zephyr/dt-bindings/clock/kinetis_sim.h @@ -25,6 +25,7 @@ #define KINETIS_SIM_ER32KSEL_LPO1KHZ 3 #define KINETIS_SIM_ENET_CLK 4321 +#define KINETIS_SIM_ENET_1588_CLK 4322 #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 d3b974cb6d4..4d5f20f371e 100644 --- a/include/zephyr/dt-bindings/clock/mcux_lpc_syscon_clock.h +++ b/include/zephyr/dt-bindings/clock/mcux_lpc_syscon_clock.h @@ -78,4 +78,7 @@ #define MCUX_LCDIC_CLK MCUX_LPC_CLK_ID(0x0E, 0x00) +#define MCUX_LPADC1_CLK MCUX_LPC_CLK_ID(0x0F, 0x00) +#define MCUX_LPADC2_CLK MCUX_LPC_CLK_ID(0x0F, 0x01) + #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_MCUX_LPC_SYSCON_H_ */ diff --git a/include/zephyr/dt-bindings/clock/npcx_clock.h b/include/zephyr/dt-bindings/clock/npcx_clock.h index 713a05c5726..d522478d229 100644 --- a/include/zephyr/dt-bindings/clock/npcx_clock.h +++ b/include/zephyr/dt-bindings/clock/npcx_clock.h @@ -20,6 +20,7 @@ #define NPCX_CLOCK_BUS_FMCLK 10 #define NPCX_CLOCK_BUS_FIU0 NPCX_CLOCK_BUS_FIU #define NPCX_CLOCK_BUS_FIU1 11 +#define NPCX_CLOCK_BUS_MCLKD 12 /* clock enable/disable references */ #define NPCX_PWDWN_CTL1 0 @@ -30,6 +31,7 @@ #define NPCX_PWDWN_CTL6 5 #define NPCX_PWDWN_CTL7 6 #define NPCX_PWDWN_CTL8 7 -#define NPCX_PWDWN_CTL_COUNT 8 +#define NPCX_PWDWN_CTL9 8 +#define NPCX_PWDWN_CTL_COUNT 9 #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_NPCX_CLOCK_H_ */ diff --git a/include/zephyr/dt-bindings/clock/stm32wl_clock.h b/include/zephyr/dt-bindings/clock/stm32wl_clock.h index 081490d37e1..125e9a765e8 100644 --- a/include/zephyr/dt-bindings/clock/stm32wl_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32wl_clock.h @@ -29,9 +29,10 @@ /** Fixed clocks */ /* Low speed clocks defined in stm32_common_clocks.h */ #define STM32_SRC_HSI (STM32_SRC_LSI + 1) +#define STM32_SRC_MSI (STM32_SRC_HSI + 1) /* #define STM32_SRC_HSI48 TBD */ /** Bus clock */ -#define STM32_SRC_PCLK (STM32_SRC_HSI + 1) +#define STM32_SRC_PCLK (STM32_SRC_MSI + 1) /** PLL clock outputs */ #define STM32_SRC_PLL_P (STM32_SRC_PCLK + 1) #define STM32_SRC_PLL_Q (STM32_SRC_PLL_P + 1) diff --git a/include/zephyr/dt-bindings/flash_controller/xspi.h b/include/zephyr/dt-bindings/flash_controller/xspi.h new file mode 100644 index 00000000000..3e0610e8090 --- /dev/null +++ b/include/zephyr/dt-bindings/flash_controller/xspi.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_XSPI_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_XSPI_H_ + +/** + * @name XSPI definition for the xSPI peripherals + * Note that + * SPI mode inpossible in STR transfer rate only + */ + +/* XSPI mode operating on 1 line, 2 lines, 4 lines or 8 lines */ +/* 1 Cmd Line, 1 Address Line and 1 Data Line */ +#define XSPI_SPI_MODE 1 +/* 2 Cmd Lines, 2 Address Lines and 2 Data Lines */ +#define XSPI_DUAL_MODE 2 +/* 4 Cmd Lines, 4 Address Lines and 4 Data Lines */ +#define XSPI_QUAD_MODE 4 +/* 8 Cmd Lines, 8 Address Lines and 8 Data Lines */ +#define XSPI_OCTO_MODE 8 + +/* XSPI mode operating on Single or Double Transfer Rate */ +/* Single Transfer Rate */ +#define XSPI_STR_TRANSFER 1 +/* Double Transfer Rate */ +#define XSPI_DTR_TRANSFER 2 + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_XSPI_H_ */ diff --git a/include/zephyr/dt-bindings/gpio/adi-sdp-120.h b/include/zephyr/dt-bindings/gpio/adi-sdp-120.h new file mode 100644 index 00000000000..6188ce8c004 --- /dev/null +++ b/include/zephyr/dt-bindings/gpio/adi-sdp-120.h @@ -0,0 +1,87 @@ +/** + * Copyright (c) 2024 Analog Devices Inc. + * Copyright (c) 2024 Baylibre, SAS + * + * SPDX-License-Identifier: Apache-2.0 + * + * @file + * @brief SDP-120 GPIO index definitions + * + * Defines meant to be used in conjunction with the "adi,sdp-120" + * ADI SDP-120 mapping. + * + * Example usage: + * + * @code{.dts} + * &spi1 { + * cs-gpios = <&sdp_120 SDP_120_SPI_SS_N GPIO_ACTIVE_LOW>; + * + * example_device: example-dev@0 { + * compatible = "vnd,spi-device"; + * reg = <0>; + * }; + * }; + * @endcode + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_GPIO_ADI_SDP_120_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_GPIO_ADI_SDP_120_H_ + +/* GPIO */ + +/** + * @brief IO[n] signal on a SDP-120 GPIO nexus node following + */ + +#define SDP_120_IO(n) (n-1) + +/* SPI */ +#define SDP_120_SPI_D2 SDP_120_IO(33) /* SPI_D2 */ +#define SDP_120_SPI_D3 SDP_120_IO(34) /* SPI_D3 */ +#define SDP_120_SERIAL_INT SDP_120_IO(35) /* SERIAL_INT */ +#define SDP_120_SPI_SEL_B_N SDP_120_IO(37) /* SPI_SEL_B_N */ +#define SDP_120_SPI_SEL_C_N SDP_120_IO(38) /* SPI_SEL_C_N */ +#define SDP_120_SPI_SS_N SDP_120_IO(39) /* SPI_SS_N */ + +/* GPIO */ +#define SDP_120_GPIO0 SDP_120_IO(43) /* GPIO0 */ +#define SDP_120_GPIO2 SDP_120_IO(44) /* GPIO2 */ +#define SDP_120_GPIO4 SDP_120_IO(45) /* GPIO4 */ +#define SDP_120_GPIO6 SDP_120_IO(47) /* GPIO6 */ + +/* TMR */ +#define SDP_120_TMR_A SDP_120_IO(48) /* TMR_A */ + +/* USART */ +#define SDP_120_UART_RX SDP_120_IO(59) /* UART2_RX */ +#define SDP_120_UART_TX SDP_120_IO(62) /* UART2_TX */ + +/* TMR */ +#define SDP_120_TMR_D SDP_120_IO(72) /* TMR_D */ +#define SDP_120_TMR_B SDP_120_IO(73) /* TMR_B */ + +/* GPIO */ +#define SDP_120_GPIO7 SDP_120_IO(74) /* GPIO7 */ +#define SDP_120_GPIO5 SDP_120_IO(76) /* GPIO5 */ +#define SDP_120_GPIO3 SDP_120_IO(77) /* GPIO3 */ +#define SDP_120_GPIO1 SDP_120_IO(78) /* GPIO1 */ + +/* I2C */ +#define SDP_120_SCL_0 SDP_120_IO(79) /* SCL_0 */ +#define SDP_120_SDA_0 SDP_120_IO(80) /* SDA_0 */ + +/* SPI */ +#define SDP_120_SPI_CLK SDP_120_IO(82) /* SPI_CLK */ +#define SDP_120_SPI_MISO SDP_120_IO(83) /* SPI_MISO */ +#define SDP_120_SPI_MOSI SDP_120_IO(84) /* SPI_MOSI */ +#define SDP_120_SPI_SEL_A_N SDP_120_IO(85) /* SPI_SEL_A_N */ + +/* SPORT - no driver yet */ +#define SDP_120_SPI_SPORT_TSCLK SDP_120_IO(87) /* SPORT_TSCLK */ +#define SDP_120_SPI_SPORT_DT0 SDP_120_IO(88) /* SPORT_DT0 */ +#define SDP_120_SPI_SPORT_TFS SDP_120_IO(89) /* SPORT_TFS */ +#define SDP_120_SPI_SPORT_RFS SDP_120_IO(90) /* SPORT_RFS */ +#define SDP_120_SPI_SPORT_DR0 SDP_120_IO(91) /* SPORT_DR0 */ +#define SDP_120_SPI_SPORT_RSCLK SDP_120_IO(92) /* SPORT_RSCLK */ + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_GPIO_ADI_SDP_120_H_ */ diff --git a/include/zephyr/dt-bindings/gpio/gpio.h b/include/zephyr/dt-bindings/gpio/gpio.h index 6e8631d7d6d..b4110208b3f 100644 --- a/include/zephyr/dt-bindings/gpio/gpio.h +++ b/include/zephyr/dt-bindings/gpio/gpio.h @@ -81,9 +81,10 @@ /* Note: Bits 15 downto 8 are reserved for SoC specific flags. */ -/** Configures GPIO interrupt to wakeup the system from low power mode. +/** + * Configures GPIO interrupt to wakeup the system from low power mode. */ -#define GPIO_INT_WAKEUP (1u << 28) +#define GPIO_INT_WAKEUP (1 << 28) /** * @} diff --git a/include/zephyr/dt-bindings/mipi_dbi/mipi_dbi.h b/include/zephyr/dt-bindings/mipi_dbi/mipi_dbi.h new file mode 100644 index 00000000000..6956e044d11 --- /dev/null +++ b/include/zephyr/dt-bindings/mipi_dbi/mipi_dbi.h @@ -0,0 +1,62 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_MIPI_DBI_MIPI_DBI_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_MIPI_DBI_MIPI_DBI_H_ + +/** + * @brief MIPI-DBI driver APIs + * @defgroup mipi_dbi_interface MIPI-DBI driver APIs + * @ingroup io_interfaces + * @{ + */ + +/** + * SPI 3 wire (Type C1). Uses 9 write clocks to send a byte of data. + * The bit sent on the 9th clock indicates whether the byte is a + * command or data byte + * + * + * .---. .---. .---. .---. .---. .---. .---. .---. + * SCK -' '---' '---' '---' '---' '---' '---' '---' '--- + * + * -.---.---.---.---.---.---.---.---.---.---.---.---.---.---.---. + * DOUT |D/C| D7| D6| D5| D4| D3| D2| D1| D0|D/C| D7| D6| D5| D4|...| + * -'---'---'---'---'---'---'---'---'---'---'---'---'---'---'---' + * | Word 1 | Word n + * + * -. .-- + * CS '-----------------------------------------------------------' + */ +#define MIPI_DBI_MODE_SPI_3WIRE 0x1 +/** + * SPI 4 wire (Type C3). Uses 8 write clocks to send a byte of data. + * an additional C/D pin will be use to indicate whether the byte is a + * command or data byte + * + * .---. .---. .---. .---. .---. .---. .---. .---. + * SCK -' '---' '---' '---' '---' '---' '---' '---' '--- + * + * -.---.---.---.---.---.---.---.---.---.---.---.---.---.---.---.---. + * DOUT | D7| D6| D5| D4| D3| D2| D1| D0| D7| D6| D5| D4| D3| D2| D1| D0| + * -'---'---'---'---'---'---'---'---'---'---'---'---'---'---'---'---' + * | Word 1 | Word n + * + * -. .-- + * CS '---------------------------------------------------------------' + * + * -.-------------------------------.-------------------------------.- + * CD | D/C | D/C | + * -'-------------------------------'-------------------------------'- + */ +#define MIPI_DBI_MODE_SPI_4WIRE 0x2 + +/** + * @} + */ + + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_MIPI_DBI_MIPI_DBI_H_ */ diff --git a/include/zephyr/dt-bindings/misc/nordic-domain-id-nrf54h20.h b/include/zephyr/dt-bindings/misc/nordic-domain-id-nrf54h20.h new file mode 100644 index 00000000000..a5fd23fd34b --- /dev/null +++ b/include/zephyr/dt-bindings/misc/nordic-domain-id-nrf54h20.h @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_MISC_NORDIC_DOMAIN_ID_NRF54H20_H_ + +#define NRF_DOMAIN_ID_APPLICATION 2 +#define NRF_DOMAIN_ID_RADIOCORE 3 +#define NRF_DOMAIN_ID_GLOBALFAST 12 +#define NRF_DOMAIN_ID_GLOBALSLOW 13 + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_MISC_NORDIC_DOMAIN_ID_NRF54H20_H_ */ diff --git a/include/zephyr/dt-bindings/misc/nordic-owner-id-nrf54h20.h b/include/zephyr/dt-bindings/misc/nordic-owner-id-nrf54h20.h new file mode 100644 index 00000000000..080b4e048e2 --- /dev/null +++ b/include/zephyr/dt-bindings/misc/nordic-owner-id-nrf54h20.h @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_MISC_NORDIC_OWNER_ID_NRF54H20_H_ + +#define NRF_OWNER_ID_NONE 0 +#define NRF_OWNER_ID_APPLICATION 2 +#define NRF_OWNER_ID_RADIOCORE 3 + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_MISC_NORDIC_OWNER_ID_NRF54H20_H_ */ diff --git a/include/zephyr/dt-bindings/pcie/pcie.h b/include/zephyr/dt-bindings/pcie/pcie.h index 2cf6698be53..2cd4fdd663e 100644 --- a/include/zephyr/dt-bindings/pcie/pcie.h +++ b/include/zephyr/dt-bindings/pcie/pcie.h @@ -26,9 +26,15 @@ #define PCIE_ID_DEV_SHIFT 16U #define PCIE_ID_DEV_MASK 0xFFFFU +#ifdef __DTS__ +#define CAST(type, v) (v) +#else +#define CAST(type, v) ((type)(v)) +#endif + #define PCIE_ID(vend, dev) \ ((((vend) & PCIE_ID_VEND_MASK) << PCIE_ID_VEND_SHIFT) | \ - (((dev) & PCIE_ID_DEV_MASK) << PCIE_ID_DEV_SHIFT)) + (CAST(uint32_t, (dev) & PCIE_ID_DEV_MASK) << PCIE_ID_DEV_SHIFT)) #define PCIE_ID_TO_VEND(id) (((id) >> PCIE_ID_VEND_SHIFT) & PCIE_ID_VEND_MASK) #define PCIE_ID_TO_DEV(id) (((id) >> PCIE_ID_DEV_SHIFT) & PCIE_ID_DEV_MASK) diff --git a/include/zephyr/dt-bindings/pinctrl/ambiq-apollo3-pinctrl.h b/include/zephyr/dt-bindings/pinctrl/ambiq-apollo3-pinctrl.h new file mode 100644 index 00000000000..fbbbd42ae4c --- /dev/null +++ b/include/zephyr/dt-bindings/pinctrl/ambiq-apollo3-pinctrl.h @@ -0,0 +1,494 @@ +/* + * Copyright (c) 2023 Ambiq Micro Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __APOLLO3_PINCTRL_H__ +#define __APOLLO3_PINCTRL_H__ + +#define APOLLO3_ALT_FUNC_POS 0 +#define APOLLO3_ALT_FUNC_MASK 0xf + +#define APOLLO3_PIN_NUM_POS 4 +#define APOLLO3_PIN_NUM_MASK 0x7f + +#define APOLLO3_PINMUX(pin_num, alt_func) \ + (pin_num << APOLLO3_PIN_NUM_POS | alt_func << APOLLO3_ALT_FUNC_POS) + +#define SLSCL_P0 APOLLO3_PINMUX(0, 0) +#define SLSCK_P0 APOLLO3_PINMUX(0, 1) +#define CLKOUT_P0 APOLLO3_PINMUX(0, 2) +#define GPIO_P0 APOLLO3_PINMUX(0, 3) +#define MSPI0_4_P0 APOLLO3_PINMUX(0, 5) +#define NCE0_P0 APOLLO3_PINMUX(0, 7) +#define SLSDAWIR3_P1 APOLLO3_PINMUX(1, 0) +#define SLMOSI_P1 APOLLO3_PINMUX(1, 1) +#define UART0TX_P1 APOLLO3_PINMUX(1, 2) +#define GPIO_P1 APOLLO3_PINMUX(1, 3) +#define MSPI0_5_P1 APOLLO3_PINMUX(1, 5) +#define NCE1_P1 APOLLO3_PINMUX(1, 7) +#define UART1RX_P2 APOLLO3_PINMUX(2, 0) +#define SLMISO_P2 APOLLO3_PINMUX(2, 1) +#define UART0RX_P2 APOLLO3_PINMUX(2, 2) +#define GPIO_P2 APOLLO3_PINMUX(2, 3) +#define MSPI0_6_P2 APOLLO3_PINMUX(2, 5) +#define NCE2_P2 APOLLO3_PINMUX(2, 7) +#define UA0RTS_P3 APOLLO3_PINMUX(3, 0) +#define SLNCE_P3 APOLLO3_PINMUX(3, 1) +#define NCE3_P3 APOLLO3_PINMUX(3, 2) +#define GPIO_P3 APOLLO3_PINMUX(3, 3) +#define MSPI0_7_P3 APOLLO3_PINMUX(3, 5) +#define TRIG1_P3 APOLLO3_PINMUX(3, 6) +#define I2SWCLK_P3 APOLLO3_PINMUX(3, 7) +#define UA0CTS_P4 APOLLO3_PINMUX(4, 0) +#define SLINT_P4 APOLLO3_PINMUX(4, 1) +#define NCE4_P4 APOLLO3_PINMUX(4, 2) +#define GPIO_P4 APOLLO3_PINMUX(4, 3) +#define UART1RX_P4 APOLLO3_PINMUX(4, 5) +#define CTIM17_P4 APOLLO3_PINMUX(4, 6) +#define MSPI0_2_P4 APOLLO3_PINMUX(4, 7) +#define M0SCL_P5 APOLLO3_PINMUX(5, 0) +#define M0SCK_P5 APOLLO3_PINMUX(5, 1) +#define UA0RTS_P5 APOLLO3_PINMUX(5, 2) +#define GPIO_P5 APOLLO3_PINMUX(5, 3) +#define CT8_P5 APOLLO3_PINMUX(5, 7) +#define M0SDAWIR3_P6 APOLLO3_PINMUX(6, 0) +#define M0MISO_P6 APOLLO3_PINMUX(6, 1) +#define UA0CTS_P6 APOLLO3_PINMUX(6, 2) +#define GPIO_P6 APOLLO3_PINMUX(6, 3) +#define CTIM10_P6 APOLLO3_PINMUX(6, 5) +#define I2SDAT_P6 APOLLO3_PINMUX(6, 7) +#define NCE7_P7 APOLLO3_PINMUX(7, 0) +#define M0MOSI_P7 APOLLO3_PINMUX(7, 1) +#define CLKOUT_P7 APOLLO3_PINMUX(7, 2) +#define GPIO_P7 APOLLO3_PINMUX(7, 3) +#define TRIG0_P7 APOLLO3_PINMUX(7, 4) +#define UART0TX_P7 APOLLO3_PINMUX(7, 5) +#define CTIM19_P7 APOLLO3_PINMUX(7, 7) +#define M1SCL_P8 APOLLO3_PINMUX(8, 0) +#define M1SCK_P8 APOLLO3_PINMUX(8, 1) +#define NCE8_P8 APOLLO3_PINMUX(8, 2) +#define GPIO_P8 APOLLO3_PINMUX(8, 3) +#define SCCCLK_P8 APOLLO3_PINMUX(8, 4) +#define UART1TX_P8 APOLLO3_PINMUX(8, 6) +#define M1SDAWIR3_P9 APOLLO3_PINMUX(9, 0) +#define M1MISO_P9 APOLLO3_PINMUX(9, 1) +#define NCE9_P9 APOLLO3_PINMUX(9, 2) +#define GPIO_P9 APOLLO3_PINMUX(9, 3) +#define SCCIO_P9 APOLLO3_PINMUX(9, 4) +#define UART1RX_P9 APOLLO3_PINMUX(9, 6) +#define UART1TX_P10 APOLLO3_PINMUX(10, 0) +#define M1MOSI_P10 APOLLO3_PINMUX(10, 1) +#define NCE10_P10 APOLLO3_PINMUX(10, 2) +#define GPIO_P10 APOLLO3_PINMUX(10, 3) +#define PDMCLK_P10 APOLLO3_PINMUX(10, 4) +#define UA1RTS_P10 APOLLO3_PINMUX(10, 6) +#define ADCSE2_P11 APOLLO3_PINMUX(11, 0) +#define NCE11_P11 APOLLO3_PINMUX(11, 1) +#define CTIM31_P11 APOLLO3_PINMUX(11, 2) +#define GPIO_P11 APOLLO3_PINMUX(11, 3) +#define SLINT_P11 APOLLO3_PINMUX(11, 4) +#define UA1CTS_P11 APOLLO3_PINMUX(11, 5) +#define UART0RX_P11 APOLLO3_PINMUX(11, 6) +#define PDMDATA_P11 APOLLO3_PINMUX(11, 7) +#define ADCD0NSE9_P12 APOLLO3_PINMUX(12, 0) +#define NCE12_P12 APOLLO3_PINMUX(12, 1) +#define CT0_P12 APOLLO3_PINMUX(12, 2) +#define GPIO_P12 APOLLO3_PINMUX(12, 3) +#define PDMCLK_P12 APOLLO3_PINMUX(12, 5) +#define UA0CTS_P12 APOLLO3_PINMUX(12, 6) +#define UART1TX_P12 APOLLO3_PINMUX(12, 7) +#define ADCD0PSE8_P13 APOLLO3_PINMUX(13, 0) +#define NCE13_P13 APOLLO3_PINMUX(13, 1) +#define CTIM2_P13 APOLLO3_PINMUX(13, 2) +#define GPIO_P13 APOLLO3_PINMUX(13, 3) +#define I2SBCLK_P13 APOLLO3_PINMUX(13, 4) +#define UA0RTS_P13 APOLLO3_PINMUX(13, 6) +#define UART1RX_P13 APOLLO3_PINMUX(13, 7) +#define ADCD1P_P14 APOLLO3_PINMUX(14, 0) +#define NCE14_P14 APOLLO3_PINMUX(14, 1) +#define UART1TX_P14 APOLLO3_PINMUX(14, 2) +#define GPIO_P14 APOLLO3_PINMUX(14, 3) +#define PDMCLK_P14 APOLLO3_PINMUX(14, 4) +#define SWDCK_P14 APOLLO3_PINMUX(14, 6) +#define XT32KHz_P14 APOLLO3_PINMUX(14, 7) +#define ADCD1N_P15 APOLLO3_PINMUX(15, 0) +#define NCE15_P15 APOLLO3_PINMUX(15, 1) +#define UART1RX_P15 APOLLO3_PINMUX(15, 2) +#define GPIO_P15 APOLLO3_PINMUX(15, 3) +#define PDMDATA_P15 APOLLO3_PINMUX(15, 4) +#define SWDIO_P15 APOLLO3_PINMUX(15, 6) +#define SWO_P15 APOLLO3_PINMUX(15, 7) +#define ADCSE0_P16 APOLLO3_PINMUX(16, 0) +#define NCE16_P16 APOLLO3_PINMUX(16, 1) +#define TRIG0_P16 APOLLO3_PINMUX(16, 2) +#define GPIO_P16 APOLLO3_PINMUX(16, 3) +#define SCCRST_P16 APOLLO3_PINMUX(16, 4) +#define CMPIN0_P16 APOLLO3_PINMUX(16, 5) +#define UART0TX_P16 APOLLO3_PINMUX(16, 6) +#define UA1RTS_P16 APOLLO3_PINMUX(16, 7) +#define CMPRF1_P17 APOLLO3_PINMUX(17, 0) +#define NCE17_P17 APOLLO3_PINMUX(17, 1) +#define TRIG1_P17 APOLLO3_PINMUX(17, 2) +#define GPIO_P17 APOLLO3_PINMUX(17, 3) +#define SCCCLK_P17 APOLLO3_PINMUX(17, 4) +#define UART0RX_P17 APOLLO3_PINMUX(17, 6) +#define UA1CTS_P17 APOLLO3_PINMUX(17, 7) +#define CMPIN1_P18 APOLLO3_PINMUX(18, 0) +#define NCE18_P18 APOLLO3_PINMUX(18, 1) +#define CTIM4_P18 APOLLO3_PINMUX(18, 2) +#define GPIO_P18 APOLLO3_PINMUX(18, 3) +#define UA0RTS_P18 APOLLO3_PINMUX(18, 4) +#define UART1TX_P18 APOLLO3_PINMUX(18, 6) +#define SCCIO_P18 APOLLO3_PINMUX(18, 7) +#define CMPRF0_P19 APOLLO3_PINMUX(19, 0) +#define NCE19_P19 APOLLO3_PINMUX(19, 1) +#define CTIM6_P19 APOLLO3_PINMUX(19, 2) +#define GPIO_P19 APOLLO3_PINMUX(19, 3) +#define SCCCLK_P19 APOLLO3_PINMUX(19, 4) +#define UART1RX_P19 APOLLO3_PINMUX(19, 6) +#define I2SBCLK_P19 APOLLO3_PINMUX(19, 7) +#define SWDCK_P20 APOLLO3_PINMUX(20, 0) +#define NCE20_P20 APOLLO3_PINMUX(20, 1) +#define GPIO_P20 APOLLO3_PINMUX(20, 3) +#define UART0TX_P20 APOLLO3_PINMUX(20, 4) +#define UART1TX_P20 APOLLO3_PINMUX(20, 5) +#define I2SBCLK_P20 APOLLO3_PINMUX(20, 6) +#define UA1RTS_P20 APOLLO3_PINMUX(20, 7) +#define SWDIO_P21 APOLLO3_PINMUX(21, 0) +#define NCE21_P21 APOLLO3_PINMUX(21, 1) +#define GPIO_P21 APOLLO3_PINMUX(21, 3) +#define UART0RX_P21 APOLLO3_PINMUX(21, 4) +#define UART1RX_P21 APOLLO3_PINMUX(21, 5) +#define SCCRST_P21 APOLLO3_PINMUX(21, 6) +#define UA1CTS_P21 APOLLO3_PINMUX(21, 7) +#define UART0TX_P22 APOLLO3_PINMUX(22, 0) +#define NCE22_P22 APOLLO3_PINMUX(22, 1) +#define CTIM12_P22 APOLLO3_PINMUX(22, 2) +#define GPIO_P22 APOLLO3_PINMUX(22, 3) +#define PDMCLK_P22 APOLLO3_PINMUX(22, 4) +#define MSPI0_0_P22 APOLLO3_PINMUX(22, 6) +#define SWO_P22 APOLLO3_PINMUX(22, 7) +#define UART0RX_P23 APOLLO3_PINMUX(23, 0) +#define NCE23_P23 APOLLO3_PINMUX(23, 1) +#define CTIM14_P23 APOLLO3_PINMUX(23, 2) +#define GPIO_P23 APOLLO3_PINMUX(23, 3) +#define I2SWCLK_P23 APOLLO3_PINMUX(23, 4) +#define CMPOUT_P23 APOLLO3_PINMUX(23, 5) +#define MSPI0_3_P23 APOLLO3_PINMUX(23, 6) +#define UART1TX_P24 APOLLO3_PINMUX(24, 0) +#define NCE24_P24 APOLLO3_PINMUX(24, 1) +#define MSPI0_8_P24 APOLLO3_PINMUX(24, 2) +#define GPIO_P24 APOLLO3_PINMUX(24, 3) +#define UA0CTS_P24 APOLLO3_PINMUX(24, 4) +#define CTIM21_P24 APOLLO3_PINMUX(24, 5) +#define XT32KHz_P24 APOLLO3_PINMUX(24, 6) +#define SWO_P24 APOLLO3_PINMUX(24, 7) +#define UART1RX_P25 APOLLO3_PINMUX(25, 0) +#define NCE25_P25 APOLLO3_PINMUX(25, 1) +#define CTIM1_P25 APOLLO3_PINMUX(25, 2) +#define GPIO_P25 APOLLO3_PINMUX(25, 3) +#define M2SDAWIR3_P25 APOLLO3_PINMUX(25, 4) +#define M2MISO_P25 APOLLO3_PINMUX(25, 5) +#define NCE26_P26 APOLLO3_PINMUX(26, 1) +#define CTIM3_P26 APOLLO3_PINMUX(26, 2) +#define GPIO_P26 APOLLO3_PINMUX(26, 3) +#define SCCRST_P26 APOLLO3_PINMUX(26, 4) +#define MSPI0_1_P26 APOLLO3_PINMUX(26, 5) +#define UART0TX_P26 APOLLO3_PINMUX(26, 6) +#define UA1CTS_P26 APOLLO3_PINMUX(26, 7) +#define UART0RX_P27 APOLLO3_PINMUX(27, 0) +#define NCE27_P27 APOLLO3_PINMUX(27, 1) +#define CTIM5_P27 APOLLO3_PINMUX(27, 2) +#define GPIO_P27 APOLLO3_PINMUX(27, 3) +#define M2SCL_P27 APOLLO3_PINMUX(27, 4) +#define M2SCK_P27 APOLLO3_PINMUX(27, 5) +#define I2SWCLK_P28 APOLLO3_PINMUX(28, 0) +#define NCE28_P28 APOLLO3_PINMUX(28, 1) +#define CTIM7_P28 APOLLO3_PINMUX(28, 2) +#define GPIO_P28 APOLLO3_PINMUX(28, 3) +#define M2MOSI_P28 APOLLO3_PINMUX(28, 5) +#define UART0TX_P28 APOLLO3_PINMUX(28, 6) +#define ADCSE1_P29 APOLLO3_PINMUX(29, 0) +#define NCE29_P29 APOLLO3_PINMUX(29, 1) +#define CTIM9_P29 APOLLO3_PINMUX(29, 2) +#define GPIO_P29 APOLLO3_PINMUX(29, 3) +#define UA0CTS_P29 APOLLO3_PINMUX(29, 4) +#define UA1CTS_P29 APOLLO3_PINMUX(29, 5) +#define UART0RX_P29 APOLLO3_PINMUX(29, 6) +#define PDMDATA_P29 APOLLO3_PINMUX(29, 7) +#define NCE30_P30 APOLLO3_PINMUX(30, 1) +#define CTIM11_P30 APOLLO3_PINMUX(30, 2) +#define GPIO_P30 APOLLO3_PINMUX(30, 3) +#define UART0TX_P30 APOLLO3_PINMUX(30, 4) +#define UA1RTS_P30 APOLLO3_PINMUX(30, 5) +#define BLEIF_SCK_P30 APOLLO3_PINMUX(30, 6) +#define I2SDAT_P30 APOLLO3_PINMUX(30, 7) +#define ADCSE3_P31 APOLLO3_PINMUX(31, 0) +#define NCE31_P31 APOLLO3_PINMUX(31, 1) +#define CTIM13_P31 APOLLO3_PINMUX(31, 2) +#define GPIO_P31 APOLLO3_PINMUX(31, 3) +#define UART0RX_P31 APOLLO3_PINMUX(31, 4) +#define SCCCLK_P31 APOLLO3_PINMUX(31, 5) +#define BLEIF_MISO_P31 APOLLO3_PINMUX(31, 6) +#define UA1RTS_P31 APOLLO3_PINMUX(31, 7) +#define ADCSE4_P32 APOLLO3_PINMUX(32, 0) +#define NCE32_P32 APOLLO3_PINMUX(32, 1) +#define CTIM15_P32 APOLLO3_PINMUX(32, 2) +#define GPIO_P32 APOLLO3_PINMUX(32, 3) +#define SCCIO_P32 APOLLO3_PINMUX(32, 4) +#define BLEIF_MOSI_P32 APOLLO3_PINMUX(32, 6) +#define UA1CTS_P32 APOLLO3_PINMUX(32, 7) +#define ADCSE5_P33 APOLLO3_PINMUX(33, 0) +#define NCE33_P33 APOLLO3_PINMUX(33, 1) +#define XT32KHz_P33 APOLLO3_PINMUX(33, 2) +#define GPIO_P33 APOLLO3_PINMUX(33, 3) +#define BLEIF_CSN_P33 APOLLO3_PINMUX(33, 4) +#define UA0CTS_P33 APOLLO3_PINMUX(33, 5) +#define CTIM23_P33 APOLLO3_PINMUX(33, 6) +#define SWO_P33 APOLLO3_PINMUX(33, 7) +#define ADCSE6_P34 APOLLO3_PINMUX(34, 0) +#define NCE34_P34 APOLLO3_PINMUX(34, 1) +#define UA1RTS_P34 APOLLO3_PINMUX(34, 2) +#define GPIO_P34 APOLLO3_PINMUX(34, 3) +#define CMPRF2_P34 APOLLO3_PINMUX(34, 4) +#define UA0RTS_P34 APOLLO3_PINMUX(34, 5) +#define UART0RX_P34 APOLLO3_PINMUX(34, 6) +#define PDMDATA_P34 APOLLO3_PINMUX(34, 7) +#define ADCSE7_P35 APOLLO3_PINMUX(35, 0) +#define NCE35_P35 APOLLO3_PINMUX(35, 1) +#define UART1TX_P35 APOLLO3_PINMUX(35, 2) +#define GPIO_P35 APOLLO3_PINMUX(35, 3) +#define I2SDAT_P35 APOLLO3_PINMUX(35, 4) +#define CTIM27_P35 APOLLO3_PINMUX(35, 5) +#define UA0RTS_P35 APOLLO3_PINMUX(35, 6) +#define BLEIF_STATUS_P35 APOLLO3_PINMUX(35, 7) +#define TRIG1_P36 APOLLO3_PINMUX(36, 0) +#define NCE36_P36 APOLLO3_PINMUX(36, 1) +#define UART1RX_P36 APOLLO3_PINMUX(36, 2) +#define GPIO_P36 APOLLO3_PINMUX(36, 3) +#define XT32KHz_P36 APOLLO3_PINMUX(36, 4) +#define UA1CTS_P36 APOLLO3_PINMUX(36, 5) +#define UA0CTS_P36 APOLLO3_PINMUX(36, 6) +#define PDMDATA_P36 APOLLO3_PINMUX(36, 7) +#define TRIG2_P37 APOLLO3_PINMUX(37, 0) +#define NCE37_P37 APOLLO3_PINMUX(37, 1) +#define UA0RTS_P37 APOLLO3_PINMUX(37, 2) +#define GPIO_P37 APOLLO3_PINMUX(37, 3) +#define SCCIO_P37 APOLLO3_PINMUX(37, 4) +#define UART1TX_P37 APOLLO3_PINMUX(37, 5) +#define PDMCLK_P37 APOLLO3_PINMUX(37, 6) +#define CTIM29_P37 APOLLO3_PINMUX(37, 7) +#define TRIG3_P38 APOLLO3_PINMUX(38, 0) +#define NCE38_P38 APOLLO3_PINMUX(38, 1) +#define UA0CTS_P38 APOLLO3_PINMUX(38, 2) +#define GPIO_P38 APOLLO3_PINMUX(38, 3) +#define M3MOSI_P38 APOLLO3_PINMUX(38, 5) +#define UART1RX_P38 APOLLO3_PINMUX(38, 6) +#define UART0TX_P39 APOLLO3_PINMUX(39, 0) +#define UART1TX_P39 APOLLO3_PINMUX(39, 1) +#define CTIM25_P39 APOLLO3_PINMUX(39, 2) +#define GPIO_P39 APOLLO3_PINMUX(39, 3) +#define M4SCL_P39 APOLLO3_PINMUX(39, 4) +#define M4SCK_P39 APOLLO3_PINMUX(39, 5) +#define UART0RX_P40 APOLLO3_PINMUX(40, 0) +#define UART1RX_P40 APOLLO3_PINMUX(40, 1) +#define TRIG0_P40 APOLLO3_PINMUX(40, 2) +#define GPIO_P40 APOLLO3_PINMUX(40, 3) +#define M4SDAWIR3_P40 APOLLO3_PINMUX(40, 4) +#define M4MISO_P40 APOLLO3_PINMUX(40, 5) +#define NCE41_P41 APOLLO3_PINMUX(41, 0) +#define BLEIF_IRQ_P41 APOLLO3_PINMUX(41, 1) +#define SWO_P41 APOLLO3_PINMUX(41, 2) +#define GPIO_P41 APOLLO3_PINMUX(41, 3) +#define I2SWCLK_P41 APOLLO3_PINMUX(41, 4) +#define UA1RTS_P41 APOLLO3_PINMUX(41, 5) +#define UART0TX_P41 APOLLO3_PINMUX(41, 6) +#define UA0RTS_P41 APOLLO3_PINMUX(41, 7) +#define UART1TX_P42 APOLLO3_PINMUX(42, 0) +#define NCE42_P42 APOLLO3_PINMUX(42, 1) +#define CTIM16_P42 APOLLO3_PINMUX(42, 2) +#define GPIO_P42 APOLLO3_PINMUX(42, 3) +#define M3SCL_P42 APOLLO3_PINMUX(42, 4) +#define M3SCK_P42 APOLLO3_PINMUX(42, 5) +#define UART1RX_P43 APOLLO3_PINMUX(43, 0) +#define NCE43_P43 APOLLO3_PINMUX(43, 1) +#define CTIM18_P43 APOLLO3_PINMUX(43, 2) +#define GPIO_P43 APOLLO3_PINMUX(43, 3) +#define M3SDAWIR3_P43 APOLLO3_PINMUX(43, 4) +#define M3MISO_P43 APOLLO3_PINMUX(43, 5) +#define UA1RTS_P44 APOLLO3_PINMUX(44, 0) +#define NCE44_P44 APOLLO3_PINMUX(44, 1) +#define CTIM20_P44 APOLLO3_PINMUX(44, 2) +#define GPIO_P44 APOLLO3_PINMUX(44, 3) +#define M4MOSI_P44 APOLLO3_PINMUX(44, 5) +#define UART0TX_P44 APOLLO3_PINMUX(44, 6) +#define UA1CTS_P45 APOLLO3_PINMUX(45, 0) +#define NCE45_P45 APOLLO3_PINMUX(45, 1) +#define CTIM22_P45 APOLLO3_PINMUX(45, 2) +#define GPIO_P45 APOLLO3_PINMUX(45, 3) +#define I2SDAT_P45 APOLLO3_PINMUX(45, 4) +#define PDMDATA_P45 APOLLO3_PINMUX(45, 5) +#define UART0RX_P45 APOLLO3_PINMUX(45, 6) +#define SWO_P45 APOLLO3_PINMUX(45, 7) +#define I2SBCLK_P46 APOLLO3_PINMUX(46, 0) +#define NCE46_P46 APOLLO3_PINMUX(46, 1) +#define CTIM24_P46 APOLLO3_PINMUX(46, 2) +#define GPIO_P46 APOLLO3_PINMUX(46, 3) +#define SCCRST_P46 APOLLO3_PINMUX(46, 4) +#define PDMCLK_P46 APOLLO3_PINMUX(46, 5) +#define UART1TX_P46 APOLLO3_PINMUX(46, 6) +#define SWO_P46 APOLLO3_PINMUX(46, 7) +#define XT32KHz_P47 APOLLO3_PINMUX(47, 0) +#define NCE47_P47 APOLLO3_PINMUX(47, 1) +#define CTIM26_P47 APOLLO3_PINMUX(47, 2) +#define GPIO_P47 APOLLO3_PINMUX(47, 3) +#define M5MOSI_P47 APOLLO3_PINMUX(47, 5) +#define UART1RX_P47 APOLLO3_PINMUX(47, 6) +#define UART0TX_P48 APOLLO3_PINMUX(48, 0) +#define NCE48_P48 APOLLO3_PINMUX(48, 1) +#define CTIM28_P48 APOLLO3_PINMUX(48, 2) +#define GPIO_P48 APOLLO3_PINMUX(48, 3) +#define M5SCL_P48 APOLLO3_PINMUX(48, 4) +#define M5SCK_P48 APOLLO3_PINMUX(48, 5) +#define UART0RX_P49 APOLLO3_PINMUX(49, 0) +#define NCE49_P49 APOLLO3_PINMUX(49, 1) +#define CTIM30_P49 APOLLO3_PINMUX(49, 2) +#define GPIO_P49 APOLLO3_PINMUX(49, 3) +#define M5SDAWIR3_P49 APOLLO3_PINMUX(49, 4) +#define M5MISO_P49 APOLLO3_PINMUX(49, 5) +#define SWO_P50 APOLLO3_PINMUX(50, 0) +#define NCE50_P50 APOLLO3_PINMUX(50, 1) +#define CT0_P50 APOLLO3_PINMUX(50, 2) +#define GPIO_P50 APOLLO3_PINMUX(50, 3) +#define UART0TX_P50 APOLLO3_PINMUX(50, 4) +#define UART0RX_P50 APOLLO3_PINMUX(50, 5) +#define UART1TX_P50 APOLLO3_PINMUX(50, 6) +#define UART1RX_P50 APOLLO3_PINMUX(50, 7) +#define MSPI1_0_P51 APOLLO3_PINMUX(51, 0) +#define NCE51_P51 APOLLO3_PINMUX(51, 1) +#define CTIM1_P51 APOLLO3_PINMUX(51, 2) +#define GPIO_P51 APOLLO3_PINMUX(51, 3) +#define MSPI1_1_P52 APOLLO3_PINMUX(52, 0) +#define NCE52_P52 APOLLO3_PINMUX(52, 1) +#define CTIM2_P52 APOLLO3_PINMUX(52, 2) +#define GPIO_P52 APOLLO3_PINMUX(52, 3) +#define MSPI1_2_P53 APOLLO3_PINMUX(53, 0) +#define NCE53_P53 APOLLO3_PINMUX(53, 1) +#define CTIM3_P53 APOLLO3_PINMUX(53, 2) +#define GPIO_P53 APOLLO3_PINMUX(53, 3) +#define MSPI1_3_P54 APOLLO3_PINMUX(54, 0) +#define NCE54_P54 APOLLO3_PINMUX(54, 1) +#define CTIM4_P54 APOLLO3_PINMUX(54, 2) +#define GPIO_P54 APOLLO3_PINMUX(54, 3) +#define MSPI1_4_P55 APOLLO3_PINMUX(55, 0) +#define NCE55_P55 APOLLO3_PINMUX(55, 1) +#define CTIM5_P55 APOLLO3_PINMUX(55, 2) +#define GPIO_P55 APOLLO3_PINMUX(55, 3) +#define MSPI1_5_P56 APOLLO3_PINMUX(56, 0) +#define NCE56_P56 APOLLO3_PINMUX(56, 1) +#define CTIM6_P56 APOLLO3_PINMUX(56, 2) +#define GPIO_P56 APOLLO3_PINMUX(56, 3) +#define MSPI1_6_P57 APOLLO3_PINMUX(57, 0) +#define NCE57_P57 APOLLO3_PINMUX(57, 1) +#define CTIM7_P57 APOLLO3_PINMUX(57, 2) +#define GPIO_P57 APOLLO3_PINMUX(57, 3) +#define MSPI1_7_P58 APOLLO3_PINMUX(58, 0) +#define NCE58_P58 APOLLO3_PINMUX(58, 1) +#define CTIM8_P58 APOLLO3_PINMUX(58, 2) +#define GPIO_P58 APOLLO3_PINMUX(58, 3) +#define MSPI1_8_P59 APOLLO3_PINMUX(59, 0) +#define NCE59_P59 APOLLO3_PINMUX(59, 1) +#define CTIM9_P59 APOLLO3_PINMUX(59, 2) +#define GPIO_P59 APOLLO3_PINMUX(59, 3) +#define MSPI1_9_P60 APOLLO3_PINMUX(60, 0) +#define NCE60_P60 APOLLO3_PINMUX(60, 1) +#define CTIM10_P60 APOLLO3_PINMUX(60, 2) +#define GPIO_P60 APOLLO3_PINMUX(60, 3) +#define SWO_P61 APOLLO3_PINMUX(61, 0) +#define NCE61_P61 APOLLO3_PINMUX(61, 1) +#define CTIM11_P61 APOLLO3_PINMUX(61, 2) +#define GPIO_P61 APOLLO3_PINMUX(61, 3) +#define UART0TX_P61 APOLLO3_PINMUX(61, 4) +#define UART0RX_P61 APOLLO3_PINMUX(61, 5) +#define UART1TX_P61 APOLLO3_PINMUX(61, 6) +#define UART1RX_P61 APOLLO3_PINMUX(61, 7) +#define SWO_P62 APOLLO3_PINMUX(62, 0) +#define NCE62_P62 APOLLO3_PINMUX(62, 1) +#define CTIM12_P62 APOLLO3_PINMUX(62, 2) +#define GPIO_P62 APOLLO3_PINMUX(62, 3) +#define UA0CTS_P62 APOLLO3_PINMUX(62, 4) +#define UA0RTS_P62 APOLLO3_PINMUX(62, 5) +#define UA1CTS_P62 APOLLO3_PINMUX(62, 6) +#define UA1RTS_P62 APOLLO3_PINMUX(62, 7) +#define SWO_P63 APOLLO3_PINMUX(63, 0) +#define NCE63_P63 APOLLO3_PINMUX(63, 1) +#define CTIM13_P63 APOLLO3_PINMUX(63, 2) +#define GPIO_P63 APOLLO3_PINMUX(63, 3) +#define UA0CTS_P63 APOLLO3_PINMUX(63, 4) +#define UA0RTS_P63 APOLLO3_PINMUX(63, 5) +#define UA1CTS_P63 APOLLO3_PINMUX(63, 6) +#define UA1RTS_P63 APOLLO3_PINMUX(63, 7) +#define MSPI2_0_P64 APOLLO3_PINMUX(64, 0) +#define NCE64_P64 APOLLO3_PINMUX(64, 1) +#define CTIM14_P64 APOLLO3_PINMUX(64, 2) +#define GPIO_P64 APOLLO3_PINMUX(64, 3) +#define MSPI2_1_P65 APOLLO3_PINMUX(65, 0) +#define NCE65_P65 APOLLO3_PINMUX(65, 1) +#define CTIM15_P65 APOLLO3_PINMUX(65, 2) +#define GPIO_P65 APOLLO3_PINMUX(65, 3) +#define MSPI2_2_P66 APOLLO3_PINMUX(66, 0) +#define NCE66_P66 APOLLO3_PINMUX(66, 1) +#define CTIM16_P66 APOLLO3_PINMUX(66, 2) +#define GPIO_P66 APOLLO3_PINMUX(66, 3) +#define MSPI2_3_P67 APOLLO3_PINMUX(67, 0) +#define NCE67_P67 APOLLO3_PINMUX(67, 1) +#define CTIM17_P67 APOLLO3_PINMUX(67, 2) +#define GPIO_P67 APOLLO3_PINMUX(67, 3) +#define MSPI2_4_P68 APOLLO3_PINMUX(68, 0) +#define NCE68_P68 APOLLO3_PINMUX(68, 1) +#define CTIM18_P68 APOLLO3_PINMUX(68, 2) +#define GPIO_P68 APOLLO3_PINMUX(68, 3) +#define SWO_P69 APOLLO3_PINMUX(69, 0) +#define NCE69_P69 APOLLO3_PINMUX(69, 1) +#define CTIM19_P69 APOLLO3_PINMUX(69, 2) +#define GPIO_P69 APOLLO3_PINMUX(69, 3) +#define UART0TX_P69 APOLLO3_PINMUX(69, 4) +#define UART0RX_P69 APOLLO3_PINMUX(69, 5) +#define UART1TX_P69 APOLLO3_PINMUX(69, 6) +#define UART1RX_P69 APOLLO3_PINMUX(69, 7) +#define SWO_P70 APOLLO3_PINMUX(70, 0) +#define NCE70_P70 APOLLO3_PINMUX(70, 1) +#define CTIM20_P70 APOLLO3_PINMUX(70, 2) +#define GPIO_P70 APOLLO3_PINMUX(70, 3) +#define UART0TX_P70 APOLLO3_PINMUX(70, 4) +#define UART0RX_P70 APOLLO3_PINMUX(70, 5) +#define UART1TX_P70 APOLLO3_PINMUX(70, 6) +#define UART1RX_P70 APOLLO3_PINMUX(70, 7) +#define SWO_P71 APOLLO3_PINMUX(71, 0) +#define NCE71_P71 APOLLO3_PINMUX(71, 1) +#define CTIM21_P71 APOLLO3_PINMUX(71, 2) +#define GPIO_P71 APOLLO3_PINMUX(71, 3) +#define UART0TX_P71 APOLLO3_PINMUX(71, 4) +#define UART0RX_P71 APOLLO3_PINMUX(71, 5) +#define UART1TX_P71 APOLLO3_PINMUX(71, 6) +#define UART1RX_P71 APOLLO3_PINMUX(71, 7) +#define SWO_P72 APOLLO3_PINMUX(72, 0) +#define NCE72_P72 APOLLO3_PINMUX(72, 1) +#define CTIM22_P72 APOLLO3_PINMUX(72, 2) +#define GPIO_P72 APOLLO3_PINMUX(72, 3) +#define UART0TX_P72 APOLLO3_PINMUX(72, 4) +#define UART0RX_P72 APOLLO3_PINMUX(72, 5) +#define UART1TX_P72 APOLLO3_PINMUX(72, 6) +#define UART1RX_P72 APOLLO3_PINMUX(72, 7) +#define SWO_P73 APOLLO3_PINMUX(73, 0) +#define NCE73_P73 APOLLO3_PINMUX(73, 1) +#define CTIM23_P73 APOLLO3_PINMUX(73, 2) +#define GPIO_P73 APOLLO3_PINMUX(73, 3) +#define UA0CTS_P73 APOLLO3_PINMUX(73, 4) +#define UA0RTS_P73 APOLLO3_PINMUX(73, 5) +#define UA1CTS_P73 APOLLO3_PINMUX(73, 6) +#define UA1RTS_P73 APOLLO3_PINMUX(73, 7) + +#endif /* __APOLLO3_PINCTRL_H__ */ diff --git a/include/zephyr/dt-bindings/pinctrl/esp32-pinctrl.h b/include/zephyr/dt-bindings/pinctrl/esp32-pinctrl.h index b961c27facf..2728fbd06f4 100644 --- a/include/zephyr/dt-bindings/pinctrl/esp32-pinctrl.h +++ b/include/zephyr/dt-bindings/pinctrl/esp32-pinctrl.h @@ -8133,6 +8133,164 @@ #define PCNT7_CH1SIG_GPIO39 \ ESP32_PINMUX(39, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) +/* SDHC0_CD */ +#define SDHC0_CD_GPIO5 \ + ESP32_PINMUX(5, ESP_HOST_CARD_DETECT_N_2, ESP_NOSIG) + +#define SDHC0_CD_GPIO6 \ + ESP32_PINMUX(6, ESP_HOST_CARD_DETECT_N_2, ESP_NOSIG) + +#define SDHC0_CD_GPIO7 \ + ESP32_PINMUX(7, ESP_HOST_CARD_DETECT_N_2, ESP_NOSIG) + +#define SDHC0_CD_GPIO8 \ + ESP32_PINMUX(8, ESP_HOST_CARD_DETECT_N_2, ESP_NOSIG) + +#define SDHC0_CD_GPIO9 \ + ESP32_PINMUX(9, ESP_HOST_CARD_DETECT_N_2, ESP_NOSIG) + +#define SDHC0_CD_GPIO10 \ + ESP32_PINMUX(10, ESP_HOST_CARD_DETECT_N_2, ESP_NOSIG) + +#define SDHC0_CD_GPIO11 \ + ESP32_PINMUX(11, ESP_HOST_CARD_DETECT_N_2, ESP_NOSIG) + +#define SDHC0_CD_GPIO16 \ + ESP32_PINMUX(16, ESP_HOST_CARD_DETECT_N_2, ESP_NOSIG) + +#define SDHC0_CD_GPIO17 \ + ESP32_PINMUX(17, ESP_HOST_CARD_DETECT_N_2, ESP_NOSIG) + +#define SDHC0_CD_GPIO18 \ + ESP32_PINMUX(18, ESP_HOST_CARD_DETECT_N_2, ESP_NOSIG) + +#define SDHC0_CD_GPIO19 \ + ESP32_PINMUX(19, ESP_HOST_CARD_DETECT_N_2, ESP_NOSIG) + +#define SDHC0_CD_GPIO20 \ + ESP32_PINMUX(20, ESP_HOST_CARD_DETECT_N_2, ESP_NOSIG) + +#define SDHC0_CD_GPIO21 \ + ESP32_PINMUX(21, ESP_HOST_CARD_DETECT_N_2, ESP_NOSIG) + +#define SDHC0_CD_GPIO22 \ + ESP32_PINMUX(22, ESP_HOST_CARD_DETECT_N_2, ESP_NOSIG) + +#define SDHC0_CD_GPIO23 \ + ESP32_PINMUX(23, ESP_HOST_CARD_DETECT_N_2, ESP_NOSIG) + +#define SDHC0_CD_GPIO25 \ + ESP32_PINMUX(25, ESP_HOST_CARD_DETECT_N_2, ESP_NOSIG) + +#define SDHC0_CD_GPIO26 \ + ESP32_PINMUX(26, ESP_HOST_CARD_DETECT_N_2, ESP_NOSIG) + +#define SDHC0_CD_GPIO27 \ + ESP32_PINMUX(27, ESP_HOST_CARD_DETECT_N_2, ESP_NOSIG) + +#define SDHC0_CD_GPIO32 \ + ESP32_PINMUX(32, ESP_HOST_CARD_DETECT_N_2, ESP_NOSIG) + +#define SDHC0_CD_GPIO33 \ + ESP32_PINMUX(33, ESP_HOST_CARD_DETECT_N_2, ESP_NOSIG) + +#define SDHC0_CD_GPIO34 \ + ESP32_PINMUX(34, ESP_HOST_CARD_DETECT_N_2, ESP_NOSIG) + +#define SDHC0_CD_GPIO35 \ + ESP32_PINMUX(35, ESP_HOST_CARD_DETECT_N_2, ESP_NOSIG) + +#define SDHC0_CD_GPIO36 \ + ESP32_PINMUX(36, ESP_HOST_CARD_DETECT_N_2, ESP_NOSIG) + +#define SDHC0_CD_GPIO37 \ + ESP32_PINMUX(37, ESP_HOST_CARD_DETECT_N_2, ESP_NOSIG) + +#define SDHC0_CD_GPIO38 \ + ESP32_PINMUX(38, ESP_HOST_CARD_DETECT_N_2, ESP_NOSIG) + +#define SDHC0_CD_GPIO39 \ + ESP32_PINMUX(39, ESP_HOST_CARD_DETECT_N_2, ESP_NOSIG) + +/* SDHC0_WP */ +#define SDHC0_WP_GPIO5 \ + ESP32_PINMUX(5, ESP_HOST_CARD_WRITE_PRT_2, ESP_NOSIG) + +#define SDHC0_WP_GPIO6 \ + ESP32_PINMUX(6, ESP_HOST_CARD_WRITE_PRT_2, ESP_NOSIG) + +#define SDHC0_WP_GPIO7 \ + ESP32_PINMUX(7, ESP_HOST_CARD_WRITE_PRT_2, ESP_NOSIG) + +#define SDHC0_WP_GPIO8 \ + ESP32_PINMUX(8, ESP_HOST_CARD_WRITE_PRT_2, ESP_NOSIG) + +#define SDHC0_WP_GPIO9 \ + ESP32_PINMUX(9, ESP_HOST_CARD_WRITE_PRT_2, ESP_NOSIG) + +#define SDHC0_WP_GPIO10 \ + ESP32_PINMUX(10, ESP_HOST_CARD_WRITE_PRT_2, ESP_NOSIG) + +#define SDHC0_WP_GPIO11 \ + ESP32_PINMUX(11, ESP_HOST_CARD_WRITE_PRT_2, ESP_NOSIG) + +#define SDHC0_WP_GPIO16 \ + ESP32_PINMUX(16, ESP_HOST_CARD_WRITE_PRT_2, ESP_NOSIG) + +#define SDHC0_WP_GPIO17 \ + ESP32_PINMUX(17, ESP_HOST_CARD_WRITE_PRT_2, ESP_NOSIG) + +#define SDHC0_WP_GPIO18 \ + ESP32_PINMUX(18, ESP_HOST_CARD_WRITE_PRT_2, ESP_NOSIG) + +#define SDHC0_WP_GPIO19 \ + ESP32_PINMUX(19, ESP_HOST_CARD_WRITE_PRT_2, ESP_NOSIG) + +#define SDHC0_WP_GPIO20 \ + ESP32_PINMUX(20, ESP_HOST_CARD_WRITE_PRT_2, ESP_NOSIG) + +#define SDHC0_WP_GPIO21 \ + ESP32_PINMUX(21, ESP_HOST_CARD_WRITE_PRT_2, ESP_NOSIG) + +#define SDHC0_WP_GPIO22 \ + ESP32_PINMUX(22, ESP_HOST_CARD_WRITE_PRT_2, ESP_NOSIG) + +#define SDHC0_WP_GPIO23 \ + ESP32_PINMUX(23, ESP_HOST_CARD_WRITE_PRT_2, ESP_NOSIG) + +#define SDHC0_WP_GPIO25 \ + ESP32_PINMUX(25, ESP_HOST_CARD_WRITE_PRT_2, ESP_NOSIG) + +#define SDHC0_WP_GPIO26 \ + ESP32_PINMUX(26, ESP_HOST_CARD_WRITE_PRT_2, ESP_NOSIG) + +#define SDHC0_WP_GPIO27 \ + ESP32_PINMUX(27, ESP_HOST_CARD_WRITE_PRT_2, ESP_NOSIG) + +#define SDHC0_WP_GPIO32 \ + ESP32_PINMUX(32, ESP_HOST_CARD_WRITE_PRT_2, ESP_NOSIG) + +#define SDHC0_WP_GPIO33 \ + ESP32_PINMUX(33, ESP_HOST_CARD_WRITE_PRT_2, ESP_NOSIG) + +#define SDHC0_WP_GPIO34 \ + ESP32_PINMUX(34, ESP_HOST_CARD_WRITE_PRT_2, ESP_NOSIG) + +#define SDHC0_WP_GPIO35 \ + ESP32_PINMUX(35, ESP_HOST_CARD_WRITE_PRT_2, ESP_NOSIG) + +#define SDHC0_WP_GPIO36 \ + ESP32_PINMUX(36, ESP_HOST_CARD_WRITE_PRT_2, ESP_NOSIG) + +#define SDHC0_WP_GPIO37 \ + ESP32_PINMUX(37, ESP_HOST_CARD_WRITE_PRT_2, ESP_NOSIG) + +#define SDHC0_WP_GPIO38 \ + ESP32_PINMUX(38, ESP_HOST_CARD_WRITE_PRT_2, ESP_NOSIG) + +#define SDHC0_WP_GPIO39 \ + ESP32_PINMUX(39, ESP_HOST_CARD_WRITE_PRT_2, ESP_NOSIG) + /* SMI_MDC */ #define SMI_MDC_GPIO0 \ ESP32_PINMUX(0, ESP_NOSIG, ESP_EMAC_MDC_O) diff --git a/include/zephyr/dt-bindings/pinctrl/gecko-pinctrl-s1.h b/include/zephyr/dt-bindings/pinctrl/gecko-pinctrl-s1.h index 425c767b2f3..fdfde7fccac 100644 --- a/include/zephyr/dt-bindings/pinctrl/gecko-pinctrl-s1.h +++ b/include/zephyr/dt-bindings/pinctrl/gecko-pinctrl-s1.h @@ -85,6 +85,11 @@ #define GECKO_FUN_SPI_CS_LOC 20U #define GECKO_FUN_SPI_SCK_LOC 21U +#define GECKO_FUN_I2C_SDA 22U +#define GECKO_FUN_I2C_SCL 23U +#define GECKO_FUN_I2C_SDA_LOC 24U +#define GECKO_FUN_I2C_SCL_LOC 25U + /** @} */ diff --git a/include/zephyr/dt-bindings/pinctrl/gecko-pinctrl.h b/include/zephyr/dt-bindings/pinctrl/gecko-pinctrl.h index 5498ca036fb..5624f1e809e 100644 --- a/include/zephyr/dt-bindings/pinctrl/gecko-pinctrl.h +++ b/include/zephyr/dt-bindings/pinctrl/gecko-pinctrl.h @@ -66,6 +66,11 @@ #define GECKO_FUN_SPI_CSN 7U #define GECKO_FUN_SPI_SCK 8U +#define GECKO_FUN_I2C_SDA 9U +#define GECKO_FUN_I2C_SCL 10U +#define GECKO_FUN_I2C_SDA_LOC 11U +#define GECKO_FUN_I2C_SCL_LOC 12U + /** @} */ /** diff --git a/include/zephyr/dt-bindings/reset/npcx4_reset.h b/include/zephyr/dt-bindings/reset/npcx4_reset.h new file mode 100644 index 00000000000..46793b66eac --- /dev/null +++ b/include/zephyr/dt-bindings/reset/npcx4_reset.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2024 Nuvoton Technology Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_RESET_NPCX4_RESET_H +#define ZEPHYR_INCLUDE_DT_BINDINGS_RESET_NPCX4_RESET_H + +#define NPCX_RESET_SWRST_CTL1_OFFSET 0 +#define NPCX_RESET_SWRST_CTL2_OFFSET 32 +#define NPCX_RESET_SWRST_CTL3_OFFSET 64 +#define NPCX_RESET_SWRST_CTL4_OFFSET 96 + +#define NPCX_RESET_GPIO0 (NPCX_RESET_SWRST_CTL1_OFFSET + 0) +#define NPCX_RESET_GPIO1 (NPCX_RESET_SWRST_CTL1_OFFSET + 1) +#define NPCX_RESET_GPIO2 (NPCX_RESET_SWRST_CTL1_OFFSET + 2) +#define NPCX_RESET_GPIO3 (NPCX_RESET_SWRST_CTL1_OFFSET + 3) +#define NPCX_RESET_GPIO4 (NPCX_RESET_SWRST_CTL1_OFFSET + 4) +#define NPCX_RESET_GPIO5 (NPCX_RESET_SWRST_CTL1_OFFSET + 5) +#define NPCX_RESET_GPIO6 (NPCX_RESET_SWRST_CTL1_OFFSET + 6) +#define NPCX_RESET_GPIO7 (NPCX_RESET_SWRST_CTL1_OFFSET + 7) +#define NPCX_RESET_GPIO8 (NPCX_RESET_SWRST_CTL1_OFFSET + 8) +#define NPCX_RESET_GPIO9 (NPCX_RESET_SWRST_CTL1_OFFSET + 9) +#define NPCX_RESET_GPIOA (NPCX_RESET_SWRST_CTL1_OFFSET + 10) +#define NPCX_RESET_GPIOB (NPCX_RESET_SWRST_CTL1_OFFSET + 11) +#define NPCX_RESET_GPIOC (NPCX_RESET_SWRST_CTL1_OFFSET + 12) +#define NPCX_RESET_GPIOD (NPCX_RESET_SWRST_CTL1_OFFSET + 13) +#define NPCX_RESET_GPIOE (NPCX_RESET_SWRST_CTL1_OFFSET + 14) +#define NPCX_RESET_GPIOF (NPCX_RESET_SWRST_CTL1_OFFSET + 15) +#define NPCX_RESET_ITIM64 (NPCX_RESET_SWRST_CTL1_OFFSET + 16) +#define NPCX_RESET_ITIM32_1 (NPCX_RESET_SWRST_CTL1_OFFSET + 18) +#define NPCX_RESET_ITIM32_2 (NPCX_RESET_SWRST_CTL1_OFFSET + 19) +#define NPCX_RESET_ITIM32_3 (NPCX_RESET_SWRST_CTL1_OFFSET + 20) +#define NPCX_RESET_ITIM32_4 (NPCX_RESET_SWRST_CTL1_OFFSET + 21) +#define NPCX_RESET_ITIM32_5 (NPCX_RESET_SWRST_CTL1_OFFSET + 22) +#define NPCX_RESET_ITIM32_6 (NPCX_RESET_SWRST_CTL1_OFFSET + 23) +#define NPCX_RESET_MTC (NPCX_RESET_SWRST_CTL1_OFFSET + 25) +#define NPCX_RESET_MIWU0 (NPCX_RESET_SWRST_CTL1_OFFSET + 26) +#define NPCX_RESET_MIWU1 (NPCX_RESET_SWRST_CTL1_OFFSET + 27) +#define NPCX_RESET_MIWU2 (NPCX_RESET_SWRST_CTL1_OFFSET + 28) +#define NPCX_RESET_GDMA1 (NPCX_RESET_SWRST_CTL1_OFFSET + 29) +#define NPCX_RESET_GDMA2 (NPCX_RESET_SWRST_CTL1_OFFSET + 30) + +#define NPCX_RESET_PMC (NPCX_RESET_SWRST_CTL2_OFFSET + 0) +#define NPCX_RESET_SHI (NPCX_RESET_SWRST_CTL2_OFFSET + 2) +#define NPCX_RESET_SPIP (NPCX_RESET_SWRST_CTL2_OFFSET + 3) +#define NPCX_RESET_ADCE (NPCX_RESET_SWRST_CTL2_OFFSET + 4) +#define NPCX_RESET_PECI (NPCX_RESET_SWRST_CTL2_OFFSET + 5) +#define NPCX_RESET_CRUART2 (NPCX_RESET_SWRST_CTL2_OFFSET + 6) +#define NPCX_RESET_ADCI (NPCX_RESET_SWRST_CTL2_OFFSET + 7) +#define NPCX_RESET_SMB0 (NPCX_RESET_SWRST_CTL2_OFFSET + 8) +#define NPCX_RESET_SMB1 (NPCX_RESET_SWRST_CTL2_OFFSET + 9) +#define NPCX_RESET_SMB2 (NPCX_RESET_SWRST_CTL2_OFFSET + 10) +#define NPCX_RESET_SMB3 (NPCX_RESET_SWRST_CTL2_OFFSET + 11) +#define NPCX_RESET_SMB4 (NPCX_RESET_SWRST_CTL2_OFFSET + 12) +#define NPCX_RESET_SMB5 (NPCX_RESET_SWRST_CTL2_OFFSET + 13) +#define NPCX_RESET_SMB6 (NPCX_RESET_SWRST_CTL2_OFFSET + 14) +#define NPCX_RESET_TWD (NPCX_RESET_SWRST_CTL2_OFFSET + 15) +#define NPCX_RESET_PWM0 (NPCX_RESET_SWRST_CTL2_OFFSET + 16) +#define NPCX_RESET_PWM1 (NPCX_RESET_SWRST_CTL2_OFFSET + 17) +#define NPCX_RESET_PWM2 (NPCX_RESET_SWRST_CTL2_OFFSET + 18) +#define NPCX_RESET_PWM3 (NPCX_RESET_SWRST_CTL2_OFFSET + 19) +#define NPCX_RESET_PWM4 (NPCX_RESET_SWRST_CTL2_OFFSET + 20) +#define NPCX_RESET_PWM5 (NPCX_RESET_SWRST_CTL2_OFFSET + 21) +#define NPCX_RESET_PWM6 (NPCX_RESET_SWRST_CTL2_OFFSET + 22) +#define NPCX_RESET_PWM7 (NPCX_RESET_SWRST_CTL2_OFFSET + 23) +#define NPCX_RESET_MFT16_1 (NPCX_RESET_SWRST_CTL2_OFFSET + 24) +#define NPCX_RESET_MFT16_2 (NPCX_RESET_SWRST_CTL2_OFFSET + 25) +#define NPCX_RESET_MFT16_3 (NPCX_RESET_SWRST_CTL2_OFFSET + 26) +#define NPCX_RESET_SMB7 (NPCX_RESET_SWRST_CTL2_OFFSET + 27) +#define NPCX_RESET_CRUART1 (NPCX_RESET_SWRST_CTL2_OFFSET + 28) +#define NPCX_RESET_PS2 (NPCX_RESET_SWRST_CTL2_OFFSET + 29) +#define NPCX_RESET_SDP (NPCX_RESET_SWRST_CTL2_OFFSET + 30) +#define NPCX_RESET_KBS (NPCX_RESET_SWRST_CTL2_OFFSET + 31) + +#define NPCX_RESET_SIOCFG (NPCX_RESET_SWRST_CTL3_OFFSET + 0) +#define NPCX_RESET_SERPORT (NPCX_RESET_SWRST_CTL3_OFFSET + 1) +#define NPCX_RESET_I3C_1 (NPCX_RESET_SWRST_CTL3_OFFSET + 4) +#define NPCX_RESET_I3C_2 (NPCX_RESET_SWRST_CTL3_OFFSET + 5) +#define NPCX_RESET_I3C_3 (NPCX_RESET_SWRST_CTL3_OFFSET + 6) +#define NPCX_RESET_I3C_RD (NPCX_RESET_SWRST_CTL3_OFFSET + 7) +#define NPCX_RESET_MSWC (NPCX_RESET_SWRST_CTL3_OFFSET + 8) +#define NPCX_RESET_SHM (NPCX_RESET_SWRST_CTL3_OFFSET + 9) +#define NPCX_RESET_PMCH1 (NPCX_RESET_SWRST_CTL3_OFFSET + 10) +#define NPCX_RESET_PMCH2 (NPCX_RESET_SWRST_CTL3_OFFSET + 11) +#define NPCX_RESET_PMCH3 (NPCX_RESET_SWRST_CTL3_OFFSET + 12) +#define NPCX_RESET_PMCH4 (NPCX_RESET_SWRST_CTL3_OFFSET + 13) +#define NPCX_RESET_KBC (NPCX_RESET_SWRST_CTL3_OFFSET + 15) +#define NPCX_RESET_C2HOST (NPCX_RESET_SWRST_CTL3_OFFSET + 16) +#define NPCX_RESET_CRUART3 (NPCX_RESET_SWRST_CTL3_OFFSET + 18) +#define NPCX_RESET_CRUART4 (NPCX_RESET_SWRST_CTL3_OFFSET + 19) +#define NPCX_RESET_LFCG (NPCX_RESET_SWRST_CTL3_OFFSET + 20) +#define NPCX_RESET_DEV (NPCX_RESET_SWRST_CTL3_OFFSET + 22) +#define NPCX_RESET_SYSCFG (NPCX_RESET_SWRST_CTL3_OFFSET + 23) +#define NPCX_RESET_SBY (NPCX_RESET_SWRST_CTL3_OFFSET + 24) +#define NPCX_RESET_BBRAM (NPCX_RESET_SWRST_CTL3_OFFSET + 25) +#define NPCX_RESET_SHA_2B (NPCX_RESET_SWRST_CTL3_OFFSET + 26) +#define NPCX_RESET_SHA_2A (NPCX_RESET_SWRST_CTL3_OFFSET + 29) + +#define NPCX_RESET_MDC (NPCX_RESET_SWRST_CTL4_OFFSET + 15) +#define NPCX_RESET_FIU0 (NPCX_RESET_SWRST_CTL4_OFFSET + 16) +#define NPCX_RESET_FIU1 (NPCX_RESET_SWRST_CTL4_OFFSET + 17) +#define NPCX_RESET_MDMA1 (NPCX_RESET_SWRST_CTL4_OFFSET + 24) +#define NPCX_RESET_MDMA2 (NPCX_RESET_SWRST_CTL4_OFFSET + 25) +#define NPCX_RESET_MDMA3 (NPCX_RESET_SWRST_CTL4_OFFSET + 26) +#define NPCX_RESET_MDMA4 (NPCX_RESET_SWRST_CTL4_OFFSET + 27) +#define NPCX_RESET_MDMA5 (NPCX_RESET_SWRST_CTL4_OFFSET + 28) +#define NPCX_RESET_MDMA6 (NPCX_RESET_SWRST_CTL4_OFFSET + 29) +#define NPCX_RESET_MDMA7 (NPCX_RESET_SWRST_CTL4_OFFSET + 30) + +#define NPCX_RESET_ID_START NPCX_RESET_GPIO0 +#define NPCX_RESET_ID_END NPCX_RESET_MDMA7 +#endif diff --git a/include/zephyr/dt-bindings/reset/npcx7_reset.h b/include/zephyr/dt-bindings/reset/npcx7_reset.h new file mode 100644 index 00000000000..b9df5482976 --- /dev/null +++ b/include/zephyr/dt-bindings/reset/npcx7_reset.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2024 Nuvoton Technology Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_RESET_NPCX7_RESET_H +#define ZEPHYR_INCLUDE_DT_BINDINGS_RESET_NPCX7_RESET_H + +#define NPCX_RESET_SWRST_CTL1_OFFSET 0 +#define NPCX_RESET_SWRST_CTL2_OFFSET 32 +#define NPCX_RESET_SWRST_CTL3_OFFSET 64 + +#define NPCX_RESET_GPIO0 (NPCX_RESET_SWRST_CTL1_OFFSET + 0) +#define NPCX_RESET_GPIO1 (NPCX_RESET_SWRST_CTL1_OFFSET + 1) +#define NPCX_RESET_GPIO2 (NPCX_RESET_SWRST_CTL1_OFFSET + 2) +#define NPCX_RESET_GPIO3 (NPCX_RESET_SWRST_CTL1_OFFSET + 3) +#define NPCX_RESET_GPIO4 (NPCX_RESET_SWRST_CTL1_OFFSET + 4) +#define NPCX_RESET_GPIO5 (NPCX_RESET_SWRST_CTL1_OFFSET + 5) +#define NPCX_RESET_GPIO6 (NPCX_RESET_SWRST_CTL1_OFFSET + 6) +#define NPCX_RESET_GPIO7 (NPCX_RESET_SWRST_CTL1_OFFSET + 7) +#define NPCX_RESET_GPIO8 (NPCX_RESET_SWRST_CTL1_OFFSET + 8) +#define NPCX_RESET_GPIO9 (NPCX_RESET_SWRST_CTL1_OFFSET + 9) +#define NPCX_RESET_GPIOA (NPCX_RESET_SWRST_CTL1_OFFSET + 10) +#define NPCX_RESET_GPIOB (NPCX_RESET_SWRST_CTL1_OFFSET + 11) +#define NPCX_RESET_GPIOC (NPCX_RESET_SWRST_CTL1_OFFSET + 12) +#define NPCX_RESET_GPIOD (NPCX_RESET_SWRST_CTL1_OFFSET + 13) +#define NPCX_RESET_GPIOE (NPCX_RESET_SWRST_CTL1_OFFSET + 14) +#define NPCX_RESET_GPIOF (NPCX_RESET_SWRST_CTL1_OFFSET + 15) +#define NPCX_RESET_ITIM64 (NPCX_RESET_SWRST_CTL1_OFFSET + 16) +#define NPCX_RESET_ITIM16_1 (NPCX_RESET_SWRST_CTL1_OFFSET + 18) +#define NPCX_RESET_ITIM16_2 (NPCX_RESET_SWRST_CTL1_OFFSET + 19) +#define NPCX_RESET_ITIM16_3 (NPCX_RESET_SWRST_CTL1_OFFSET + 20) +#define NPCX_RESET_ITIM16_4 (NPCX_RESET_SWRST_CTL1_OFFSET + 21) +#define NPCX_RESET_ITIM16_5 (NPCX_RESET_SWRST_CTL1_OFFSET + 22) +#define NPCX_RESET_ITIM16_6 (NPCX_RESET_SWRST_CTL1_OFFSET + 23) +#define NPCX_RESET_ITIM32 (NPCX_RESET_SWRST_CTL1_OFFSET + 24) +#define NPCX_RESET_MTC (NPCX_RESET_SWRST_CTL1_OFFSET + 25) +#define NPCX_RESET_MIWU0 (NPCX_RESET_SWRST_CTL1_OFFSET + 26) +#define NPCX_RESET_MIWU1 (NPCX_RESET_SWRST_CTL1_OFFSET + 27) +#define NPCX_RESET_MIWU2 (NPCX_RESET_SWRST_CTL1_OFFSET + 28) +#define NPCX_RESET_GDMA (NPCX_RESET_SWRST_CTL1_OFFSET + 29) +#define NPCX_RESET_FIU (NPCX_RESET_SWRST_CTL1_OFFSET + 30) + +#define NPCX_RESET_PMC (NPCX_RESET_SWRST_CTL2_OFFSET + 0) +#define NPCX_RESET_SHI (NPCX_RESET_SWRST_CTL2_OFFSET + 2) +#define NPCX_RESET_SPIP (NPCX_RESET_SWRST_CTL2_OFFSET + 3) +#define NPCX_RESET_PECI (NPCX_RESET_SWRST_CTL2_OFFSET + 5) +#define NPCX_RESET_CRUART2 (NPCX_RESET_SWRST_CTL2_OFFSET + 6) +#define NPCX_RESET_ADC (NPCX_RESET_SWRST_CTL2_OFFSET + 7) +#define NPCX_RESET_SMB0 (NPCX_RESET_SWRST_CTL2_OFFSET + 8) +#define NPCX_RESET_SMB1 (NPCX_RESET_SWRST_CTL2_OFFSET + 9) +#define NPCX_RESET_SMB2 (NPCX_RESET_SWRST_CTL2_OFFSET + 10) +#define NPCX_RESET_SMB3 (NPCX_RESET_SWRST_CTL2_OFFSET + 11) +#define NPCX_RESET_SMB4 (NPCX_RESET_SWRST_CTL2_OFFSET + 12) +#define NPCX_RESET_SMB5 (NPCX_RESET_SWRST_CTL2_OFFSET + 13) +#define NPCX_RESET_SMB6 (NPCX_RESET_SWRST_CTL2_OFFSET + 14) +#define NPCX_RESET_TWD (NPCX_RESET_SWRST_CTL2_OFFSET + 15) +#define NPCX_RESET_PWM0 (NPCX_RESET_SWRST_CTL2_OFFSET + 16) +#define NPCX_RESET_PWM1 (NPCX_RESET_SWRST_CTL2_OFFSET + 17) +#define NPCX_RESET_PWM2 (NPCX_RESET_SWRST_CTL2_OFFSET + 18) +#define NPCX_RESET_PWM3 (NPCX_RESET_SWRST_CTL2_OFFSET + 19) +#define NPCX_RESET_PWM4 (NPCX_RESET_SWRST_CTL2_OFFSET + 20) +#define NPCX_RESET_PWM5 (NPCX_RESET_SWRST_CTL2_OFFSET + 21) +#define NPCX_RESET_PWM6 (NPCX_RESET_SWRST_CTL2_OFFSET + 22) +#define NPCX_RESET_PWM7 (NPCX_RESET_SWRST_CTL2_OFFSET + 23) +#define NPCX_RESET_MFT16_1 (NPCX_RESET_SWRST_CTL2_OFFSET + 24) +#define NPCX_RESET_MFT16_2 (NPCX_RESET_SWRST_CTL2_OFFSET + 25) +#define NPCX_RESET_MFT16_3 (NPCX_RESET_SWRST_CTL2_OFFSET + 26) +#define NPCX_RESET_SMB7 (NPCX_RESET_SWRST_CTL2_OFFSET + 27) +#define NPCX_RESET_CRUART1 (NPCX_RESET_SWRST_CTL2_OFFSET + 28) +#define NPCX_RESET_PS2 (NPCX_RESET_SWRST_CTL2_OFFSET + 29) +#define NPCX_RESET_SDP (NPCX_RESET_SWRST_CTL2_OFFSET + 30) +#define NPCX_RESET_KBS (NPCX_RESET_SWRST_CTL2_OFFSET + 31) + +#define NPCX_RESET_SIOCFG (NPCX_RESET_SWRST_CTL3_OFFSET + 0) +#define NPCX_RESET_SERPORT (NPCX_RESET_SWRST_CTL3_OFFSET + 1) +#define NPCX_RESET_MSWC (NPCX_RESET_SWRST_CTL3_OFFSET + 8) +#define NPCX_RESET_SHM (NPCX_RESET_SWRST_CTL3_OFFSET + 9) +#define NPCX_RESET_PMCH1 (NPCX_RESET_SWRST_CTL3_OFFSET + 10) +#define NPCX_RESET_PMCH2 (NPCX_RESET_SWRST_CTL3_OFFSET + 11) +#define NPCX_RESET_PMCH3 (NPCX_RESET_SWRST_CTL3_OFFSET + 12) +#define NPCX_RESET_PMCH4 (NPCX_RESET_SWRST_CTL3_OFFSET + 13) +#define NPCX_RESET_KBC (NPCX_RESET_SWRST_CTL3_OFFSET + 15) +#define NPCX_RESET_C2HOST (NPCX_RESET_SWRST_CTL3_OFFSET + 16) +#define NPCX_RESET_LFCG (NPCX_RESET_SWRST_CTL3_OFFSET + 20) +#define NPCX_RESET_DEV (NPCX_RESET_SWRST_CTL3_OFFSET + 22) +#define NPCX_RESET_SYSCFG (NPCX_RESET_SWRST_CTL3_OFFSET + 23) +#define NPCX_RESET_SBY (NPCX_RESET_SWRST_CTL3_OFFSET + 24) +#define NPCX_RESET_BBRAM (NPCX_RESET_SWRST_CTL3_OFFSET + 25) + +#define NPCX_RESET_ID_START NPCX_RESET_GPIO0 +#define NPCX_RESET_ID_END NPCX_RESET_BBRAM +#endif diff --git a/include/zephyr/dt-bindings/reset/npcx9_reset.h b/include/zephyr/dt-bindings/reset/npcx9_reset.h new file mode 100644 index 00000000000..c8032bddd30 --- /dev/null +++ b/include/zephyr/dt-bindings/reset/npcx9_reset.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2024 Nuvoton Technology Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_RESET_NPCX9_RESET_H +#define ZEPHYR_INCLUDE_DT_BINDINGS_RESET_NPCX9_RESET_H + +#define NPCX_RESET_SWRST_CTL1_OFFSET 0 +#define NPCX_RESET_SWRST_CTL2_OFFSET 32 +#define NPCX_RESET_SWRST_CTL3_OFFSET 64 +#define NPCX_RESET_SWRST_CTL4_OFFSET 96 + +#define NPCX_RESET_GPIO0 (NPCX_RESET_SWRST_CTL1_OFFSET + 0) +#define NPCX_RESET_GPIO1 (NPCX_RESET_SWRST_CTL1_OFFSET + 1) +#define NPCX_RESET_GPIO2 (NPCX_RESET_SWRST_CTL1_OFFSET + 2) +#define NPCX_RESET_GPIO3 (NPCX_RESET_SWRST_CTL1_OFFSET + 3) +#define NPCX_RESET_GPIO4 (NPCX_RESET_SWRST_CTL1_OFFSET + 4) +#define NPCX_RESET_GPIO5 (NPCX_RESET_SWRST_CTL1_OFFSET + 5) +#define NPCX_RESET_GPIO6 (NPCX_RESET_SWRST_CTL1_OFFSET + 6) +#define NPCX_RESET_GPIO7 (NPCX_RESET_SWRST_CTL1_OFFSET + 7) +#define NPCX_RESET_GPIO8 (NPCX_RESET_SWRST_CTL1_OFFSET + 8) +#define NPCX_RESET_GPIO9 (NPCX_RESET_SWRST_CTL1_OFFSET + 9) +#define NPCX_RESET_GPIOA (NPCX_RESET_SWRST_CTL1_OFFSET + 10) +#define NPCX_RESET_GPIOB (NPCX_RESET_SWRST_CTL1_OFFSET + 11) +#define NPCX_RESET_GPIOC (NPCX_RESET_SWRST_CTL1_OFFSET + 12) +#define NPCX_RESET_GPIOD (NPCX_RESET_SWRST_CTL1_OFFSET + 13) +#define NPCX_RESET_GPIOE (NPCX_RESET_SWRST_CTL1_OFFSET + 14) +#define NPCX_RESET_GPIOF (NPCX_RESET_SWRST_CTL1_OFFSET + 15) +#define NPCX_RESET_ITIM64 (NPCX_RESET_SWRST_CTL1_OFFSET + 16) +#define NPCX_RESET_ITIM32_1 (NPCX_RESET_SWRST_CTL1_OFFSET + 18) +#define NPCX_RESET_ITIM32_2 (NPCX_RESET_SWRST_CTL1_OFFSET + 19) +#define NPCX_RESET_ITIM32_3 (NPCX_RESET_SWRST_CTL1_OFFSET + 20) +#define NPCX_RESET_ITIM32_4 (NPCX_RESET_SWRST_CTL1_OFFSET + 21) +#define NPCX_RESET_ITIM32_5 (NPCX_RESET_SWRST_CTL1_OFFSET + 22) +#define NPCX_RESET_ITIM32_6 (NPCX_RESET_SWRST_CTL1_OFFSET + 23) +#define NPCX_RESET_MTC (NPCX_RESET_SWRST_CTL1_OFFSET + 25) +#define NPCX_RESET_MIWU0 (NPCX_RESET_SWRST_CTL1_OFFSET + 26) +#define NPCX_RESET_MIWU1 (NPCX_RESET_SWRST_CTL1_OFFSET + 27) +#define NPCX_RESET_MIWU2 (NPCX_RESET_SWRST_CTL1_OFFSET + 28) +#define NPCX_RESET_GDMA (NPCX_RESET_SWRST_CTL1_OFFSET + 29) +#define NPCX_RESET_FIU (NPCX_RESET_SWRST_CTL1_OFFSET + 30) + +#define NPCX_RESET_PMC (NPCX_RESET_SWRST_CTL2_OFFSET + 0) +#define NPCX_RESET_SHI (NPCX_RESET_SWRST_CTL2_OFFSET + 2) +#define NPCX_RESET_SPIP (NPCX_RESET_SWRST_CTL2_OFFSET + 3) +#define NPCX_RESET_PECI (NPCX_RESET_SWRST_CTL2_OFFSET + 5) +#define NPCX_RESET_CRUART2 (NPCX_RESET_SWRST_CTL2_OFFSET + 6) +#define NPCX_RESET_ADC (NPCX_RESET_SWRST_CTL2_OFFSET + 7) +#define NPCX_RESET_SMB0 (NPCX_RESET_SWRST_CTL2_OFFSET + 8) +#define NPCX_RESET_SMB1 (NPCX_RESET_SWRST_CTL2_OFFSET + 9) +#define NPCX_RESET_SMB2 (NPCX_RESET_SWRST_CTL2_OFFSET + 10) +#define NPCX_RESET_SMB3 (NPCX_RESET_SWRST_CTL2_OFFSET + 11) +#define NPCX_RESET_SMB4 (NPCX_RESET_SWRST_CTL2_OFFSET + 12) +#define NPCX_RESET_SMB5 (NPCX_RESET_SWRST_CTL2_OFFSET + 13) +#define NPCX_RESET_SMB6 (NPCX_RESET_SWRST_CTL2_OFFSET + 14) +#define NPCX_RESET_TWD (NPCX_RESET_SWRST_CTL2_OFFSET + 15) +#define NPCX_RESET_PWM0 (NPCX_RESET_SWRST_CTL2_OFFSET + 16) +#define NPCX_RESET_PWM1 (NPCX_RESET_SWRST_CTL2_OFFSET + 17) +#define NPCX_RESET_PWM2 (NPCX_RESET_SWRST_CTL2_OFFSET + 18) +#define NPCX_RESET_PWM3 (NPCX_RESET_SWRST_CTL2_OFFSET + 19) +#define NPCX_RESET_PWM4 (NPCX_RESET_SWRST_CTL2_OFFSET + 20) +#define NPCX_RESET_PWM5 (NPCX_RESET_SWRST_CTL2_OFFSET + 21) +#define NPCX_RESET_PWM6 (NPCX_RESET_SWRST_CTL2_OFFSET + 22) +#define NPCX_RESET_PWM7 (NPCX_RESET_SWRST_CTL2_OFFSET + 23) +#define NPCX_RESET_MFT16_1 (NPCX_RESET_SWRST_CTL2_OFFSET + 24) +#define NPCX_RESET_MFT16_2 (NPCX_RESET_SWRST_CTL2_OFFSET + 25) +#define NPCX_RESET_MFT16_3 (NPCX_RESET_SWRST_CTL2_OFFSET + 26) +#define NPCX_RESET_SMB7 (NPCX_RESET_SWRST_CTL2_OFFSET + 27) +#define NPCX_RESET_CRUART1 (NPCX_RESET_SWRST_CTL2_OFFSET + 28) +#define NPCX_RESET_PS2 (NPCX_RESET_SWRST_CTL2_OFFSET + 29) +#define NPCX_RESET_SDP (NPCX_RESET_SWRST_CTL2_OFFSET + 30) +#define NPCX_RESET_KBS (NPCX_RESET_SWRST_CTL2_OFFSET + 31) + +#define NPCX_RESET_SIOCFG (NPCX_RESET_SWRST_CTL3_OFFSET + 0) +#define NPCX_RESET_SERPORT (NPCX_RESET_SWRST_CTL3_OFFSET + 1) +#define NPCX_RESET_I3C (NPCX_RESET_SWRST_CTL3_OFFSET + 5) +#define NPCX_RESET_MSWC (NPCX_RESET_SWRST_CTL3_OFFSET + 8) +#define NPCX_RESET_SHM (NPCX_RESET_SWRST_CTL3_OFFSET + 9) +#define NPCX_RESET_PMCH1 (NPCX_RESET_SWRST_CTL3_OFFSET + 10) +#define NPCX_RESET_PMCH2 (NPCX_RESET_SWRST_CTL3_OFFSET + 11) +#define NPCX_RESET_PMCH3 (NPCX_RESET_SWRST_CTL3_OFFSET + 12) +#define NPCX_RESET_PMCH4 (NPCX_RESET_SWRST_CTL3_OFFSET + 13) +#define NPCX_RESET_KBC (NPCX_RESET_SWRST_CTL3_OFFSET + 15) +#define NPCX_RESET_C2HOST (NPCX_RESET_SWRST_CTL3_OFFSET + 16) +#define NPCX_RESET_CRUART3 (NPCX_RESET_SWRST_CTL3_OFFSET + 18) +#define NPCX_RESET_CRUART4 (NPCX_RESET_SWRST_CTL3_OFFSET + 19) +#define NPCX_RESET_LFCG (NPCX_RESET_SWRST_CTL3_OFFSET + 20) +#define NPCX_RESET_DEV (NPCX_RESET_SWRST_CTL3_OFFSET + 22) +#define NPCX_RESET_SYSCFG (NPCX_RESET_SWRST_CTL3_OFFSET + 23) +#define NPCX_RESET_SBY (NPCX_RESET_SWRST_CTL3_OFFSET + 24) +#define NPCX_RESET_BBRAM (NPCX_RESET_SWRST_CTL3_OFFSET + 25) +#define NPCX_RESET_SHA (NPCX_RESET_SWRST_CTL3_OFFSET + 29) + +#define NPCX_RESET_MDMA1 (NPCX_RESET_SWRST_CTL4_OFFSET + 24) +#define NPCX_RESET_MDMA2 (NPCX_RESET_SWRST_CTL4_OFFSET + 25) +#define NPCX_RESET_MDMA3 (NPCX_RESET_SWRST_CTL4_OFFSET + 26) +#define NPCX_RESET_MDMA4 (NPCX_RESET_SWRST_CTL4_OFFSET + 27) +#define NPCX_RESET_MDMA5 (NPCX_RESET_SWRST_CTL4_OFFSET + 28) + +#define NPCX_RESET_ID_START NPCX_RESET_GPIO0 +#define NPCX_RESET_ID_END NPCX_RESET_MDMA5 +#endif diff --git a/include/zephyr/dt-bindings/reset/nxp_syscon_reset_common.h b/include/zephyr/dt-bindings/reset/nxp_syscon_reset_common.h new file mode 100644 index 00000000000..9888572325a --- /dev/null +++ b/include/zephyr/dt-bindings/reset/nxp_syscon_reset_common.h @@ -0,0 +1,12 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_RESET_NXP_SYSCON_RESET_COMMON_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_RESET_NXP_SYSCON_RESET_COMMON_H_ + +#define NXP_SYSCON_RESET(offset, bit) ((offset << 16) | bit) + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_RESET_NXP_SYSCON_RESET_COMMON_H_ */ diff --git a/include/zephyr/dt-bindings/sensor/ina226.h b/include/zephyr/dt-bindings/sensor/ina226.h new file mode 100644 index 00000000000..9efd704eb9d --- /dev/null +++ b/include/zephyr/dt-bindings/sensor/ina226.h @@ -0,0 +1,45 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_INA226_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_INA226_H_ + +#include + +/* Reset Mode. */ +#define INA226_RST_NORMAL_OPERATION 0x00 +#define INA226_RST_SYSTEM_RESET 0x01 + +/* Averaging Mode. */ +#define INA226_AVG_MODE_1 0x00 +#define INA226_AVG_MODE_4 0x01 +#define INA226_AVG_MODE_16 0x02 +#define INA226_AVG_MODE_64 0x03 +#define INA226_AVG_MODE_128 0x04 +#define INA226_AVG_MODE_256 0x05 +#define INA226_AVG_MODE_512 0x06 +#define INA226_AVG_MODE_1024 0x07 + +/* Conversion time for bus and shunt voltage in micro-seconds. */ +#define INA226_CONV_TIME_140 0x00 +#define INA226_CONV_TIME_204 0x01 +#define INA226_CONV_TIME_332 0x02 +#define INA226_CONV_TIME_588 0x03 +#define INA226_CONV_TIME_1100 0x04 +#define INA226_CONV_TIME_2116 0x05 +#define INA226_CONV_TIME_4156 0x06 +#define INA226_CONV_TIME_8244 0x07 + +/* Operating Mode. */ +#define INA226_OPER_MODE_POWER_DOWN 0x00 +#define INA226_OPER_MODE_SHUNT_VOLTAGE_TRIG 0x01 +#define INA226_OPER_MODE_BUS_VOLTAGE_TRIG 0x02 +#define INA226_OPER_MODE_SHUNT_BUS_VOLTAGE_TRIG 0x03 +#define INA226_OPER_MODE_SHUNT_VOLTAGE_CONT 0x05 +#define INA226_OPER_MODE_BUS_VOLTAGE_CONT 0x06 +#define INA226_OPER_MODE_SHUNT_BUS_VOLTAGE_CONT 0x07 + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_INA226_H_ */ diff --git a/include/zephyr/dt-bindings/sensor/lis2dh.h b/include/zephyr/dt-bindings/sensor/lis2dh.h index a697f34cc80..ff13d13a321 100644 --- a/include/zephyr/dt-bindings/sensor/lis2dh.h +++ b/include/zephyr/dt-bindings/sensor/lis2dh.h @@ -7,7 +7,7 @@ #define ZEPHYR_INCLUDE_DT_BINDINGS_ST_LIS2DH_H_ /* GPIO interrupt configuration */ -#define LIS2DH_DT_GPIO_INT_EDGE 0 +#define LIS2DH_DT_GPIO_INT_EDGE_BOTH 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 diff --git a/include/zephyr/input/input_paw32xx.h b/include/zephyr/input/input_paw32xx.h new file mode 100644 index 00000000000..ff425bda8b6 --- /dev/null +++ b/include/zephyr/input/input_paw32xx.h @@ -0,0 +1,26 @@ +/* + * Copyright 2024 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_INPUT_PAW32XX_H_ +#define ZEPHYR_INCLUDE_INPUT_PAW32XX_H_ + +/** + * @brief Set resolution on a paw32xx device + * + * @param dev paw32xx device. + * @param res_cpi CPI resolution, 200 to 3200. + */ +int paw32xx_set_resolution(const struct device *dev, uint16_t res_cpi); + +/** + * @brief Set force awake mode on a paw32xx device + * + * @param dev paw32xx device. + * @param enable whether to enable or disable force awake mode. + */ +int paw32xx_force_awake(const struct device *dev, bool enable); + +#endif /* ZEPHYR_INCLUDE_INPUT_PAW32XX_H_ */ diff --git a/include/zephyr/internal/syscall_handler.h b/include/zephyr/internal/syscall_handler.h index d3879621917..09a19f10743 100644 --- a/include/zephyr/internal/syscall_handler.h +++ b/include/zephyr/internal/syscall_handler.h @@ -62,7 +62,7 @@ static inline bool k_is_in_user_syscall(void) * calls from supervisor mode bypass everything directly to * the implementation function. */ - return !k_is_in_isr() && _current->syscall_frame != NULL; + return !k_is_in_isr() && (_current->syscall_frame != NULL); } /** diff --git a/include/zephyr/ipc/icmsg.h b/include/zephyr/ipc/icmsg.h index 3bc03804ca8..80e3412095a 100644 --- a/include/zephyr/ipc/icmsg.h +++ b/include/zephyr/ipc/icmsg.h @@ -111,7 +111,7 @@ int icmsg_close(const struct icmsg_config_t *conf, * @param[in] len Size of data in the @p msg buffer. * * - * @retval 0 on success. + * @retval Number of sent bytes. * @retval -EBUSY when the instance has not finished handshake with the remote * instance. * @retval -ENODATA when the requested data to send is empty. diff --git a/include/zephyr/kernel.h b/include/zephyr/kernel.h index da43eea9771..32c554c159d 100644 --- a/include/zephyr/kernel.h +++ b/include/zephyr/kernel.h @@ -46,7 +46,7 @@ BUILD_ASSERT(sizeof(intptr_t) == sizeof(long)); #define K_ANY NULL -#if CONFIG_NUM_COOP_PRIORITIES + CONFIG_NUM_PREEMPT_PRIORITIES == 0 +#if (CONFIG_NUM_COOP_PRIORITIES + CONFIG_NUM_PREEMPT_PRIORITIES) == 0 #error Zero available thread priorities defined! #endif @@ -1774,6 +1774,19 @@ static inline uint32_t k_uptime_get_32(void) return (uint32_t)k_uptime_get(); } +/** + * @brief Get system uptime in seconds. + * + * This routine returns the elapsed time since the system booted, + * in seconds. + * + * @return Current uptime in seconds. + */ +static inline uint32_t k_uptime_seconds(void) +{ + return k_ticks_to_sec_floor32(k_uptime_ticks()); +} + /** * @brief Get elapsed time. * @@ -2017,9 +2030,8 @@ int k_queue_merge_slist(struct k_queue *queue, sys_slist_t *list); * @funcprops \isr_ok * * @param queue Address of the queue. - * @param timeout Non-negative waiting period to obtain a data item - * or one of the special values K_NO_WAIT and - * K_FOREVER. + * @param timeout Waiting period to obtain a data item, or one of the special + * values K_NO_WAIT and K_FOREVER. * * @return Address of the data item if successful; NULL if returned * without waiting, or waiting period timed out. @@ -2163,8 +2175,8 @@ struct z_futex_data { * @param futex Address of the futex. * @param expected Expected value of the futex, if it is different the caller * will not wait on it. - * @param timeout Non-negative waiting period on the futex, or - * one of the special values K_NO_WAIT or K_FOREVER. + * @param timeout Waiting period on the futex, or one of the special values + * K_NO_WAIT or K_FOREVER. * @retval -EACCES Caller does not have read access to futex address. * @retval -EAGAIN If the futex value did not match the expected parameter. * @retval -EINVAL Futex parameter address not recognized by the kernel. @@ -4004,6 +4016,11 @@ struct k_work_queue_config { * control. */ bool no_yield; + + /** Control whether the work queue thread should be marked as + * essential thread. + */ + bool essential; }; /** @brief A structure used to hold work until it can be processed. */ @@ -4559,9 +4576,8 @@ int k_msgq_cleanup(struct k_msgq *msgq); * * @param msgq Address of the message queue. * @param data Pointer to the message. - * @param timeout Non-negative waiting period to add the message, - * or one of the special values K_NO_WAIT and - * K_FOREVER. + * @param timeout Waiting period to add the message, or one of the special + * values K_NO_WAIT and K_FOREVER. * * @retval 0 Message sent. * @retval -ENOMSG Returned without waiting or queue purged. @@ -5186,7 +5202,7 @@ int k_mem_slab_init(struct k_mem_slab *slab, void *buffer, * * @param slab Address of the memory slab. * @param mem Pointer to block address area. - * @param timeout Non-negative waiting period to wait for operation to complete. + * @param timeout Waiting period to wait for operation to complete. * Use K_NO_WAIT to return without waiting, * or K_FOREVER to wait as long as necessary. * @@ -5318,7 +5334,8 @@ struct k_heap { void k_heap_init(struct k_heap *h, void *mem, size_t bytes) __attribute_nonnull(1); -/** @brief Allocate aligned memory from a k_heap +/** + * @brief Allocate aligned memory from a k_heap * * Behaves in all ways like k_heap_alloc(), except that the returned * memory (if available) will have a starting address in memory which @@ -5379,7 +5396,7 @@ 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] */ -#define Z_HEAP_MIN_SIZE (sizeof(void *) > 4 ? 56 : 44) +#define Z_HEAP_MIN_SIZE ((sizeof(void *) > 4) ? 56 : 44) /** * @brief Define a static k_heap in the specified linker section @@ -5780,7 +5797,7 @@ __syscall int k_poll(struct k_poll_event *events, int num_events, __syscall void k_poll_signal_init(struct k_poll_signal *sig); -/* +/** * @brief Reset a poll signal object's state to unsignaled. * * @param sig A poll signal object diff --git a/include/zephyr/kernel/internal/mm.h b/include/zephyr/kernel/internal/mm.h index d4183753415..61a8c69c5ee 100644 --- a/include/zephyr/kernel/internal/mm.h +++ b/include/zephyr/kernel/internal/mm.h @@ -168,7 +168,7 @@ extern "C" { * This API is part of infrastructure still under development and may * change. * - * @param[out] virt Output virtual address storage location + * @param[out] virt_ptr 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 diff --git a/include/zephyr/kernel/mm/demand_paging.h b/include/zephyr/kernel/mm/demand_paging.h index 35dae90a235..343c10478b9 100644 --- a/include/zephyr/kernel/mm/demand_paging.h +++ b/include/zephyr/kernel/mm/demand_paging.h @@ -267,10 +267,10 @@ void k_mem_paging_eviction_init(void); * 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. + * z_page_frame_to_virt(pf) 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 that virtual address 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 diff --git a/include/zephyr/kernel/thread.h b/include/zephyr/kernel/thread.h index cbbb35aa7d6..fd8e4c02f23 100644 --- a/include/zephyr/kernel/thread.h +++ b/include/zephyr/kernel/thread.h @@ -206,13 +206,12 @@ struct _thread_userspace_local_data { typedef struct k_thread_runtime_stats { #ifdef CONFIG_SCHED_THREAD_USAGE - uint64_t execution_cycles; - uint64_t total_cycles; /* total # of non-idle cycles */ /* - * In the context of thread statistics, [execution_cycles] is the same - * as the total # of non-idle cycles. In the context of CPU statistics, - * it refers to the sum of non-idle + idle cycles. + * For CPU stats, execution_cycles is the sum of non-idle + idle cycles. + * For thread stats, execution_cycles = total_cycles. */ + uint64_t execution_cycles; /* total # of cycles (cpu: non-idle + idle) */ + uint64_t total_cycles; /* total # of non-idle cycles */ #endif /* CONFIG_SCHED_THREAD_USAGE */ #ifdef CONFIG_SCHED_THREAD_USAGE_ANALYSIS diff --git a/include/zephyr/kernel_structs.h b/include/zephyr/kernel_structs.h index ff8bde4e571..baa2046f07c 100644 --- a/include/zephyr/kernel_structs.h +++ b/include/zephyr/kernel_structs.h @@ -33,13 +33,7 @@ #endif #define K_NUM_THREAD_PRIO (CONFIG_NUM_PREEMPT_PRIORITIES + CONFIG_NUM_COOP_PRIORITIES + 1) - -#if defined(CONFIG_64BIT) -#define PRIQ_BITMAP_SIZE (DIV_ROUND_UP(K_NUM_THREAD_PRIO, 8 * sizeof(uint64_t))) -#else -#define PRIQ_BITMAP_SIZE (DIV_ROUND_UP(K_NUM_THREAD_PRIO, 8 * sizeof(uint32_t))) -#endif - +#define PRIQ_BITMAP_SIZE (DIV_ROUND_UP(K_NUM_THREAD_PRIO, BITS_PER_LONG)) #ifdef __cplusplus extern "C" { @@ -127,11 +121,7 @@ struct _priq_rb { */ struct _priq_mq { sys_dlist_t queues[K_NUM_THREAD_PRIO]; -#ifdef CONFIG_64BIT - uint64_t bitmask[PRIQ_BITMAP_SIZE]; -#else - uint32_t bitmask[PRIQ_BITMAP_SIZE]; -#endif + unsigned long bitmask[PRIQ_BITMAP_SIZE]; }; struct _ready_q { diff --git a/include/zephyr/linker/common-ram.ld b/include/zephyr/linker/common-ram.ld index 538b3465b01..0f750f93cd8 100644 --- a/include/zephyr/linker/common-ram.ld +++ b/include/zephyr/linker/common-ram.ld @@ -5,10 +5,10 @@ #if defined(CONFIG_NETWORKING) #ifndef NETWORK_RAM_SECTIONS #define NETWORK_RAM_SECTIONS \ - ITERABLE_SECTION_RAM(net_if, 4) \ - ITERABLE_SECTION_RAM(net_if_dev, 4) \ - ITERABLE_SECTION_RAM(net_l2, 4) \ - ITERABLE_SECTION_RAM(eth_bridge, 4) + ITERABLE_SECTION_RAM(net_if, Z_LINK_ITERABLE_SUBALIGN) \ + ITERABLE_SECTION_RAM(net_if_dev, Z_LINK_ITERABLE_SUBALIGN) \ + ITERABLE_SECTION_RAM(net_l2, Z_LINK_ITERABLE_SUBALIGN) \ + ITERABLE_SECTION_RAM(eth_bridge, Z_LINK_ITERABLE_SUBALIGN) #endif #endif /* NETWORKING */ @@ -43,8 +43,8 @@ __device_states_end = .; } GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) -#if CONFIG_PM_DEVICE - ITERABLE_SECTION_RAM(pm_device_slots, 4) +#ifdef CONFIG_PM_DEVICE + ITERABLE_SECTION_RAM(pm_device_slots, Z_LINK_ITERABLE_SUBALIGN) #endif #if defined(CONFIG_DEVICE_DEPS_DYNAMIC) @@ -54,9 +54,9 @@ } GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) #endif /* CONFIG_DEVICE_DEPS_DYNAMIC */ - ITERABLE_SECTION_RAM_GC_ALLOWED(log_mpsc_pbuf, 4) - ITERABLE_SECTION_RAM(log_msg_ptr, 4) - ITERABLE_SECTION_RAM(log_dynamic, 4) + ITERABLE_SECTION_RAM_GC_ALLOWED(log_mpsc_pbuf, Z_LINK_ITERABLE_SUBALIGN) + ITERABLE_SECTION_RAM(log_msg_ptr, Z_LINK_ITERABLE_SUBALIGN) + ITERABLE_SECTION_RAM(log_dynamic, Z_LINK_ITERABLE_SUBALIGN) #ifdef CONFIG_USERSPACE /* All kernel objects within are assumed to be either completely @@ -69,34 +69,34 @@ _static_kernel_objects_begin = .; #endif /* CONFIG_USERSPACE */ - ITERABLE_SECTION_RAM_GC_ALLOWED(k_timer, 4) - ITERABLE_SECTION_RAM_GC_ALLOWED(k_mem_slab, 4) - ITERABLE_SECTION_RAM_GC_ALLOWED(k_heap, 4) - ITERABLE_SECTION_RAM_GC_ALLOWED(k_mutex, 4) - ITERABLE_SECTION_RAM_GC_ALLOWED(k_stack, 4) - ITERABLE_SECTION_RAM_GC_ALLOWED(k_msgq, 4) - ITERABLE_SECTION_RAM_GC_ALLOWED(k_mbox, 4) - ITERABLE_SECTION_RAM_GC_ALLOWED(k_pipe, 4) - ITERABLE_SECTION_RAM_GC_ALLOWED(k_sem, 4) - ITERABLE_SECTION_RAM_GC_ALLOWED(k_event, 4) - ITERABLE_SECTION_RAM_GC_ALLOWED(k_queue, 4) - ITERABLE_SECTION_RAM_GC_ALLOWED(k_fifo, 4) - ITERABLE_SECTION_RAM_GC_ALLOWED(k_lifo, 4) - ITERABLE_SECTION_RAM_GC_ALLOWED(k_condvar, 4) - ITERABLE_SECTION_RAM_GC_ALLOWED(sys_mem_blocks_ptr, 4) - - ITERABLE_SECTION_RAM(net_buf_pool, 4) + ITERABLE_SECTION_RAM_GC_ALLOWED(k_timer, Z_LINK_ITERABLE_SUBALIGN) + ITERABLE_SECTION_RAM_GC_ALLOWED(k_mem_slab, Z_LINK_ITERABLE_SUBALIGN) + ITERABLE_SECTION_RAM_GC_ALLOWED(k_heap, Z_LINK_ITERABLE_SUBALIGN) + ITERABLE_SECTION_RAM_GC_ALLOWED(k_mutex, Z_LINK_ITERABLE_SUBALIGN) + ITERABLE_SECTION_RAM_GC_ALLOWED(k_stack, Z_LINK_ITERABLE_SUBALIGN) + ITERABLE_SECTION_RAM_GC_ALLOWED(k_msgq, Z_LINK_ITERABLE_SUBALIGN) + ITERABLE_SECTION_RAM_GC_ALLOWED(k_mbox, Z_LINK_ITERABLE_SUBALIGN) + ITERABLE_SECTION_RAM_GC_ALLOWED(k_pipe, Z_LINK_ITERABLE_SUBALIGN) + ITERABLE_SECTION_RAM_GC_ALLOWED(k_sem, Z_LINK_ITERABLE_SUBALIGN) + ITERABLE_SECTION_RAM_GC_ALLOWED(k_event, Z_LINK_ITERABLE_SUBALIGN) + ITERABLE_SECTION_RAM_GC_ALLOWED(k_queue, Z_LINK_ITERABLE_SUBALIGN) + ITERABLE_SECTION_RAM_GC_ALLOWED(k_fifo, Z_LINK_ITERABLE_SUBALIGN) + ITERABLE_SECTION_RAM_GC_ALLOWED(k_lifo, Z_LINK_ITERABLE_SUBALIGN) + ITERABLE_SECTION_RAM_GC_ALLOWED(k_condvar, Z_LINK_ITERABLE_SUBALIGN) + ITERABLE_SECTION_RAM_GC_ALLOWED(sys_mem_blocks_ptr, Z_LINK_ITERABLE_SUBALIGN) + + ITERABLE_SECTION_RAM(net_buf_pool, Z_LINK_ITERABLE_SUBALIGN) #if defined(CONFIG_NETWORKING) NETWORK_RAM_SECTIONS #endif /* NETWORKING */ #if defined(CONFIG_PCIE) - ITERABLE_SECTION_RAM(pcie_dev, 4) + ITERABLE_SECTION_RAM(pcie_dev, Z_LINK_ITERABLE_SUBALIGN) #endif /* PCIE */ #if defined(CONFIG_UART_MUX) - ITERABLE_SECTION_RAM(uart_mux, 4) + ITERABLE_SECTION_RAM(uart_mux, Z_LINK_ITERABLE_SUBALIGN) #endif #if defined(CONFIG_USB_DEVICE_STACK) @@ -108,7 +108,7 @@ __usb_descriptor_end = .; } GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) - ITERABLE_SECTION_RAM(usb_cfg_data, 4) + ITERABLE_SECTION_RAM(usb_cfg_data, Z_LINK_ITERABLE_SUBALIGN) #endif /* CONFIG_USB_DEVICE_STACK */ #if defined(CONFIG_USB_DEVICE_BOS) @@ -122,14 +122,14 @@ #endif /* CONFIG_USB_DEVICE_BOS */ #if defined(CONFIG_RTIO) - ITERABLE_SECTION_RAM(rtio, 4) - ITERABLE_SECTION_RAM(rtio_iodev, 4) - ITERABLE_SECTION_RAM(rtio_sqe_pool, 4) - ITERABLE_SECTION_RAM(rtio_cqe_pool, 4) + ITERABLE_SECTION_RAM(rtio, Z_LINK_ITERABLE_SUBALIGN) + ITERABLE_SECTION_RAM(rtio_iodev, Z_LINK_ITERABLE_SUBALIGN) + ITERABLE_SECTION_RAM(rtio_sqe_pool, Z_LINK_ITERABLE_SUBALIGN) + ITERABLE_SECTION_RAM(rtio_cqe_pool, Z_LINK_ITERABLE_SUBALIGN) #endif /* CONFIG_RTIO */ #if defined(CONFIG_SENSING) - ITERABLE_SECTION_RAM(sensing_sensor, 4) + ITERABLE_SECTION_RAM(sensing_sensor, Z_LINK_ITERABLE_SUBALIGN) #endif /* CONFIG_SENSING */ #if defined(CONFIG_ZBUS) @@ -137,11 +137,11 @@ #endif /* CONFIG_ZBUS */ #if defined(CONFIG_DEVICE_MUTABLE) - ITERABLE_SECTION_RAM(device_mutable, 4) + ITERABLE_SECTION_RAM(device_mutable, Z_LINK_ITERABLE_SUBALIGN) #endif #if defined(CONFIG_BT_ZEPHYR_NUS) - ITERABLE_SECTION_RAM(bt_nus_inst, 4) + ITERABLE_SECTION_RAM(bt_nus_inst, Z_LINK_ITERABLE_SUBALIGN) #endif #ifdef CONFIG_USERSPACE diff --git a/include/zephyr/linker/common-rom/common-rom-bt.ld b/include/zephyr/linker/common-rom/common-rom-bt.ld index 842aa31da24..56ae87bce97 100644 --- a/include/zephyr/linker/common-rom/common-rom-bt.ld +++ b/include/zephyr/linker/common-rom/common-rom-bt.ld @@ -2,41 +2,41 @@ #include - ITERABLE_SECTION_ROM(bt_l2cap_fixed_chan, 4) + ITERABLE_SECTION_ROM(bt_l2cap_fixed_chan, Z_LINK_ITERABLE_SUBALIGN) #if defined(CONFIG_BT_CLASSIC) - ITERABLE_SECTION_ROM(bt_l2cap_br_fixed_chan, 4) + ITERABLE_SECTION_ROM(bt_l2cap_br_fixed_chan, Z_LINK_ITERABLE_SUBALIGN) #endif #if defined(CONFIG_BT_CONN) - ITERABLE_SECTION_ROM(bt_conn_cb, 4) + ITERABLE_SECTION_ROM(bt_conn_cb, Z_LINK_ITERABLE_SUBALIGN) #endif - ITERABLE_SECTION_ROM(bt_gatt_service_static, 4) + ITERABLE_SECTION_ROM(bt_gatt_service_static, Z_LINK_ITERABLE_SUBALIGN) #if defined(CONFIG_BT_MESH) - ITERABLE_SECTION_ROM(bt_mesh_subnet_cb, 4) - ITERABLE_SECTION_ROM(bt_mesh_app_key_cb, 4) + ITERABLE_SECTION_ROM(bt_mesh_subnet_cb, Z_LINK_ITERABLE_SUBALIGN) + ITERABLE_SECTION_ROM(bt_mesh_app_key_cb, Z_LINK_ITERABLE_SUBALIGN) - ITERABLE_SECTION_ROM(bt_mesh_hb_cb, 4) + ITERABLE_SECTION_ROM(bt_mesh_hb_cb, Z_LINK_ITERABLE_SUBALIGN) #if defined(CONFIG_BT_TESTING) - ITERABLE_SECTION_ROM(bt_mesh_beacon_cb, 4) + ITERABLE_SECTION_ROM(bt_mesh_beacon_cb, Z_LINK_ITERABLE_SUBALIGN) #endif #endif #if defined(CONFIG_BT_MESH_FRIEND) - ITERABLE_SECTION_ROM(bt_mesh_friend_cb, 4) + ITERABLE_SECTION_ROM(bt_mesh_friend_cb, Z_LINK_ITERABLE_SUBALIGN) #endif #if defined(CONFIG_BT_MESH_LOW_POWER) - ITERABLE_SECTION_ROM(bt_mesh_lpn_cb, 4) + ITERABLE_SECTION_ROM(bt_mesh_lpn_cb, Z_LINK_ITERABLE_SUBALIGN) #endif #if defined(CONFIG_BT_IAS) - ITERABLE_SECTION_ROM(bt_ias_cb, 4) + ITERABLE_SECTION_ROM(bt_ias_cb, Z_LINK_ITERABLE_SUBALIGN) #endif #if defined(CONFIG_BT_MESH_GATT_PROXY) - ITERABLE_SECTION_ROM(bt_mesh_proxy_cb, 4) + ITERABLE_SECTION_ROM(bt_mesh_proxy_cb, Z_LINK_ITERABLE_SUBALIGN) #endif diff --git a/include/zephyr/linker/common-rom/common-rom-debug.ld b/include/zephyr/linker/common-rom/common-rom-debug.ld index 6617e52d4e6..07d89ca6069 100644 --- a/include/zephyr/linker/common-rom/common-rom-debug.ld +++ b/include/zephyr/linker/common-rom/common-rom-debug.ld @@ -2,7 +2,7 @@ #include - ITERABLE_SECTION_ROM(tracing_backend, 4) + ITERABLE_SECTION_ROM(tracing_backend, Z_LINK_ITERABLE_SUBALIGN) SECTION_DATA_PROLOGUE(zephyr_dbg_info,,) { 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 dfa19d13492..35ac520cc07 100644 --- a/include/zephyr/linker/common-rom/common-rom-kernel-devices.ld +++ b/include/zephyr/linker/common-rom/common-rom-kernel-devices.ld @@ -18,9 +18,12 @@ CREATE_OBJ_LEVEL(init, APPLICATION) CREATE_OBJ_LEVEL(init, SMP) __init_end = .; + __deferred_init_list_start = .; + KEEP(*(.z_deferred_init)) + __deferred_init_list_end = .; } GROUP_ROM_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) - ITERABLE_SECTION_ROM_NUMERIC(device, 4) + ITERABLE_SECTION_ROM_NUMERIC(device, Z_LINK_ITERABLE_SUBALIGN) #if defined(CONFIG_GEN_SW_ISR_TABLE) && defined(CONFIG_SHARED_INTERRUPTS) /* since z_shared_isr() is not referenced anywhere when @@ -75,7 +78,7 @@ /* Build-time assignment of permissions to kernel objects to * threads declared with K_THREAD_DEFINE() */ - ITERABLE_SECTION_ROM(k_object_assignment, 4) + ITERABLE_SECTION_ROM(k_object_assignment, Z_LINK_ITERABLE_SUBALIGN) #endif SECTION_DATA_PROLOGUE(app_shmem_regions,,) @@ -85,12 +88,12 @@ __app_shmem_regions_end = .; } GROUP_ROM_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) - ITERABLE_SECTION_ROM(k_p4wq_initparam, 4) + ITERABLE_SECTION_ROM(k_p4wq_initparam, Z_LINK_ITERABLE_SUBALIGN) - ITERABLE_SECTION_ROM(_static_thread_data, 4) + ITERABLE_SECTION_ROM(_static_thread_data, Z_LINK_ITERABLE_SUBALIGN) #if defined(CONFIG_PCIE) - ITERABLE_SECTION_ROM(irq_alloc, 4) + ITERABLE_SECTION_ROM(irq_alloc, Z_LINK_ITERABLE_SUBALIGN) #endif /* CONFIG_PCIE */ #if !defined(CONFIG_DEVICE_DEPS_DYNAMIC) diff --git a/include/zephyr/linker/common-rom/common-rom-logging.ld b/include/zephyr/linker/common-rom/common-rom-logging.ld index 9bb3e34626c..23c8ec757c4 100644 --- a/include/zephyr/linker/common-rom/common-rom-logging.ld +++ b/include/zephyr/linker/common-rom/common-rom-logging.ld @@ -3,16 +3,16 @@ #include #if defined(CONFIG_LOG_FMT_SECTION_STRIP) && defined(DEVNULL_REGION) - SECTION_PROLOGUE(log_strings,(COPY),SUBALIGN(4)) + SECTION_PROLOGUE(log_strings,(COPY),SUBALIGN(Z_LINK_ITERABLE_SUBALIGN)) { Z_LINK_ITERABLE(log_strings); } GROUP_ROM_LINK_IN(DEVNULL_REGION, DEVNULL_REGION) #else - ITERABLE_SECTION_ROM(log_strings, 4) + ITERABLE_SECTION_ROM(log_strings, Z_LINK_ITERABLE_SUBALIGN) #endif - ITERABLE_SECTION_ROM(log_const, 4) + ITERABLE_SECTION_ROM(log_const, Z_LINK_ITERABLE_SUBALIGN) - ITERABLE_SECTION_ROM(log_backend, 4) + ITERABLE_SECTION_ROM(log_backend, Z_LINK_ITERABLE_SUBALIGN) - ITERABLE_SECTION_ROM(log_link, 4) + ITERABLE_SECTION_ROM(log_link, Z_LINK_ITERABLE_SUBALIGN) diff --git a/include/zephyr/linker/common-rom/common-rom-misc.ld b/include/zephyr/linker/common-rom/common-rom-misc.ld index 6c03bfb79a4..5daa7b71084 100644 --- a/include/zephyr/linker/common-rom/common-rom-misc.ld +++ b/include/zephyr/linker/common-rom/common-rom-misc.ld @@ -3,45 +3,45 @@ #include #if defined(CONFIG_EC_HOST_CMD) - ITERABLE_SECTION_ROM(ec_host_cmd_handler, 4) + ITERABLE_SECTION_ROM(ec_host_cmd_handler, Z_LINK_ITERABLE_SUBALIGN) #endif #if defined(CONFIG_SETTINGS) - ITERABLE_SECTION_ROM(settings_handler_static, 4) + ITERABLE_SECTION_ROM(settings_handler_static, Z_LINK_ITERABLE_SUBALIGN) #endif #if defined(CONFIG_SENSING) - ITERABLE_SECTION_ROM(sensing_sensor_info, 4) + ITERABLE_SECTION_ROM(sensing_sensor_info, Z_LINK_ITERABLE_SUBALIGN) #endif #if defined(CONFIG_SENSOR_INFO) - ITERABLE_SECTION_ROM(sensor_info, 4) + ITERABLE_SECTION_ROM(sensor_info, Z_LINK_ITERABLE_SUBALIGN) #endif #if defined(CONFIG_SENSOR_ASYNC_API) - ITERABLE_SECTION_ROM(sensor_decoder_api, 4) + ITERABLE_SECTION_ROM(sensor_decoder_api, Z_LINK_ITERABLE_SUBALIGN) #endif #if defined(CONFIG_MCUMGR) - ITERABLE_SECTION_ROM(mcumgr_handler, 4) + ITERABLE_SECTION_ROM(mcumgr_handler, Z_LINK_ITERABLE_SUBALIGN) #endif #if defined(CONFIG_INPUT) - ITERABLE_SECTION_ROM(input_callback, 4) + ITERABLE_SECTION_ROM(input_callback, Z_LINK_ITERABLE_SUBALIGN) #endif #if defined(CONFIG_EMUL) - ITERABLE_SECTION_ROM(emul, 4) + ITERABLE_SECTION_ROM(emul, Z_LINK_ITERABLE_SUBALIGN) #endif /* CONFIG_EMUL */ #if defined(CONFIG_ZBUS) - ITERABLE_SECTION_ROM(zbus_channel, 4) - ITERABLE_SECTION_ROM(zbus_observer, 4) - ITERABLE_SECTION_ROM(zbus_channel_observation, 4) + ITERABLE_SECTION_ROM(zbus_channel, Z_LINK_ITERABLE_SUBALIGN) + ITERABLE_SECTION_ROM(zbus_observer, Z_LINK_ITERABLE_SUBALIGN) + ITERABLE_SECTION_ROM(zbus_channel_observation, Z_LINK_ITERABLE_SUBALIGN) #endif /* CONFIG_ZBUS */ #ifdef CONFIG_LLEXT - ITERABLE_SECTION_ROM(llext_const_symbol, 4) + ITERABLE_SECTION_ROM(llext_const_symbol, Z_LINK_ITERABLE_SUBALIGN) #endif /* CONFIG_LLEXT */ SECTION_DATA_PROLOGUE(symbol_to_keep,,) @@ -51,20 +51,20 @@ __symbol_to_keep_end = .; } GROUP_ROM_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) - ITERABLE_SECTION_ROM(shell, 4) + ITERABLE_SECTION_ROM(shell, Z_LINK_ITERABLE_SUBALIGN) - ITERABLE_SECTION_ROM(shell_root_cmds, 4) + ITERABLE_SECTION_ROM(shell_root_cmds, Z_LINK_ITERABLE_SUBALIGN) - ITERABLE_SECTION_ROM(shell_subcmds, 4) + ITERABLE_SECTION_ROM(shell_subcmds, Z_LINK_ITERABLE_SUBALIGN) - ITERABLE_SECTION_ROM(shell_dynamic_subcmds, 4) + ITERABLE_SECTION_ROM(shell_dynamic_subcmds, Z_LINK_ITERABLE_SUBALIGN) - ITERABLE_SECTION_ROM(cfb_font, 4) + ITERABLE_SECTION_ROM(cfb_font, Z_LINK_ITERABLE_SUBALIGN) #if defined(CONFIG_GNSS) - ITERABLE_SECTION_ROM(gnss_data_callback, 4) + ITERABLE_SECTION_ROM(gnss_data_callback, Z_LINK_ITERABLE_SUBALIGN) #endif #if defined(CONFIG_GNSS_SATELLITES) - ITERABLE_SECTION_ROM(gnss_satellites_callback, 4) + ITERABLE_SECTION_ROM(gnss_satellites_callback, Z_LINK_ITERABLE_SUBALIGN) #endif diff --git a/include/zephyr/linker/common-rom/common-rom-net.ld b/include/zephyr/linker/common-rom/common-rom-net.ld index e73addfd166..5305f9cf873 100644 --- a/include/zephyr/linker/common-rom/common-rom-net.ld +++ b/include/zephyr/linker/common-rom/common-rom-net.ld @@ -3,29 +3,29 @@ #include #if defined(CONFIG_NET_SOCKETS) - ITERABLE_SECTION_ROM(net_socket_register, 4) + ITERABLE_SECTION_ROM(net_socket_register, Z_LINK_ITERABLE_SUBALIGN) #endif #if defined(CONFIG_NET_L2_PPP) - ITERABLE_SECTION_ROM(ppp_protocol_handler, 4) + ITERABLE_SECTION_ROM(ppp_protocol_handler, Z_LINK_ITERABLE_SUBALIGN) #endif #if defined(CONFIG_DNS_SD) - ITERABLE_SECTION_ROM(dns_sd_rec, 4) + ITERABLE_SECTION_ROM(dns_sd_rec, Z_LINK_ITERABLE_SUBALIGN) #endif #if defined(CONFIG_HTTP_SERVER) - ITERABLE_SECTION_ROM(http_service_desc, 4) + ITERABLE_SECTION_ROM(http_service_desc, Z_LINK_ITERABLE_SUBALIGN) #endif #if defined(CONFIG_COAP_SERVER) - ITERABLE_SECTION_ROM(coap_service, 4) + ITERABLE_SECTION_ROM(coap_service, Z_LINK_ITERABLE_SUBALIGN) #endif #if defined(CONFIG_NET_MGMT_EVENT) - ITERABLE_SECTION_ROM(net_mgmt_event_static_handler, 4) + ITERABLE_SECTION_ROM(net_mgmt_event_static_handler, Z_LINK_ITERABLE_SUBALIGN) #endif #if defined(CONFIG_NET_SOCKETS_SERVICE) - ITERABLE_SECTION_ROM(net_socket_service_desc, 4) + ITERABLE_SECTION_ROM(net_socket_service_desc, Z_LINK_ITERABLE_SUBALIGN) #endif diff --git a/include/zephyr/linker/debug-sections.ld b/include/zephyr/linker/debug-sections.ld index e768801b7c7..2a70cccb79e 100644 --- a/include/zephyr/linker/debug-sections.ld +++ b/include/zephyr/linker/debug-sections.ld @@ -39,9 +39,12 @@ /* DWARF 3 */ SECTION_PROLOGUE(.debug_pubtypes, 0,) { *(.debug_pubtypes) } SECTION_PROLOGUE(.debug_ranges, 0,) { *(.debug_ranges) } - /* DWARF Extension. */ - SECTION_PROLOGUE(.debug_macro, 0,) { *(.debug_macro) } /* DWARF 5 */ + SECTION_PROLOGUE(.debug_addr, 0,) { *(.debug_addr) } SECTION_PROLOGUE(.debug_line_str, 0,) { *(.debug_line_str) } SECTION_PROLOGUE(.debug_loclists, 0,) { *(.debug_loclists) } + SECTION_PROLOGUE(.debug_macro, 0,) { *(.debug_macro) } + SECTION_PROLOGUE(.debug_names, 0,) { *(.debug_names) } SECTION_PROLOGUE(.debug_rnglists, 0,) { *(.debug_rnglists) } + SECTION_PROLOGUE(.debug_str_offsets, 0,) { *(.debug_str_offsets) } + SECTION_PROLOGUE(.debug_sup, 0,) { *(.debug_sup) } diff --git a/include/zephyr/linker/iterable_sections.h b/include/zephyr/linker/iterable_sections.h index 2bc1f870b42..3eb4e9527b8 100644 --- a/include/zephyr/linker/iterable_sections.h +++ b/include/zephyr/linker/iterable_sections.h @@ -32,6 +32,8 @@ *(SORT_BY_NAME(._##struct_type.static.*)); \ _CONCAT(_##struct_type, _list_end) = . +#define Z_LINK_ITERABLE_SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN + /** * @brief Define a read-only iterable section output. * diff --git a/include/zephyr/linker/linker-defs.h b/include/zephyr/linker/linker-defs.h index f2737c7f6f2..ec37a3718d5 100644 --- a/include/zephyr/linker/linker-defs.h +++ b/include/zephyr/linker/linker-defs.h @@ -159,7 +159,7 @@ extern char __gcov_bss_size[]; /* end address of image, used by newlib for the heap */ extern char _end[]; -#if DT_NODE_HAS_STATUS(DT_CHOSEN(zephyr_ccm), okay) +#if (DT_NODE_HAS_STATUS(DT_CHOSEN(zephyr_ccm), okay)) extern char __ccm_data_rom_start[]; extern char __ccm_start[]; extern char __ccm_data_start[]; @@ -171,14 +171,14 @@ extern char __ccm_noinit_end[]; extern char __ccm_end[]; #endif -#if DT_NODE_HAS_STATUS(DT_CHOSEN(zephyr_itcm), okay) +#if (DT_NODE_HAS_STATUS(DT_CHOSEN(zephyr_itcm), okay)) extern char __itcm_start[]; extern char __itcm_end[]; extern char __itcm_size[]; extern char __itcm_load_start[]; #endif -#if DT_NODE_HAS_STATUS(DT_CHOSEN(zephyr_dtcm), okay) +#if (DT_NODE_HAS_STATUS(DT_CHOSEN(zephyr_dtcm), okay)) extern char __dtcm_data_start[]; extern char __dtcm_data_end[]; extern char __dtcm_bss_start[]; @@ -190,7 +190,7 @@ extern char __dtcm_start[]; extern char __dtcm_end[]; #endif -#if DT_NODE_HAS_STATUS(DT_CHOSEN(zephyr_ocm), okay) +#if (DT_NODE_HAS_STATUS(DT_CHOSEN(zephyr_ocm), okay)) extern char __ocm_data_start[]; extern char __ocm_data_end[]; extern char __ocm_bss_start[]; diff --git a/include/zephyr/llext/llext.h b/include/zephyr/llext/llext.h index 99d780ee3b6..59a136ab5d4 100644 --- a/include/zephyr/llext/llext.h +++ b/include/zephyr/llext/llext.h @@ -141,6 +141,7 @@ struct llext_load_param { * @param[in] ldr_parm Loader parameters * * @retval 0 Success + * @retval > 0 extension use count * @retval -ENOMEM Not enough memory * @retval -EINVAL Invalid ELF stream */ @@ -163,7 +164,7 @@ int llext_unload(struct llext **ext); * @retval NULL if no symbol found * @retval addr Address of symbol in memory if found */ -const void * const llext_find_sym(const struct llext_symtable *sym_table, const char *sym_name); +const void *llext_find_sym(const struct llext_symtable *sym_table, const char *sym_name); /** * @brief Call a function by name diff --git a/include/zephyr/logging/log_ctrl.h b/include/zephyr/logging/log_ctrl.h index 56b0458c2ec..eb8cb560655 100644 --- a/include/zephyr/logging/log_ctrl.h +++ b/include/zephyr/logging/log_ctrl.h @@ -47,6 +47,12 @@ void log_core_init(void); */ void log_init(void); +/** @brief Trigger the log processing thread to process logs immediately. + * + * @note Function has no effect when CONFIG_LOG_MODE_IMMEDIATE is set. + */ +void log_thread_trigger(void); + /** * @brief Function for providing thread which is processing logs. * diff --git a/include/zephyr/logging/log_instance.h b/include/zephyr/logging/log_instance.h index dbaf72f3b06..5d12ca0c1e2 100644 --- a/include/zephyr/logging/log_instance.h +++ b/include/zephyr/logging/log_instance.h @@ -36,9 +36,9 @@ struct log_source_dynamic_data { */ uint32_t dummy[2]; #endif -#if defined(CONFIG_RISCV) && defined(CONFIG_64BIT) - /* Workaround: RV64 needs to ensure that structure is just 8 bytes. */ - uint32_t dummy; +#if defined(CONFIG_64BIT) + /* Workaround: Ensure that structure size is a multiple of 8 bytes. */ + uint32_t dummy_64; #endif }; diff --git a/include/zephyr/logging/log_internal.h b/include/zephyr/logging/log_internal.h index 94ea12a248f..e6d212b165d 100644 --- a/include/zephyr/logging/log_internal.h +++ b/include/zephyr/logging/log_internal.h @@ -114,8 +114,6 @@ void z_log_msg_commit(struct log_msg *msg); * * @param[out] backoff Recommended backoff needed to maintain ordering of processed * messages. Used only when links are using dedicated buffers. - * - * @param Message or null if no pending messages. */ union log_msg_generic *z_log_msg_claim(k_timeout_t *backoff); diff --git a/include/zephyr/logging/log_msg.h b/include/zephyr/logging/log_msg.h index 2d314d47f82..2f6b3a04616 100644 --- a/include/zephyr/logging/log_msg.h +++ b/include/zephyr/logging/log_msg.h @@ -72,7 +72,7 @@ struct log_msg_hdr { /* Attempting to keep best alignment. When address is 64 bit and timestamp 32 * swap the order to have 16 byte header instead of 24 byte. */ -#if (INTPTR_MAX > INT32_MAX) && !CONFIG_LOG_TIMESTAMP_64BIT +#if (INTPTR_MAX > INT32_MAX) && !defined(CONFIG_LOG_TIMESTAMP_64BIT) log_timestamp_t timestamp; const void *source; #else @@ -652,7 +652,7 @@ __syscall void z_log_msg_simple_create_2(const void *source, uint32_t level, * * @param package Package. * - * @oaram data Data. + * @param data Data. */ __syscall void z_log_msg_static_create(const void *source, const struct log_msg_desc desc, @@ -788,6 +788,14 @@ static inline const void *log_msg_get_source(struct log_msg *msg) return msg->hdr.source; } +/** @brief Get log message source ID. + * + * @param msg Log message. + * + * @return Source ID, or -1 if not available. + */ +int16_t log_msg_get_source_id(struct log_msg *msg); + /** @brief Get timestamp. * * @param msg Log message. diff --git a/include/zephyr/lorawan/lorawan.h b/include/zephyr/lorawan/lorawan.h index 1bad5130730..058c4cbabc7 100644 --- a/include/zephyr/lorawan/lorawan.h +++ b/include/zephyr/lorawan/lorawan.h @@ -41,6 +41,22 @@ enum lorawan_act_type { LORAWAN_ACT_ABP, /**< Activation by Personalization (ABP) */ }; +/** + * @brief LoRaWAN channels mask sizes. + */ +enum lorawan_channels_mask_size { + LORAWAN_CHANNELS_MASK_SIZE_AS923 = 1, /**< Region AS923 mask size */ + LORAWAN_CHANNELS_MASK_SIZE_AU915 = 6, /**< Region AU915 mask size */ + LORAWAN_CHANNELS_MASK_SIZE_CN470 = 6, /**< Region CN470 mask size */ + LORAWAN_CHANNELS_MASK_SIZE_CN779 = 1, /**< Region CN779 mask size */ + LORAWAN_CHANNELS_MASK_SIZE_EU433 = 1, /**< Region EU433 mask size */ + LORAWAN_CHANNELS_MASK_SIZE_EU868 = 1, /**< Region EU868 mask size */ + LORAWAN_CHANNELS_MASK_SIZE_KR920 = 1, /**< Region KR920 mask size */ + LORAWAN_CHANNELS_MASK_SIZE_IN865 = 1, /**< Region IN865 mask size */ + LORAWAN_CHANNELS_MASK_SIZE_US915 = 6, /**< Region US915 mask size */ + LORAWAN_CHANNELS_MASK_SIZE_RU864 = 1, /**< Region RU864 mask size */ +}; + /** * @brief LoRaWAN datarate types. */ @@ -295,6 +311,21 @@ int lorawan_set_conf_msg_tries(uint8_t tries); */ void lorawan_enable_adr(bool enable); +/** + * @brief Set the channels mask. + * + * Change the default channels mask. When mask is not changed, all the channels + * can be used for data transmission. Some Network Servers don't use all the channels, + * in this case, the channels mask must be provided. + * + * @param channels_mask Buffer with channels mask to be used. + * @param channels_mask_size Size of channels mask buffer. + * + * @retval 0 successful + * @retval -EINVAL channels mask or channels mask size is wrong + */ +int lorawan_set_channels_mask(uint16_t *channels_mask, size_t channels_mask_size); + /** * @brief Set the default data rate * @@ -373,6 +404,24 @@ int lorawan_clock_sync_get(uint32_t *gps_time); #endif /* CONFIG_LORAWAN_APP_CLOCK_SYNC */ +#ifdef CONFIG_LORAWAN_FRAG_TRANSPORT + +/** + * @brief Run Fragmented Data Block Transport service + * + * This service receives fragmented data (usually firmware images) and + * stores them in the image-1 flash partition. + * + * After all fragments have been received, the provided callback is invoked. + * + * @param transport_finished_cb Callback for notification of finished data transfer. + * + * @return 0 if successful, negative errno otherwise. + */ +int lorawan_frag_transport_run(void (*transport_finished_cb)(void)); + +#endif /* CONFIG_LORAWAN_FRAG_TRANSPORT */ + #ifdef __cplusplus } #endif diff --git a/include/zephyr/mgmt/ec_host_cmd/backend.h b/include/zephyr/mgmt/ec_host_cmd/backend.h index ed61e0e33c2..66f04e97868 100644 --- a/include/zephyr/mgmt/ec_host_cmd/backend.h +++ b/include/zephyr/mgmt/ec_host_cmd/backend.h @@ -103,7 +103,7 @@ typedef int (*ec_host_cmd_backend_api_init)(const struct ec_host_cmd_backend *ba */ typedef int (*ec_host_cmd_backend_api_send)(const struct ec_host_cmd_backend *backend); -__subsystem struct ec_host_cmd_backend_api { +struct ec_host_cmd_backend_api { ec_host_cmd_backend_api_init init; ec_host_cmd_backend_api_send send; }; diff --git a/include/zephyr/mgmt/hawkbit.h b/include/zephyr/mgmt/hawkbit.h index 46a0ff34328..08da3df1b1c 100644 --- a/include/zephyr/mgmt/hawkbit.h +++ b/include/zephyr/mgmt/hawkbit.h @@ -13,6 +13,8 @@ #ifndef ZEPHYR_INCLUDE_MGMT_HAWKBIT_H_ #define ZEPHYR_INCLUDE_MGMT_HAWKBIT_H_ +#include + #define HAWKBIT_JSON_URL "/default/controller/v1" /** @@ -33,13 +35,55 @@ enum hawkbit_response { HAWKBIT_UPDATE_INSTALLED, HAWKBIT_NO_UPDATE, HAWKBIT_CANCEL_UPDATE, + HAWKBIT_NOT_INITIALIZED, HAWKBIT_PROBE_IN_PROGRESS, }; +/** + * @brief hawkBit configuration structure. + * + * @details This structure is used to store the hawkBit configuration + * settings. + */ +struct hawkbit_runtime_config { + char *server_addr; + uint16_t server_port; + char *auth_token; + sec_tag_t tls_tag; +}; + +/** + * @brief Callback to provide the custom data to the hawkBit server. + * + * @details This callback is used to provide the custom data to the hawkBit server. + * The custom data is used to provide the hawkBit server with the device specific + * data. + * + * @param device_id The device ID. + * @param buffer The buffer to store the json. + * @param buffer_size The size of the buffer. + */ +typedef int (*hawkbit_config_device_data_cb_handler_t)(const char *device_id, uint8_t *buffer, + const size_t buffer_size); + +/** + * @brief Set the custom data callback. + * + * @details This function is used to set the custom data callback. + * The callback is used to provide the custom data to the hawkBit server. + * + * @param cb The callback function. + * + * @retval 0 on success. + * @retval -EINVAL if the callback is NULL. + */ +int hawkbit_set_custom_data_cb(hawkbit_config_device_data_cb_handler_t cb); + /** * @brief Init the flash partition * - * @return 0 on success, negative on error. + * @retval 0 on success. + * @retval -errno if init fails. */ int hawkbit_init(void); @@ -54,12 +98,17 @@ void hawkbit_autohandler(void); /** * @brief The hawkBit probe verify if there is some update to be performed. * - * @return HAWKBIT_UPDATE_INSTALLED has an update available. - * @return HAWKBIT_NO_UPDATE no update available. - * @return HAWKBIT_NETWORKING_ERROR fail to connect to the hawkBit server. - * @return HAWKBIT_METADATA_ERROR fail to parse or to encode the metadata. - * @return HAWKBIT_OK if success. - * @return HAWKBIT_DOWNLOAD_ERROR fail while downloading the update package. + * @retval HAWKBIT_NETWORKING_ERROR fail to connect to the hawkBit server. + * @retval HAWKBIT_UNCONFIRMED_IMAGE image is unconfirmed. + * @retval HAWKBIT_PERMISSION_ERROR fail to get the permission to access the hawkBit server. + * @retval HAWKBIT_METADATA_ERROR fail to parse or to encode the metadata. + * @retval HAWKBIT_DOWNLOAD_ERROR fail while downloading the update package. + * @retval HAWKBIT_OK if the image was already updated. + * @retval HAWKBIT_UPDATE_INSTALLED if an update was installed. Reboot is required to apply it. + * @retval HAWKBIT_NO_UPDATE if no update was available. + * @retval HAWKBIT_CANCEL_UPDATE if the update was cancelled by the server. + * @retval HAWKBIT_NOT_INITIALIZED if hawkBit is not initialized. + * @retval HAWKBIT_PROBE_IN_PROGRESS if probe is currently running. */ enum hawkbit_response hawkbit_probe(void); @@ -68,6 +117,162 @@ enum hawkbit_response hawkbit_probe(void); */ void hawkbit_reboot(void); +/** + * @brief Callback to get the device identity. + * + * @param id Pointer to the buffer to store the device identity + * @param id_max_len The maximum length of the buffer + */ +typedef bool (*hawkbit_get_device_identity_cb_handler_t)(char *id, int id_max_len); + +/** + * @brief Set the device identity callback. + * + * @details This function is used to set a custom device identity callback. + * + * @param cb The callback function. + * + * @retval 0 on success. + * @retval -EINVAL if the callback is NULL. + */ +int hawkbit_set_device_identity_cb(hawkbit_get_device_identity_cb_handler_t cb); + +/** + * @brief Set the hawkBit server configuration settings. + * + * @param config Configuration settings to set. + * @retval 0 on success. + * @retval -EAGAIN if probe is currently running. + */ +int hawkbit_set_config(struct hawkbit_runtime_config *config); + +/** + * @brief Get the hawkBit server configuration settings. + * + * @return Configuration settings. + */ +struct hawkbit_runtime_config hawkbit_get_config(void); + +/** + * @brief Set the hawkBit server address. + * + * @param addr_str Server address to set. + * @retval 0 on success. + * @retval -EAGAIN if probe is currently running. + */ +static inline int hawkbit_set_server_addr(char *addr_str) +{ + struct hawkbit_runtime_config set_config = { + .server_addr = addr_str, .server_port = 0, .auth_token = NULL, .tls_tag = 0}; + + return hawkbit_set_config(&set_config); +} + +/** + * @brief Set the hawkBit server port. + * + * @param port Server port to set. + * @retval 0 on success. + * @retval -EAGAIN if probe is currently running. + */ +static inline int hawkbit_set_server_port(uint16_t port) +{ + struct hawkbit_runtime_config set_config = { + .server_addr = NULL, .server_port = port, .auth_token = NULL, .tls_tag = 0}; + + return hawkbit_set_config(&set_config); +} + +/** + * @brief Set the hawkBit security token. + * + * @param token Security token to set. + * @retval 0 on success. + * @retval -EAGAIN if probe is currently running. + */ +static inline int hawkbit_set_ddi_security_token(char *token) +{ + struct hawkbit_runtime_config set_config = { + .server_addr = NULL, .server_port = 0, .auth_token = token, .tls_tag = 0}; + + return hawkbit_set_config(&set_config); +} + +/** + * @brief Set the hawkBit TLS tag + * + * @param tag TLS tag to set. + * @retval 0 on success. + * @retval -EAGAIN if probe is currently running. + */ +static inline int hawkbit_set_tls_tag(sec_tag_t tag) +{ + struct hawkbit_runtime_config set_config = { + .server_addr = NULL, .server_port = 0, .auth_token = NULL, .tls_tag = tag}; + + return hawkbit_set_config(&set_config); +} + +/** + * @brief Get the hawkBit server address. + * + * @return Server address. + */ +static inline char *hawkbit_get_server_addr(void) +{ + return hawkbit_get_config().server_addr; +} + +/** + * @brief Get the hawkBit server port. + * + * @return Server port. + */ +static inline uint16_t hawkbit_get_server_port(void) +{ + return hawkbit_get_config().server_port; +} + +/** + * @brief Get the hawkBit security token. + * + * @return Security token. + */ +static inline char *hawkbit_get_ddi_security_token(void) +{ + return hawkbit_get_config().auth_token; +} + +/** + * @brief Get the hawkBit TLS tag. + * + * @return TLS tag. + */ +static inline sec_tag_t hawkbit_get_tls_tag(void) +{ + return hawkbit_get_config().tls_tag; +} + +/** + * @brief Get the hawkBit action id. + * + * @return Action id. + +*/ +int32_t hawkbit_get_action_id(void); + +/** + * @brief Resets the hawkBit action id, that is saved in settings. + * + * @details This should be done after changing the hawkBit server. + * + * @retval 0 on success. + * @retval -EAGAIN if probe is currently running. + * @retval -EIO if the action id could not be reset. + * + */ +int hawkbit_reset_action_id(void); + /** * @} */ diff --git a/include/zephyr/modem/backend/uart.h b/include/zephyr/modem/backend/uart.h index 0280494e350..f68f411c6e2 100644 --- a/include/zephyr/modem/backend/uart.h +++ b/include/zephyr/modem/backend/uart.h @@ -12,6 +12,7 @@ #include #include +#include #ifndef ZEPHYR_MODEM_BACKEND_UART_ #define ZEPHYR_MODEM_BACKEND_UART_ @@ -24,6 +25,7 @@ struct modem_backend_uart_isr { struct ring_buf receive_rdb[2]; struct ring_buf transmit_rb; atomic_t transmit_buf_len; + atomic_t receive_buf_len; uint8_t receive_rdb_used; uint32_t transmit_buf_put_limit; }; @@ -45,6 +47,11 @@ struct modem_backend_uart { struct k_work_delayable receive_ready_work; struct k_work transmit_idle_work; +#if CONFIG_MODEM_STATS + struct modem_stats_buffer receive_buf_stats; + struct modem_stats_buffer transmit_buf_stats; +#endif + union { struct modem_backend_uart_isr isr; struct modem_backend_uart_async async; diff --git a/include/zephyr/modem/chat.h b/include/zephyr/modem/chat.h index 28a2bc6bf9f..a30a7191ba9 100644 --- a/include/zephyr/modem/chat.h +++ b/include/zephyr/modem/chat.h @@ -10,6 +10,7 @@ #include #include +#include #ifndef ZEPHYR_MODEM_CHAT_ #define ZEPHYR_MODEM_CHAT_ @@ -81,9 +82,15 @@ struct modem_chat_match { #define MODEM_CHAT_MATCH_DEFINE(_sym, _match, _separators, _callback) \ const static struct modem_chat_match _sym = MODEM_CHAT_MATCH(_match, _separators, _callback) +/* Helper struct to match any response without callback. */ +extern const struct modem_chat_match modem_chat_any_match; + #define MODEM_CHAT_MATCHES_DEFINE(_sym, ...) \ const static struct modem_chat_match _sym[] = {__VA_ARGS__} +/* Helper struct to match nothing. */ +extern const struct modem_chat_match modem_chat_empty_matches[0]; + /** * @brief Modem chat script chat */ @@ -118,18 +125,21 @@ struct modem_chat_script_chat { .timeout = 0, \ } -#define MODEM_CHAT_SCRIPT_CMD_RESP_NONE(_request, _timeout) \ +#define MODEM_CHAT_SCRIPT_CMD_RESP_NONE(_request, _timeout_ms) \ { \ .request = (uint8_t *)(_request), \ .request_size = (uint16_t)(sizeof(_request) - 1), \ .response_matches = NULL, \ .response_matches_size = 0, \ - .timeout = _timeout, \ + .timeout = _timeout_ms, \ } #define MODEM_CHAT_SCRIPT_CMDS_DEFINE(_sym, ...) \ const struct modem_chat_script_chat _sym[] = {__VA_ARGS__} +/* Helper struct to have no chat script command. */ +extern const struct modem_chat_script_chat modem_chat_empty_script_chats[0]; + enum modem_chat_script_result { MODEM_CHAT_SCRIPT_RESULT_SUCCESS, MODEM_CHAT_SCRIPT_RESULT_ABORT, @@ -166,7 +176,7 @@ struct modem_chat_script { uint32_t timeout; }; -#define MODEM_CHAT_SCRIPT_DEFINE(_sym, _script_chats, _abort_matches, _callback, _timeout) \ +#define MODEM_CHAT_SCRIPT_DEFINE(_sym, _script_chats, _abort_matches, _callback, _timeout_s) \ const static struct modem_chat_script _sym = { \ .name = #_sym, \ .script_chats = _script_chats, \ @@ -174,9 +184,16 @@ struct modem_chat_script { .abort_matches = _abort_matches, \ .abort_matches_size = ARRAY_SIZE(_abort_matches), \ .callback = _callback, \ - .timeout = _timeout, \ + .timeout = _timeout_s, \ } +#define MODEM_CHAT_SCRIPT_NO_ABORT_DEFINE(_sym, _script_chats, _callback, _timeout_s) \ + MODEM_CHAT_SCRIPT_DEFINE(_sym, _script_chats, modem_chat_empty_matches, \ + _callback, _timeout_s) + +#define MODEM_CHAT_SCRIPT_EMPTY_DEFINE(_sym) \ + MODEM_CHAT_SCRIPT_NO_ABORT_DEFINE(_sym, modem_chat_empty_script_chats, NULL, 0) + enum modem_chat_script_send_state { /* No data to send */ MODEM_CHAT_SCRIPT_SEND_STATE_IDLE, @@ -253,6 +270,12 @@ struct modem_chat { /* Process received data */ struct k_work receive_work; + + /* Statistics */ +#if CONFIG_MODEM_STATS + struct modem_stats_buffer receive_buf_stats; + struct modem_stats_buffer work_buf_stats; +#endif }; /** diff --git a/include/zephyr/modem/cmux.h b/include/zephyr/modem/cmux.h index 57ee6a8505b..2e6990f5aa0 100644 --- a/include/zephyr/modem/cmux.h +++ b/include/zephyr/modem/cmux.h @@ -25,6 +25,7 @@ #include #include +#include #ifndef ZEPHYR_MODEM_CMUX_ #define ZEPHYR_MODEM_CMUX_ @@ -102,6 +103,11 @@ struct modem_cmux_dlci { /* State */ enum modem_cmux_dlci_state state; + + /* Statistics */ +#if CONFIG_MODEM_STATS + struct modem_stats_buffer receive_buf_stats; +#endif }; struct modem_cmux_frame { @@ -160,6 +166,12 @@ struct modem_cmux { /* Synchronize actions */ struct k_event event; + + /* Statistics */ +#if CONFIG_MODEM_STATS + struct modem_stats_buffer receive_buf_stats; + struct modem_stats_buffer transmit_buf_stats; +#endif }; /** diff --git a/include/zephyr/modem/ppp.h b/include/zephyr/modem/ppp.h index c0eca885fcd..799aac60b0b 100644 --- a/include/zephyr/modem/ppp.h +++ b/include/zephyr/modem/ppp.h @@ -12,6 +12,7 @@ #include #include +#include #ifndef ZEPHYR_MODEM_PPP_ #define ZEPHYR_MODEM_PPP_ @@ -113,6 +114,11 @@ struct modem_ppp { #if defined(CONFIG_NET_STATISTICS_PPP) struct net_stats_ppp stats; #endif + +#if CONFIG_MODEM_STATS + struct modem_stats_buffer receive_buf_stats; + struct modem_stats_buffer transmit_buf_stats; +#endif }; /** diff --git a/include/zephyr/modem/stats.h b/include/zephyr/modem/stats.h new file mode 100644 index 00000000000..23fb3eac50b --- /dev/null +++ b/include/zephyr/modem/stats.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2024 Trackunit Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#ifndef ZEPHYR_MODEM_STATS_ +#define ZEPHYR_MODEM_STATS_ + +/** + * @cond INTERNAL_HIDDEN + */ + +/** Modem statistics buffer structure */ +struct modem_stats_buffer { + sys_snode_t node; + char name[CONFIG_MODEM_STATS_BUFFER_NAME_SIZE]; + uint32_t max_used; + uint32_t size; +}; + +/** + * @endcond + */ + +/** + * @brief Initialize modem statistics buffer + * + * @param buffer Modem statistics buffer instance + * @param name Name of buffer instance + * @param size Size of buffer + */ +void modem_stats_buffer_init(struct modem_stats_buffer *buffer, + const char *name, uint32_t size); + +/** + * @brief Advertise modem statistics buffer size + * + * @param buffer Modem statistics buffer instance + * @param length Length of buffer + * + * @note Invoke when buffer size changes + * @note Safe to invoke from ISR + */ +void modem_stats_buffer_advertise_length(struct modem_stats_buffer *buffer, uint32_t length); + +#endif /* ZEPHYR_MODEM_STATS_ */ diff --git a/include/zephyr/net/bt.h b/include/zephyr/net/bt.h deleted file mode 100644 index 04d9d21967e..00000000000 --- a/include/zephyr/net/bt.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2017 Intel Corporation. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief Bluetooth L2 stack public header - */ - -#ifndef ZEPHYR_INCLUDE_NET_BT_H_ -#define ZEPHYR_INCLUDE_NET_BT_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/* Management part definitions */ - -#define _NET_BT_LAYER NET_MGMT_LAYER_L2 -#define _NET_BT_CODE 0x155 -#define _NET_BT_BASE (NET_MGMT_IFACE_BIT | \ - NET_MGMT_LAYER(_NET_BT_LAYER) | \ - NET_MGMT_LAYER_CODE(_NET_BT_CODE)) -#define _NET_BT_EVENT (_NET_BT_BASE | NET_MGMT_EVENT_BIT) - -enum net_request_bt_cmd { - NET_REQUEST_BT_CMD_ADVERTISE = 1, - NET_REQUEST_BT_CMD_CONNECT, - NET_REQUEST_BT_CMD_SCAN, - NET_REQUEST_BT_CMD_DISCONNECT, -}; - -#define NET_REQUEST_BT_ADVERTISE \ - (_NET_BT_BASE | NET_REQUEST_BT_CMD_ADVERTISE) - -NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_BT_ADVERTISE); - -#define NET_REQUEST_BT_CONNECT \ - (_NET_BT_BASE | NET_REQUEST_BT_CMD_CONNECT) - -NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_BT_CONNECT); - -#define NET_REQUEST_BT_SCAN \ - (_NET_BT_BASE | NET_REQUEST_BT_CMD_SCAN) - -NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_BT_SCAN); - -enum net_event_bt_cmd { - NET_EVENT_BT_CMD_SCAN_RESULT = 1, -}; - -#define NET_EVENT_BT_SCAN_RESULT \ - (_NET_BT_EVENT | NET_EVENT_BT_CMD_SCAN_RESULT) - -#define NET_REQUEST_BT_DISCONNECT \ - (_NET_BT_BASE | NET_REQUEST_BT_CMD_DISCONNECT) - -NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_BT_DISCONNECT); - -#ifdef __cplusplus -} -#endif - -#endif /* ZEPHYR_INCLUDE_NET_BT_H_ */ diff --git a/include/zephyr/net/buf.h b/include/zephyr/net/buf.h index cf7e1279662..2855017b282 100644 --- a/include/zephyr/net/buf.h +++ b/include/zephyr/net/buf.h @@ -963,7 +963,7 @@ struct net_buf_simple_state { static inline void net_buf_simple_save(struct net_buf_simple *buf, struct net_buf_simple_state *state) { - state->offset = net_buf_simple_headroom(buf); + state->offset = (uint16_t)net_buf_simple_headroom(buf); state->len = buf->len; } @@ -1017,10 +1017,10 @@ struct net_buf { /** Where the buffer should go when freed up. */ uint8_t pool_id; - /* Size of user data on this buffer */ + /** Size of user data on this buffer */ uint8_t user_data_size; - /* Union for convenience access to the net_buf_simple members, also + /** Union for convenience access to the net_buf_simple members, also * preserving the old API. */ union { @@ -1042,13 +1042,17 @@ struct net_buf { uint8_t *__buf; }; + /** @cond INTERNAL_HIDDEN */ struct net_buf_simple b; + /** @endcond */ }; /** System metadata for this buffer. */ uint8_t user_data[] __net_buf_align; }; +/** @cond INTERNAL_HIDDEN */ + struct net_buf_data_cb { uint8_t * __must_check (*alloc)(struct net_buf *buf, size_t *size, k_timeout_t timeout); @@ -1062,6 +1066,8 @@ struct net_buf_data_alloc { size_t max_alloc_size; }; +/** @endcond */ + /** * @brief Network buffer pool representation. * @@ -1071,7 +1077,7 @@ struct net_buf_pool { /** LIFO to place the buffer into when free */ struct k_lifo free; - /* to prevent concurrent access/modifications */ + /** To prevent concurrent access/modifications */ struct k_spinlock lock; /** Number of buffers in pool */ @@ -1080,7 +1086,7 @@ struct net_buf_pool { /** Number of uninitialized buffers */ uint16_t uninit_count; - /* Size of user data allocated to this pool */ + /** Size of user data allocated to this pool */ uint8_t user_data_size; #if defined(CONFIG_NET_BUF_POOL_USAGE) @@ -1172,12 +1178,14 @@ extern const struct net_buf_data_alloc net_buf_heap_alloc; _net_buf_##_name, _count, _ud_size, \ _destroy) +/** @cond INTERNAL_HIDDEN */ + struct net_buf_pool_fixed { uint8_t *data_pool; }; -/** @cond INTERNAL_HIDDEN */ extern const struct net_buf_data_cb net_buf_fixed_cb; + /** @endcond */ /** @@ -1315,14 +1323,19 @@ int net_buf_id(struct net_buf *buf); /** * @brief Allocate a new fixed buffer from a pool. * + * @note Some types of data allocators do not support + * blocking (such as the HEAP type). In this case it's still possible + * for net_buf_alloc() to fail (return NULL) even if it was given + * K_FOREVER. + * + * @note The timeout value will be overridden to K_NO_WAIT if called from the + * system workqueue. + * * @param pool Which pool to allocate the buffer from. * @param timeout Affects the action taken should the pool be empty. * If K_NO_WAIT, then return immediately. If K_FOREVER, then * wait as long as necessary. Otherwise, wait until the specified - * timeout. Note that some types of data allocators do not support - * blocking (such as the HEAP type). In this case it's still possible - * for net_buf_alloc() to fail (return NULL) even if it was given - * K_FOREVER. + * timeout. * * @return New buffer or NULL if out of buffers. */ @@ -1350,15 +1363,20 @@ static inline struct net_buf * __must_check net_buf_alloc(struct net_buf_pool *p /** * @brief Allocate a new variable length buffer from a pool. * + * @note Some types of data allocators do not support + * blocking (such as the HEAP type). In this case it's still possible + * for net_buf_alloc() to fail (return NULL) even if it was given + * K_FOREVER. + * + * @note The timeout value will be overridden to K_NO_WAIT if called from the + * system workqueue. + * * @param pool Which pool to allocate the buffer from. * @param size Amount of data the buffer must be able to fit. * @param timeout Affects the action taken should the pool be empty. * If K_NO_WAIT, then return immediately. If K_FOREVER, then * wait as long as necessary. Otherwise, wait until the specified - * timeout. Note that some types of data allocators do not support - * blocking (such as the HEAP type). In this case it's still possible - * for net_buf_alloc() to fail (return NULL) even if it was given - * K_FOREVER. + * timeout. * * @return New buffer or NULL if out of buffers. */ @@ -1382,16 +1400,21 @@ struct net_buf * __must_check net_buf_alloc_len(struct net_buf_pool *pool, * Allocate a new buffer from a pool, where the data pointer comes from the * user and not from the pool. * + * @note Some types of data allocators do not support + * blocking (such as the HEAP type). In this case it's still possible + * for net_buf_alloc() to fail (return NULL) even if it was given + * K_FOREVER. + * + * @note The timeout value will be overridden to K_NO_WAIT if called from the + * system workqueue. + * * @param pool Which pool to allocate the buffer from. * @param data External data pointer * @param size Amount of data the pointed data buffer if able to fit. * @param timeout Affects the action taken should the pool be empty. * If K_NO_WAIT, then return immediately. If K_FOREVER, then * wait as long as necessary. Otherwise, wait until the specified - * timeout. Note that some types of data allocators do not support - * blocking (such as the HEAP type). In this case it's still possible - * for net_buf_alloc() to fail (return NULL) even if it was given - * K_FOREVER. + * timeout. * * @return New buffer or NULL if out of buffers. */ diff --git a/include/zephyr/net/canbus.h b/include/zephyr/net/canbus.h index da5b6a3e067..1d7056a72ea 100644 --- a/include/zephyr/net/canbus.h +++ b/include/zephyr/net/canbus.h @@ -4,8 +4,12 @@ * SPDX-License-Identifier: Apache-2.0 */ -#ifndef ZEPHYR_INCLUDE_NET_CAN_H_ -#define ZEPHYR_INCLUDE_NET_CAN_H_ +/** @file + * @brief CAN bus socket API definitions. + */ + +#ifndef ZEPHYR_INCLUDE_NET_CANBUS_H_ +#define ZEPHYR_INCLUDE_NET_CANBUS_H_ #include #include @@ -52,4 +56,4 @@ BUILD_ASSERT(offsetof(struct canbus_api, iface_api) == 0); } #endif -#endif /* ZEPHYR_INCLUDE_NET_CAN_H_ */ +#endif /* ZEPHYR_INCLUDE_NET_CANBUS_H_ */ diff --git a/include/zephyr/net/capture.h b/include/zephyr/net/capture.h index 0d5a61c4911..0a90e444f72 100644 --- a/include/zephyr/net/capture.h +++ b/include/zephyr/net/capture.h @@ -271,7 +271,7 @@ struct net_capture_cooked { /** * @brief Initialize cooked mode capture context. * - * @param cooked Cooked context struct allocated by user. + * @param ctx Cooked context struct allocated by user. * @param hatype Link-layer address type * @param halen Link-layer address length (maximum is 8 bytes) * @param addr Link-layer address @@ -307,7 +307,7 @@ static inline int net_capture_cooked_setup(struct net_capture_cooked *ctx, * layer packets so that packet boundary is not lost. * * @param ctx Cooked mode capture context. - * @param buf Data to capture. + * @param data Data to capture. * @param len Length of the data. * @param type The direction and type of the packet (did we sent it etc). * @param ptype Protocol type id. These are the ETH_P_* types set in ethernet.h diff --git a/include/zephyr/net/coap.h b/include/zephyr/net/coap.h index 7f69cc4e9a7..c6714ee9dcb 100644 --- a/include/zephyr/net/coap.h +++ b/include/zephyr/net/coap.h @@ -27,7 +27,7 @@ #include #include #include - +#include #include #ifdef __cplusplus @@ -82,12 +82,16 @@ enum coap_method { COAP_METHOD_IPATCH = 7, /**< IPATCH */ }; +/** @cond INTERNAL_HIDDEN */ + #define COAP_REQUEST_MASK 0x07 #define COAP_VERSION_1 1U #define COAP_OBSERVE_MAX_AGE 0xFFFFFF +/** @endcond */ + /** * @brief CoAP packets may be of one of these types. */ @@ -193,10 +197,14 @@ enum coap_response_code { COAP_MAKE_RESPONSE_CODE(5, 5) }; +/** @cond INTERNAL_HIDDEN */ + #define COAP_CODE_EMPTY (0) #define COAP_TOKEN_MAX_LEN 8UL +/** @endcond */ + /** * @brief Set of Content-Format option values for CoAP. * @@ -214,11 +222,15 @@ enum coap_content_format { COAP_CONTENT_FORMAT_APP_CBOR = 60 /**< application/cbor */ }; +/** @cond INTERNAL_HIDDEN */ + /* block option helper */ #define GET_BLOCK_NUM(v) ((v) >> 4) #define GET_BLOCK_SIZE(v) (((v) & 0x7)) #define GET_MORE(v) (!!((v) & 0x08)) +/** @endcond */ + struct coap_observer; struct coap_packet; struct coap_pending; @@ -251,10 +263,15 @@ typedef void (*coap_notify_t)(struct coap_resource *resource, struct coap_resource { /** Which function to be called for each CoAP method */ coap_method_t get, post, put, del, fetch, patch, ipatch; + /** Notify function to call */ coap_notify_t notify; + /** Resource path */ const char * const *path; + /** User specific opaque data */ void *user_data; + /** List of resource observers */ sys_slist_t observers; + /** Resource age */ int age; }; @@ -262,9 +279,13 @@ struct coap_resource { * @brief Represents a remote device that is observing a local resource. */ struct coap_observer { + /** Observer list node */ sys_snode_t list; + /** Observer connection end point information */ struct sockaddr addr; + /** Observer token */ uint8_t token[8]; + /** Extended token length */ uint8_t tkl; }; @@ -344,11 +365,17 @@ struct coap_pending { * also used when observing resources. */ struct coap_reply { + /** CoAP reply callback */ coap_reply_t reply; + /** User specific opaque data */ void *user_data; + /** Reply age */ int age; + /** Reply id */ uint16_t id; + /** Reply token */ uint8_t token[8]; + /** Extended token length */ uint8_t tkl; }; @@ -696,12 +723,36 @@ static inline uint16_t coap_block_size_to_bytes( return (1 << (block_size + 4)); } +/** + * @brief Helper for converting block size in bytes to enumeration. + * + * NOTE: Only valid CoAP block sizes map correctly. + * + * @param bytes CoAP block size in bytes. + * @return enum coap_block_size + */ +static inline enum coap_block_size coap_bytes_to_block_size(uint16_t bytes) +{ + int sz = u32_count_trailing_zeros(bytes) - 4; + + if (sz < COAP_BLOCK_16) { + return COAP_BLOCK_16; + } + if (sz > COAP_BLOCK_1024) { + return COAP_BLOCK_1024; + } + return sz; +} + /** * @brief Represents the current state of a block-wise transaction. */ struct coap_block_context { + /** Total size of the block-wise transaction */ size_t total_size; + /** Current size of the block-wise transaction */ size_t current; + /** Block size */ enum coap_block_size block_size; }; diff --git a/include/zephyr/net/coap_client.h b/include/zephyr/net/coap_client.h index e48048d5c26..a3576a244c5 100644 --- a/include/zephyr/net/coap_client.h +++ b/include/zephyr/net/coap_client.h @@ -22,7 +22,7 @@ #include #include - +/** Maximum size of a CoAP message */ #define MAX_COAP_MSG_LEN (CONFIG_COAP_CLIENT_MESSAGE_HEADER_SIZE + \ CONFIG_COAP_CLIENT_MESSAGE_SIZE) @@ -67,12 +67,17 @@ struct coap_client_request { * @brief Representation of extra options for the CoAP client request */ struct coap_client_option { + /** Option code */ uint16_t code; #if defined(CONFIG_COAP_EXTENDED_OPTIONS_LEN) + /** Option len */ uint16_t len; + /** Buffer for the length */ uint8_t value[CONFIG_COAP_EXTENDED_OPTIONS_LEN_VALUE]; #else + /** Option len */ uint8_t len; + /** Buffer for the length */ uint8_t value[12]; #endif }; @@ -84,12 +89,17 @@ struct coap_client_internal_request { uint32_t last_id; uint8_t request_tkl; bool request_ongoing; + atomic_t in_callback; 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]; + + /* For GETs with observe option set */ + bool is_observe; + int last_response_id; }; struct coap_client { @@ -137,6 +147,16 @@ int coap_client_init(struct coap_client *client, const char *info); int coap_client_req(struct coap_client *client, int sock, const struct sockaddr *addr, struct coap_client_request *req, struct coap_transmission_parameters *params); +/** + * @brief Cancel all current requests. + * + * This is intended for canceling long-running requests (e.g. GETs with the OBSERVE option set) + * which has gone stale for some reason. + * + * @param client Client instance. + */ +void coap_client_cancel_requests(struct coap_client *client); + /** * @} */ diff --git a/include/zephyr/net/coap_link_format.h b/include/zephyr/net/coap_link_format.h index cabfb9ff859..7c7c3c5f2f3 100644 --- a/include/zephyr/net/coap_link_format.h +++ b/include/zephyr/net/coap_link_format.h @@ -70,7 +70,9 @@ int coap_well_known_core_get_len(struct coap_resource *resources, * to a valid coap_core_metadata structure. */ struct coap_core_metadata { + /** List of attributes to add */ const char * const *attributes; + /** User specific data */ void *user_data; }; diff --git a/include/zephyr/net/coap_mgmt.h b/include/zephyr/net/coap_mgmt.h index f19eec6eb4b..a52293a9265 100644 --- a/include/zephyr/net/coap_mgmt.h +++ b/include/zephyr/net/coap_mgmt.h @@ -38,8 +38,6 @@ struct coap_service; struct coap_resource; struct coap_observer; -/** @endcond */ - enum net_event_coap_cmd { /* Service events */ NET_EVENT_COAP_CMD_SERVICE_STARTED = 1, @@ -49,6 +47,8 @@ enum net_event_coap_cmd { NET_EVENT_COAP_CMD_OBSERVER_REMOVED, }; +/** @endcond */ + /** * @brief coap_mgmt event raised when a service has started */ @@ -77,7 +77,7 @@ enum net_event_coap_cmd { * @brief CoAP Service event structure. */ struct net_event_coap_service { - /* The CoAP service for which the event is emitted */ + /** The CoAP service for which the event is emitted */ const struct coap_service *service; }; @@ -85,9 +85,9 @@ struct net_event_coap_service { * @brief CoAP Observer event structure. */ struct net_event_coap_observer { - /* The CoAP resource for which the event is emitted */ + /** The CoAP resource for which the event is emitted */ struct coap_resource *resource; - /* The observer that is added/removed */ + /** The observer that is added/removed */ struct coap_observer *observer; }; diff --git a/include/zephyr/net/conn_mgr_connectivity.h b/include/zephyr/net/conn_mgr_connectivity.h index d083509b437..048f40124de 100644 --- a/include/zephyr/net/conn_mgr_connectivity.h +++ b/include/zephyr/net/conn_mgr_connectivity.h @@ -41,13 +41,13 @@ extern "C" { NET_MGMT_EVENT_BIT) #define _NET_MGMT_CONN_IF_EVENT (NET_MGMT_IFACE_BIT | _NET_MGMT_CONN_BASE) -/** @endcond */ - enum net_event_conn_cmd { NET_EVENT_CONN_CMD_IF_TIMEOUT = 1, NET_EVENT_CONN_CMD_IF_FATAL_ERROR, }; +/** @endcond */ + /** * @brief net_mgmt event raised when a connection attempt times out */ diff --git a/include/zephyr/net/conn_mgr_monitor.h b/include/zephyr/net/conn_mgr_monitor.h index 94c50d90f19..16a873b7b2f 100644 --- a/include/zephyr/net/conn_mgr_monitor.h +++ b/include/zephyr/net/conn_mgr_monitor.h @@ -4,6 +4,11 @@ * SPDX-License-Identifier: Apache-2.0 */ +/** + * @file + * @brief API for monitoring network connections and interfaces. + */ + #ifndef ZEPHYR_INCLUDE_CONN_MGR_H_ #define ZEPHYR_INCLUDE_CONN_MGR_H_ diff --git a/include/zephyr/net/dhcpv4.h b/include/zephyr/net/dhcpv4.h index b06a7cb0320..c31d5f91417 100644 --- a/include/zephyr/net/dhcpv4.h +++ b/include/zephyr/net/dhcpv4.h @@ -54,14 +54,14 @@ enum net_dhcpv4_state { * within corresponding changes to net_dhcpv4_msg_type_name. */ enum net_dhcpv4_msg_type { - NET_DHCPV4_MSG_TYPE_DISCOVER = 1, - NET_DHCPV4_MSG_TYPE_OFFER = 2, - NET_DHCPV4_MSG_TYPE_REQUEST = 3, - NET_DHCPV4_MSG_TYPE_DECLINE = 4, - NET_DHCPV4_MSG_TYPE_ACK = 5, - NET_DHCPV4_MSG_TYPE_NAK = 6, - NET_DHCPV4_MSG_TYPE_RELEASE = 7, - NET_DHCPV4_MSG_TYPE_INFORM = 8, + NET_DHCPV4_MSG_TYPE_DISCOVER = 1, /**< Discover message */ + NET_DHCPV4_MSG_TYPE_OFFER = 2, /**< Offer message */ + NET_DHCPV4_MSG_TYPE_REQUEST = 3, /**< Request message */ + NET_DHCPV4_MSG_TYPE_DECLINE = 4, /**< Decline message */ + NET_DHCPV4_MSG_TYPE_ACK = 5, /**< Acknowledge message */ + NET_DHCPV4_MSG_TYPE_NAK = 6, /**< Negative acknowledge message */ + NET_DHCPV4_MSG_TYPE_RELEASE = 7, /**< Release message */ + NET_DHCPV4_MSG_TYPE_INFORM = 8, /**< Inform message */ }; struct net_dhcpv4_option_callback; diff --git a/include/zephyr/net/dns_resolve.h b/include/zephyr/net/dns_resolve.h index 46e5ad8e4df..fff5d4ad867 100644 --- a/include/zephyr/net/dns_resolve.h +++ b/include/zephyr/net/dns_resolve.h @@ -13,8 +13,10 @@ #ifndef ZEPHYR_INCLUDE_NET_DNS_RESOLVE_H_ #define ZEPHYR_INCLUDE_NET_DNS_RESOLVE_H_ +#include #include -#include +#include +#include #ifdef __cplusplus extern "C" { @@ -88,9 +90,13 @@ enum dns_query_type { * Address info struct is passed to callback that gets all the results. */ struct dns_addrinfo { + /** IP address information */ struct sockaddr ai_addr; + /** Length of the ai_addr field */ socklen_t ai_addrlen; - uint8_t ai_family; + /** Address family of the address information */ + uint8_t ai_family; + /** Canonical name of the address */ char ai_canonname[DNS_MAX_NAME_SIZE + 1]; }; @@ -157,22 +163,27 @@ typedef void (*dns_resolve_cb_t)(enum dns_resolve_status status, struct dns_addrinfo *info, void *user_data); +/** @cond INTERNAL_HIDDEN */ + enum dns_resolve_context_state { DNS_RESOLVE_CONTEXT_ACTIVE, DNS_RESOLVE_CONTEXT_DEACTIVATING, DNS_RESOLVE_CONTEXT_INACTIVE, }; +/** @endcond */ + /** * DNS resolve context structure. */ struct dns_resolve_context { + /** List of configured DNS servers */ struct { /** DNS server information */ struct sockaddr dns_server; /** Connection to the DNS server */ - struct net_context *net_ctx; + int sock; /** Is this server mDNS one */ uint8_t is_mdns : 1; @@ -181,6 +192,16 @@ struct dns_resolve_context { uint8_t is_llmnr : 1; } servers[CONFIG_DNS_RESOLVER_MAX_SERVERS + DNS_MAX_MCAST_SERVERS]; +/** @cond INTERNAL_HIDDEN */ +#if (IS_ENABLED(CONFIG_NET_IPV6) && IS_ENABLED(CONFIG_NET_IPV4)) +#define DNS_RESOLVER_MAX_POLL (2 * (CONFIG_DNS_RESOLVER_MAX_SERVERS + DNS_MAX_MCAST_SERVERS)) +#else +#define DNS_RESOLVER_MAX_POLL (1 * (CONFIG_DNS_RESOLVER_MAX_SERVERS + DNS_MAX_MCAST_SERVERS)) +#endif + /** Socket polling for each server connection */ + struct zsock_pollfd fds[DNS_RESOLVER_MAX_POLL]; +/** @endcond */ + /** Prevent concurrent access */ struct k_mutex lock; diff --git a/include/zephyr/net/dsa.h b/include/zephyr/net/dsa.h index 479690509a3..1aed17e11ba 100644 --- a/include/zephyr/net/dsa.h +++ b/include/zephyr/net/dsa.h @@ -21,6 +21,8 @@ * @{ */ +/** @cond INTERNAL_HIDDEN */ + #define NET_DSA_PORT_MAX_COUNT 8 #define DSA_STATUS_PERIOD_MS K_MSEC(1000) @@ -34,6 +36,8 @@ #define DSA_TAG_SIZE 0 #endif +/** @endcond */ + #ifdef __cplusplus extern "C" { #endif diff --git a/include/zephyr/net/dummy.h b/include/zephyr/net/dummy.h index bcf250a341c..4c5fe031234 100644 --- a/include/zephyr/net/dummy.h +++ b/include/zephyr/net/dummy.h @@ -4,6 +4,11 @@ * SPDX-License-Identifier: Apache-2.0 */ +/** @file + * @brief Dummy layer 2 + * + * This is not to be included by the application. + */ #ifndef ZEPHYR_INCLUDE_NET_DUMMY_H_ #define ZEPHYR_INCLUDE_NET_DUMMY_H_ @@ -22,6 +27,7 @@ extern "C" { * @{ */ +/** Dummy L2 API operations. */ struct dummy_api { /** * The net_if_api must be placed in first position in this diff --git a/include/zephyr/net/ethernet.h b/include/zephyr/net/ethernet.h index 9ecc7340d03..30fbb200bce 100644 --- a/include/zephyr/net/ethernet.h +++ b/include/zephyr/net/ethernet.h @@ -20,11 +20,7 @@ #include #include - -#if defined(CONFIG_NET_LLDP) #include -#endif - #include #include #include @@ -49,14 +45,15 @@ extern "C" { * @{ */ -#define NET_ETH_ADDR_LEN 6U - -/** @cond INTERNAL_HIDDEN */ +#define NET_ETH_ADDR_LEN 6U /**< Ethernet MAC address length */ +/** Ethernet address */ struct net_eth_addr { - uint8_t addr[NET_ETH_ADDR_LEN]; + uint8_t addr[NET_ETH_ADDR_LEN]; /**< Buffer storing the address */ }; +/** @cond INTERNAL_HIDDEN */ + #define NET_ETH_HDR(pkt) ((struct net_eth_hdr *)net_pkt_data(pkt)) #define NET_ETH_PTYPE_CAN 0x000C /* CAN: Controller Area Network */ @@ -108,8 +105,12 @@ struct net_eth_addr { #define ETH_P_HDLC NET_ETH_PTYPE_HDLC #endif -#define NET_ETH_MINIMAL_FRAME_SIZE 60 -#define NET_ETH_MTU 1500 +/** @endcond */ + +#define NET_ETH_MINIMAL_FRAME_SIZE 60 /**< Minimum Ethernet frame size */ +#define NET_ETH_MTU 1500 /**< Ethernet MTU size */ + +/** @cond INTERNAL_HIDDEN */ #if defined(CONFIG_NET_VLAN) #define _NET_ETH_MAX_HDR_SIZE (sizeof(struct net_eth_vlan_hdr)) @@ -134,7 +135,7 @@ struct net_eth_addr { /** @endcond */ -/** Ethernet hardware capabilities */ +/** @brief Ethernet hardware capabilities */ enum ethernet_hw_caps { /** TX Checksum offloading supported for all of IPv4, UDP, TCP */ ETHERNET_HW_TX_CHKSUM_OFFLOAD = BIT(0), @@ -181,8 +182,10 @@ enum ethernet_hw_caps { /** VLAN Tag stripping */ ETHERNET_HW_VLAN_TAG_STRIP = BIT(14), - /** DSA switch */ - ETHERNET_DSA_SLAVE_PORT = BIT(15), + /** DSA switch slave port */ + ETHERNET_DSA_SLAVE_PORT = BIT(15), + + /** DSA switch master port */ ETHERNET_DSA_MASTER_PORT = BIT(16), /** IEEE 802.1Qbv (scheduled traffic) supported */ @@ -230,11 +233,14 @@ enum ethernet_t1s_param_type { }; /** @endcond */ + +/** Ethernet T1S specific parameters */ struct ethernet_t1s_param { /** Type of T1S parameter */ enum ethernet_t1s_param_type type; union { - /* PLCA is the Physical Layer (PHY) Collision + /** + * PLCA is the Physical Layer (PHY) Collision * Avoidance technique employed with multidrop * 10Base-T1S standard. * @@ -273,6 +279,7 @@ struct ethernet_t1s_param { }; }; +/** Ethernet Qav specific parameters */ struct ethernet_qav_param { /** ID of the priority queue to use */ int queue_id; @@ -314,6 +321,7 @@ enum ethernet_gate_state_operation { /** @endcond */ +/** Ethernet Qbv specific parameters */ struct ethernet_qbv_param { /** Port id */ int port_id; @@ -325,6 +333,7 @@ struct ethernet_qbv_param { /** True if Qbv is enabled or not */ bool enabled; + /** Gate control information */ struct { /** True = open, False = closed */ bool gate_status[NET_TC_TX_COUNT]; @@ -342,7 +351,8 @@ struct ethernet_qbv_param { /** Number of entries in gate control list */ uint32_t gate_control_list_len; - /* The time values are set in one go when type is set to + /** + * The time values are set in one go when type is set to * ETHERNET_QBV_PARAM_TYPE_TIME */ struct { @@ -378,6 +388,7 @@ enum ethernet_qbu_preempt_status { /** @endcond */ +/** Ethernet Qbu specific parameters */ struct ethernet_qbu_param { /** Port id */ int port_id; @@ -390,8 +401,7 @@ struct ethernet_qbu_param { /** Release advance (nanoseconds) */ uint32_t release_advance; - /** sequence of framePreemptionAdminStatus values. - */ + /** sequence of framePreemptionAdminStatus values */ enum ethernet_qbu_preempt_status frame_preempt_statuses[NET_TC_TX_COUNT]; @@ -401,14 +411,14 @@ struct ethernet_qbu_param { /** Link partner status (from Qbr) */ bool link_partner_status; - /** Additional fragment size (from Qbr). The minimum non-final + /** + * Additional fragment size (from Qbr). The minimum non-final * fragment size is (additional_fragment_size + 1) * 64 octets */ uint8_t additional_fragment_size : 2; }; }; - /** @cond INTERNAL_HIDDEN */ enum ethernet_filter_type { @@ -427,7 +437,7 @@ enum ethernet_if_types { L2_ETH_IF_TYPE_WIFI, } __packed; - +/** Ethernet filter description */ struct ethernet_filter { /** Type of filter */ enum ethernet_filter_type type; @@ -445,6 +455,7 @@ enum ethernet_txtime_param_type { /** @endcond */ +/** Ethernet TXTIME specific parameters */ struct ethernet_txtime_param { /** Type of TXTIME parameter */ enum ethernet_txtime_param_type type; @@ -455,6 +466,7 @@ struct ethernet_txtime_param { }; /** @cond INTERNAL_HIDDEN */ + struct ethernet_config { union { bool auto_negotiation; @@ -482,8 +494,10 @@ struct ethernet_config { struct ethernet_filter filter; }; }; + /** @endcond */ +/** Ethernet L2 API operations. */ struct ethernet_api { /** * The net_if_api must be placed in first position in this @@ -491,11 +505,11 @@ struct ethernet_api { */ struct net_if_api iface_api; -#if defined(CONFIG_NET_STATISTICS_ETHERNET) /** Collect optional ethernet specific statistics. This pointer * should be set by driver if statistics needs to be collected * for that driver. */ +#if defined(CONFIG_NET_STATISTICS_ETHERNET) struct net_stats_eth *(*get_stats)(const struct device *dev); #endif @@ -518,18 +532,18 @@ struct ethernet_api { enum ethernet_config_type type, struct ethernet_config *config); -#if defined(CONFIG_NET_VLAN) /** The IP stack will call this function when a VLAN tag is enabled * or disabled. If enable is set to true, then the VLAN tag was added, * if it is false then the tag was removed. The driver can utilize * this information if needed. */ +#if defined(CONFIG_NET_VLAN) int (*vlan_setup)(const struct device *dev, struct net_if *iface, uint16_t tag, bool enable); #endif /* CONFIG_NET_VLAN */ -#if defined(CONFIG_PTP_CLOCK) /** Return ptp_clock device that is tied to this ethernet device */ +#if defined(CONFIG_PTP_CLOCK) const struct device *(*get_ptp_clock)(const struct device *dev); #endif /* CONFIG_PTP_CLOCK */ @@ -537,12 +551,13 @@ struct ethernet_api { int (*send)(const struct device *dev, struct net_pkt *pkt); }; +/** @cond INTERNAL_HIDDEN */ + /* Make sure that the network interface API is properly setup inside * Ethernet API struct (it is the first one). */ BUILD_ASSERT(offsetof(struct ethernet_api, iface_api) == 0); -/** @cond INTERNAL_HIDDEN */ struct net_eth_hdr { struct net_eth_addr dst; struct net_eth_addr src; @@ -567,7 +582,7 @@ struct ethernet_vlan { /** @endcond */ -#if defined(CONFIG_NET_LLDP) +/** Ethernet LLDP specific parameters */ struct ethernet_lldp { /** Used for track timers */ sys_snode_t node; @@ -593,7 +608,8 @@ struct ethernet_lldp { /** LLDP RX callback function */ net_lldp_recv_cb_t cb; }; -#endif /* CONFIG_NET_LLDP */ + +/** @cond INTERNAL_HIDDEN */ enum ethernet_flags { ETH_CARRIER_UP, @@ -671,8 +687,6 @@ struct ethernet_context { */ void ethernet_init(struct net_if *iface); -/** @cond INTERNAL_HIDDEN */ - #define ETHERNET_L2_CTX_TYPE struct ethernet_context /* Separate header for VLAN as some of device interfaces might not @@ -688,7 +702,15 @@ struct net_eth_vlan_hdr { uint16_t type; } __packed; +/** @endcond */ +/** + * @brief Check if the Ethernet MAC address is a broadcast address. + * + * @param addr A valid pointer to a Ethernet MAC address. + * + * @return true if address is a broadcast address, false if not + */ static inline bool net_eth_is_addr_broadcast(struct net_eth_addr *addr) { if (addr->addr[0] == 0xff && @@ -703,6 +725,13 @@ static inline bool net_eth_is_addr_broadcast(struct net_eth_addr *addr) return false; } +/** + * @brief Check if the Ethernet MAC address is unspecified. + * + * @param addr A valid pointer to a Ethernet MAC address. + * + * @return true if address is unspecified, false if not + */ static inline bool net_eth_is_addr_unspecified(struct net_eth_addr *addr) { if (addr->addr[0] == 0x00 && @@ -717,6 +746,13 @@ static inline bool net_eth_is_addr_unspecified(struct net_eth_addr *addr) return false; } +/** + * @brief Check if the Ethernet MAC address is a multicast address. + * + * @param addr A valid pointer to a Ethernet MAC address. + * + * @return true if address is a multicast address, false if not + */ static inline bool net_eth_is_addr_multicast(struct net_eth_addr *addr) { #if defined(CONFIG_NET_IPV6) @@ -737,16 +773,37 @@ static inline bool net_eth_is_addr_multicast(struct net_eth_addr *addr) return false; } +/** + * @brief Check if the Ethernet MAC address is a group address. + * + * @param addr A valid pointer to a Ethernet MAC address. + * + * @return true if address is a group address, false if not + */ static inline bool net_eth_is_addr_group(struct net_eth_addr *addr) { return addr->addr[0] & 0x01; } +/** + * @brief Check if the Ethernet MAC address is valid. + * + * @param addr A valid pointer to a Ethernet MAC address. + * + * @return true if address is valid, false if not + */ static inline bool net_eth_is_addr_valid(struct net_eth_addr *addr) { return !net_eth_is_addr_unspecified(addr) && !net_eth_is_addr_group(addr); } +/** + * @brief Check if the Ethernet MAC address is a LLDP multicast address. + * + * @param addr A valid pointer to a Ethernet MAC address. + * + * @return true if address is a LLDP multicast address, false if not + */ static inline bool net_eth_is_addr_lldp_multicast(struct net_eth_addr *addr) { #if defined(CONFIG_NET_GPTP) || defined(CONFIG_NET_LLDP) @@ -758,11 +815,20 @@ static inline bool net_eth_is_addr_lldp_multicast(struct net_eth_addr *addr) addr->addr[5] == 0x0e) { return true; } +#else + ARG_UNUSED(addr); #endif return false; } +/** + * @brief Check if the Ethernet MAC address is a PTP multicast address. + * + * @param addr A valid pointer to a Ethernet MAC address. + * + * @return true if address is a PTP multicast address, false if not + */ static inline bool net_eth_is_addr_ptp_multicast(struct net_eth_addr *addr) { #if defined(CONFIG_NET_GPTP) @@ -774,15 +840,20 @@ static inline bool net_eth_is_addr_ptp_multicast(struct net_eth_addr *addr) addr->addr[5] == 0x00) { return true; } +#else + ARG_UNUSED(addr); #endif return false; } +/** + * @brief Return Ethernet broadcast address. + * + * @return Ethernet broadcast address. + */ const struct net_eth_addr *net_eth_broadcast_addr(void); -/** @endcond */ - /** * @brief Convert IPv4 multicast address to Ethernet address. * @@ -989,6 +1060,8 @@ static inline bool net_eth_is_vlan_interface(struct net_if *iface) } #endif +/** @cond INTERNAL_HIDDEN */ + #if !defined(CONFIG_ETH_DRIVER_RAW_MODE) #define Z_ETH_NET_DEVICE_INIT_INSTANCE(node_id, dev_id, name, instance, \ @@ -1017,6 +1090,8 @@ static inline bool net_eth_is_vlan_interface(struct net_if *iface) init_fn, pm, data, config, prio, \ api, mtu) +/** @endcond */ + /** * @brief Create an Ethernet network interface and bind it to network device. * diff --git a/include/zephyr/net/ethernet_bridge.h b/include/zephyr/net/ethernet_bridge.h index aa86f63a561..fa2ca546983 100644 --- a/include/zephyr/net/ethernet_bridge.h +++ b/include/zephyr/net/ethernet_bridge.h @@ -56,6 +56,8 @@ struct eth_bridge { STRUCT_SECTION_ITERABLE(eth_bridge, name) = \ ETH_BRIDGE_INITIALIZER(name) +/** @cond INTERNAL_HIDDEN */ + struct eth_bridge_iface_context { sys_snode_t node; struct eth_bridge *instance; @@ -67,6 +69,8 @@ struct eth_bridge_listener { struct k_fifo pkt_queue; }; +/** @endcond */ + /** * @brief Add an Ethernet network interface to a bridge * diff --git a/include/zephyr/net/gptp.h b/include/zephyr/net/gptp.h index 049a94ec99e..488583e4d53 100644 --- a/include/zephyr/net/gptp.h +++ b/include/zephyr/net/gptp.h @@ -130,6 +130,7 @@ struct gptp_port_identity { uint16_t port_number; } __packed; +/** gPTP message flags */ struct gptp_flags { union { /** Byte access. */ @@ -140,6 +141,7 @@ struct gptp_flags { }; } __packed; +/** gPTP message header */ struct gptp_hdr { /** Type of the message. */ uint8_t message_type:4; diff --git a/include/zephyr/net/hostname.h b/include/zephyr/net/hostname.h index d9bac4393c2..4e801ffbda5 100644 --- a/include/zephyr/net/hostname.h +++ b/include/zephyr/net/hostname.h @@ -28,17 +28,22 @@ extern "C" { (sizeof(CONFIG_NET_HOSTNAME) - 1 + \ (IS_ENABLED(CONFIG_NET_HOSTNAME_UNIQUE) ? sizeof("0011223344556677") - 1 : 0))) #else +/** Maximum hostname length */ #define NET_HOSTNAME_MAX_LEN \ (sizeof(CONFIG_NET_HOSTNAME) - 1 + \ (IS_ENABLED(CONFIG_NET_HOSTNAME_UNIQUE) ? sizeof("0011223344556677") - 1 : 0)) #endif +/** @cond INTERNAL_HIDDEN */ + #if defined(CONFIG_NET_HOSTNAME_ENABLE) #define NET_HOSTNAME_SIZE NET_HOSTNAME_MAX_LEN + 1 #else #define NET_HOSTNAME_SIZE 1 #endif +/** @endcond */ + /** * @brief Get the device hostname * diff --git a/include/zephyr/net/http/client.h b/include/zephyr/net/http/client.h index e1ff3e63b9a..71eb1b32f33 100644 --- a/include/zephyr/net/http/client.h +++ b/include/zephyr/net/http/client.h @@ -16,6 +16,8 @@ /** * @brief HTTP client API * @defgroup http_client HTTP client API + * @since 2.1 + * @version 0.2.0 * @ingroup networking * @{ */ @@ -28,6 +30,8 @@ extern "C" { #endif +/** @cond INTERNAL_HIDDEN */ + #if !defined(HTTP_CRLF) #define HTTP_CRLF "\r\n" #endif @@ -36,10 +40,12 @@ extern "C" { #define HTTP_STATUS_STR_SIZE 32 #endif -/* Is there more data to come */ +/** @endcond */ + +/** Is there more data to come */ enum http_final_call { - HTTP_DATA_MORE = 0, - HTTP_DATA_FINAL = 1, + HTTP_DATA_MORE = 0, /**< More data will come */ + HTTP_DATA_FINAL = 1, /**< End of data */ }; struct http_request; @@ -172,7 +178,7 @@ struct http_response { */ size_t processed; - /* https://tools.ietf.org/html/rfc7230#section-3.1.2 + /** See https://tools.ietf.org/html/rfc7230#section-3.1.2 for more information. * The status-code element is a 3-digit integer code * * The reason-phrase element exists for the sole @@ -191,9 +197,9 @@ struct http_response { */ uint16_t http_status_code; - uint8_t cl_present : 1; - uint8_t body_found : 1; - uint8_t message_complete : 1; + uint8_t cl_present : 1; /**< Is Content-Length field present */ + uint8_t body_found : 1; /**< Is message body found */ + uint8_t message_complete : 1; /**< Is HTTP message parsing complete */ }; /** HTTP client internal data that the application should not touch diff --git a/include/zephyr/net/http/frame.h b/include/zephyr/net/http/frame.h new file mode 100644 index 00000000000..02d063c6866 --- /dev/null +++ b/include/zephyr/net/http/frame.h @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2023, Emna Rekik + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief HTTP2 frame information. + */ + +#ifndef ZEPHYR_INCLUDE_NET_HTTP_SERVER_FRAME_H_ +#define ZEPHYR_INCLUDE_NET_HTTP_SERVER_FRAME_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** HTTP2 frame types */ +enum http_frame_type { + /** Data frame */ + HTTP_SERVER_DATA_FRAME = 0x00, + /** Headers frame */ + HTTP_SERVER_HEADERS_FRAME = 0x01, + /** Priority frame */ + HTTP_SERVER_PRIORITY_FRAME = 0x02, + /** Reset stream frame */ + HTTP_SERVER_RST_STREAM_FRAME = 0x03, + /** Settings frame */ + HTTP_SERVER_SETTINGS_FRAME = 0x04, + /** Push promise frame */ + HTTP_SERVER_PUSH_PROMISE_FRAME = 0x05, + /** Ping frame */ + HTTP_SERVER_PING_FRAME = 0x06, + /** Goaway frame */ + HTTP_SERVER_GOAWAY_FRAME = 0x07, + /** Window update frame */ + HTTP_SERVER_WINDOW_UPDATE_FRAME = 0x08, + /** Continuation frame */ + HTTP_SERVER_CONTINUATION_FRAME = 0x09 +}; + +/** @cond INTERNAL_HIDDEN */ + +#define HTTP_SERVER_HPACK_METHOD 0 +#define HTTP_SERVER_HPACK_PATH 1 + +#define HTTP_SERVER_FLAG_SETTINGS_ACK 0x1 +#define HTTP_SERVER_FLAG_END_HEADERS 0x4 +#define HTTP_SERVER_FLAG_END_STREAM 0x1 + +#define HTTP_SERVER_FRAME_HEADER_SIZE 9 +#define HTTP_SERVER_FRAME_LENGTH_OFFSET 0 +#define HTTP_SERVER_FRAME_TYPE_OFFSET 3 +#define HTTP_SERVER_FRAME_FLAGS_OFFSET 4 +#define HTTP_SERVER_FRAME_STREAM_ID_OFFSET 5 + +/** @endcond */ + +/** HTTP2 settings field */ +struct http_settings_field { + uint16_t id; /**< Field id */ + uint32_t value; /**< Field value */ +} __packed; + +/** @brief HTTP2 settings */ +enum http_settings { + /** Header table size */ + HTTP_SETTINGS_HEADER_TABLE_SIZE = 1, + /** Enable push */ + HTTP_SETTINGS_ENABLE_PUSH = 2, + /** Maximum number of concurrent streams */ + HTTP_SETTINGS_MAX_CONCURRENT_STREAMS = 3, + /** Initial window size */ + HTTP_SETTINGS_INITIAL_WINDOW_SIZE = 4, + /** Max frame size */ + HTTP_SETTINGS_MAX_FRAME_SIZE = 5, + /** Max header list size */ + HTTP_SETTINGS_MAX_HEADER_LIST_SIZE = 6, +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/zephyr/net/http/hpack.h b/include/zephyr/net/http/hpack.h new file mode 100644 index 00000000000..0a85cf7c8ad --- /dev/null +++ b/include/zephyr/net/http/hpack.h @@ -0,0 +1,149 @@ +/** @file + * @brief HTTP HPACK + */ + +/* + * Copyright (c) 2023 Emna Rekik + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_NET_HTTP_SERVER_HPACK_H_ +#define ZEPHYR_INCLUDE_NET_HTTP_SERVER_HPACK_H_ + +#include +#include + +/** + * @brief HTTP HPACK + * @defgroup http_hpack HTTP HPACK + * @ingroup networking + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** @cond INTERNAL_HIDDEN */ + +enum http_hpack_static_key { + HTTP_SERVER_HPACK_INVALID = 0, + HTTP_SERVER_HPACK_AUTHORITY = 1, + HTTP_SERVER_HPACK_METHOD_GET = 2, + HTTP_SERVER_HPACK_METHOD_POST = 3, + HTTP_SERVER_HPACK_PATH_ROOT = 4, + HTTP_SERVER_HPACK_PATH_INDEX = 5, + HTTP_SERVER_HPACK_SCHEME_HTTP = 6, + HTTP_SERVER_HPACK_SCHEME_HTTPS = 7, + HTTP_SERVER_HPACK_STATUS_200 = 8, + HTTP_SERVER_HPACK_STATUS_204 = 9, + HTTP_SERVER_HPACK_STATUS_206 = 10, + HTTP_SERVER_HPACK_STATUS_304 = 11, + HTTP_SERVER_HPACK_STATUS_400 = 12, + HTTP_SERVER_HPACK_STATUS_404 = 13, + HTTP_SERVER_HPACK_STATUS_500 = 14, + HTTP_SERVER_HPACK_ACCEPT_CHARSET = 15, + HTTP_SERVER_HPACK_ACCEPT_ENCODING = 16, + HTTP_SERVER_HPACK_ACCEPT_LANGUAGE = 17, + HTTP_SERVER_HPACK_ACCEPT_RANGES = 18, + HTTP_SERVER_HPACK_ACCEPT = 19, + HTTP_SERVER_HPACK_ACCESS_CONTROL_ALLOW_ORIGIN = 20, + HTTP_SERVER_HPACK_AGE = 21, + HTTP_SERVER_HPACK_ALLOW = 22, + HTTP_SERVER_HPACK_AUTHORIZATION = 23, + HTTP_SERVER_HPACK_CACHE_CONTROL = 24, + HTTP_SERVER_HPACK_CONTENT_DISPOSITION = 25, + HTTP_SERVER_HPACK_CONTENT_ENCODING = 26, + HTTP_SERVER_HPACK_CONTENT_LANGUAGE = 27, + HTTP_SERVER_HPACK_CONTENT_LENGTH = 28, + HTTP_SERVER_HPACK_CONTENT_LOCATION = 29, + HTTP_SERVER_HPACK_CONTENT_RANGE = 30, + HTTP_SERVER_HPACK_CONTENT_TYPE = 31, + HTTP_SERVER_HPACK_COOKIE = 32, + HTTP_SERVER_HPACK_DATE = 33, + HTTP_SERVER_HPACK_ETAG = 34, + HTTP_SERVER_HPACK_EXPECT = 35, + HTTP_SERVER_HPACK_EXPIRES = 36, + HTTP_SERVER_HPACK_FROM = 37, + HTTP_SERVER_HPACK_HOST = 38, + HTTP_SERVER_HPACK_IF_MATCH = 39, + HTTP_SERVER_HPACK_IF_MODIFIED_SINCE = 40, + HTTP_SERVER_HPACK_IF_NONE_MATCH = 41, + HTTP_SERVER_HPACK_IF_RANGE = 42, + HTTP_SERVER_HPACK_IF_UNMODIFIED_SINCE = 43, + HTTP_SERVER_HPACK_LAST_MODIFIED = 44, + HTTP_SERVER_HPACK_LINK = 45, + HTTP_SERVER_HPACK_LOCATION = 46, + HTTP_SERVER_HPACK_MAX_FORWARDS = 47, + HTTP_SERVER_HPACK_PROXY_AUTHENTICATE = 48, + HTTP_SERVER_HPACK_PROXY_AUTHORIZATION = 49, + HTTP_SERVER_HPACK_RANGE = 50, + HTTP_SERVER_HPACK_REFERER = 51, + HTTP_SERVER_HPACK_REFRESH = 52, + HTTP_SERVER_HPACK_RETRY_AFTER = 53, + HTTP_SERVER_HPACK_SERVER = 54, + HTTP_SERVER_HPACK_SET_COOKIE = 55, + HTTP_SERVER_HPACK_STRICT_TRANSPORT_SECURITY = 56, + HTTP_SERVER_HPACK_TRANSFER_ENCODING = 57, + HTTP_SERVER_HPACK_USER_AGENT = 58, + HTTP_SERVER_HPACK_VARY = 59, + HTTP_SERVER_HPACK_VIA = 60, + HTTP_SERVER_HPACK_WWW_AUTHENTICATE = 61, +}; + +/* TODO Kconfig */ +#define HTTP2_HEADER_FIELD_MAX_LEN 256 + +#if defined(CONFIG_HTTP_SERVER) +#define HTTP_SERVER_HUFFMAN_DECODE_BUFFER_SIZE CONFIG_HTTP_SERVER_HUFFMAN_DECODE_BUFFER_SIZE +#else +#define HTTP_SERVER_HUFFMAN_DECODE_BUFFER_SIZE 0 +#endif + +/** @endcond */ + +/** HTTP2 header field with decoding buffer. */ +struct http_hpack_header_buf { + /** A pointer to the decoded header field name. */ + const char *name; + + /** A pointer to the decoded header field value. */ + const char *value; + + /** Length of the decoded header field name. */ + size_t name_len; + + /** Length of the decoded header field value. */ + size_t value_len; + + /** Encoding/Decoding buffer. Used with Huffman encoding/decoding. */ + uint8_t buf[HTTP_SERVER_HUFFMAN_DECODE_BUFFER_SIZE]; + + /** Length of the data in the decoding buffer. */ + size_t datalen; +}; + +/** @cond INTERNAL_HIDDEN */ + +int http_hpack_huffman_decode(const uint8_t *encoded_buf, size_t encoded_len, + uint8_t *buf, size_t buflen); +int http_hpack_huffman_encode(const uint8_t *str, size_t str_len, + uint8_t *buf, size_t buflen); +int http_hpack_decode_header(const uint8_t *buf, size_t datalen, + struct http_hpack_header_buf *header); +int http_hpack_encode_header(uint8_t *buf, size_t buflen, + struct http_hpack_header_buf *header); + +/** @endcond */ + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif diff --git a/include/zephyr/net/http/method.h b/include/zephyr/net/http/method.h index a45c555e97b..30f4aaeeaca 100644 --- a/include/zephyr/net/http/method.h +++ b/include/zephyr/net/http/method.h @@ -57,6 +57,10 @@ enum http_method { HTTP_MKCALENDAR = 30, /**< MKCALENDAR */ HTTP_LINK = 31, /**< LINK */ HTTP_UNLINK = 32, /**< UNLINK */ + + /** @cond INTERNAL_HIDDEN */ + HTTP_METHOD_END_VALUE /* keep this the last value */ + /** @endcond */ }; #ifdef __cplusplus diff --git a/include/zephyr/net/http/server.h b/include/zephyr/net/http/server.h new file mode 100644 index 00000000000..3e5223427dc --- /dev/null +++ b/include/zephyr/net/http/server.h @@ -0,0 +1,403 @@ +/* + * Copyright (c) 2023, Emna Rekik + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_NET_HTTP_SERVER_H_ +#define ZEPHYR_INCLUDE_NET_HTTP_SERVER_H_ + +/** + * @file server.h + * + * @brief HTTP server API + * + * @defgroup http_server HTTP server API + * @ingroup networking + * @{ + */ + +#include + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** @cond INTERNAL_HIDDEN */ + +#if defined(CONFIG_HTTP_SERVER) +#define HTTP_SERVER_CLIENT_BUFFER_SIZE CONFIG_HTTP_SERVER_CLIENT_BUFFER_SIZE +#define HTTP_SERVER_MAX_STREAMS CONFIG_HTTP_SERVER_MAX_STREAMS +#define HTTP_SERVER_MAX_CONTENT_TYPE_LEN CONFIG_HTTP_SERVER_MAX_CONTENT_TYPE_LENGTH +#define HTTP_SERVER_MAX_URL_LENGTH CONFIG_HTTP_SERVER_MAX_URL_LENGTH +#else +#define HTTP_SERVER_CLIENT_BUFFER_SIZE 0 +#define HTTP_SERVER_MAX_STREAMS 0 +#define HTTP_SERVER_MAX_CONTENT_TYPE_LEN 0 +#define HTTP_SERVER_MAX_URL_LENGTH 0 +#endif + +/* Maximum header field name / value length. This is only used to detect Upgrade and + * websocket header fields and values in the http1 server so the value is quite short. + */ +#define HTTP_SERVER_MAX_HEADER_LEN 32 + +#define HTTP2_PREFACE "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" + +/** @endcond */ + +/** + * @brief HTTP server resource type. + */ +enum http_resource_type { + /** Static resource, cannot be modified on runtime. */ + HTTP_RESOURCE_TYPE_STATIC, + + /** Dynamic resource, server interacts with the application via registered + * @ref http_resource_dynamic_cb_t. + */ + HTTP_RESOURCE_TYPE_DYNAMIC, + + /** Websocket resource, application takes control over Websocket connection + * after and upgrade. + */ + HTTP_RESOURCE_TYPE_WEBSOCKET, +}; + +/** + * @brief Representation of a server resource, common for all resource types. + */ +struct http_resource_detail { + /** Bitmask of supported HTTP methods (@ref http_method). */ + uint32_t bitmask_of_supported_http_methods; + + /** Resource type. */ + enum http_resource_type type; + + /** Length of the URL path. */ + int path_len; + + /** Content encoding of the resource. */ + const char *content_encoding; + + /** Content type of the resource. */ + const char *content_type; +}; + +/** @cond INTERNAL_HIDDEN */ +BUILD_ASSERT(NUM_BITS( + sizeof(((struct http_resource_detail *)0)->bitmask_of_supported_http_methods)) + >= (HTTP_METHOD_END_VALUE - 1)); +/** @endcond */ + +/** + * @brief Representation of a static server resource. + */ +struct http_resource_detail_static { + /** Common resource details. */ + struct http_resource_detail common; + + /** Content of the static resource. */ + const void *static_data; + + /** Size of the static resource. */ + size_t static_data_len; +}; + +/** @cond INTERNAL_HIDDEN */ +/* Make sure that the common is the first in the struct. */ +BUILD_ASSERT(offsetof(struct http_resource_detail_static, common) == 0); +/** @endcond */ + +struct http_client_ctx; + +/** Indicates the status of the currently processed piece of data. */ +enum http_data_status { + /** Transaction aborted, data incomplete. */ + HTTP_SERVER_DATA_ABORTED = -1, + /** Transaction incomplete, more data expected. */ + HTTP_SERVER_DATA_MORE = 0, + /** Final data fragment in current transaction. */ + HTTP_SERVER_DATA_FINAL = 1, +}; + +/** + * @typedef http_resource_dynamic_cb_t + * @brief Callback used when data is received. Data to be sent to client + * can be specified. + * + * @param client HTTP context information for this client connection. + * @param status HTTP data status, indicate whether more data is expected or not. + * @param data_buffer Data received. + * @param data_len Amount of data received. + * @param user_data User specified data. + * + * @return >0 amount of data to be sent to client, let server to call this + * function again when new data is received. + * 0 nothing to sent to client, close the connection + * <0 error, close the connection. + */ +typedef int (*http_resource_dynamic_cb_t)(struct http_client_ctx *client, + enum http_data_status status, + uint8_t *data_buffer, + size_t data_len, + void *user_data); + +/** + * @brief Representation of a dynamic server resource. + */ +struct http_resource_detail_dynamic { + /** Common resource details. */ + struct http_resource_detail common; + + /** Resource callback used by the server to interact with the + * application. + */ + http_resource_dynamic_cb_t cb; + + /** Data buffer used to exchanged data between server and the, + * application. + */ + uint8_t *data_buffer; + + /** Length of the data in the data buffer. */ + size_t data_buffer_len; + + /** A pointer to the client currently processing resource, used to + * prevent concurrent access to the resource from multiple clients. + */ + struct http_client_ctx *holder; + + /** A pointer to the user data registered by the application. */ + void *user_data; +}; + +/** @cond INTERNAL_HIDDEN */ +BUILD_ASSERT(offsetof(struct http_resource_detail_dynamic, common) == 0); +/** @endcond */ + +/** + * @typedef http_resource_websocket_cb_t + * @brief Callback used when a Websocket connection is setup. The application + * will need to handle all functionality related to the connection like + * reading and writing websocket data, and closing the connection. + * + * @param ws_socket A socket for the Websocket data. + * @param user_data User specified data. + * + * @return 0 Accepting the connection, HTTP server library will no longer + * handle data to/from the socket and it is application responsibility + * to send and receive data to/from the supplied socket. + * <0 error, close the connection. + */ +typedef int (*http_resource_websocket_cb_t)(int ws_socket, + void *user_data); + +/** @brief Representation of a websocket server resource */ +struct http_resource_detail_websocket { + /** Common resource details. */ + struct http_resource_detail common; + + /** Websocket socket value */ + int ws_sock; + + /** Resource callback used by the server to interact with the + * application. + */ + http_resource_websocket_cb_t cb; + + /** Data buffer used to exchanged data between server and the, + * application. + */ + uint8_t *data_buffer; + + /** Length of the data in the data buffer. */ + size_t data_buffer_len; + + /** A pointer to the user data registered by the application. */ + void *user_data; +}; + +/** @cond INTERNAL_HIDDEN */ +BUILD_ASSERT(offsetof(struct http_resource_detail_websocket, common) == 0); +/** @endcond */ + +/** @cond INTERNAL_HIDDEN */ + +enum http_stream_state { + HTTP_SERVER_STREAM_IDLE, + HTTP_SERVER_STREAM_RESERVED_LOCAL, + HTTP_SERVER_STREAM_RESERVED_REMOTE, + HTTP_SERVER_STREAM_OPEN, + HTTP_SERVER_STREAM_HALF_CLOSED_LOCAL, + HTTP_SERVER_STREAM_HALF_CLOSED_REMOTE, + HTTP_SERVER_STREAM_CLOSED +}; + +enum http_server_state { + HTTP_SERVER_FRAME_HEADER_STATE, + HTTP_SERVER_PREFACE_STATE, + HTTP_SERVER_REQUEST_STATE, + HTTP_SERVER_FRAME_DATA_STATE, + HTTP_SERVER_FRAME_HEADERS_STATE, + HTTP_SERVER_FRAME_SETTINGS_STATE, + HTTP_SERVER_FRAME_PRIORITY_STATE, + HTTP_SERVER_FRAME_WINDOW_UPDATE_STATE, + HTTP_SERVER_FRAME_CONTINUATION_STATE, + HTTP_SERVER_FRAME_PING_STATE, + HTTP_SERVER_FRAME_RST_STREAM_STATE, + HTTP_SERVER_FRAME_GOAWAY_STATE, + HTTP_SERVER_DONE_STATE, +}; + +enum http1_parser_state { + HTTP1_INIT_HEADER_STATE, + HTTP1_WAITING_HEADER_STATE, + HTTP1_RECEIVING_HEADER_STATE, + HTTP1_RECEIVED_HEADER_STATE, + HTTP1_RECEIVING_DATA_STATE, + HTTP1_MESSAGE_COMPLETE_STATE, +}; + +#define HTTP_SERVER_INITIAL_WINDOW_SIZE 65536 +#define HTTP_SERVER_WS_MAX_SEC_KEY_LEN 32 + +/** @endcond */ + +/** @brief HTTP/2 stream representation. */ +struct http_stream_ctx { + int stream_id; /**< Stream identifier. */ + enum http_stream_state stream_state; /**< Stream state. */ + int window_size; /**< Stream-level window size. */ +}; + +/** @brief HTTP/2 frame representation. */ +struct http_frame { + uint32_t length; /**< Frame payload length. */ + uint32_t stream_identifier; /**< Stream ID the frame belongs to. */ + uint8_t type; /**< Frame type. */ + uint8_t flags; /**< Frame flags. */ + uint8_t *payload; /**< A pointer to the frame payload. */ +}; + +/** + * @brief Representation of an HTTP client connected to the server. + */ +struct http_client_ctx { + /** Socket descriptor associated with the server. */ + int fd; + + /** Client data buffer. */ + unsigned char buffer[HTTP_SERVER_CLIENT_BUFFER_SIZE]; + + /** Cursor indicating currently processed byte. */ + unsigned char *cursor; + + /** Data left to process in the buffer. */ + size_t data_len; + + /** Connection-level window size. */ + int window_size; + + /** Server state for the associated client. */ + enum http_server_state server_state; + + /** Currently processed HTTP/2 frame. */ + struct http_frame current_frame; + + /** Currently processed resource detail. */ + struct http_resource_detail *current_detail; + + /** HTTP/2 header parser context. */ + struct http_hpack_header_buf header_field; + + /** HTTP/2 streams context. */ + struct http_stream_ctx streams[HTTP_SERVER_MAX_STREAMS]; + + /** HTTP/1 parser configuration. */ + struct http_parser_settings parser_settings; + + /** HTTP/1 parser context. */ + struct http_parser parser; + + /** Request URL. */ + unsigned char url_buffer[HTTP_SERVER_MAX_URL_LENGTH]; + + /** Request content type. */ + unsigned char content_type[HTTP_SERVER_MAX_CONTENT_TYPE_LEN]; + + /** Temp buffer for currently processed header (HTTP/1 only). */ + unsigned char header_buffer[HTTP_SERVER_MAX_HEADER_LEN]; + + /** Request content length. */ + size_t content_len; + + /** Request method. */ + enum http_method method; + + /** HTTP/1 parser state. */ + enum http1_parser_state parser_state; + + /** Length of the payload length in the currently processed request + * fragment (HTTP/1 only). + */ + int http1_frag_data_len; + + /** Client inactivity timer. The client connection is closed by the + * server when it expires. + */ + struct k_work_delayable inactivity_timer; + +/** @cond INTERNAL_HIDDEN */ + /** Websocket security key. */ + IF_ENABLED(CONFIG_WEBSOCKET, (uint8_t ws_sec_key[HTTP_SERVER_WS_MAX_SEC_KEY_LEN])); +/** @endcond */ + + /** Flag indicating that headers were sent in the reply. */ + bool headers_sent : 1; + + /** Flag indicating that HTTP2 preface was sent. */ + bool preface_sent : 1; + + /** Flag indicating that upgrade header was present in the request. */ + bool has_upgrade_header : 1; + + /** Flag indicating HTTP/2 upgrade takes place. */ + bool http2_upgrade : 1; + + /** Flag indicating Websocket upgrade takes place. */ + bool websocket_upgrade : 1; + + /** Flag indicating Websocket key is being processed. */ + bool websocket_sec_key_next : 1; +}; + +/** @brief Start the HTTP2 server. + * + * The server runs in a background thread. Once started, the server will create + * a server socket for all HTTP services registered in the system and accept + * connections from clients (see @ref HTTP_SERVICE_DEFINE). + */ +int http_server_start(void); + +/** @brief Stop the HTTP2 server. + * + * All server sockets are closed and the server thread is suspended. + */ +int http_server_stop(void); + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif diff --git a/include/zephyr/net/http/service.h b/include/zephyr/net/http/service.h index b6997334de4..e541c768f56 100644 --- a/include/zephyr/net/http/service.h +++ b/include/zephyr/net/http/service.h @@ -7,17 +7,32 @@ #ifndef ZEPHYR_INCLUDE_NET_HTTP_SERVICE_H_ #define ZEPHYR_INCLUDE_NET_HTTP_SERVICE_H_ +/** + * @file service.h + * + * @brief HTTP service API + * + * @defgroup http_service HTTP service API + * @ingroup networking + * @{ + */ + #include #include +#include #include +#include #ifdef __cplusplus extern "C" { #endif +/** HTTP resource description */ struct http_resource_desc { + /** Resource name */ const char *resource; + /** Detail associated with this resource */ void *detail; }; @@ -42,9 +57,11 @@ struct http_resource_desc { const STRUCT_SECTION_ITERABLE_ALTERNATE(http_resource_desc_##_service, http_resource_desc, \ _name) = { \ .resource = _resource, \ - .detail = (_detail), \ + .detail = (void *)(_detail), \ } +/** @cond INTERNAL_HIDDEN */ + struct http_service_desc { const char *host; uint16_t *port; @@ -53,10 +70,14 @@ struct http_service_desc { size_t backlog; struct http_resource_desc *res_begin; struct http_resource_desc *res_end; +#if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS) + const sec_tag_t *sec_tag_list; + size_t sec_tag_list_size; +#endif }; #define __z_http_service_define(_name, _host, _port, _concurrent, _backlog, _detail, _res_begin, \ - _res_end) \ + _res_end, ...) \ static const STRUCT_SECTION_ITERABLE(http_service_desc, _name) = { \ .host = _host, \ .port = (uint16_t *)(_port), \ @@ -65,8 +86,16 @@ struct http_service_desc { .backlog = (_backlog), \ .res_begin = (_res_begin), \ .res_end = (_res_end), \ + COND_CODE_1(CONFIG_NET_SOCKETS_SOCKOPT_TLS, \ + (.sec_tag_list = COND_CODE_0(NUM_VA_ARGS_LESS_1(__VA_ARGS__), (NULL), \ + (GET_ARG_N(1, __VA_ARGS__))),), ()) \ + COND_CODE_1(CONFIG_NET_SOCKETS_SOCKOPT_TLS, \ + (.sec_tag_list_size = COND_CODE_0(NUM_VA_ARGS_LESS_1(__VA_ARGS__), (0),\ + (GET_ARG_N(1, GET_ARGS_LESS_N(1, __VA_ARGS__))))), ())\ } +/** @endcond */ + /** * @brief Define an HTTP service without static resources. * @@ -88,6 +117,33 @@ struct http_service_desc { #define HTTP_SERVICE_DEFINE_EMPTY(_name, _host, _port, _concurrent, _backlog, _detail) \ __z_http_service_define(_name, _host, _port, _concurrent, _backlog, _detail, NULL, NULL) +/** + * @brief Define an HTTPS service without static resources. + * + * @note The @p _host parameter must be non-`NULL`. It is used to specify an IP address either in + * IPv4 or IPv6 format a fully-qualified hostname or a virtual host. + * + * @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 _concurrent Maximum number of concurrent clients. + * @param _backlog Maximum number queued connections. + * @param _detail Implementation-specific detail associated with the service. + * @param _sec_tag_list TLS security tag list used to setup a HTTPS socket. + * @param _sec_tag_list_size TLS security tag list size used to setup a HTTPS socket. + */ +#define HTTPS_SERVICE_DEFINE_EMPTY(_name, _host, _port, _concurrent, _backlog, _detail, \ + _sec_tag_list, _sec_tag_list_size) \ + __z_http_service_define(_name, _host, _port, _concurrent, _backlog, _detail, NULL, NULL, \ + _sec_tag_list, _sec_tag_list_size); \ + BUILD_ASSERT(IS_ENABLED(CONFIG_NET_SOCKETS_SOCKOPT_TLS), \ + "TLS is required for HTTP secure (CONFIG_NET_SOCKETS_SOCKOPT_TLS)") + /** * @brief Define an HTTP service with static resources. * @@ -113,6 +169,37 @@ struct http_service_desc { &_CONCAT(_http_resource_desc_##_name, _list_start)[0], \ &_CONCAT(_http_resource_desc_##_name, _list_end)[0]) +/** + * @brief Define an HTTPS service with static resources. + * + * @note The @p _host parameter must be non-`NULL`. It is used to specify an IP address either in + * IPv4 or IPv6 format a fully-qualified hostname or a virtual host. + * + * @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 _concurrent Maximum number of concurrent clients. + * @param _backlog Maximum number queued connections. + * @param _detail Implementation-specific detail associated with the service. + * @param _sec_tag_list TLS security tag list used to setup a HTTPS socket. + * @param _sec_tag_list_size TLS security tag list size used to setup a HTTPS socket. + */ +#define HTTPS_SERVICE_DEFINE(_name, _host, _port, _concurrent, _backlog, _detail, \ + _sec_tag_list, _sec_tag_list_size) \ + extern struct http_resource_desc _CONCAT(_http_resource_desc_##_name, _list_start)[]; \ + extern struct http_resource_desc _CONCAT(_http_resource_desc_##_name, _list_end)[]; \ + __z_http_service_define(_name, _host, _port, _concurrent, _backlog, _detail, \ + &_CONCAT(_http_resource_desc_##_name, _list_start)[0], \ + &_CONCAT(_http_resource_desc_##_name, _list_end)[0], \ + _sec_tag_list, _sec_tag_list_size); \ + BUILD_ASSERT(IS_ENABLED(CONFIG_NET_SOCKETS_SOCKOPT_TLS), \ + "TLS is required for HTTP secure (CONFIG_NET_SOCKETS_SOCKOPT_TLS)") + /** * @brief Count the number of HTTP services. * @@ -130,7 +217,7 @@ struct http_service_desc { /** * @brief Iterate over all HTTP services. * - * @param _it Name of iterator (of type @ref http_service_desc) + * @param _it Name of http_service_desc iterator */ #define HTTP_SERVICE_FOREACH(_it) STRUCT_SECTION_FOREACH(http_service_desc, _it) @@ -165,4 +252,8 @@ struct http_service_desc { } #endif +/** + * @} + */ + #endif /* ZEPHYR_INCLUDE_NET_HTTP_SERVICE_H_ */ diff --git a/include/zephyr/net/icmp.h b/include/zephyr/net/icmp.h index a5b9f6b2455..6d6a6b2c867 100644 --- a/include/zephyr/net/icmp.h +++ b/include/zephyr/net/icmp.h @@ -5,11 +5,12 @@ */ /** @file icmp.h + * + * @brief ICMP sending and receiving. * * @defgroup icmp Send and receive IPv4 or IPv6 ICMP Echo Request messages. * @ingroup networking * @{ - * @brief ICMP sending and receiving. */ #ifndef ZEPHYR_INCLUDE_NET_ICMP_H_ @@ -27,10 +28,10 @@ extern "C" { #endif -#define NET_ICMPV4_ECHO_REQUEST 8 -#define NET_ICMPV4_ECHO_REPLY 0 -#define NET_ICMPV6_ECHO_REQUEST 128 -#define NET_ICMPV6_ECHO_REPLY 129 +#define NET_ICMPV4_ECHO_REQUEST 8 /**< ICMPv4 Echo-Request */ +#define NET_ICMPV4_ECHO_REPLY 0 /**< ICMPv4 Echo-Reply */ +#define NET_ICMPV6_ECHO_REQUEST 128 /**< ICMPv6 Echo-Request */ +#define NET_ICMPV6_ECHO_REPLY 129 /**< ICMPv6 Echo-Reply */ struct net_icmp_ctx; struct net_icmp_ip_hdr; @@ -136,7 +137,7 @@ struct net_icmp_ping_params { /** Network packet priority. */ int priority; - /* Arbitrary payload data that will be included in the Echo Reply + /** Arbitrary payload data that will be included in the Echo Reply * verbatim. May be NULL. */ const void *data; diff --git a/include/zephyr/net/ieee802154.h b/include/zephyr/net/ieee802154.h index 927a9036db3..b60aa7071f3 100644 --- a/include/zephyr/net/ieee802154.h +++ b/include/zephyr/net/ieee802154.h @@ -241,10 +241,11 @@ struct ieee802154_security_ctx { /** INTERNAL_HIDDEN @endcond */ }; +/** @brief IEEE 802.15.4 device role */ enum ieee802154_device_role { - IEEE802154_DEVICE_ROLE_ENDDEVICE, - IEEE802154_DEVICE_ROLE_COORDINATOR, - IEEE802154_DEVICE_ROLE_PAN_COORDINATOR, + IEEE802154_DEVICE_ROLE_ENDDEVICE, /**< End device */ + IEEE802154_DEVICE_ROLE_COORDINATOR, /**< Coordinator */ + IEEE802154_DEVICE_ROLE_PAN_COORDINATOR, /**< PAN coordinator */ }; /** IEEE 802.15.4 L2 context. */ diff --git a/include/zephyr/net/ieee802154_ie.h b/include/zephyr/net/ieee802154_ie.h index 0be4c1576e5..a2378a38efa 100644 --- a/include/zephyr/net/ieee802154_ie.h +++ b/include/zephyr/net/ieee802154_ie.h @@ -40,8 +40,8 @@ * @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, + IEEE802154_IE_TYPE_HEADER = 0x0, /**< Header type */ + IEEE802154_IE_TYPE_PAYLOAD, /**< Payload type */ }; /** @@ -51,13 +51,13 @@ enum ieee802154_ie_type { * 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, + IEEE802154_HEADER_IE_ELEMENT_ID_VENDOR_SPECIFIC_IE = 0x00, /**< Vendor specific IE */ + IEEE802154_HEADER_IE_ELEMENT_ID_CSL_IE = 0x1a, /**< CSL IE */ + IEEE802154_HEADER_IE_ELEMENT_ID_RIT_IE = 0x1b, /**< RIT IE */ + IEEE802154_HEADER_IE_ELEMENT_ID_RENDEZVOUS_TIME_IE = 0x1d, /**< Rendezvous time IE */ + IEEE802154_HEADER_IE_ELEMENT_ID_TIME_CORRECTION_IE = 0x1e, /**< Time correction IE */ + IEEE802154_HEADER_IE_ELEMENT_ID_HEADER_TERMINATION_1 = 0x7e, /**< Header termination 1 */ + IEEE802154_HEADER_IE_ELEMENT_ID_HEADER_TERMINATION_2 = 0x7f, /**< Header termination 2 */ /* partial list, add additional ids as needed */ }; @@ -67,36 +67,40 @@ enum ieee802154_header_ie_element_id { /** @brief Vendor Specific Header IE, see section 7.4.2.3. */ struct ieee802154_header_ie_vendor_specific { + /** Vendor OUI */ uint8_t vendor_oui[IEEE802154_VENDOR_SPECIFIC_IE_OUI_LEN]; + /** Vendor specific information */ 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; + uint16_t csl_phase; /**< CSL phase */ + uint16_t csl_period; /**< CSL period */ + uint16_t csl_rendezvous_time; /**< 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; + uint16_t csl_phase; /**< CSL phase */ + uint16_t csl_period; /**< CSL period */ } __packed; /** @brief Generic CSL IE, see section 7.4.2.3. */ struct ieee802154_header_ie_csl { union { + /** CSL full information */ struct ieee802154_header_ie_csl_full full; + /** CSL reduced information */ 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; + uint8_t time_to_first_listen; /**< Time to First Listen */ + uint8_t number_of_repeat_listen; /**< Number of Repeat Listen */ + uint16_t repeat_listen_interval; /**< Repeat listen interval */ } __packed; /** @@ -104,8 +108,8 @@ struct ieee802154_header_ie_rit { * (macCslInterval is nonzero). */ struct ieee802154_header_ie_rendezvous_time_full { - uint16_t rendezvous_time; - uint16_t wakeup_interval; + uint16_t rendezvous_time; /**< Rendezvous time */ + uint16_t wakeup_interval; /**< Wakeup interval */ } __packed; /** @@ -113,22 +117,26 @@ struct ieee802154_header_ie_rendezvous_time_full { * (macCslInterval is zero). */ struct ieee802154_header_ie_rendezvous_time_reduced { - uint16_t rendezvous_time; + uint16_t rendezvous_time; /**< Rendezvous time */ } __packed; /** @brief Rendezvous Time IE, see section 7.4.2.6. */ struct ieee802154_header_ie_rendezvous_time { union { + /** Rendezvous time full information */ struct ieee802154_header_ie_rendezvous_time_full full; + /** Rendezvous time reduced information */ 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; + uint16_t time_sync_info; /**< Time synchronization information */ } __packed; +/** @cond INTERNAL_HIDDEN */ + /* @brief Generic Header IE, see section 7.4.2.1. */ struct ieee802154_header_ie { #if CONFIG_LITTLE_ENDIAN @@ -152,6 +160,8 @@ struct ieee802154_header_ie { } content; } __packed; +/** INTERNAL_HIDDEN @endcond */ + /** @brief The header IE's header length (2 bytes). */ #define IEEE802154_HEADER_IE_HEADER_LENGTH sizeof(uint16_t) diff --git a/include/zephyr/net/ieee802154_mgmt.h b/include/zephyr/net/ieee802154_mgmt.h index 1f08c0b73c0..59372423558 100644 --- a/include/zephyr/net/ieee802154_mgmt.h +++ b/include/zephyr/net/ieee802154_mgmt.h @@ -322,8 +322,8 @@ struct ieee802154_req_params { /** Result address */ union { - uint16_t short_addr; /* in CPU byte order */ - uint8_t addr[IEEE802154_MAX_ADDR_LENGTH]; /* in big endian */ + uint16_t short_addr; /**< in CPU byte order */ + uint8_t addr[IEEE802154_MAX_ADDR_LENGTH]; /**< in big endian */ }; /** length of address */ @@ -339,13 +339,13 @@ struct ieee802154_req_params { * see tables 9-9 and 9-10 in section 9.5. */ struct ieee802154_security_params { - uint8_t key[16]; /* secKeyDescriptor.secKey */ - uint8_t key_len; /* a key length of 16 bytes is mandatory for standards conformance */ - uint8_t key_mode : 2; /* secKeyIdMode */ - uint8_t level : 3; /* Used instead of a frame-specific SecurityLevel parameter when + uint8_t key[16]; /**< secKeyDescriptor.secKey */ + uint8_t key_len; /**< Key length of 16 bytes is mandatory for standards conformance */ + uint8_t key_mode : 2; /**< secKeyIdMode */ + uint8_t level : 3; /**< Used instead of a frame-specific SecurityLevel parameter when * constructing the auxiliary security header */ - uint8_t _unused : 3; + uint8_t _unused : 3; /**< unused value (ignore) */ }; #ifdef __cplusplus diff --git a/include/zephyr/net/ieee802154_radio.h b/include/zephyr/net/ieee802154_radio.h index 922d43c4b51..028a2d1ea1b 100644 --- a/include/zephyr/net/ieee802154_radio.h +++ b/include/zephyr/net/ieee802154_radio.h @@ -233,8 +233,8 @@ enum ieee802154_phy_channel_page { * ieee802154_phy_supported_channels. */ struct ieee802154_phy_channel_range { - uint16_t from_channel; - uint16_t to_channel; + uint16_t from_channel; /**< From channel range */ + uint16_t to_channel; /**< To channel range */ }; /** @@ -533,11 +533,11 @@ enum ieee802154_hw_caps { /** Filter type, see @ref ieee802154_radio_api::filter */ enum ieee802154_filter_type { - IEEE802154_FILTER_TYPE_IEEE_ADDR, - IEEE802154_FILTER_TYPE_SHORT_ADDR, - IEEE802154_FILTER_TYPE_PAN_ID, - IEEE802154_FILTER_TYPE_SRC_IEEE_ADDR, - IEEE802154_FILTER_TYPE_SRC_SHORT_ADDR, + IEEE802154_FILTER_TYPE_IEEE_ADDR, /**< Address type filter */ + IEEE802154_FILTER_TYPE_SHORT_ADDR, /**< Short address type filter */ + IEEE802154_FILTER_TYPE_PAN_ID, /**< PAN id type filter */ + IEEE802154_FILTER_TYPE_SRC_IEEE_ADDR, /**< Source address type filter */ + IEEE802154_FILTER_TYPE_SRC_SHORT_ADDR, /**< Source short address type filter */ }; /** Driver events, see @ref IEEE802154_CONFIG_EVENT_HANDLER */ @@ -1125,15 +1125,15 @@ struct ieee802154_config { union { /** see @ref IEEE802154_CONFIG_AUTO_ACK_FPB */ struct { - bool enabled; - enum ieee802154_fpb_mode mode; + bool enabled; /**< Is auto ACK FPB enabled */ + enum ieee802154_fpb_mode mode; /**< Auto ACK FPB mode */ } auto_ack_fpb; /** see @ref IEEE802154_CONFIG_ACK_FPB */ struct { - uint8_t *addr; /* in little endian for both, short and extended address */ - bool extended; - bool enabled; + uint8_t *addr; /**< little endian for both short and extended address */ + bool extended; /**< Is extended address */ + bool enabled; /**< Is enabled */ } ack_fpb; /** see @ref IEEE802154_CONFIG_PAN_COORDINATOR */ @@ -1194,6 +1194,9 @@ struct ieee802154_config { */ net_time_t duration; + /** + * Used channel + */ uint8_t channel; } rx_slot; @@ -1670,7 +1673,7 @@ struct ieee802154_radio_api { * @retval -EBUSY The frame could not be sent because the medium was * busy (CSMA/CA or CCA offloading feature only). * @retval -ENOMSG The frame was not confirmed by an ACK packet (TX ACK - * offloading feature only). + * offloading feature only) or the received ACK packet was invalid. * @retval -ENOBUFS The frame could not be scheduled due to missing * internal resources (timed TX offloading feature only). * @retval -ENETDOWN The interface is not "UP". diff --git a/include/zephyr/net/ieee802154_radio_openthread.h b/include/zephyr/net/ieee802154_radio_openthread.h index f6f9949d328..e45bbc6b85b 100644 --- a/include/zephyr/net/ieee802154_radio_openthread.h +++ b/include/zephyr/net/ieee802154_radio_openthread.h @@ -25,6 +25,7 @@ enum ieee802154_openthread_hw_caps { IEEE802154_OPENTHREAD_HW_MULTIPLE_CCA = BIT(IEEE802154_HW_CAPS_BITS_PRIV_START), }; +/** @brief TX mode */ enum ieee802154_openthread_tx_mode { /** * The @ref IEEE802154_OPENTHREAD_TX_MODE_TXTIME_MULTIPLE_CCA mode allows to send @@ -93,6 +94,7 @@ enum ieee802154_openthread_config_type { /** OpenThread specific configuration data of ieee802154 driver. */ struct ieee802154_openthread_config { union { + /** Common configuration */ struct ieee802154_config common; /** ``IEEE802154_OPENTHREAD_CONFIG_MAX_EXTRA_CCA_ATTEMPTS`` @@ -134,6 +136,7 @@ enum ieee802154_openthread_attr { */ struct ieee802154_openthread_attr_value { union { + /** Common attribute value */ struct ieee802154_attr_value common; /** @brief Attribute value for @ref IEEE802154_OPENTHREAD_ATTR_T_RECCA */ diff --git a/include/zephyr/net/igmp.h b/include/zephyr/net/igmp.h index ed39a31359f..7dbfd78e1d8 100644 --- a/include/zephyr/net/igmp.h +++ b/include/zephyr/net/igmp.h @@ -27,10 +27,11 @@ extern "C" { #endif +/** IGMP parameters */ 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 */ + 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 */ }; /** diff --git a/include/zephyr/net/ipv4_autoconf.h b/include/zephyr/net/ipv4_autoconf.h index 5fec5eb6637..3b686faffca 100644 --- a/include/zephyr/net/ipv4_autoconf.h +++ b/include/zephyr/net/ipv4_autoconf.h @@ -13,13 +13,15 @@ /** Current state of IPv4 Autoconfiguration */ enum net_ipv4_autoconf_state { - NET_IPV4_AUTOCONF_INIT, - NET_IPV4_AUTOCONF_PROBE, - NET_IPV4_AUTOCONF_ANNOUNCE, - NET_IPV4_AUTOCONF_ASSIGNED, - NET_IPV4_AUTOCONF_RENEW, + NET_IPV4_AUTOCONF_INIT, /**< Initialization state */ + NET_IPV4_AUTOCONF_PROBE, /**< Probing state */ + NET_IPV4_AUTOCONF_ANNOUNCE, /**< Announce state */ + NET_IPV4_AUTOCONF_ASSIGNED, /**< Assigned state */ + NET_IPV4_AUTOCONF_RENEW, /**< Renew state */ }; +/** @cond INTERNAL_HIDDEN */ + /** * @brief Initialize IPv4 auto configuration engine. */ @@ -29,4 +31,6 @@ void net_ipv4_autoconf_init(void); #define net_ipv4_autoconf_init(...) #endif +/** @endcond */ + #endif /* ZEPHYR_INCLUDE_NET_IPV4_AUTOCONF_H_ */ diff --git a/include/zephyr/net/lwm2m.h b/include/zephyr/net/lwm2m.h index e68f5fb47ad..0ae5314e3d0 100644 --- a/include/zephyr/net/lwm2m.h +++ b/include/zephyr/net/lwm2m.h @@ -7,11 +7,6 @@ /** @file lwm2m.h * - * @defgroup lwm2m_api LwM2M high-level API - * @since 1.9 - * @version 0.8.0 - * @ingroup networking - * @{ * @brief LwM2M high-level API * * @details @@ -21,6 +16,12 @@ * * @note For more information refer to Technical Specification * OMA-TS-LightweightM2M_Core-V1_1_1-20190617-A + * + * @defgroup lwm2m_api LwM2M high-level API + * @since 1.9 + * @version 0.8.0 + * @ingroup networking + * @{ */ #ifndef ZEPHYR_INCLUDE_NET_LWM2M_H_ @@ -283,7 +284,9 @@ struct lwm2m_ctx { struct lwm2m_time_series_elem { /** Cached data Unix timestamp */ time_t t; + /** Element value */ union { + /** @cond INTERNAL_HIDDEN */ uint8_t u8; uint16_t u16; uint32_t u32; @@ -295,6 +298,7 @@ struct lwm2m_time_series_elem { time_t time; double f; bool b; + /** @endcond */ }; }; @@ -329,6 +333,10 @@ typedef void *(*lwm2m_engine_get_data_cb_t)(uint16_t obj_inst_id, * make use of this callback to pass the data back to the client or LwM2M * objects. * + * On a block-wise transfers the handler is called multiple times with the data blocks + * and increasing offset. The last block has the last_block flag set to true. + * Beginning of the block transfer has the offset set to 0. + * * A function of this type can be registered via: * lwm2m_engine_register_validate_callback() * lwm2m_engine_register_post_write_callback() @@ -344,6 +352,7 @@ typedef void *(*lwm2m_engine_get_data_cb_t)(uint16_t obj_inst_id, * false. * @param[in] total_size Expected total size of data for a block transfer. * For non-block transfers this is 0. + * @param[in] offset Offset of the data block. For non-block transfers this is always 0. * * @return Callback returns a negative error code (errno.h) indicating * reason of failure or 0 for success. @@ -351,7 +360,7 @@ typedef void *(*lwm2m_engine_get_data_cb_t)(uint16_t obj_inst_id, typedef int (*lwm2m_engine_set_data_cb_t)(uint16_t obj_inst_id, uint16_t res_id, uint16_t res_inst_id, uint8_t *data, uint16_t data_len, - bool last_block, size_t total_size); + bool last_block, size_t total_size, size_t offset); /** * @brief Asynchronous event notification callback. @@ -2139,21 +2148,37 @@ void lwm2m_acknowledge(struct lwm2m_ctx *client_ctx); * lwm2m_rd_client_start() */ enum lwm2m_rd_client_event { + /** Invalid event */ LWM2M_RD_CLIENT_EVENT_NONE, + /** Bootstrap registration failure */ LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_REG_FAILURE, + /** Bootstrap registration complete */ LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_REG_COMPLETE, + /** Bootstrap transfer complete */ LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_TRANSFER_COMPLETE, + /** Registration failure */ LWM2M_RD_CLIENT_EVENT_REGISTRATION_FAILURE, + /** Registration complete */ LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE, + /** Registration timeout */ LWM2M_RD_CLIENT_EVENT_REG_TIMEOUT, + /** Registration update complete */ LWM2M_RD_CLIENT_EVENT_REG_UPDATE_COMPLETE, + /** De-registration failure */ LWM2M_RD_CLIENT_EVENT_DEREGISTER_FAILURE, + /** Disconnected */ LWM2M_RD_CLIENT_EVENT_DISCONNECT, + /** Queue mode RX off */ LWM2M_RD_CLIENT_EVENT_QUEUE_MODE_RX_OFF, + /** Engine suspended */ LWM2M_RD_CLIENT_EVENT_ENGINE_SUSPENDED, + /** Network error */ LWM2M_RD_CLIENT_EVENT_NETWORK_ERROR, + /** Registration update */ LWM2M_RD_CLIENT_EVENT_REG_UPDATE, + /** De-register */ LWM2M_RD_CLIENT_EVENT_DEREGISTER, + /** Server disabled */ LWM2M_RD_CLIENT_EVENT_SERVER_DISABLED, }; @@ -2265,9 +2290,9 @@ char *lwm2m_path_log_buf(char *buf, struct lwm2m_obj_path *path); * lwm2m_send_cb() */ enum lwm2m_send_status { - LWM2M_SEND_STATUS_SUCCESS, - LWM2M_SEND_STATUS_FAILURE, - LWM2M_SEND_STATUS_TIMEOUT, + LWM2M_SEND_STATUS_SUCCESS, /**< Succeed */ + LWM2M_SEND_STATUS_FAILURE, /**< Failure */ + LWM2M_SEND_STATUS_TIMEOUT, /**< Timeout */ }; /** diff --git a/include/zephyr/net/lwm2m_path.h b/include/zephyr/net/lwm2m_path.h index cd42c4942da..ad012c8aba8 100644 --- a/include/zephyr/net/lwm2m_path.h +++ b/include/zephyr/net/lwm2m_path.h @@ -8,7 +8,10 @@ #define ZEPHYR_INCLUDE_NET_LWM2M_PATH_H_ /** + * @file lwm2m.h + * * @brief LwM2M path helper macros + * * @defgroup lwm2m_path_helpers LwM2M path helper macros * @ingroup lwm2m_api * @{ diff --git a/include/zephyr/net/mdio.h b/include/zephyr/net/mdio.h index 8d1998f7cec..6ed13c1a6fd 100644 --- a/include/zephyr/net/mdio.h +++ b/include/zephyr/net/mdio.h @@ -110,7 +110,7 @@ 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 */ +/** BASE-T1 PMA/PMD control register */ #define MDIO_PMA_PMD_BT1_CTRL 0x0834U /* BASE-T1 Auto-negotiation Control register */ @@ -152,9 +152,9 @@ enum mdio_opcode { #define MDIO_AN_T1_ADV_M_MST BIT(4) /* BASE-T1 Auto-negotiation Advertisement register [47:32] */ -/* 10BASE-T1L High Level Transmit Operating Mode Request */ +/** 10BASE-T1L High Level Transmit Operating Mode Request */ #define MDIO_AN_T1_ADV_H_10L_TX_HI_REQ BIT(12) -/* 10BASE-T1L High Level Transmit Operating Mode Ability */ +/** 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 */ diff --git a/include/zephyr/net/mii.h b/include/zephyr/net/mii.h index fc2a65bc306..371f19665c2 100644 --- a/include/zephyr/net/mii.h +++ b/include/zephyr/net/mii.h @@ -131,8 +131,9 @@ #define MII_ADVERTISE_10_FULL (1 << 6) /** try for 10 Mb/s half duplex support */ #define MII_ADVERTISE_10_HALF (1 << 5) -/** Selector Field */ +/** Selector Field Mask */ #define MII_ADVERTISE_SEL_MASK (0x1F << 0) +/** Selector Field */ #define MII_ADVERTISE_SEL_IEEE_802_3 0x01 /* 1000BASE-T Control Register bit definitions */ @@ -141,6 +142,7 @@ /** try for 1000BASE-T half duplex support */ #define MII_ADVERTISE_1000_HALF (1 << 8) +/** Advertise all speeds */ #define MII_ADVERTISE_ALL (MII_ADVERTISE_10_HALF | MII_ADVERTISE_10_FULL |\ MII_ADVERTISE_100_HALF | MII_ADVERTISE_100_FULL |\ MII_ADVERTISE_SEL_IEEE_802_3) diff --git a/include/zephyr/net/mqtt.h b/include/zephyr/net/mqtt.h index 54b2532f0fa..9c09069b107 100644 --- a/include/zephyr/net/mqtt.h +++ b/include/zephyr/net/mqtt.h @@ -6,16 +6,17 @@ /** @file mqtt.h * - * @defgroup mqtt_socket MQTT Client library - * @since 1.14 - * @version 0.8.0 - * @ingroup networking - * @{ * @brief MQTT Client Implementation * * @note The implementation assumes TCP module is enabled. * * @note By default the implementation uses MQTT version 3.1.1. + * + * @defgroup mqtt_socket MQTT Client library + * @since 1.14 + * @version 0.8.0 + * @ingroup networking + * @{ */ #ifndef ZEPHYR_INCLUDE_NET_MQTT_H_ @@ -423,15 +424,16 @@ struct mqtt_transport { */ enum mqtt_transport_type type; + /** Use either unsecured TCP or secured TLS transport */ union { - /* TCP socket transport for MQTT */ + /** TCP socket transport for MQTT */ struct { /** Socket descriptor. */ int sock; } tcp; #if defined(CONFIG_MQTT_LIB_TLS) - /* TLS socket transport for MQTT */ + /** TLS socket transport for MQTT */ struct { /** Socket descriptor. */ int sock; @@ -564,6 +566,9 @@ struct mqtt_client { * Default is CONFIG_MQTT_CLEAN_SESSION. */ uint8_t clean_session : 1; + + /** User specific opaque data */ + void *user_data; }; /** diff --git a/include/zephyr/net/mqtt_sn.h b/include/zephyr/net/mqtt_sn.h index cb1a6d33731..102cb5e692a 100644 --- a/include/zephyr/net/mqtt_sn.h +++ b/include/zephyr/net/mqtt_sn.h @@ -6,15 +6,15 @@ /** @file mqtt_sn.h * - * @defgroup mqtt_sn_socket MQTT-SN Client library - * @ingroup networking - * @{ * @brief MQTT-SN Client Implementation * * @details * MQTT-SN Client's Application interface is defined in this header. * Targets protocol version 1.2. * + * @defgroup mqtt_sn_socket MQTT-SN Client library + * @ingroup networking + * @{ */ #ifndef ZEPHYR_INCLUDE_NET_MQTT_SN_H_ diff --git a/include/zephyr/net/net_context.h b/include/zephyr/net/net_context.h index 658a0767c02..8e85af1fde9 100644 --- a/include/zephyr/net/net_context.h +++ b/include/zephyr/net/net_context.h @@ -35,6 +35,8 @@ extern "C" { /** Is this context used or not */ #define NET_CONTEXT_IN_USE BIT(0) +/** @cond INTERNAL_HIDDEN */ + /** State of the context (bits 1 & 2 in the flags) */ enum net_context_state { NET_CONTEXT_IDLE = 0, @@ -46,6 +48,8 @@ enum net_context_state { NET_CONTEXT_LISTENING = 3, }; +/** @endcond */ + /** * The address family, connection type and IP protocol are * stored into a bit field to save space. @@ -65,7 +69,7 @@ enum net_context_state { /** Is the socket closing / closed */ #define NET_CONTEXT_CLOSING_SOCK BIT(10) -/* Context is bound to a specific interface */ +/** Context is bound to a specific interface */ #define NET_CONTEXT_BOUND_TO_IFACE BIT(11) struct net_context; @@ -348,6 +352,13 @@ __net_socket struct net_context { #if defined(CONFIG_NET_CONTEXT_RECV_PKTINFO) /** Receive network packet information in recvmsg() call */ bool recv_pktinfo; +#endif +#if defined(CONFIG_NET_IPV6) + /** + * Source address selection preferences. Currently used only for IPv6, + * see RFC 5014 for details. + */ + uint16_t addr_preferences; #endif } options; @@ -435,7 +446,7 @@ static inline void net_context_set_accepting(struct net_context *context, if (accepting) { context->flags |= NET_CONTEXT_ACCEPTING_SOCK; } else { - context->flags &= ~NET_CONTEXT_ACCEPTING_SOCK; + context->flags &= (uint16_t)~NET_CONTEXT_ACCEPTING_SOCK; } } @@ -467,13 +478,17 @@ static inline void net_context_set_closing(struct net_context *context, if (closing) { context->flags |= NET_CONTEXT_CLOSING_SOCK; } else { - context->flags &= ~NET_CONTEXT_CLOSING_SOCK; + context->flags &= (uint16_t)~NET_CONTEXT_CLOSING_SOCK; } } +/** @cond INTERNAL_HIDDEN */ + #define NET_CONTEXT_STATE_SHIFT 1 #define NET_CONTEXT_STATE_MASK 0x03 +/** @endcond */ + /** * @brief Get state for this network context. * @@ -547,7 +562,7 @@ static inline void net_context_set_family(struct net_context *context, if (family == AF_UNSPEC || family == AF_INET || family == AF_INET6 || family == AF_PACKET || family == AF_CAN) { /* Family is in BIT(4), BIT(5) and BIT(6) */ - flag = family << 3; + flag = (uint8_t)(family << 3); } context->flags |= flag; @@ -589,7 +604,7 @@ static inline void net_context_set_type(struct net_context *context, if (type == SOCK_DGRAM || type == SOCK_STREAM || type == SOCK_RAW) { /* Type is in BIT(6) and BIT(7)*/ - flag = type << 6; + flag = (uint16_t)(type << 6); } context->flags |= flag; @@ -707,7 +722,7 @@ static inline void net_context_set_iface(struct net_context *context, { NET_ASSERT(iface); - context->iface = net_if_get_by_iface(iface); + context->iface = (uint8_t)net_if_get_by_iface(iface); } /** @@ -1251,23 +1266,25 @@ int net_context_recv(struct net_context *context, int net_context_update_recv_wnd(struct net_context *context, int32_t delta); +/** @brief Network context options. These map to BSD socket option values. */ enum net_context_option { - NET_OPT_PRIORITY = 1, - NET_OPT_TXTIME = 2, - NET_OPT_SOCKS5 = 3, - NET_OPT_RCVTIMEO = 4, - NET_OPT_SNDTIMEO = 5, - NET_OPT_RCVBUF = 6, - NET_OPT_SNDBUF = 7, - NET_OPT_DSCP_ECN = 8, - NET_OPT_REUSEADDR = 9, - NET_OPT_REUSEPORT = 10, - NET_OPT_IPV6_V6ONLY = 11, - NET_OPT_RECV_PKTINFO = 12, - NET_OPT_MCAST_TTL = 13, - NET_OPT_MCAST_HOP_LIMIT = 14, - NET_OPT_UNICAST_HOP_LIMIT = 15, - NET_OPT_TTL = 16, + NET_OPT_PRIORITY = 1, /**< Context priority */ + NET_OPT_TXTIME = 2, /**< TX time */ + NET_OPT_SOCKS5 = 3, /**< SOCKS5 */ + NET_OPT_RCVTIMEO = 4, /**< Receive timeout */ + NET_OPT_SNDTIMEO = 5, /**< Send timeout */ + NET_OPT_RCVBUF = 6, /**< Receive buffer */ + NET_OPT_SNDBUF = 7, /**< Send buffer */ + NET_OPT_DSCP_ECN = 8, /**< DSCP ECN */ + NET_OPT_REUSEADDR = 9, /**< Re-use address */ + NET_OPT_REUSEPORT = 10, /**< Re-use port */ + NET_OPT_IPV6_V6ONLY = 11, /**< Share IPv4 and IPv6 port space */ + NET_OPT_RECV_PKTINFO = 12, /**< Receive packet information */ + NET_OPT_MCAST_TTL = 13, /**< IPv4 multicast TTL */ + NET_OPT_MCAST_HOP_LIMIT = 14, /**< IPv6 multicast hop limit */ + NET_OPT_UNICAST_HOP_LIMIT = 15, /**< IPv6 unicast hop limit */ + NET_OPT_TTL = 16, /**< IPv4 unicast TTL */ + NET_OPT_ADDR_PREFERENCES = 17, /**< IPv6 address preference */ }; /** diff --git a/include/zephyr/net/net_event.h b/include/zephyr/net/net_event.h index 881bb8dc276..b149934f8bc 100644 --- a/include/zephyr/net/net_event.h +++ b/include/zephyr/net/net_event.h @@ -41,18 +41,6 @@ enum net_event_if_cmd { NET_EVENT_IF_CMD_ADMIN_UP, }; -#define NET_EVENT_IF_DOWN \ - (_NET_EVENT_IF_BASE | NET_EVENT_IF_CMD_DOWN) - -#define NET_EVENT_IF_UP \ - (_NET_EVENT_IF_BASE | NET_EVENT_IF_CMD_UP) - -#define NET_EVENT_IF_ADMIN_DOWN \ - (_NET_EVENT_IF_BASE | NET_EVENT_IF_CMD_ADMIN_DOWN) - -#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 @@ -81,162 +69,246 @@ enum net_event_ipv6_cmd { NET_EVENT_IPV6_CMD_DHCP_START, NET_EVENT_IPV6_CMD_DHCP_BOUND, NET_EVENT_IPV6_CMD_DHCP_STOP, + NET_EVENT_IPV6_CMD_ADDR_DEPRECATED, + NET_EVENT_IPV6_CMD_PE_ENABLED, + NET_EVENT_IPV6_CMD_PE_DISABLED, + NET_EVENT_IPV6_CMD_PE_FILTER_ADD, + NET_EVENT_IPV6_CMD_PE_FILTER_DEL, +}; + +/* IPv4 Events*/ +#define _NET_IPV4_LAYER NET_MGMT_LAYER_L3 +#define _NET_IPV4_CORE_CODE 0x004 +#define _NET_EVENT_IPV4_BASE (NET_MGMT_EVENT_BIT | \ + NET_MGMT_IFACE_BIT | \ + NET_MGMT_LAYER(_NET_IPV4_LAYER) | \ + NET_MGMT_LAYER_CODE(_NET_IPV4_CORE_CODE)) + +enum net_event_ipv4_cmd { + NET_EVENT_IPV4_CMD_ADDR_ADD = 1, + NET_EVENT_IPV4_CMD_ADDR_DEL, + NET_EVENT_IPV4_CMD_MADDR_ADD, + NET_EVENT_IPV4_CMD_MADDR_DEL, + NET_EVENT_IPV4_CMD_ROUTER_ADD, + NET_EVENT_IPV4_CMD_ROUTER_DEL, + NET_EVENT_IPV4_CMD_DHCP_START, + NET_EVENT_IPV4_CMD_DHCP_BOUND, + NET_EVENT_IPV4_CMD_DHCP_STOP, + NET_EVENT_IPV4_CMD_MCAST_JOIN, + NET_EVENT_IPV4_CMD_MCAST_LEAVE, }; +/* L4 network events */ +#define _NET_L4_LAYER NET_MGMT_LAYER_L4 +#define _NET_L4_CORE_CODE 0x114 +#define _NET_EVENT_L4_BASE (NET_MGMT_EVENT_BIT | \ + NET_MGMT_IFACE_BIT | \ + NET_MGMT_LAYER(_NET_L4_LAYER) | \ + NET_MGMT_LAYER_CODE(_NET_L4_CORE_CODE)) + +enum net_event_l4_cmd { + NET_EVENT_L4_CMD_CONNECTED = 1, + 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, + NET_EVENT_L4_CMD_CAPTURE_STARTED, + NET_EVENT_L4_CMD_CAPTURE_STOPPED, +}; + +/** @endcond */ + +/** Event emitted when the network interface goes down. */ +#define NET_EVENT_IF_DOWN \ + (_NET_EVENT_IF_BASE | NET_EVENT_IF_CMD_DOWN) + +/** Event emitted when the network interface goes up. */ +#define NET_EVENT_IF_UP \ + (_NET_EVENT_IF_BASE | NET_EVENT_IF_CMD_UP) + +/** Event emitted when the network interface is taken down manually. */ +#define NET_EVENT_IF_ADMIN_DOWN \ + (_NET_EVENT_IF_BASE | NET_EVENT_IF_CMD_ADMIN_DOWN) + +/** Event emitted when the network interface goes up manually. */ +#define NET_EVENT_IF_ADMIN_UP \ + (_NET_EVENT_IF_BASE | NET_EVENT_IF_CMD_ADMIN_UP) + +/** Event emitted when an IPv6 address is added to the system. */ #define NET_EVENT_IPV6_ADDR_ADD \ (_NET_EVENT_IPV6_BASE | NET_EVENT_IPV6_CMD_ADDR_ADD) +/** Event emitted when an IPv6 address is removed from the system. */ #define NET_EVENT_IPV6_ADDR_DEL \ (_NET_EVENT_IPV6_BASE | NET_EVENT_IPV6_CMD_ADDR_DEL) +/** Event emitted when an IPv6 multicast address is added to the system. */ #define NET_EVENT_IPV6_MADDR_ADD \ (_NET_EVENT_IPV6_BASE | NET_EVENT_IPV6_CMD_MADDR_ADD) +/** Event emitted when an IPv6 multicast address is removed from the system. */ #define NET_EVENT_IPV6_MADDR_DEL \ (_NET_EVENT_IPV6_BASE | NET_EVENT_IPV6_CMD_MADDR_DEL) +/** Event emitted when an IPv6 prefix is added to the system. */ #define NET_EVENT_IPV6_PREFIX_ADD \ (_NET_EVENT_IPV6_BASE | NET_EVENT_IPV6_CMD_PREFIX_ADD) +/** Event emitted when an IPv6 prefix is removed from the system. */ #define NET_EVENT_IPV6_PREFIX_DEL \ (_NET_EVENT_IPV6_BASE | NET_EVENT_IPV6_CMD_PREFIX_DEL) +/** Event emitted when an IPv6 multicast group is joined. */ #define NET_EVENT_IPV6_MCAST_JOIN \ (_NET_EVENT_IPV6_BASE | NET_EVENT_IPV6_CMD_MCAST_JOIN) +/** Event emitted when an IPv6 multicast group is left. */ #define NET_EVENT_IPV6_MCAST_LEAVE \ (_NET_EVENT_IPV6_BASE | NET_EVENT_IPV6_CMD_MCAST_LEAVE) +/** Event emitted when an IPv6 router is added to the system. */ #define NET_EVENT_IPV6_ROUTER_ADD \ (_NET_EVENT_IPV6_BASE | NET_EVENT_IPV6_CMD_ROUTER_ADD) +/** Event emitted when an IPv6 router is removed from the system. */ #define NET_EVENT_IPV6_ROUTER_DEL \ (_NET_EVENT_IPV6_BASE | NET_EVENT_IPV6_CMD_ROUTER_DEL) +/** Event emitted when an IPv6 route is added to the system. */ #define NET_EVENT_IPV6_ROUTE_ADD \ (_NET_EVENT_IPV6_BASE | NET_EVENT_IPV6_CMD_ROUTE_ADD) +/** Event emitted when an IPv6 route is removed from the system. */ #define NET_EVENT_IPV6_ROUTE_DEL \ (_NET_EVENT_IPV6_BASE | NET_EVENT_IPV6_CMD_ROUTE_DEL) +/** Event emitted when an IPv6 duplicate address detection succeeds. */ #define NET_EVENT_IPV6_DAD_SUCCEED \ (_NET_EVENT_IPV6_BASE | NET_EVENT_IPV6_CMD_DAD_SUCCEED) +/** Event emitted when an IPv6 duplicate address detection fails. */ #define NET_EVENT_IPV6_DAD_FAILED \ (_NET_EVENT_IPV6_BASE | NET_EVENT_IPV6_CMD_DAD_FAILED) +/** Event emitted when an IPv6 neighbor is added to the system. */ #define NET_EVENT_IPV6_NBR_ADD \ (_NET_EVENT_IPV6_BASE | NET_EVENT_IPV6_CMD_NBR_ADD) +/** Event emitted when an IPv6 neighbor is removed from the system. */ #define NET_EVENT_IPV6_NBR_DEL \ (_NET_EVENT_IPV6_BASE | NET_EVENT_IPV6_CMD_NBR_DEL) +/** Event emitted when an IPv6 DHCP client starts. */ #define NET_EVENT_IPV6_DHCP_START \ (_NET_EVENT_IPV6_BASE | NET_EVENT_IPV6_CMD_DHCP_START) +/** Event emitted when an IPv6 DHCP client address is bound. */ #define NET_EVENT_IPV6_DHCP_BOUND \ (_NET_EVENT_IPV6_BASE | NET_EVENT_IPV6_CMD_DHCP_BOUND) +/** Event emitted when an IPv6 DHCP client is stopped. */ #define NET_EVENT_IPV6_DHCP_STOP \ (_NET_EVENT_IPV6_BASE | NET_EVENT_IPV6_CMD_DHCP_STOP) -/* IPv4 Events*/ -#define _NET_IPV4_LAYER NET_MGMT_LAYER_L3 -#define _NET_IPV4_CORE_CODE 0x004 -#define _NET_EVENT_IPV4_BASE (NET_MGMT_EVENT_BIT | \ - NET_MGMT_IFACE_BIT | \ - NET_MGMT_LAYER(_NET_IPV4_LAYER) | \ - NET_MGMT_LAYER_CODE(_NET_IPV4_CORE_CODE)) +/** IPv6 address is deprecated. */ +#define NET_EVENT_IPV6_ADDR_DEPRECATED \ + (_NET_EVENT_IPV6_BASE | NET_EVENT_IPV6_CMD_ADDR_DEPRECATED) -enum net_event_ipv4_cmd { - NET_EVENT_IPV4_CMD_ADDR_ADD = 1, - NET_EVENT_IPV4_CMD_ADDR_DEL, - NET_EVENT_IPV4_CMD_MADDR_ADD, - NET_EVENT_IPV4_CMD_MADDR_DEL, - NET_EVENT_IPV4_CMD_ROUTER_ADD, - NET_EVENT_IPV4_CMD_ROUTER_DEL, - NET_EVENT_IPV4_CMD_DHCP_START, - NET_EVENT_IPV4_CMD_DHCP_BOUND, - NET_EVENT_IPV4_CMD_DHCP_STOP, - NET_EVENT_IPV4_CMD_MCAST_JOIN, - NET_EVENT_IPV4_CMD_MCAST_LEAVE, -}; +/** IPv6 Privacy extension is enabled. */ +#define NET_EVENT_IPV6_PE_ENABLED \ + (_NET_EVENT_IPV6_BASE | NET_EVENT_IPV6_CMD_PE_ENABLED) + +/** IPv6 Privacy extension is disabled. */ +#define NET_EVENT_IPV6_PE_DISABLED \ + (_NET_EVENT_IPV6_BASE | NET_EVENT_IPV6_CMD_PE_DISABLED) + +/** IPv6 Privacy extension filter is added. */ +#define NET_EVENT_IPV6_PE_FILTER_ADD \ + (_NET_EVENT_IPV6_BASE | NET_EVENT_IPV6_CMD_PE_FILTER_ADD) +/** IPv6 Privacy extension filter is removed. */ +#define NET_EVENT_IPV6_PE_FILTER_DEL \ + (_NET_EVENT_IPV6_BASE | NET_EVENT_IPV6_CMD_PE_FILTER_DEL) + +/** Event emitted when an IPv4 address is added to the system. */ #define NET_EVENT_IPV4_ADDR_ADD \ (_NET_EVENT_IPV4_BASE | NET_EVENT_IPV4_CMD_ADDR_ADD) +/** Event emitted when an IPv4 address is removed from the system. */ #define NET_EVENT_IPV4_ADDR_DEL \ (_NET_EVENT_IPV4_BASE | NET_EVENT_IPV4_CMD_ADDR_DEL) +/** Event emitted when an IPv4 multicast address is added to the system. */ #define NET_EVENT_IPV4_MADDR_ADD \ (_NET_EVENT_IPV4_BASE | NET_EVENT_IPV4_CMD_MADDR_ADD) +/** Event emitted when an IPv4 multicast address is removed from the system. */ #define NET_EVENT_IPV4_MADDR_DEL \ (_NET_EVENT_IPV4_BASE | NET_EVENT_IPV4_CMD_MADDR_DEL) +/** Event emitted when an IPv4 router is added to the system. */ #define NET_EVENT_IPV4_ROUTER_ADD \ (_NET_EVENT_IPV4_BASE | NET_EVENT_IPV4_CMD_ROUTER_ADD) +/** Event emitted when an IPv4 router is removed from the system. */ #define NET_EVENT_IPV4_ROUTER_DEL \ (_NET_EVENT_IPV4_BASE | NET_EVENT_IPV4_CMD_ROUTER_DEL) +/** Event emitted when an IPv4 DHCP client is started. */ #define NET_EVENT_IPV4_DHCP_START \ (_NET_EVENT_IPV4_BASE | NET_EVENT_IPV4_CMD_DHCP_START) +/** Event emitted when an IPv4 DHCP client address is bound. */ #define NET_EVENT_IPV4_DHCP_BOUND \ (_NET_EVENT_IPV4_BASE | NET_EVENT_IPV4_CMD_DHCP_BOUND) +/** Event emitted when an IPv4 DHCP client is stopped. */ #define NET_EVENT_IPV4_DHCP_STOP \ (_NET_EVENT_IPV4_BASE | NET_EVENT_IPV4_CMD_DHCP_STOP) +/** Event emitted when an IPv4 multicast group is joined. */ #define NET_EVENT_IPV4_MCAST_JOIN \ (_NET_EVENT_IPV4_BASE | NET_EVENT_IPV4_CMD_MCAST_JOIN) +/** Event emitted when an IPv4 multicast group is left. */ #define NET_EVENT_IPV4_MCAST_LEAVE \ (_NET_EVENT_IPV4_BASE | NET_EVENT_IPV4_CMD_MCAST_LEAVE) - -/* L4 network events */ -#define _NET_L4_LAYER NET_MGMT_LAYER_L4 -#define _NET_L4_CORE_CODE 0x114 -#define _NET_EVENT_L4_BASE (NET_MGMT_EVENT_BIT | \ - NET_MGMT_IFACE_BIT | \ - NET_MGMT_LAYER(_NET_L4_LAYER) | \ - NET_MGMT_LAYER_CODE(_NET_L4_CORE_CODE)) - -enum net_event_l4_cmd { - NET_EVENT_L4_CMD_CONNECTED = 1, - 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, - NET_EVENT_L4_CMD_CAPTURE_STARTED, - NET_EVENT_L4_CMD_CAPTURE_STOPPED, -}; - -#define NET_EVENT_L4_CONNECTED \ +/** Event emitted when the system is considered to be connected. + * The connected in this context means that the network interface is up, + * and the interface has either IPv4 or IPv6 address assigned to it. + */ +#define NET_EVENT_L4_CONNECTED \ (_NET_EVENT_L4_BASE | NET_EVENT_L4_CMD_CONNECTED) +/** Event emitted when the system is no longer connected. + * Typically this means that network connectivity is lost either by + * the network interface is going down, or the interface has no longer + * an IP address etc. + */ #define NET_EVENT_L4_DISCONNECTED \ (_NET_EVENT_L4_BASE | NET_EVENT_L4_CMD_DISCONNECTED) +/** Event emitted when a DNS server is added to the system. */ #define NET_EVENT_DNS_SERVER_ADD \ (_NET_EVENT_L4_BASE | NET_EVENT_L4_CMD_DNS_SERVER_ADD) +/** Event emitted when a DNS server is removed from the system. */ #define NET_EVENT_DNS_SERVER_DEL \ (_NET_EVENT_L4_BASE | NET_EVENT_L4_CMD_DNS_SERVER_DEL) +/** Event emitted when the system hostname is changed. */ #define NET_EVENT_HOSTNAME_CHANGED \ (_NET_EVENT_L4_BASE | NET_EVENT_L4_CMD_HOSTNAME_CHANGED) +/** Network packet capture is started. */ #define NET_EVENT_CAPTURE_STARTED \ (_NET_EVENT_L4_BASE | NET_EVENT_L4_CMD_CAPTURE_STARTED) +/** Network packet capture is stopped. */ #define NET_EVENT_CAPTURE_STOPPED \ (_NET_EVENT_L4_BASE | NET_EVENT_L4_CMD_CAPTURE_STOPPED) -/** @endcond */ - /** * @brief Network Management event information structure * Used to pass information on network events like @@ -248,6 +320,7 @@ enum net_event_l4_cmd { * information. */ struct net_event_ipv6_addr { + /** IPv6 address related to this event */ struct in6_addr addr; }; @@ -261,8 +334,10 @@ struct net_event_ipv6_addr { * @note: idx will be '-1' in case of NET_EVENT_IPV6_NBR_DEL event. */ struct net_event_ipv6_nbr { + /** Neighbor IPv6 address */ struct in6_addr addr; - int idx; /* NBR index*/ + /** Neighbor index in cache */ + int idx; }; /** @@ -274,8 +349,11 @@ struct net_event_ipv6_nbr { * information. */ struct net_event_ipv6_route { + /** IPv6 address of the next hop */ struct in6_addr nexthop; - struct in6_addr addr; /* addr/prefix */ + /** IPv6 address or prefix of the route */ + struct in6_addr addr; + /** IPv6 prefix length */ uint8_t prefix_len; }; @@ -288,8 +366,11 @@ struct net_event_ipv6_route { * information. */ struct net_event_ipv6_prefix { - struct in6_addr addr; /* prefix */ + /** IPv6 prefix */ + struct in6_addr addr; + /** IPv6 prefix length */ uint8_t len; + /** IPv6 prefix lifetime in seconds */ uint32_t lifetime; }; @@ -300,9 +381,27 @@ struct net_event_ipv6_prefix { * information. */ struct net_event_l4_hostname { + /** New hostname */ char hostname[NET_HOSTNAME_SIZE]; }; +/** + * @brief Network Management event information structure + * Used to pass information on network events like + * NET_EVENT_IPV6_PE_FILTER_ADD and + * NET_EVENT_IPV6_PE_FILTER_DEL + * when CONFIG_NET_MGMT_EVENT_INFO is enabled and event generator pass the + * information. + * + * This is only available if CONFIG_NET_IPV6_PE_FILTER_PREFIX_COUNT is >0. + */ +struct net_event_ipv6_pe_filter { + /** IPv6 address of privacy extension filter */ + struct in6_addr prefix; + /** IPv6 filter deny or allow list */ + bool is_deny_list; +}; + #ifdef __cplusplus } #endif diff --git a/include/zephyr/net/net_if.h b/include/zephyr/net/net_if.h index 03a936626d1..b1a2ca8925a 100644 --- a/include/zephyr/net/net_if.h +++ b/include/zephyr/net/net_if.h @@ -53,6 +53,11 @@ struct net_if_addr { /** IP address */ struct net_addr address; + /** Reference counter. This is used to prevent address removal if there + * are sockets that have bound the local endpoint to this address. + */ + atomic_t atomic_ref; + #if defined(CONFIG_NET_NATIVE_IPV6) struct net_timeout lifetime; #endif @@ -68,12 +73,31 @@ struct net_if_addr { /** What is the current state of the address */ enum net_addr_state addr_state; -#if defined(CONFIG_NET_IPV6_DAD) && defined(CONFIG_NET_NATIVE_IPV6) +#if defined(CONFIG_NET_NATIVE_IPV6) +#if defined(CONFIG_NET_IPV6_PE) + /** Address creation time. This is used to determine if the maximum + * lifetime for this address is reached or not. The value is in seconds. + */ + uint32_t addr_create_time; + + /** Preferred lifetime for the address in seconds. + */ + uint32_t addr_preferred_lifetime; + + /** Address timeout value. This is only used if DAD needs to be redone + * for this address because of earlier DAD failure. This value is in + * seconds. + */ + int32_t addr_timeout; +#endif + +#if defined(CONFIG_NET_IPV6_DAD) /** How many times we have done DAD */ uint8_t dad_count; /* What interface the DAD is running */ uint8_t ifindex; #endif +#endif /* CONFIG_NET_NATIVE_IPV6 */ /** Is the IP address valid forever */ uint8_t is_infinite : 1; @@ -84,7 +108,12 @@ struct net_if_addr { /** Is this IP address usage limited to the subnet (mesh) or not */ uint8_t is_mesh_local : 1; - uint8_t _unused : 5; + /** Is this IP address temporary and generated for example by + * IPv6 privacy extension (RFC 8981) + */ + uint8_t is_temporary : 1; + + uint8_t _unused : 4; }; /** @@ -234,15 +263,15 @@ enum net_if_flag { /** @endcond */ }; -/** Network interface operational status (RFC 2863). */ +/** @brief Network interface operational status (RFC 2863). */ enum net_if_oper_state { - NET_IF_OPER_UNKNOWN, - NET_IF_OPER_NOTPRESENT, - NET_IF_OPER_DOWN, - NET_IF_OPER_LOWERLAYERDOWN, - NET_IF_OPER_TESTING, - NET_IF_OPER_DORMANT, - NET_IF_OPER_UP, + NET_IF_OPER_UNKNOWN, /**< Initial (unknown) value */ + NET_IF_OPER_NOTPRESENT, /**< Hardware missing */ + NET_IF_OPER_DOWN, /**< Interface is down */ + NET_IF_OPER_LOWERLAYERDOWN, /**< Lower layer interface is down */ + NET_IF_OPER_TESTING, /**< Training mode */ + NET_IF_OPER_DORMANT, /**< Waiting external action */ + NET_IF_OPER_UP, /**< Interface is up */ } __packed; #if defined(CONFIG_NET_OFFLOAD) @@ -261,6 +290,7 @@ struct net_offload; #endif /* @endcond */ +/** IPv6 configuration */ struct net_if_ipv6 { /** Unicast IP addresses */ struct net_if_addr unicast[NET_IF_MAX_IPV6_ADDR]; @@ -279,6 +309,15 @@ struct net_if_ipv6 { /** Retransmit timer (RFC 4861, page 52) */ uint32_t retrans_timer; + +#if defined(CONFIG_NET_IPV6_PE) + /** Privacy extension DESYNC_FACTOR value from RFC 8981 ch 3.4. + * "DESYNC_FACTOR is a random value within the range 0 - MAX_DESYNC_FACTOR. + * It is computed every time a temporary address is created. + */ + uint32_t desync_factor; +#endif /* CONFIG_NET_IPV6_PE */ + #if defined(CONFIG_NET_IPV6_ND) && defined(CONFIG_NET_NATIVE_IPV6) /** Router solicitation timer node */ sys_snode_t rs_node; @@ -298,6 +337,7 @@ struct net_if_ipv6 { }; #if defined(CONFIG_NET_DHCPV6) && defined(CONFIG_NET_NATIVE_IPV6) +/** DHCPv6 configuration */ struct net_if_dhcpv6 { /** Used for timer list. */ sys_snode_t node; @@ -382,6 +422,7 @@ struct net_if_addr_ipv4 { struct in_addr netmask; }; +/** IPv4 configuration */ struct net_if_ipv4 { /** Unicast IP addresses */ struct net_if_addr_ipv4 unicast[NET_IF_MAX_IPV4_ADDR]; @@ -595,7 +636,7 @@ struct net_if_dev { /** Interface's private L2 data pointer */ void *l2_data; - /* For internal use */ + /** For internal use */ ATOMIC_DEFINE(flags, NET_IF_NUM_FLAGS); /** The hardware link address */ @@ -651,10 +692,29 @@ struct net_if { int tx_pending; #endif + /** Mutex protecting this network interface instance */ struct k_mutex lock; + + /** Mutex used when sending data */ struct k_mutex tx_lock; + + /** Network interface specific flags */ + /** Enable IPv6 privacy extension (RFC 8981), this is enabled + * by default if PE support is enabled in configuration. + */ + uint8_t pe_enabled : 1; + + /** If PE is enabled, then this tells whether public addresses + * are preferred over temporary ones for this interface. + */ + uint8_t pe_prefer_public : 1; + + /** Unused bit flags (ignore) */ + uint8_t _unused : 6; }; +/** @cond INTERNAL_HIDDEN */ + static inline void net_if_lock(struct net_if *iface) { NET_ASSERT(iface); @@ -694,6 +754,8 @@ static inline void net_if_tx_unlock(struct net_if *iface) k_mutex_unlock(&iface->tx_lock); } +/** @endcond */ + /** * @brief Set a value in network interface flags * @@ -1110,6 +1172,31 @@ static inline int net_if_set_link_addr_unlocked(struct net_if *iface, int net_if_set_link_addr_locked(struct net_if *iface, uint8_t *addr, uint8_t len, enum net_link_type type); + +#if CONFIG_NET_IF_LOG_LEVEL >= LOG_LEVEL_DBG +extern int net_if_addr_unref_debug(struct net_if *iface, + sa_family_t family, + const void *addr, + const char *caller, int line); +#define net_if_addr_unref(iface, family, addr) \ + net_if_addr_unref_debug(iface, family, addr, __func__, __LINE__) + +extern struct net_if_addr *net_if_addr_ref_debug(struct net_if *iface, + sa_family_t family, + const void *addr, + const char *caller, + int line); +#define net_if_addr_ref(iface, family, addr) \ + net_if_addr_ref_debug(iface, family, addr, __func__, __LINE__) +#else +extern int net_if_addr_unref(struct net_if *iface, + sa_family_t family, + const void *addr); +extern struct net_if_addr *net_if_addr_ref(struct net_if *iface, + sa_family_t family, + const void *addr); +#endif /* CONFIG_NET_IF_LOG_LEVEL */ + /** @endcond */ /** @@ -1565,7 +1652,7 @@ void net_if_ipv6_maddr_leave(struct net_if *iface, * @return Pointer to prefix, NULL if not found. */ struct net_if_ipv6_prefix *net_if_ipv6_prefix_get(struct net_if *iface, - struct in6_addr *addr); + const struct in6_addr *addr); /** * @brief Check if this IPv6 prefix belongs to this interface @@ -1744,6 +1831,8 @@ uint8_t net_if_ipv6_get_hop_limit(struct net_if *iface); */ void net_if_ipv6_set_hop_limit(struct net_if *iface, uint8_t hop_limit); +/** @cond INTERNAL_HIDDEN */ + /* 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. @@ -1755,6 +1844,8 @@ static inline void net_ipv6_set_hop_limit(struct net_if *iface, net_if_ipv6_set_hop_limit(iface, hop_limit); } +/** @endcond */ + /** * @brief Get IPv6 multicast hop limit specified for a given interface. This is the * default value but can be overridden by the user. @@ -1919,6 +2010,35 @@ static inline const struct in6_addr *net_if_ipv6_select_src_addr( } #endif +/** + * @brief Get a IPv6 source address that should be used when sending + * network data to destination. Use a hint set to the socket to select + * the proper address. + * + * @param iface Interface that was used when packet was received. + * If the interface is not known, then NULL can be given. + * @param dst IPv6 destination address + * @param flags Hint from the related socket. See RFC 5014 for value details. + * + * @return Pointer to IPv6 address to use, NULL if no IPv6 address + * could be found. + */ +#if defined(CONFIG_NET_NATIVE_IPV6) +const struct in6_addr *net_if_ipv6_select_src_addr_hint(struct net_if *iface, + const struct in6_addr *dst, + int flags); +#else +static inline const struct in6_addr *net_if_ipv6_select_src_addr_hint( + struct net_if *iface, const struct in6_addr *dst, int flags) +{ + ARG_UNUSED(iface); + ARG_UNUSED(dst); + ARG_UNUSED(flags); + + return NULL; +} +#endif + /** * @brief Get a network interface that should be used when sending * IPv6 network data to destination. diff --git a/include/zephyr/net/net_ip.h b/include/zephyr/net/net_ip.h index 64ce6000cac..413d3efb094 100644 --- a/include/zephyr/net/net_ip.h +++ b/include/zephyr/net/net_ip.h @@ -138,26 +138,26 @@ enum net_sock_type { /** IPv6 address struct */ struct in6_addr { union { - uint8_t s6_addr[16]; - uint16_t s6_addr16[8]; /* In big endian */ - uint32_t s6_addr32[4]; /* In big endian */ + uint8_t s6_addr[16]; /**< IPv6 address buffer */ + uint16_t s6_addr16[8]; /**< In big endian */ + uint32_t s6_addr32[4]; /**< In big endian */ }; }; -/* Binary size of the IPv6 address */ +/** Binary size of the IPv6 address */ #define NET_IPV6_ADDR_SIZE 16 /** IPv4 address struct */ struct in_addr { union { - uint8_t s4_addr[4]; - uint16_t s4_addr16[2]; /* In big endian */ - uint32_t s4_addr32[1]; /* In big endian */ - uint32_t s_addr; /* In big endian, for POSIX compatibility. */ + uint8_t s4_addr[4]; /**< IPv4 address buffer */ + uint16_t s4_addr16[2]; /**< In big endian */ + uint32_t s4_addr32[1]; /**< In big endian */ + uint32_t s_addr; /**< In big endian, for POSIX compatibility. */ }; }; -/* Binary size of the IPv4 address */ +/** Binary size of the IPv4 address */ #define NET_IPV4_ADDR_SIZE 4 /** Socket address family type */ @@ -176,51 +176,56 @@ typedef size_t socklen_t; /** Socket address struct for IPv6. */ struct sockaddr_in6 { - sa_family_t sin6_family; /* AF_INET6 */ - uint16_t sin6_port; /* Port number */ - struct in6_addr sin6_addr; /* IPv6 address */ - uint8_t sin6_scope_id; /* interfaces for a scope */ -}; - -struct sockaddr_in6_ptr { - sa_family_t sin6_family; /* AF_INET6 */ - uint16_t sin6_port; /* Port number */ - struct in6_addr *sin6_addr; /* IPv6 address */ - uint8_t sin6_scope_id; /* interfaces for a scope */ + sa_family_t sin6_family; /**< AF_INET6 */ + uint16_t sin6_port; /**< Port number */ + struct in6_addr sin6_addr; /**< IPv6 address */ + uint8_t sin6_scope_id; /**< Interfaces for a scope */ }; /** Socket address struct for IPv4. */ struct sockaddr_in { - sa_family_t sin_family; /* AF_INET */ - uint16_t sin_port; /* Port number */ - struct in_addr sin_addr; /* IPv4 address */ -}; - -struct sockaddr_in_ptr { - sa_family_t sin_family; /* AF_INET */ - uint16_t sin_port; /* Port number */ - struct in_addr *sin_addr; /* IPv4 address */ + sa_family_t sin_family; /**< AF_INET */ + uint16_t sin_port; /**< Port number */ + struct in_addr sin_addr; /**< IPv4 address */ }; /** Socket address struct for packet socket. */ struct sockaddr_ll { - sa_family_t sll_family; /* Always AF_PACKET */ - uint16_t sll_protocol; /* Physical-layer protocol */ - int sll_ifindex; /* Interface number */ - uint16_t sll_hatype; /* ARP hardware type */ - uint8_t sll_pkttype; /* Packet type */ - uint8_t sll_halen; /* Length of address */ - uint8_t sll_addr[8]; /* Physical-layer address, big endian */ + sa_family_t sll_family; /**< Always AF_PACKET */ + uint16_t sll_protocol; /**< Physical-layer protocol */ + int sll_ifindex; /**< Interface number */ + uint16_t sll_hatype; /**< ARP hardware type */ + uint8_t sll_pkttype; /**< Packet type */ + uint8_t sll_halen; /**< Length of address */ + uint8_t sll_addr[8]; /**< Physical-layer address, big endian */ +}; + +/** @cond INTERNAL_HIDDEN */ + +/** Socket address struct for IPv6 where address is a pointer */ +struct sockaddr_in6_ptr { + sa_family_t sin6_family; /**< AF_INET6 */ + uint16_t sin6_port; /**< Port number */ + struct in6_addr *sin6_addr; /**< IPv6 address */ + uint8_t sin6_scope_id; /**< interfaces for a scope */ }; +/** Socket address struct for IPv4 where address is a pointer */ +struct sockaddr_in_ptr { + sa_family_t sin_family; /**< AF_INET */ + uint16_t sin_port; /**< Port number */ + struct in_addr *sin_addr; /**< IPv4 address */ +}; + +/** Socket address struct for packet socket where address is a pointer */ struct sockaddr_ll_ptr { - sa_family_t sll_family; /* Always AF_PACKET */ - uint16_t sll_protocol; /* Physical-layer protocol */ - int sll_ifindex; /* Interface number */ - uint16_t sll_hatype; /* ARP hardware type */ - uint8_t sll_pkttype; /* Packet type */ - uint8_t sll_halen; /* Length of address */ - uint8_t *sll_addr; /* Physical-layer address, big endian */ + sa_family_t sll_family; /**< Always AF_PACKET */ + uint16_t sll_protocol; /**< Physical-layer protocol */ + int sll_ifindex; /**< Interface number */ + uint16_t sll_hatype; /**< ARP hardware type */ + uint8_t sll_pkttype; /**< Packet type */ + uint8_t sll_halen; /**< Length of address */ + uint8_t *sll_addr; /**< Physical-layer address, big endian */ }; struct sockaddr_can_ptr { @@ -228,31 +233,37 @@ struct sockaddr_can_ptr { int can_ifindex; }; +/** @endcond */ + #if !defined(HAVE_IOVEC) +/** IO vector array element */ struct iovec { - void *iov_base; - size_t iov_len; + void *iov_base; /**< Pointer to data */ + size_t iov_len; /**< Length of the data */ }; #endif +/** Message struct */ struct msghdr { - void *msg_name; /* optional socket address, big endian */ - socklen_t msg_namelen; /* size of socket address */ - struct iovec *msg_iov; /* scatter/gather array */ - size_t msg_iovlen; /* number of elements in msg_iov */ - void *msg_control; /* ancillary data */ - size_t msg_controllen; /* ancillary data buffer len */ - int msg_flags; /* flags on received message */ + void *msg_name; /**< Optional socket address, big endian */ + socklen_t msg_namelen; /**< Size of socket address */ + struct iovec *msg_iov; /**< Scatter/gather array */ + size_t msg_iovlen; /**< Number of elements in msg_iov */ + void *msg_control; /**< Ancillary data */ + size_t msg_controllen; /**< Ancillary data buffer len */ + int msg_flags; /**< Flags on received message */ }; +/** Control message ancillary data */ struct cmsghdr { - socklen_t cmsg_len; /* Number of bytes, including header */ - int cmsg_level; /* Originating protocol */ - int cmsg_type; /* Protocol-specific type */ - /* Flexible array member to force alignment of cmsghdr */ - z_max_align_t cmsg_data[]; + socklen_t cmsg_len; /**< Number of bytes, including header */ + int cmsg_level; /**< Originating protocol */ + int cmsg_type; /**< Protocol-specific type */ + z_max_align_t cmsg_data[]; /**< Flexible array member to force alignment of cmsghdr */ }; +/** @cond INTERNAL_HIDDEN */ + /* Alignment for headers and data. These are arch specific but define * them here atm if not found alredy. */ @@ -263,13 +274,24 @@ struct cmsghdr { #define ALIGN_D(x) ROUND_UP(x, __alignof__(z_max_align_t)) #endif +/** @endcond */ + #if !defined(CMSG_FIRSTHDR) +/** + * Returns a pointer to the first cmsghdr in the ancillary data buffer + * associated with the passed msghdr. It returns NULL if there isn't + * enough space for a cmsghdr in the buffer. + */ #define CMSG_FIRSTHDR(msghdr) \ ((msghdr)->msg_controllen >= sizeof(struct cmsghdr) ? \ (struct cmsghdr *)((msghdr)->msg_control) : NULL) #endif #if !defined(CMSG_NXTHDR) +/** + * Returns the next valid cmsghdr after the passed cmsghdr. It returns NULL + * when there isn't enough space left in the buffer. + */ #define CMSG_NXTHDR(msghdr, cmsg) \ (((cmsg) == NULL) ? CMSG_FIRSTHDR(msghdr) : \ (((uint8_t *)(cmsg) + ALIGN_H((cmsg)->cmsg_len) + \ @@ -281,14 +303,30 @@ struct cmsghdr { #endif #if !defined(CMSG_DATA) +/** + * Returns a pointer to the data portion of a cmsghdr. The pointer returned + * cannot be assumed to be suitably aligned for accessing arbitrary payload + * data types. Applications should not cast it to a pointer type matching + * the payload, but should instead use memcpy(3) to copy data to or from a + * suitably declared object. + */ #define CMSG_DATA(cmsg) ((uint8_t *)(cmsg) + ALIGN_D(sizeof(struct cmsghdr))) #endif #if !defined(CMSG_SPACE) +/** + * Returns the number of bytes an ancillary element with payload of the passed + * data length occupies. + */ #define CMSG_SPACE(length) (ALIGN_D(sizeof(struct cmsghdr)) + ALIGN_H(length)) #endif #if !defined(CMSG_LEN) +/** + * Returns the value to store in the cmsg_len member of the cmsghdr structure, + * taking into account any necessary alignment. + * It takes the data length as an argument. + */ #define CMSG_LEN(length) (ALIGN_D(sizeof(struct cmsghdr)) + length) #endif @@ -345,8 +383,10 @@ struct cmsghdr { /** Generic sockaddr struct. Must be cast to proper type. */ struct sockaddr { - sa_family_t sa_family; + sa_family_t sa_family; /**< Address family */ +/** @cond INTERNAL_HIDDEN */ char data[NET_SOCKADDR_MAX_SIZE - sizeof(sa_family_t)]; +/** @endcond */ }; /** @cond INTERNAL_HIDDEN */ @@ -376,15 +416,30 @@ struct net_addr { }; }; +/** A pointer to IPv6 any address (all values zero) */ +extern const struct in6_addr in6addr_any; + +/** A pointer to IPv6 loopback address (::1) */ +extern const struct in6_addr in6addr_loopback; + +/** @endcond */ + +/** IPv6 address initializer */ #define IN6ADDR_ANY_INIT { { { 0, 0, 0, 0, 0, 0, 0, 0, 0, \ 0, 0, 0, 0, 0, 0, 0 } } } + +/** IPv6 loopback address initializer */ #define IN6ADDR_LOOPBACK_INIT { { { 0, 0, 0, 0, 0, 0, 0, \ 0, 0, 0, 0, 0, 0, 0, 0, 1 } } } -extern const struct in6_addr in6addr_any; -extern const struct in6_addr in6addr_loopback; +/** IPv4 any address */ +#define INADDR_ANY 0 -/** @endcond */ +/** IPv4 address initializer */ +#define INADDR_ANY_INIT { { { INADDR_ANY } } } + +/** IPv6 loopback address initializer */ +#define INADDR_LOOPBACK_INIT { { { 127, 0, 0, 1 } } } /** Max length of the IPv4 address as a string. Defined by POSIX. */ #define INET_ADDRSTRLEN 16 @@ -399,13 +454,9 @@ extern const struct in6_addr in6addr_loopback; #define NET_IPV6_ADDR_LEN sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx") #define NET_IPV4_ADDR_LEN sizeof("xxx.xxx.xxx.xxx") -#define INADDR_ANY 0 -#define INADDR_ANY_INIT { { { INADDR_ANY } } } - -#define INADDR_LOOPBACK_INIT { { { 127, 0, 0, 1 } } } - /** @endcond */ +/** @brief IP Maximum Transfer Unit */ enum net_ip_mtu { /** IPv6 MTU length. We must be able to receive this size IPv6 packet * without fragmentation. @@ -422,7 +473,7 @@ enum net_ip_mtu { NET_IPV4_MTU = 576, }; -/** Network packet priority settings described in IEEE 802.1Q Annex I.1 */ +/** @brief Network packet priority settings described in IEEE 802.1Q Annex I.1 */ enum net_priority { NET_PRIORITY_BK = 1, /**< Background (lowest) */ NET_PRIORITY_BE = 0, /**< Best effort (default) */ @@ -434,9 +485,9 @@ enum net_priority { NET_PRIORITY_NC = 7 /**< Network control (highest) */ } __packed; -#define NET_MAX_PRIORITIES 8 /* How many priority values there are */ +#define NET_MAX_PRIORITIES 8 /**< How many priority values there are */ -/** IPv6/IPv4 network connection tuple */ +/** @brief IPv6/IPv4 network connection tuple */ struct net_tuple { struct net_addr *remote_addr; /**< IPv6/IPv4 remote address */ struct net_addr *local_addr; /**< IPv6/IPv4 local address */ @@ -445,7 +496,7 @@ struct net_tuple { enum net_ip_protocol ip_proto; /**< IP protocol */ }; -/** What is the current state of the network address */ +/** @brief What is the current state of the network address */ enum net_addr_state { NET_ADDR_ANY_STATE = -1, /**< Default (invalid) address type */ NET_ADDR_TENTATIVE = 0, /**< Tentative address */ @@ -453,7 +504,7 @@ enum net_addr_state { NET_ADDR_DEPRECATED, /**< Deprecated address */ } __packed; -/** How the network address is assigned to network interface */ +/** @brief How the network address is assigned to network interface */ enum net_addr_type { /** Default value. This is not a valid value. */ NET_ADDR_ANY = 0, @@ -687,7 +738,7 @@ static inline bool net_ipv6_is_prefix(const uint8_t *addr1, } /* Create a mask that has remaining most significant bits set */ - mask = ((0xff << (8 - remain)) ^ 0xff) << remain; + mask = (uint8_t)((0xff << (8 - remain)) ^ 0xff) << remain; return (addr1[bytes] & mask) == (addr2[bytes] & mask); } @@ -1385,15 +1436,6 @@ static inline void net_ipv6_addr_create_iid(struct in6_addr *addr, addr->s6_addr[12] = 0xfe; memcpy(&addr->s6_addr[13], lladdr->addr + 3, 3); -#if defined(CONFIG_NET_L2_BT_ZEP1656) - /* Workaround against older Linux kernel BT IPSP code. - * This will be removed eventually. - */ - if (lladdr->type == NET_LINK_BLUETOOTH) { - addr->s6_addr[8] ^= 0x02; - } -#endif - if (lladdr->type == NET_LINK_ETHERNET) { addr->s6_addr[8] ^= 0x02; } @@ -1439,20 +1481,6 @@ static inline bool net_ipv6_addr_based_on_ll(const struct in6_addr *addr, (addr->s6_addr[8] ^ 0x02) == lladdr->addr[0]) { return true; } - } else if (lladdr->type == NET_LINK_BLUETOOTH) { - if (!memcmp(&addr->s6_addr[9], &lladdr->addr[1], 2) && - !memcmp(&addr->s6_addr[13], &lladdr->addr[3], 3) && - addr->s6_addr[11] == 0xff && - addr->s6_addr[12] == 0xfe -#if defined(CONFIG_NET_L2_BT_ZEP1656) - /* Workaround against older Linux kernel BT IPSP - * code. This will be removed eventually. - */ - && (addr->s6_addr[8] ^ 0x02) == lladdr->addr[0] -#endif - ) { - return true; - } } break; @@ -1732,6 +1760,47 @@ static inline uint8_t net_priority2vlan(enum net_priority priority) */ const char *net_family2str(sa_family_t family); +/** + * @brief Add IPv6 prefix as a privacy extension filter. + * + * @details Note that the filters can either allow or deny listing. + * + * @param addr IPv6 prefix + * @param is_denylist Tells if this filter is for allowing or denying listing. + * + * @return 0 if ok, <0 if error + */ +#if defined(CONFIG_NET_IPV6_PE) +int net_ipv6_pe_add_filter(struct in6_addr *addr, bool is_denylist); +#else +static inline int net_ipv6_pe_add_filter(struct in6_addr *addr, + bool is_denylist) +{ + ARG_UNUSED(addr); + ARG_UNUSED(is_denylist); + + return -ENOTSUP; +} +#endif /* CONFIG_NET_IPV6_PE */ + +/** + * @brief Delete IPv6 prefix from privacy extension filter list. + * + * @param addr IPv6 prefix + * + * @return 0 if ok, <0 if error + */ +#if defined(CONFIG_NET_IPV6_PE) +int net_ipv6_pe_del_filter(struct in6_addr *addr); +#else +static inline int net_ipv6_pe_del_filter(struct in6_addr *addr) +{ + ARG_UNUSED(addr); + + return -ENOTSUP; +} +#endif /* CONFIG_NET_IPV6_PE */ + #ifdef __cplusplus } #endif diff --git a/include/zephyr/net/net_l2.h b/include/zephyr/net/net_l2.h index 7f221f91367..3008572847d 100644 --- a/include/zephyr/net/net_l2.h +++ b/include/zephyr/net/net_l2.h @@ -116,12 +116,6 @@ NET_L2_DECLARE_PUBLIC(PPP_L2); NET_L2_DECLARE_PUBLIC(IEEE802154_L2); #endif /* CONFIG_NET_L2_IEEE802154 */ -#ifdef CONFIG_NET_L2_BT -#define BLUETOOTH_L2 BLUETOOTH -#define BLUETOOTH_L2_CTX_TYPE void* -NET_L2_DECLARE_PUBLIC(BLUETOOTH_L2); -#endif /* CONFIG_NET_L2_BT */ - #ifdef CONFIG_NET_L2_OPENTHREAD #define OPENTHREAD_L2 OPENTHREAD NET_L2_DECLARE_PUBLIC(OPENTHREAD_L2); diff --git a/include/zephyr/net/net_mgmt.h b/include/zephyr/net/net_mgmt.h index f90bc8e1836..55c65b122ec 100644 --- a/include/zephyr/net/net_mgmt.h +++ b/include/zephyr/net/net_mgmt.h @@ -90,14 +90,33 @@ typedef int (*net_mgmt_request_handler_t)(uint32_t mgmt_request, struct net_if *iface, void *data, size_t len); +/** + * @brief Generate a network management event. + * + * @param _mgmt_request Management event identifier + * @param _iface Network interface + * @param _data Any additional data for the event + * @param _len Length of the additional data. + */ #define net_mgmt(_mgmt_request, _iface, _data, _len) \ net_mgmt_##_mgmt_request(_mgmt_request, _iface, _data, _len) +/** + * @brief Declare a request handler function for the given network event. + * + * @param _mgmt_request Management event identifier + */ #define NET_MGMT_DEFINE_REQUEST_HANDLER(_mgmt_request) \ extern int net_mgmt_##_mgmt_request(uint32_t mgmt_request, \ struct net_if *iface, \ void *data, size_t len) +/** + * @brief Create a request handler function for the given network event. + * + * @param _mgmt_request Management event identifier + * @param _func Function for handling this event + */ #define NET_MGMT_REGISTER_REQUEST_HANDLER(_mgmt_request, _func) \ FUNC_ALIAS(_func, net_mgmt_##_mgmt_request, int) @@ -258,7 +277,7 @@ void net_mgmt_del_event_callback(struct net_mgmt_event_callback *cb); * @param mgmt_event The actual network event code to notify * @param iface a valid pointer on a struct net_if if only the event is * based on an iface. NULL otherwise. - * @param info a valid pointer on the information you want to pass along + * @param info A valid pointer on the information you want to pass along * with the event. NULL otherwise. Note the data pointed there is * normalized by the related event. * @param length size of the data pointed by info pointer. @@ -266,10 +285,20 @@ void net_mgmt_del_event_callback(struct net_mgmt_event_callback *cb); * Note: info and length are disabled if CONFIG_NET_MGMT_EVENT_INFO * is not defined. */ -#ifdef CONFIG_NET_MGMT_EVENT +#if defined(CONFIG_NET_MGMT_EVENT) void net_mgmt_event_notify_with_info(uint32_t mgmt_event, struct net_if *iface, const void *info, size_t length); +#else +#define net_mgmt_event_notify_with_info(...) +#endif +/** + * @brief Used by the system to notify an event without any additional information. + * @param mgmt_event The actual network event code to notify + * @param iface A valid pointer on a struct net_if if only the event is + * based on an iface. NULL otherwise. + */ +#if defined(CONFIG_NET_MGMT_EVENT) static inline void net_mgmt_event_notify(uint32_t mgmt_event, struct net_if *iface) { @@ -277,7 +306,6 @@ static inline void net_mgmt_event_notify(uint32_t mgmt_event, } #else #define net_mgmt_event_notify(...) -#define net_mgmt_event_notify_with_info(...) #endif /** diff --git a/include/zephyr/net/net_pkt.h b/include/zephyr/net/net_pkt.h index 7d3015588ac..4c5b592fde4 100644 --- a/include/zephyr/net/net_pkt.h +++ b/include/zephyr/net/net_pkt.h @@ -46,6 +46,8 @@ extern "C" { struct net_context; +/** @cond INTERNAL_HIDDEN */ + /* buffer cursor used in net_pkt */ struct net_pkt_cursor { /** Current net_buf pointer by the cursor */ @@ -54,6 +56,8 @@ struct net_pkt_cursor { uint8_t *pos; }; +/** @endcond */ + /** * @brief Network packet. * @@ -72,8 +76,8 @@ struct net_pkt { /** buffer holding the packet */ union { - struct net_buf *frags; - struct net_buf *buffer; + struct net_buf *frags; /**< buffer fragment */ + struct net_buf *buffer; /**< alias to a buffer fragment */ }; /** Internal buffer iterator used for reading/writing */ @@ -177,12 +181,6 @@ struct net_pkt { */ #endif uint8_t ppp_msg : 1; /* This is a PPP message */ -#if defined(CONFIG_NET_TCP) - uint8_t tcp_first_msg : 1; /* Is this the first time this pkt is - * sent, or is this a resend of a TCP - * segment. - */ -#endif uint8_t captured : 1; /* Set to 1 if this packet is already being * captured */ @@ -483,25 +481,6 @@ static inline void net_pkt_set_ip_ecn(struct net_pkt *pkt, uint8_t ecn) #endif } -static inline uint8_t net_pkt_tcp_1st_msg(struct net_pkt *pkt) -{ -#if defined(CONFIG_NET_TCP) - return pkt->tcp_first_msg; -#else - return true; -#endif -} - -static inline void net_pkt_set_tcp_1st_msg(struct net_pkt *pkt, bool is_1st) -{ -#if defined(CONFIG_NET_TCP) - pkt->tcp_first_msg = is_1st; -#else - ARG_UNUSED(pkt); - ARG_UNUSED(is_1st); -#endif -} - static inline uint8_t net_pkt_eof(struct net_pkt *pkt) { return pkt->eof; @@ -1426,9 +1405,13 @@ static inline void net_pkt_set_remote_address(struct net_pkt *pkt, #define NET_PKT_SLAB_DEFINE(name, count) \ K_MEM_SLAB_DEFINE(name, sizeof(struct net_pkt), count, 4) +/** @cond INTERNAL_HIDDEN */ + /* Backward compatibility macro */ #define NET_PKT_TX_SLAB_DEFINE(name, count) NET_PKT_SLAB_DEFINE(name, count) +/** @endcond */ + /** * @brief Create a data fragment net_buf pool * @@ -1880,9 +1863,13 @@ struct net_pkt *net_pkt_rx_alloc(k_timeout_t timeout); struct net_pkt *net_pkt_alloc_on_iface(struct net_if *iface, k_timeout_t timeout); +/** @cond INTERNAL_HIDDEN */ + /* Same as above but specifically for RX packet */ struct net_pkt *net_pkt_rx_alloc_on_iface(struct net_if *iface, k_timeout_t timeout); +/** @endcond */ + #endif /** @@ -1943,12 +1930,17 @@ struct net_pkt *net_pkt_alloc_with_buffer(struct net_if *iface, enum net_ip_protocol proto, k_timeout_t timeout); +/** @cond INTERNAL_HIDDEN */ + /* Same as above but specifically for RX packet */ struct net_pkt *net_pkt_rx_alloc_with_buffer(struct net_if *iface, size_t size, sa_family_t family, enum net_ip_protocol proto, k_timeout_t timeout); + +/** @endcond */ + #endif /** @@ -2165,7 +2157,18 @@ struct net_pkt *net_pkt_shallow_clone(struct net_pkt *pkt, */ int net_pkt_read(struct net_pkt *pkt, void *data, size_t length); -/* Read uint8_t data data a net_pkt */ +/** + * @brief Read a byte (uint8_t) from a net_pkt + * + * @details net_pkt's cursor should be properly initialized and, + * if needed, positioned using net_pkt_skip. + * Cursor position will be updated after the operation. + * + * @param pkt The network packet from where to read + * @param data The destination uint8_t where to copy the data + * + * @return 0 on success, negative errno code otherwise. + */ static inline int net_pkt_read_u8(struct net_pkt *pkt, uint8_t *data) { return net_pkt_read(pkt, data, 1); @@ -2228,13 +2231,35 @@ int net_pkt_read_be32(struct net_pkt *pkt, uint32_t *data); */ int net_pkt_write(struct net_pkt *pkt, const void *data, size_t length); -/* Write uint8_t data into a net_pkt. */ +/** + * @brief Write a byte (uint8_t) data to a net_pkt + * + * @details net_pkt's cursor should be properly initialized and, + * if needed, positioned using net_pkt_skip. + * Cursor position will be updated after the operation. + * + * @param pkt The network packet from where to read + * @param data The uint8_t value to write + * + * @return 0 on success, negative errno code otherwise. + */ static inline int net_pkt_write_u8(struct net_pkt *pkt, uint8_t data) { return net_pkt_write(pkt, &data, sizeof(uint8_t)); } -/* Write uint16_t big endian data into a net_pkt. */ +/** + * @brief Write a uint16_t big endian data to a net_pkt + * + * @details net_pkt's cursor should be properly initialized and, + * if needed, positioned using net_pkt_skip. + * Cursor position will be updated after the operation. + * + * @param pkt The network packet from where to read + * @param data The uint16_t value in host byte order to write + * + * @return 0 on success, negative errno code otherwise. + */ static inline int net_pkt_write_be16(struct net_pkt *pkt, uint16_t data) { uint16_t data_be16 = htons(data); @@ -2242,7 +2267,18 @@ static inline int net_pkt_write_be16(struct net_pkt *pkt, uint16_t data) return net_pkt_write(pkt, &data_be16, sizeof(uint16_t)); } -/* Write uint32_t big endian data into a net_pkt. */ +/** + * @brief Write a uint32_t big endian data to a net_pkt + * + * @details net_pkt's cursor should be properly initialized and, + * if needed, positioned using net_pkt_skip. + * Cursor position will be updated after the operation. + * + * @param pkt The network packet from where to read + * @param data The uint32_t value in host byte order to write + * + * @return 0 on success, negative errno code otherwise. + */ static inline int net_pkt_write_be32(struct net_pkt *pkt, uint32_t data) { uint32_t data_be32 = htonl(data); @@ -2250,7 +2286,18 @@ static inline int net_pkt_write_be32(struct net_pkt *pkt, uint32_t data) return net_pkt_write(pkt, &data_be32, sizeof(uint32_t)); } -/* Write uint32_t little endian data into a net_pkt. */ +/** + * @brief Write a uint32_t little endian data to a net_pkt + * + * @details net_pkt's cursor should be properly initialized and, + * if needed, positioned using net_pkt_skip. + * Cursor position will be updated after the operation. + * + * @param pkt The network packet from where to read + * @param data The uint32_t value in host byte order to write + * + * @return 0 on success, negative errno code otherwise. + */ static inline int net_pkt_write_le32(struct net_pkt *pkt, uint32_t data) { uint32_t data_le32 = sys_cpu_to_le32(data); @@ -2258,7 +2305,18 @@ static inline int net_pkt_write_le32(struct net_pkt *pkt, uint32_t data) return net_pkt_write(pkt, &data_le32, sizeof(uint32_t)); } -/* Write uint16_t little endian data into a net_pkt. */ +/** + * @brief Write a uint16_t little endian data to a net_pkt + * + * @details net_pkt's cursor should be properly initialized and, + * if needed, positioned using net_pkt_skip. + * Cursor position will be updated after the operation. + * + * @param pkt The network packet from where to read + * @param data The uint16_t value in host byte order to write + * + * @return 0 on success, negative errno code otherwise. + */ static inline int net_pkt_write_le16(struct net_pkt *pkt, uint16_t data) { uint16_t data_le16 = sys_cpu_to_le16(data); @@ -2336,6 +2394,8 @@ bool net_pkt_is_contiguous(struct net_pkt *pkt, size_t size); */ size_t net_pkt_get_contiguous_len(struct net_pkt *pkt); +/** @cond INTERNAL_HIDDEN */ + struct net_pkt_data_access { #if !defined(CONFIG_NET_HEADERS_ALWAYS_CONTIGUOUS) void *data; @@ -2368,6 +2428,8 @@ struct net_pkt_data_access { #endif /* CONFIG_NET_HEADERS_ALWAYS_CONTIGUOUS */ +/** @endcond */ + /** * @brief Get data from a network packet in a contiguous way * diff --git a/include/zephyr/net/net_pkt_filter.h b/include/zephyr/net/net_pkt_filter.h index aa1ad89b0e6..753ca347eb4 100644 --- a/include/zephyr/net/net_pkt_filter.h +++ b/include/zephyr/net/net_pkt_filter.h @@ -46,7 +46,7 @@ struct npf_test { /** @brief filter rule structure */ struct npf_rule { - sys_snode_t node; + sys_snode_t node; /**< Slist rule list node */ enum net_verdict result; /**< result if all tests pass */ uint32_t nb_tests; /**< number of tests for this rule */ struct npf_test *tests[]; /**< pointers to @ref npf_test instances */ @@ -59,8 +59,8 @@ extern struct npf_rule npf_default_drop; /** @brief rule set for a given test location */ struct npf_rule_list { - sys_slist_t rule_head; - struct k_spinlock lock; + sys_slist_t rule_head; /**< List head */ + struct k_spinlock lock; /**< Lock protecting the list access */ }; /** @brief rule list applied to outgoing packets */ @@ -107,6 +107,8 @@ bool npf_remove_rule(struct npf_rule_list *rules, struct npf_rule *rule); */ bool npf_remove_all_rules(struct npf_rule_list *rules); +/** @cond INTERNAL_HIDDEN */ + /* convenience shortcuts */ #define npf_insert_send_rule(rule) npf_insert_rule(&npf_send_rules, rule) #define npf_insert_recv_rule(rule) npf_insert_rule(&npf_recv_rules, rule) @@ -138,6 +140,8 @@ bool npf_remove_all_rules(struct npf_rule_list *rules); #define npf_remove_all_ipv6_recv_rules() npf_remove_all_rules(&npf_ipv6_recv_rules) #endif /* CONFIG_NET_PKT_FILTER_IPV6_HOOK */ +/** @endcond */ + /** * @brief Statically define one packet filter rule * diff --git a/include/zephyr/net/net_stats.h b/include/zephyr/net/net_stats.h index f5a567fcdbc..5a2ac84eaa2 100644 --- a/include/zephyr/net/net_stats.h +++ b/include/zephyr/net/net_stats.h @@ -186,8 +186,13 @@ struct net_stats_udp { * @brief IPv6 neighbor discovery statistics */ struct net_stats_ipv6_nd { + /** Number of dropped IPv6 neighbor discovery packets. */ net_stats_t drop; + + /** Number of received IPv6 neighbor discovery packets. */ net_stats_t recv; + + /** Number of sent IPv6 neighbor discovery packets. */ net_stats_t sent; }; @@ -195,13 +200,13 @@ struct net_stats_ipv6_nd { * @brief IPv6 multicast listener daemon statistics */ struct net_stats_ipv6_mld { - /** Number of received IPv6 MLD queries */ + /** Number of received IPv6 MLD queries. */ net_stats_t recv; - /** Number of sent IPv6 MLD reports */ + /** Number of sent IPv6 MLD reports. */ net_stats_t sent; - /** Number of dropped IPv6 MLD packets */ + /** Number of dropped IPv6 MLD packets. */ net_stats_t drop; }; @@ -223,7 +228,10 @@ struct net_stats_ipv4_igmp { * @brief Network packet transfer times for calculating average TX time */ struct net_stats_tx_time { + /** Sum of network packet transfer times. */ uint64_t sum; + + /** Number of network packets transferred. */ net_stats_t count; }; @@ -231,10 +239,15 @@ struct net_stats_tx_time { * @brief Network packet receive times for calculating average RX time */ struct net_stats_rx_time { + /** Sum of network packet receive times. */ uint64_t sum; + + /** Number of network packets received. */ net_stats_t count; }; +/** @cond INTERNAL_HIDDEN */ + #if NET_TC_TX_COUNT == 0 #define NET_TC_TX_STATS_COUNT 1 #else @@ -247,29 +260,43 @@ struct net_stats_rx_time { #define NET_TC_RX_STATS_COUNT NET_TC_RX_COUNT #endif +/** @endcond */ + /** * @brief Traffic class statistics */ struct net_stats_tc { + /** TX statistics for each traffic class */ struct { + /** Helper for calculating average TX time statistics */ struct net_stats_tx_time tx_time; #if defined(CONFIG_NET_PKT_TXTIME_STATS_DETAIL) + /** Detailed TX time statistics inside network stack */ struct net_stats_tx_time tx_time_detail[NET_PKT_DETAIL_STATS_COUNT]; #endif + /** Number of packets sent for this traffic class */ net_stats_t pkts; + /** Number of bytes sent for this traffic class */ net_stats_t bytes; + /** Priority of this traffic class */ uint8_t priority; } sent[NET_TC_TX_STATS_COUNT]; + /** RX statistics for each traffic class */ struct { + /** Helper for calculating average RX time statistics */ struct net_stats_rx_time rx_time; #if defined(CONFIG_NET_PKT_RXTIME_STATS_DETAIL) + /** Detailed RX time statistics inside network stack */ struct net_stats_rx_time rx_time_detail[NET_PKT_DETAIL_STATS_COUNT]; #endif + /** Number of packets received for this traffic class */ net_stats_t pkts; + /** Number of bytes received for this traffic class */ net_stats_t bytes; + /** Priority of this traffic class */ uint8_t priority; } recv[NET_TC_RX_STATS_COUNT]; }; @@ -279,9 +306,13 @@ struct net_stats_tc { * @brief Power management statistics */ struct net_stats_pm { + /** Total suspend time */ uint64_t overall_suspend_time; + /** How many times we were suspended */ net_stats_t suspend_count; + /** How long the last suspend took */ uint32_t last_suspend_time; + /** Network interface last suspend start time */ uint32_t start_time; }; @@ -367,6 +398,7 @@ struct net_stats { #endif #if defined(CONFIG_NET_STATISTICS_POWER_MANAGEMENT) + /** Power management statistics */ struct net_stats_pm pm; #endif }; @@ -375,26 +407,61 @@ struct net_stats { * @brief Ethernet error statistics */ struct net_stats_eth_errors { + /** Number of RX length errors */ net_stats_t rx_length_errors; + + /** Number of RX overrun errors */ net_stats_t rx_over_errors; + + /** Number of RX CRC errors */ net_stats_t rx_crc_errors; + + /** Number of RX frame errors */ net_stats_t rx_frame_errors; + + /** Number of RX net_pkt allocation errors */ net_stats_t rx_no_buffer_count; + + /** Number of RX missed errors */ net_stats_t rx_missed_errors; + + /** Number of RX long length errors */ net_stats_t rx_long_length_errors; + + /** Number of RX short length errors */ net_stats_t rx_short_length_errors; + + /** Number of RX buffer align errors */ net_stats_t rx_align_errors; + + /** Number of RX DMA failed errors */ net_stats_t rx_dma_failed; + + /** Number of RX net_buf allocation errors */ net_stats_t rx_buf_alloc_failed; + /** Number of TX aborted errors */ net_stats_t tx_aborted_errors; + + /** Number of TX carrier errors */ net_stats_t tx_carrier_errors; + + /** Number of TX FIFO errors */ net_stats_t tx_fifo_errors; + + /** Number of TX heartbeat errors */ net_stats_t tx_heartbeat_errors; + + /** Number of TX window errors */ net_stats_t tx_window_errors; + + /** Number of TX DMA failed errors */ net_stats_t tx_dma_failed; + /** Number of uncorrected ECC errors */ net_stats_t uncorr_ecc_errors; + + /** Number of corrected ECC errors */ net_stats_t corr_ecc_errors; }; @@ -402,9 +469,16 @@ struct net_stats_eth_errors { * @brief Ethernet flow control statistics */ struct net_stats_eth_flow { + /** Number of RX XON flow control */ net_stats_t rx_flow_control_xon; + + /** Number of RX XOFF flow control */ net_stats_t rx_flow_control_xoff; + + /** Number of TX XON flow control */ net_stats_t tx_flow_control_xon; + + /** Number of TX XOFF flow control */ net_stats_t tx_flow_control_xoff; }; @@ -412,7 +486,10 @@ struct net_stats_eth_flow { * @brief Ethernet checksum statistics */ struct net_stats_eth_csum { + /** Number of good RX checksum offloading */ net_stats_t rx_csum_offload_good; + + /** Number of failed RX checksum offloading */ net_stats_t rx_csum_offload_errors; }; @@ -420,8 +497,13 @@ struct net_stats_eth_csum { * @brief Ethernet hardware timestamp statistics */ struct net_stats_eth_hw_timestamp { + /** Number of RX hardware timestamp cleared */ net_stats_t rx_hwtstamp_cleared; + + /** Number of RX hardware timestamp timeout */ net_stats_t tx_hwtstamp_timeouts; + + /** Number of RX hardware timestamp skipped */ net_stats_t tx_hwtstamp_skipped; }; @@ -430,8 +512,8 @@ struct net_stats_eth_hw_timestamp { * @brief Ethernet vendor specific statistics */ struct net_stats_eth_vendor { - const char * const key; - uint32_t value; + const char * const key; /**< Key name of vendor statistics */ + uint32_t value; /**< Value of the statistics key */ }; #endif @@ -439,20 +521,48 @@ struct net_stats_eth_vendor { * @brief All Ethernet specific statistics */ struct net_stats_eth { + /** Total number of bytes received and sent */ struct net_stats_bytes bytes; + + /** Total number of packets received and sent */ struct net_stats_pkts pkts; + + /** Total number of broadcast packets received and sent */ struct net_stats_pkts broadcast; + + /** Total number of multicast packets received and sent */ struct net_stats_pkts multicast; + + /** Total number of errors in RX and TX */ struct net_stats_pkts errors; + + /** Total number of errors in RX and TX */ struct net_stats_eth_errors error_details; + + /** Total number of flow control errors in RX and TX */ struct net_stats_eth_flow flow_control; + + /** Total number of checksum errors in RX and TX */ struct net_stats_eth_csum csum; + + /** Total number of hardware timestamp errors in RX and TX */ struct net_stats_eth_hw_timestamp hw_timestamp; + + /** Total number of collisions */ net_stats_t collisions; + + /** Total number of dropped TX packets */ net_stats_t tx_dropped; + + /** Total number of TX timeout errors */ net_stats_t tx_timeout_count; + + /** Total number of TX queue restarts */ net_stats_t tx_restart_queue; + + /** Total number of RX unknown protocol packets */ net_stats_t unknown_protocol; + #ifdef CONFIG_NET_STATISTICS_ETHERNET_VENDOR /** Array is terminated with an entry containing a NULL key */ struct net_stats_eth_vendor *vendor; @@ -463,7 +573,10 @@ struct net_stats_eth { * @brief All PPP specific statistics */ struct net_stats_ppp { + /** Total number of bytes received and sent */ struct net_stats_bytes bytes; + + /** Total number of packets received and sent */ struct net_stats_pkts pkts; /** Number of received and dropped PPP frames. */ @@ -488,18 +601,33 @@ struct net_stats_sta_mgmt { * @brief All Wi-Fi specific statistics */ struct net_stats_wifi { + /** Total number of beacon errors */ struct net_stats_sta_mgmt sta_mgmt; + + /** Total number of bytes received and sent */ struct net_stats_bytes bytes; + + /** Total number of packets received and sent */ struct net_stats_pkts pkts; + + /** Total number of broadcast packets received and sent */ struct net_stats_pkts broadcast; + + /** Total number of multicast packets received and sent */ struct net_stats_pkts multicast; + + /** Total number of errors in RX and TX */ struct net_stats_pkts errors; + + /** Total number of unicast packets received and sent */ struct net_stats_pkts unicast; }; #if defined(CONFIG_NET_STATISTICS_USER_API) /* Management part definitions */ +/** @cond INTERNAL_HIDDEN */ + #define _NET_STATS_LAYER NET_MGMT_LAYER_L3 #define _NET_STATS_CODE 0x101 #define _NET_STATS_BASE (NET_MGMT_LAYER(_NET_STATS_LAYER) | \ @@ -522,96 +650,133 @@ enum net_request_stats_cmd { NET_REQUEST_STATS_CMD_GET_WIFI, }; +/** @endcond */ + +/** Request all network statistics */ #define NET_REQUEST_STATS_GET_ALL \ (_NET_STATS_BASE | NET_REQUEST_STATS_CMD_GET_ALL) -NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_STATS_GET_ALL); - +/** Request all processing error statistics */ #define NET_REQUEST_STATS_GET_PROCESSING_ERROR \ (_NET_STATS_BASE | NET_REQUEST_STATS_CMD_GET_PROCESSING_ERROR) -NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_STATS_GET_PROCESSING_ERROR); - +/** Request number of received and sent bytes */ #define NET_REQUEST_STATS_GET_BYTES \ (_NET_STATS_BASE | NET_REQUEST_STATS_CMD_GET_BYTES) -NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_STATS_GET_BYTES); - +/** Request IP error statistics */ #define NET_REQUEST_STATS_GET_IP_ERRORS \ (_NET_STATS_BASE | NET_REQUEST_STATS_CMD_GET_IP_ERRORS) +/** @cond INTERNAL_HIDDEN */ + +NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_STATS_GET_ALL); +NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_STATS_GET_PROCESSING_ERROR); +NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_STATS_GET_BYTES); NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_STATS_GET_IP_ERRORS); +/** @endcond */ + #if defined(CONFIG_NET_STATISTICS_IPV4) +/** Request IPv4 statistics */ #define NET_REQUEST_STATS_GET_IPV4 \ (_NET_STATS_BASE | NET_REQUEST_STATS_CMD_GET_IPV4) +/** @cond INTERNAL_HIDDEN */ NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_STATS_GET_IPV4); +/** @endcond */ #endif /* CONFIG_NET_STATISTICS_IPV4 */ #if defined(CONFIG_NET_STATISTICS_IPV6) +/** Request IPv6 statistics */ #define NET_REQUEST_STATS_GET_IPV6 \ (_NET_STATS_BASE | NET_REQUEST_STATS_CMD_GET_IPV6) +/** @cond INTERNAL_HIDDEN */ NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_STATS_GET_IPV6); +/** @endcond */ #endif /* CONFIG_NET_STATISTICS_IPV6 */ #if defined(CONFIG_NET_STATISTICS_IPV6_ND) +/** Request IPv6 neighbor discovery statistics */ #define NET_REQUEST_STATS_GET_IPV6_ND \ (_NET_STATS_BASE | NET_REQUEST_STATS_CMD_GET_IPV6_ND) +/** @cond INTERNAL_HIDDEN */ NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_STATS_GET_IPV6_ND); +/** @endcond */ #endif /* CONFIG_NET_STATISTICS_IPV6_ND */ #if defined(CONFIG_NET_STATISTICS_ICMP) +/** Request ICMPv4 and ICMPv6 statistics */ #define NET_REQUEST_STATS_GET_ICMP \ (_NET_STATS_BASE | NET_REQUEST_STATS_CMD_GET_ICMP) +/** @cond INTERNAL_HIDDEN */ NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_STATS_GET_ICMP); +/** @endcond */ #endif /* CONFIG_NET_STATISTICS_ICMP */ #if defined(CONFIG_NET_STATISTICS_UDP) +/** Request UDP statistics */ #define NET_REQUEST_STATS_GET_UDP \ (_NET_STATS_BASE | NET_REQUEST_STATS_CMD_GET_UDP) +/** @cond INTERNAL_HIDDEN */ NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_STATS_GET_UDP); +/** @endcond */ #endif /* CONFIG_NET_STATISTICS_UDP */ #if defined(CONFIG_NET_STATISTICS_TCP) +/** Request TCP statistics */ #define NET_REQUEST_STATS_GET_TCP \ (_NET_STATS_BASE | NET_REQUEST_STATS_CMD_GET_TCP) +/** @cond INTERNAL_HIDDEN */ NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_STATS_GET_TCP); +/** @endcond */ #endif /* CONFIG_NET_STATISTICS_TCP */ #if defined(CONFIG_NET_STATISTICS_ETHERNET) +/** Request Ethernet statistics */ #define NET_REQUEST_STATS_GET_ETHERNET \ (_NET_STATS_BASE | NET_REQUEST_STATS_CMD_GET_ETHERNET) +/** @cond INTERNAL_HIDDEN */ NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_STATS_GET_ETHERNET); +/** @endcond */ #endif /* CONFIG_NET_STATISTICS_ETHERNET */ #if defined(CONFIG_NET_STATISTICS_PPP) +/** Request PPP statistics */ #define NET_REQUEST_STATS_GET_PPP \ (_NET_STATS_BASE | NET_REQUEST_STATS_CMD_GET_PPP) +/** @cond INTERNAL_HIDDEN */ NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_STATS_GET_PPP); +/** @endcond */ #endif /* CONFIG_NET_STATISTICS_PPP */ #endif /* CONFIG_NET_STATISTICS_USER_API */ #if defined(CONFIG_NET_STATISTICS_POWER_MANAGEMENT) +/** Request network power management statistics */ #define NET_REQUEST_STATS_GET_PM \ (_NET_STATS_BASE | NET_REQUEST_STATS_CMD_GET_PM) +/** @cond INTERNAL_HIDDEN */ NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_STATS_GET_PM); +/** @endcond */ #endif /* CONFIG_NET_STATISTICS_POWER_MANAGEMENT */ #if defined(CONFIG_NET_STATISTICS_WIFI) +/** Request Wi-Fi statistics */ #define NET_REQUEST_STATS_GET_WIFI \ (_NET_STATS_BASE | NET_REQUEST_STATS_CMD_GET_WIFI) +/** @cond INTERNAL_HIDDEN */ NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_STATS_GET_WIFI); +/** @endcond */ #endif /* CONFIG_NET_STATISTICS_WIFI */ /** diff --git a/include/zephyr/net/net_timeout.h b/include/zephyr/net/net_timeout.h index fb40ec93616..87d312648f4 100644 --- a/include/zephyr/net/net_timeout.h +++ b/include/zephyr/net/net_timeout.h @@ -61,12 +61,13 @@ struct net_timeout { */ sys_snode_t node; - /* Time at which the timer was last set. + /** Time at which the timer was last set. * - * This usually corresponds to the low 32 bits of k_uptime_get(). */ + * This usually corresponds to the low 32 bits of k_uptime_get(). + */ uint32_t timer_start; - /* Portion of remaining timeout that does not exceed + /** Portion of remaining timeout that does not exceed * NET_TIMEOUT_MAX_VALUE. * * This value is updated in parallel with timer_start and wrap_counter @@ -74,7 +75,7 @@ struct net_timeout { */ uint32_t timer_timeout; - /* Timer wrap count. + /** Timer wrap count. * * This tracks multiples of NET_TIMEOUT_MAX_VALUE milliseconds that * have yet to pass. It is also updated along with timer_start and diff --git a/include/zephyr/net/offloaded_netdev.h b/include/zephyr/net/offloaded_netdev.h index ce90cf77bf3..009a0666515 100644 --- a/include/zephyr/net/offloaded_netdev.h +++ b/include/zephyr/net/offloaded_netdev.h @@ -58,7 +58,7 @@ struct offloaded_if_api { /** Enable or disable the device (in response to admin state change) */ int (*enable)(const struct net_if *iface, bool state); - /* Types of offloaded net device */ + /** Types of offloaded net device */ enum offloaded_net_if_types (*get_type)(void); }; diff --git a/include/zephyr/net/openthread.h b/include/zephyr/net/openthread.h index 81c2629d6c0..0d933df460f 100644 --- a/include/zephyr/net/openthread.h +++ b/include/zephyr/net/openthread.h @@ -199,8 +199,12 @@ int openthread_api_mutex_try_lock(struct openthread_context *ot_context); */ void openthread_api_mutex_unlock(struct openthread_context *ot_context); +/** @cond INTERNAL_HIDDEN */ + #define OPENTHREAD_L2_CTX_TYPE struct openthread_context +/** @endcond */ + #ifdef __cplusplus } #endif diff --git a/include/zephyr/net/phy.h b/include/zephyr/net/phy.h index 38c6d1f5bbe..160b31df237 100644 --- a/include/zephyr/net/phy.h +++ b/include/zephyr/net/phy.h @@ -42,8 +42,31 @@ enum phy_link_speed { LINK_FULL_1000BASE_T = BIT(5), }; +/** + * @brief Check if phy link is full duplex. + * + * @param x Link capabilities + * + * @return True if link is full duplex, false if not. + */ #define PHY_LINK_IS_FULL_DUPLEX(x) (x & (BIT(1) | BIT(3) | BIT(5))) + +/** + * @brief Check if phy link speed is 1 Gbit/sec. + * + * @param x Link capabilities + * + * @return True if link is 1 Gbit/sec, false if not. + */ #define PHY_LINK_IS_SPEED_1000M(x) (x & (BIT(4) | BIT(5))) + +/** + * @brief Check if phy link speed is 100 Mbit/sec. + * + * @param x Link capabilities + * + * @return True if link is 1 Mbit/sec, false if not. + */ #define PHY_LINK_IS_SPEED_100M(x) (x & (BIT(2) | BIT(3))) /** @brief Link state */ diff --git a/include/zephyr/net/ppp.h b/include/zephyr/net/ppp.h index 36c6bf64eeb..da31eca01a1 100644 --- a/include/zephyr/net/ppp.h +++ b/include/zephyr/net/ppp.h @@ -4,6 +4,10 @@ * SPDX-License-Identifier: Apache-2.0 */ +/** + * @file + * @brief PPP (Point-to-Point Protocol) + */ #ifndef ZEPHYR_INCLUDE_NET_PPP_H_ #define ZEPHYR_INCLUDE_NET_PPP_H_ @@ -103,6 +107,8 @@ enum ppp_phase { PPP_TERMINATE, }; +/** @cond INTERNAL_HIDDEN */ + /** * PPP states, RFC 1661 ch. 4.2 */ @@ -136,10 +142,13 @@ enum ppp_packet_type { PPP_DISCARD_REQ = 11 }; +/** @endcond */ + /** * LCP option types from RFC 1661 ch. 6 */ enum lcp_option_type { + /** Reserved option value (do not use) */ LCP_OPTION_RESERVED = 0, /** Maximum-Receive-Unit */ @@ -168,6 +177,7 @@ enum lcp_option_type { * IPCP option types from RFC 1332 */ enum ipcp_option_type { + /** Reserved IPCP option value (do not use) */ IPCP_OPTION_RESERVED = 0, /** IP Addresses */ @@ -198,6 +208,7 @@ enum ipcp_option_type { * IPV6CP option types from RFC 5072 */ enum ipv6cp_option_type { + /** Reserved IPV6CP option value (do not use) */ IPV6CP_OPTION_RESERVED = 0, /** Interface identifier */ @@ -225,6 +236,7 @@ struct ppp_fsm { /** Timeout timer */ struct k_work_delayable timer; + /** FSM callbacks */ struct { /** Acknowledge Configuration Information */ int (*config_info_ack)(struct ppp_fsm *fsm, @@ -284,6 +296,7 @@ struct ppp_fsm { struct net_pkt *pkt); } cb; + /** My options */ struct { /** Options information */ const struct ppp_my_option_info *info; @@ -329,6 +342,8 @@ struct ppp_fsm { uint8_t ack_received : 1; }; +/** @cond INTERNAL_HIDDEN */ + #define PPP_MY_OPTION_ACKED BIT(0) #define PPP_MY_OPTION_REJECTED BIT(1) @@ -336,6 +351,16 @@ struct ppp_my_option_data { uint32_t flags; }; +#define IPCP_NUM_MY_OPTIONS 3 +#define IPV6CP_NUM_MY_OPTIONS 1 + +enum ppp_flags { + PPP_CARRIER_UP, +}; + +/** @endcond */ + +/** Link control protocol options */ struct lcp_options { /** Magic number */ uint32_t magic; @@ -354,26 +379,24 @@ struct lcp_options { #define LCP_NUM_MY_OPTIONS 1 #endif +/** IPv4 control protocol options */ struct ipcp_options { /** IPv4 address */ struct in_addr address; + + /** Primary DNS server address */ struct in_addr dns1_address; + + /** Secondary DNS server address */ struct in_addr dns2_address; }; -#define IPCP_NUM_MY_OPTIONS 3 - +/** IPv6 control protocol options */ struct ipv6cp_options { /** Interface identifier */ uint8_t iid[PPP_INTERFACE_IDENTIFIER_LEN]; }; -#define IPV6CP_NUM_MY_OPTIONS 1 - -enum ppp_flags { - PPP_CARRIER_UP, -}; - /** PPP L2 context specific to certain network interface */ struct ppp_context { /** Flags representing PPP state, which are accessed from multiple @@ -384,6 +407,7 @@ struct ppp_context { /** PPP startup worker. */ struct k_work_delayable startup; + /** LCP options */ struct { /** Finite state machine for LCP */ struct ppp_fsm fsm; @@ -402,6 +426,7 @@ struct ppp_context { } lcp; #if defined(CONFIG_NET_IPV4) + /** ICMP options */ struct { /** Finite state machine for IPCP */ struct ppp_fsm fsm; @@ -418,6 +443,7 @@ struct ppp_context { #endif #if defined(CONFIG_NET_IPV6) + /** IPV6CP options */ struct { /** Finite state machine for IPV6CP */ struct ppp_fsm fsm; @@ -434,6 +460,7 @@ struct ppp_context { #endif #if defined(CONFIG_NET_L2_PPP_PAP) + /** PAP options */ struct { /** Finite state machine for PAP */ struct ppp_fsm fsm; @@ -441,7 +468,9 @@ struct ppp_context { #endif #if defined(CONFIG_NET_SHELL) + /** Network shell PPP command internal data */ struct { + /** Ping command internal data */ struct { /** Callback to be called when Echo-Reply is received. */ @@ -544,22 +573,26 @@ enum net_event_ppp_cmd { NET_EVENT_PPP_CMD_PHASE_DEAD, }; +struct net_if; + +/** @endcond */ + +/** Event emitted when PPP carrier is on */ #define NET_EVENT_PPP_CARRIER_ON \ (_NET_PPP_EVENT | NET_EVENT_PPP_CMD_CARRIER_ON) +/** Event emitted when PPP carrier is off */ #define NET_EVENT_PPP_CARRIER_OFF \ (_NET_PPP_EVENT | NET_EVENT_PPP_CMD_CARRIER_OFF) +/** Event emitted when PPP goes into running phase */ #define NET_EVENT_PPP_PHASE_RUNNING \ (_NET_PPP_EVENT | NET_EVENT_PPP_CMD_PHASE_RUNNING) +/** Event emitted when PPP goes into dead phase */ #define NET_EVENT_PPP_PHASE_DEAD \ (_NET_PPP_EVENT | NET_EVENT_PPP_CMD_PHASE_DEAD) -struct net_if; - -/** @endcond */ - /** * @brief Raise CARRIER_ON event when PPP is connected. * diff --git a/include/zephyr/net/ptp_time.h b/include/zephyr/net/ptp_time.h index 99c5037e7ba..269325cdde1 100644 --- a/include/zephyr/net/ptp_time.h +++ b/include/zephyr/net/ptp_time.h @@ -109,6 +109,8 @@ extern "C" { struct net_ptp_time { /** Seconds encoded on 48 bits. */ union { + +/** @cond INTERNAL_HIDDEN */ struct { #ifdef CONFIG_LITTLE_ENDIAN uint32_t low; @@ -120,6 +122,9 @@ struct net_ptp_time { uint32_t low; #endif } _sec; +/** @endcond */ + + /** Second value. */ uint64_t second; }; @@ -147,6 +152,8 @@ struct net_ptp_time { struct net_ptp_extended_time { /** Seconds encoded on 48 bits. */ union { + +/** @cond INTERNAL_HIDDEN */ struct { #ifdef CONFIG_LITTLE_ENDIAN uint32_t low; @@ -158,11 +165,16 @@ struct net_ptp_extended_time { uint32_t low; #endif } _sec; +/** @endcond */ + + /** Second value. */ uint64_t second; }; /** Fractional nanoseconds on 48 bits. */ union { + +/** @cond INTERNAL_HIDDEN */ struct { #ifdef CONFIG_LITTLE_ENDIAN uint32_t low; @@ -174,6 +186,9 @@ struct net_ptp_extended_time { uint32_t low; #endif } _fns; +/** @endcond */ + + /** Fractional nanoseconds value. */ uint64_t fract_nsecond; }; } __packed; diff --git a/include/zephyr/net/sntp.h b/include/zephyr/net/sntp.h index a1c8a59e0e8..68a733d355d 100644 --- a/include/zephyr/net/sntp.h +++ b/include/zephyr/net/sntp.h @@ -5,6 +5,11 @@ * SPDX-License-Identifier: Apache-2.0 */ +/** + * @file + * @brief SNTP (Simple Network Time Protocol) + */ + #ifndef ZEPHYR_INCLUDE_NET_SNTP_H_ #define ZEPHYR_INCLUDE_NET_SNTP_H_ @@ -23,21 +28,24 @@ extern "C" { /** Time as returned by SNTP API, fractional seconds since 1 Jan 1970 */ struct sntp_time { - uint64_t seconds; - uint32_t fraction; + uint64_t seconds; /**< Second value */ + uint32_t fraction; /**< Fractional seconds value */ #if defined(CONFIG_SNTP_UNCERTAINTY) - uint64_t uptime_us; - uint32_t uncertainty_us; + uint64_t uptime_us; /**< Uptime in microseconds */ + uint32_t uncertainty_us; /**< Uncertainty in microseconds */ #endif }; /** SNTP context */ struct sntp_ctx { + +/** @cond INTERNAL_HIDDEN */ struct { struct zsock_pollfd fds[1]; int nfds; int fd; } sock; +/** @endcond */ /** Timestamp when the request was sent from client to server. * This is used to check if the originated timestamp in the server diff --git a/include/zephyr/net/socket.h b/include/zephyr/net/socket.h index 79eb8f32455..47fcbf18da1 100644 --- a/include/zephyr/net/socket.h +++ b/include/zephyr/net/socket.h @@ -22,13 +22,16 @@ * @{ */ +#include #include #include +#include #include -#include #include +#include #include #include +#include #include #include @@ -36,17 +39,6 @@ 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; /**< Socket descriptor */ - short events; /**< Requested events */ - short revents; /**< Returned events */ -}; - /** * @name Options for poll() * @{ @@ -284,6 +276,7 @@ struct zsock_addrinfo { 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 */ + int ai_eflags; /**< Extended flags for special usage */ 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 */ @@ -562,6 +555,8 @@ static inline ssize_t zsock_recv(int sock, void *buf, size_t max_len, */ __syscall int zsock_fcntl_impl(int sock, int cmd, int flags); +/** @cond INTERNAL_HIDDEN */ + /* * Need this wrapper because newer GCC versions got too smart and "typecheck" * even macros. @@ -579,6 +574,8 @@ static inline int zsock_fcntl_wrapper(int sock, int cmd, ...) #define zsock_fcntl zsock_fcntl_wrapper +/** @endcond */ + /** * @brief Control underlying socket parameters * @@ -598,6 +595,8 @@ static inline int zsock_fcntl_wrapper(int sock, int cmd, ...) */ __syscall int zsock_ioctl_impl(int sock, unsigned long request, va_list ap); +/** @cond INTERNAL_HIDDEN */ + static inline int zsock_ioctl_wrapper(int sock, unsigned long request, ...) { int ret; @@ -612,6 +611,8 @@ static inline int zsock_ioctl_wrapper(int sock, unsigned long request, ...) #define zsock_ioctl zsock_ioctl_wrapper +/** @endcond */ + /** * @brief Efficiently poll multiple sockets for events * @@ -766,6 +767,8 @@ __syscall int z_zsock_getaddrinfo_internal(const char *host, #define AI_ADDRCONFIG 0x20 /** Assume service (port) is numeric */ #define AI_NUMERICSERV 0x400 +/** Extra flags present (see RFC 5014) */ +#define AI_EXTFLAGS 0x800 /** @} */ /** @@ -1279,6 +1282,27 @@ struct ipv6_mreq { */ #define IPV6_RECVPKTINFO 49 +/** RFC5014: Source address selection. */ +#define IPV6_ADDR_PREFERENCES 72 + +/** Prefer temporary address as source. */ +#define IPV6_PREFER_SRC_TMP 0x0001 +/** Prefer public address as source. */ +#define IPV6_PREFER_SRC_PUBLIC 0x0002 +/** Either public or temporary address is selected as a default source + * depending on the output interface configuration (this is the default value). + * This is Linux specific option not found in the RFC. + */ +#define IPV6_PREFER_SRC_PUBTMP_DEFAULT 0x0100 +/** Prefer Care-of address as source. Ignored in Zephyr. */ +#define IPV6_PREFER_SRC_COA 0x0004 +/** Prefer Home address as source. Ignored in Zephyr. */ +#define IPV6_PREFER_SRC_HOME 0x0400 +/** Prefer CGA (Cryptographically Generated Address) address as source. Ignored in Zephyr. */ +#define IPV6_PREFER_SRC_CGA 0x0008 +/** Prefer non-CGA address as source. Ignored in Zephyr. */ +#define IPV6_PREFER_SRC_NONCGA 0x0800 + /** * @brief Incoming IPv6 packet information. * diff --git a/include/zephyr/net/socket_net_mgmt.h b/include/zephyr/net/socket_net_mgmt.h index c2c07a93b15..3c173f96a6f 100644 --- a/include/zephyr/net/socket_net_mgmt.h +++ b/include/zephyr/net/socket_net_mgmt.h @@ -29,6 +29,8 @@ extern "C" { * @{ */ +/** @cond INTERNAL_HIDDEN */ + /* Protocols of the protocol family PF_NET_MGMT */ #define NET_MGMT_EVENT_PROTO 0x01 @@ -36,6 +38,8 @@ extern "C" { #define SOL_NET_MGMT_BASE 100 #define SOL_NET_MGMT_RAW (SOL_NET_MGMT_BASE + 1) +/** @endcond */ + /** * struct sockaddr_nm - The sockaddr structure for NET_MGMT sockets * diff --git a/include/zephyr/net/socket_offload.h b/include/zephyr/net/socket_offload.h index d0f2d29cfe4..988d0fb686b 100644 --- a/include/zephyr/net/socket_offload.h +++ b/include/zephyr/net/socket_offload.h @@ -26,9 +26,11 @@ extern "C" { * POSIX socket API standard for arguments, return values and setting of errno. */ struct socket_dns_offload { + /** DNS getaddrinfo offloaded implementation API */ int (*getaddrinfo)(const char *node, const char *service, const struct zsock_addrinfo *hints, struct zsock_addrinfo **res); + /** DNS freeaddrinfo offloaded implementation API */ void (*freeaddrinfo)(struct zsock_addrinfo *res); }; @@ -39,12 +41,16 @@ struct socket_dns_offload { */ void socket_offload_dns_register(const struct socket_dns_offload *ops); +/** @cond INTERNAL_HIDDEN */ + int socket_offload_getaddrinfo(const char *node, const char *service, const struct zsock_addrinfo *hints, struct zsock_addrinfo **res); void socket_offload_freeaddrinfo(struct zsock_addrinfo *res); +/** @endcond */ + #ifdef __cplusplus } #endif diff --git a/include/zephyr/net/socket_poll.h b/include/zephyr/net/socket_poll.h new file mode 100644 index 00000000000..97e03804311 --- /dev/null +++ b/include/zephyr/net/socket_poll.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_NET_SOCKET_POLL_H_ +#define ZEPHYR_INCLUDE_NET_SOCKET_POLL_H_ + +/* Setting for pollfd to avoid circular inclusion */ + +/** + * @brief BSD Sockets compatible API + * @defgroup bsd_sockets BSD Sockets compatible API + * @ingroup networking + * @{ + */ + +#ifdef __cplusplus +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; /**< Socket descriptor */ + short events; /**< Requested events */ + short revents; /**< Returned events */ +}; + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_NET_SOCKET_POLL_H_ */ diff --git a/include/zephyr/net/socket_select.h b/include/zephyr/net/socket_select.h index 1e7507711a1..d4cfef32cbc 100644 --- a/include/zephyr/net/socket_select.h +++ b/include/zephyr/net/socket_select.h @@ -4,6 +4,11 @@ * SPDX-License-Identifier: Apache-2.0 */ +/** @file socket_select.h + * + * @brief BSD select support functions. + */ + #ifndef ZEPHYR_INCLUDE_NET_SOCKET_SELECT_H_ #define ZEPHYR_INCLUDE_NET_SOCKET_SELECT_H_ @@ -21,10 +26,13 @@ extern "C" { #endif +/** @cond INTERNAL_HIDDEN */ + typedef struct zsock_fd_set { uint32_t bitset[(CONFIG_POSIX_MAX_FDS + 31) / 32]; } zsock_fd_set; +/** @endcond */ /** * @brief Legacy function to poll multiple sockets for events @@ -106,6 +114,8 @@ void ZSOCK_FD_CLR(int fd, zsock_fd_set *set); */ void ZSOCK_FD_SET(int fd, zsock_fd_set *set); +/** @cond INTERNAL_HIDDEN */ + #ifdef CONFIG_NET_SOCKETS_POSIX_NAMES #define fd_set zsock_fd_set @@ -140,6 +150,8 @@ static inline void FD_SET(int fd, zsock_fd_set *set) #endif /* CONFIG_NET_SOCKETS_POSIX_NAMES */ +/** @endcond */ + #ifdef __cplusplus } #endif diff --git a/include/zephyr/net/socket_service.h b/include/zephyr/net/socket_service.h index a4e21f00a33..b1037bf07c3 100644 --- a/include/zephyr/net/socket_service.h +++ b/include/zephyr/net/socket_service.h @@ -75,6 +75,8 @@ struct net_socket_service_desc { int *idx; }; +/** @cond INTERNAL_HIDDEN */ + #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__) @@ -110,6 +112,8 @@ extern void net_socket_service_callback(struct k_work *work); .idx = &__z_net_socket_svc_get_idx(_name), \ } +/** @endcond */ + /** * @brief Statically define a network socket service. * The user callback is called asynchronously for this service meaning that diff --git a/include/zephyr/net/socket_types.h b/include/zephyr/net/socket_types.h index 6195315e51a..0727dd77bdf 100644 --- a/include/zephyr/net/socket_types.h +++ b/include/zephyr/net/socket_types.h @@ -4,6 +4,11 @@ * SPDX-License-Identifier: Apache-2.0 */ +/** + * @file + * @brief socket types definitionis + */ + #ifndef ZEPHYR_INCLUDE_NET_SOCKET_TYPES_H_ #define ZEPHYR_INCLUDE_NET_SOCKET_TYPES_H_ @@ -16,6 +21,7 @@ #include +/** @cond INTERNAL_HIDDEN */ #ifdef CONFIG_NEWLIB_LIBC @@ -52,6 +58,8 @@ extern "C" { } #endif +/** @endcond */ + /** * @} */ diff --git a/include/zephyr/net/socketcan.h b/include/zephyr/net/socketcan.h index c4916487d99..dd2a7049288 100644 --- a/include/zephyr/net/socketcan.h +++ b/include/zephyr/net/socketcan.h @@ -28,9 +28,11 @@ extern "C" { * @{ */ -/* Protocols of the protocol family PF_CAN */ +/** Protocols of the protocol family PF_CAN */ #define CAN_RAW 1 +/** @cond INTERNAL_HIDDEN */ + /* SocketCAN options */ #define SOL_CAN_BASE 100 #define SOL_CAN_RAW (SOL_CAN_BASE + CAN_RAW) @@ -39,28 +41,35 @@ enum { CAN_RAW_FILTER = 1, }; +/** @endcond */ + /* SocketCAN MTU size compatible with Linux */ #ifdef CONFIG_CAN_FD_MODE +/** SocketCAN max data length */ #define SOCKETCAN_MAX_DLEN 64U +/** CAN FD frame MTU */ #define CANFD_MTU (sizeof(struct socketcan_frame)) +/** CAN frame MTU */ #define CAN_MTU (CANFD_MTU - 56U) #else /* CONFIG_CAN_FD_MODE */ +/** SocketCAN max data length */ #define SOCKETCAN_MAX_DLEN 8U +/** CAN frame MTU */ #define CAN_MTU (sizeof(struct socketcan_frame)) #endif /* !CONFIG_CAN_FD_MODE */ /* 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 */ +#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 */ /** * struct sockaddr_can - The sockaddr structure for CAN sockets * */ struct sockaddr_can { - sa_family_t can_family; - int can_ifindex; + sa_family_t can_family; /**< Address family */ + int can_ifindex; /**< SocketCAN network interface index */ }; /** diff --git a/include/zephyr/net/socketutils.h b/include/zephyr/net/socketutils.h index 7a7b862a7a7..b118f7531d9 100644 --- a/include/zephyr/net/socketutils.h +++ b/include/zephyr/net/socketutils.h @@ -4,6 +4,11 @@ * SPDX-License-Identifier: Apache-2.0 */ +/** + * @file + * @brief Socket utility functions. + */ + #ifndef ZEPHYR_INCLUDE_NET_SOCKETUTILS_H_ #define ZEPHYR_INCLUDE_NET_SOCKETUTILS_H_ diff --git a/include/zephyr/net/tftp.h b/include/zephyr/net/tftp.h index 61db441e548..eb3df0cc0c1 100644 --- a/include/zephyr/net/tftp.h +++ b/include/zephyr/net/tftp.h @@ -5,11 +5,12 @@ */ /** @file tftp.h + * + * @brief TFTP Client Implementation * * @defgroup tftp_client TFTP Client library * @ingroup networking * @{ - * @brief TFTP Client Implementation */ #ifndef ZEPHYR_INCLUDE_NET_TFTP_H_ diff --git a/include/zephyr/net/trickle.h b/include/zephyr/net/trickle.h index fb6ee8f74be..9d46ffa0b91 100644 --- a/include/zephyr/net/trickle.h +++ b/include/zephyr/net/trickle.h @@ -60,11 +60,11 @@ struct net_trickle { uint8_t k; /**< Redundancy constant */ uint8_t c; /**< Consistency counter */ - bool double_to; + bool double_to; /**< Flag telling if the internval is doubled */ - struct k_work_delayable timer; + struct k_work_delayable timer; /**< Internal timer struct */ net_trickle_cb_t cb; /**< Callback to be called when timer expires */ - void *user_data; + void *user_data; /**< User specific opaque data */ }; /** @cond INTERNAL_HIDDEN */ diff --git a/include/zephyr/net/virtual.h b/include/zephyr/net/virtual.h index d64bab15577..806665296f9 100644 --- a/include/zephyr/net/virtual.h +++ b/include/zephyr/net/virtual.h @@ -81,6 +81,7 @@ struct virtual_interface_config { #endif /** @endcond */ +/** Virtual L2 API operations. */ struct virtual_interface_api { /** * The net_if_api must be placed in first position in this diff --git a/include/zephyr/net/websocket.h b/include/zephyr/net/websocket.h index 1a0853891a0..3b2d9dddd67 100644 --- a/include/zephyr/net/websocket.h +++ b/include/zephyr/net/websocket.h @@ -38,13 +38,14 @@ extern "C" { #define WEBSOCKET_FLAG_PING 0x00000010 /**< Ping message */ #define WEBSOCKET_FLAG_PONG 0x00000020 /**< Pong message */ +/** @brief Websocket option codes */ enum websocket_opcode { - WEBSOCKET_OPCODE_CONTINUE = 0x00, - WEBSOCKET_OPCODE_DATA_TEXT = 0x01, - WEBSOCKET_OPCODE_DATA_BINARY = 0x02, - WEBSOCKET_OPCODE_CLOSE = 0x08, - WEBSOCKET_OPCODE_PING = 0x09, - WEBSOCKET_OPCODE_PONG = 0x0A, + WEBSOCKET_OPCODE_CONTINUE = 0x00, /**< Message continues */ + WEBSOCKET_OPCODE_DATA_TEXT = 0x01, /**< Textual data */ + WEBSOCKET_OPCODE_DATA_BINARY = 0x02, /**< Binary data */ + WEBSOCKET_OPCODE_CLOSE = 0x08, /**< Closing connection */ + WEBSOCKET_OPCODE_PING = 0x09, /**< Ping message */ + WEBSOCKET_OPCODE_PONG = 0x0A, /**< Pong message */ }; /** @@ -182,9 +183,38 @@ int websocket_recv_msg(int ws_sock, uint8_t *buf, size_t buf_len, * the connection. * * @param ws_sock Websocket id returned by websocket_connect(). + * + * @return <0 if error, 0 the connection was closed successfully */ int websocket_disconnect(int ws_sock); +/** + * @brief Register a socket as websocket. This is called by HTTP server + * when a connection is upgraded to a websocket connection. + * + * @param http_sock Underlying socket connection socket. + * @param recv_buf Temporary receive buffer for websocket parsing. This must + * point to a memory area that is valid for the duration of the whole + * websocket session. + * @param recv_buf_len Length of the temporary receive buffer. + * + * @return <0 if error, >=0 the actual websocket to be used by application + */ +int websocket_register(int http_sock, uint8_t *recv_buf, size_t recv_buf_len); + +/** + * @brief Unregister a websocket. This is called when we no longer need + * the underlaying "real" socket. This will close first the websocket + * and then the original socket. + * + * @param ws_sock Websocket connection socket. + * + * @return <0 if error, 0 the websocket connection is now fully closed + */ +int websocket_unregister(int ws_sock); + +/** @cond INTERNAL_HIDDEN */ + #if defined(CONFIG_WEBSOCKET_CLIENT) void websocket_init(void); #else @@ -193,6 +223,8 @@ static inline void websocket_init(void) } #endif +/** @endcond */ + #ifdef __cplusplus } #endif diff --git a/include/zephyr/net/wifi.h b/include/zephyr/net/wifi.h index ebfc76d2192..5f47209b83f 100644 --- a/include/zephyr/net/wifi.h +++ b/include/zephyr/net/wifi.h @@ -22,16 +22,21 @@ #include /* for ARRAY_SIZE */ +/** Length of the country code string */ #define WIFI_COUNTRY_CODE_LEN 2 +/** @cond INTERNAL_HIDDEN */ + #define WIFI_LISTEN_INTERVAL_MIN 0 #define WIFI_LISTEN_INTERVAL_MAX 65535 +/** @endcond */ + #ifdef __cplusplus extern "C" { #endif -/** IEEE 802.11 security types. */ +/** @brief IEEE 802.11 security types. */ enum wifi_security_type { /** No security. */ WIFI_SECURITY_TYPE_NONE = 0, @@ -52,15 +57,17 @@ enum wifi_security_type { /** WPA/WPA2/WPA3 PSK security. */ WIFI_SECURITY_TYPE_WPA_AUTO_PERSONAL, +/** @cond INTERNAL_HIDDEN */ __WIFI_SECURITY_TYPE_AFTER_LAST, WIFI_SECURITY_TYPE_MAX = __WIFI_SECURITY_TYPE_AFTER_LAST - 1, WIFI_SECURITY_TYPE_UNKNOWN +/** @endcond */ }; /** Helper function to get user-friendly security type name. */ const char *wifi_security_txt(enum wifi_security_type security); -/** IEEE 802.11w - Management frame protection. */ +/** @brief IEEE 802.11w - Management frame protection. */ enum wifi_mfp_options { /** MFP disabled. */ WIFI_MFP_DISABLE = 0, @@ -69,9 +76,11 @@ enum wifi_mfp_options { /** MFP required. */ WIFI_MFP_REQUIRED, +/** @cond INTERNAL_HIDDEN */ __WIFI_MFP_AFTER_LAST, WIFI_MFP_MAX = __WIFI_MFP_AFTER_LAST - 1, WIFI_MFP_UNKNOWN +/** @endcond */ }; /** Helper function to get user-friendly MFP name.*/ @@ -99,17 +108,25 @@ enum wifi_frequency_bands { /** Helper function to get user-friendly frequency band name. */ const char *wifi_band_txt(enum wifi_frequency_bands band); +/** Max SSID length */ #define WIFI_SSID_MAX_LEN 32 +/** Minimum PSK length */ #define WIFI_PSK_MIN_LEN 8 +/** Maximum PSK length */ #define WIFI_PSK_MAX_LEN 64 +/** Max SAW password length */ #define WIFI_SAE_PSWD_MAX_LEN 128 +/** MAC address length */ #define WIFI_MAC_ADDR_LEN 6 +/** Minimum channel number */ #define WIFI_CHANNEL_MIN 1 +/** Maximum channel number */ #define WIFI_CHANNEL_MAX 233 +/** Any channel number */ #define WIFI_CHANNEL_ANY 255 -/** Wi-Fi interface states. +/** @brief Wi-Fi interface states. * * Based on https://w1.fi/wpa_supplicant/devel/defs_8h.html#a4aeb27c1e4abd046df3064ea9756f0bc */ @@ -135,9 +152,11 @@ enum wifi_iface_state { /** All authentication completed, ready to pass data. */ WIFI_STATE_COMPLETED, +/** @cond INTERNAL_HIDDEN */ __WIFI_STATE_AFTER_LAST, WIFI_STATE_MAX = __WIFI_STATE_AFTER_LAST - 1, WIFI_STATE_UNKNOWN +/** @endcond */ }; /* We rely on the strict order of the enum values, so, let's check it */ @@ -155,7 +174,7 @@ BUILD_ASSERT(WIFI_STATE_DISCONNECTED < WIFI_STATE_INTERFACE_DISABLED && /** Helper function to get user-friendly interface state name. */ const char *wifi_state_txt(enum wifi_iface_state state); -/** Wi-Fi interface modes. +/** @brief Wi-Fi interface modes. * * Based on https://w1.fi/wpa_supplicant/devel/defs_8h.html#a4aeb27c1e4abd046df3064ea9756f0bc */ @@ -173,15 +192,17 @@ enum wifi_iface_mode { /** 802.11s Mesh mode. */ WIFI_MODE_MESH = 5, +/** @cond INTERNAL_HIDDEN */ __WIFI_MODE_AFTER_LAST, WIFI_MODE_MAX = __WIFI_MODE_AFTER_LAST - 1, WIFI_MODE_UNKNOWN +/** @endcond */ }; /** Helper function to get user-friendly interface mode name. */ const char *wifi_mode_txt(enum wifi_iface_mode mode); -/** Wi-Fi link operating modes +/** @brief Wi-Fi link operating modes * * As per https://en.wikipedia.org/wiki/Wi-Fi#Versions_and_generations. */ @@ -205,15 +226,17 @@ enum wifi_link_mode { /** 802.11be. */ WIFI_7, +/** @cond INTERNAL_HIDDEN */ __WIFI_LINK_MODE_AFTER_LAST, WIFI_LINK_MODE_MAX = __WIFI_LINK_MODE_AFTER_LAST - 1, WIFI_LINK_MODE_UNKNOWN +/** @endcond */ }; /** Helper function to get user-friendly link mode name. */ const char *wifi_link_mode_txt(enum wifi_link_mode link_mode); -/** Wi-Fi scanning types. */ +/** @brief Wi-Fi scanning types. */ enum wifi_scan_type { /** Active scanning (default). */ WIFI_SCAN_TYPE_ACTIVE = 0, @@ -221,7 +244,7 @@ enum wifi_scan_type { WIFI_SCAN_TYPE_PASSIVE, }; -/** Wi-Fi power save states. */ +/** @brief Wi-Fi power save states. */ enum wifi_ps { /** Power save disabled. */ WIFI_PS_DISABLED = 0, @@ -232,7 +255,7 @@ enum wifi_ps { /** Helper function to get user-friendly ps name. */ const char *wifi_ps_txt(enum wifi_ps ps_name); -/** Wi-Fi power save modes. */ +/** @brief Wi-Fi power save modes. */ enum wifi_ps_mode { /** Legacy power save mode. */ WIFI_PS_MODE_LEGACY = 0, @@ -246,11 +269,12 @@ enum wifi_ps_mode { /** Helper function to get user-friendly ps mode name. */ const char *wifi_ps_mode_txt(enum wifi_ps_mode ps_mode); -/* Interface index Min and Max values */ +/** Network interface index min value */ #define WIFI_INTERFACE_INDEX_MIN 1 +/** Network interface index max value */ #define WIFI_INTERFACE_INDEX_MAX 255 -/** Wifi operational mode */ +/** @brief Wifi operational mode */ enum wifi_operational_modes { /** STA mode setting enable */ WIFI_STA_MODE = BIT(0), @@ -266,7 +290,7 @@ enum wifi_operational_modes { WIFI_SOFTAP_MODE = BIT(5), }; -/** Mode filter settings */ +/** @brief Mode filter settings */ enum wifi_filter { /** Support management, data and control packet sniffing */ WIFI_PACKET_FILTER_ALL = BIT(0), @@ -278,7 +302,7 @@ enum wifi_filter { WIFI_PACKET_FILTER_CTRL = BIT(3), }; -/** Wi-Fi Target Wake Time (TWT) operations. */ +/** @brief Wi-Fi Target Wake Time (TWT) operations. */ enum wifi_twt_operation { /** TWT setup operation */ WIFI_TWT_SETUP = 0, @@ -289,7 +313,7 @@ enum wifi_twt_operation { /** Helper function to get user-friendly twt operation name. */ const char *wifi_twt_operation_txt(enum wifi_twt_operation twt_operation); -/** Wi-Fi Target Wake Time (TWT) negotiation types. */ +/** @brief Wi-Fi Target Wake Time (TWT) negotiation types. */ enum wifi_twt_negotiation_type { /** TWT individual negotiation */ WIFI_TWT_INDIVIDUAL = 0, @@ -302,7 +326,7 @@ enum wifi_twt_negotiation_type { /** Helper function to get user-friendly twt negotiation type name. */ const char *wifi_twt_negotiation_type_txt(enum wifi_twt_negotiation_type twt_negotiation); -/** Wi-Fi Target Wake Time (TWT) setup commands. */ +/** @brief Wi-Fi Target Wake Time (TWT) setup commands. */ enum wifi_twt_setup_cmd { /** TWT setup request */ WIFI_TWT_SETUP_CMD_REQUEST = 0, @@ -325,7 +349,7 @@ enum wifi_twt_setup_cmd { /** Helper function to get user-friendly twt setup cmd name. */ const char *wifi_twt_setup_cmd_txt(enum wifi_twt_setup_cmd twt_setup); -/** Wi-Fi Target Wake Time (TWT) negotiation status. */ +/** @brief Wi-Fi Target Wake Time (TWT) negotiation status. */ enum wifi_twt_setup_resp_status { /** TWT response received for TWT request */ WIFI_TWT_RESP_RECEIVED = 0, @@ -333,7 +357,7 @@ enum wifi_twt_setup_resp_status { WIFI_TWT_RESP_NOT_RECEIVED, }; -/** Target Wake Time (TWT) error codes. */ +/** @brief Target Wake Time (TWT) error codes. */ enum wifi_twt_fail_reason { /** Unspecified error */ WIFI_TWT_FAIL_UNSPECIFIED, @@ -359,7 +383,7 @@ enum wifi_twt_fail_reason { WIFI_TWT_FAIL_FLOW_ALREADY_EXISTS, }; -/** Wi-Fi Target Wake Time (TWT) teradown status. */ +/** @brief Wi-Fi Target Wake Time (TWT) teradown status. */ enum wifi_twt_teardown_status { /** TWT teardown success */ WIFI_TWT_TEARDOWN_SUCCESS = 0, @@ -400,7 +424,7 @@ static inline const char *wifi_twt_get_err_code_str(int16_t err_no) return ""; } -/** Wi-Fi power save parameters. */ +/** @brief Wi-Fi power save parameters. */ enum wifi_ps_param_type { /** Power save state. */ WIFI_PS_PARAM_STATE, @@ -414,7 +438,7 @@ enum wifi_ps_param_type { WIFI_PS_PARAM_TIMEOUT, }; -/** Wi-Fi power save modes. */ +/** @brief Wi-Fi power save modes. */ enum wifi_ps_wakeup_mode { /** DTIM based wakeup. */ WIFI_PS_WAKEUP_MODE_DTIM = 0, @@ -425,7 +449,7 @@ enum wifi_ps_wakeup_mode { /** Helper function to get user-friendly ps wakeup mode name. */ const char *wifi_ps_wakeup_mode_txt(enum wifi_ps_wakeup_mode ps_wakeup_mode); -/** Wi-Fi power save error codes. */ +/** @brief Wi-Fi power save error codes. */ enum wifi_config_ps_param_fail_reason { /** Unspecified error */ WIFI_PS_PARAM_FAIL_UNSPECIFIED, diff --git a/include/zephyr/net/wifi_mgmt.h b/include/zephyr/net/wifi_mgmt.h index 70fd5978fba..8c2b61fa936 100644 --- a/include/zephyr/net/wifi_mgmt.h +++ b/include/zephyr/net/wifi_mgmt.h @@ -28,6 +28,8 @@ extern "C" { /* Management part definitions */ +/** @cond INTERNAL_HIDDEN */ + #define _NET_WIFI_LAYER NET_MGMT_LAYER_L2 #define _NET_WIFI_CODE 0x156 #define _NET_WIFI_BASE (NET_MGMT_IFACE_BIT | \ @@ -50,7 +52,9 @@ extern "C" { #define WIFI_MGMT_BAND_STR_SIZE_MAX 8 #define WIFI_MGMT_SCAN_MAX_BSS_CNT 65535 -/** Wi-Fi management commands */ +/** @endcond */ + +/** @brief Wi-Fi management commands */ enum net_request_wifi_cmd { /** Scan for Wi-Fi networks */ NET_REQUEST_WIFI_CMD_SCAN = 1, @@ -84,88 +88,109 @@ enum net_request_wifi_cmd { NET_REQUEST_WIFI_CMD_VERSION, /** Set RTS threshold */ NET_REQUEST_WIFI_CMD_RTS_THRESHOLD, + +/** @cond INTERNAL_HIDDEN */ NET_REQUEST_WIFI_CMD_MAX +/** @endcond */ }; +/** Request a Wi-Fi scan */ #define NET_REQUEST_WIFI_SCAN \ (_NET_WIFI_BASE | NET_REQUEST_WIFI_CMD_SCAN) NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_SCAN); +/** Request a Wi-Fi connect */ #define NET_REQUEST_WIFI_CONNECT \ (_NET_WIFI_BASE | NET_REQUEST_WIFI_CMD_CONNECT) NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_CONNECT); +/** Request a Wi-Fi disconnect */ #define NET_REQUEST_WIFI_DISCONNECT \ (_NET_WIFI_BASE | NET_REQUEST_WIFI_CMD_DISCONNECT) NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_DISCONNECT); +/** Request a Wi-Fi access point enable */ #define NET_REQUEST_WIFI_AP_ENABLE \ (_NET_WIFI_BASE | NET_REQUEST_WIFI_CMD_AP_ENABLE) NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_AP_ENABLE); +/** Request a Wi-Fi access point disable */ #define NET_REQUEST_WIFI_AP_DISABLE \ (_NET_WIFI_BASE | NET_REQUEST_WIFI_CMD_AP_DISABLE) NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_AP_DISABLE); +/** Request a Wi-Fi network interface status */ #define NET_REQUEST_WIFI_IFACE_STATUS \ (_NET_WIFI_BASE | NET_REQUEST_WIFI_CMD_IFACE_STATUS) NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_IFACE_STATUS); -#define NET_REQUEST_WIFI_PS \ +/** Request a Wi-Fi power save */ +#define NET_REQUEST_WIFI_PS \ (_NET_WIFI_BASE | NET_REQUEST_WIFI_CMD_PS) NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_PS); -#define NET_REQUEST_WIFI_TWT \ +/** Request a Wi-Fi TWT */ +#define NET_REQUEST_WIFI_TWT \ (_NET_WIFI_BASE | NET_REQUEST_WIFI_CMD_TWT) NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_TWT); +/** Request a Wi-Fi power save configuration */ #define NET_REQUEST_WIFI_PS_CONFIG \ (_NET_WIFI_BASE | NET_REQUEST_WIFI_CMD_PS_CONFIG) NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_PS_CONFIG); + +/** Request a Wi-Fi regulatory domain */ #define NET_REQUEST_WIFI_REG_DOMAIN \ (_NET_WIFI_BASE | NET_REQUEST_WIFI_CMD_REG_DOMAIN) NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_REG_DOMAIN); -#define NET_REQUEST_WIFI_MODE \ +/** Request current Wi-Fi mode */ +#define NET_REQUEST_WIFI_MODE \ (_NET_WIFI_BASE | NET_REQUEST_WIFI_CMD_MODE) NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_MODE); -#define NET_REQUEST_WIFI_PACKET_FILTER \ +/** Request Wi-Fi packet filter */ +#define NET_REQUEST_WIFI_PACKET_FILTER \ (_NET_WIFI_BASE | NET_REQUEST_WIFI_CMD_PACKET_FILTER) NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_PACKET_FILTER); -#define NET_REQUEST_WIFI_CHANNEL \ +/** Request a Wi-Fi channel */ +#define NET_REQUEST_WIFI_CHANNEL \ (_NET_WIFI_BASE | NET_REQUEST_WIFI_CMD_CHANNEL) NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_CHANNEL); +/** Request a Wi-Fi access point to disconnect a station */ #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 \ +/** Request a Wi-Fi version */ +#define NET_REQUEST_WIFI_VERSION \ (_NET_WIFI_BASE | NET_REQUEST_WIFI_CMD_VERSION) NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_VERSION); -#define NET_REQUEST_WIFI_RTS_THRESHOLD \ +/** Request a Wi-Fi RTS threashold */ +#define NET_REQUEST_WIFI_RTS_THRESHOLD \ (_NET_WIFI_BASE | NET_REQUEST_WIFI_CMD_RTS_THRESHOLD) NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_RTS_THRESHOLD); -/** Wi-Fi management events */ + +/** @brief Wi-Fi management events */ enum net_event_wifi_cmd { /** Scan results available */ NET_EVENT_WIFI_CMD_SCAN_RESULT = 1, @@ -197,46 +222,59 @@ enum net_event_wifi_cmd { NET_EVENT_WIFI_CMD_AP_STA_DISCONNECTED, }; +/** Event emitted for Wi-Fi scan result */ #define NET_EVENT_WIFI_SCAN_RESULT \ (_NET_WIFI_EVENT | NET_EVENT_WIFI_CMD_SCAN_RESULT) +/** Event emitted when Wi-Fi scan is done */ #define NET_EVENT_WIFI_SCAN_DONE \ (_NET_WIFI_EVENT | NET_EVENT_WIFI_CMD_SCAN_DONE) +/** Event emitted for Wi-Fi connect result */ #define NET_EVENT_WIFI_CONNECT_RESULT \ (_NET_WIFI_EVENT | NET_EVENT_WIFI_CMD_CONNECT_RESULT) +/** Event emitted for Wi-Fi disconnect result */ #define NET_EVENT_WIFI_DISCONNECT_RESULT \ (_NET_WIFI_EVENT | NET_EVENT_WIFI_CMD_DISCONNECT_RESULT) -#define NET_EVENT_WIFI_IFACE_STATUS \ +/** Event emitted for Wi-Fi network interface status */ +#define NET_EVENT_WIFI_IFACE_STATUS \ (_NET_WIFI_EVENT | NET_EVENT_WIFI_CMD_IFACE_STATUS) +/** Event emitted for Wi-Fi TWT information */ #define NET_EVENT_WIFI_TWT \ (_NET_WIFI_EVENT | NET_EVENT_WIFI_CMD_TWT) +/** Event emitted for Wi-Fi TWT sleep state */ #define NET_EVENT_WIFI_TWT_SLEEP_STATE \ (_NET_WIFI_EVENT | NET_EVENT_WIFI_CMD_TWT_SLEEP_STATE) +/** Event emitted for Wi-Fi raw scan result */ #define NET_EVENT_WIFI_RAW_SCAN_RESULT \ (_NET_WIFI_EVENT | NET_EVENT_WIFI_CMD_RAW_SCAN_RESULT) +/** Event emitted Wi-Fi disconnect is completed */ #define NET_EVENT_WIFI_DISCONNECT_COMPLETE \ (_NET_WIFI_EVENT | NET_EVENT_WIFI_CMD_DISCONNECT_COMPLETE) +/** Event emitted for Wi-Fi access point enable result */ #define NET_EVENT_WIFI_AP_ENABLE_RESULT \ (_NET_WIFI_EVENT | NET_EVENT_WIFI_CMD_AP_ENABLE_RESULT) +/** Event emitted for Wi-Fi access point disable result */ #define NET_EVENT_WIFI_AP_DISABLE_RESULT \ (_NET_WIFI_EVENT | NET_EVENT_WIFI_CMD_AP_DISABLE_RESULT) +/** Event emitted when Wi-Fi station is connected in AP mode */ #define NET_EVENT_WIFI_AP_STA_CONNECTED \ (_NET_WIFI_EVENT | NET_EVENT_WIFI_CMD_AP_STA_CONNECTED) +/** Event emitted Wi-Fi station is disconnected from AP */ #define NET_EVENT_WIFI_AP_STA_DISCONNECTED \ (_NET_WIFI_EVENT | NET_EVENT_WIFI_CMD_AP_STA_DISCONNECTED) -/** Wi-Fi version */ +/** @brief Wi-Fi version */ struct wifi_version { /** Driver version */ const char *drv_version; @@ -306,7 +344,7 @@ struct wifi_scan_params { struct wifi_band_channel band_chan[WIFI_MGMT_SCAN_CHAN_MAX_MANUAL]; }; -/** Wi-Fi scan result, each result is provided to the net_mgmt_event_callback +/** @brief Wi-Fi scan result, each result is provided to the net_mgmt_event_callback * via its info attribute (see net_mgmt.h) */ struct wifi_scan_result { @@ -330,7 +368,7 @@ struct wifi_scan_result { uint8_t mac_length; }; -/** Wi-Fi connect request parameters */ +/** @brief Wi-Fi connect request parameters */ struct wifi_connect_req_params { /** SSID */ const uint8_t *ssid; @@ -358,7 +396,7 @@ struct wifi_connect_req_params { int timeout; }; -/** Wi-Fi connect result codes. To be overlaid on top of \ref wifi_status +/** @brief 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 { @@ -385,12 +423,14 @@ enum wifi_conn_status { WIFI_STATUS_DISCONN_FIRST_STATUS = WIFI_STATUS_CONN_LAST_STATUS, }; -/** Wi-Fi disconnect reason codes. To be overlaid on top of \ref wifi_status +/** @brief 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 { + /** Success, overload status as reason */ + WIFI_REASON_DISCONN_SUCCESS = 0, /** Unspecified reason */ - WIFI_REASON_DISCONN_UNSPECIFIED = WIFI_STATUS_DISCONN_FIRST_STATUS, + WIFI_REASON_DISCONN_UNSPECIFIED, /** Disconnected due to user request */ WIFI_REASON_DISCONN_USER_REQUEST, /** Disconnected due to AP leaving */ @@ -399,7 +439,7 @@ enum wifi_disconn_reason { WIFI_REASON_DISCONN_INACTIVITY, }; -/** Wi-Fi AP mode result codes. To be overlaid on top of \ref wifi_status +/** @brief 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 { @@ -421,17 +461,21 @@ enum wifi_ap_status { WIFI_STATUS_AP_OP_NOT_PERMITTED, }; -/** Generic Wi-Fi status for commands and events */ +/** @brief Generic Wi-Fi status for commands and events */ struct wifi_status { union { + /** Status value */ int status; + /** Connection status */ enum wifi_conn_status conn_status; + /** Disconnection reason status */ enum wifi_disconn_reason disconn_reason; + /** Access point status */ enum wifi_ap_status ap_status; }; }; -/** Wi-Fi interface status */ +/** @brief Wi-Fi interface status */ struct wifi_iface_status { /** Interface state, see enum wifi_iface_state */ int state; @@ -463,11 +507,11 @@ struct wifi_iface_status { bool twt_capable; }; -/** Wi-Fi power save parameters */ +/** @brief Wi-Fi power save parameters */ struct wifi_ps_params { - /* Power save state */ + /** Power save state */ enum wifi_ps enabled; - /* Listen interval */ + /** Listen interval */ unsigned short listen_interval; /** Wi-Fi power save wakeup mode */ enum wifi_ps_wakeup_mode wakeup_mode; @@ -488,7 +532,7 @@ struct wifi_ps_params { enum wifi_config_ps_param_fail_reason fail_reason; }; -/** Wi-Fi TWT parameters */ +/** @brief Wi-Fi TWT parameters */ struct wifi_twt_params { /** TWT operation, see enum wifi_twt_operation */ enum wifi_twt_operation operation; @@ -519,7 +563,7 @@ struct wifi_twt_params { bool announce; /** Wake up time */ uint32_t twt_wake_interval; - /* Wake ahead notification is sent earlier than + /** 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. @@ -536,6 +580,8 @@ struct wifi_twt_params { enum wifi_twt_fail_reason fail_reason; }; +/** @cond INTERNAL_HIDDEN */ + /* Flow ID is only 3 bits */ #define WIFI_MAX_TWT_FLOWS 8 #define WIFI_MAX_TWT_INTERVAL_US (LONG_MAX - 1) @@ -543,7 +589,9 @@ struct wifi_twt_params { #define WIFI_MAX_TWT_WAKE_INTERVAL_US 262144 #define WIFI_MAX_TWT_WAKE_AHEAD_DURATION_US (LONG_MAX - 1) -/** Wi-Fi TWT flow information */ +/** @endcond */ + +/** @brief Wi-Fi TWT flow information */ struct wifi_twt_flow_info { /** Interval = Wake up time + Sleeping time */ uint64_t twt_interval; @@ -563,11 +611,11 @@ struct wifi_twt_flow_info { bool announce; /** Wake up time */ uint32_t twt_wake_interval; - /* wake ahead duration */ + /** Wake ahead duration */ uint32_t twt_wake_ahead_duration; }; -/** Wi-Fi power save configuration */ +/** @brief Wi-Fi power save configuration */ struct wifi_ps_config { /** Number of TWT flows */ char num_twt_flows; @@ -577,7 +625,7 @@ struct wifi_ps_config { struct wifi_ps_params ps_params; }; -/** Generic get/set operation for any command*/ +/** @brief Generic get/set operation for any command*/ enum wifi_mgmt_op { /** Get operation */ WIFI_MGMT_GET = 0, @@ -585,9 +633,10 @@ enum wifi_mgmt_op { WIFI_MGMT_SET = 1, }; +/** Max regulatory channel number */ #define MAX_REG_CHAN_NUM 42 -/** Per-channel regulatory attributes */ +/** @brief Per-channel regulatory attributes */ struct wifi_reg_chan_info { /** Center frequency in MHz */ unsigned short center_frequency; @@ -601,9 +650,9 @@ struct wifi_reg_chan_info { unsigned short dfs:1; } __packed; -/** Regulatory domain information or configuration */ +/** @brief Regulatory domain information or configuration */ struct wifi_reg_domain { - /* Regulatory domain operation */ + /** Regulatory domain operation */ enum wifi_mgmt_op oper; /** Ignore all other regulatory hints over this one */ bool force; @@ -615,7 +664,7 @@ struct wifi_reg_domain { struct wifi_reg_chan_info *chan_info; }; -/** Wi-Fi TWT sleep states */ +/** @brief Wi-Fi TWT sleep states */ enum wifi_twt_sleep_state { /** TWT sleep state: sleeping */ WIFI_TWT_STATE_SLEEP = 0, @@ -624,7 +673,7 @@ enum wifi_twt_sleep_state { }; #if defined(CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS) || defined(__DOXYGEN__) -/** Wi-Fi raw scan result */ +/** @brief Wi-Fi raw scan result */ struct wifi_raw_scan_result { /** RSSI */ int8_t rssi; @@ -637,7 +686,7 @@ struct wifi_raw_scan_result { }; #endif /* CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS */ -/** AP mode - connected STA details */ +/** @brief AP mode - connected STA details */ struct wifi_ap_sta_info { /** Link mode, see enum wifi_link_mode */ enum wifi_link_mode link_mode; @@ -649,6 +698,8 @@ struct wifi_ap_sta_info { bool twt_capable; }; +/** @cond INTERNAL_HIDDEN */ + /* for use in max info size calculations */ union wifi_mgmt_events { struct wifi_scan_result scan_result; @@ -661,7 +712,9 @@ union wifi_mgmt_events { struct wifi_ap_sta_info ap_sta_info; }; -/** Wi-Fi mode setup */ +/** @endcond */ + +/** @brief Wi-Fi mode setup */ struct wifi_mode_info { /** Mode setting for a specific mode of operation */ uint8_t mode; @@ -671,7 +724,7 @@ struct wifi_mode_info { enum wifi_mgmt_op oper; }; -/** Wi-Fi filter setting for monitor, prmoiscuous, TX-injection modes */ +/** @brief Wi-Fi filter setting for monitor, prmoiscuous, TX-injection modes */ struct wifi_filter_info { /** Filter setting */ uint8_t filter; @@ -683,7 +736,7 @@ struct wifi_filter_info { enum wifi_mgmt_op oper; }; -/** Wi-Fi channel setting for monitor and TX-injection modes */ +/** @brief Wi-Fi channel setting for monitor and TX-injection modes */ struct wifi_channel_info { /** Channel value to set */ uint16_t channel; diff --git a/include/zephyr/net/wifi_nm.h b/include/zephyr/net/wifi_nm.h index dd97fcdd8b6..615d4915757 100644 --- a/include/zephyr/net/wifi_nm.h +++ b/include/zephyr/net/wifi_nm.h @@ -42,6 +42,8 @@ struct wifi_nm_instance { struct net_if *mgd_ifaces[CONFIG_WIFI_NM_MAX_MANAGED_INTERFACES]; }; +/** @cond INTERNAL_HIDDEN */ + #define WIFI_NM_NAME(name) wifi_nm_##name #define DEFINE_WIFI_NM_INSTANCE(_name, _ops) \ @@ -51,6 +53,8 @@ struct wifi_nm_instance { .mgd_ifaces = { NULL }, \ } +/** @endcond */ + /** * @brief Get a Network manager instance for a given name * diff --git a/include/zephyr/net/wifi_utils.h b/include/zephyr/net/wifi_utils.h index 537db787648..511d2033532 100644 --- a/include/zephyr/net/wifi_utils.h +++ b/include/zephyr/net/wifi_utils.h @@ -28,7 +28,10 @@ extern "C" { * @{ */ +/** Maximum length of the band specification string */ #define WIFI_UTILS_MAX_BAND_STR_LEN 3 + +/** Maximum length of the channel specification string */ #define WIFI_UTILS_MAX_CHAN_STR_LEN 4 /** diff --git a/include/zephyr/net/zperf.h b/include/zephyr/net/zperf.h index a6290483300..c97c9d01439 100644 --- a/include/zephyr/net/zperf.h +++ b/include/zephyr/net/zperf.h @@ -24,8 +24,11 @@ extern "C" { #endif +/** @cond INTERNAL_HIDDEN */ + enum zperf_status { ZPERF_SESSION_STARTED, + ZPERF_SESSION_PERIODIC_RESULT, ZPERF_SESSION_FINISHED, ZPERF_SESSION_ERROR } __packed; @@ -40,6 +43,7 @@ struct zperf_upload_params { uint8_t tos; int tcp_nodelay; int priority; + uint32_t report_interval_ms; } options; }; @@ -49,17 +53,20 @@ struct zperf_download_params { char if_name[IFNAMSIZ]; }; +/** @endcond */ + +/** Performance results */ struct zperf_results { - uint32_t nb_packets_sent; - uint32_t nb_packets_rcvd; - uint32_t nb_packets_lost; - uint32_t nb_packets_outorder; - uint64_t total_len; - uint64_t time_in_us; - uint32_t jitter_in_us; - uint64_t client_time_in_us; - uint32_t packet_size; - uint32_t nb_packets_errors; + uint32_t nb_packets_sent; /**< Number of packets sent */ + uint32_t nb_packets_rcvd; /**< Number of packets received */ + uint32_t nb_packets_lost; /**< Number of packets lost */ + uint32_t nb_packets_outorder; /**< Number of packets out of order */ + uint64_t total_len; /**< Total length of the transferred data */ + uint64_t time_in_us; /**< Total time of the transfer in microseconds */ + uint32_t jitter_in_us; /**< Jitter in microseconds */ + uint64_t client_time_in_us; /**< Client connection time in microseconds */ + uint32_t packet_size; /**< Packet size */ + uint32_t nb_packets_errors; /**< Number of packet errors */ }; /** diff --git a/include/zephyr/pm/device_runtime.h b/include/zephyr/pm/device_runtime.h index 3510a910f3a..fde8f631ca2 100644 --- a/include/zephyr/pm/device_runtime.h +++ b/include/zephyr/pm/device_runtime.h @@ -48,7 +48,7 @@ int pm_device_runtime_auto_enable(const struct device *dev); * @param dev Device instance. * * @retval 0 If the device runtime PM is enabled successfully. - * @retval -EPERM If device has power state locked. + * @retval -EBUSY If device is busy. * @retval -ENOTSUP If the device does not support PM. * @retval -errno Other negative errno, result of suspending the device. * @@ -158,6 +158,17 @@ int pm_device_runtime_put_async(const struct device *dev, k_timeout_t delay); */ bool pm_device_runtime_is_enabled(const struct device *dev); +/** + * @brief Return the current device usage counter. + * + * @param dev Device instance. + * + * @returns the current usage counter. + * @retval -ENOTSUP If the device is not using runtime PM. + * @retval -ENOSYS If the runtime PM is not enabled at all. + */ +int pm_device_runtime_usage(const struct device *dev); + #else static inline int pm_device_runtime_auto_enable(const struct device *dev) @@ -204,6 +215,12 @@ static inline bool pm_device_runtime_is_enabled(const struct device *dev) return false; } +static inline int pm_device_runtime_usage(const struct device *dev) +{ + ARG_UNUSED(dev); + return -ENOSYS; +} + #endif /** @} */ diff --git a/include/zephyr/posix/aio.h b/include/zephyr/posix/aio.h new file mode 100644 index 00000000000..8645ff801c1 --- /dev/null +++ b/include/zephyr/posix/aio.h @@ -0,0 +1,46 @@ +/* + * Copyright 2024 Tenstorrent AI ULC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_ZEPHYR_POSIX_AIO_H_ +#define ZEPHYR_INCLUDE_ZEPHYR_POSIX_AIO_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct aiocb { + int aio_fildes; + off_t aio_offset; + volatile void *aio_buf; + size_t aio_nbytes; + int aio_reqprio; + struct sigevent aio_sigevent; + int aio_lio_opcode; +}; + +#if _POSIX_C_SOURCE >= 200112L + +int aio_cancel(int fildes, struct aiocb *aiocbp); +int aio_error(const struct aiocb *aiocbp); +int aio_fsync(int filedes, struct aiocb *aiocbp); +int aio_read(struct aiocb *aiocbp); +ssize_t aio_return(struct aiocb *aiocbp); +int aio_suspend(const struct aiocb *const list[], int nent, const struct timespec *timeout); +int aio_write(struct aiocb *aiocbp); +int lio_listio(int mode, struct aiocb *const ZRESTRICT list[], int nent, + struct sigevent *ZRESTRICT sig); + +#endif /* _POSIX_C_SOURCE >= 200112L */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_ZEPHYR_POSIX_AIO_H_ */ diff --git a/include/zephyr/posix/pthread.h b/include/zephyr/posix/pthread.h index 2cc05b6df25..7cd0f7e1160 100644 --- a/include/zephyr/posix/pthread.h +++ b/include/zephyr/posix/pthread.h @@ -276,20 +276,6 @@ int pthread_mutexattr_init(pthread_mutexattr_t *attr); */ int pthread_mutexattr_destroy(pthread_mutexattr_t *attr); -/** - * @brief Declare a pthread barrier - * - * Declaration API for a pthread barrier. 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 barrier - * @param count Thread count, same as the "count" argument to - * pthread_barrier_init() - * @deprecated Use @ref pthread_barrier_init instead. - */ -#define PTHREAD_BARRIER_DEFINE(name, count) pthread_barrier_t name = -1 __DEPRECATED_MACRO - #define PTHREAD_BARRIER_SERIAL_THREAD 1 /* diff --git a/include/zephyr/posix/stropts.h b/include/zephyr/posix/stropts.h index 649f0d87b7a..41afdb5ae28 100644 --- a/include/zephyr/posix/stropts.h +++ b/include/zephyr/posix/stropts.h @@ -22,6 +22,7 @@ int fdetach(const char *path); int fattach(int fildes, const char *path); int getmsg(int fildes, struct strbuf *ctlptr, struct strbuf *dataptr, int *flagsp); int getpmsg(int fildes, struct strbuf *ctlptr, struct strbuf *dataptr, int *bandp, int *flagsp); +int isastream(int fildes); #ifdef __cplusplus } diff --git a/include/zephyr/posix/unistd.h b/include/zephyr/posix/unistd.h index 0865a8e131c..f829ebac235 100644 --- a/include/zephyr/posix/unistd.h +++ b/include/zephyr/posix/unistd.h @@ -37,23 +37,23 @@ extern "C" { /* Constants for Options 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_ASYNCHRONOUS_IO Z_SC_VAL_IFDEF(CONFIG_POSIX_ASYNCHRONOUS_IO, _POSIX_VERSION) +#define _POSIX_BARRIERS Z_SC_VAL_IFDEF(CONFIG_PTHREAD_BARRIER, _POSIX_VERSION) +#define _POSIX_CHOWN_RESTRICTED (0) #define _POSIX_CLOCK_SELECTION Z_SC_VAL_IFDEF(CONFIG_POSIX_CLOCK, _POSIX_VERSION) #define _POSIX_CPUTIME (-1L) -#define _POSIX_FSYNC (-1L) +#define _POSIX_FSYNC Z_SC_VAL_IFDEF(CONFIG_POSIX_FSYNC, _POSIX_VERSION) #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_MAPPED_FILES (-1L) #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_NO_TRUNC (0) #define _POSIX_PRIORITIZED_IO (-1L) -#define _POSIX_PRIORITY_SCHEDULING (-1L) +#define _POSIX_PRIORITY_SCHEDULING Z_SC_VAL_IFDEF(CONFIG_POSIX_PRIORITY_SCHEDULING, _POSIX_VERSION) #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) @@ -237,6 +237,8 @@ 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); +int fsync(int fd); +int ftruncate(int fd, off_t length); /* File System related operations */ int rename(const char *old, const char *newp); @@ -261,6 +263,7 @@ extern char *optarg; extern int opterr, optind, optopt; #endif +int getentropy(void *buffer, size_t length); pid_t getpid(void); unsigned sleep(unsigned int seconds); int usleep(useconds_t useconds); diff --git a/include/zephyr/rtio/rtio.h b/include/zephyr/rtio/rtio.h index 4fc8cf23bda..f5bb6fcd484 100644 --- a/include/zephyr/rtio/rtio.h +++ b/include/zephyr/rtio/rtio.h @@ -737,22 +737,22 @@ static inline void rtio_block_pool_free(struct rtio *r, void *buf, uint32_t buf_ } #define Z_RTIO_SQE_POOL_DEFINE(name, sz) \ - static struct rtio_iodev_sqe _sqe_pool_##name[sz]; \ + static struct rtio_iodev_sqe CONCAT(_sqe_pool_, name)[sz]; \ STRUCT_SECTION_ITERABLE(rtio_sqe_pool, name) = { \ .free_q = RTIO_MPSC_INIT((name.free_q)), \ .pool_size = sz, \ .pool_free = sz, \ - .pool = _sqe_pool_##name, \ + .pool = CONCAT(_sqe_pool_, name), \ } #define Z_RTIO_CQE_POOL_DEFINE(name, sz) \ - static struct rtio_cqe _cqe_pool_##name[sz]; \ + static struct rtio_cqe CONCAT(_cqe_pool_, name)[sz]; \ STRUCT_SECTION_ITERABLE(rtio_cqe_pool, name) = { \ .free_q = RTIO_MPSC_INIT((name.free_q)), \ .pool_size = sz, \ .pool_free = sz, \ - .pool = _cqe_pool_##name, \ + .pool = CONCAT(_cqe_pool_, name), \ } /** @@ -779,19 +779,19 @@ static inline void rtio_block_pool_free(struct rtio *r, void *buf, uint32_t buf_ #define Z_RTIO_BLOCK_POOL_DEFINE(name, blk_sz, blk_cnt, blk_align) \ RTIO_BMEM uint8_t __aligned(WB_UP(blk_align)) \ - _block_pool_##name[blk_cnt*WB_UP(blk_sz)]; \ - _SYS_MEM_BLOCKS_DEFINE_WITH_EXT_BUF(name, WB_UP(blk_sz), blk_cnt, _block_pool_##name, \ - RTIO_DMEM) + CONCAT(_block_pool_, name)[blk_cnt*WB_UP(blk_sz)]; \ + _SYS_MEM_BLOCKS_DEFINE_WITH_EXT_BUF(name, WB_UP(blk_sz), blk_cnt, \ + CONCAT(_block_pool_, name), RTIO_DMEM) #define Z_RTIO_DEFINE(name, _sqe_pool, _cqe_pool, _block_pool) \ IF_ENABLED(CONFIG_RTIO_SUBMIT_SEM, \ - (static K_SEM_DEFINE(_submit_sem_##name, 0, K_SEM_MAX_LIMIT))) \ + (static K_SEM_DEFINE(CONCAT(_submit_sem_, name), 0, K_SEM_MAX_LIMIT))) \ IF_ENABLED(CONFIG_RTIO_CONSUME_SEM, \ - (static K_SEM_DEFINE(_consume_sem_##name, 0, K_SEM_MAX_LIMIT))) \ + (static K_SEM_DEFINE(CONCAT(_consume_sem_, name), 0, K_SEM_MAX_LIMIT))) \ STRUCT_SECTION_ITERABLE(rtio, name) = { \ - IF_ENABLED(CONFIG_RTIO_SUBMIT_SEM, (.submit_sem = &_submit_sem_##name,)) \ + IF_ENABLED(CONFIG_RTIO_SUBMIT_SEM, (.submit_sem = &CONCAT(_submit_sem_, name),)) \ IF_ENABLED(CONFIG_RTIO_SUBMIT_SEM, (.submit_count = 0,)) \ - IF_ENABLED(CONFIG_RTIO_CONSUME_SEM, (.consume_sem = &_consume_sem_##name,)) \ + IF_ENABLED(CONFIG_RTIO_CONSUME_SEM, (.consume_sem = &CONCAT(_consume_sem_, name),))\ .cq_count = ATOMIC_INIT(0), \ .xcqcnt = ATOMIC_INIT(0), \ .sqe_pool = _sqe_pool, \ @@ -808,10 +808,11 @@ static inline void rtio_block_pool_free(struct rtio *r, void *buf, uint32_t buf_ * @param sq_sz Size of the submission queue entry pool * @param cq_sz Size of the completion queue entry pool */ -#define RTIO_DEFINE(name, sq_sz, cq_sz) \ - Z_RTIO_SQE_POOL_DEFINE(name##_sqe_pool, sq_sz); \ - Z_RTIO_CQE_POOL_DEFINE(name##_cqe_pool, cq_sz); \ - Z_RTIO_DEFINE(name, &name##_sqe_pool, &name##_cqe_pool, NULL) \ +#define RTIO_DEFINE(name, sq_sz, cq_sz) \ + Z_RTIO_SQE_POOL_DEFINE(CONCAT(name, _sqe_pool), sq_sz); \ + Z_RTIO_CQE_POOL_DEFINE(CONCAT(name, _cqe_pool), cq_sz); \ + Z_RTIO_DEFINE(name, &CONCAT(name, _sqe_pool), \ + &CONCAT(name, _cqe_pool), NULL) /* clang-format on */ diff --git a/include/zephyr/sd/sd_spec.h b/include/zephyr/sd/sd_spec.h index ed61932e655..7e08488805c 100644 --- a/include/zephyr/sd/sd_spec.h +++ b/include/zephyr/sd/sd_spec.h @@ -12,6 +12,7 @@ #define ZEPHYR_SUBSYS_SD_SPEC_H_ #include +#include #ifdef __cplusplus extern "C" { @@ -368,7 +369,18 @@ enum sd_group_num { /* Maximum data rate possible for SD high speed cards */ enum hs_max_data_rate { - HS_MAX_DTR = 50000000, + HS_UNSUPPORTED = 0, + HS_MAX_DTR = MHZ(50), +}; + +/* Maximum data rate possible for SD uhs cards */ +enum uhs_max_data_rate { + UHS_UNSUPPORTED = 0, + UHS_SDR12_MAX_DTR = MHZ(25), + UHS_SDR25_MAX_DTR = MHZ(50), + UHS_SDR50_MAX_DTR = MHZ(100), + UHS_SDR104_MAX_DTR = MHZ(208), + UHS_DDR50_MAX_DTR = MHZ(50), }; /** @@ -379,6 +391,7 @@ enum hs_max_data_rate { */ enum sd_bus_speed { UHS_SDR12_BUS_SPEED = BIT(0), + DEFAULT_BUS_SPEED = BIT(0), HIGH_SPEED_BUS_SPEED = BIT(1), UHS_SDR25_BUS_SPEED = BIT(1), UHS_SDR50_BUS_SPEED = BIT(2), @@ -393,10 +406,14 @@ enum sd_bus_speed { * controller to identify timing of card. */ enum sd_timing_mode { + SD_TIMING_DEFAULT = 0U, + /*!< Default Mode */ SD_TIMING_SDR12 = 0U, - /*!< Default mode & SDR12 */ + /*!< SDR12 mode */ + SD_TIMING_HIGH_SPEED = 1U, + /*!< High speed mode */ SD_TIMING_SDR25 = 1U, - /*!< High speed mode & SDR25 */ + /*!< SDR25 mode */ SD_TIMING_SDR50 = 2U, /*!< SDR50 mode*/ SD_TIMING_SDR104 = 3U, @@ -411,16 +428,16 @@ enum sd_timing_mode { * Controls the SD host controller clock speed on the SD bus. */ enum sdhc_clock_speed { - SDMMC_CLOCK_400KHZ = 400000U, - SD_CLOCK_25MHZ = 25000000U, - SD_CLOCK_50MHZ = 50000000U, - SD_CLOCK_100MHZ = 100000000U, - SD_CLOCK_208MHZ = 208000000U, - MMC_CLOCK_26MHZ = 26000000U, - MMC_CLOCK_52MHZ = 52000000U, - MMC_CLOCK_DDR52 = 52000000U, - MMC_CLOCK_HS200 = 200000000U, - MMC_CLOCK_HS400 = 200000000U, /* Same clock freq as HS200, just DDR */ + SDMMC_CLOCK_400KHZ = KHZ(400), + SD_CLOCK_25MHZ = MHZ(25), + SD_CLOCK_50MHZ = MHZ(50), + SD_CLOCK_100MHZ = MHZ(100), + SD_CLOCK_208MHZ = MHZ(208), + MMC_CLOCK_26MHZ = MHZ(26), + MMC_CLOCK_52MHZ = MHZ(52), + MMC_CLOCK_DDR52 = MHZ(52), + MMC_CLOCK_HS200 = MHZ(200), + MMC_CLOCK_HS400 = MHZ(200), /* Same clock freq as HS200, just DDR */ }; /** @@ -487,7 +504,7 @@ enum sd_driver_strength { */ struct sd_switch_caps { enum hs_max_data_rate hs_max_dtr; - enum sdhc_clock_speed uhs_max_dtr; + enum uhs_max_data_rate uhs_max_dtr; enum sd_bus_speed bus_speed; enum sd_driver_type sd_drv_type; enum sd_current_limit sd_current_limit; diff --git a/include/zephyr/sensing/sensing.h b/include/zephyr/sensing/sensing.h index 0a84c822ad1..96fb119b0ed 100644 --- a/include/zephyr/sensing/sensing.h +++ b/include/zephyr/sensing/sensing.h @@ -38,16 +38,20 @@ extern "C" { */ struct sensing_sensor_version { union { - uint32_t value; + uint32_t value; /**< The version represented as a 32-bit value. */ struct { - uint8_t major; - uint8_t minor; - uint8_t hotfix; - uint8_t build; + uint8_t major; /**< The major version number. */ + uint8_t minor; /**< The minor version number. */ + uint8_t hotfix; /**< The hotfix version number. */ + uint8_t build; /**< The build version number. */ }; }; }; +/** + * @brief Macro to create a sensor version value. + * + */ #define SENSING_SENSOR_VERSION(_major, _minor, _hotfix, _build) \ (FIELD_PREP(GENMASK(31, 24), _major) | \ FIELD_PREP(GENMASK(23, 16), _minor) | \ @@ -83,8 +87,8 @@ struct sensing_sensor_version { * */ enum sensing_sensor_state { - SENSING_SENSOR_STATE_READY = 0, - SENSING_SENSOR_STATE_OFFLINE = 1, + SENSING_SENSOR_STATE_READY = 0, /**< The sensor is ready. */ + SENSING_SENSOR_STATE_OFFLINE = 1, /**< The sensor is offline. */ }; /** @@ -92,27 +96,27 @@ enum sensing_sensor_state { * */ enum sensing_sensor_attribute { + /** The interval attribute of a sensor configuration. */ SENSING_SENSOR_ATTRIBUTE_INTERVAL = 0, + /** The sensitivity attribute of a sensor configuration. */ SENSING_SENSOR_ATTRIBUTE_SENSITIVITY = 1, + /** The latency attribute of a sensor configuration. */ SENSING_SENSOR_ATTRIBUTE_LATENCY = 2, + /** The maximum number of attributes that a sensor configuration can have. */ SENSING_SENSOR_ATTRIBUTE_MAX, }; - /** * @brief Define Sensing subsystem sensor handle * */ typedef void *sensing_sensor_handle_t; - /** * @brief Sensor data event receive callback. * * @param handle The sensor instance handle. - * * @param buf The data buffer with sensor data. - * * @param context User provided context pointer. */ typedef void (*sensing_data_event_t)( @@ -151,41 +155,52 @@ struct sensing_sensor_info { * */ struct sensing_callback_list { - sensing_data_event_t on_data_event; - void *context; + sensing_data_event_t on_data_event; /**< Callback function for a sensor data event. */ + void *context; /**< Associated context with on_data_event */ }; + /** * @struct sensing_sensor_config * @brief Sensing subsystem sensor configure, including interval, sensitivity, latency * */ struct sensing_sensor_config { - enum sensing_sensor_attribute attri; + enum sensing_sensor_attribute attri; /**< Attribute of the sensor configuration. */ /** \ref SENSING_SENSITIVITY_INDEX_ALL */ - int8_t data_field; + int8_t data_field; /**< Data field of the sensor configuration. */ union { + /** Interval between two sensor samples in microseconds (us). */ uint32_t interval; + + /** + * Sensitivity threshold for reporting new data. A new sensor sample is reported + * only if the difference between it and the previous sample exceeds this + * sensitivity value. + */ uint32_t sensitivity; + + /** + * Maximum duration for batching sensor samples before reporting in + * microseconds (us). This defines how long sensor samples can be + * accumulated before they must be reported. + */ uint64_t latency; }; }; - - /** - * @brief Get all supported sensor instances' information. - * - * This API just returns read only information of sensor instances, pointer info will - * directly point to internal buffer, no need for caller to allocate buffer, - * no side effect to sensor instances. - * - * @param num_sensors Get number of sensor instances. - * - * @param info For receiving sensor instances' information array pointer. - * - * @return 0 on success or negative error value on failure. - */ +/** + * @brief Get all supported sensor instances' information. + * + * This API just returns read only information of sensor instances, pointer info will + * directly point to internal buffer, no need for caller to allocate buffer, + * no side effect to sensor instances. + * + * @param num_sensors Get number of sensor instances. + * @param info For receiving sensor instances' information array pointer. + * @return 0 on success or negative error value on failure. + */ int sensing_get_sensors(int *num_sensors, const struct sensing_sensor_info **info); /** @@ -197,12 +212,9 @@ int sensing_get_sensors(int *num_sensors, const struct sensing_sensor_info **inf * meanwhile, also register sensing callback list * * @param info The sensor info got from \ref sensing_get_sensors - * * @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( @@ -219,12 +231,9 @@ int sensing_open_sensor( * meanwhile, also register sensing callback list. * * @param dev pointer device get from device tree. - * * @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( @@ -235,7 +244,6 @@ int sensing_open_sensor_by_dt( * @brief Close sensor instance. * * @param handle The sensor instance handle need to close. - * * @return 0 on success or negative error value on failure. */ int sensing_close_sensor( @@ -245,11 +253,8 @@ int sensing_close_sensor( * @brief Set current config items to Sensing subsystem. * * @param handle The sensor instance handle. - * * @param configs The configs to be set according to config attribute. - * * @param count count of configs. - * * @return 0 on success or negative error value on failure, not support etc. */ int sensing_set_config( @@ -260,11 +265,8 @@ int sensing_set_config( * @brief Get current config items from Sensing subsystem. * * @param handle The sensor instance handle. - * * @param configs The configs to be get according to config attribute. - * * @param count count of configs. - * * @return 0 on success or negative error value on failure, not support etc. */ int sensing_get_config( @@ -275,7 +277,6 @@ int sensing_get_config( * @brief Get sensor information from sensor instance handle. * * @param handle The sensor instance handle. - * * @return a const pointer to \ref sensing_sensor_info on success or NULL on failure. */ const struct sensing_sensor_info *sensing_get_sensor_info( @@ -289,5 +290,4 @@ const struct sensing_sensor_info *sensing_get_sensor_info( * @} */ - #endif /*ZEPHYR_INCLUDE_SENSING_H_*/ diff --git a/include/zephyr/sensing/sensing_datatypes.h b/include/zephyr/sensing/sensing_datatypes.h index a5abcc3c8f8..b18b22b4180 100644 --- a/include/zephyr/sensing/sensing_datatypes.h +++ b/include/zephyr/sensing/sensing_datatypes.h @@ -45,9 +45,9 @@ * system/chre/chre_api/include/chre_api/chre/sensor_types.h */ struct sensing_sensor_value_header { - /** base timestamp of this data readings, unit is micro seconds */ + /** Base timestamp of this data readings, unit is micro seconds */ uint64_t base_timestamp; - /** count of this data readings */ + /** Count of this data readings */ uint16_t reading_count; }; @@ -65,19 +65,28 @@ struct sensing_sensor_value_header { * q31 version */ struct sensing_sensor_value_3d_q31 { + /** Header of the sensor value data structure. */ struct sensing_sensor_value_header header; - int8_t shift; + int8_t shift; /**< The shift value for the q31_t v[3] reading. */ struct { + /** Timestamp delta of the reading. Unit is micro seconds. */ uint32_t timestamp_delta; union { + /** + * 3D vector of the reading represented as an array. + * For SENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D and + * SENSING_SENSOR_TYPE_MOTION_UNCALIB_ACCELEROMETER_3D, + * the unit is Gs (gravitational force). + * For SENSING_SENSOR_TYPE_MOTION_GYROMETER_3D, the unit is degrees. + */ q31_t v[3]; struct { - q31_t x; - q31_t y; - q31_t z; + q31_t x; /**< X value of the 3D vector. */ + q31_t y; /**< Y value of the 3D vector. */ + q31_t z; /**< Z value of the 3D vector. */ }; }; - } readings[1]; + } readings[1]; /**< Array of readings. */ }; /** @@ -86,11 +95,17 @@ struct sensing_sensor_value_3d_q31 { * uint32_t version */ struct sensing_sensor_value_uint32 { + /** Header of the sensor value data structure. */ struct sensing_sensor_value_header header; struct { + /** Timestamp delta of the reading. Unit is micro seconds. */ uint32_t timestamp_delta; + /** + * Value of the reading. + * For SENSING_SENSOR_TYPE_LIGHT_AMBIENTLIGHT, the unit is luxs. + */ uint32_t v; - } readings[1]; + } readings[1]; /**< Array of readings. */ }; /** @@ -99,15 +114,20 @@ struct sensing_sensor_value_uint32 { * q31 version */ struct sensing_sensor_value_q31 { + /** Header of the sensor value data structure. */ struct sensing_sensor_value_header header; - int8_t shift; + int8_t shift; /**< The shift value for the q31_t v reading. */ struct { + /** Timestamp delta of the reading. Unit is micro seconds. */ uint32_t timestamp_delta; + /** + * Value of the reading. + * For SENSING_SENSOR_TYPE_MOTION_HINGE_ANGLE, the unit is degrees. + */ q31_t v; - } readings[1]; + } readings[1]; /**< Array of readings. */ }; - /** * @} */ diff --git a/include/zephyr/sensing/sensing_sensor.h b/include/zephyr/sensing/sensing_sensor.h index 434c13b9052..2c5e526f760 100644 --- a/include/zephyr/sensing/sensing_sensor.h +++ b/include/zephyr/sensing/sensing_sensor.h @@ -57,30 +57,40 @@ struct sensing_sensor_register_info { struct sensing_sensor_version version; }; +/** @cond INTERNAL_HIDDEN */ + +/** + * @brief Enumeration for sensing subsystem event. + * + * This enumeration defines the various events used by the sensing subsystem. + */ enum { - EVENT_CONFIG_READY, + EVENT_CONFIG_READY, /**< Configuration is ready. */ }; +/** + * @brief Enumeration for sensor flag bit. + * + * This enumeration defines the bit for sensor flag. + */ enum { - SENSOR_LATER_CFG_BIT, + SENSOR_LATER_CFG_BIT, /**< Indicates if there is a configuration request pending. */ }; /** * @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; + sys_snode_t snode; /**< Node in the singly-linked list of connections. */ + struct sensing_sensor *source; /**< Source sensor of the connection. */ + struct sensing_sensor *sink; /**< Sink sensor of the connection. */ + uint32_t interval; /**< Report interval in micro seconds. */ + /** Sensitivity of the connection. */ int sensitivity[CONFIG_SENSING_MAX_SENSITIVITY_COUNT]; - /* copy sensor data to connection data buf from reporter */ - void *data; - /* client(sink) next consume time */ + void *data; /**< Pointer to sensor sample data of the connection. */ + /** Next consume time of the connection. Unit is micro seconds. */ uint64_t next_consume_time; - /* post data to application */ - struct sensing_callback_list *callback_list; + struct sensing_callback_list *callback_list; /**< Callback list of the connection. */ }; /** @@ -93,57 +103,126 @@ struct sensing_connection { * build report relationship model base on them, etc. */ struct sensing_sensor { - const struct device *dev; - const struct sensing_sensor_info *info; + const struct device *dev; /**< Device of the sensor instance. */ + const struct sensing_sensor_info *info; /**< Info of the sensor instance. */ + /** Register info of the sensor instance. */ const struct sensing_sensor_register_info *register_info; - const uint16_t reporter_num; - sys_slist_t client_list; - uint32_t interval; - uint8_t sensitivity_count; + const uint16_t reporter_num; /**< Reporter number of the sensor instance. */ + sys_slist_t client_list; /**< List of the sensor clients. */ + uint32_t interval; /**< Report interval of the sensor sample in micro seconds. */ + uint8_t sensitivity_count; /**< Sensitivity count of the sensor instance. */ + /** Sensitivity array of the sensor instance. */ 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; + enum sensing_sensor_state state; /**< State of the sensor instance. */ + struct rtio_iodev *iodev; /**< Pointer to RTIO device of the sensor instance. */ + struct k_timer timer; /**< Timer for non streaming mode */ + struct rtio_sqe *stream_sqe; /**< Sqe for streaming mode. */ + atomic_t flag; /**< Sensor flag of the sensor instance. */ + struct sensing_connection *conns; /**< Pointer to sensor connections. */ }; +/** + * @brief Macro to generate a name for a sensor info structure. + * + * This macro generates a name for a sensor info structure based on a node and an index. + * + * @param node The devicetree node identifier. + * @param idx Logical index into the sensor-types array. + */ #define SENSING_SENSOR_INFO_NAME(node, idx) \ _CONCAT(_CONCAT(__sensing_sensor_info_, idx), DEVICE_DT_NAME_GET(node)) +/** + * @brief Macro to define a sensor info structure. + * + * This macro defines a sensor info structure based on a node and an index. + * The structure includes the type, name, friendly name, vendor, model, and minimal interval of the + * sensor. + * + * @param node The devicetree node identifier. + * @param idx Logical index into the sensor-types array. + */ #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), \ + .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),\ + .minimal_interval = DT_PROP(node, minimal_interval), \ }; +/** + * @brief Macro to generate a name for a connections array. + * + * This macro generates a name for a connections array based on a node. + * + * @param node The devicetree node identifier. + */ #define SENSING_CONNECTIONS_NAME(node) \ _CONCAT(__sensing_connections_, DEVICE_DT_NAME_GET(node)) +/** + * @brief Macro to generate a name for a sensor source. + * + * This macro generates a name for a sensor source based on an index and a node. + * + * @param idx Logical index into the reporters array. + * @param node The devicetree node identifier. + */ #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)) +/** + * @brief Macro to declare an external sensor source. + * + * This macro declares an external sensor source based on an index and a node. + * + * @param idx Logical index into the reporters array. + * @param node The devicetree node identifier. + */ #define SENSING_SENSOR_SOURCE_EXTERN(idx, node) \ -extern struct sensing_sensor SENSING_SENSOR_SOURCE_NAME(idx, node); \ +extern struct sensing_sensor SENSING_SENSOR_SOURCE_NAME(idx, node); +/** + * @brief Macro to initialize a connection. + * + * This macro initializes a connection with a source name and a callback list pointer. + * + * @param source_name The name of struct sensing_sensor for source sensor. + * @param cb_list_ptr Pointer to sensing callback list. + */ #define SENSING_CONNECTION_INITIALIZER(source_name, cb_list_ptr) \ { \ .callback_list = cb_list_ptr, \ .source = &source_name, \ } +/** + * @brief Macro to define a connection. + * + * This macro defines a connection based on an index, a node, and a callback list pointer. + * + * @param idx Logical index into the reporters array. + * @param node The devicetree node identifier. + * @param cb_list_ptr Pointer to sensing callback list. + */ #define SENSING_CONNECTION_DEFINE(idx, node, cb_list_ptr) \ SENSING_CONNECTION_INITIALIZER(SENSING_SENSOR_SOURCE_NAME(idx, node), \ cb_list_ptr) +/** + * @brief Macro to define an array of connections. + * + * This macro defines an array of connections based on a node, a number, and a callback list + * pointer. + * + * @param node The devicetree node identifier. + * @param num The number of the connections. + * @param cb_list_ptr Pointer to sensing callback list. + */ #define SENSING_CONNECTIONS_DEFINE(node, num, cb_list_ptr) \ LISTIFY(num, SENSING_SENSOR_SOURCE_EXTERN, \ (), node) \ @@ -153,20 +232,56 @@ extern struct sensing_sensor SENSING_SENSOR_SOURCE_NAME(idx, node); \ (,), node, cb_list_ptr) \ }; +/** + * @brief Structure for sensor submit configuration. + * + * This structure represents a sensor submit configuration. It includes the channel, info index, and + * streaming flag. + */ struct sensing_submit_config { - enum sensor_channel chan; - const int info_index; - const bool is_streaming; + enum sensor_channel chan; /**< Channel of the sensor to submit. */ + const int info_index; /**< Logical index into the sensor-types array. */ + const bool is_streaming; /**< Working in streaming mode or not. */ }; +/** + * @brief External declaration for the sensing I/O device API. + * + * This external declaration represents the sensing I/O device API. + */ extern const struct rtio_iodev_api __sensing_iodev_api; +/** + * @brief Macro to generate a name for a submit configuration. + * + * This macro generates a name for a submit configuration based on a node and an index. + * + * @param node The devicetree node identifier. + * @param idx Logical index into the sensor-types array. + */ #define SENSING_SUBMIT_CFG_NAME(node, idx) \ _CONCAT(_CONCAT(__sensing_submit_cfg_, idx), DEVICE_DT_NAME_GET(node)) +/** + * @brief Macro to generate a name for a sensor I/O device. + * + * This macro generates a name for a sensor I/O device based on a node and an index. + * + * @param node The devicetree node identifier. + * @param idx Logical index into the sensor-types array. + */ #define SENSING_SENSOR_IODEV_NAME(node, idx) \ _CONCAT(_CONCAT(__sensing_iodev_, idx), DEVICE_DT_NAME_GET(node)) +/** + * @brief Macro to define a sensor I/O device. + * + * This macro defines a sensor I/O device based on a node and an index. + * The device includes a submit configuration with a streaming flag and an info index. + * + * @param node The devicetree node identifier. + * @param idx Logical index into the sensor-types array. + */ #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), \ @@ -176,9 +291,30 @@ extern const struct rtio_iodev_api __sensing_iodev_api; &__sensing_iodev_api, \ &SENSING_SUBMIT_CFG_NAME(node, idx)); +/** + * @brief Macro to generate a name for a sensor. + * + * This macro generates a name for a sensor based on a node and an index. + * + * @param node The devicetree node identifier. + * @param idx Logical index into the sensor-types array. + */ #define SENSING_SENSOR_NAME(node, idx) \ _CONCAT(_CONCAT(__sensing_sensor_, idx), DEVICE_DT_NAME_GET(node)) +/** + * @brief Macro to define a sensor. + * + * This macro defines a sensor based on a node, a property, an index, a register info pointer, and a + * callback list pointer. The sensor includes a device, info, register info, reporter number, + * connections, and an I/O device. + * + * @param node The devicetree node identifier. + * @param prop property name. + * @param idx Logical index into the sensor-types array. + * @param reg_ptr Pointer to the device's sensing_sensor_register_info. + * @param cb_list_ptr Pointer to sensing callback list. + */ #define SENSING_SENSOR_DEFINE(node, prop, idx, reg_ptr, cb_list_ptr) \ SENSING_SENSOR_INFO_DEFINE(node, idx) \ SENSING_SENSOR_IODEV_DEFINE(node, idx) \ @@ -192,9 +328,22 @@ extern const struct rtio_iodev_api __sensing_iodev_api; .iodev = &SENSING_SENSOR_IODEV_NAME(node, idx), \ }; +/** + * @brief Macro to define sensors. + * + * This macro defines sensors based on a node, a register info pointer, and a callback list pointer. + * It uses the DT_FOREACH_PROP_ELEM_VARGS macro to define each sensor. + * + * @param node The devicetree node identifier. + * @param reg_ptr Pointer to the device's sensing_sensor_register_info. + * @param cb_list_ptr Pointer to sensing callback list. + */ #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) + +/** @endcond */ + /** * @brief Like SENSOR_DEVICE_DT_DEFINE() with sensing specifics. * @@ -203,26 +352,17 @@ extern const struct rtio_iodev_api __sensing_iodev_api; * sensors. * * @param node The devicetree node identifier. - * * @param reg_ptr Pointer to the device's sensing_sensor_register_info. - * - * @param cb_list_ptr Pointer to devices callback list. - * + * @param cb_list_ptr Pointer to sensing callback list. * @param init_fn Name of the init function of the driver. - * * @param pm_device PM device resources reference (NULL if device does not use * PM). - * * @param data_ptr Pointer to the device's private data. - * * @param cfg_ptr The address to the structure containing the configuration * information for this instance of the driver. - * * @param level The initialization level. See SYS_INIT() for details. - * * @param prio Priority within the selected initialization level. See * SYS_INIT() for details. - * * @param api_ptr Provides an initial pointer to the API function struct used * by the driver. Can be NULL. */ @@ -244,7 +384,6 @@ extern const struct rtio_iodev_api __sensing_iodev_api; * * @param inst instance number. This is replaced by * DT_DRV_COMPAT(inst) in the call to SENSING_SENSORS_DT_DEFINE(). - * * @param ... other parameters as expected by SENSING_SENSORS_DT_DEFINE(). */ #define SENSING_SENSORS_DT_INST_DEFINE(inst, ...) \ @@ -254,16 +393,12 @@ extern const struct rtio_iodev_api __sensing_iodev_api; * @brief Get reporter handles of a given sensor instance by sensor type. * * @param dev The sensor instance device structure. - * * @param type The given type, \ref SENSING_SENSOR_TYPE_ALL to get reporters * with all types. - * * @param max_handles The max count of the \p reporter_handles array input. Can * get real count number via \ref sensing_sensor_get_reporters_count - * * @param reporter_handles Input handles array for receiving found reporter * sensor instances - * * @return number of reporters found, 0 returned if not found. */ int sensing_sensor_get_reporters( @@ -274,9 +409,7 @@ int sensing_sensor_get_reporters( * @brief Get reporters count of a given sensor instance by sensor type. * * @param dev The sensor instance device structure. - * * @param type The sensor type for checking, \ref SENSING_SENSOR_TYPE_ALL - * * @return Count of reporters by \p type, 0 returned if no reporters by \p type. */ int sensing_sensor_get_reporters_count( @@ -286,9 +419,7 @@ int sensing_sensor_get_reporters_count( * @brief Get this sensor's state * * @param dev The sensor instance device structure. - * * @param state Returned sensor state value - * * @return 0 on success or negative error value on failure. */ int sensing_sensor_get_state( diff --git a/include/zephyr/sensing/sensing_sensor_types.h b/include/zephyr/sensing/sensing_sensor_types.h index db15af1e279..de9328c7b21 100644 --- a/include/zephyr/sensing/sensing_sensor_types.h +++ b/include/zephyr/sensing/sensing_sensor_types.h @@ -27,8 +27,11 @@ /** * sensor category motion */ +/* Sensor type for 3D accelerometers. */ #define SENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D 0x73 +/* Sensor type for 3D gyrometers. */ #define SENSING_SENSOR_TYPE_MOTION_GYROMETER_3D 0x76 +/* Sensor type for motion detectors. */ #define SENSING_SENSOR_TYPE_MOTION_MOTION_DETECTOR 0x77 @@ -37,10 +40,16 @@ */ #define SENSING_SENSOR_TYPE_OTHER_CUSTOM 0xE1 +/* Sensor type for uncalibrated 3D accelerometers. */ #define SENSING_SENSOR_TYPE_MOTION_UNCALIB_ACCELEROMETER_3D 0x240 - +/* Sensor type for hinge angle sensors. */ #define SENSING_SENSOR_TYPE_MOTION_HINGE_ANGLE 0x20B +/** + * @brief Sensor type for all sensors. + * + * This macro defines the sensor type for all sensors. + */ #define SENSING_SENSOR_TYPE_ALL 0xFFFF /** diff --git a/include/zephyr/settings/settings.h b/include/zephyr/settings/settings.h index 0bae0658d43..99b9fc21077 100644 --- a/include/zephyr/settings/settings.h +++ b/include/zephyr/settings/settings.h @@ -303,6 +303,16 @@ int settings_load_subtree_direct( */ int settings_save(void); +/** + * Save limited set of currently running serialized items. All serialized items + * that belong to subtree and which are different from currently persisted + * values will be saved. + * + * @param[in] subtree name of the subtree to be loaded. + * @return 0 on success, non-zero on failure. + */ +int settings_save_subtree(const char *subtree); + /** * Write a single serialized value to persisted storage (if it has * changed value). diff --git a/include/zephyr/shared_irq.h b/include/zephyr/shared_irq.h index 575ef119d3a..e5ffdf1edd8 100644 --- a/include/zephyr/shared_irq.h +++ b/include/zephyr/shared_irq.h @@ -9,6 +9,7 @@ #ifndef ZEPHYR_INCLUDE_SHARED_IRQ_H_ #define ZEPHYR_INCLUDE_SHARED_IRQ_H_ +#include #ifdef __cplusplus extern "C" { @@ -25,7 +26,7 @@ typedef int (*shared_irq_enable_t)(const struct device *dev, typedef int (*shared_irq_disable_t)(const struct device *dev, const struct device *isr_dev); -struct shared_irq_driver_api { +__subsystem struct shared_irq_driver_api { shared_irq_register_t isr_register; shared_irq_enable_t enable; shared_irq_disable_t disable; diff --git a/include/zephyr/shell/shell.h b/include/zephyr/shell/shell.h index 91dd73a2d9b..d99baf00d5a 100644 --- a/include/zephyr/shell/shell.h +++ b/include/zephyr/shell/shell.h @@ -131,6 +131,34 @@ struct shell_static_args { const struct device *shell_device_lookup(size_t idx, const char *prefix); +/** + * @brief Filter callback type, for use with shell_device_lookup_filter + * + * This is used as an argument of shell_device_lookup_filter to only return + * devices that match a specific condition, implemented by the filter. + * + * @param dev pointer to a struct device. + * + * @return bool, true if the filter matches the device type. + */ +typedef bool (*shell_device_filter_t)(const struct device *dev); + +/** + * @brief Get a device by index and filter. + * + * This can be used to return devices matching a specific type. + * + * Devices that the filter returns false for, failed to initialize or do not + * have a non-empty name are excluded from the candidates for a match. + * + * @param idx the device number starting from zero. + * + * @param filter a pointer to a shell_device_filter_t function that returns + * true if the device matches the filter. + */ +const struct device *shell_device_filter(size_t idx, + shell_device_filter_t filter); + /** * @brief Shell command handler prototype. * @@ -1008,9 +1036,10 @@ int shell_stop(const struct shell *sh); * @param[in] fmt Format string. * @param[in] ... List of parameters to print. */ -void __printf_like(3, 4) shell_fprintf(const struct shell *sh, - enum shell_vt100_color color, - const char *fmt, ...); +void __printf_like(3, 4) shell_fprintf_impl(const struct shell *sh, enum shell_vt100_color color, + const char *fmt, ...); + +#define shell_fprintf(sh, color, fmt, ...) shell_fprintf_impl(sh, color, fmt, ##__VA_ARGS__) /** * @brief vprintf-like function which sends formatted data stream to the shell. @@ -1277,4 +1306,9 @@ int shell_get_return_value(const struct shell *sh); } #endif +#ifdef CONFIG_SHELL_CUSTOM_HEADER +/* This include must always be at the end of shell.h */ +#include +#endif + #endif /* SHELL_H__ */ diff --git a/include/zephyr/smf.h b/include/zephyr/smf.h index c7a2c4fbff4..5b5f303630d 100644 --- a/include/zephyr/smf.h +++ b/include/zephyr/smf.h @@ -13,68 +13,34 @@ #ifndef ZEPHYR_INCLUDE_SMF_H_ #define ZEPHYR_INCLUDE_SMF_H_ +#include + /** * @brief State Machine Framework API * @defgroup smf State Machine Framework API + * @version 0.1.0 * @ingroup os_services * @{ */ -#ifdef CONFIG_SMF_ANCESTOR_SUPPORT -/** - * @brief Macro to create a hierarchical state. - * - * @param _entry State entry function - * @param _run State run function - * @param _exit State exit function - * @param _parent State parent object or NULL - */ -#ifndef CONFIG_SMF_INITIAL_TRANSITION -#define SMF_CREATE_STATE(_entry, _run, _exit, _parent) \ -{ \ - .entry = _entry, \ - .run = _run, \ - .exit = _exit, \ - .parent = _parent \ -} -#else /** - * @brief Macro to create a hierarchical state. + * @brief Macro to create a hierarchical state with initial transitions. * - * @param _entry State entry function - * @param _run State run function - * @param _exit State exit function + * @param _entry State entry function or NULL + * @param _run State run function or NULL + * @param _exit State exit function or NULL * @param _parent State parent object or NULL * @param _initial State initial transition object or NULL */ -#define SMF_CREATE_STATE(_entry, _run, _exit, _parent, _initial) \ -{ \ - .entry = _entry, \ - .run = _run, \ - .exit = _exit, \ - .parent = _parent, \ - .initial = _initial \ -} -#endif /* CONFIG_SMF_INITIAL_TRANSITION */ - -#else - -/** - * @brief Macro to create a flat state. - * - * @param _entry State entry function - * @param _run State run function - * @param _exit State exit function - */ -#define SMF_CREATE_STATE(_entry, _run, _exit) \ -{ \ - .entry = _entry, \ - .run = _run, \ - .exit = _exit \ +#define SMF_CREATE_STATE(_entry, _run, _exit, _parent, _initial) \ +{ \ + .entry = _entry, \ + .run = _run, \ + .exit = _exit, \ + IF_ENABLED(CONFIG_SMF_ANCESTOR_SUPPORT, (.parent = _parent,)) \ + IF_ENABLED(CONFIG_SMF_INITIAL_TRANSITION, (.initial = _initial,)) \ } -#endif /* CONFIG_SMF_ANCESTOR_SUPPORT */ - /** * @brief Macro to cast user defined object to state machine * context. @@ -107,6 +73,7 @@ struct smf_state { const state_execution run; /** Optional method that will be run when this state exists */ const state_execution exit; +#ifdef CONFIG_SMF_ANCESTOR_SUPPORT /** * Optional parent state that contains common entry/run/exit * implementation among various child states. @@ -114,8 +81,8 @@ struct smf_state { * run: Parent function executes AFTER child function. * exit: Parent function executes AFTER child function. * - * Note: When transitioning between two child states with a shared parent, - * that parent's exit and entry functions do not execute. + * Note: When transitioning between two child states with a shared + * parent, that parent's exit and entry functions do not execute. */ const struct smf_state *parent; @@ -124,7 +91,8 @@ struct smf_state { * Optional initial transition state. NULL for leaf states. */ const struct smf_state *initial; -#endif +#endif /* CONFIG_SMF_INITIAL_TRANSITION */ +#endif /* CONFIG_SMF_ANCESTOR_SUPPORT */ }; /** Defines the current context of the state machine. */ @@ -133,6 +101,11 @@ struct smf_ctx { const struct smf_state *current; /** Previous state the state machine executed */ const struct smf_state *previous; + +#ifdef CONFIG_SMF_ANCESTOR_SUPPORT + /** Currently executing state (which may be a parent) */ + const struct smf_state *executing; +#endif /* CONFIG_SMF_ANCESTOR_SUPPORT */ /** * This value is set by the set_terminate function and * should terminate the state machine when its set to a @@ -157,8 +130,8 @@ void smf_set_initial(struct smf_ctx *ctx, const struct smf_state *init_state); /** * @brief Changes a state machines state. This handles exiting the previous - * state and entering the target state. A common parent state will not - * exited nor be re-entered. + * state and entering the target state. For HSMs the entry and exit + * actions of the Least Common Ancestor will not be run. * * @param ctx State machine context * @param new_state State to transition to (NULL is valid and exits all states) diff --git a/include/zephyr/storage/stream_flash.h b/include/zephyr/storage/stream_flash.h index d53b6414a3e..40787d773d5 100644 --- a/include/zephyr/storage/stream_flash.h +++ b/include/zephyr/storage/stream_flash.h @@ -98,21 +98,23 @@ int stream_flash_init(struct stream_flash_ctx *ctx, const struct device *fdev, size_t stream_flash_bytes_written(struct stream_flash_ctx *ctx); /** - * @brief Process input buffers to be written to flash device in single blocks. + * @brief Process input buffers to be written to flash device in single blocks. * Will store remainder between calls. * - * A final call to this function with flush set to true - * will write out the remaining block buffer to flash. + * A write with the @p flush set to true has to be issued as the last + * write request for a given context, as it concludes write of a stream, + * and flushes buffers to storage device. + * + * @warning There must not be any additional write requests issued for a flushed context, + * unless it is re-initialized, as such write attempts may result in the function + * failing and returning error. + * Once context has been flushed, it can be re-initialized and re-used for new + * stream flash session. * * @param ctx context * @param data data to write * @param len Number of bytes to write * @param flush when true this forces any buffered data to be written to flash - * A write with the @p flush set to true has to be issued as the last - * write request for a given context, as it concludes write of a stream; - * there must not be issued any more write requests for given context, - * unless it is re-initialized, and such write attempts may result in the - * function returning error. * * @return non-negative on success, negative errno code on fail */ diff --git a/include/zephyr/sys/__assert.h b/include/zephyr/sys/__assert.h index fc0b9476ea6..9f1ab977bee 100644 --- a/include/zephyr/sys/__assert.h +++ b/include/zephyr/sys/__assert.h @@ -12,15 +12,21 @@ #ifdef CONFIG_ASSERT #ifndef __ASSERT_ON +#ifdef CONFIG_ASSERT_LEVEL #define __ASSERT_ON CONFIG_ASSERT_LEVEL #endif #endif +#endif #ifdef CONFIG_FORCE_NO_ASSERT #undef __ASSERT_ON #define __ASSERT_ON 0 #endif +#ifndef __ASSERT_ON +#define __ASSERT_ON 0 +#endif + #ifdef __cplusplus extern "C" { #endif diff --git a/include/zephyr/sys/bitarray.h b/include/zephyr/sys/bitarray.h index 90d1f59345b..35ee721ddf7 100644 --- a/include/zephyr/sys/bitarray.h +++ b/include/zephyr/sys/bitarray.h @@ -168,6 +168,61 @@ int sys_bitarray_test_and_clear_bit(sys_bitarray_t *bitarray, size_t bit, int *p int sys_bitarray_alloc(sys_bitarray_t *bitarray, size_t num_bits, size_t *offset); +/** + * Calculates the bit-wise XOR of two bitarrays in a region. + * The result is stored in the first bitarray passed in (@p dst). + * Both bitarrays must be of the same size. + * + * @param dst Bitarray struct + * @param other Bitarray struct + * @param num_bits Number of bits in the region, must be larger than 0 + * @param offset Starting bit location + * + * @retval 0 Operation successful + * @retval -EINVAL Invalid argument (e.g. out-of-bounds access, mismatching bitarrays, trying to xor + * 0 bits, etc.) + */ +int sys_bitarray_xor(sys_bitarray_t *dst, sys_bitarray_t *other, size_t num_bits, size_t offset); + +/** + * Find nth bit set in region + * + * This counts the number of bits set (@p count) in a + * region (@p offset, @p num_bits) and returns the index (@p found_at) + * of the nth set bit, if it exists, as long with a zero return value. + * + * If it does not exist, @p found_at is not updated and the method returns + * + * @param[in] bitarray Bitarray struct + * @param[in] n Nth bit set to look for + * @param[in] num_bits Number of bits to check, must be larger than 0 + * @param[in] offset Starting bit position + * @param[out] found_at Index of the nth bit set, if found + * + * @retval 0 Operation successful + * @retval 1 Nth bit set was not found in region + * @retval -EINVAL Invalid argument (e.g. out-of-bounds access, trying to count 0 bits, etc.) + */ +int sys_bitarray_find_nth_set(sys_bitarray_t *bitarray, size_t n, size_t num_bits, size_t offset, + size_t *found_at); + +/** + * Count bits set in a bit array region + * + * This counts the number of bits set (@p count) in a + * region (@p offset, @p num_bits). + * + * @param[in] bitarray Bitarray struct + * @param[in] num_bits Number of bits to check, must be larger than 0 + * @param[in] offset Starting bit position + * @param[out] count Number of bits set in the region if successful + * + * @retval 0 Operation successful + * @retval -EINVAL Invalid argument (e.g. out-of-bounds access, trying to count 0 bits, etc.) + */ +int sys_bitarray_popcount_region(sys_bitarray_t *bitarray, size_t num_bits, size_t offset, + size_t *count); + /** * Free bits in a bit array * diff --git a/include/zephyr/sys/cbprintf_internal.h b/include/zephyr/sys/cbprintf_internal.h index da824fea2c4..e54903a0a1d 100644 --- a/include/zephyr/sys/cbprintf_internal.h +++ b/include/zephyr/sys/cbprintf_internal.h @@ -548,7 +548,7 @@ extern "C" { * Floats are promoted to double so they use size of double, others int storage * or it's own storage size if it is bigger than int. * - * @param x argument. + * @param v argument. * * @return Number of bytes used for storing the argument. */ @@ -676,7 +676,7 @@ do { \ Z_CBPRINTF_IS_LONGDOUBLE(_arg) && \ !IS_ENABLED(CONFIG_CBPRINTF_PACKAGE_LONGDOUBLE)),\ "Packaging of long double not enabled in Kconfig."); \ - while (_align_offset % Z_CBPRINTF_ALIGNMENT(_arg) != 0UL) { \ + while ((_align_offset % Z_CBPRINTF_ALIGNMENT(_arg)) != 0UL) { \ _idx += sizeof(int); \ _align_offset += sizeof(int); \ } \ diff --git a/include/zephyr/sys/list_gen.h b/include/zephyr/sys/list_gen.h index ba29f7d9bec..82d1986fe9b 100644 --- a/include/zephyr/sys/list_gen.h +++ b/include/zephyr/sys/list_gen.h @@ -72,7 +72,7 @@ static inline sys_ ## __nname ## _t * \ sys_ ## __lname ## _peek_next(sys_ ## __nname ## _t *node) \ { \ - return node != NULL ? \ + return (node != NULL) ? \ sys_ ## __lname ## _peek_next_no_check(node) : \ NULL; \ } diff --git a/include/zephyr/sys/math_extras_impl.h b/include/zephyr/sys/math_extras_impl.h index f6f856c4ad4..76e0fa19cb6 100644 --- a/include/zephyr/sys/math_extras_impl.h +++ b/include/zephyr/sys/math_extras_impl.h @@ -187,7 +187,7 @@ static inline bool size_mul_overflow(size_t a, size_t b, size_t *result) #if use_builtin(__builtin_clz) static inline int u32_count_leading_zeros(uint32_t x) { - return x == 0 ? 32 : __builtin_clz(x); + return (x == 0) ? 32 : __builtin_clz(x); } #else /* !use_builtin(__builtin_clz) */ static inline int u32_count_leading_zeros(uint32_t x) @@ -205,7 +205,7 @@ static inline int u32_count_leading_zeros(uint32_t x) #if use_builtin(__builtin_clzll) static inline int u64_count_leading_zeros(uint64_t x) { - return x == 0 ? 64 : __builtin_clzll(x); + return (x == 0) ? 64 : __builtin_clzll(x); } #else /* !use_builtin(__builtin_clzll) */ static inline int u64_count_leading_zeros(uint64_t x) @@ -221,7 +221,7 @@ static inline int u64_count_leading_zeros(uint64_t x) #if use_builtin(__builtin_ctz) static inline int u32_count_trailing_zeros(uint32_t x) { - return x == 0 ? 32 : __builtin_ctz(x); + return (x == 0) ? 32 : __builtin_ctz(x); } #else /* !use_builtin(__builtin_ctz) */ static inline int u32_count_trailing_zeros(uint32_t x) @@ -239,7 +239,7 @@ static inline int u32_count_trailing_zeros(uint32_t x) #if use_builtin(__builtin_ctzll) static inline int u64_count_trailing_zeros(uint64_t x) { - return x == 0 ? 64 : __builtin_ctzll(x); + return (x == 0) ? 64 : __builtin_ctzll(x); } #else /* !use_builtin(__builtin_ctzll) */ static inline int u64_count_trailing_zeros(uint64_t x) diff --git a/include/zephyr/sys/rb.h b/include/zephyr/sys/rb.h index 3054119ff66..71d671b6222 100644 --- a/include/zephyr/sys/rb.h +++ b/include/zephyr/sys/rb.h @@ -232,7 +232,7 @@ struct rbnode *z_rb_foreach_next(struct rbtree *tree, struct _rb_foreach *f); for (struct _rb_foreach __f = _RB_FOREACH_INIT(tree, node); \ ({struct rbnode *n = z_rb_foreach_next(tree, &__f); \ node = n ? CONTAINER_OF(n, __typeof__(*(node)), \ - field) : NULL; }) != NULL; \ + field) : NULL; (node); }) != NULL; \ /**/) /** @} */ diff --git a/include/zephyr/sys/sflist.h b/include/zephyr/sys/sflist.h index 97580800831..f26c69270a4 100644 --- a/include/zephyr/sys/sflist.h +++ b/include/zephyr/sys/sflist.h @@ -12,7 +12,7 @@ * @brief Flagged single-linked list implementation. * * Similar to @ref single-linked-list_apis with the added ability to define - * two bits of user "flags" for each node. They can be accessed and modified + * user "flags" bits for each node. They can be accessed and modified * using the sys_sfnode_flags_get() and sys_sfnode_flags_set() APIs. * * Flagged single-linked list implementation using inline macros/functions. @@ -25,7 +25,7 @@ #ifndef ZEPHYR_INCLUDE_SYS_SFLIST_H_ #define ZEPHYR_INCLUDE_SYS_SFLIST_H_ -#include +#include #include #include #include "list_gen.h" @@ -34,15 +34,9 @@ extern "C" { #endif -#ifdef __LP64__ -typedef uint64_t unative_t; -#else -typedef uint32_t unative_t; -#endif - /** @cond INTERNAL_HIDDEN */ struct _sfnode { - unative_t next_and_flags; + uintptr_t next_and_flags; }; /** @endcond */ @@ -218,7 +212,11 @@ static inline void sys_sflist_init(sys_sflist_t *list) * @param ptr_to_list A pointer on the list to initialize */ #define SYS_SFLIST_STATIC_INIT(ptr_to_list) {NULL, NULL} -#define SYS_SFLIST_FLAGS_MASK 0x3UL + +/* Flag bits are stored in unused LSB of the sys_sfnode_t pointer */ +#define SYS_SFLIST_FLAGS_MASK ((uintptr_t)(__alignof__(sys_sfnode_t) - 1)) +/* At least 2 available flag bits are expected */ +BUILD_ASSERT(SYS_SFLIST_FLAGS_MASK >= 0x3); static inline sys_sfnode_t *z_sfnode_next_peek(sys_sfnode_t *node) { @@ -232,7 +230,7 @@ static inline void z_sfnode_next_set(sys_sfnode_t *parent, { uint8_t cur_flags = sys_sfnode_flags_get(parent); - parent->next_and_flags = cur_flags | (unative_t)child; + parent->next_and_flags = cur_flags | (uintptr_t)child; } static inline void z_sflist_head_set(sys_sflist_t *list, sys_sfnode_t *node) @@ -277,7 +275,8 @@ static inline sys_sfnode_t *sys_sflist_peek_tail(sys_sflist_t *list) * @brief Fetch flags value for a particular sfnode * * @param node A pointer to the node to fetch flags from - * @return The value of flags, which will be between 0 and 3 + * @return The value of flags, which will be between 0 and 3 on 32-bit + * architectures, or between 0 and 7 on 64-bit architectures */ static inline uint8_t sys_sfnode_flags_get(sys_sfnode_t *node) { @@ -288,14 +287,15 @@ static inline uint8_t sys_sfnode_flags_get(sys_sfnode_t *node) * @brief Initialize an sflist node * * Set an initial flags value for this slist node, which can be a value between - * 0 and 3. These flags will persist even if the node is moved around - * within a list, removed, or transplanted to a different slist. + * 0 and 3 on 32-bit architectures, or between 0 and 7 on 64-bit architectures. + * These flags will persist even if the node is moved around within a list, + * removed, or transplanted to a different slist. * * This is ever so slightly faster than sys_sfnode_flags_set() and should * only be used on a node that hasn't been added to any list. * * @param node A pointer to the node to set the flags on - * @param flags A value between 0 and 3 to set the flags value + * @param flags The flags value to set */ static inline void sys_sfnode_init(sys_sfnode_t *node, uint8_t flags) { @@ -307,16 +307,17 @@ static inline void sys_sfnode_init(sys_sfnode_t *node, uint8_t flags) * @brief Set flags value for an sflist node * * Set a flags value for this slist node, which can be a value between - * 0 and 3. These flags will persist even if the node is moved around - * within a list, removed, or transplanted to a different slist. + * 0 and 3 on 32-bit architectures, or between 0 and 7 on 64-bit architectures. + * These flags will persist even if the node is moved around within a list, + * removed, or transplanted to a different slist. * * @param node A pointer to the node to set the flags on - * @param flags A value between 0 and 3 to set the flags value + * @param flags The flags value to set */ static inline void sys_sfnode_flags_set(sys_sfnode_t *node, uint8_t flags) { __ASSERT((flags & ~SYS_SFLIST_FLAGS_MASK) == 0UL, "flags too large"); - node->next_and_flags = (unative_t)(z_sfnode_next_peek(node)) | flags; + node->next_and_flags = (uintptr_t)(z_sfnode_next_peek(node)) | flags; } /* diff --git a/include/zephyr/sys/sys_heap.h b/include/zephyr/sys/sys_heap.h index aa72793a242..82f7202048e 100644 --- a/include/zephyr/sys/sys_heap.h +++ b/include/zephyr/sys/sys_heap.h @@ -162,11 +162,6 @@ void sys_heap_free(struct sys_heap *heap, void *mem); * new block fails, then NULL will be returned and the old block will * not be freed or modified. * - * @note The return of a NULL on failure is a different behavior than - * POSIX realloc(), which specifies that the original pointer will be - * returned (i.e. it is not possible to safely detect realloc() - * failure in POSIX, but it is here). - * * @param heap Heap from which to allocate * @param ptr Original pointer returned from a previous allocation * @param align Alignment in bytes, must be a power of two diff --git a/include/zephyr/sys/time_units.h b/include/zephyr/sys/time_units.h index 62c199bc488..e088099ef91 100644 --- a/include/zephyr/sys/time_units.h +++ b/include/zephyr/sys/time_units.h @@ -56,7 +56,7 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) } #endif /* CONFIG_TIMER_READS_ITS_FREQUENCY_AT_RUNTIME */ -#if defined(__cplusplus) && __cplusplus >= 201402L +#if defined(__cplusplus) && (__cplusplus >= 201402L) #if defined(CONFIG_TIMER_READS_ITS_FREQUENCY_AT_RUNTIME) #define TIME_CONSTEXPR #else @@ -272,20 +272,21 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * #!/usr/bin/perl -w * use strict; * - * my %human = ("ms" => "milliseconds", + * my %human = ("sec" => "seconds", + * "ms" => "milliseconds", * "us" => "microseconds", * "ns" => "nanoseconds", * "cyc" => "hardware cycles", * "ticks" => "ticks"); * my %human_round = ("ceil" => "Rounds up", - * "near" => "Round nearest", - * "floor" => "Truncates"); + * "near" => "Round nearest", + * "floor" => "Truncates"); * * sub big { return $_[0] eq "us" || $_[0] eq "ns"; } - * sub prefix { return $_[0] eq "ms" || $_[0] eq "us" || $_[0] eq "ns"; } + * sub prefix { return $_[0] eq "sec" || $_[0] eq "ms" || $_[0] eq "us" || $_[0] eq "ns"; } * - * for my $from_unit ("ms", "us", "ns", "cyc", "ticks") { - * for my $to_unit ("ms", "us", "ns", "cyc", "ticks") { + * for my $from_unit ("sec", "ms", "us", "ns", "cyc", "ticks") { + * for my $to_unit ("sec", "ms", "us", "ns", "cyc", "ticks") { * next if $from_unit eq $to_unit; * next if prefix($from_unit) && prefix($to_unit); * for my $round ("floor", "near", "ceil") { @@ -301,7 +302,7 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * * my $hfrom = $human{$from_unit}; * my $hto = $human{$to_unit}; - * my $hround = $human_round{$round}; + * my $hround = $human_round{$round}; * print "/", "** \@brief Convert $hfrom to $hto. $ret32 bits. $hround.\n"; * print " *\n"; * print " * Converts time values in $hfrom to $hto.\n"; @@ -314,12 +315,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * print " * Truncates to the next lowest output unit.\n"; * } * print " *\n"; - * print " * \@param t Source time in $hfrom. uint64_t\n"; - * print " *\n"; + * print " * \@warning Generated. Do not edit. See above.\n"; + * print " *\n"; + * print " * \@param t Source time in $hfrom. uint64_t\n"; + * print " *\n"; * print " * \@return The converted time value in $hto. $type\n"; * print " *", "/\n"; - * - * print "/", "* Generated. Do not edit. See above. *", "/\n"; * print "#define $sym(t) \\\n"; * print "\tz_tmcvt_$ret32(t, Z_HZ_$from_unit, Z_HZ_$to_unit,"; * print " $const_hz, $rup, $roff)\n"; @@ -333,6 +334,7 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) /* Some more concise declarations to simplify the generator script and * save bytes below */ +#define Z_HZ_sec 1 #define Z_HZ_ms 1000 #define Z_HZ_us 1000000 #define Z_HZ_ns 1000000000 @@ -340,17 +342,210 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) #define Z_HZ_ticks CONFIG_SYS_CLOCK_TICKS_PER_SEC #define Z_CCYC (!IS_ENABLED(CONFIG_TIMER_READS_ITS_FREQUENCY_AT_RUNTIME)) +/** @brief Convert seconds to hardware cycles. 32 bits. Truncates. + * + * Converts time values in seconds to hardware cycles. + * Computes result in 32 bit precision. + * Truncates to the next lowest output unit. + * + * @warning Generated. Do not edit. See above. + * + * @param t Source time in seconds. uint64_t + * + * @return The converted time value in hardware cycles. uint32_t + */ +#define k_sec_to_cyc_floor32(t) \ + z_tmcvt_32(t, Z_HZ_sec, Z_HZ_cyc, Z_CCYC, false, false) + + +/** @brief Convert seconds to hardware cycles. 64 bits. Truncates. + * + * Converts time values in seconds to hardware cycles. + * Computes result in 64 bit precision. + * Truncates to the next lowest output unit. + * + * @warning Generated. Do not edit. See above. + * + * @param t Source time in seconds. uint64_t + * + * @return The converted time value in hardware cycles. uint64_t + */ +#define k_sec_to_cyc_floor64(t) \ + z_tmcvt_64(t, Z_HZ_sec, Z_HZ_cyc, Z_CCYC, false, false) + + +/** @brief Convert seconds to hardware cycles. 32 bits. Round nearest. + * + * Converts time values in seconds to hardware cycles. + * Computes result in 32 bit precision. + * Rounds to the nearest output unit. + * + * @warning Generated. Do not edit. See above. + * + * @param t Source time in seconds. uint64_t + * + * @return The converted time value in hardware cycles. uint32_t + */ +#define k_sec_to_cyc_near32(t) \ + z_tmcvt_32(t, Z_HZ_sec, Z_HZ_cyc, Z_CCYC, false, true) + + +/** @brief Convert seconds to hardware cycles. 64 bits. Round nearest. + * + * Converts time values in seconds to hardware cycles. + * Computes result in 64 bit precision. + * Rounds to the nearest output unit. + * + * @warning Generated. Do not edit. See above. + * + * @param t Source time in seconds. uint64_t + * + * @return The converted time value in hardware cycles. uint64_t + */ +#define k_sec_to_cyc_near64(t) \ + z_tmcvt_64(t, Z_HZ_sec, Z_HZ_cyc, Z_CCYC, false, true) + + +/** @brief Convert seconds to hardware cycles. 32 bits. Rounds up. + * + * Converts time values in seconds to hardware cycles. + * Computes result in 32 bit precision. + * Rounds up to the next highest output unit. + * + * @warning Generated. Do not edit. See above. + * + * @param t Source time in seconds. uint64_t + * + * @return The converted time value in hardware cycles. uint32_t + */ +#define k_sec_to_cyc_ceil32(t) \ + z_tmcvt_32(t, Z_HZ_sec, Z_HZ_cyc, Z_CCYC, true, false) + + +/** @brief Convert seconds to hardware cycles. 64 bits. Rounds up. + * + * Converts time values in seconds to hardware cycles. + * Computes result in 64 bit precision. + * Rounds up to the next highest output unit. + * + * @warning Generated. Do not edit. See above. + * + * @param t Source time in seconds. uint64_t + * + * @return The converted time value in hardware cycles. uint64_t + */ +#define k_sec_to_cyc_ceil64(t) \ + z_tmcvt_64(t, Z_HZ_sec, Z_HZ_cyc, Z_CCYC, true, false) + + +/** @brief Convert seconds to ticks. 32 bits. Truncates. + * + * Converts time values in seconds to ticks. + * Computes result in 32 bit precision. + * Truncates to the next lowest output unit. + * + * @warning Generated. Do not edit. See above. + * + * @param t Source time in seconds. uint64_t + * + * @return The converted time value in ticks. uint32_t + */ +#define k_sec_to_ticks_floor32(t) \ + z_tmcvt_32(t, Z_HZ_sec, Z_HZ_ticks, true, false, false) + + +/** @brief Convert seconds to ticks. 64 bits. Truncates. + * + * Converts time values in seconds to ticks. + * Computes result in 64 bit precision. + * Truncates to the next lowest output unit. + * + * @warning Generated. Do not edit. See above. + * + * @param t Source time in seconds. uint64_t + * + * @return The converted time value in ticks. uint64_t + */ +#define k_sec_to_ticks_floor64(t) \ + z_tmcvt_64(t, Z_HZ_sec, Z_HZ_ticks, true, false, false) + + +/** @brief Convert seconds to ticks. 32 bits. Round nearest. + * + * Converts time values in seconds to ticks. + * Computes result in 32 bit precision. + * Rounds to the nearest output unit. + * + * @warning Generated. Do not edit. See above. + * + * @param t Source time in seconds. uint64_t + * + * @return The converted time value in ticks. uint32_t + */ +#define k_sec_to_ticks_near32(t) \ + z_tmcvt_32(t, Z_HZ_sec, Z_HZ_ticks, true, false, true) + + +/** @brief Convert seconds to ticks. 64 bits. Round nearest. + * + * Converts time values in seconds to ticks. + * Computes result in 64 bit precision. + * Rounds to the nearest output unit. + * + * @warning Generated. Do not edit. See above. + * + * @param t Source time in seconds. uint64_t + * + * @return The converted time value in ticks. uint64_t + */ +#define k_sec_to_ticks_near64(t) \ + z_tmcvt_64(t, Z_HZ_sec, Z_HZ_ticks, true, false, true) + + +/** @brief Convert seconds to ticks. 32 bits. Rounds up. + * + * Converts time values in seconds to ticks. + * Computes result in 32 bit precision. + * Rounds up to the next highest output unit. + * + * @warning Generated. Do not edit. See above. + * + * @param t Source time in seconds. uint64_t + * + * @return The converted time value in ticks. uint32_t + */ +#define k_sec_to_ticks_ceil32(t) \ + z_tmcvt_32(t, Z_HZ_sec, Z_HZ_ticks, true, true, false) + + +/** @brief Convert seconds to ticks. 64 bits. Rounds up. + * + * Converts time values in seconds to ticks. + * Computes result in 64 bit precision. + * Rounds up to the next highest output unit. + * + * @warning Generated. Do not edit. See above. + * + * @param t Source time in seconds. uint64_t + * + * @return The converted time value in ticks. uint64_t + */ +#define k_sec_to_ticks_ceil64(t) \ + z_tmcvt_64(t, Z_HZ_sec, Z_HZ_ticks, true, true, false) + + /** @brief Convert milliseconds to hardware cycles. 32 bits. Truncates. * * Converts time values in milliseconds to hardware cycles. * Computes result in 32 bit precision. * Truncates to the next lowest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in milliseconds. uint64_t * * @return The converted time value in hardware cycles. uint32_t */ -/* Generated. Do not edit. See above. */ #define k_ms_to_cyc_floor32(t) \ z_tmcvt_32(t, Z_HZ_ms, Z_HZ_cyc, Z_CCYC, false, false) @@ -361,11 +556,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 64 bit precision. * Truncates to the next lowest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in milliseconds. uint64_t * * @return The converted time value in hardware cycles. uint64_t */ -/* Generated. Do not edit. See above. */ #define k_ms_to_cyc_floor64(t) \ z_tmcvt_64(t, Z_HZ_ms, Z_HZ_cyc, Z_CCYC, false, false) @@ -376,11 +572,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 32 bit precision. * Rounds to the nearest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in milliseconds. uint64_t * * @return The converted time value in hardware cycles. uint32_t */ -/* Generated. Do not edit. See above. */ #define k_ms_to_cyc_near32(t) \ z_tmcvt_32(t, Z_HZ_ms, Z_HZ_cyc, Z_CCYC, false, true) @@ -391,11 +588,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 64 bit precision. * Rounds to the nearest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in milliseconds. uint64_t * * @return The converted time value in hardware cycles. uint64_t */ -/* Generated. Do not edit. See above. */ #define k_ms_to_cyc_near64(t) \ z_tmcvt_64(t, Z_HZ_ms, Z_HZ_cyc, Z_CCYC, false, true) @@ -406,11 +604,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 32 bit precision. * Rounds up to the next highest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in milliseconds. uint64_t * * @return The converted time value in hardware cycles. uint32_t */ -/* Generated. Do not edit. See above. */ #define k_ms_to_cyc_ceil32(t) \ z_tmcvt_32(t, Z_HZ_ms, Z_HZ_cyc, Z_CCYC, true, false) @@ -421,11 +620,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 64 bit precision. * Rounds up to the next highest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in milliseconds. uint64_t * * @return The converted time value in hardware cycles. uint64_t */ -/* Generated. Do not edit. See above. */ #define k_ms_to_cyc_ceil64(t) \ z_tmcvt_64(t, Z_HZ_ms, Z_HZ_cyc, Z_CCYC, true, false) @@ -436,11 +636,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 32 bit precision. * Truncates to the next lowest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in milliseconds. uint64_t * * @return The converted time value in ticks. uint32_t */ -/* Generated. Do not edit. See above. */ #define k_ms_to_ticks_floor32(t) \ z_tmcvt_32(t, Z_HZ_ms, Z_HZ_ticks, true, false, false) @@ -451,11 +652,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 64 bit precision. * Truncates to the next lowest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in milliseconds. uint64_t * * @return The converted time value in ticks. uint64_t */ -/* Generated. Do not edit. See above. */ #define k_ms_to_ticks_floor64(t) \ z_tmcvt_64(t, Z_HZ_ms, Z_HZ_ticks, true, false, false) @@ -466,11 +668,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 32 bit precision. * Rounds to the nearest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in milliseconds. uint64_t * * @return The converted time value in ticks. uint32_t */ -/* Generated. Do not edit. See above. */ #define k_ms_to_ticks_near32(t) \ z_tmcvt_32(t, Z_HZ_ms, Z_HZ_ticks, true, false, true) @@ -481,11 +684,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 64 bit precision. * Rounds to the nearest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in milliseconds. uint64_t * * @return The converted time value in ticks. uint64_t */ -/* Generated. Do not edit. See above. */ #define k_ms_to_ticks_near64(t) \ z_tmcvt_64(t, Z_HZ_ms, Z_HZ_ticks, true, false, true) @@ -496,11 +700,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 32 bit precision. * Rounds up to the next highest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in milliseconds. uint64_t * * @return The converted time value in ticks. uint32_t */ -/* Generated. Do not edit. See above. */ #define k_ms_to_ticks_ceil32(t) \ z_tmcvt_32(t, Z_HZ_ms, Z_HZ_ticks, true, true, false) @@ -511,11 +716,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 64 bit precision. * Rounds up to the next highest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in milliseconds. uint64_t * * @return The converted time value in ticks. uint64_t */ -/* Generated. Do not edit. See above. */ #define k_ms_to_ticks_ceil64(t) \ z_tmcvt_64(t, Z_HZ_ms, Z_HZ_ticks, true, true, false) @@ -526,11 +732,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 32 bit precision. * Truncates to the next lowest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in microseconds. uint64_t * * @return The converted time value in hardware cycles. uint32_t */ -/* Generated. Do not edit. See above. */ #define k_us_to_cyc_floor32(t) \ z_tmcvt_32(t, Z_HZ_us, Z_HZ_cyc, Z_CCYC, false, false) @@ -541,11 +748,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 64 bit precision. * Truncates to the next lowest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in microseconds. uint64_t * * @return The converted time value in hardware cycles. uint64_t */ -/* Generated. Do not edit. See above. */ #define k_us_to_cyc_floor64(t) \ z_tmcvt_64(t, Z_HZ_us, Z_HZ_cyc, Z_CCYC, false, false) @@ -556,11 +764,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 32 bit precision. * Rounds to the nearest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in microseconds. uint64_t * * @return The converted time value in hardware cycles. uint32_t */ -/* Generated. Do not edit. See above. */ #define k_us_to_cyc_near32(t) \ z_tmcvt_32(t, Z_HZ_us, Z_HZ_cyc, Z_CCYC, false, true) @@ -571,11 +780,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 64 bit precision. * Rounds to the nearest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in microseconds. uint64_t * * @return The converted time value in hardware cycles. uint64_t */ -/* Generated. Do not edit. See above. */ #define k_us_to_cyc_near64(t) \ z_tmcvt_64(t, Z_HZ_us, Z_HZ_cyc, Z_CCYC, false, true) @@ -586,11 +796,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 32 bit precision. * Rounds up to the next highest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in microseconds. uint64_t * * @return The converted time value in hardware cycles. uint32_t */ -/* Generated. Do not edit. See above. */ #define k_us_to_cyc_ceil32(t) \ z_tmcvt_32(t, Z_HZ_us, Z_HZ_cyc, Z_CCYC, true, false) @@ -601,11 +812,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 64 bit precision. * Rounds up to the next highest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in microseconds. uint64_t * * @return The converted time value in hardware cycles. uint64_t */ -/* Generated. Do not edit. See above. */ #define k_us_to_cyc_ceil64(t) \ z_tmcvt_64(t, Z_HZ_us, Z_HZ_cyc, Z_CCYC, true, false) @@ -616,11 +828,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 32 bit precision. * Truncates to the next lowest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in microseconds. uint64_t * * @return The converted time value in ticks. uint32_t */ -/* Generated. Do not edit. See above. */ #define k_us_to_ticks_floor32(t) \ z_tmcvt_32(t, Z_HZ_us, Z_HZ_ticks, true, false, false) @@ -631,11 +844,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 64 bit precision. * Truncates to the next lowest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in microseconds. uint64_t * * @return The converted time value in ticks. uint64_t */ -/* Generated. Do not edit. See above. */ #define k_us_to_ticks_floor64(t) \ z_tmcvt_64(t, Z_HZ_us, Z_HZ_ticks, true, false, false) @@ -646,11 +860,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 32 bit precision. * Rounds to the nearest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in microseconds. uint64_t * * @return The converted time value in ticks. uint32_t */ -/* Generated. Do not edit. See above. */ #define k_us_to_ticks_near32(t) \ z_tmcvt_32(t, Z_HZ_us, Z_HZ_ticks, true, false, true) @@ -661,11 +876,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 64 bit precision. * Rounds to the nearest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in microseconds. uint64_t * * @return The converted time value in ticks. uint64_t */ -/* Generated. Do not edit. See above. */ #define k_us_to_ticks_near64(t) \ z_tmcvt_64(t, Z_HZ_us, Z_HZ_ticks, true, false, true) @@ -676,11 +892,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 32 bit precision. * Rounds up to the next highest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in microseconds. uint64_t * * @return The converted time value in ticks. uint32_t */ -/* Generated. Do not edit. See above. */ #define k_us_to_ticks_ceil32(t) \ z_tmcvt_32(t, Z_HZ_us, Z_HZ_ticks, true, true, false) @@ -691,11 +908,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 64 bit precision. * Rounds up to the next highest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in microseconds. uint64_t * * @return The converted time value in ticks. uint64_t */ -/* Generated. Do not edit. See above. */ #define k_us_to_ticks_ceil64(t) \ z_tmcvt_64(t, Z_HZ_us, Z_HZ_ticks, true, true, false) @@ -706,11 +924,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 32 bit precision. * Truncates to the next lowest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in nanoseconds. uint64_t * * @return The converted time value in hardware cycles. uint32_t */ -/* Generated. Do not edit. See above. */ #define k_ns_to_cyc_floor32(t) \ z_tmcvt_32(t, Z_HZ_ns, Z_HZ_cyc, Z_CCYC, false, false) @@ -721,11 +940,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 64 bit precision. * Truncates to the next lowest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in nanoseconds. uint64_t * * @return The converted time value in hardware cycles. uint64_t */ -/* Generated. Do not edit. See above. */ #define k_ns_to_cyc_floor64(t) \ z_tmcvt_64(t, Z_HZ_ns, Z_HZ_cyc, Z_CCYC, false, false) @@ -736,11 +956,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 32 bit precision. * Rounds to the nearest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in nanoseconds. uint64_t * * @return The converted time value in hardware cycles. uint32_t */ -/* Generated. Do not edit. See above. */ #define k_ns_to_cyc_near32(t) \ z_tmcvt_32(t, Z_HZ_ns, Z_HZ_cyc, Z_CCYC, false, true) @@ -751,11 +972,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 64 bit precision. * Rounds to the nearest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in nanoseconds. uint64_t * * @return The converted time value in hardware cycles. uint64_t */ -/* Generated. Do not edit. See above. */ #define k_ns_to_cyc_near64(t) \ z_tmcvt_64(t, Z_HZ_ns, Z_HZ_cyc, Z_CCYC, false, true) @@ -766,11 +988,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 32 bit precision. * Rounds up to the next highest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in nanoseconds. uint64_t * * @return The converted time value in hardware cycles. uint32_t */ -/* Generated. Do not edit. See above. */ #define k_ns_to_cyc_ceil32(t) \ z_tmcvt_32(t, Z_HZ_ns, Z_HZ_cyc, Z_CCYC, true, false) @@ -781,11 +1004,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 64 bit precision. * Rounds up to the next highest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in nanoseconds. uint64_t * * @return The converted time value in hardware cycles. uint64_t */ -/* Generated. Do not edit. See above. */ #define k_ns_to_cyc_ceil64(t) \ z_tmcvt_64(t, Z_HZ_ns, Z_HZ_cyc, Z_CCYC, true, false) @@ -796,11 +1020,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 32 bit precision. * Truncates to the next lowest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in nanoseconds. uint64_t * * @return The converted time value in ticks. uint32_t */ -/* Generated. Do not edit. See above. */ #define k_ns_to_ticks_floor32(t) \ z_tmcvt_32(t, Z_HZ_ns, Z_HZ_ticks, true, false, false) @@ -811,11 +1036,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 64 bit precision. * Truncates to the next lowest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in nanoseconds. uint64_t * * @return The converted time value in ticks. uint64_t */ -/* Generated. Do not edit. See above. */ #define k_ns_to_ticks_floor64(t) \ z_tmcvt_64(t, Z_HZ_ns, Z_HZ_ticks, true, false, false) @@ -826,11 +1052,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 32 bit precision. * Rounds to the nearest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in nanoseconds. uint64_t * * @return The converted time value in ticks. uint32_t */ -/* Generated. Do not edit. See above. */ #define k_ns_to_ticks_near32(t) \ z_tmcvt_32(t, Z_HZ_ns, Z_HZ_ticks, true, false, true) @@ -841,11 +1068,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 64 bit precision. * Rounds to the nearest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in nanoseconds. uint64_t * * @return The converted time value in ticks. uint64_t */ -/* Generated. Do not edit. See above. */ #define k_ns_to_ticks_near64(t) \ z_tmcvt_64(t, Z_HZ_ns, Z_HZ_ticks, true, false, true) @@ -856,11 +1084,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 32 bit precision. * Rounds up to the next highest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in nanoseconds. uint64_t * * @return The converted time value in ticks. uint32_t */ -/* Generated. Do not edit. See above. */ #define k_ns_to_ticks_ceil32(t) \ z_tmcvt_32(t, Z_HZ_ns, Z_HZ_ticks, true, true, false) @@ -871,26 +1100,124 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 64 bit precision. * Rounds up to the next highest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in nanoseconds. uint64_t * * @return The converted time value in ticks. uint64_t */ -/* Generated. Do not edit. See above. */ #define k_ns_to_ticks_ceil64(t) \ z_tmcvt_64(t, Z_HZ_ns, Z_HZ_ticks, true, true, false) +/** @brief Convert hardware cycles to seconds. 32 bits. Truncates. + * + * Converts time values in hardware cycles to seconds. + * Computes result in 32 bit precision. + * Truncates to the next lowest output unit. + * + * @warning Generated. Do not edit. See above. + * + * @param t Source time in hardware cycles. uint64_t + * + * @return The converted time value in seconds. uint32_t + */ +#define k_cyc_to_sec_floor32(t) \ + z_tmcvt_32(t, Z_HZ_cyc, Z_HZ_sec, Z_CCYC, false, false) + + +/** @brief Convert hardware cycles to seconds. 64 bits. Truncates. + * + * Converts time values in hardware cycles to seconds. + * Computes result in 64 bit precision. + * Truncates to the next lowest output unit. + * + * @warning Generated. Do not edit. See above. + * + * @param t Source time in hardware cycles. uint64_t + * + * @return The converted time value in seconds. uint64_t + */ +#define k_cyc_to_sec_floor64(t) \ + z_tmcvt_64(t, Z_HZ_cyc, Z_HZ_sec, Z_CCYC, false, false) + + +/** @brief Convert hardware cycles to seconds. 32 bits. Round nearest. + * + * Converts time values in hardware cycles to seconds. + * Computes result in 32 bit precision. + * Rounds to the nearest output unit. + * + * @warning Generated. Do not edit. See above. + * + * @param t Source time in hardware cycles. uint64_t + * + * @return The converted time value in seconds. uint32_t + */ +#define k_cyc_to_sec_near32(t) \ + z_tmcvt_32(t, Z_HZ_cyc, Z_HZ_sec, Z_CCYC, false, true) + + +/** @brief Convert hardware cycles to seconds. 64 bits. Round nearest. + * + * Converts time values in hardware cycles to seconds. + * Computes result in 64 bit precision. + * Rounds to the nearest output unit. + * + * @warning Generated. Do not edit. See above. + * + * @param t Source time in hardware cycles. uint64_t + * + * @return The converted time value in seconds. uint64_t + */ +#define k_cyc_to_sec_near64(t) \ + z_tmcvt_64(t, Z_HZ_cyc, Z_HZ_sec, Z_CCYC, false, true) + + +/** @brief Convert hardware cycles to seconds. 32 bits. Rounds up. + * + * Converts time values in hardware cycles to seconds. + * Computes result in 32 bit precision. + * Rounds up to the next highest output unit. + * + * @warning Generated. Do not edit. See above. + * + * @param t Source time in hardware cycles. uint64_t + * + * @return The converted time value in seconds. uint32_t + */ +#define k_cyc_to_sec_ceil32(t) \ + z_tmcvt_32(t, Z_HZ_cyc, Z_HZ_sec, Z_CCYC, true, false) + + +/** @brief Convert hardware cycles to seconds. 64 bits. Rounds up. + * + * Converts time values in hardware cycles to seconds. + * Computes result in 64 bit precision. + * Rounds up to the next highest output unit. + * + * @warning Generated. Do not edit. See above. + * + * @param t Source time in hardware cycles. uint64_t + * + * @return The converted time value in seconds. uint64_t + */ +#define k_cyc_to_sec_ceil64(t) \ + z_tmcvt_64(t, Z_HZ_cyc, Z_HZ_sec, Z_CCYC, true, false) + + /** @brief Convert hardware cycles to milliseconds. 32 bits. Truncates. * * Converts time values in hardware cycles to milliseconds. * Computes result in 32 bit precision. * Truncates to the next lowest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in hardware cycles. uint64_t * * @return The converted time value in milliseconds. uint32_t */ -/* Generated. Do not edit. See above. */ #define k_cyc_to_ms_floor32(t) \ z_tmcvt_32(t, Z_HZ_cyc, Z_HZ_ms, Z_CCYC, false, false) @@ -901,11 +1228,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 64 bit precision. * Truncates to the next lowest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in hardware cycles. uint64_t * * @return The converted time value in milliseconds. uint64_t */ -/* Generated. Do not edit. See above. */ #define k_cyc_to_ms_floor64(t) \ z_tmcvt_64(t, Z_HZ_cyc, Z_HZ_ms, Z_CCYC, false, false) @@ -916,11 +1244,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 32 bit precision. * Rounds to the nearest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in hardware cycles. uint64_t * * @return The converted time value in milliseconds. uint32_t */ -/* Generated. Do not edit. See above. */ #define k_cyc_to_ms_near32(t) \ z_tmcvt_32(t, Z_HZ_cyc, Z_HZ_ms, Z_CCYC, false, true) @@ -931,11 +1260,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 64 bit precision. * Rounds to the nearest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in hardware cycles. uint64_t * * @return The converted time value in milliseconds. uint64_t */ -/* Generated. Do not edit. See above. */ #define k_cyc_to_ms_near64(t) \ z_tmcvt_64(t, Z_HZ_cyc, Z_HZ_ms, Z_CCYC, false, true) @@ -946,11 +1276,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 32 bit precision. * Rounds up to the next highest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in hardware cycles. uint64_t * * @return The converted time value in milliseconds. uint32_t */ -/* Generated. Do not edit. See above. */ #define k_cyc_to_ms_ceil32(t) \ z_tmcvt_32(t, Z_HZ_cyc, Z_HZ_ms, Z_CCYC, true, false) @@ -961,11 +1292,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 64 bit precision. * Rounds up to the next highest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in hardware cycles. uint64_t * * @return The converted time value in milliseconds. uint64_t */ -/* Generated. Do not edit. See above. */ #define k_cyc_to_ms_ceil64(t) \ z_tmcvt_64(t, Z_HZ_cyc, Z_HZ_ms, Z_CCYC, true, false) @@ -976,11 +1308,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 32 bit precision. * Truncates to the next lowest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in hardware cycles. uint64_t * * @return The converted time value in microseconds. uint32_t */ -/* Generated. Do not edit. See above. */ #define k_cyc_to_us_floor32(t) \ z_tmcvt_32(t, Z_HZ_cyc, Z_HZ_us, Z_CCYC, false, false) @@ -991,11 +1324,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 64 bit precision. * Truncates to the next lowest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in hardware cycles. uint64_t * * @return The converted time value in microseconds. uint64_t */ -/* Generated. Do not edit. See above. */ #define k_cyc_to_us_floor64(t) \ z_tmcvt_64(t, Z_HZ_cyc, Z_HZ_us, Z_CCYC, false, false) @@ -1006,11 +1340,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 32 bit precision. * Rounds to the nearest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in hardware cycles. uint64_t * * @return The converted time value in microseconds. uint32_t */ -/* Generated. Do not edit. See above. */ #define k_cyc_to_us_near32(t) \ z_tmcvt_32(t, Z_HZ_cyc, Z_HZ_us, Z_CCYC, false, true) @@ -1021,11 +1356,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 64 bit precision. * Rounds to the nearest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in hardware cycles. uint64_t * * @return The converted time value in microseconds. uint64_t */ -/* Generated. Do not edit. See above. */ #define k_cyc_to_us_near64(t) \ z_tmcvt_64(t, Z_HZ_cyc, Z_HZ_us, Z_CCYC, false, true) @@ -1036,11 +1372,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 32 bit precision. * Rounds up to the next highest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in hardware cycles. uint64_t * * @return The converted time value in microseconds. uint32_t */ -/* Generated. Do not edit. See above. */ #define k_cyc_to_us_ceil32(t) \ z_tmcvt_32(t, Z_HZ_cyc, Z_HZ_us, Z_CCYC, true, false) @@ -1051,11 +1388,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 64 bit precision. * Rounds up to the next highest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in hardware cycles. uint64_t * * @return The converted time value in microseconds. uint64_t */ -/* Generated. Do not edit. See above. */ #define k_cyc_to_us_ceil64(t) \ z_tmcvt_64(t, Z_HZ_cyc, Z_HZ_us, Z_CCYC, true, false) @@ -1066,11 +1404,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 32 bit precision. * Truncates to the next lowest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in hardware cycles. uint64_t * * @return The converted time value in nanoseconds. uint32_t */ -/* Generated. Do not edit. See above. */ #define k_cyc_to_ns_floor32(t) \ z_tmcvt_32(t, Z_HZ_cyc, Z_HZ_ns, Z_CCYC, false, false) @@ -1081,11 +1420,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 64 bit precision. * Truncates to the next lowest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in hardware cycles. uint64_t * * @return The converted time value in nanoseconds. uint64_t */ -/* Generated. Do not edit. See above. */ #define k_cyc_to_ns_floor64(t) \ z_tmcvt_64(t, Z_HZ_cyc, Z_HZ_ns, Z_CCYC, false, false) @@ -1096,11 +1436,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 32 bit precision. * Rounds to the nearest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in hardware cycles. uint64_t * * @return The converted time value in nanoseconds. uint32_t */ -/* Generated. Do not edit. See above. */ #define k_cyc_to_ns_near32(t) \ z_tmcvt_32(t, Z_HZ_cyc, Z_HZ_ns, Z_CCYC, false, true) @@ -1111,11 +1452,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 64 bit precision. * Rounds to the nearest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in hardware cycles. uint64_t * * @return The converted time value in nanoseconds. uint64_t */ -/* Generated. Do not edit. See above. */ #define k_cyc_to_ns_near64(t) \ z_tmcvt_64(t, Z_HZ_cyc, Z_HZ_ns, Z_CCYC, false, true) @@ -1126,11 +1468,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 32 bit precision. * Rounds up to the next highest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in hardware cycles. uint64_t * * @return The converted time value in nanoseconds. uint32_t */ -/* Generated. Do not edit. See above. */ #define k_cyc_to_ns_ceil32(t) \ z_tmcvt_32(t, Z_HZ_cyc, Z_HZ_ns, Z_CCYC, true, false) @@ -1141,11 +1484,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 64 bit precision. * Rounds up to the next highest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in hardware cycles. uint64_t * * @return The converted time value in nanoseconds. uint64_t */ -/* Generated. Do not edit. See above. */ #define k_cyc_to_ns_ceil64(t) \ z_tmcvt_64(t, Z_HZ_cyc, Z_HZ_ns, Z_CCYC, true, false) @@ -1156,11 +1500,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 32 bit precision. * Truncates to the next lowest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in hardware cycles. uint64_t * * @return The converted time value in ticks. uint32_t */ -/* Generated. Do not edit. See above. */ #define k_cyc_to_ticks_floor32(t) \ z_tmcvt_32(t, Z_HZ_cyc, Z_HZ_ticks, Z_CCYC, false, false) @@ -1171,11 +1516,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 64 bit precision. * Truncates to the next lowest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in hardware cycles. uint64_t * * @return The converted time value in ticks. uint64_t */ -/* Generated. Do not edit. See above. */ #define k_cyc_to_ticks_floor64(t) \ z_tmcvt_64(t, Z_HZ_cyc, Z_HZ_ticks, Z_CCYC, false, false) @@ -1186,11 +1532,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 32 bit precision. * Rounds to the nearest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in hardware cycles. uint64_t * * @return The converted time value in ticks. uint32_t */ -/* Generated. Do not edit. See above. */ #define k_cyc_to_ticks_near32(t) \ z_tmcvt_32(t, Z_HZ_cyc, Z_HZ_ticks, Z_CCYC, false, true) @@ -1201,11 +1548,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 64 bit precision. * Rounds to the nearest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in hardware cycles. uint64_t * * @return The converted time value in ticks. uint64_t */ -/* Generated. Do not edit. See above. */ #define k_cyc_to_ticks_near64(t) \ z_tmcvt_64(t, Z_HZ_cyc, Z_HZ_ticks, Z_CCYC, false, true) @@ -1216,11 +1564,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 32 bit precision. * Rounds up to the next highest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in hardware cycles. uint64_t * * @return The converted time value in ticks. uint32_t */ -/* Generated. Do not edit. See above. */ #define k_cyc_to_ticks_ceil32(t) \ z_tmcvt_32(t, Z_HZ_cyc, Z_HZ_ticks, Z_CCYC, true, false) @@ -1231,26 +1580,124 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 64 bit precision. * Rounds up to the next highest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in hardware cycles. uint64_t * * @return The converted time value in ticks. uint64_t */ -/* Generated. Do not edit. See above. */ #define k_cyc_to_ticks_ceil64(t) \ z_tmcvt_64(t, Z_HZ_cyc, Z_HZ_ticks, Z_CCYC, true, false) +/** @brief Convert ticks to seconds. 32 bits. Truncates. + * + * Converts time values in ticks to seconds. + * Computes result in 32 bit precision. + * Truncates to the next lowest output unit. + * + * @warning Generated. Do not edit. See above. + * + * @param t Source time in ticks. uint64_t + * + * @return The converted time value in seconds. uint32_t + */ +#define k_ticks_to_sec_floor32(t) \ + z_tmcvt_32(t, Z_HZ_ticks, Z_HZ_sec, true, false, false) + + +/** @brief Convert ticks to seconds. 64 bits. Truncates. + * + * Converts time values in ticks to seconds. + * Computes result in 64 bit precision. + * Truncates to the next lowest output unit. + * + * @warning Generated. Do not edit. See above. + * + * @param t Source time in ticks. uint64_t + * + * @return The converted time value in seconds. uint64_t + */ +#define k_ticks_to_sec_floor64(t) \ + z_tmcvt_64(t, Z_HZ_ticks, Z_HZ_sec, true, false, false) + + +/** @brief Convert ticks to seconds. 32 bits. Round nearest. + * + * Converts time values in ticks to seconds. + * Computes result in 32 bit precision. + * Rounds to the nearest output unit. + * + * @warning Generated. Do not edit. See above. + * + * @param t Source time in ticks. uint64_t + * + * @return The converted time value in seconds. uint32_t + */ +#define k_ticks_to_sec_near32(t) \ + z_tmcvt_32(t, Z_HZ_ticks, Z_HZ_sec, true, false, true) + + +/** @brief Convert ticks to seconds. 64 bits. Round nearest. + * + * Converts time values in ticks to seconds. + * Computes result in 64 bit precision. + * Rounds to the nearest output unit. + * + * @warning Generated. Do not edit. See above. + * + * @param t Source time in ticks. uint64_t + * + * @return The converted time value in seconds. uint64_t + */ +#define k_ticks_to_sec_near64(t) \ + z_tmcvt_64(t, Z_HZ_ticks, Z_HZ_sec, true, false, true) + + +/** @brief Convert ticks to seconds. 32 bits. Rounds up. + * + * Converts time values in ticks to seconds. + * Computes result in 32 bit precision. + * Rounds up to the next highest output unit. + * + * @warning Generated. Do not edit. See above. + * + * @param t Source time in ticks. uint64_t + * + * @return The converted time value in seconds. uint32_t + */ +#define k_ticks_to_sec_ceil32(t) \ + z_tmcvt_32(t, Z_HZ_ticks, Z_HZ_sec, true, true, false) + + +/** @brief Convert ticks to seconds. 64 bits. Rounds up. + * + * Converts time values in ticks to seconds. + * Computes result in 64 bit precision. + * Rounds up to the next highest output unit. + * + * @warning Generated. Do not edit. See above. + * + * @param t Source time in ticks. uint64_t + * + * @return The converted time value in seconds. uint64_t + */ +#define k_ticks_to_sec_ceil64(t) \ + z_tmcvt_64(t, Z_HZ_ticks, Z_HZ_sec, true, true, false) + + /** @brief Convert ticks to milliseconds. 32 bits. Truncates. * * Converts time values in ticks to milliseconds. * Computes result in 32 bit precision. * Truncates to the next lowest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in ticks. uint64_t * * @return The converted time value in milliseconds. uint32_t */ -/* Generated. Do not edit. See above. */ #define k_ticks_to_ms_floor32(t) \ z_tmcvt_32(t, Z_HZ_ticks, Z_HZ_ms, true, false, false) @@ -1261,11 +1708,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 64 bit precision. * Truncates to the next lowest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in ticks. uint64_t * * @return The converted time value in milliseconds. uint64_t */ -/* Generated. Do not edit. See above. */ #define k_ticks_to_ms_floor64(t) \ z_tmcvt_64(t, Z_HZ_ticks, Z_HZ_ms, true, false, false) @@ -1276,11 +1724,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 32 bit precision. * Rounds to the nearest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in ticks. uint64_t * * @return The converted time value in milliseconds. uint32_t */ -/* Generated. Do not edit. See above. */ #define k_ticks_to_ms_near32(t) \ z_tmcvt_32(t, Z_HZ_ticks, Z_HZ_ms, true, false, true) @@ -1291,11 +1740,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 64 bit precision. * Rounds to the nearest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in ticks. uint64_t * * @return The converted time value in milliseconds. uint64_t */ -/* Generated. Do not edit. See above. */ #define k_ticks_to_ms_near64(t) \ z_tmcvt_64(t, Z_HZ_ticks, Z_HZ_ms, true, false, true) @@ -1306,11 +1756,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 32 bit precision. * Rounds up to the next highest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in ticks. uint64_t * * @return The converted time value in milliseconds. uint32_t */ -/* Generated. Do not edit. See above. */ #define k_ticks_to_ms_ceil32(t) \ z_tmcvt_32(t, Z_HZ_ticks, Z_HZ_ms, true, true, false) @@ -1321,11 +1772,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 64 bit precision. * Rounds up to the next highest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in ticks. uint64_t * * @return The converted time value in milliseconds. uint64_t */ -/* Generated. Do not edit. See above. */ #define k_ticks_to_ms_ceil64(t) \ z_tmcvt_64(t, Z_HZ_ticks, Z_HZ_ms, true, true, false) @@ -1336,11 +1788,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 32 bit precision. * Truncates to the next lowest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in ticks. uint64_t * * @return The converted time value in microseconds. uint32_t */ -/* Generated. Do not edit. See above. */ #define k_ticks_to_us_floor32(t) \ z_tmcvt_32(t, Z_HZ_ticks, Z_HZ_us, true, false, false) @@ -1351,11 +1804,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 64 bit precision. * Truncates to the next lowest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in ticks. uint64_t * * @return The converted time value in microseconds. uint64_t */ -/* Generated. Do not edit. See above. */ #define k_ticks_to_us_floor64(t) \ z_tmcvt_64(t, Z_HZ_ticks, Z_HZ_us, true, false, false) @@ -1366,11 +1820,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 32 bit precision. * Rounds to the nearest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in ticks. uint64_t * * @return The converted time value in microseconds. uint32_t */ -/* Generated. Do not edit. See above. */ #define k_ticks_to_us_near32(t) \ z_tmcvt_32(t, Z_HZ_ticks, Z_HZ_us, true, false, true) @@ -1381,11 +1836,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 64 bit precision. * Rounds to the nearest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in ticks. uint64_t * * @return The converted time value in microseconds. uint64_t */ -/* Generated. Do not edit. See above. */ #define k_ticks_to_us_near64(t) \ z_tmcvt_64(t, Z_HZ_ticks, Z_HZ_us, true, false, true) @@ -1396,11 +1852,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 32 bit precision. * Rounds up to the next highest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in ticks. uint64_t * * @return The converted time value in microseconds. uint32_t */ -/* Generated. Do not edit. See above. */ #define k_ticks_to_us_ceil32(t) \ z_tmcvt_32(t, Z_HZ_ticks, Z_HZ_us, true, true, false) @@ -1411,11 +1868,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 64 bit precision. * Rounds up to the next highest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in ticks. uint64_t * * @return The converted time value in microseconds. uint64_t */ -/* Generated. Do not edit. See above. */ #define k_ticks_to_us_ceil64(t) \ z_tmcvt_64(t, Z_HZ_ticks, Z_HZ_us, true, true, false) @@ -1426,11 +1884,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 32 bit precision. * Truncates to the next lowest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in ticks. uint64_t * * @return The converted time value in nanoseconds. uint32_t */ -/* Generated. Do not edit. See above. */ #define k_ticks_to_ns_floor32(t) \ z_tmcvt_32(t, Z_HZ_ticks, Z_HZ_ns, true, false, false) @@ -1441,11 +1900,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 64 bit precision. * Truncates to the next lowest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in ticks. uint64_t * * @return The converted time value in nanoseconds. uint64_t */ -/* Generated. Do not edit. See above. */ #define k_ticks_to_ns_floor64(t) \ z_tmcvt_64(t, Z_HZ_ticks, Z_HZ_ns, true, false, false) @@ -1456,11 +1916,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 32 bit precision. * Rounds to the nearest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in ticks. uint64_t * * @return The converted time value in nanoseconds. uint32_t */ -/* Generated. Do not edit. See above. */ #define k_ticks_to_ns_near32(t) \ z_tmcvt_32(t, Z_HZ_ticks, Z_HZ_ns, true, false, true) @@ -1471,11 +1932,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 64 bit precision. * Rounds to the nearest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in ticks. uint64_t * * @return The converted time value in nanoseconds. uint64_t */ -/* Generated. Do not edit. See above. */ #define k_ticks_to_ns_near64(t) \ z_tmcvt_64(t, Z_HZ_ticks, Z_HZ_ns, true, false, true) @@ -1486,11 +1948,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 32 bit precision. * Rounds up to the next highest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in ticks. uint64_t * * @return The converted time value in nanoseconds. uint32_t */ -/* Generated. Do not edit. See above. */ #define k_ticks_to_ns_ceil32(t) \ z_tmcvt_32(t, Z_HZ_ticks, Z_HZ_ns, true, true, false) @@ -1501,11 +1964,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 64 bit precision. * Rounds up to the next highest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in ticks. uint64_t * * @return The converted time value in nanoseconds. uint64_t */ -/* Generated. Do not edit. See above. */ #define k_ticks_to_ns_ceil64(t) \ z_tmcvt_64(t, Z_HZ_ticks, Z_HZ_ns, true, true, false) @@ -1516,11 +1980,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 32 bit precision. * Truncates to the next lowest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in ticks. uint64_t * * @return The converted time value in hardware cycles. uint32_t */ -/* Generated. Do not edit. See above. */ #define k_ticks_to_cyc_floor32(t) \ z_tmcvt_32(t, Z_HZ_ticks, Z_HZ_cyc, Z_CCYC, false, false) @@ -1531,11 +1996,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 64 bit precision. * Truncates to the next lowest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in ticks. uint64_t * * @return The converted time value in hardware cycles. uint64_t */ -/* Generated. Do not edit. See above. */ #define k_ticks_to_cyc_floor64(t) \ z_tmcvt_64(t, Z_HZ_ticks, Z_HZ_cyc, Z_CCYC, false, false) @@ -1546,11 +2012,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 32 bit precision. * Rounds to the nearest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in ticks. uint64_t * * @return The converted time value in hardware cycles. uint32_t */ -/* Generated. Do not edit. See above. */ #define k_ticks_to_cyc_near32(t) \ z_tmcvt_32(t, Z_HZ_ticks, Z_HZ_cyc, Z_CCYC, false, true) @@ -1561,11 +2028,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 64 bit precision. * Rounds to the nearest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in ticks. uint64_t * * @return The converted time value in hardware cycles. uint64_t */ -/* Generated. Do not edit. See above. */ #define k_ticks_to_cyc_near64(t) \ z_tmcvt_64(t, Z_HZ_ticks, Z_HZ_cyc, Z_CCYC, false, true) @@ -1576,11 +2044,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 32 bit precision. * Rounds up to the next highest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in ticks. uint64_t * * @return The converted time value in hardware cycles. uint32_t */ -/* Generated. Do not edit. See above. */ #define k_ticks_to_cyc_ceil32(t) \ z_tmcvt_32(t, Z_HZ_ticks, Z_HZ_cyc, Z_CCYC, true, false) @@ -1591,11 +2060,12 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) * Computes result in 64 bit precision. * Rounds up to the next highest output unit. * + * @warning Generated. Do not edit. See above. + * * @param t Source time in ticks. uint64_t * * @return The converted time value in hardware cycles. uint64_t */ -/* Generated. Do not edit. See above. */ #define k_ticks_to_cyc_ceil64(t) \ z_tmcvt_64(t, Z_HZ_ticks, Z_HZ_cyc, Z_CCYC, true, false) diff --git a/include/zephyr/sys/util_macro.h b/include/zephyr/sys/util_macro.h index 81df23f9150..5b3864d2e3c 100644 --- a/include/zephyr/sys/util_macro.h +++ b/include/zephyr/sys/util_macro.h @@ -623,6 +623,8 @@ extern "C" { /** * @brief Number of arguments in the variable arguments list minus one. * + * @note Supports up to 64 arguments. + * * @param ... List of arguments * @return Number of variadic arguments in the argument list, minus one */ @@ -635,6 +637,17 @@ extern "C" { 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, \ 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, ~) +/** + * @brief Number of arguments in the variable arguments list. + * + * @note Supports up to 63 arguments. + * + * @param ... List of arguments + * @return Number of variadic arguments in the argument list + */ +#define NUM_VA_ARGS(...) \ + COND_CODE_1(IS_EMPTY(__VA_ARGS__), (0), (UTIL_INC(NUM_VA_ARGS_LESS_1(__VA_ARGS__)))) + /** * @brief Mapping macro that pastes results together * diff --git a/include/zephyr/toolchain/gcc.h b/include/zephyr/toolchain/gcc.h index 767dc10f742..99da187f9e4 100644 --- a/include/zephyr/toolchain/gcc.h +++ b/include/zephyr/toolchain/gcc.h @@ -82,7 +82,7 @@ * static_assert() is not available) */ #elif !defined(__cplusplus) && \ - ((__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) || \ + (((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6))) || \ (__STDC_VERSION__) >= 201100) #define BUILD_ASSERT(EXPR, MSG...) _Static_assert(EXPR, "" MSG) #else @@ -138,7 +138,7 @@ __extension__ ({ \ }) -#if __GNUC__ >= 7 && (defined(CONFIG_ARM) || defined(CONFIG_ARM64)) +#if (__GNUC__ >= 7) && (defined(CONFIG_ARM) || defined(CONFIG_ARM64)) /* Version of UNALIGNED_PUT() which issues a compiler_barrier() after * the store. It is required to workaround an apparent optimization @@ -489,52 +489,85 @@ do { \ * to generate named symbol/value pairs for kconfigs. */ -#if defined(CONFIG_ARM) || defined(CONFIG_X86) || defined(CONFIG_ARC) || defined(CONFIG_ARM64) || \ - defined(CONFIG_NIOS2) || defined(CONFIG_XTENSA) || defined(CONFIG_MIPS) || \ - defined(CONFIG_ARCH_POSIX) || defined(CONFIG_SPARC) - -#define GEN_ABSOLUTE_SYM(name, value) \ - do { \ - __asm__(".global " #name); \ - __asm__(".set " #name ", %c0" ::"n"(value)); \ - __asm__(".type " #name ", STT_OBJECT"); \ - } while (false) - -#define GEN_ABSOLUTE_SYM_KCONFIG(name, value) \ - do { \ - __asm__(".global " #name); \ - __asm__(".set " #name ", " #value); \ - __asm__(".type " #name ", STT_OBJECT"); \ - } while (false) - -/* The following is a workaround for the RISC-V target, which - * has a bug so it errors out on the target-agnostic '%c'. - * - * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=112434 - * - * > error: invalid 'asm': invalid use of '%c' - * - * According to commit cd83e85edc5d741f6b52c6b5995303c30bda443a, - * '%0' is equivalent to '%c0' for the RISC-V target. We use - * this as a workaround for now. - * - * This workaround should be removed when the above bug is fixed - * in all supported Zephyr toolchain versions. +#if defined(CONFIG_ARM) + +/* + * GNU/ARM backend does not have a proper operand modifier which does not + * produces prefix # followed by value, such as %0 for PowerPC, Intel, and + * MIPS. The workaround performed here is using %B0 which converts + * the value to ~(value). Thus "n"(~(value)) is set in operand constraint + * to output (value) in the ARM specific GEN_OFFSET macro. */ -#elif defined(CONFIG_RISCV) -#define GEN_ABSOLUTE_SYM(name, value) \ - do { \ - __asm__(".global " #name); \ - __asm__(".set " #name ", %0" ::"n"(value)); \ - __asm__(".type " #name ", STT_OBJECT"); \ - } while (false) - -#define GEN_ABSOLUTE_SYM_KCONFIG(name, value) \ - do { \ - __asm__(".global " #name); \ - __asm__(".set " #name ", " #value); \ - __asm__(".type " #name ", STT_OBJECT"); \ - } while (false) + +#define GEN_ABSOLUTE_SYM(name, value) \ + __asm__(".globl\t" #name "\n\t.equ\t" #name \ + ",%B0" \ + "\n\t.type\t" #name ",%%object" : : "n"(~(value))) + +#define GEN_ABSOLUTE_SYM_KCONFIG(name, value) \ + __asm__(".globl\t" #name \ + "\n\t.equ\t" #name "," #value \ + "\n\t.type\t" #name ",%object") + +#elif defined(CONFIG_X86) + +#define GEN_ABSOLUTE_SYM(name, value) \ + __asm__(".globl\t" #name "\n\t.equ\t" #name \ + ",%c0" \ + "\n\t.type\t" #name ",@object" : : "n"(value)) + +#define GEN_ABSOLUTE_SYM_KCONFIG(name, value) \ + __asm__(".globl\t" #name \ + "\n\t.equ\t" #name "," #value \ + "\n\t.type\t" #name ",@object") + +#elif defined(CONFIG_ARC) || defined(CONFIG_ARM64) + +#define GEN_ABSOLUTE_SYM(name, value) \ + __asm__(".globl\t" #name "\n\t.equ\t" #name \ + ",%c0" \ + "\n\t.type\t" #name ",@object" : : "n"(value)) + +#define GEN_ABSOLUTE_SYM_KCONFIG(name, value) \ + __asm__(".globl\t" #name \ + "\n\t.equ\t" #name "," #value \ + "\n\t.type\t" #name ",@object") + +#elif defined(CONFIG_NIOS2) || defined(CONFIG_RISCV) || \ + defined(CONFIG_XTENSA) || defined(CONFIG_MIPS) + +/* No special prefixes necessary for constants in this arch AFAICT */ +#define GEN_ABSOLUTE_SYM(name, value) \ + __asm__(".globl\t" #name "\n\t.equ\t" #name \ + ",%0" \ + "\n\t.type\t" #name ",%%object" : : "n"(value)) + +#define GEN_ABSOLUTE_SYM_KCONFIG(name, value) \ + __asm__(".globl\t" #name \ + "\n\t.equ\t" #name "," #value \ + "\n\t.type\t" #name ",%object") + +#elif defined(CONFIG_ARCH_POSIX) +#define GEN_ABSOLUTE_SYM(name, value) \ + __asm__(".globl\t" #name "\n\t.equ\t" #name \ + ",%c0" \ + "\n\t.type\t" #name ",@object" : : "n"(value)) + +#define GEN_ABSOLUTE_SYM_KCONFIG(name, value) \ + __asm__(".globl\t" #name \ + "\n\t.equ\t" #name "," #value \ + "\n\t.type\t" #name ",@object") + +#elif defined(CONFIG_SPARC) +#define GEN_ABSOLUTE_SYM(name, value) \ + __asm__(".global\t" #name "\n\t.equ\t" #name \ + ",%0" \ + "\n\t.type\t" #name ",#object" : : "n"(value)) + +#define GEN_ABSOLUTE_SYM_KCONFIG(name, value) \ + __asm__(".globl\t" #name \ + "\n\t.equ\t" #name "," #value \ + "\n\t.type\t" #name ",#object") #else #error processor architecture not supported @@ -557,7 +590,7 @@ do { \ /* random suffix to avoid naming conflict */ \ __typeof__(a) _value_a_ = (a); \ __typeof__(b) _value_b_ = (b); \ - _value_a_ > _value_b_ ? _value_a_ : _value_b_; \ + (_value_a_ > _value_b_) ? _value_a_ : _value_b_; \ }) /** @brief Return smaller value of two provided expressions. @@ -569,7 +602,7 @@ do { \ /* random suffix to avoid naming conflict */ \ __typeof__(a) _value_a_ = (a); \ __typeof__(b) _value_b_ = (b); \ - _value_a_ < _value_b_ ? _value_a_ : _value_b_; \ + (_value_a_ < _value_b_) ? _value_a_ : _value_b_; \ }) /** @brief Return a value clamped to a given range. @@ -610,6 +643,12 @@ do { \ #define __noasan /**/ #endif +#if defined(CONFIG_UBSAN) +#define __noubsan __attribute__((no_sanitize("undefined"))) +#else +#define __noubsan +#endif + /** * @brief Function attribute to disable stack protector. * diff --git a/include/zephyr/toolchain/llvm.h b/include/zephyr/toolchain/llvm.h index 8a78d4e8404..d2bc4aeac34 100644 --- a/include/zephyr/toolchain/llvm.h +++ b/include/zephyr/toolchain/llvm.h @@ -30,84 +30,102 @@ #include -#ifndef __INT8_C -#define __INT8_C(x) x -#endif - -#ifndef INT8_C -#define INT8_C(x) __INT8_C(x) -#endif - -#ifndef __UINT8_C -#define __UINT8_C(x) x ## U -#endif - -#ifndef UINT8_C -#define UINT8_C(x) __UINT8_C(x) -#endif - -#ifndef __INT16_C -#define __INT16_C(x) x -#endif - -#ifndef INT16_C -#define INT16_C(x) __INT16_C(x) -#endif - -#ifndef __UINT16_C -#define __UINT16_C(x) x ## U -#endif - -#ifndef UINT16_C -#define UINT16_C(x) __UINT16_C(x) -#endif - -#ifndef __INT32_C +/* + * Provide these definitions only when minimal libc is used. + * Avoid collision with defines from include/zephyr/toolchain/zephyr_stdint.h + */ +#ifdef CONFIG_MINIMAL_LIBC +#ifndef CONFIG_ENFORCE_ZEPHYR_STDINT + +#define __int_c(v, suffix) v ## suffix +#define int_c(v, suffix) __int_c(v, suffix) +#define uint_c(v, suffix) __int_c(v ## U, suffix) + +#ifdef __INT64_TYPE__ +#undef __int_least64_c_suffix__ +#undef __int_least32_c_suffix__ +#undef __int_least16_c_suffix__ +#undef __int_least8_c_suffix__ +#ifdef __INT64_C_SUFFIX__ +#define __int_least64_c_suffix__ __INT64_C_SUFFIX__ +#define __int_least32_c_suffix__ __INT64_C_SUFFIX__ +#define __int_least16_c_suffix__ __INT64_C_SUFFIX__ +#define __int_least8_c_suffix__ __INT64_C_SUFFIX__ +#endif /* __INT64_C_SUFFIX__ */ +#endif /* __INT64_TYPE__ */ + +#ifdef __INT_LEAST64_TYPE__ +#ifdef __int_least64_c_suffix__ +#define __INT64_C(x) int_c(x, __int_least64_c_suffix__) +#define __UINT64_C(x) uint_c(x, __int_least64_c_suffix__) +#else +#define __INT64_C(x) x +#define __UINT64_C(x) x ## U +#endif /* __int_least64_c_suffix__ */ +#endif /* __INT_LEAST64_TYPE__ */ + +#ifdef __INT32_TYPE__ +#undef __int_least32_c_suffix__ +#undef __int_least16_c_suffix__ +#undef __int_least8_c_suffix__ +#ifdef __INT32_C_SUFFIX__ +#define __int_least32_c_suffix__ __INT32_C_SUFFIX__ +#define __int_least16_c_suffix__ __INT32_C_SUFFIX__ +#define __int_least8_c_suffix__ __INT32_C_SUFFIX__ +#endif /* __INT32_C_SUFFIX__ */ +#endif /* __INT32_TYPE__ */ + +#ifdef __INT_LEAST32_TYPE__ +#ifdef __int_least32_c_suffix__ +#define __INT32_C(x) int_c(x, __int_least32_c_suffix__) +#define __UINT32_C(x) uint_c(x, __int_least32_c_suffix__) +#else #define __INT32_C(x) x -#endif - -#ifndef INT32_C -#define INT32_C(x) __INT32_C(x) -#endif - -#ifndef __UINT32_C #define __UINT32_C(x) x ## U -#endif - -#ifndef UINT32_C -#define UINT32_C(x) __UINT32_C(x) -#endif - -#ifndef __INT64_C -#define __INT64_C(x) x -#endif - -#ifndef INT64_C -#define INT64_C(x) __INT64_C(x) -#endif - -#ifndef __UINT64_C -#define __UINT64_C(x) x ## ULL -#endif - -#ifndef UINT64_C -#define UINT64_C(x) __UINT64_C(x) -#endif - -#ifndef __INTMAX_C -#define __INTMAX_C(x) x -#endif +#endif /* __int_least32_c_suffix__ */ +#endif /* __INT_LEAST32_TYPE__ */ + +#ifdef __INT16_TYPE__ +#undef __int_least16_c_suffix__ +#undef __int_least8_c_suffix__ +#ifdef __INT16_C_SUFFIX__ +#define __int_least16_c_suffix__ __INT16_C_SUFFIX__ +#define __int_least8_c_suffix__ __INT16_C_SUFFIX__ +#endif /* __INT16_C_SUFFIX__ */ +#endif /* __INT16_TYPE__ */ + +#ifdef __INT_LEAST16_TYPE__ +#ifdef __int_least16_c_suffix__ +#define __INT16_C(x) int_c(x, __int_least16_c_suffix__) +#define __UINT16_C(x) uint_c(x, __int_least16_c_suffix__) +#else +#define __INT16_C(x) x +#define __UINT16_C(x) x ## U +#endif /* __int_least16_c_suffix__ */ +#endif /* __INT_LEAST16_TYPE__ */ + +#ifdef __INT8_TYPE__ +#undef __int_least8_c_suffix__ +#ifdef __INT8_C_SUFFIX__ +#define __int_least8_c_suffix__ __INT8_C_SUFFIX__ +#endif /* __INT8_C_SUFFIX__ */ +#endif /* __INT8_TYPE__ */ + +#ifdef __INT_LEAST8_TYPE__ +#ifdef __int_least8_c_suffix__ +#define __INT8_C(x) int_c(x, __int_least8_c_suffix__) +#define __UINT8_C(x) uint_c(x, __int_least8_c_suffix__) +#else +#define __INT8_C(x) x +#define __UINT8_C(x) x ## U +#endif /* __int_least8_c_suffix__ */ +#endif /* __INT_LEAST8_TYPE__ */ -#ifndef INTMAX_C -#define INTMAX_C(x) __INTMAX_C(x) -#endif +#endif /* !CONFIG_ENFORCE_ZEPHYR_STDINT */ -#ifndef __UINTMAX_C -#define __UINTMAX_C(x) x ## ULL -#endif +#define __INTMAX_C(x) int_c(x, __INTMAX_C_SUFFIX__) +#define __UINTMAX_C(x) int_c(x, __UINTMAX_C_SUFFIX__) -#ifndef UINTMAX_C -#define UINTMAX_C(x) __UINTMAX_C(x) -#endif +#endif /* CONFIG_MINIMAL_LIBC */ #endif /* ZEPHYR_INCLUDE_TOOLCHAIN_LLVM_H_ */ diff --git a/include/zephyr/usb/bos.h b/include/zephyr/usb/bos.h index b7a0ef08339..f73e7c06678 100644 --- a/include/zephyr/usb/bos.h +++ b/include/zephyr/usb/bos.h @@ -17,12 +17,13 @@ * @{ */ -/** - * @brief Helper macro to place the BOS compatibility descriptor - * in the right memory section. - */ -#define USB_DEVICE_BOS_DESC_DEFINE_CAP \ - static __in_section(usb, bos_desc_area, 1) __aligned(1) __used +/** Root BOS Descriptor */ +struct usb_bos_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t wTotalLength; + uint8_t bNumDeviceCaps; +} __packed; /** Device capability type codes */ enum usb_bos_capability_types { @@ -62,45 +63,6 @@ struct usb_bos_capability_msos { uint8_t bAltEnumCode; } __packed; -/** - * @brief Register BOS capability descriptor - * - * This function should be used by the application to register BOS capability - * descriptors before the USB device stack is enabled. - * - * @param[in] hdr Pointer to BOS capability descriptor - */ -void usb_bos_register_cap(struct usb_bos_platform_descriptor *hdr); - -/** - * @cond INTERNAL_HIDDEN - * Internally used functions - */ - -/* BOS Descriptor (root descriptor) */ -struct usb_bos_descriptor { - uint8_t bLength; - uint8_t bDescriptorType; - uint16_t wTotalLength; - uint8_t bNumDeviceCaps; -} __packed; - -#define USB_DEVICE_BOS_DESC_DEFINE_HDR \ - static __in_section(usb, bos_desc_area, 0) __aligned(1) __used - -size_t usb_bos_get_length(void); - -void usb_bos_fix_total_length(void); - -const void *usb_bos_get_header(void); - -#if defined(CONFIG_USB_DEVICE_BOS) -int usb_handle_bos(struct usb_setup_packet *setup, int32_t *len, uint8_t **data); -#else -#define usb_handle_bos(x, y, z) -ENOTSUP -#endif -/** @endcond */ - /** * @} */ diff --git a/include/zephyr/usb/class/usb_hid.h b/include/zephyr/usb/class/usb_hid.h index 8fc380b970e..f15d0526e4a 100644 --- a/include/zephyr/usb/class/usb_hid.h +++ b/include/zephyr/usb/class/usb_hid.h @@ -54,9 +54,7 @@ struct hid_ops { * the next transfer. */ hid_int_ready_callback int_in_ready; -#ifdef CONFIG_ENABLE_HID_INT_OUT_EP hid_int_ready_callback int_out_ready; -#endif }; /** diff --git a/include/zephyr/usb/class/usbd_hid.h b/include/zephyr/usb/class/usbd_hid.h new file mode 100644 index 00000000000..5dd6d0dad23 --- /dev/null +++ b/include/zephyr/usb/class/usbd_hid.h @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief USBD HID device API header + */ + +#ifndef ZEPHYR_INCLUDE_USBD_HID_CLASS_DEVICE_H_ +#define ZEPHYR_INCLUDE_USBD_HID_CLASS_DEVICE_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief USBD HID Device API + * @defgroup usbd_hid_device USBD HID device API + * @ingroup usb + * @{ + */ + +/* + * HID Device overview: + * + * +---------------------+ + * | | + * | | + * | HID Device | + * | User "top half" | + * | of the device that +-------+ + * | deals with input | | + * | sampling | | + * | | | + * | | | + * | ------------------- | | + * | | | + * | HID Device user | | + * | callbacks | | + * | handlers | | + * +---------------------+ | + * ^ | HID Device Driver API: + * | | + * set_protocol() | | hid_device_register() + * get_report() | | hid_device_submit_report( + * .... | | ... + * v | + * +---------------------+ | + * | | | + * | HID Device | | + * | "bottom half" |<------+ + * | USB HID class | + * | implementation | + * | | + * | | + * +---------------------+ + * ^ + * v + * +--------------------+ + * | | + * | USB Device | + * | Support | + * | | + * +--------------------+ + */ + +/** HID report types + * Report types used in Get/Set Report requests. + */ +enum { + HID_REPORT_TYPE_INPUT = 1, + HID_REPORT_TYPE_OUTPUT, + HID_REPORT_TYPE_FEATURE, +}; + +/** + * @brief HID device user callbacks + * + * Each device depends on a user part that handles feature, input, and output + * report processing according to the device functionality described by the + * report descriptor. Which callbacks must be implemented depends on the device + * functionality. The USB device part of the HID device, cannot interpret + * device specific report descriptor and only handles USB specific parts, + * transfers and validation of requests, all reports are opaque to it. + * Callbacks are called from the USB device stack thread and must not block. + */ +struct hid_device_ops { + /** + * The interface ready callback is called with the ready argument set + * to true when the corresponding interface is part of the active + * configuration and the device can e.g. begin submitting input + * reports, and with the argument set to false when the interface is no + * longer active. This callback is optional. + */ + void (*iface_ready)(const struct device *dev, const bool ready); + + /** + * This callback is called for the HID Get Report request to get a + * feature, input, or output report, which is specified by the argument + * type. If there is no report ID in the report descriptor, the id + * argument is zero. The callback implementation must check the + * arguments, such as whether the report type is supported, and return + * a nonzero value to indicate an unsupported type or an error. + */ + int (*get_report)(const struct device *dev, + const uint8_t type, const uint8_t id, + const uint16_t len, uint8_t *const buf); + + /** + * This callback is called for the HID Set Report request to set a + * feature, input, or output report, which is specified by the argument + * type. If there is no report ID in the report descriptor, the id + * argument is zero. The callback implementation must check the + * arguments, such as whether the report type is supported, and return + * a nonzero value to indicate an unsupported type or an error. + */ + int (*set_report)(const struct device *dev, + const uint8_t type, const uint8_t id, + const uint16_t len, const uint8_t *const buf); + + /** + * Notification to limit intput report frequency. + * The device should mute an input report submission until a new + * event occurs or until the time specified by the duration value has + * elapsed. If a report ID is used in the report descriptor, the + * device must store the duration and handle the specified report + * accordingly. Duration time resolution is in miliseconds. + */ + void (*set_idle)(const struct device *dev, + const uint8_t id, const uint32_t duration); + + /** + * If a report ID is used in the report descriptor, the device + * must implement this callback and return the duration for the + * specified report ID. Duration time resolution is in miliseconds. + */ + uint32_t (*get_idle)(const struct device *dev, const uint8_t id); + + /** + * Notification that the host has changed the protocol from + * Boot Protocol(0) to Report Protocol(1) or vice versa. + */ + void (*set_protocol)(const struct device *dev, const uint8_t proto); + + /** + * Notification that input report submitted with + * hid_device_submit_report() has been sent. + * If the device does not use the callback, hid_device_submit_report() + * will be processed synchronously. + */ + void (*input_report_done)(const struct device *dev); + + /** + * New output report callback. Callback will only be called for reports + * received through the optional interrupt OUT pipe. If there is no + * interrupt OUT pipe, output reports will be received using set_report(). + * If a report ID is used in the report descriptor, the host places the ID + * in the buffer first, followed by the report data. + */ + void (*output_report)(const struct device *dev, const uint16_t len, + const uint8_t *const buf); + /** + * Optional Start of Frame (SoF) event callback. + * There will always be software and hardware dependent jitter and + * latency. This should be used very carefully, it should not block + * and the execution time should be quite short. + */ + void (*sof)(const struct device *dev); +}; + +/** + * @brief Register HID device report descriptor and user callbacks + * + * The device must register report descriptor and user callbacks before + * USB device support is initialized and enabled. + * + * @param[in] dev Pointer to HID device + * @param[in] rdesc Pointer to HID report descriptor + * @param[in] rsize Size of HID report descriptor + * @param[in] ops Pointer to HID device callbacks + */ +int hid_device_register(const struct device *dev, + const uint8_t *const rdesc, const uint16_t rsize, + const struct hid_device_ops *const ops); + +/** + * @brief Submit new input report + * + * Submit a new input report to be sent via the interrupt IN pipe. If sync is + * true, the functions will block until the report is sent. + * If the device does not provide input_report_done() callback, + * hid_device_submit_report() will be processed synchronously. + * + * @param[in] dev Pointer to HID device + * @param[in] size Size of the input report + * @param[in] report Input report buffer. Report buffer must be aligned. + * + * @return 0 on success, negative errno code on fail. + */ +int hid_device_submit_report(const struct device *dev, + const uint16_t size, const uint8_t *const report); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_USBD_HID_CLASS_DEVICE_H_ */ diff --git a/include/zephyr/usb/usb_ch9.h b/include/zephyr/usb/usb_ch9.h index fa18b1c2dc8..8fe33f46b71 100644 --- a/include/zephyr/usb/usb_ch9.h +++ b/include/zephyr/usb/usb_ch9.h @@ -14,6 +14,7 @@ #include #include +#include #include #ifndef ZEPHYR_INCLUDE_USB_CH9_H_ @@ -163,6 +164,19 @@ struct usb_device_descriptor { uint8_t bNumConfigurations; } __packed; +/** USB Device Qualifier Descriptor defined in spec. Table 9-9 */ +struct usb_device_qualifier_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t bcdUSB; + uint8_t bDeviceClass; + uint8_t bDeviceSubClass; + uint8_t bDeviceProtocol; + uint8_t bMaxPacketSize0; + uint8_t bNumConfigurations; + uint8_t bReserved; +} __packed; + /** USB Standard Configuration Descriptor defined in spec. Table 9-10 */ struct usb_cfg_descriptor { uint8_t bLength; @@ -254,6 +268,7 @@ struct usb_association_descriptor { /** USB Specification Release Numbers (bcdUSB Descriptor field) */ #define USB_SRN_1_1 0x0110 #define USB_SRN_2_0 0x0200 +#define USB_SRN_2_0_1 0x0201 #define USB_SRN_2_1 0x0210 #define USB_DEC_TO_BCD(dec) ((((dec) / 10) << 4) | ((dec) % 10)) @@ -321,6 +336,18 @@ struct usb_association_descriptor { /** USB endpoint transfer type interrupt */ #define USB_EP_TYPE_INTERRUPT 3U +/** Calculate full speed interrupt endpoint bInterval from a value in microseconds */ +#define USB_FS_INT_EP_INTERVAL(us) CLAMP(((us) / 1000U), 1U, 255U) + +/** Calculate high speed interrupt endpoint bInterval from a value in microseconds */ +#define USB_HS_INT_EP_INTERVAL(us) CLAMP((ilog2((us) / 125U) + 1U), 1U, 16U) + +/** Calculate high speed isochronous endpoint bInterval from a value in microseconds */ +#define USB_FS_ISO_EP_INTERVAL(us) CLAMP(((us) / 1000U), 1U, 16U) + +/** Calculate high speed isochronous endpoint bInterval from a value in microseconds */ +#define USB_HS_ISO_EP_INTERVAL(us) CLAMP((ilog2((us) / 125U) + 1U), 1U, 16U) + #ifdef __cplusplus } #endif diff --git a/include/zephyr/usb/usb_device.h b/include/zephyr/usb/usb_device.h index 0de535365ee..59c3db1cb59 100644 --- a/include/zephyr/usb/usb_device.h +++ b/include/zephyr/usb/usb_device.h @@ -446,6 +446,23 @@ int usb_wakeup_request(void); */ bool usb_get_remote_wakeup_status(void); +/** + * @brief Helper macro to place the BOS compatibility descriptor + * in the right memory section. + */ +#define USB_DEVICE_BOS_DESC_DEFINE_CAP \ + static __in_section(usb, bos_desc_area, 1) __aligned(1) __used + +/** + * @brief Register BOS capability descriptor + * + * This function should be used by the application to register BOS capability + * descriptors before the USB device stack is enabled. + * + * @param[in] hdr Pointer to BOS capability descriptor + */ +void usb_bos_register_cap(void *hdr); + /** * @} */ diff --git a/include/zephyr/usb/usbd.h b/include/zephyr/usb/usbd.h index d6c6eb032f9..6d697c88869 100644 --- a/include/zephyr/usb/usbd.h +++ b/include/zephyr/usb/usbd.h @@ -15,6 +15,7 @@ #define ZEPHYR_INCLUDE_USBD_H_ #include +#include #include #include #include @@ -58,8 +59,10 @@ extern "C" { */ #define USB_STRING_DESCRIPTOR_LENGTH(s) (sizeof(s) * 2) -/* Used internally to keep descriptors in order */ -enum usbd_desc_usage_type { +/** Used internally to keep descriptors in order + * @cond INTERNAL_HIDDEN + */ +enum usbd_str_desc_utype { USBD_DUT_STRING_LANG, USBD_DUT_STRING_MANUFACTURER, USBD_DUT_STRING_PRODUCT, @@ -67,25 +70,52 @@ enum usbd_desc_usage_type { USBD_DUT_STRING_INTERFACE, }; +enum usbd_bos_desc_utype { + USBD_DUT_BOS_NONE, +}; +/** @endcond */ + +/** + * USBD string descriptor data + */ +struct usbd_str_desc_data { + /** Descriptor index, required for string descriptors */ + uint8_t idx; + /** Descriptor usage type (not bDescriptorType) */ + enum usbd_str_desc_utype utype : 8; + /** The string descriptor is in ASCII7 format */ + unsigned int ascii7 : 1; + /** Device stack obtains SerialNumber using the HWINFO API */ + unsigned int use_hwinfo : 1; +}; + +/** + * USBD BOS Device Capability descriptor data + */ +struct usbd_bos_desc_data { + /** Descriptor usage type (not bDescriptorType) */ + enum usbd_bos_desc_utype utype : 8; +}; + /** * Descriptor node * * Descriptor node is used to manage descriptors that are not - * directly part of a structure, such as string or bos descriptors. + * directly part of a structure, such as string or BOS capability descriptors. */ struct usbd_desc_node { /** slist node struct */ sys_dnode_t node; - /** Descriptor index, required for string descriptors */ - unsigned int idx : 8; - /** Descriptor usage type (not bDescriptorType) */ - unsigned int utype : 8; - /** If not set, string descriptor must be converted to UTF16LE */ - unsigned int utf16le : 1; - /** If not set, device stack obtains SN using the hwinfo API */ - unsigned int custom_sn : 1; - /** Pointer to a descriptor */ - void *desc; + union { + struct usbd_str_desc_data str; + struct usbd_bos_desc_data bos; + }; + /** Opaque pointer to a descriptor payload */ + const void *const ptr; + /** Descriptor size in bytes */ + uint8_t bLength; + /** Descriptor type */ + uint8_t bDescriptorType; }; /** @@ -141,6 +171,18 @@ struct usbd_ch9_data { uint8_t alternate[USBD_NUMOF_INTERFACES_MAX]; }; +/** + * @brief USB device speed + */ +enum usbd_speed { + /** Device supports or is connected to a full speed bus */ + USBD_SPEED_FS, + /** Device supports or is connected to a high speed bus */ + USBD_SPEED_HS, + /** Device supports or is connected to a super speed bus */ + USBD_SPEED_SS, +}; + /** * USB device support status */ @@ -153,8 +195,26 @@ struct usbd_status { unsigned int suspended : 1; /** USB remote wake-up feature is enabled */ unsigned int rwup : 1; + /** USB device speed */ + enum usbd_speed speed : 2; }; +struct usbd_contex; + +/** + * @brief Callback type definition for USB device message delivery + * + * The implementation uses the system workqueue, and a callback provided and + * registered by the application. The application callback is called in the + * context of the system workqueue. Notification messages are stored in a queue + * and delivered to the callback in sequence. + * + * @param[in] ctx Pointer to USB device support context + * @param[in] msg Pointer to USB device message + */ +typedef void (*usbd_msg_cb_t)(struct usbd_contex *const ctx, + const struct usbd_msg *const msg); + /** * USB device support runtime context * @@ -172,14 +232,18 @@ struct usbd_contex { usbd_msg_cb_t msg_cb; /** Middle layer runtime data */ struct usbd_ch9_data ch9_data; - /** slist to manage descriptors like string, bos */ + /** slist to manage descriptors like string, BOS */ sys_dlist_t descriptors; - /** slist to manage device configurations */ - sys_slist_t configs; + /** slist to manage Full-Speed device configurations */ + sys_slist_t fs_configs; + /** slist to manage High-Speed device configurations */ + sys_slist_t hs_configs; /** Status of the USB device support */ struct usbd_status status; - /** Pointer to device descriptor */ - void *desc; + /** Pointer to Full-Speed device descriptor */ + void *fs_desc; + /** Pointer to High-Speed device descriptor */ + void *hs_desc; }; /** @@ -195,68 +259,89 @@ struct usbd_cctx_vendor_req { /** USB Class instance registered flag */ #define USBD_CCTX_REGISTERED 0 -struct usbd_class_node; +struct usbd_class_data; /** * @brief USB device support class instance API */ struct usbd_class_api { /** Feature halt state update handler */ - void (*feature_halt)(struct usbd_class_node *const node, + void (*feature_halt)(struct usbd_class_data *const c_data, uint8_t ep, bool halted); /** Configuration update handler */ - void (*update)(struct usbd_class_node *const node, + void (*update)(struct usbd_class_data *const c_data, uint8_t iface, uint8_t alternate); /** USB control request handler to device */ - int (*control_to_dev)(struct usbd_class_node *const node, + int (*control_to_dev)(struct usbd_class_data *const c_data, const struct usb_setup_packet *const setup, const struct net_buf *const buf); /** USB control request handler to host */ - int (*control_to_host)(struct usbd_class_node *const node, + int (*control_to_host)(struct usbd_class_data *const c_data, const struct usb_setup_packet *const setup, struct net_buf *const buf); /** Endpoint request completion event handler */ - int (*request)(struct usbd_class_node *const node, + int (*request)(struct usbd_class_data *const c_data, struct net_buf *buf, int err); /** USB power management handler suspended */ - void (*suspended)(struct usbd_class_node *const node); + void (*suspended)(struct usbd_class_data *const c_data); /** USB power management handler resumed */ - void (*resumed)(struct usbd_class_node *const node); + void (*resumed)(struct usbd_class_data *const c_data); /** Start of Frame */ - void (*sof)(struct usbd_class_node *const node); + void (*sof)(struct usbd_class_data *const c_data); /** Class associated configuration is selected */ - void (*enable)(struct usbd_class_node *const node); + void (*enable)(struct usbd_class_data *const c_data); /** Class associated configuration is disabled */ - void (*disable)(struct usbd_class_node *const node); + void (*disable)(struct usbd_class_data *const c_data); /** Initialization of the class implementation */ - int (*init)(struct usbd_class_node *const node); + int (*init)(struct usbd_class_data *const c_data); /** Shutdown of the class implementation */ - void (*shutdown)(struct usbd_class_node *const node); + void (*shutdown)(struct usbd_class_data *const c_data); + + /** Get function descriptor based on speed parameter */ + void *(*get_desc)(struct usbd_class_data *const c_data, + const enum usbd_speed speed); }; /** * @brief USB device support class data */ struct usbd_class_data { + /** Name of the USB device class instance */ + const char *name; /** Pointer to USB device stack context structure */ struct usbd_contex *uds_ctx; - /** Pointer to a class implementation descriptor that should end with - * a nil descriptor (bLength = 0 and bDescriptorType = 0). - */ - void *desc; + /** Pointer to device support class API */ + const struct usbd_class_api *api; /** Supported vendor request table, can be NULL */ const struct usbd_cctx_vendor_req *v_reqs; + /** Pointer to private data */ + void *priv; +}; + +/** + * @cond INTERNAL_HIDDEN + * + * Variables necessary for per speed class management. For each speed (Full, + * High) there is separate `struct usbd_class_node` pointing to the same + * `struct usbd_class_data` (because the class can only operate at one speed + * at a time). + */ +struct usbd_class_node { + /** Node information for the slist. */ + sys_snode_t node; + /** Pointer to public class node instance. */ + struct usbd_class_data *const c_data; /** Bitmap of all endpoints assigned to the instance. * The IN endpoints are mapped in the upper halfword. */ @@ -269,24 +354,43 @@ struct usbd_class_data { uint32_t iface_bm; /** Variable to store the state of the class instance */ atomic_t state; - /** Pointer to private data */ - void *priv; }; -struct usbd_class_node { - /** Node information for the slist. */ - sys_snode_t node; - /** Name of the USB device class instance */ - const char *name; - /** Pointer to device support class API */ - const struct usbd_class_api *api; - /** Pointer to USB device support class data */ - struct usbd_class_data *data; -}; +/** @endcond */ + +/** + * @brief Get the USB device runtime context under which the class is registered + * + * The class implementation must use this function and not access the members + * of the struct directly. + * + * @param[in] c_data Pointer to USB device class data + * + * @return Pointer to USB device runtime context + */ +static inline struct usbd_contex *usbd_class_get_ctx(const struct usbd_class_data *const c_data) +{ + return c_data->uds_ctx; +} + +/** + * @brief Get class implementation private data + * + * The class implementation must use this function and not access the members + * of the struct directly. + * + * @param[in] c_data Pointer to USB device class data + * + * @return Pointer to class implementation private data + */ +static inline void *usbd_class_get_private(const struct usbd_class_data *const c_data) +{ + return c_data->priv; +} #define USBD_DEVICE_DEFINE(device_name, uhc_dev, vid, pid) \ static struct usb_device_descriptor \ - desc_##device_name = { \ + fs_desc_##device_name = { \ .bLength = sizeof(struct usb_device_descriptor), \ .bDescriptorType = USB_DESC_DEVICE, \ .bcdUSB = sys_cpu_to_le16(USB_SRN_2_0), \ @@ -302,10 +406,28 @@ struct usbd_class_node { .iSerialNumber = 0, \ .bNumConfigurations = 0, \ }; \ + static struct usb_device_descriptor \ + hs_desc_##device_name = { \ + .bLength = sizeof(struct usb_device_descriptor), \ + .bDescriptorType = USB_DESC_DEVICE, \ + .bcdUSB = sys_cpu_to_le16(USB_SRN_2_0), \ + .bDeviceClass = USB_BCC_MISCELLANEOUS, \ + .bDeviceSubClass = 2, \ + .bDeviceProtocol = 1, \ + .bMaxPacketSize0 = 64, \ + .idVendor = vid, \ + .idProduct = pid, \ + .bcdDevice = sys_cpu_to_le16(USB_BCD_DRN), \ + .iManufacturer = 0, \ + .iProduct = 0, \ + .iSerialNumber = 0, \ + .bNumConfigurations = 0, \ + }; \ static STRUCT_SECTION_ITERABLE(usbd_contex, device_name) = { \ .name = STRINGIFY(device_name), \ .dev = uhc_dev, \ - .desc = &desc_##device_name, \ + .fs_desc = &fs_desc_##device_name, \ + .hs_desc = &hs_desc_##device_name, \ } #define USBD_CONFIGURATION_DEFINE(name, attrib, power) \ @@ -339,33 +461,38 @@ struct usbd_class_node { * @param name Language string descriptor node identifier. */ #define USBD_DESC_LANG_DEFINE(name) \ - static struct usb_string_descriptor \ - string_desc_##name = { \ + static uint16_t langid_##name = sys_cpu_to_le16(0x0409); \ + static struct usbd_desc_node name = { \ .bLength = sizeof(struct usb_string_descriptor), \ .bDescriptorType = USB_DESC_STRING, \ - .bString = sys_cpu_to_le16(0x0409), \ - }; \ - static struct usbd_desc_node name = { \ - .idx = 0, \ - .utype = USBD_DUT_STRING_LANG, \ - .desc = &string_desc_##name, \ + .str = { \ + .idx = 0, \ + .utype = USBD_DUT_STRING_LANG, \ + }, \ + .ptr = &langid_##name, \ } -#define USBD_DESC_STRING_DEFINE(d_name, d_string, d_utype) \ - struct usb_string_descriptor_##d_name { \ - uint8_t bLength; \ - uint8_t bDescriptorType; \ - uint8_t bString[USB_BSTRING_LENGTH(d_string)]; \ - } __packed; \ - static struct usb_string_descriptor_##d_name \ - string_desc_##d_name = { \ - .bLength = USB_STRING_DESCRIPTOR_LENGTH(d_string), \ - .bDescriptorType = USB_DESC_STRING, \ - .bString = d_string, \ - }; \ - static struct usbd_desc_node d_name = { \ - .utype = d_utype, \ - .desc = &string_desc_##d_name, \ +/** + * @brief Create a string descriptor + * + * This macro defines a descriptor node and a string descriptor. + * The string literal passed to the macro should be in the ASCII7 format. It + * is converted to UTF16LE format on the host request. + * + * @param d_name Internal string descriptor node identifier name + * @param d_string ASCII7 encoded string literal + * @param d_utype String descriptor usage type + */ +#define USBD_DESC_STRING_DEFINE(d_name, d_string, d_utype) \ + static uint8_t ascii_##d_name[USB_BSTRING_LENGTH(d_string)] = d_string; \ + static struct usbd_desc_node d_name = { \ + .str = { \ + .utype = d_utype, \ + .ascii7 = true, \ + }, \ + .bLength = USB_STRING_DESCRIPTOR_LENGTH(d_string), \ + .bDescriptorType = USB_DESC_STRING, \ + .ptr = &ascii_##d_name, \ } /** @@ -399,23 +526,57 @@ struct usbd_class_node { /** * @brief Create a string descriptor node and serial number string descriptor * - * This macro defines a descriptor node and a string descriptor that, - * when added to the device context, is automatically used as the serial number - * string descriptor. The string literal parameter is used as a placeholder, - * the unique number is obtained from hwinfo. Both descriptor node and descriptor - * are defined with static-storage-class specifier. + * This macro defines a descriptor node that, when added to the device context, + * is automatically used as the serial number string descriptor. A valid serial + * number is generated from HWID (HWINFO= whenever this string descriptor is + * requested. * * @param d_name String descriptor node identifier. - * @param d_string ASCII7 encoded serial number string literal placeholder */ -#define USBD_DESC_SERIAL_NUMBER_DEFINE(d_name, d_string) \ - USBD_DESC_STRING_DEFINE(d_name, d_string, USBD_DUT_STRING_SERIAL_NUMBER) +#define USBD_DESC_SERIAL_NUMBER_DEFINE(d_name) \ + static struct usbd_desc_node d_name = { \ + .str = { \ + .utype = USBD_DUT_STRING_SERIAL_NUMBER, \ + .ascii7 = true, \ + .use_hwinfo = true, \ + }, \ + .bDescriptorType = USB_DESC_STRING, \ + } -#define USBD_DEFINE_CLASS(class_name, class_api, class_data) \ - static STRUCT_SECTION_ITERABLE(usbd_class_node, class_name) = { \ - .name = STRINGIFY(class_name), \ - .api = class_api, \ - .data = class_data, \ +/** + * @brief Define BOS Device Capability descriptor node + * + * The application defines a BOS capability descriptor node for descriptors + * such as USB 2.0 Extension Descriptor. + * + * @param name Descriptor node identifier + * @param len Device Capability descriptor length + * @param subset Pointer to a Device Capability descriptor + */ +#define USBD_DESC_BOS_DEFINE(name, len, subset) \ + static struct usbd_desc_node name = { \ + .bos = { \ + .utype = USBD_DUT_BOS_NONE, \ + }, \ + .ptr = subset, \ + .bLength = len, \ + .bDescriptorType = USB_DESC_BOS, \ + } + +#define USBD_DEFINE_CLASS(class_name, class_api, class_priv, class_v_reqs) \ + static struct usbd_class_data class_name = { \ + .name = STRINGIFY(class_name), \ + .api = class_api, \ + .v_reqs = class_v_reqs, \ + .priv = class_priv, \ + }; \ + static STRUCT_SECTION_ITERABLE_ALTERNATE( \ + usbd_class_fs, usbd_class_node, class_name##_fs) = { \ + .c_data = &class_name, \ + }; \ + static STRUCT_SECTION_ITERABLE_ALTERNATE( \ + usbd_class_hs, usbd_class_node, class_name##_hs) = { \ + .c_data = &class_name, \ } /** @brief Helper to declare request table of usbd_cctx_vendor_req @@ -441,7 +602,7 @@ struct usbd_class_node { /** * @brief Add common USB descriptor * - * Add common descriptor like string or bos. + * Add common descriptor like string or BOS Device Capability. * * @param[in] uds_ctx Pointer to USB device support context * @param[in] dn Pointer to USB descriptor node @@ -451,15 +612,35 @@ struct usbd_class_node { int usbd_add_descriptor(struct usbd_contex *uds_ctx, struct usbd_desc_node *dn); +/** + * @brief Get USB string descriptor index from descriptor node + * + * @param[in] desc_nd Pointer to USB descriptor node + * + * @return Descriptor index, 0 if descriptor is not part of any device + */ +uint8_t usbd_str_desc_get_idx(const struct usbd_desc_node *const desc_nd); + +/** + * @brief Remove USB string descriptor + * + * Remove linked USB string descriptor from any list. + * + * @param[in] desc_nd Pointer to USB descriptor node + */ +void usbd_remove_descriptor(struct usbd_desc_node *const desc_nd); + /** * @brief Add a USB device configuration * * @param[in] uds_ctx Pointer to USB device support context + * @param[in] speed Speed at which this configuration operates * @param[in] cd Pointer to USB configuration node * * @return 0 on success, other values on fail. */ int usbd_add_configuration(struct usbd_contex *uds_ctx, + const enum usbd_speed speed, struct usbd_config_node *cd); /** @@ -478,13 +659,14 @@ int usbd_add_configuration(struct usbd_contex *uds_ctx, * * @param[in] uds_ctx Pointer to USB device support context * @param[in] name Class instance name + * @param[in] speed Configuration speed * @param[in] cfg Configuration value (similar to bConfigurationValue) * * @return 0 on success, other values on fail. */ int usbd_register_class(struct usbd_contex *uds_ctx, const char *name, - uint8_t cfg); + const enum usbd_speed speed, uint8_t cfg); /** * @brief Unregister an USB class instance @@ -495,13 +677,14 @@ int usbd_register_class(struct usbd_contex *uds_ctx, * * @param[in] uds_ctx Pointer to USB device support context * @param[in] name Class instance name + * @param[in] speed Configuration speed * @param[in] cfg Configuration value (similar to bConfigurationValue) * * @return 0 on success, other values on fail. */ int usbd_unregister_class(struct usbd_contex *uds_ctx, const char *name, - uint8_t cfg); + const enum usbd_speed speed, uint8_t cfg); /** * @brief Register USB notification message callback @@ -592,32 +775,18 @@ int usbd_ep_clear_halt(struct usbd_contex *uds_ctx, uint8_t ep); */ bool usbd_ep_is_halted(struct usbd_contex *uds_ctx, uint8_t ep); -/** - * @brief Allocate buffer for USB device control request - * - * Allocate a new buffer from controller's driver buffer pool. - * - * @param[in] uds_ctx Pointer to USB device support context - * @param[in] ep Endpoint address - * @param[in] size Size of the request buffer - * - * @return pointer to allocated request or NULL on error. - */ -struct net_buf *usbd_ep_ctrl_buf_alloc(struct usbd_contex *const uds_ctx, - const uint8_t ep, const size_t size); - /** * @brief Allocate buffer for USB device request * * Allocate a new buffer from controller's driver buffer pool. * - * @param[in] c_nd Pointer to USB device class node + * @param[in] c_data Pointer to USB device class data * @param[in] ep Endpoint address * @param[in] size Size of the request buffer * * @return pointer to allocated request or NULL on error. */ -struct net_buf *usbd_ep_buf_alloc(const struct usbd_class_node *const c_nd, +struct net_buf *usbd_ep_buf_alloc(const struct usbd_class_data *const c_data, const uint8_t ep, const size_t size); /** @@ -638,12 +807,12 @@ int usbd_ep_ctrl_enqueue(struct usbd_contex *const uds_ctx, * * Add request to the queue. * - * @param[in] c_nd Pointer to USB device class node + * @param[in] c_data Pointer to USB device class data * @param[in] buf Pointer to UDC request buffer * * @return 0 on success, or error from udc_ep_enqueue() */ -int usbd_ep_enqueue(const struct usbd_class_node *const c_nd, +int usbd_ep_enqueue(const struct usbd_class_data *const c_data, struct net_buf *const buf); /** @@ -684,16 +853,35 @@ bool usbd_is_suspended(struct usbd_contex *uds_ctx); */ int usbd_wakeup_request(struct usbd_contex *uds_ctx); +/** + * @brief Get actual device speed + * + * @param[in] uds_ctx Pointer to a device context + * + * @return Actual device speed + */ +enum usbd_speed usbd_bus_speed(const struct usbd_contex *const uds_ctx); + +/** + * @brief Get highest speed supported by the controller + * + * @param[in] uds_ctx Pointer to a device context + * + * @return Highest supported speed + */ +enum usbd_speed usbd_caps_speed(const struct usbd_contex *const uds_ctx); + /** * @brief Set USB device descriptor value bcdUSB * * @param[in] uds_ctx Pointer to USB device support context + * @param[in] speed Speed for which the bcdUSB should be set * @param[in] bcd bcdUSB value * * @return 0 on success, other values on fail. */ int usbd_device_set_bcd(struct usbd_contex *const uds_ctx, - const uint16_t bcd); + const enum usbd_speed speed, const uint16_t bcd); /** * @brief Set USB device descriptor value idVendor @@ -721,6 +909,7 @@ int usbd_device_set_pid(struct usbd_contex *const uds_ctx, * @brief Set USB device descriptor code triple Base Class, SubClass, and Protocol * * @param[in] uds_ctx Pointer to USB device support context + * @param[in] speed Speed for which the code triple should be set * @param[in] base_class bDeviceClass value * @param[in] subclass bDeviceSubClass value * @param[in] protocol bDeviceProtocol value @@ -728,6 +917,7 @@ int usbd_device_set_pid(struct usbd_contex *const uds_ctx, * @return 0 on success, other values on fail. */ int usbd_device_set_code_triple(struct usbd_contex *const uds_ctx, + const enum usbd_speed speed, const uint8_t base_class, const uint8_t subclass, const uint8_t protocol); @@ -735,37 +925,58 @@ int usbd_device_set_code_triple(struct usbd_contex *const uds_ctx, * @brief Setup USB device configuration attribute Remote Wakeup * * @param[in] uds_ctx Pointer to USB device support context + * @param[in] speed Configuration speed * @param[in] cfg Configuration number * @param[in] enable Sets attribute if true, clears it otherwise * * @return 0 on success, other values on fail. */ int usbd_config_attrib_rwup(struct usbd_contex *const uds_ctx, + const enum usbd_speed speed, const uint8_t cfg, const bool enable); /** * @brief Setup USB device configuration attribute Self-powered * * @param[in] uds_ctx Pointer to USB device support context + * @param[in] speed Configuration speed * @param[in] cfg Configuration number * @param[in] enable Sets attribute if true, clears it otherwise * * @return 0 on success, other values on fail. */ int usbd_config_attrib_self(struct usbd_contex *const uds_ctx, + const enum usbd_speed speed, const uint8_t cfg, const bool enable); /** * @brief Setup USB device configuration power consumption * * @param[in] uds_ctx Pointer to USB device support context + * @param[in] speed Configuration speed * @param[in] cfg Configuration number * @param[in] power Maximum power consumption value (bMaxPower) * * @return 0 on success, other values on fail. */ int usbd_config_maxpower(struct usbd_contex *const uds_ctx, + const enum usbd_speed speed, const uint8_t cfg, const uint8_t power); + +/** + * @brief Check that the controller can detect the VBUS state change. + * + * This can be used in a generic application to explicitly handle the VBUS + * detected event after usbd_init(). For example, to call usbd_enable() after a + * short delay to give the PMIC time to detect the bus, or to handle cases + * where usbd_enable() can only be called after a VBUS detected event. + * + * @param[in] uds_ctx Pointer to USB device support context + * + * @return true if controller can detect VBUS state change, false otherwise + */ +bool usbd_can_detect_vbus(struct usbd_contex *const uds_ctx); + /** * @} */ diff --git a/include/zephyr/usb/usbd_msg.h b/include/zephyr/usb/usbd_msg.h index 00ef52a3865..a11cff7d1da 100644 --- a/include/zephyr/usb/usbd_msg.h +++ b/include/zephyr/usb/usbd_msg.h @@ -81,18 +81,6 @@ struct usbd_msg { }; }; -/** - * @brief Callback type definition for USB device message delivery - * - * The implementation uses the system workqueue, and a callback provided and - * registered by the application. The application callback is called in the - * context of the system workqueue. Notification messages are stored in a queue - * and delivered to the callback in sequence. - * - * @param[in] msg Pointer to USB device message - */ -typedef void (*usbd_msg_cb_t)(const struct usbd_msg *const msg); - /** * @brief Returns the message type as a constant string * diff --git a/include/zephyr/zbus/zbus.h b/include/zephyr/zbus/zbus.h index 2c0c0622aed..151b5ec9860 100644 --- a/include/zephyr/zbus/zbus.h +++ b/include/zephyr/zbus/zbus.h @@ -510,7 +510,7 @@ struct zbus_channel_observation { * @retval -EAGAIN Waiting period timed out. * @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. + * value when the @kconfig{CONFIG_ZBUS_ASSERT_MOCK} is enabled. */ int zbus_chan_pub(const struct zbus_channel *chan, const void *msg, k_timeout_t timeout); @@ -529,7 +529,7 @@ int zbus_chan_pub(const struct zbus_channel *chan, const void *msg, k_timeout_t * @retval -EBUSY The channel is busy. * @retval -EAGAIN Waiting period timed out. * @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. + * function only returns this value when the @kconfig{CONFIG_ZBUS_ASSERT_MOCK} is enabled. */ int zbus_chan_read(const struct zbus_channel *chan, void *msg, k_timeout_t timeout); @@ -552,7 +552,7 @@ int zbus_chan_read(const struct zbus_channel *chan, void *msg, k_timeout_t timeo * @retval -EBUSY The channel is busy. * @retval -EAGAIN Waiting period timed out. * @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. + * function only returns this value when the @kconfig{CONFIG_ZBUS_ASSERT_MOCK} is enabled. */ int zbus_chan_claim(const struct zbus_channel *chan, k_timeout_t timeout); @@ -568,7 +568,7 @@ int zbus_chan_claim(const struct zbus_channel *chan, k_timeout_t timeout); * * @retval 0 Channel finished. * @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. + * function only returns this value when the @kconfig{CONFIG_ZBUS_ASSERT_MOCK} is enabled. */ int zbus_chan_finish(const struct zbus_channel *chan); @@ -588,7 +588,7 @@ int zbus_chan_finish(const struct zbus_channel *chan); * @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. + * value when the @kconfig{CONFIG_ZBUS_ASSERT_MOCK} is enabled. */ int zbus_chan_notify(const struct zbus_channel *chan, k_timeout_t timeout); @@ -747,7 +747,7 @@ struct zbus_observer_node { * * @retval 0 Observer set enable. * @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. + * function only returns this value when the @kconfig{CONFIG_ZBUS_ASSERT_MOCK} is enabled. */ int zbus_obs_set_enable(struct zbus_observer *obs, bool enabled); @@ -832,7 +832,7 @@ static inline const char *zbus_obs_name(const struct zbus_observer *obs) * * @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. + * function only returns this value when the @kconfig{CONFIG_ZBUS_ASSERT_MOCK} is enabled. */ int zbus_obs_attach_to_thread(const struct zbus_observer *obs); @@ -843,7 +843,7 @@ int zbus_obs_attach_to_thread(const struct zbus_observer *obs); * * @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. + * function only returns this value when the @kconfig{CONFIG_ZBUS_ASSERT_MOCK} is enabled. */ int zbus_obs_detach_from_thread(const struct zbus_observer *obs); @@ -865,7 +865,7 @@ int zbus_obs_detach_from_thread(const struct zbus_observer *obs); * @retval -EAGAIN Waiting period timed out. * @retval -EINVAL The observer is not a subscriber. * @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. + * function only returns this value when the @kconfig{CONFIG_ZBUS_ASSERT_MOCK} is enabled. */ int zbus_sub_wait(const struct zbus_observer *sub, const struct zbus_channel **chan, k_timeout_t timeout); diff --git a/kernel/Kconfig b/kernel/Kconfig index 8114a7b84dc..f8a3926d451 100644 --- a/kernel/Kconfig +++ b/kernel/Kconfig @@ -156,7 +156,7 @@ config SCHED_CPU_MASK_PIN_ONLY config MAIN_STACK_SIZE int "Size of stack for initialization and main thread" default 2048 if COVERAGE_GCOV - default 512 if ZTEST && !(RISCV || X86 || ARM) + default 512 if ZTEST && !(RISCV || X86 || ARM || ARC) default 1024 help When the initialization is complete, the thread executing it then @@ -441,6 +441,7 @@ config SKIP_BSS_CLEAR config BOOT_BANNER bool "Boot banner" default y + depends on !NCS_BOOT_BANNER select PRINTK select EARLY_CONSOLE help @@ -943,59 +944,7 @@ config BOUNDS_CHECK_BYPASS_MITIGATION macros do nothing. endmenu - -menu "Memory Domains" - -config MAX_DOMAIN_PARTITIONS - int "Maximum number of partitions per memory domain" - default 16 - range 0 255 - depends on USERSPACE - help - Configure the maximum number of partitions per memory domain. - -config ARCH_MEM_DOMAIN_DATA - bool - depends on USERSPACE - help - This hidden option is selected by the target architecture if - architecture-specific data is needed on a per memory domain basis. - If so, the architecture defines a 'struct arch_mem_domain' which is - embedded within every struct k_mem_domain. The architecture - must also define the arch_mem_domain_init() function to set this up - when a memory domain is created. - - Typical uses might be a set of page tables for that memory domain. - -config ARCH_MEM_DOMAIN_SYNCHRONOUS_API - bool - depends on USERSPACE - help - This hidden option is selected by the target architecture if - modifying a memory domain's partitions at runtime, or changing - a memory domain's thread membership requires synchronous calls - into the architecture layer. - - If enabled, the architecture layer must implement the following - APIs: - - arch_mem_domain_thread_add - arch_mem_domain_thread_remove - arch_mem_domain_partition_remove - arch_mem_domain_partition_add - - It's important to note that although supervisor threads can be - members of memory domains, they have no implications on supervisor - thread access to memory. Memory domain APIs may only be invoked from - supervisor mode. - - For these reasons, on uniprocessor systems unless memory access - policy is managed in separate software constructions like page - tables, these APIs don't need to be implemented as the underlying - memory management hardware will be reprogrammed on context switch - anyway. -endmenu - +rsource "Kconfig.mem_domain" rsource "Kconfig.smp" config TICKLESS_KERNEL @@ -1020,6 +969,12 @@ config THREAD_LOCAL_STORAGE help This option enables thread local storage (TLS) support in kernel. +config KERNEL_WHOLE_ARCHIVE + bool + help + This option forces every object file in the libkernel.a archive + to be included, rather than searching the archive for required object files. + endmenu rsource "Kconfig.device" diff --git a/kernel/Kconfig.mem_domain b/kernel/Kconfig.mem_domain new file mode 100644 index 00000000000..28f3d003639 --- /dev/null +++ b/kernel/Kconfig.mem_domain @@ -0,0 +1,79 @@ +# Kernel configuration options + +# Copyright (c) 2014-2015 Wind River Systems, Inc. +# SPDX-License-Identifier: Apache-2.0 + +menu "Memory Domains" + +config MAX_DOMAIN_PARTITIONS + int "Maximum number of partitions per memory domain" + default 16 + range 0 255 + depends on USERSPACE + help + Configure the maximum number of partitions per memory domain. + +config ARCH_MEM_DOMAIN_DATA + bool + depends on USERSPACE + help + This hidden option is selected by the target architecture if + architecture-specific data is needed on a per memory domain basis. + If so, the architecture defines a 'struct arch_mem_domain' which is + embedded within every struct k_mem_domain. The architecture + must also define the arch_mem_domain_init() function to set this up + when a memory domain is created. + + Typical uses might be a set of page tables for that memory domain. + +config ARCH_MEM_DOMAIN_SYNCHRONOUS_API + bool + depends on USERSPACE + help + This hidden option is selected by the target architecture if + modifying a memory domain's partitions at runtime, or changing + a memory domain's thread membership requires synchronous calls + into the architecture layer. + + If enabled, the architecture layer must implement the following + APIs: + + arch_mem_domain_thread_add + arch_mem_domain_thread_remove + arch_mem_domain_partition_remove + arch_mem_domain_partition_add + + It's important to note that although supervisor threads can be + members of memory domains, they have no implications on supervisor + thread access to memory. Memory domain APIs may only be invoked from + supervisor mode. + + For these reasons, on uniprocessor systems unless memory access + policy is managed in separate software constructions like page + tables, these APIs don't need to be implemented as the underlying + memory management hardware will be reprogrammed on context switch + anyway. + +config ARCH_MEM_DOMAIN_SUPPORTS_ISOLATED_STACKS + bool + help + This hidden option is selected by the target architecture if + the architecture supports isolating thread stacks for threads + within the same memory domain. + +config MEM_DOMAIN_ISOLATED_STACKS + bool + default y + depends on (MMU || MPU) && ARCH_MEM_DOMAIN_SUPPORTS_ISOLATED_STACKS + help + If enabled, thread stacks within the same memory domains are + isolated which means threads within the same memory domains + have no access to others threads' stacks. + + If disabled, threads within the same memory domains can access + other threads' stacks. + + Regardless of this settings, threads cannot access the stacks of + threads outside of their domains. + +endmenu diff --git a/kernel/device.c b/kernel/device.c index 6124ada5140..4b19d247c00 100644 --- a/kernel/device.c +++ b/kernel/device.c @@ -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 (k_usermode_string_copy(name_copy, (char *)name, sizeof(name_copy)) + if (k_usermode_string_copy(name_copy, name, sizeof(name_copy)) != 0) { return NULL; } diff --git a/kernel/dynamic.c b/kernel/dynamic.c index d03e3669346..89f80933dd0 100644 --- a/kernel/dynamic.c +++ b/kernel/dynamic.c @@ -166,6 +166,15 @@ int z_impl_k_thread_stack_free(k_thread_stack_t *stack) #ifdef CONFIG_USERSPACE static inline int z_vrfy_k_thread_stack_free(k_thread_stack_t *stack) { + /* The thread stack object must not be in initialized state. + * + * Thread stack objects are initialized when the thread is created + * and de-initialized whent the thread is destroyed. Since we can't + * free a stack that is in use, we have to check that the caller + * has access to the object but that it is not in use anymore. + */ + K_OOPS(K_SYSCALL_OBJ_NEVER_INIT(stack, K_OBJ_THREAD_STACK_ELEMENT)); + return z_impl_k_thread_stack_free(stack); } #include diff --git a/kernel/futex.c b/kernel/futex.c index 1354a6314e4..813ce0f62e3 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -17,7 +17,7 @@ static struct z_futex_data *k_futex_find_data(struct k_futex *futex) struct k_object *obj; obj = k_object_find(futex); - if (obj == NULL || obj->type != K_OBJ_FUTEX) { + if ((obj == NULL) || (obj->type != K_OBJ_FUTEX)) { return NULL; } diff --git a/kernel/include/kernel_internal.h b/kernel/include/kernel_internal.h index c598720999a..b2e1ccf7068 100644 --- a/kernel/include/kernel_internal.h +++ b/kernel/include/kernel_internal.h @@ -140,7 +140,7 @@ extern void smp_timer_init(void); extern void z_early_rand_get(uint8_t *buf, size_t length); -#if CONFIG_STACK_POINTER_RANDOM +#if defined(CONFIG_STACK_POINTER_RANDOM) && (CONFIG_STACK_POINTER_RANDOM != 0) extern int z_stack_adjust_initialized; #endif /* CONFIG_STACK_POINTER_RANDOM */ diff --git a/kernel/include/ksched.h b/kernel/include/ksched.h index 2943ee1e612..a25755aac27 100644 --- a/kernel/include/ksched.h +++ b/kernel/include/ksched.h @@ -37,6 +37,8 @@ BUILD_ASSERT(K_LOWEST_APPLICATION_THREAD_PRIO #define Z_ASSERT_VALID_PRIO(prio, entry_point) __ASSERT((prio) == -1, "") #endif /* CONFIG_MULTITHREADING */ +extern struct k_thread _thread_dummy; + void z_sched_init(void); void z_move_thread_to_end_of_prio_q(struct k_thread *thread); void z_unpend_thread_no_timeout(struct k_thread *thread); @@ -115,7 +117,7 @@ int32_t z_sched_prio_cmp(struct k_thread *thread_1, struct k_thread *thread_2); static inline bool _is_valid_prio(int prio, void *entry_point) { - if (prio == K_IDLE_PRIO && z_is_idle_thread_entry(entry_point)) { + if ((prio == K_IDLE_PRIO) && z_is_idle_thread_entry(entry_point)) { return true; } diff --git a/kernel/include/kthread.h b/kernel/include/kthread.h index 9311552e0f0..bf5fb1da08f 100644 --- a/kernel/include/kthread.h +++ b/kernel/include/kthread.h @@ -75,7 +75,7 @@ static inline int thread_is_metairq(struct k_thread *thread) #endif /* CONFIG_NUM_METAIRQ_PRIORITIES */ } -#if CONFIG_ASSERT +#ifdef CONFIG_ASSERT static inline bool is_thread_dummy(struct k_thread *thread) { return (thread->base.thread_state & _THREAD_DUMMY) != 0U; diff --git a/kernel/include/mmu.h b/kernel/include/mmu.h index 4650b65bc89..ddfbdd2e16e 100644 --- a/kernel/include/mmu.h +++ b/kernel/include/mmu.h @@ -9,7 +9,7 @@ #ifdef CONFIG_MMU #include -#include +#include #include #include #include @@ -26,7 +26,7 @@ * core kernel. */ #define Z_PHYS_RAM_START ((uintptr_t)CONFIG_SRAM_BASE_ADDRESS) -#define Z_PHYS_RAM_SIZE ((size_t)KB(CONFIG_SRAM_SIZE)) +#define Z_PHYS_RAM_SIZE (KB(CONFIG_SRAM_SIZE)) #define Z_PHYS_RAM_END (Z_PHYS_RAM_START + Z_PHYS_RAM_SIZE) #define Z_NUM_PAGE_FRAMES (Z_PHYS_RAM_SIZE / (size_t)CONFIG_MMU_PAGE_SIZE) @@ -36,8 +36,8 @@ #define Z_VIRT_RAM_END (Z_VIRT_RAM_START + Z_VIRT_RAM_SIZE) /* Boot-time virtual location of the kernel image. */ -#define Z_KERNEL_VIRT_START ((uint8_t *)(&z_mapped_start)) -#define Z_KERNEL_VIRT_END ((uint8_t *)(&z_mapped_end)) +#define Z_KERNEL_VIRT_START ((uint8_t *)&z_mapped_start[0]) +#define Z_KERNEL_VIRT_END ((uint8_t *)&z_mapped_end[0]) #define Z_KERNEL_VIRT_SIZE (Z_KERNEL_VIRT_END - Z_KERNEL_VIRT_START) #define Z_VM_OFFSET ((CONFIG_KERNEL_VM_BASE + CONFIG_KERNEL_VM_OFFSET) - \ @@ -64,31 +64,38 @@ /* * z_page_frame flags bits + * + * Requirements: + * - Z_PAGE_FRAME_FREE must be one of the possible sfnode flag bits + * - All bit values must be lower than CONFIG_MMU_PAGE_SIZE */ -/** This page contains critical kernel data and will never be swapped */ -#define Z_PAGE_FRAME_PINNED BIT(0) +/** This physical page is free and part of the free list */ +#define Z_PAGE_FRAME_FREE BIT(0) /** This physical page is reserved by hardware; we will never use it */ #define Z_PAGE_FRAME_RESERVED BIT(1) +/** This page contains critical kernel data and will never be swapped */ +#define Z_PAGE_FRAME_PINNED BIT(2) + /** * This physical page is mapped to some virtual memory address * * Currently, we just support one mapping per page frame. If a page frame * is mapped to multiple virtual pages then it must be pinned. */ -#define Z_PAGE_FRAME_MAPPED BIT(2) +#define Z_PAGE_FRAME_MAPPED BIT(3) /** * This page frame is currently involved in a page-in/out operation */ -#define Z_PAGE_FRAME_BUSY BIT(3) +#define Z_PAGE_FRAME_BUSY BIT(4) /** * This page frame has a clean copy in the backing store */ -#define Z_PAGE_FRAME_BACKED BIT(4) +#define Z_PAGE_FRAME_BACKED BIT(5) /** * Data structure for physical page frames @@ -98,68 +105,89 @@ */ struct z_page_frame { union { - /* If mapped, virtual address this page is mapped to */ - void *addr; - - /* If unmapped and available, free pages list membership. */ - sys_snode_t node; + /* + * If mapped, Z_PAGE_FRAME_* flags and virtual address + * this page is mapped to. + */ + uintptr_t va_and_flags; + + /* + * If unmapped and available, free pages list membership + * with the Z_PAGE_FRAME_FREE flag. + */ + sys_sfnode_t node; }; - /* Z_PAGE_FRAME_* flags */ - uint8_t flags; - - /* TODO: Backing store and eviction algorithms may both need to - * introduce custom members for accounting purposes. Come up with - * a layer of abstraction for this. They may also want additional - * flags bits which shouldn't clobber each other. At all costs - * the total size of struct z_page_frame must be minimized. + /* Backing store and eviction algorithms may both need to + * require additional per-frame custom data for accounting purposes. + * They should declare their own array with indices matching + * z_page_frames[] ones whenever possible. + * They may also want additional flags bits that could be stored here + * and they shouldn't clobber each other. At all costs the total + * size of struct z_page_frame must be minimized. */ +}; - /* On Xtensa we can't pack this struct because of the memory alignment. - */ -#ifdef CONFIG_XTENSA -} __aligned(4); -#else -} __packed; -#endif /* CONFIG_XTENSA */ +/* Note: this must be false for the other flag bits to be valid */ +static inline bool z_page_frame_is_free(struct z_page_frame *pf) +{ + return (pf->va_and_flags & Z_PAGE_FRAME_FREE) != 0U; +} static inline bool z_page_frame_is_pinned(struct z_page_frame *pf) { - return (pf->flags & Z_PAGE_FRAME_PINNED) != 0U; + return (pf->va_and_flags & Z_PAGE_FRAME_PINNED) != 0U; } static inline bool z_page_frame_is_reserved(struct z_page_frame *pf) { - return (pf->flags & Z_PAGE_FRAME_RESERVED) != 0U; + return (pf->va_and_flags & Z_PAGE_FRAME_RESERVED) != 0U; } static inline bool z_page_frame_is_mapped(struct z_page_frame *pf) { - return (pf->flags & Z_PAGE_FRAME_MAPPED) != 0U; + return (pf->va_and_flags & Z_PAGE_FRAME_MAPPED) != 0U; } static inline bool z_page_frame_is_busy(struct z_page_frame *pf) { - return (pf->flags & Z_PAGE_FRAME_BUSY) != 0U; + return (pf->va_and_flags & Z_PAGE_FRAME_BUSY) != 0U; } static inline bool z_page_frame_is_backed(struct z_page_frame *pf) { - return (pf->flags & Z_PAGE_FRAME_BACKED) != 0U; + return (pf->va_and_flags & Z_PAGE_FRAME_BACKED) != 0U; } static inline bool z_page_frame_is_evictable(struct z_page_frame *pf) { - return (!z_page_frame_is_reserved(pf) && z_page_frame_is_mapped(pf) && - !z_page_frame_is_pinned(pf) && !z_page_frame_is_busy(pf)); + return (!z_page_frame_is_free(pf) && + !z_page_frame_is_reserved(pf) && + z_page_frame_is_mapped(pf) && + !z_page_frame_is_pinned(pf) && + !z_page_frame_is_busy(pf)); } -/* If true, page is not being used for anything, is not reserved, is a member - * of some free pages list, isn't busy, and may be mapped in memory +/* If true, page is not being used for anything, is not reserved, is not + * a member of some free pages list, isn't busy, and is ready to be mapped + * in memory */ static inline bool z_page_frame_is_available(struct z_page_frame *page) { - return page->flags == 0U; + return page->va_and_flags == 0U; +} + +static inline void z_page_frame_set(struct z_page_frame *pf, uint8_t flags) +{ + pf->va_and_flags |= flags; +} + +static inline void z_page_frame_clear(struct z_page_frame *pf, uint8_t flags) +{ + /* ensure bit inversion to follow is done on the proper type width */ + uintptr_t wide_flags = flags; + + pf->va_and_flags &= ~wide_flags; } static inline void z_assert_phys_aligned(uintptr_t phys) @@ -180,7 +208,9 @@ static inline uintptr_t z_page_frame_to_phys(struct z_page_frame *pf) /* Presumes there is but one mapping in the virtual address space */ static inline void *z_page_frame_to_virt(struct z_page_frame *pf) { - return pf->addr; + uintptr_t flags_mask = CONFIG_MMU_PAGE_SIZE - 1; + + return (void *)(pf->va_and_flags & ~flags_mask); } static inline bool z_is_page_frame(uintptr_t phys) diff --git a/kernel/include/priority_q.h b/kernel/include/priority_q.h index e9ea0bff407..f744e6c5467 100644 --- a/kernel/include/priority_q.h +++ b/kernel/include/priority_q.h @@ -7,13 +7,20 @@ #ifndef ZEPHYR_KERNEL_INCLUDE_PRIORITY_Q_H_ #define ZEPHYR_KERNEL_INCLUDE_PRIORITY_Q_H_ +#include +#include -/* Dump Scheduling */ +extern int32_t z_sched_prio_cmp(struct k_thread *thread_1, + struct k_thread *thread_2); + +bool z_priq_rb_lessthan(struct rbnode *a, struct rbnode *b); + +/* Dumb Scheduling */ #if defined(CONFIG_SCHED_DUMB) #define _priq_run_add z_priq_dumb_add #define _priq_run_remove z_priq_dumb_remove # if defined(CONFIG_SCHED_CPU_MASK) -# define _priq_run_best _priq_dumb_mask_best +# define _priq_run_best z_priq_dumb_mask_best # else # define _priq_run_best z_priq_dumb_best # endif /* CONFIG_SCHED_CPU_MASK */ @@ -25,11 +32,11 @@ /* Multi Queue Scheduling */ #elif defined(CONFIG_SCHED_MULTIQ) -# if defined(CONFIG_64BIT) -# define NBITS 64 -# else -# define NBITS 32 -# endif +#if defined(CONFIG_64BIT) +#define NBITS 64 +#else +#define NBITS 32 +#endif /* CONFIG_64BIT */ #define _priq_run_add z_priq_mq_add #define _priq_run_remove z_priq_mq_remove @@ -40,30 +47,99 @@ static ALWAYS_INLINE void z_priq_mq_remove(struct _priq_mq *pq, struct k_thread /* Scalable Wait Queue */ #if defined(CONFIG_WAITQ_SCALABLE) -#define z_priq_wait_add z_priq_rb_add +#define _priq_wait_add z_priq_rb_add #define _priq_wait_remove z_priq_rb_remove #define _priq_wait_best z_priq_rb_best -/* Dump Wait Queue */ +/* Dumb Wait Queue */ #elif defined(CONFIG_WAITQ_DUMB) -#define z_priq_wait_add z_priq_dumb_add +#define _priq_wait_add z_priq_dumb_add #define _priq_wait_remove z_priq_dumb_remove #define _priq_wait_best z_priq_dumb_best #endif -/* Dumb Scheduling*/ -struct k_thread *z_priq_dumb_best(sys_dlist_t *pq); -void z_priq_dumb_remove(sys_dlist_t *pq, struct k_thread *thread); +static ALWAYS_INLINE void z_priq_dumb_remove(sys_dlist_t *pq, struct k_thread *thread) +{ + ARG_UNUSED(pq); -/* Scalable Scheduling */ -void z_priq_rb_add(struct _priq_rb *pq, struct k_thread *thread); -void z_priq_rb_remove(struct _priq_rb *pq, struct k_thread *thread); + sys_dlist_remove(&thread->base.qnode_dlist); +} -/* Multi Queue Scheduling */ -struct k_thread *z_priq_mq_best(struct _priq_mq *pq); -struct k_thread *z_priq_rb_best(struct _priq_rb *pq); +static ALWAYS_INLINE struct k_thread *z_priq_dumb_best(sys_dlist_t *pq) +{ + struct k_thread *thread = NULL; + sys_dnode_t *n = sys_dlist_peek_head(pq); + if (n != NULL) { + thread = CONTAINER_OF(n, struct k_thread, base.qnode_dlist); + } + return thread; +} -bool z_priq_rb_lessthan(struct rbnode *a, struct rbnode *b); +static ALWAYS_INLINE void z_priq_rb_add(struct _priq_rb *pq, struct k_thread *thread) +{ + struct k_thread *t; + + thread->base.order_key = pq->next_order_key++; + + /* Renumber at wraparound. This is tiny code, and in practice + * will almost never be hit on real systems. BUT on very + * long-running systems where a priq never completely empties + * AND that contains very large numbers of threads, it can be + * a latency glitch to loop over all the threads like this. + */ + if (!pq->next_order_key) { + RB_FOR_EACH_CONTAINER(&pq->tree, t, base.qnode_rb) { + t->base.order_key = pq->next_order_key++; + } + } + + rb_insert(&pq->tree, &thread->base.qnode_rb); +} + +static ALWAYS_INLINE void z_priq_rb_remove(struct _priq_rb *pq, struct k_thread *thread) +{ + rb_remove(&pq->tree, &thread->base.qnode_rb); + + if (!pq->tree.root) { + pq->next_order_key = 0; + } +} + +static ALWAYS_INLINE struct k_thread *z_priq_rb_best(struct _priq_rb *pq) +{ + struct k_thread *thread = NULL; + struct rbnode *n = rb_get_min(&pq->tree); + + if (n != NULL) { + thread = CONTAINER_OF(n, struct k_thread, base.qnode_rb); + } + return thread; +} + +static ALWAYS_INLINE struct k_thread *z_priq_mq_best(struct _priq_mq *pq) +{ + struct k_thread *thread = NULL; + + for (int i = 0; i < PRIQ_BITMAP_SIZE; ++i) { + if (!pq->bitmask[i]) { + continue; + } + +#ifdef CONFIG_64BIT + sys_dlist_t *l = &pq->queues[i * 64 + u64_count_trailing_zeros(pq->bitmask[i])]; +#else + sys_dlist_t *l = &pq->queues[i * 32 + u32_count_trailing_zeros(pq->bitmask[i])]; +#endif + sys_dnode_t *n = sys_dlist_peek_head(l); + + if (n != NULL) { + thread = CONTAINER_OF(n, struct k_thread, base.qnode_dlist); + break; + } + } + + return thread; +} #ifdef CONFIG_SCHED_MULTIQ @@ -105,4 +181,43 @@ static ALWAYS_INLINE void z_priq_mq_remove(struct _priq_mq *pq, } } #endif /* CONFIG_SCHED_MULTIQ */ + + + +#ifdef CONFIG_SCHED_CPU_MASK +static ALWAYS_INLINE struct k_thread *z_priq_dumb_mask_best(sys_dlist_t *pq) +{ + /* With masks enabled we need to be prepared to walk the list + * looking for one we can run + */ + struct k_thread *thread; + + SYS_DLIST_FOR_EACH_CONTAINER(pq, thread, base.qnode_dlist) { + if ((thread->base.cpu_mask & BIT(_current_cpu->id)) != 0) { + return thread; + } + } + return NULL; +} +#endif /* CONFIG_SCHED_CPU_MASK */ + + +#if defined(CONFIG_SCHED_DUMB) || defined(CONFIG_WAITQ_DUMB) +static ALWAYS_INLINE void z_priq_dumb_add(sys_dlist_t *pq, + struct k_thread *thread) +{ + struct k_thread *t; + + SYS_DLIST_FOR_EACH_CONTAINER(pq, t, base.qnode_dlist) { + if (z_sched_prio_cmp(thread, t) > 0) { + sys_dlist_insert(&t->base.qnode_dlist, + &thread->base.qnode_dlist); + return; + } + } + + sys_dlist_append(pq, &thread->base.qnode_dlist); +} +#endif /* CONFIG_SCHED_DUMB || CONFIG_WAITQ_DUMB */ + #endif /* ZEPHYR_KERNEL_INCLUDE_PRIORITY_Q_H_ */ diff --git a/kernel/init.c b/kernel/init.c index fe6c176a072..00765f5483a 100644 --- a/kernel/init.c +++ b/kernel/init.c @@ -36,6 +36,7 @@ #include #include #include +#include LOG_MODULE_REGISTER(os, CONFIG_KERNEL_LOG_LEVEL); BUILD_ASSERT(CONFIG_MP_NUM_CPUS == CONFIG_MP_MAX_NUM_CPUS, @@ -45,8 +46,9 @@ BUILD_ASSERT(CONFIG_MP_NUM_CPUS == CONFIG_MP_MAX_NUM_CPUS, __pinned_bss struct z_kernel _kernel; -__pinned_bss -atomic_t _cpus_active; +#ifdef CONFIG_PM +__pinned_bss atomic_t _cpus_active; +#endif /* init/main and idle threads */ K_THREAD_PINNED_STACK_DEFINE(z_main_stack, CONFIG_MAIN_STACK_SIZE); @@ -301,6 +303,37 @@ extern volatile uintptr_t __stack_chk_guard; __pinned_bss bool z_sys_post_kernel; +static int do_device_init(const struct init_entry *entry) +{ + const struct device *dev = entry->dev; + int rc = 0; + + if (entry->init_fn.dev != NULL) { + rc = entry->init_fn.dev(dev); + /* Mark device initialized. If initialization + * failed, record the error condition. + */ + if (rc != 0) { + if (rc < 0) { + rc = -rc; + } + if (rc > UINT8_MAX) { + rc = UINT8_MAX; + } + dev->state->init_res = rc; + } + } + + dev->state->initialized = true; + + if (rc == 0) { + /* Run automatic device runtime enablement */ + (void)pm_device_runtime_auto_enable(dev); + } + + return rc; +} + /** * @brief Execute all the init entry initialization functions at a given level * @@ -332,36 +365,39 @@ static void z_sys_init_run_level(enum init_level level) const struct device *dev = entry->dev; if (dev != NULL) { - int rc = 0; - - if (entry->init_fn.dev != NULL) { - rc = entry->init_fn.dev(dev); - /* Mark device initialized. If initialization - * failed, record the error condition. - */ - if (rc != 0) { - if (rc < 0) { - rc = -rc; - } - if (rc > UINT8_MAX) { - rc = UINT8_MAX; - } - dev->state->init_res = rc; - } - } - - dev->state->initialized = true; - - if (rc == 0) { - /* Run automatic device runtime enablement */ - (void)pm_device_runtime_auto_enable(dev); - } + do_device_init(entry); } else { (void)entry->init_fn.sys(); } } } + +int z_impl_device_init(const struct device *dev) +{ + if (dev == NULL) { + return -ENOENT; + } + + STRUCT_SECTION_FOREACH_ALTERNATE(_deferred_init, init_entry, entry) { + if (entry->dev == dev) { + return do_device_init(entry); + } + } + + return -ENOENT; +} + +#ifdef CONFIG_USERSPACE +static inline int z_vrfy_device_init(const struct device *dev) +{ + K_OOPS(K_SYSCALL_OBJ_INIT(dev, K_OBJ_ANY)); + + return z_impl_device_init(dev); +} +#include +#endif + extern void boot_banner(void); @@ -389,7 +425,7 @@ static void bg_thread_main(void *unused1, void *unused2, void *unused3) z_sys_post_kernel = true; z_sys_init_run_level(INIT_LEVEL_POST_KERNEL); -#if CONFIG_STACK_POINTER_RANDOM +#if defined(CONFIG_STACK_POINTER_RANDOM) && (CONFIG_STACK_POINTER_RANDOM != 0) z_stack_adjust_initialized = 1; #endif /* CONFIG_STACK_POINTER_RANDOM */ boot_banner(); @@ -477,11 +513,13 @@ void z_init_cpu(int id) CONFIG_SCHED_THREAD_USAGE_AUTO_ENABLE; #endif +#ifdef CONFIG_PM /* * Increment number of CPUs active. The pm subsystem * will keep track of this from here. */ atomic_inc(&_cpus_active); +#endif #ifdef CONFIG_OBJ_CORE_SYSTEM k_obj_core_init_and_link(K_OBJ_CORE(&_kernel.cpus[id]), &obj_type_cpu); @@ -615,12 +653,7 @@ FUNC_NORETURN void z_cstart(void) LOG_CORE_INIT(); #if defined(CONFIG_MULTITHREADING) - /* Note: The z_ready_thread() call in prepare_multithreading() requires - * a dummy thread even if CONFIG_ARCH_HAS_CUSTOM_SWAP_TO_MAIN=y - */ - struct k_thread dummy_thread; - - z_dummy_thread_init(&dummy_thread); + z_dummy_thread_init(&_thread_dummy); #endif /* CONFIG_MULTITHREADING */ /* do any necessary initialization of static devices */ z_device_state_init(); diff --git a/kernel/kheap.c b/kernel/kheap.c index fd29df2e92c..ccdd6690788 100644 --- a/kernel/kheap.c +++ b/kernel/kheap.c @@ -123,7 +123,7 @@ void k_heap_free(struct k_heap *heap, void *mem) sys_heap_free(&heap->heap, mem); SYS_PORT_TRACING_OBJ_FUNC(k_heap, free, heap); - if (IS_ENABLED(CONFIG_MULTITHREADING) && z_unpend_all(&heap->wait_q) != 0) { + if (IS_ENABLED(CONFIG_MULTITHREADING) && (z_unpend_all(&heap->wait_q) != 0)) { z_reschedule(&heap->lock, key); } else { k_spin_unlock(&heap->lock, key); diff --git a/kernel/mem_domain.c b/kernel/mem_domain.c index 5c41c1418fe..16b337acf01 100644 --- a/kernel/mem_domain.c +++ b/kernel/mem_domain.c @@ -225,8 +225,8 @@ int k_mem_domain_remove_partition(struct k_mem_domain *domain, /* find a partition that matches the given start and size */ for (p_idx = 0; p_idx < max_partitions; p_idx++) { - if (domain->partitions[p_idx].start == part->start && - domain->partitions[p_idx].size == part->size) { + if ((domain->partitions[p_idx].start == part->start) && + (domain->partitions[p_idx].size == part->size)) { break; } } diff --git a/kernel/mem_slab.c b/kernel/mem_slab.c index 609063ef630..9482f0e88c5 100644 --- a/kernel/mem_slab.c +++ b/kernel/mem_slab.c @@ -172,7 +172,7 @@ SYS_INIT(init_mem_slab_obj_core_list, PRE_KERNEL_1, int k_mem_slab_init(struct k_mem_slab *slab, void *buffer, size_t block_size, uint32_t num_blocks) { - int rc = 0; + int rc; slab->info.num_blocks = num_blocks; slab->info.block_size = block_size; @@ -261,7 +261,7 @@ void k_mem_slab_free(struct k_mem_slab *slab, void *mem) "Invalid memory pointer provided"); SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_mem_slab, free, slab); - if (slab->free_list == NULL && IS_ENABLED(CONFIG_MULTITHREADING)) { + if ((slab->free_list == NULL) && IS_ENABLED(CONFIG_MULTITHREADING)) { struct k_thread *pending_thread = z_unpend_first_thread(&slab->wait_q); if (pending_thread != NULL) { diff --git a/kernel/mmu.c b/kernel/mmu.c index 4d364a1b0a6..f74b8c7cf44 100644 --- a/kernel/mmu.c +++ b/kernel/mmu.c @@ -81,7 +81,10 @@ static bool page_frames_initialized; /* LCOV_EXCL_START */ static void page_frame_dump(struct z_page_frame *pf) { - if (z_page_frame_is_reserved(pf)) { + if (z_page_frame_is_free(pf)) { + COLOR(GREY); + printk("-"); + } else if (z_page_frame_is_reserved(pf)) { COLOR(CYAN); printk("R"); } else if (z_page_frame_is_busy(pf)) { @@ -381,7 +384,7 @@ static void *virt_region_alloc(size_t size, size_t align) * This implies in the future there may be multiple slists managing physical * pages. Each page frame will still just have one snode link. */ -static sys_slist_t free_page_frame_list; +static sys_sflist_t free_page_frame_list; /* Number of unused and available free page frames. * This information may go stale immediately. @@ -395,15 +398,16 @@ static size_t z_free_page_count; /* Get an unused page frame. don't care which one, or NULL if there are none */ static struct z_page_frame *free_page_frame_list_get(void) { - sys_snode_t *node; + sys_sfnode_t *node; struct z_page_frame *pf = NULL; - node = sys_slist_get(&free_page_frame_list); + node = sys_sflist_get(&free_page_frame_list); if (node != NULL) { z_free_page_count--; pf = CONTAINER_OF(node, struct z_page_frame, node); - PF_ASSERT(pf, z_page_frame_is_available(pf), - "unavailable but somehow on free list"); + PF_ASSERT(pf, z_page_frame_is_free(pf), + "on free list but not free"); + pf->va_and_flags = 0; } return pf; @@ -414,21 +418,20 @@ static void free_page_frame_list_put(struct z_page_frame *pf) { PF_ASSERT(pf, z_page_frame_is_available(pf), "unavailable page put on free list"); - /* The structure is packed, which ensures that this is true */ - void *node = pf; - sys_slist_append(&free_page_frame_list, node); + sys_sfnode_init(&pf->node, Z_PAGE_FRAME_FREE); + sys_sflist_append(&free_page_frame_list, &pf->node); z_free_page_count++; } static void free_page_frame_list_init(void) { - sys_slist_init(&free_page_frame_list); + sys_sflist_init(&free_page_frame_list); } static void page_frame_free_locked(struct z_page_frame *pf) { - pf->flags = 0; + pf->va_and_flags = 0; free_page_frame_list_put(pf); } @@ -441,6 +444,8 @@ static void page_frame_free_locked(struct z_page_frame *pf) */ static void frame_mapped_set(struct z_page_frame *pf, void *addr) { + PF_ASSERT(pf, !z_page_frame_is_free(pf), + "attempted to map a page frame on the free list"); PF_ASSERT(pf, !z_page_frame_is_reserved(pf), "attempted to map a reserved page frame"); @@ -450,10 +455,14 @@ static void frame_mapped_set(struct z_page_frame *pf, void *addr) * Zephyr equivalent of VSDOs */ PF_ASSERT(pf, !z_page_frame_is_mapped(pf) || z_page_frame_is_pinned(pf), - "non-pinned and already mapped to %p", pf->addr); + "non-pinned and already mapped to %p", + z_page_frame_to_virt(pf)); + + uintptr_t flags_mask = CONFIG_MMU_PAGE_SIZE - 1; + uintptr_t va = (uintptr_t)addr & ~flags_mask; - pf->flags |= Z_PAGE_FRAME_MAPPED; - pf->addr = addr; + pf->va_and_flags &= flags_mask; + pf->va_and_flags |= va | Z_PAGE_FRAME_MAPPED; } /* LCOV_EXCL_START */ @@ -475,7 +484,7 @@ static int virt_to_page_frame(void *virt, uintptr_t *phys) Z_PAGE_FRAME_FOREACH(paddr, pf) { if (z_page_frame_is_mapped(pf)) { - if (virt == pf->addr) { + if (virt == z_page_frame_to_virt(pf)) { ret = 0; if (phys != NULL) { *phys = z_page_frame_to_phys(pf); @@ -523,7 +532,8 @@ static int map_anon_page(void *addr, uint32_t flags) pf = k_mem_paging_eviction_select(&dirty); __ASSERT(pf != NULL, "failed to get a page frame"); - LOG_DBG("evicting %p at 0x%lx", pf->addr, + LOG_DBG("evicting %p at 0x%lx", + z_page_frame_to_virt(pf), z_page_frame_to_phys(pf)); ret = page_frame_prepare_locked(pf, &dirty, false, &location); if (ret != 0) { @@ -532,7 +542,7 @@ static int map_anon_page(void *addr, uint32_t flags) if (dirty) { do_backing_store_page_out(location); } - pf->flags = 0; + pf->va_and_flags = 0; #else return -ENOMEM; #endif /* CONFIG_DEMAND_PAGING */ @@ -542,7 +552,7 @@ static int map_anon_page(void *addr, uint32_t flags) arch_mem_map(addr, phys, CONFIG_MMU_PAGE_SIZE, flags | K_MEM_CACHE_WB); if (lock) { - pf->flags |= Z_PAGE_FRAME_PINNED; + z_page_frame_set(pf, Z_PAGE_FRAME_PINNED); } frame_mapped_set(pf, addr); @@ -581,7 +591,7 @@ void *k_mem_map_impl(uintptr_t phys, size_t size, uint32_t flags, bool is_anon) /* Need extra for the guard pages (before and after) which we * won't map. */ - total_size = size + CONFIG_MMU_PAGE_SIZE * 2; + total_size = size + (CONFIG_MMU_PAGE_SIZE * 2); dst = virt_region_alloc(total_size, CONFIG_MMU_PAGE_SIZE); if (dst == NULL) { @@ -731,7 +741,7 @@ void k_mem_unmap_impl(void *addr, size_t size, bool is_anon) * region. So we also need to free them from the bitmap. */ pos = (uint8_t *)addr - CONFIG_MMU_PAGE_SIZE; - total_size = size + CONFIG_MMU_PAGE_SIZE * 2; + total_size = size + (CONFIG_MMU_PAGE_SIZE * 2); virt_region_free(pos, total_size); out: @@ -930,9 +940,9 @@ static void mark_linker_section_pinned(void *start_addr, void *end_addr, frame_mapped_set(pf, addr); if (pin) { - pf->flags |= Z_PAGE_FRAME_PINNED; + z_page_frame_set(pf, Z_PAGE_FRAME_PINNED); } else { - pf->flags &= ~Z_PAGE_FRAME_PINNED; + z_page_frame_clear(pf, Z_PAGE_FRAME_PINNED); } } } @@ -975,7 +985,7 @@ void z_mem_manage_init(void) * structures, and any code used to perform page fault * handling, page-ins, etc. */ - pf->flags |= Z_PAGE_FRAME_PINNED; + z_page_frame_set(pf, Z_PAGE_FRAME_PINNED); } #endif /* CONFIG_LINKER_GENERIC_SECTIONS_PRESENT_AT_BOOT */ @@ -1177,7 +1187,7 @@ static int page_frame_prepare_locked(struct z_page_frame *pf, bool *dirty_ptr, LOG_ERR("out of backing store memory"); return -ENOMEM; } - arch_mem_page_out(pf->addr, *location_ptr); + arch_mem_page_out(z_page_frame_to_virt(pf), *location_ptr); } else { /* Shouldn't happen unless this function is mis-used */ __ASSERT(!dirty, "un-mapped page determined to be dirty"); @@ -1186,7 +1196,7 @@ static int page_frame_prepare_locked(struct z_page_frame *pf, bool *dirty_ptr, /* Mark as busy so that z_page_frame_is_evictable() returns false */ __ASSERT(!z_page_frame_is_busy(pf), "page frame 0x%lx is already busy", phys); - pf->flags |= Z_PAGE_FRAME_BUSY; + z_page_frame_set(pf, Z_PAGE_FRAME_BUSY); #endif /* CONFIG_DEMAND_PAGING_ALLOW_IRQ */ /* Update dirty parameter, since we set to true if it wasn't backed * even if otherwise clean @@ -1222,7 +1232,7 @@ static int do_mem_evict(void *addr) dirty = (flags & ARCH_DATA_PAGE_DIRTY) != 0; pf = z_phys_to_page_frame(phys); - __ASSERT(pf->addr == addr, "page frame address mismatch"); + __ASSERT(z_page_frame_to_virt(pf) == addr, "page frame address mismatch"); ret = page_frame_prepare_locked(pf, &dirty, false, &location); if (ret != 0) { goto out; @@ -1294,7 +1304,7 @@ int z_page_frame_evict(uintptr_t phys) ret = 0; goto out; } - flags = arch_page_info_get(pf->addr, NULL, false); + flags = arch_page_info_get(z_page_frame_to_virt(pf), NULL, false); /* Shouldn't ever happen */ __ASSERT((flags & ARCH_DATA_PAGE_LOADED) != 0, "data page not loaded"); dirty = (flags & ARCH_DATA_PAGE_DIRTY) != 0; @@ -1440,9 +1450,9 @@ static bool do_page_fault(void *addr, bool pin) * during the page-in/out operation. * * We do however re-enable interrupts during the page-in/page-out - * operation iff interrupts were enabled when the exception was taken; - * in this configuration page faults in an ISR are a bug; all their - * code/data must be pinned. + * operation if and only if interrupts were enabled when the exception + * was taken; in this configuration page faults in an ISR are a bug; + * all their code/data must be pinned. * * If interrupts were disabled when the exception was taken, the * arch code is responsible for keeping them that way when entering @@ -1480,7 +1490,7 @@ static bool do_page_fault(void *addr, bool pin) uintptr_t phys = page_in_location; pf = z_phys_to_page_frame(phys); - pf->flags |= Z_PAGE_FRAME_PINNED; + z_page_frame_set(pf, Z_PAGE_FRAME_PINNED); } /* This if-block is to pin the page if it is @@ -1500,7 +1510,8 @@ static bool do_page_fault(void *addr, bool pin) /* Need to evict a page frame */ pf = do_eviction_select(&dirty); __ASSERT(pf != NULL, "failed to get a page frame"); - LOG_DBG("evicting %p at 0x%lx", pf->addr, + LOG_DBG("evicting %p at 0x%lx", + z_page_frame_to_virt(pf), z_page_frame_to_phys(pf)); paging_stats_eviction_inc(faulting_thread, dirty); @@ -1522,14 +1533,13 @@ static bool do_page_fault(void *addr, bool pin) #ifdef CONFIG_DEMAND_PAGING_ALLOW_IRQ key = irq_lock(); - pf->flags &= ~Z_PAGE_FRAME_BUSY; + z_page_frame_clear(pf, Z_PAGE_FRAME_BUSY); #endif /* CONFIG_DEMAND_PAGING_ALLOW_IRQ */ + z_page_frame_clear(pf, Z_PAGE_FRAME_MAPPED); + frame_mapped_set(pf, addr); if (pin) { - pf->flags |= Z_PAGE_FRAME_PINNED; + z_page_frame_set(pf, Z_PAGE_FRAME_PINNED); } - pf->flags |= Z_PAGE_FRAME_MAPPED; - pf->addr = UINT_TO_POINTER(POINTER_TO_UINT(addr) - & ~(CONFIG_MMU_PAGE_SIZE - 1)); arch_mem_page_in(addr, z_page_frame_to_phys(pf)); k_mem_paging_backing_store_page_finalize(pf, page_in_location); @@ -1593,7 +1603,7 @@ static void do_mem_unpin(void *addr) "invalid data page at %p", addr); if ((flags & ARCH_DATA_PAGE_LOADED) != 0) { pf = z_phys_to_page_frame(phys); - pf->flags &= ~Z_PAGE_FRAME_PINNED; + z_page_frame_clear(pf, Z_PAGE_FRAME_PINNED); } irq_unlock(key); } diff --git a/kernel/msg_q.c b/kernel/msg_q.c index b315cde80e1..b3cd959d578 100644 --- a/kernel/msg_q.c +++ b/kernel/msg_q.c @@ -151,7 +151,7 @@ int z_impl_k_msgq_put(struct k_msgq *msgq, const void *data, k_timeout_t timeout /* put message in queue */ __ASSERT_NO_MSG(msgq->write_ptr >= msgq->buffer_start && msgq->write_ptr < msgq->buffer_end); - (void)memcpy(msgq->write_ptr, data, msgq->msg_size); + (void)memcpy(msgq->write_ptr, (char *)data, msgq->msg_size); msgq->write_ptr += msgq->msg_size; if (msgq->write_ptr == msgq->buffer_end) { msgq->write_ptr = msgq->buffer_start; @@ -227,7 +227,7 @@ int z_impl_k_msgq_get(struct k_msgq *msgq, void *data, k_timeout_t timeout) if (msgq->used_msgs > 0U) { /* take first available message from queue */ - (void)memcpy(data, msgq->read_ptr, msgq->msg_size); + (void)memcpy((char *)data, msgq->read_ptr, msgq->msg_size); msgq->read_ptr += msgq->msg_size; if (msgq->read_ptr == msgq->buffer_end) { msgq->read_ptr = msgq->buffer_start; @@ -242,7 +242,7 @@ int z_impl_k_msgq_get(struct k_msgq *msgq, void *data, k_timeout_t timeout) /* add thread's message to queue */ __ASSERT_NO_MSG(msgq->write_ptr >= msgq->buffer_start && msgq->write_ptr < msgq->buffer_end); - (void)memcpy(msgq->write_ptr, pending_thread->base.swap_data, + (void)memcpy(msgq->write_ptr, (char *)pending_thread->base.swap_data, msgq->msg_size); msgq->write_ptr += msgq->msg_size; if (msgq->write_ptr == msgq->buffer_end) { @@ -302,7 +302,7 @@ int z_impl_k_msgq_peek(struct k_msgq *msgq, void *data) if (msgq->used_msgs > 0U) { /* take first available message from queue */ - (void)memcpy(data, msgq->read_ptr, msgq->msg_size); + (void)memcpy((char *)data, msgq->read_ptr, msgq->msg_size); result = 0; } else { /* don't wait for a message to become available */ diff --git a/kernel/pipes.c b/kernel/pipes.c index de5c6656165..d91a4d6b7c1 100644 --- a/kernel/pipes.c +++ b/kernel/pipes.c @@ -162,8 +162,8 @@ int k_pipe_cleanup(struct k_pipe *pipe) k_spinlock_key_t key = k_spin_lock(&pipe->lock); - CHECKIF(z_waitq_head(&pipe->wait_q.readers) != NULL || - z_waitq_head(&pipe->wait_q.writers) != NULL) { + CHECKIF((z_waitq_head(&pipe->wait_q.readers) != NULL) || + (z_waitq_head(&pipe->wait_q.writers) != NULL)) { k_spin_unlock(&pipe->lock, key); SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_pipe, cleanup, pipe, -EAGAIN); @@ -308,7 +308,7 @@ static size_t pipe_buffer_list_populate(sys_dlist_t *list, static int pipe_return_code(size_t min_xfer, size_t bytes_remaining, size_t bytes_requested) { - if (bytes_requested - bytes_remaining >= min_xfer) { + if ((bytes_requested - bytes_remaining) >= min_xfer) { /* * At least the minimum number of requested * bytes have been transferred. @@ -394,7 +394,7 @@ int z_impl_k_pipe_put(struct k_pipe *pipe, const void *data, SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_pipe, put, pipe, timeout); - CHECKIF((min_xfer > bytes_to_write) || bytes_written == NULL) { + CHECKIF((min_xfer > bytes_to_write) || (bytes_written == NULL)) { SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_pipe, put, pipe, timeout, -EINVAL); @@ -519,9 +519,9 @@ int z_vrfy_k_pipe_put(struct k_pipe *pipe, const void *data, { 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)); + K_OOPS(K_SYSCALL_MEMORY_READ(data, bytes_to_write)); - return z_impl_k_pipe_put((struct k_pipe *)pipe, data, + return z_impl_k_pipe_put(pipe, data, bytes_to_write, bytes_written, min_xfer, timeout); } @@ -704,7 +704,7 @@ int z_impl_k_pipe_get(struct k_pipe *pipe, void *data, size_t bytes_to_read, SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_pipe, get, pipe, timeout); - CHECKIF((min_xfer > bytes_to_read) || bytes_read == NULL) { + CHECKIF((min_xfer > bytes_to_read) || (bytes_read == NULL)) { SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_pipe, get, pipe, timeout, -EINVAL); @@ -727,9 +727,9 @@ int z_vrfy_k_pipe_get(struct k_pipe *pipe, void *data, size_t 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)); + K_OOPS(K_SYSCALL_MEMORY_WRITE(data, bytes_to_read)); - return z_impl_k_pipe_get((struct k_pipe *)pipe, (void *)data, + return z_impl_k_pipe_get(pipe, data, bytes_to_read, bytes_read, min_xfer, timeout); } @@ -742,7 +742,7 @@ size_t z_impl_k_pipe_read_avail(struct k_pipe *pipe) k_spinlock_key_t key; /* Buffer and size are fixed. No need to spin. */ - if (pipe->buffer == NULL || pipe->size == 0U) { + if ((pipe->buffer == NULL) || (pipe->size == 0U)) { res = 0; goto out; } @@ -779,7 +779,7 @@ size_t z_impl_k_pipe_write_avail(struct k_pipe *pipe) k_spinlock_key_t key; /* Buffer and size are fixed. No need to spin. */ - if (pipe->buffer == NULL || pipe->size == 0U) { + if ((pipe->buffer == NULL) || (pipe->size == 0U)) { res = 0; goto out; } diff --git a/kernel/priority_queues.c b/kernel/priority_queues.c index 692abfa7c6c..68752c3ab54 100644 --- a/kernel/priority_queues.c +++ b/kernel/priority_queues.c @@ -7,26 +7,7 @@ #include #include #include - -void z_priq_dumb_remove(sys_dlist_t *pq, struct k_thread *thread) -{ - ARG_UNUSED(pq); - - __ASSERT_NO_MSG(!z_is_idle_thread_object(thread)); - - sys_dlist_remove(&thread->base.qnode_dlist); -} - -struct k_thread *z_priq_dumb_best(sys_dlist_t *pq) -{ - struct k_thread *thread = NULL; - sys_dnode_t *n = sys_dlist_peek_head(pq); - - if (n != NULL) { - thread = CONTAINER_OF(n, struct k_thread, base.qnode_dlist); - } - return thread; -} +#include bool z_priq_rb_lessthan(struct rbnode *a, struct rbnode *b) { @@ -47,73 +28,3 @@ bool z_priq_rb_lessthan(struct rbnode *a, struct rbnode *b) ? 1 : 0; } } - -void z_priq_rb_add(struct _priq_rb *pq, struct k_thread *thread) -{ - struct k_thread *t; - - __ASSERT_NO_MSG(!z_is_idle_thread_object(thread)); - - thread->base.order_key = pq->next_order_key++; - - /* Renumber at wraparound. This is tiny code, and in practice - * will almost never be hit on real systems. BUT on very - * long-running systems where a priq never completely empties - * AND that contains very large numbers of threads, it can be - * a latency glitch to loop over all the threads like this. - */ - if (!pq->next_order_key) { - RB_FOR_EACH_CONTAINER(&pq->tree, t, base.qnode_rb) { - t->base.order_key = pq->next_order_key++; - } - } - - rb_insert(&pq->tree, &thread->base.qnode_rb); -} - -void z_priq_rb_remove(struct _priq_rb *pq, struct k_thread *thread) -{ - __ASSERT_NO_MSG(!z_is_idle_thread_object(thread)); - - rb_remove(&pq->tree, &thread->base.qnode_rb); - - if (!pq->tree.root) { - pq->next_order_key = 0; - } -} - -struct k_thread *z_priq_rb_best(struct _priq_rb *pq) -{ - struct k_thread *thread = NULL; - struct rbnode *n = rb_get_min(&pq->tree); - - if (n != NULL) { - thread = CONTAINER_OF(n, struct k_thread, base.qnode_rb); - } - return thread; -} - -struct k_thread *z_priq_mq_best(struct _priq_mq *pq) -{ - struct k_thread *thread = NULL; - - for (int i = 0; i < PRIQ_BITMAP_SIZE; ++i) { - if (!pq->bitmask[i]) { - continue; - } - -#ifdef CONFIG_64BIT - sys_dlist_t *l = &pq->queues[i * 64 + u64_count_trailing_zeros(pq->bitmask[i])]; -#else - sys_dlist_t *l = &pq->queues[i * 32 + u32_count_trailing_zeros(pq->bitmask[i])]; -#endif - sys_dnode_t *n = sys_dlist_peek_head(l); - - if (n != NULL) { - thread = CONTAINER_OF(n, struct k_thread, base.qnode_dlist); - break; - } - } - - return thread; -} diff --git a/kernel/queue.c b/kernel/queue.c index b99bfb0174a..fcccde56f93 100644 --- a/kernel/queue.c +++ b/kernel/queue.c @@ -249,7 +249,7 @@ int k_queue_append_list(struct k_queue *queue, void *head, void *tail) SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_queue, append_list, queue); /* invalid head or tail of list */ - CHECKIF(head == NULL || tail == NULL) { + CHECKIF((head == NULL) || (tail == NULL)) { SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_queue, append_list, queue, -EINVAL); return -EINVAL; diff --git a/kernel/sched.c b/kernel/sched.c index 10bc50cfeaa..bb9676b1832 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -30,6 +30,11 @@ extern struct k_thread *pending_current; struct k_spinlock _sched_spinlock; +/* Storage to "complete" the context switch from an invalid/incomplete thread + * context (ex: exiting an ISR that aborted _current) + */ +__incoherent struct k_thread _thread_dummy; + static void update_cache(int preempt_ok); 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); @@ -82,43 +87,6 @@ int32_t z_sched_prio_cmp(struct k_thread *thread_1, return 0; } -#ifdef CONFIG_SCHED_CPU_MASK -static ALWAYS_INLINE struct k_thread *_priq_dumb_mask_best(sys_dlist_t *pq) -{ - /* With masks enabled we need to be prepared to walk the list - * looking for one we can run - */ - struct k_thread *thread; - - SYS_DLIST_FOR_EACH_CONTAINER(pq, thread, base.qnode_dlist) { - if ((thread->base.cpu_mask & BIT(_current_cpu->id)) != 0) { - return thread; - } - } - return NULL; -} -#endif /* CONFIG_SCHED_CPU_MASK */ - -#if defined(CONFIG_SCHED_DUMB) || defined(CONFIG_WAITQ_DUMB) -static ALWAYS_INLINE void z_priq_dumb_add(sys_dlist_t *pq, - struct k_thread *thread) -{ - struct k_thread *t; - - __ASSERT_NO_MSG(!z_is_idle_thread_object(thread)); - - SYS_DLIST_FOR_EACH_CONTAINER(pq, t, base.qnode_dlist) { - if (z_sched_prio_cmp(thread, t) > 0) { - sys_dlist_insert(&t->base.qnode_dlist, - &thread->base.qnode_dlist); - return; - } - } - - sys_dlist_append(pq, &thread->base.qnode_dlist); -} -#endif /* CONFIG_SCHED_DUMB || CONFIG_WAITQ_DUMB */ - static ALWAYS_INLINE void *thread_runq(struct k_thread *thread) { #ifdef CONFIG_SCHED_CPU_MASK_PIN_ONLY @@ -150,11 +118,15 @@ static ALWAYS_INLINE void *curr_cpu_runq(void) static ALWAYS_INLINE void runq_add(struct k_thread *thread) { + __ASSERT_NO_MSG(!z_is_idle_thread_object(thread)); + _priq_run_add(thread_runq(thread), thread); } static ALWAYS_INLINE void runq_remove(struct k_thread *thread) { + __ASSERT_NO_MSG(!z_is_idle_thread_object(thread)); + _priq_run_remove(thread_runq(thread), thread); } @@ -168,7 +140,7 @@ static ALWAYS_INLINE struct k_thread *runq_best(void) */ static inline bool should_queue_thread(struct k_thread *thread) { - return !IS_ENABLED(CONFIG_SMP) || thread != _current; + return !IS_ENABLED(CONFIG_SMP) || (thread != _current); } static ALWAYS_INLINE void queue_thread(struct k_thread *thread) @@ -193,7 +165,6 @@ static ALWAYS_INLINE void dequeue_thread(struct k_thread *thread) } } -#ifdef CONFIG_SMP /* Called out of z_swap() when CONFIG_SMP. The current thread can * never live in the run queue until we are inexorably on the context * switch path on SMP, otherwise there is a deadlock condition where a @@ -220,11 +191,11 @@ static inline bool is_halting(struct k_thread *thread) return (thread->base.thread_state & (_THREAD_ABORTING | _THREAD_SUSPENDING)) != 0U; } -#endif /* CONFIG_SMP */ /* Clear the halting bits (_THREAD_ABORTING and _THREAD_SUSPENDING) */ static inline void clear_halting(struct k_thread *thread) { + barrier_dmem_fence_full(); /* Other cpus spin on this locklessly! */ thread->base.thread_state &= ~(_THREAD_ABORTING | _THREAD_SUSPENDING); } @@ -301,7 +272,7 @@ static ALWAYS_INLINE struct k_thread *next_up(void) } /* Put _current back into the queue */ - if (thread != _current && active && + if ((thread != _current) && active && !z_is_idle_thread_object(_current) && !queued) { queue_thread(_current); } @@ -454,84 +425,75 @@ 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 +/* Spins in ISR context, waiting for a thread known to be running on + * another CPU to catch the IPI we sent and halt. Note that we check + * for ourselves being asynchronously halted first to prevent simple + * deadlocks (but not complex ones involving cycles of 3+ threads!). + * Acts to release the provided lock before returning. */ -static void z_thread_halt(struct k_thread *thread, k_spinlock_key_t key, - bool terminate) +static void thread_halt_spin(struct k_thread *thread, k_spinlock_key_t key) { -#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. - */ + if (is_halting(_current)) { halt_thread(_current, - is_aborting(_current) ? _THREAD_DEAD - : _THREAD_SUSPENDED); + is_aborting(_current) ? _THREAD_DEAD : _THREAD_SUSPENDED); } + k_spin_unlock(&_sched_spinlock, key); + while (is_halting(thread)) { + unsigned int k = arch_irq_lock(); - bool active = thread_active_elsewhere(thread); + arch_spin_relax(); /* Requires interrupts be masked */ + arch_irq_unlock(k); + } +} - if (active) { - /* It's running somewhere else, flag and poke */ - thread->base.thread_state |= (terminate ? _THREAD_ABORTING - : _THREAD_SUSPENDING); +/* Shared handler for k_thread_{suspend,abort}(). Called with the + * scheduler lock held and the key passed (which it may + * release/reacquire!) which will be released before a possible return + * (aborting _current will not return, obviously), which may be after + * a context switch. + */ +static void z_thread_halt(struct k_thread *thread, k_spinlock_key_t key, + bool terminate) +{ + _wait_q_t *wq = &thread->join_queue; +#ifdef CONFIG_SMP + wq = terminate ? wq : &thread->halt_queue; +#endif - /* We might spin to wait, so a true synchronous IPI is needed - * here, not deferred! - */ -#ifdef CONFIG_SCHED_IPI_SUPPORTED + /* If the target is a thread running on another CPU, flag and + * poke (note that we might spin to wait, so a true + * synchronous IPI is needed here, not deferred!), it will + * halt itself in the IPI. Otherwise it's unscheduled, so we + * can clean it up directly. + */ + if (thread_active_elsewhere(thread)) { + thread->base.thread_state |= (terminate ? _THREAD_ABORTING + : _THREAD_SUSPENDING); +#if defined(CONFIG_SMP) && defined(CONFIG_SCHED_IPI_SUPPORTED) arch_sched_ipi(); -#endif /* CONFIG_SCHED_IPI_SUPPORTED */ - } - - if (is_halting(thread) && (thread != _current)) { +#endif 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); + thread_halt_spin(thread, key); + } else { + add_to_waitq_locked(_current, wq); z_swap(&_sched_spinlock, key); } - return; /* lock has been released */ - } -#endif /* CONFIG_SMP */ - 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); + 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); + } } + /* NOTE: the scheduler lock has been released. Don't put + * logic here, it's likely to be racy/deadlocky even if you + * re-take the lock! + */ } + void z_impl_k_thread_suspend(struct k_thread *thread) { SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_thread, suspend, thread); @@ -616,7 +578,7 @@ static void add_to_waitq_locked(struct k_thread *thread, _wait_q_t *wait_q) if (wait_q != NULL) { thread->base.pended_on = wait_q; - z_priq_wait_add(&wait_q->waitq, thread); + _priq_wait_add(&wait_q->waitq, thread); } } @@ -947,6 +909,7 @@ void *z_get_next_switch_handle(void *interrupted) arch_cohere_stacks(old_thread, interrupted, new_thread); _current_cpu->swap_ok = 0; + new_thread->base.cpu = arch_curr_cpu()->id; set_current(new_thread); #ifdef CONFIG_TIMESLICING @@ -1044,7 +1007,7 @@ void z_impl_k_thread_priority_set(k_tid_t thread, int prio) bool need_sched = z_thread_prio_set((struct k_thread *)thread, prio); flag_ipi(); - if (need_sched && _current->base.sched_locked == 0U) { + if (need_sched && (_current->base.sched_locked == 0U)) { z_reschedule_unlocked(); } } @@ -1328,12 +1291,13 @@ extern void thread_abort_hook(struct k_thread *thread); */ static void halt_thread(struct k_thread *thread, uint8_t new_state) { + bool dummify = false; + /* We hold the lock, and the thread is known not to be running * anywhere. */ 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); } @@ -1344,6 +1308,16 @@ static void halt_thread(struct k_thread *thread, uint8_t new_state) } (void)z_abort_thread_timeout(thread); unpend_all(&thread->join_queue); + + /* Edge case: aborting _current from within an + * ISR that preempted it requires clearing the + * _current pointer so the upcoming context + * switch doesn't clobber the now-freed + * memory + */ + if (thread == _current && arch_is_in_isr()) { + dummify = true; + } } #ifdef CONFIG_SMP unpend_all(&thread->halt_queue); @@ -1351,6 +1325,7 @@ static void halt_thread(struct k_thread *thread, uint8_t new_state) update_cache(1); if (new_state == _THREAD_SUSPENDED) { + clear_halting(thread); return; } @@ -1382,6 +1357,29 @@ static void halt_thread(struct k_thread *thread, uint8_t new_state) #ifdef CONFIG_THREAD_ABORT_NEED_CLEANUP k_thread_abort_cleanup(thread); #endif /* CONFIG_THREAD_ABORT_NEED_CLEANUP */ + + /* Do this "set _current to dummy" step last so that + * subsystems above can rely on _current being + * unchanged. Disabled for posix as that arch + * continues to use the _current pointer in its swap + * code. Note that we must leave a non-null switch + * handle for any threads spinning in join() (this can + * never be used, as our thread is flagged dead, but + * it must not be NULL otherwise join can deadlock). + */ + if (dummify && !IS_ENABLED(CONFIG_ARCH_POSIX)) { +#ifdef CONFIG_USE_SWITCH + _current->switch_handle = _current; +#endif + z_dummy_thread_init(&_thread_dummy); + + } + + /* Finally update the halting thread state, on which + * other CPUs might be spinning (see + * thread_halt_spin()). + */ + clear_halting(thread); } } @@ -1411,6 +1409,8 @@ void z_impl_k_thread_abort(struct k_thread *thread) z_thread_abort(thread); + __ASSERT_NO_MSG((thread->base.thread_state & _THREAD_DEAD) != 0); + SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_thread, abort, thread); } #endif /* !CONFIG_ARCH_HAS_THREAD_ABORT */ @@ -1418,7 +1418,7 @@ void z_impl_k_thread_abort(struct k_thread *thread) int z_impl_k_thread_join(struct k_thread *thread, k_timeout_t timeout) { k_spinlock_key_t key = k_spin_lock(&_sched_spinlock); - int ret = 0; + int ret; SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_thread, join, thread, timeout); diff --git a/kernel/sem.c b/kernel/sem.c index 819abd3879c..0a8b861cfbe 100644 --- a/kernel/sem.c +++ b/kernel/sem.c @@ -48,7 +48,7 @@ int z_impl_k_sem_init(struct k_sem *sem, unsigned int initial_count, /* * Limit cannot be zero and count cannot be greater than limit */ - CHECKIF(limit == 0U || limit > K_SEM_MAX_LIMIT || initial_count > limit) { + CHECKIF(limit == 0U || initial_count > limit) { SYS_PORT_TRACING_OBJ_FUNC(k_sem, init, sem, -EINVAL); return -EINVAL; @@ -131,7 +131,7 @@ static inline void z_vrfy_k_sem_give(struct k_sem *sem) int z_impl_k_sem_take(struct k_sem *sem, k_timeout_t timeout) { - int ret = 0; + int ret; __ASSERT(((arch_is_in_isr() == false) || K_TIMEOUT_EQ(timeout, K_NO_WAIT)), ""); @@ -189,7 +189,7 @@ void z_impl_k_sem_reset(struct k_sem *sem) static inline int z_vrfy_k_sem_take(struct k_sem *sem, k_timeout_t timeout) { K_OOPS(K_SYSCALL_OBJ(sem, K_OBJ_SEM)); - return z_impl_k_sem_take((struct k_sem *)sem, timeout); + return z_impl_k_sem_take(sem, timeout); } #include diff --git a/kernel/smp.c b/kernel/smp.c index 6e6cad2688f..a5659525278 100644 --- a/kernel/smp.c +++ b/kernel/smp.c @@ -60,6 +60,7 @@ unsigned int z_smp_global_lock(void) if (!_current->base.global_lock_count) { while (!atomic_cas(&global_lock, 0, 1)) { + arch_spin_relax(); } } @@ -74,7 +75,7 @@ void z_smp_global_unlock(unsigned int key) _current->base.global_lock_count--; if (!_current->base.global_lock_count) { - atomic_clear(&global_lock); + (void)atomic_clear(&global_lock); } } @@ -85,7 +86,7 @@ void z_smp_global_unlock(unsigned int key) void z_smp_release_global_lock(struct k_thread *thread) { if (!thread->base.global_lock_count) { - atomic_clear(&global_lock); + (void)atomic_clear(&global_lock); } } @@ -108,7 +109,6 @@ static void wait_for_start_signal(atomic_t *start_flag) static inline void smp_init_top(void *arg) { - struct k_thread dummy_thread; struct cpu_start_cb csc = arg ? *(struct cpu_start_cb *)arg : (struct cpu_start_cb){0}; /* Let start_cpu() know that this CPU has powered up. */ @@ -123,7 +123,7 @@ static inline void smp_init_top(void *arg) /* Initialize the dummy thread struct so that * the scheduler can schedule actual threads to run. */ - z_dummy_thread_init(&dummy_thread); + z_dummy_thread_init(&_thread_dummy); } #ifdef CONFIG_SYS_CLOCK_EXISTS diff --git a/kernel/spinlock_validate.c b/kernel/spinlock_validate.c index 90da6fac1b6..cb7ff5a3e7f 100644 --- a/kernel/spinlock_validate.c +++ b/kernel/spinlock_validate.c @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include +#include #include bool z_spin_lock_valid(struct k_spinlock *l) @@ -20,10 +20,17 @@ bool z_spin_lock_valid(struct k_spinlock *l) bool z_spin_unlock_valid(struct k_spinlock *l) { - if (l->thread_cpu != (_current_cpu->id | (uintptr_t)_current)) { + uintptr_t tcpu = l->thread_cpu; + + l->thread_cpu = 0; + + if (arch_is_in_isr() && _current->base.thread_state & _THREAD_DUMMY) { + /* Edge case where an ISR aborted _current */ + return true; + } + if (tcpu != (_current_cpu->id | (uintptr_t)_current)) { return false; } - l->thread_cpu = 0; return true; } diff --git a/kernel/stack.c b/kernel/stack.c index 822abfca363..5ddc4178f89 100644 --- a/kernel/stack.c +++ b/kernel/stack.c @@ -8,6 +8,7 @@ * @brief fixed-size stack object */ +#include #include #include @@ -50,7 +51,7 @@ int32_t z_impl_k_stack_alloc_init(struct k_stack *stack, uint32_t num_entries) if (buffer != NULL) { k_stack_init(stack, buffer, num_entries); stack->flags = K_STACK_FLAG_ALLOC; - ret = (int32_t)0; + ret = 0; } else { ret = -ENOMEM; } @@ -64,8 +65,12 @@ 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) { + size_t total_size; + K_OOPS(K_SYSCALL_OBJ_NEVER_INIT(stack, K_OBJ_STACK)); K_OOPS(K_SYSCALL_VERIFY(num_entries > 0)); + K_OOPS(K_SYSCALL_VERIFY(!size_mul_overflow(num_entries, sizeof(stack_data_t), + &total_size))); return z_impl_k_stack_alloc_init(stack, num_entries); } #include diff --git a/kernel/system_work_q.c b/kernel/system_work_q.c index 02b1c4c2d22..5cc26fd82e1 100644 --- a/kernel/system_work_q.c +++ b/kernel/system_work_q.c @@ -24,6 +24,7 @@ static int k_sys_work_q_init(void) struct k_work_queue_config cfg = { .name = "sysworkq", .no_yield = IS_ENABLED(CONFIG_SYSTEM_WORKQUEUE_NO_YIELD), + .essential = true, }; k_work_queue_start(&k_sys_work_q, diff --git a/kernel/thread.c b/kernel/thread.c index 981a048bb0d..3b197743b09 100644 --- a/kernel/thread.c +++ b/kernel/thread.c @@ -174,7 +174,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 (k_usermode_string_copy(name, (char *)str, sizeof(name)) != 0) { + if (k_usermode_string_copy(name, str, sizeof(name)) != 0) { return -EFAULT; } @@ -284,15 +284,15 @@ static inline int z_vrfy_k_thread_name_copy(k_tid_t thread, /* Special case: we allow reading the names of initialized threads * even if we don't have permission on them */ - if (thread == NULL || ko->type != K_OBJ_THREAD || - (ko->flags & K_OBJ_FLAG_INITIALIZED) == 0) { + if ((thread == NULL) || (ko->type != K_OBJ_THREAD) || + ((ko->flags & K_OBJ_FLAG_INITIALIZED) == 0)) { return -EINVAL; } if (K_SYSCALL_MEMORY_WRITE(buf, size) != 0) { return -EFAULT; } len = strlen(thread->name); - if (len + 1 > size) { + if ((len + 1) > size) { return -ENOSPC; } @@ -356,7 +356,7 @@ static inline void z_vrfy_k_thread_start(struct k_thread *thread) #include #endif /* CONFIG_USERSPACE */ -#if CONFIG_STACK_POINTER_RANDOM +#if defined(CONFIG_STACK_POINTER_RANDOM) && (CONFIG_STACK_POINTER_RANDOM != 0) int z_stack_adjust_initialized; static size_t random_offset(size_t stack_size) @@ -487,7 +487,7 @@ static char *setup_thread_stack(struct k_thread *new_thread, new_thread->userspace_local_data = (struct _thread_userspace_local_data *)(stack_ptr - delta); #endif /* CONFIG_THREAD_USERSPACE_LOCAL_DATA */ -#if CONFIG_STACK_POINTER_RANDOM +#if defined(CONFIG_STACK_POINTER_RANDOM) && (CONFIG_STACK_POINTER_RANDOM != 0) delta += random_offset(stack_buf_size); #endif /* CONFIG_STACK_POINTER_RANDOM */ delta = ROUND_UP(delta, ARCH_STACK_PTR_ALIGN); diff --git a/kernel/timeout.c b/kernel/timeout.c index 8c727e204f9..cf4a6d681d5 100644 --- a/kernel/timeout.c +++ b/kernel/timeout.c @@ -40,14 +40,14 @@ static struct _timeout *first(void) { sys_dnode_t *t = sys_dlist_peek_head(&timeout_list); - return t == NULL ? NULL : CONTAINER_OF(t, struct _timeout, node); + return (t == NULL) ? NULL : CONTAINER_OF(t, struct _timeout, node); } static struct _timeout *next(struct _timeout *t) { sys_dnode_t *n = sys_dlist_peek_next(&timeout_list, &t->node); - return n == NULL ? NULL : CONTAINER_OF(n, struct _timeout, node); + return (n == NULL) ? NULL : CONTAINER_OF(n, struct _timeout, node); } static void remove_timeout(struct _timeout *t) @@ -114,7 +114,7 @@ void z_add_timeout(struct _timeout *to, _timeout_func_t fn, struct _timeout *t; if (IS_ENABLED(CONFIG_TIMEOUT_64BIT) && - Z_TICK_ABS(timeout.ticks) >= 0) { + (Z_TICK_ABS(timeout.ticks) >= 0)) { k_ticks_t ticks = Z_TICK_ABS(timeout.ticks) - curr_tick; to->dticks = MAX(1, ticks); diff --git a/kernel/timeslicing.c b/kernel/timeslicing.c index 401bcea0c7c..07ae497c7f9 100644 --- a/kernel/timeslicing.c +++ b/kernel/timeslicing.c @@ -95,6 +95,7 @@ void k_thread_time_slice_set(struct k_thread *thread, int32_t thread_slice_ticks thread->base.slice_ticks = thread_slice_ticks; thread->base.slice_expired = expired; thread->base.slice_data = data; + z_reset_time_slice(thread); } } #endif diff --git a/kernel/usage.c b/kernel/usage.c index 7ec5e30c8d2..ad40e3ffd48 100644 --- a/kernel/usage.c +++ b/kernel/usage.c @@ -220,7 +220,6 @@ void z_sched_thread_usage(struct k_thread *thread, #ifdef CONFIG_SCHED_THREAD_USAGE_ALL stats->idle_cycles = 0; #endif /* CONFIG_SCHED_THREAD_USAGE_ALL */ - stats->execution_cycles = thread->base.usage.total; k_spin_unlock(&usage_lock, key); } diff --git a/kernel/userspace.c b/kernel/userspace.c index 0d9a437570a..664971e2727 100644 --- a/kernel/userspace.c +++ b/kernel/userspace.c @@ -221,7 +221,7 @@ static size_t obj_align_get(enum k_objects otype) return ret; } -static struct dyn_obj *dyn_object_find(void *obj) +static struct dyn_obj *dyn_object_find(const void *obj) { struct dyn_obj *node; k_spinlock_key_t key; @@ -277,8 +277,10 @@ static bool thread_idx_alloc(uintptr_t *tidx) if (idx != 0) { *tidx = base + (idx - 1); - sys_bitfield_clear_bit((mem_addr_t)_thread_idx_map, - *tidx); + /* Clear the bit. We already know the array index, + * and the bit to be cleared. + */ + _thread_idx_map[i] &= ~(BIT(idx - 1)); /* Clear permission from all objects */ k_object_wordlist_foreach(clear_perms_cb, @@ -308,7 +310,11 @@ static void thread_idx_free(uintptr_t tidx) /* To prevent leaked permission when index is recycled */ k_object_wordlist_foreach(clear_perms_cb, (void *)tidx); - sys_bitfield_set_bit((mem_addr_t)_thread_idx_map, tidx); + /* Figure out which bits to set in _thread_idx_map[] and set it. */ + int base = tidx / NUM_BITS(_thread_idx_map[0]); + int offset = tidx % NUM_BITS(_thread_idx_map[0]); + + _thread_idx_map[base] |= BIT(offset); } static struct k_object *dynamic_object_create(enum k_objects otype, size_t align, @@ -391,7 +397,7 @@ static void *z_object_alloc(enum k_objects otype, size_t size) struct k_object *zo; uintptr_t tidx = 0; - if (otype <= K_OBJ_ANY || otype >= K_OBJ_LAST) { + if ((otype <= K_OBJ_ANY) || (otype >= K_OBJ_LAST)) { LOG_ERR("bad object type %d requested", otype); return NULL; } @@ -490,7 +496,7 @@ struct k_object *k_object_find(const void *obj) * 11.8 but is justified since we know dynamic objects * were not declared with a const qualifier. */ - dyn = dyn_object_find((void *)obj); + dyn = dyn_object_find(obj); if (dyn != NULL) { ret = &dyn->kobj; } @@ -586,7 +592,7 @@ static void wordlist_cb(struct k_object *ko, void *ctx_ptr) struct perm_ctx *ctx = (struct perm_ctx *)ctx_ptr; if (sys_bitfield_test_bit((mem_addr_t)&ko->perms, ctx->parent_id) && - (struct k_thread *)ko->name != ctx->parent) { + ((struct k_thread *)ko->name != ctx->parent)) { sys_bitfield_set_bit((mem_addr_t)&ko->perms, ctx->child_id); } } @@ -727,7 +733,7 @@ int k_object_validate(struct k_object *ko, enum k_objects otype, enum _obj_init_check init) { if (unlikely((ko == NULL) || - (otype != K_OBJ_ANY && ko->type != otype))) { + ((otype != K_OBJ_ANY) && (ko->type != otype)))) { return -EBADF; } @@ -929,8 +935,8 @@ static int app_shmem_bss_zero(void) struct z_app_region *region, *end; - end = (struct z_app_region *)&__app_shmem_regions_end; - region = (struct z_app_region *)&__app_shmem_regions_start; + end = (struct z_app_region *)&__app_shmem_regions_end[0]; + region = (struct z_app_region *)&__app_shmem_regions_start[0]; for ( ; region < end; region++) { #if defined(CONFIG_DEMAND_PAGING) && !defined(CONFIG_LINKER_GENERIC_SECTIONS_PRESENT_AT_BOOT) @@ -981,6 +987,12 @@ static uintptr_t handler_bad_syscall(uintptr_t bad_id, uintptr_t arg2, uintptr_t arg5, uintptr_t arg6, void *ssf) { + ARG_UNUSED(arg2); + ARG_UNUSED(arg3); + ARG_UNUSED(arg4); + ARG_UNUSED(arg5); + ARG_UNUSED(arg6); + LOG_ERR("Bad system call id %" PRIuPTR " invoked", bad_id); arch_syscall_oops(ssf); CODE_UNREACHABLE; /* LCOV_EXCL_LINE */ @@ -990,6 +1002,13 @@ static uintptr_t handler_no_syscall(uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4, uintptr_t arg5, uintptr_t arg6, void *ssf) { + ARG_UNUSED(arg1); + ARG_UNUSED(arg2); + ARG_UNUSED(arg3); + ARG_UNUSED(arg4); + ARG_UNUSED(arg5); + ARG_UNUSED(arg6); + LOG_ERR("Unimplemented system call"); arch_syscall_oops(ssf); CODE_UNREACHABLE; /* LCOV_EXCL_LINE */ diff --git a/kernel/userspace_handler.c b/kernel/userspace_handler.c index a26c50828d7..da4053b4bdb 100644 --- a/kernel/userspace_handler.c +++ b/kernel/userspace_handler.c @@ -70,9 +70,8 @@ static inline void z_vrfy_k_object_release(const void *object) { struct k_object *ko; - ko = validate_any_object((void *)object); - K_OOPS(K_SYSCALL_VERIFY_MSG(ko != NULL, "object %p access denied", - (void *)object)); + ko = validate_any_object(object); + K_OOPS(K_SYSCALL_VERIFY_MSG(ko != NULL, "object %p access denied", object)); k_thread_perms_clear(ko, _current); } #include diff --git a/kernel/work.c b/kernel/work.c index cf73bdbcabe..994d6d74e80 100644 --- a/kernel/work.c +++ b/kernel/work.c @@ -271,7 +271,7 @@ static inline int queue_submit_locked(struct k_work_q *queue, return -EINVAL; } - int ret = -EBUSY; + int ret; bool chained = (_current == &queue->thread) && !k_is_in_isr(); bool draining = flag_test(&queue->flags, K_WORK_QUEUE_DRAIN_BIT); bool plugged = flag_test(&queue->flags, K_WORK_QUEUE_PLUGGED_BIT); @@ -761,6 +761,10 @@ void k_work_queue_start(struct k_work_q *queue, k_thread_name_set(&queue->thread, cfg->name); } + if ((cfg != NULL) && (cfg->essential)) { + queue->thread.base.user_options |= K_ESSENTIAL; + } + k_thread_start(&queue->thread); SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_work_queue, start, queue); @@ -1014,7 +1018,7 @@ int k_work_reschedule_for_queue(struct k_work_q *queue, SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_work, reschedule_for_queue, queue, dwork, delay); - int ret = 0; + int ret; k_spinlock_key_t key = k_spin_lock(&lock); /* Remove any active scheduling. */ diff --git a/lib/libc/Kconfig b/lib/libc/Kconfig index 8b71808ff54..1dcc3dc729a 100644 --- a/lib/libc/Kconfig +++ b/lib/libc/Kconfig @@ -43,7 +43,6 @@ config NEWLIB_LIBC_SUPPORTED config PICOLIBC_SUPPORTED bool depends on !NATIVE_APPLICATION - depends on ("$(TOOLCHAIN_HAS_PICOLIBC)" = "y") || (NATIVE_LIBRARY) depends on !REQUIRES_FULL_LIBCPP || ("$(TOOLCHAIN_HAS_PICOLIBC)" = "y") default y select FULL_LIBC_SUPPORTED @@ -57,11 +56,17 @@ config SUPPORT_MINIMAL_LIBC help Legacy symbol that selects MINIMAL_LIBC_SUPPORTED +config NATIVE_LIBC_INCOMPATIBLE + bool + help + Other Kconfig options can select this, if they are not compatible with the + native/host libC, and should only be compiled with an embedded libC + menu "C Library" choice LIBC_IMPLEMENTATION prompt "C Library Implementation" - default EXTERNAL_LIBC if NATIVE_BUILD && !(NATIVE_LIBRARY && POSIX_API) + default EXTERNAL_LIBC if NATIVE_BUILD && !(NATIVE_LIBRARY && NATIVE_LIBC_INCOMPATIBLE) default PICOLIBC default NEWLIB_LIBC if REQUIRES_FULL_LIBC default MINIMAL_LIBC diff --git a/lib/libc/common/source/stdlib/abort.c b/lib/libc/common/source/stdlib/abort.c index 49d18e8ae67..3b17be4a638 100644 --- a/lib/libc/common/source/stdlib/abort.c +++ b/lib/libc/common/source/stdlib/abort.c @@ -7,7 +7,7 @@ #include #include -void abort(void) +FUNC_NORETURN void abort(void) { printk("abort()\n"); k_panic(); diff --git a/lib/libc/minimal/include/stdint.h b/lib/libc/minimal/include/stdint.h index 904f0b49b25..80a2ff1ab29 100644 --- a/lib/libc/minimal/include/stdint.h +++ b/lib/libc/minimal/include/stdint.h @@ -104,7 +104,7 @@ typedef __UINT_LEAST64_TYPE__ uint_least64_t; typedef __INTPTR_TYPE__ intptr_t; typedef __UINTPTR_TYPE__ uintptr_t; -#ifdef __GNUC__ +#if defined(__GNUC__) || defined(__clang__) /* These macros must produce constant integer expressions, which can't * be done in the preprocessor (casts aren't allowed). Defer to the * GCC internal functions where they're available. @@ -120,7 +120,7 @@ typedef __UINTPTR_TYPE__ uintptr_t; #define UINT32_C(_v) __UINT32_C(_v) #define UINT64_C(_v) __UINT64_C(_v) #define UINTMAX_C(_v) __UINTMAX_C(_v) -#endif /* __GNUC__ */ +#endif /* defined(__GNUC__) || defined(__clang__) */ #ifdef __CCAC__ #ifndef __INT8_C diff --git a/lib/libc/minimal/include/stdlib.h b/lib/libc/minimal/include/stdlib.h index c60f9c17825..a62a4a1e4d6 100644 --- a/lib/libc/minimal/include/stdlib.h +++ b/lib/libc/minimal/include/stdlib.h @@ -12,6 +12,8 @@ #include #include +#include + #ifdef __cplusplus extern "C" { #endif @@ -41,12 +43,12 @@ void qsort(void *base, size_t nmemb, size_t size, #define EXIT_SUCCESS 0 #define EXIT_FAILURE 1 -void _exit(int status); -static inline void exit(int status) +FUNC_NORETURN void _exit(int status); +FUNC_NORETURN static inline void exit(int status) { _exit(status); } -void abort(void); +FUNC_NORETURN void abort(void); #ifdef CONFIG_MINIMAL_LIBC_RAND #define RAND_MAX INT_MAX diff --git a/lib/libc/minimal/source/stdlib/exit.c b/lib/libc/minimal/source/stdlib/exit.c index 036132ac1e9..789a2940409 100644 --- a/lib/libc/minimal/source/stdlib/exit.c +++ b/lib/libc/minimal/source/stdlib/exit.c @@ -7,7 +7,7 @@ #include #include -void _exit(int status) +FUNC_NORETURN void _exit(int status) { printk("exit\n"); while (1) { diff --git a/lib/os/fdtable.c b/lib/os/fdtable.c index 757ebf4361f..e02bc2f661f 100644 --- a/lib/os/fdtable.c +++ b/lib/os/fdtable.c @@ -354,6 +354,7 @@ int close(int fd) } FUNC_ALIAS(close, _close, int); +#ifdef CONFIG_POSIX_FSYNC int fsync(int fd) { if (_check_fd(fd) < 0) { @@ -362,6 +363,8 @@ int fsync(int fd) return z_fdtable_call_ioctl(fdtable[fd].vtable, fdtable[fd].obj, ZFD_IOCTL_FSYNC); } +FUNC_ALIAS(fsync, _fsync, int); +#endif /* CONFIG_POSIX_FSYNC */ off_t lseek(int fd, off_t offset, int whence) { diff --git a/lib/os/sem.c b/lib/os/sem.c index b01ead58e50..b7676c929c6 100644 --- a/lib/os/sem.c +++ b/lib/os/sem.c @@ -53,7 +53,7 @@ int sys_sem_init(struct sys_sem *sem, unsigned int initial_count, return -EINVAL; } - atomic_set(&sem->futex.val, initial_count); + (void)atomic_set(&sem->futex.val, initial_count); sem->limit = limit; return 0; diff --git a/lib/posix/options/CMakeLists.txt b/lib/posix/options/CMakeLists.txt index d7f3ef94e59..96995cbeebb 100644 --- a/lib/posix/options/CMakeLists.txt +++ b/lib/posix/options/CMakeLists.txt @@ -36,7 +36,9 @@ zephyr_library() add_subdirectory_ifdef(CONFIG_GETOPT getopt) zephyr_library_sources_ifdef(CONFIG_EVENTFD eventfd.c) zephyr_library_sources_ifdef(CONFIG_FNMATCH fnmatch.c) +zephyr_library_sources_ifdef(CONFIG_GETENTROPY getentropy.c) zephyr_library_sources_ifdef(CONFIG_POSIX_API perror.c) +zephyr_library_sources_ifdef(CONFIG_POSIX_ASYNCHRONOUS_IO aio.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) diff --git a/lib/posix/options/Kconfig b/lib/posix/options/Kconfig index 7b67244d127..2197148bca5 100644 --- a/lib/posix/options/Kconfig +++ b/lib/posix/options/Kconfig @@ -8,6 +8,7 @@ menu "POSIX Options" config POSIX_API depends on !NATIVE_APPLICATION bool "POSIX APIs" + select NATIVE_LIBC_INCOMPATIBLE help Enable mostly-standards-compliant implementations of various POSIX (IEEE 1003.1) APIs. @@ -24,6 +25,7 @@ config PTHREAD_IPC endif # POSIX_CLOCK +rsource "Kconfig.aio" rsource "Kconfig.barrier" rsource "Kconfig.clock" rsource "Kconfig.cond" @@ -33,6 +35,7 @@ rsource "Kconfig.eventfd" rsource "Kconfig.fdtable" rsource "Kconfig.fnmatch" rsource "Kconfig.fs" +rsource "Kconfig.getentropy" rsource "Kconfig.getopt" rsource "Kconfig.key" rsource "Kconfig.mqueue" diff --git a/lib/posix/options/Kconfig.aio b/lib/posix/options/Kconfig.aio new file mode 100644 index 00000000000..6fc35349738 --- /dev/null +++ b/lib/posix/options/Kconfig.aio @@ -0,0 +1,10 @@ +# Copyright (c) 2024 Tenstorrent AI ULC +# +# SPDX-License-Identifier: Apache-2.0 + +config POSIX_ASYNCHRONOUS_IO + bool "Asynchronous IO" + default y if POSIX_API + help + Enable this option for asynchronous I/O. This option is present for conformance purposes + only. All functions listed in return -1 and set errno to ENOSYS. diff --git a/lib/posix/options/Kconfig.fs b/lib/posix/options/Kconfig.fs index e4d5f1dea6e..bff95a906a9 100644 --- a/lib/posix/options/Kconfig.fs +++ b/lib/posix/options/Kconfig.fs @@ -10,10 +10,19 @@ menuconfig POSIX_FS help This enables POSIX style file system related APIs. +if POSIX_FS + config POSIX_MAX_OPEN_FILES int "Maximum number of open file descriptors" default 16 - depends on POSIX_FS help Maximum number of open files. Note that this setting is additionally bounded by CONFIG_POSIX_MAX_FDS. + +config POSIX_FSYNC + bool "Support for fsync()" + default y + help + This enables fsync() support. + +endif # POSIX_FS diff --git a/lib/posix/options/Kconfig.getentropy b/lib/posix/options/Kconfig.getentropy new file mode 100644 index 00000000000..74454135019 --- /dev/null +++ b/lib/posix/options/Kconfig.getentropy @@ -0,0 +1,14 @@ +# Copyright (c) 2024 Google LLC +# +# SPDX-License-Identifier: Apache-2.0 + +DT_CHOSEN_ZEPHYR_ENTROPY := zephyr,entropy + +config GETENTROPY + bool "Support for getentropy" + depends on !NATIVE_APPLICATION + select NATIVE_LIBC_INCOMPATIBLE + depends on ENTROPY_HAS_DRIVER + depends on $(dt_chosen_enabled,$(DT_CHOSEN_ZEPHYR_ENTROPY)) + help + Enable support for getentropy() function. diff --git a/lib/posix/options/Kconfig.uname b/lib/posix/options/Kconfig.uname index 09b52602db1..8b448225249 100644 --- a/lib/posix/options/Kconfig.uname +++ b/lib/posix/options/Kconfig.uname @@ -12,7 +12,7 @@ menuconfig POSIX_UNAME if POSIX_UNAME config POSIX_UNAME_VERSION_LEN int "uname version string length" - default 60 + default 70 help Defines the maximum string length of uname version. diff --git a/lib/posix/options/aio.c b/lib/posix/options/aio.c new file mode 100644 index 00000000000..538333345dd --- /dev/null +++ b/lib/posix/options/aio.c @@ -0,0 +1,82 @@ +/* + * Copyright 2024 Tenstorrent AI ULC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include + +int aio_cancel(int fildes, struct aiocb *aiocbp) +{ + ARG_UNUSED(fildes); + ARG_UNUSED(aiocbp); + + errno = ENOSYS; + return -1; +} + +int aio_error(const struct aiocb *aiocbp) +{ + ARG_UNUSED(aiocbp); + + errno = ENOSYS; + return -1; +} + +int aio_fsync(int fildes, struct aiocb *aiocbp) +{ + ARG_UNUSED(fildes); + ARG_UNUSED(aiocbp); + + errno = ENOSYS; + return -1; +} + +int aio_read(struct aiocb *aiocbp) +{ + ARG_UNUSED(aiocbp); + + errno = ENOSYS; + return -1; +} + +ssize_t aio_return(struct aiocb *aiocbp) +{ + ARG_UNUSED(aiocbp); + + errno = ENOSYS; + return -1; +} + +int aio_suspend(const struct aiocb *const list[], int nent, const struct timespec *timeout) +{ + ARG_UNUSED(list); + ARG_UNUSED(nent); + ARG_UNUSED(timeout); + + errno = ENOSYS; + return -1; +} + +int aio_write(struct aiocb *aiocbp) +{ + ARG_UNUSED(aiocbp); + + errno = ENOSYS; + return -1; +} + +int lio_listio(int mode, struct aiocb *const ZRESTRICT list[], int nent, + struct sigevent *ZRESTRICT sig) +{ + ARG_UNUSED(mode); + ARG_UNUSED(list); + ARG_UNUSED(nent); + ARG_UNUSED(sig); + + errno = ENOSYS; + return -1; +} diff --git a/lib/posix/options/eventfd.c b/lib/posix/options/eventfd.c index 767cf5a60cc..81b8f6d6dd8 100644 --- a/lib/posix/options/eventfd.c +++ b/lib/posix/options/eventfd.c @@ -247,7 +247,9 @@ static int eventfd_ioctl_op(void *obj, unsigned int request, va_list args) errno = EINVAL; ret = -1; } else { - efd->flags = flags; + int prev_flags = efd->flags & ~EFD_FLAGS_SET_INTERNAL; + + efd->flags = flags | prev_flags; ret = 0; } } break; diff --git a/lib/posix/options/fs.c b/lib/posix/options/fs.c index ca861a729b1..091a3ddccda 100644 --- a/lib/posix/options/fs.c +++ b/lib/posix/options/fs.c @@ -144,6 +144,10 @@ static int fs_ioctl_vmeth(void *obj, unsigned int request, va_list args) struct posix_fs_desc *ptr = obj; switch (request) { + case ZFD_IOCTL_FSYNC: { + rc = fs_sync(&ptr->file); + break; + } case ZFD_IOCTL_LSEEK: { off_t offset; int whence; @@ -412,3 +416,25 @@ int mkdir(const char *path, mode_t mode) return 0; } + +/** + * @brief Truncate file to specified length. + * + */ +int ftruncate(int fd, off_t length) +{ + int rc; + struct posix_fs_desc *ptr = NULL; + + ptr = z_get_fd_obj(fd, NULL, EBADF); + if (!ptr) + return -1; + + rc = fs_truncate(&ptr->file, length); + if (rc < 0) { + errno = -rc; + return -1; + } + + return 0; +} diff --git a/lib/posix/options/getentropy.c b/lib/posix/options/getentropy.c new file mode 100644 index 00000000000..dcc271617cb --- /dev/null +++ b/lib/posix/options/getentropy.c @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2024 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include +#include + +#define ENTROPY_NODE DT_CHOSEN(zephyr_entropy) + +int getentropy(void *buffer, size_t length) +{ + const struct device * const entropy = DEVICE_DT_GET(ENTROPY_NODE); + + if (!buffer) { + errno = EFAULT; + return -1; + } + + if (length > 256) { + errno = EIO; + return -1; + } + + if (!device_is_ready(entropy)) { + errno = EIO; + return -1; + } + + /* + * getentropy() uses size_t to represent buffer size, but Zephyr uses + * uint16_t. The length check above allows us to safely cast without + * overflow. + */ + if (entropy_get_entropy(entropy, buffer, (uint16_t)length)) { + errno = EIO; + return -1; + } + + return 0; +} diff --git a/lib/posix/options/getopt/getopt.h b/lib/posix/options/getopt/getopt.h index 4dfcc8b5f57..3ae474f4304 100644 --- a/lib/posix/options/getopt/getopt.h +++ b/lib/posix/options/getopt/getopt.h @@ -48,7 +48,7 @@ struct option { int val; }; -/* Function intializes getopt_state structure for current thread */ +/* Function initializes getopt_state structure for current thread */ void getopt_init(void); /* Function returns getopt_state structure for the current thread. */ diff --git a/lib/posix/options/key.c b/lib/posix/options/key.c index 553c06cf366..5e68381c53b 100644 --- a/lib/posix/options/key.c +++ b/lib/posix/options/key.c @@ -200,18 +200,18 @@ int pthread_setspecific(pthread_key_t key, const void *value) SYS_SLIST_FOR_EACH_NODE(&(thread->key_list), node_l) { - thread_spec_data = (pthread_thread_data *)node_l; - - if (thread_spec_data->key == key_obj) { - - /* Key is already present so - * 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; - } + thread_spec_data = (pthread_thread_data *)node_l; + + if (thread_spec_data->key == key_obj) { + + /* Key is already present so + * 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; + } } if (node_l == NULL) { diff --git a/lib/posix/options/stropts.c b/lib/posix/options/stropts.c index 66d44fcbb28..c1e6c9f54ed 100644 --- a/lib/posix/options/stropts.c +++ b/lib/posix/options/stropts.c @@ -58,3 +58,11 @@ int getpmsg(int fildes, struct strbuf *ctlptr, struct strbuf *dataptr, int *band errno = ENOSYS; return -1; } + +int isastream(int fildes) +{ + ARG_UNUSED(fildes); + + errno = ENOSYS; + return -1; +} diff --git a/lib/smf/smf.c b/lib/smf/smf.c index ecc10740744..fb0c95c574f 100644 --- a/lib/smf/smf.c +++ b/lib/smf/smf.c @@ -9,24 +9,22 @@ #include LOG_MODULE_REGISTER(smf); -/* - * Private structure (to this file) used to track state machine context. - * The structure is not used directly, but instead to cast the "internal" - * member of the smf_ctx structure. +/** + * @brief Private structure (to this file) used to track state machine context. + * The structure is not used directly, but instead to cast the "internal" + * member of the smf_ctx structure. */ struct internal_ctx { - bool new_state : 1; - bool terminate : 1; - bool exit : 1; - bool handled : 1; + bool new_state: 1; + bool terminate: 1; + bool is_exit: 1; + bool handled: 1; }; -static bool share_paren(const struct smf_state *test_state, - const struct smf_state *target_state) +#ifdef CONFIG_SMF_ANCESTOR_SUPPORT +static bool share_paren(const struct smf_state *test_state, const struct smf_state *target_state) { - for (const struct smf_state *state = test_state; - state != NULL; - state = state->parent) { + for (const struct smf_state *state = test_state; state != NULL; state = state->parent) { if (target_state == state) { return true; } @@ -35,21 +33,10 @@ static bool share_paren(const struct smf_state *test_state, return false; } -static bool last_state_share_paren(struct smf_ctx *const ctx, - const struct smf_state *state) -{ - /* Get parent state of previous state */ - if (!ctx->previous) { - return false; - } - - return share_paren(ctx->previous->parent, state); -} - static const struct smf_state *get_child_of(const struct smf_state *states, const struct smf_state *parent) { - for (const struct smf_state *tmp = states; ; tmp = tmp->parent) { + for (const struct smf_state *tmp = states;; tmp = tmp->parent) { if (tmp->parent == parent) { return tmp; } @@ -68,22 +55,55 @@ static const struct smf_state *get_last_of(const struct smf_state *states) } /** - * @brief Execute all ancestor entry actions + * @brief Find the Least Common Ancestor (LCA) of two states + * + * @param source transition source + * @param dest transition destination + * @return LCA state, or NULL if states have no LCA. + */ +static const struct smf_state *get_lca_of(const struct smf_state *source, + const struct smf_state *dest) +{ + for (const struct smf_state *ancestor = source->parent; ancestor != NULL; + ancestor = ancestor->parent) { + if (ancestor == dest) { + return ancestor->parent; + } else if (share_paren(dest, ancestor)) { + return ancestor; + } + } + + return NULL; +} + +/** + * @brief Executes all entry actions from the direct child of topmost to the new state * * @param ctx State machine context - * @param target The entry actions of this target's ancestors are executed + * @param new_state State we are transitioning to + * @param topmost State we are entering from. Its entry action is not executed * @return true if the state machine should terminate, else false */ -__unused static bool smf_execute_ancestor_entry_actions( - struct smf_ctx *const ctx, const struct smf_state *target) +static bool smf_execute_all_entry_actions(struct smf_ctx *const ctx, + const struct smf_state *new_state, + const struct smf_state *topmost) { - struct internal_ctx * const internal = (void *) &ctx->internal; + struct internal_ctx *const internal = (void *)&ctx->internal; - for (const struct smf_state *to_execute = get_last_of(target); - to_execute != NULL && to_execute != target; - to_execute = get_child_of(target, to_execute)) { - /* Execute parent state's entry */ - if (!last_state_share_paren(ctx, to_execute) && to_execute->entry) { + if (new_state == topmost) { + /* There are no child states, so do nothing */ + return false; + } + + for (const struct smf_state *to_execute = get_child_of(new_state, topmost); + to_execute != NULL && to_execute != new_state; + to_execute = get_child_of(new_state, to_execute)) { + /* Execute every entry action EXCEPT that of the topmost state */ + if (to_execute->entry) { + /* Keep track of the executing entry action in case it calls + * smf_set_State() + */ + ctx->executing = to_execute; to_execute->entry(ctx); /* No need to continue if terminate was set */ @@ -93,6 +113,16 @@ __unused static bool smf_execute_ancestor_entry_actions( } } + /* and execute the new state entry action */ + if (new_state->entry) { + new_state->entry(ctx); + + /* No need to continue if terminate was set */ + if (internal->terminate) { + return true; + } + } + return false; } @@ -103,9 +133,9 @@ __unused static bool smf_execute_ancestor_entry_actions( * @param target The run actions of this target's ancestors are executed * @return true if the state machine should terminate, else false */ -__unused static bool smf_execute_ancestor_run_actions(struct smf_ctx *ctx) +static bool smf_execute_ancestor_run_actions(struct smf_ctx *ctx) { - struct internal_ctx * const internal = (void *) &ctx->internal; + struct internal_ctx *const internal = (void *)&ctx->internal; /* Execute all run actions in reverse order */ /* Return if the current state switched states */ @@ -126,9 +156,10 @@ __unused static bool smf_execute_ancestor_run_actions(struct smf_ctx *ctx) } /* Try to run parent run actions */ - for (const struct smf_state *tmp_state = ctx->current->parent; - tmp_state != NULL; + for (const struct smf_state *tmp_state = ctx->current->parent; tmp_state != NULL; tmp_state = tmp_state->parent) { + /* Keep track of where we are in case an ancestor calls smf_set_state() */ + ctx->executing = tmp_state; /* Execute parent run action */ if (tmp_state->run) { tmp_state->run(ctx); @@ -156,39 +187,35 @@ __unused static bool smf_execute_ancestor_run_actions(struct smf_ctx *ctx) } /** - * @brief Execute all ancestor exit actions + * @brief Executes all exit actions from ctx->current to the direct child of topmost * * @param ctx State machine context - * @param target The exit actions of this target's ancestors are executed + * @param topmost State we are exiting to. Its exit action is not executed * @return true if the state machine should terminate, else false */ -__unused static bool smf_execute_ancestor_exit_actions( - struct smf_ctx *const ctx, const struct smf_state *target) +static bool smf_execute_all_exit_actions(struct smf_ctx *const ctx, const struct smf_state *topmost) { - struct internal_ctx * const internal = (void *) &ctx->internal; - - /* Execute all parent exit actions in reverse order */ + struct internal_ctx *const internal = (void *)&ctx->internal; - for (const struct smf_state *tmp_state = ctx->current->parent; - tmp_state != NULL; - tmp_state = tmp_state->parent) { - if ((target == NULL || !share_paren(target->parent, tmp_state)) && - tmp_state->exit) { - tmp_state->exit(ctx); + for (const struct smf_state *to_execute = ctx->current; to_execute != topmost; + to_execute = to_execute->parent) { + if (to_execute->exit) { + to_execute->exit(ctx); - /* No need to continue if terminate was set */ + /* No need to continue if terminate was set in the exit action */ if (internal->terminate) { return true; } } } + return false; } +#endif /* CONFIG_SMF_ANCESTOR_SUPPORT */ void smf_set_initial(struct smf_ctx *ctx, const struct smf_state *init_state) { - struct internal_ctx * const internal = (void *) &ctx->internal; - + struct internal_ctx *const internal = (void *)&ctx->internal; #ifdef CONFIG_SMF_INITIAL_TRANSITION /* @@ -199,98 +226,150 @@ void smf_set_initial(struct smf_ctx *ctx, const struct smf_state *init_state) init_state = init_state->initial; } #endif - internal->exit = false; + + internal->is_exit = false; internal->terminate = false; ctx->current = init_state; ctx->previous = NULL; ctx->terminate_val = 0; - if (IS_ENABLED(CONFIG_SMF_ANCESTOR_SUPPORT)) { - internal->new_state = false; +#ifdef CONFIG_SMF_ANCESTOR_SUPPORT + ctx->executing = init_state; + const struct smf_state *topmost = get_last_of(init_state); - if (smf_execute_ancestor_entry_actions(ctx, init_state)) { + /* Execute topmost state entry action, since smf_execute_all_entry_actions() + * doesn't + */ + if (topmost->entry) { + topmost->entry(ctx); + if (internal->terminate) { + /* No need to continue if terminate was set */ return; } } - /* Now execute the initial state's entry action */ + if (smf_execute_all_entry_actions(ctx, init_state, topmost)) { + /* No need to continue if terminate was set */ + return; + } +#else + /* execute entry action if it exists */ if (init_state->entry) { init_state->entry(ctx); } +#endif } -void smf_set_state(struct smf_ctx *const ctx, const struct smf_state *target) +void smf_set_state(struct smf_ctx *const ctx, const struct smf_state *new_state) { - struct internal_ctx * const internal = (void *) &ctx->internal; + struct internal_ctx *const internal = (void *)&ctx->internal; + + if (new_state == NULL) { + LOG_ERR("new_state cannot be NULL"); + return; + } /* - * It does not make sense to call set_state in an exit phase of a state + * It does not make sense to call smf_set_state in an exit phase of a state * since we are already in a transition; we would always ignore the * intended state to transition into. */ - if (internal->exit) { - LOG_WRN("Calling %s from exit action", __func__); + if (internal->is_exit) { + LOG_ERR("Calling %s from exit action", __func__); return; } - internal->exit = true; +#ifdef CONFIG_SMF_ANCESTOR_SUPPORT + const struct smf_state *topmost; + + if (share_paren(ctx->executing, new_state)) { + /* new state is a parent of where we are now*/ + topmost = new_state; + } else if (share_paren(new_state, ctx->executing)) { + /* we are a parent of the new state */ + topmost = ctx->executing; + } else { + /* not directly related, find LCA */ + topmost = get_lca_of(ctx->executing, new_state); + } + + internal->is_exit = true; + internal->new_state = true; - /* Execute the current states exit action */ - if (ctx->current->exit) { - ctx->current->exit(ctx); + /* call all exit actions up to (but not including) the topmost */ + if (smf_execute_all_exit_actions(ctx, topmost)) { + /* No need to continue if terminate was set in the exit action */ + return; + } - /* - * No need to continue if terminate was set in the - * exit action - */ + /* if self-transition, call the exit action */ + if ((ctx->executing == new_state) && (new_state->exit)) { + new_state->exit(ctx); + + /* No need to continue if terminate was set in the exit action */ if (internal->terminate) { return; } } - if (IS_ENABLED(CONFIG_SMF_ANCESTOR_SUPPORT)) { - internal->new_state = true; + internal->is_exit = false; + + /* if self transition, call the entry action */ + if ((ctx->executing == new_state) && (new_state->entry)) { + new_state->entry(ctx); - if (smf_execute_ancestor_exit_actions(ctx, target)) { + /* No need to continue if terminate was set in the entry action */ + if (internal->terminate) { return; } } - - internal->exit = false; - #ifdef CONFIG_SMF_INITIAL_TRANSITION /* * The final target will be the deepest leaf state that * the target contains. Set that as the real target. */ - while (target->initial) { - target = target->initial; + while (new_state->initial) { + new_state = new_state->initial; } #endif /* update the state variables */ ctx->previous = ctx->current; - ctx->current = target; + ctx->current = new_state; - if (IS_ENABLED(CONFIG_SMF_ANCESTOR_SUPPORT)) { - if (smf_execute_ancestor_entry_actions(ctx, target)) { + /* call all entry actions (except those of topmost) */ + if (smf_execute_all_entry_actions(ctx, new_state, topmost)) { + /* No need to continue if terminate was set in the entry action */ + return; + } +#else + /* Flat state machines have a very simple transition: */ + if (ctx->current->exit) { + internal->is_exit = true; + ctx->current->exit(ctx); + /* No need to continue if terminate was set in the exit action */ + if (internal->terminate) { return; } + internal->is_exit = false; } + /* update the state variables */ + ctx->previous = ctx->current; + ctx->current = new_state; - /* Now execute the target entry action */ if (ctx->current->entry) { ctx->current->entry(ctx); - /* - * If terminate was set, it will be handled in the - * smf_run_state function - */ + /* No need to continue if terminate was set in the entry action */ + if (internal->terminate) { + return; + } } +#endif } void smf_set_terminate(struct smf_ctx *ctx, int32_t val) { - struct internal_ctx * const internal = (void *) &ctx->internal; + struct internal_ctx *const internal = (void *)&ctx->internal; internal->terminate = true; ctx->terminate_val = val; @@ -305,22 +384,25 @@ void smf_set_handled(struct smf_ctx *ctx) int32_t smf_run_state(struct smf_ctx *const ctx) { - struct internal_ctx * const internal = (void *) &ctx->internal; + struct internal_ctx *const internal = (void *)&ctx->internal; /* No need to continue if terminate was set */ if (internal->terminate) { return ctx->terminate_val; } +#ifdef CONFIG_SMF_ANCESTOR_SUPPORT + ctx->executing = ctx->current; +#endif + if (ctx->current->run) { ctx->current->run(ctx); } - if (IS_ENABLED(CONFIG_SMF_ANCESTOR_SUPPORT)) { - if (smf_execute_ancestor_run_actions(ctx)) { - return ctx->terminate_val; - } +#ifdef CONFIG_SMF_ANCESTOR_SUPPORT + if (smf_execute_ancestor_run_actions(ctx)) { + return ctx->terminate_val; } - +#endif return 0; } diff --git a/lib/utils/bitarray.c b/lib/utils/bitarray.c index 7213ae201f5..509fa5f199f 100644 --- a/lib/utils/bitarray.c +++ b/lib/utils/bitarray.c @@ -210,6 +210,112 @@ static void set_region(sys_bitarray_t *bitarray, size_t offset, } } +int sys_bitarray_popcount_region(sys_bitarray_t *bitarray, size_t num_bits, size_t offset, + size_t *count) +{ + k_spinlock_key_t key; + size_t idx; + struct bundle_data bd; + int ret; + + key = k_spin_lock(&bitarray->lock); + + __ASSERT_NO_MSG(bitarray != NULL); + __ASSERT_NO_MSG(bitarray->num_bits > 0); + + if (num_bits == 0 || offset + num_bits > bitarray->num_bits) { + ret = -EINVAL; + goto out; + } + + CHECKIF(count == NULL) { + ret = -EINVAL; + goto out; + } + + setup_bundle_data(bitarray, &bd, offset, num_bits); + + if (bd.sidx == bd.eidx) { + /* Start/end at same bundle */ + *count = POPCOUNT(bitarray->bundles[bd.sidx] & bd.smask); + } else { + /* Start/end at different bundle. + * So count the bits in start and end bundles + * separately with correct mask applied. For in-between bundles, + * count all bits. + */ + *count = 0; + *count += POPCOUNT(bitarray->bundles[bd.sidx] & bd.smask); + *count += POPCOUNT(bitarray->bundles[bd.eidx] & bd.emask); + for (idx = bd.sidx + 1; idx < bd.eidx; idx++) { + *count += POPCOUNT(bitarray->bundles[idx]); + } + } + + ret = 0; + +out: + k_spin_unlock(&bitarray->lock, key); + return ret; +} + +int sys_bitarray_xor(sys_bitarray_t *dst, sys_bitarray_t *other, size_t num_bits, size_t offset) +{ + k_spinlock_key_t key_dst, key_other; + int ret; + size_t idx; + struct bundle_data bd; + + key_dst = k_spin_lock(&dst->lock); + key_other = k_spin_lock(&other->lock); + + __ASSERT_NO_MSG(dst != NULL); + __ASSERT_NO_MSG(dst->num_bits > 0); + __ASSERT_NO_MSG(other != NULL); + __ASSERT_NO_MSG(other->num_bits > 0); + + if (dst->num_bits != other->num_bits) { + ret = -EINVAL; + goto out; + } + + if (num_bits == 0 || offset + num_bits > dst->num_bits) { + ret = -EINVAL; + goto out; + } + + setup_bundle_data(other, &bd, offset, num_bits); + + if (bd.sidx == bd.eidx) { + /* Start/end at same bundle */ + dst->bundles[bd.sidx] = + ((other->bundles[bd.sidx] ^ dst->bundles[bd.sidx]) & bd.smask) | + (dst->bundles[bd.sidx] & ~bd.smask); + } else { + /* Start/end at different bundle. + * So xor the bits in start and end bundles according to their bitmasks + * separately. For in-between bundles, + * xor all bits. + */ + dst->bundles[bd.sidx] = + ((other->bundles[bd.sidx] ^ dst->bundles[bd.sidx]) & bd.smask) | + (dst->bundles[bd.sidx] & ~bd.smask); + dst->bundles[bd.eidx] = + ((other->bundles[bd.eidx] ^ dst->bundles[bd.eidx]) & bd.emask) | + (dst->bundles[bd.eidx] & ~bd.emask); + for (idx = bd.sidx + 1; idx < bd.eidx; idx++) { + dst->bundles[idx] ^= other->bundles[idx]; + } + } + + ret = 0; + +out: + k_spin_unlock(&other->lock, key_other); + k_spin_unlock(&dst->lock, key_dst); + return ret; +} + int sys_bitarray_set_bit(sys_bitarray_t *bitarray, size_t bit) { k_spinlock_key_t key; @@ -453,6 +559,81 @@ int sys_bitarray_alloc(sys_bitarray_t *bitarray, size_t num_bits, return ret; } +int sys_bitarray_find_nth_set(sys_bitarray_t *bitarray, size_t n, size_t num_bits, size_t offset, + size_t *found_at) +{ + k_spinlock_key_t key; + size_t count, idx; + uint32_t mask; + struct bundle_data bd; + int ret; + + __ASSERT_NO_MSG(bitarray != NULL); + __ASSERT_NO_MSG(bitarray->num_bits > 0); + + key = k_spin_lock(&bitarray->lock); + + if (n == 0 || num_bits == 0 || offset + num_bits > bitarray->num_bits) { + ret = -EINVAL; + goto out; + } + + ret = 1; + mask = 0; + setup_bundle_data(bitarray, &bd, offset, num_bits); + + count = POPCOUNT(bitarray->bundles[bd.sidx] & bd.smask); + /* If we already found more bits set than n, we found the target bundle */ + if (count >= n) { + idx = bd.sidx; + mask = bd.smask; + goto found; + } + /* Keep looking if there are more bundles */ + if (bd.sidx != bd.eidx) { + /* We are now only looking for the remaining bits */ + n -= count; + /* First bundle was already checked, keep looking in middle (complete) + * bundles. + */ + for (idx = bd.sidx + 1; idx < bd.eidx; idx++) { + count = POPCOUNT(bitarray->bundles[idx]); + if (count >= n) { + mask = ~(mask & 0); + goto found; + } + n -= count; + } + /* Continue searching in last bundle */ + count = POPCOUNT(bitarray->bundles[bd.eidx] & bd.emask); + if (count >= n) { + idx = bd.eidx; + mask = bd.emask; + goto found; + } + } + + goto out; + +found: + /* The bit we are looking for must be in the current bundle idx. + * Find out the exact index of the bit. + */ + for (int j = 0; j <= bundle_bitness(bitarray) - 1; j++) { + if (bitarray->bundles[idx] & mask & BIT(j)) { + if (--n <= 0) { + *found_at = idx * bundle_bitness(bitarray) + j; + ret = 0; + break; + } + } + } + +out: + k_spin_unlock(&bitarray->lock, key); + return ret; +} + int sys_bitarray_free(sys_bitarray_t *bitarray, size_t num_bits, size_t offset) { diff --git a/modules/Kconfig.mcuboot b/modules/Kconfig.mcuboot index a2e1803b138..b46c709d8ef 100644 --- a/modules/Kconfig.mcuboot +++ b/modules/Kconfig.mcuboot @@ -199,7 +199,6 @@ 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 @@ -215,7 +214,6 @@ 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 diff --git a/modules/Kconfig.mcux b/modules/Kconfig.mcux index 3f20250f58b..0700438661e 100644 --- a/modules/Kconfig.mcux +++ b/modules/Kconfig.mcux @@ -282,11 +282,6 @@ config HAS_MCUX_SMC help Set if the SMC module is present in the SoC. -config HAS_MCUX_CSI - bool - help - Set if the CMOS Sensor Interface module is present in the SoC. - config HAS_MCUX_LPTMR bool help diff --git a/modules/Kconfig.microchip b/modules/Kconfig.microchip index 8c30ae6087d..7497d99ead0 100644 --- a/modules/Kconfig.microchip +++ b/modules/Kconfig.microchip @@ -7,3 +7,6 @@ config HAS_MEC_HAL config HAS_MPFS_HAL bool "Microchip MPFS HAL drivers support" + +config HAS_MEC5_HAL + bool "Microchip MEC5 HAL drivers support" diff --git a/modules/Kconfig.nuvoton b/modules/Kconfig.nuvoton index 33dabc67f84..b9765360351 100644 --- a/modules/Kconfig.nuvoton +++ b/modules/Kconfig.nuvoton @@ -75,4 +75,8 @@ menu "Nuvoton NuMaker drivers" bool "NuMaker RMC" help Enable Nuvoton RMC HAL module driver + config HAS_NUMAKER_RTC + bool "NuMaker RTC" + help + Enable Nuvoton RTC HAL module driver endmenu diff --git a/modules/hal_ambiq/Kconfig b/modules/hal_ambiq/Kconfig index 28c19e9a587..b329d117c89 100644 --- a/modules/hal_ambiq/Kconfig +++ b/modules/hal_ambiq/Kconfig @@ -4,7 +4,7 @@ config AMBIQ_HAL bool "Ambiq HAL drivers support" - depends on SOC_SERIES_APOLLO4X + depends on SOC_SERIES_APOLLO4X || SOC_SERIES_APOLLO3X help Use the Ambiq HAL @@ -45,4 +45,9 @@ config AMBIQ_HAL_USE_MSPI help Use the MSPI driver from Ambiq HAL +config AMBIQ_HAL_USE_HWINFO + bool + help + Use the HWINFO driver from Ambiq HAL + endif # AMBIQ_HAL diff --git a/modules/hal_infineon/CMakeLists.txt b/modules/hal_infineon/CMakeLists.txt index 99d925b1396..c6d9d95aa24 100644 --- a/modules/hal_infineon/CMakeLists.txt +++ b/modules/hal_infineon/CMakeLists.txt @@ -2,7 +2,7 @@ # Copyright (c) 2022 Cypress Semiconductor Corporation. # SPDX-License-Identifier: Apache-2.0 -if(CONFIG_HAS_XMCLIB OR CONFIG_SOC_FAMILY_PSOC6 OR CONFIG_SOC_FAMILY_INFINEON_CAT1) +if(CONFIG_HAS_XMCLIB OR CONFIG_SOC_FAMILY_PSOC6_LEGACY OR CONFIG_SOC_FAMILY_INFINEON_CAT1) zephyr_library_named(modules_hal_infineon) zephyr_library_compile_options(-Wno-array-bounds) endif() @@ -12,7 +12,7 @@ if (CONFIG_HAS_XMCLIB) add_subdirectory(${ZEPHYR_HAL_INFINEON_MODULE_DIR}/XMCLib XMCLib) endif() -if (CONFIG_SOC_FAMILY_INFINEON_CAT1A OR CONFIG_SOC_FAMILY_PSOC6) +if (CONFIG_SOC_FAMILY_INFINEON_CAT1 OR CONFIG_SOC_FAMILY_PSOC6_LEGACY) ## Add core-lib sources for CAT1 devices add_subdirectory(core-lib) @@ -23,7 +23,7 @@ if (CONFIG_SOC_FAMILY_INFINEON_CAT1A OR CONFIG_SOC_FAMILY_PSOC6) add_subdirectory(mtb-template-cat1) endif() -if (CONFIG_SOC_FAMILY_INFINEON_CAT1A) +if (CONFIG_SOC_FAMILY_INFINEON_CAT1 AND NOT CONFIG_SOC_FAMILY_PSOC6_LEGACY) ## Add mtb-hal-cat1 sources for CAT1 devices add_subdirectory(mtb-hal-cat1) diff --git a/modules/hal_infineon/Kconfig b/modules/hal_infineon/Kconfig index 723579c5d5b..fb1431faed2 100644 --- a/modules/hal_infineon/Kconfig +++ b/modules/hal_infineon/Kconfig @@ -4,7 +4,7 @@ config ZEPHYR_HAL_INFINEON_MODULE bool -if SOC_FAMILY_PSOC6 || SOC_FAMILY_INFINEON_CAT1 +if SOC_FAMILY_INFINEON_CAT1 || SOC_FAMILY_PSOC6_LEGACY config USE_INFINEON_ADC bool @@ -77,8 +77,7 @@ config USE_INFINEON_FLASH help Enable Flash HAL module driver for Infineon devices -endif # SOC_FAMILY_PSOC6 - +endif # SOC_FAMILY_INFINEON_CAT1 || SOC_FAMILY_PSOC6_LEGACY config USE_INFINEON_ABSTRACTION_RTOS bool "Abstraction RTOS component (Zephyr support)" help diff --git a/modules/hal_infineon/mtb-hal-cat1/CMakeLists.txt b/modules/hal_infineon/mtb-hal-cat1/CMakeLists.txt index c94bd1db60c..e3d468cd764 100644 --- a/modules/hal_infineon/mtb-hal-cat1/CMakeLists.txt +++ b/modules/hal_infineon/mtb-hal-cat1/CMakeLists.txt @@ -29,8 +29,6 @@ zephyr_library_sources_ifdef(CONFIG_SOC_PACKAGE_PSOC6_01_124_BGA ${hal_cat1a_dir}/source/pin_packages/cyhal_psoc6_01_124_bga.c) zephyr_library_sources_ifdef(CONFIG_SOC_PACKAGE_PSOC6_01_124_BGA_SIP ${hal_cat1a_dir}/source/pin_packages/cyhal_psoc6_01_124_bga_sip.c) -zephyr_library_sources_ifdef(CONFIG_SOC_PACKAGE_PSOC6_01_43_SMT - ${hal_cat1a_dir}/source/pin_packages/cyhal_psoc6_01_43_smt.c) zephyr_library_sources_ifdef(CONFIG_SOC_PACKAGE_PSOC6_01_68_QFN_BLE ${hal_cat1a_dir}/source/pin_packages/cyhal_psoc6_01_68_qfn_ble.c) zephyr_library_sources_ifdef(CONFIG_SOC_PACKAGE_PSOC6_01_80_WLCSP diff --git a/modules/hal_infineon/mtb-pdl-cat1/CMakeLists.txt b/modules/hal_infineon/mtb-pdl-cat1/CMakeLists.txt index f71e0b2b3a9..f7461673961 100644 --- a/modules/hal_infineon/mtb-pdl-cat1/CMakeLists.txt +++ b/modules/hal_infineon/mtb-pdl-cat1/CMakeLists.txt @@ -7,8 +7,13 @@ set(pdl_dir ${ZEPHYR_HAL_INFINEON_MODULE_DIR}/mtb-pdl-cat1) set(pdl_drv_dir ${ZEPHYR_HAL_INFINEON_MODULE_DIR}/mtb-pdl-cat1/drivers) set(pdl_dev_cat1a_dir ${ZEPHYR_HAL_INFINEON_MODULE_DIR}/mtb-pdl-cat1/devices/COMPONENT_CAT1A) + +# Generate PDL specific SOC defines zephyr_compile_definitions(${CONFIG_SOC_PART_NUMBER}) -zephyr_compile_definitions_ifdef(CONFIG_SOC_FAMILY_INFINEON_CAT1 ${CONFIG_SOC}) +zephyr_compile_definitions_ifdef(CONFIG_SOC_FAMILY_INFINEON_CAT1 $) + +# Generate PDL specific define (w. *_device) for SOC module (e.g: CYBLE_416045_02) +zephyr_compile_definitions_ifdef(CONFIG_SOC_CYBLE_416045_02 CYBLE_416045_02_device) # Add mtb-pdl-cat1 zephyr_include_directories(${pdl_drv_dir}/include) @@ -19,11 +24,12 @@ zephyr_library_sources(${pdl_dev_cat1a_dir}/source/cy_device.c) zephyr_library_sources(${pdl_drv_dir}/source/TOOLCHAIN_GCC_ARM/cy_syslib_ext.S) # Peripheral drivers -zephyr_library_sources_ifdef(CONFIG_SOC_FAMILY_PSOC6 ${pdl_drv_dir}/source/cy_sysint.c) +zephyr_library_sources_ifdef(CONFIG_SOC_FAMILY_PSOC6_LEGACY ${pdl_drv_dir}/source/cy_sysint.c) zephyr_library_sources_ifdef(CONFIG_USE_INFINEON_ADC ${pdl_drv_dir}/source/cy_sar.c) zephyr_library_sources_ifdef(CONFIG_USE_INFINEON_I2C ${pdl_drv_dir}/source/cy_scb_i2c.c) zephyr_library_sources_ifdef(CONFIG_USE_INFINEON_LPTIMER ${pdl_drv_dir}/source/cy_mcwdt.c) zephyr_library_sources_ifdef(CONFIG_USE_INFINEON_PWM ${pdl_drv_dir}/source/cy_tcpwm_pwm.c) +zephyr_library_sources_ifdef(CONFIG_USE_INFINEON_RTC ${pdl_drv_dir}/source/cy_rtc.c) zephyr_library_sources_ifdef(CONFIG_USE_INFINEON_SDIO ${pdl_drv_dir}/source/cy_sd_host.c) zephyr_library_sources_ifdef(CONFIG_USE_INFINEON_SPI ${pdl_drv_dir}/source/cy_scb_spi.c) zephyr_library_sources_ifdef(CONFIG_USE_INFINEON_TIMER ${pdl_drv_dir}/source/cy_tcpwm_counter.c) diff --git a/modules/hal_nordic/CMakeLists.txt b/modules/hal_nordic/CMakeLists.txt index 7f46997c697..3c8c4394560 100644 --- a/modules/hal_nordic/CMakeLists.txt +++ b/modules/hal_nordic/CMakeLists.txt @@ -6,12 +6,13 @@ if (CONFIG_NRF_802154_RADIO_DRIVER OR CONFIG_NRF_802154_SERIALIZATION) endif (CONFIG_NRF_802154_RADIO_DRIVER OR CONFIG_NRF_802154_SERIALIZATION) add_subdirectory_ifdef(CONFIG_HAS_NRFX nrfx) +add_subdirectory_ifdef(CONFIG_HAS_NRFS nrfs) if(CONFIG_NRF_REGTOOL_GENERATE_UICR) list(APPEND nrf_regtool_components GENERATE:UICR) endif() if(DEFINED nrf_regtool_components) - find_package(nrf-regtool 5.1.0 REQUIRED + find_package(nrf-regtool 5.2.0 REQUIRED COMPONENTS ${nrf_regtool_components} PATHS ${CMAKE_CURRENT_LIST_DIR}/nrf-regtool NO_CMAKE_PATH diff --git a/modules/hal_nordic/Kconfig b/modules/hal_nordic/Kconfig index c9cc93e9329..13ab8d9cd2f 100644 --- a/modules/hal_nordic/Kconfig +++ b/modules/hal_nordic/Kconfig @@ -55,7 +55,7 @@ endchoice config NRF_802154_TEMPERATURE_UPDATE bool "nRF 802.15.4 temperature update" - default y + default y if !SOC_NRF54H20 help Enable temperature update for nRF 802.15.4 driver @@ -235,5 +235,6 @@ endif # NRF_802154_RADIO_DRIVER || NRF_802154_SERIALIZATION endmenu # HAS_NORDIC_DRIVERS +rsource "nrfs/Kconfig" rsource "nrfx/Kconfig" rsource "Kconfig.nrf_regtool" diff --git a/modules/hal_nordic/nrf_802154/sl_opensource/platform/nrf_802154_clock_zephyr.c b/modules/hal_nordic/nrf_802154/sl_opensource/platform/nrf_802154_clock_zephyr.c index 3a3d9501d0c..1db86f5ad14 100644 --- a/modules/hal_nordic/nrf_802154/sl_opensource/platform/nrf_802154_clock_zephyr.c +++ b/modules/hal_nordic/nrf_802154/sl_opensource/platform/nrf_802154_clock_zephyr.c @@ -4,18 +4,21 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include #include #include #include +#include +#if defined(CONFIG_CLOCK_CONTROL_NRF) #include #include +#elif !defined(NRF54H_SERIES) +#error No implementation to start or stop HFCLK due to missing clock_control. +#endif static bool hfclk_is_running; -static bool lfclk_is_running; -static struct onoff_client hfclk_cli; -static struct onoff_client lfclk_cli; void nrf_802154_clock_init(void) { @@ -27,6 +30,15 @@ void nrf_802154_clock_deinit(void) /* Intentionally empty. */ } +bool nrf_802154_clock_hfclk_is_running(void) +{ + return hfclk_is_running; +} + +#if defined(CONFIG_CLOCK_CONTROL_NRF) + +static struct onoff_client hfclk_cli; + static void hfclk_on_callback(struct onoff_manager *mgr, struct onoff_client *cli, uint32_t state, @@ -63,53 +75,39 @@ void nrf_802154_clock_hfclk_stop(void) hfclk_is_running = false; } -bool nrf_802154_clock_hfclk_is_running(void) -{ - return hfclk_is_running; -} +#elif defined(NRF54H_SERIES) -static void lfclk_on_callback(struct onoff_manager *mgr, - struct onoff_client *cli, - uint32_t state, - int res) -{ - lfclk_is_running = true; - nrf_802154_clock_lfclk_ready(); -} +#define NRF_LRCCONF_RADIO_PD NRF_LRCCONF010 +#define MAX_HFXO_RAMP_UP_TIME_US 1000 -void nrf_802154_clock_lfclk_start(void) +static void hfclk_started_timer_handler(struct k_timer *dummy) { - int ret; - struct onoff_manager *mgr = - z_nrf_clock_control_get_onoff(CLOCK_CONTROL_NRF_SUBSYS_LF); - - __ASSERT_NO_MSG(mgr != NULL); - - sys_notify_init_callback(&lfclk_cli.notify, lfclk_on_callback); - - ret = onoff_request(mgr, &lfclk_cli); - __ASSERT_NO_MSG(ret >= 0); + hfclk_is_running = true; + nrf_802154_clock_hfclk_ready(); } -void nrf_802154_clock_lfclk_stop(void) -{ - int ret; - struct onoff_manager *mgr = - z_nrf_clock_control_get_onoff(CLOCK_CONTROL_NRF_SUBSYS_LF); +K_TIMER_DEFINE(hfclk_started_timer, hfclk_started_timer_handler, NULL); - __ASSERT_NO_MSG(mgr != NULL); +void nrf_802154_clock_hfclk_start(void) +{ + /* Use register directly, there is no support for that task in nrf_lrcconf_task_trigger. + * This code might cause troubles if there are other HFXO users in this CPU. + */ + NRF_LRCCONF_RADIO_PD->EVENTS_HFXOSTARTED = 0x0; + NRF_LRCCONF_RADIO_PD->TASKS_REQHFXO = 0x1; - ret = onoff_cancel_or_release(mgr, &lfclk_cli); - __ASSERT_NO_MSG(ret >= 0); - lfclk_is_running = false; + k_timer_start(&hfclk_started_timer, K_USEC(MAX_HFXO_RAMP_UP_TIME_US), K_NO_WAIT); } -bool nrf_802154_clock_lfclk_is_running(void) +void nrf_802154_clock_hfclk_stop(void) { - return lfclk_is_running; -} + /* Use register directly, there is no support for that task in nrf_lrcconf_task_trigger. + * This code might cause troubles if there are other HFXO users in this CPU. + */ + NRF_LRCCONF_RADIO_PD->TASKS_STOPREQHFXO = 0x1; + NRF_LRCCONF_RADIO_PD->EVENTS_HFXOSTARTED = 0x0; -__WEAK void nrf_802154_clock_lfclk_ready(void) -{ - /* Intentionally empty. */ + hfclk_is_running = false; } + +#endif diff --git a/modules/hal_nordic/nrfs/CMakeLists.txt b/modules/hal_nordic/nrfs/CMakeLists.txt new file mode 100644 index 00000000000..c601b8a4233 --- /dev/null +++ b/modules/hal_nordic/nrfs/CMakeLists.txt @@ -0,0 +1,41 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + + +if(CONFIG_NRFS) + zephyr_library() + if(NOT DEFINED NRFS_DIR) + set(NRFS_DIR ${ZEPHYR_CURRENT_MODULE_DIR}/nrfs CACHE PATH "nrfs directory") + endif() + + set(INC_DIR ${NRFS_DIR}/include) + set(SRC_DIR ${NRFS_DIR}/src) + set(HELPERS_DIR ${NRFS_DIR}/helpers) + + zephyr_include_directories(${INC_DIR}) + zephyr_include_directories(${INC_DIR}/services) + zephyr_include_directories(${HELPERS_DIR}) + zephyr_include_directories(.) + zephyr_include_directories(${CMAKE_CURRENT_SOURCE_DIR}/backends) + zephyr_include_directories_ifdef(CONFIG_NRFS_DVFS_LOCAL_DOMAIN ${CMAKE_CURRENT_SOURCE_DIR}/dvfs) + + zephyr_library_sources(${HELPERS_DIR}/dvfs_oppoint.c) + + if(CONFIG_NRFS_LOCAL_DOMAIN) + zephyr_library_sources_ifdef(CONFIG_NRFS_CLOCK_SERVICE_ENABLED ${SRC_DIR}/services/nrfs_clock.c) + zephyr_library_sources_ifdef(CONFIG_NRFS_DIAG_SERVICE_ENABLED ${SRC_DIR}/services/nrfs_diag.c) + zephyr_library_sources_ifdef(CONFIG_NRFS_DVFS_SERVICE_ENABLED ${SRC_DIR}/services/nrfs_dvfs.c) + zephyr_library_sources_ifdef(CONFIG_NRFS_MRAM_SERVICE_ENABLED ${SRC_DIR}/services/nrfs_mram.c) + zephyr_library_sources_ifdef(CONFIG_NRFS_PMIC_SERVICE_ENABLED ${SRC_DIR}/services/nrfs_pmic.c) + zephyr_library_sources_ifdef(CONFIG_NRFS_RESET_SERVICE_ENABLED ${SRC_DIR}/services/nrfs_reset.c) + zephyr_library_sources_ifdef(CONFIG_NRFS_TEMP_SERVICE_ENABLED ${SRC_DIR}/services/nrfs_temp.c) + zephyr_library_sources_ifdef(CONFIG_NRFS_VBUS_DETECTOR_SERVICE_ENABLED ${SRC_DIR}/services/nrfs_usb.c) + zephyr_library_sources(${SRC_DIR}/internal/nrfs_dispatcher.c) + add_subdirectory_ifdef(CONFIG_NRFS_DVFS_LOCAL_DOMAIN dvfs) + + if(CONFIG_NRFS_DIAG_SERVICE_ENABLED) + message(WARNING "This service is for Nordic Semiconductor INTERNAL purposes ONLY. Use it with caution due to risk of hardware damage!") + endif() + endif() + zephyr_library_sources_ifdef(CONFIG_NRFS_LOCAL_DOMAIN backends/nrfs_backend_ipc_service.c) +endif() diff --git a/modules/hal_nordic/nrfs/Kconfig b/modules/hal_nordic/nrfs/Kconfig new file mode 100644 index 00000000000..b4f6715fdd2 --- /dev/null +++ b/modules/hal_nordic/nrfs/Kconfig @@ -0,0 +1,116 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config HAS_NRFS + bool + +menu "nRF Services" + depends on HAS_NRFS + +config NRFS_HAS_CLOCK_SERVICE + bool + +config NRFS_HAS_CONST_LATENCY_SERVICE + bool + +config NRFS_HAS_DIAG_SERVICE + bool + +config NRFS_HAS_DVFS_SERVICE + bool + +config NRFS_HAS_MRAM_SERVICE + bool + +config NRFS_HAS_PMIC_SERVICE + bool + +config NRFS_HAS_RESET_SERVICE + bool + +config NRFS_HAS_TEMP_SERVICE + bool + +config NRFS_HAS_VBUS_DETECTOR_SERVICE + bool + +config NRFS + bool "nRF Services Support" + select NRFS_LOCAL_DOMAIN if (SOC_NRF54H20_CPUAPP || SOC_NRF54H20_CPURAD) + depends on HAS_NRFS + help + This option enables the nRF Services library. + +if NRFS + +config NRFS_LOCAL_DOMAIN + bool "nRF Services Local Domain Support" + depends on $(dt_alias_enabled,ipc-to-cpusys) + select IPC_SERVICE + select MBOX + select EVENTS + select REBOOT + help + This option enables the nRF Services Local Domain libraries. + +config NRFS_DVFS_LOCAL_DOMAIN + bool "Local domain that supports DVFS" + depends on NRFS_LOCAL_DOMAIN + depends on NRFS_DVFS_SERVICE_ENABLED + default y if NRFS_DVFS_SERVICE_ENABLED + +menu "Enabled Services" + +module = NRFS +module-str = nRF-Services +source "subsys/logging/Kconfig.template.log_config" + +config NRFS_RESET_SERVICE_ENABLED + bool "Reset service" + depends on NRFS_HAS_RESET_SERVICE + +config NRFS_MRAM_SERVICE_ENABLED + bool "MRAM latency service" + depends on NRFS_HAS_MRAM_SERVICE + +config NRFS_TEMP_SERVICE_ENABLED + bool "Temperature service" + depends on NRFS_HAS_TEMP_SERVICE + default y + +config NRFS_VBUS_DETECTOR_SERVICE_ENABLED + bool "VBUS detector for the USB peripheral" + depends on NRFS_HAS_VBUS_DETECTOR_SERVICE + default y + +config NRFS_CONST_LATENCY_SERVICE_ENABLED + bool "DPPI constant latency service" + depends on NRFS_HAS_CONST_LATENCY_SERVICE + default y + +config NRFS_PMIC_SERVICE_ENABLED + bool "PMIC service" + depends on NRFS_HAS_PMIC_SERVICE + +config NRFS_DVFS_SERVICE_ENABLED + bool "DVFS service" + depends on NRFS_HAS_DVFS_SERVICE + default y if SOC_NRF54H20_CPUAPP + +config NRFS_DIAG_SERVICE_ENABLED + bool "System Diagnostics service (only for development purposes)" + depends on NRFS_HAS_DIAG_SERVICE + +config NRFS_CLOCK_SERVICE_ENABLED + bool "Clock service" + depends on NRFS_HAS_CLOCK_SERVICE + default y +endmenu + +rsource "backends/Kconfig" +if NRFS_DVFS_LOCAL_DOMAIN +rsource "dvfs/Kconfig" +endif # NRFS_DVFS_LOCAL_DOMAIN + +endif # NRFS +endmenu diff --git a/modules/hal_nordic/nrfs/backends/Kconfig b/modules/hal_nordic/nrfs/backends/Kconfig new file mode 100644 index 00000000000..2dc97ea63ce --- /dev/null +++ b/modules/hal_nordic/nrfs/backends/Kconfig @@ -0,0 +1,28 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + + +menu "NRFS backend settings" + +module = NRFS_BACKEND +module-str = NRFS backend +source "subsys/logging/Kconfig.template.log_config" + +config NRFS_BACKEND_IPC_SERVICE_INIT_PRIO + int "Initialization priority for NRFS IPC backend" + default 51 + help + This should be higher than priority of other drivers/subsystems + used by NRFS backend. For example MBOX_INIT_PRIORITY which is 50. + +config NRFS_MAX_BACKEND_PACKET_SIZE + int "Maximum IPC data packet size in bytes" + range 8 128 + default 32 + +config NRFS_BACKEND_TX_MSG_QUEUE_SIZE + int "Size of TX buffer message queue size" + range 1 16 + default 8 + +endmenu diff --git a/modules/hal_nordic/nrfs/backends/nrfs_backend_ipc_service.c b/modules/hal_nordic/nrfs/backends/nrfs_backend_ipc_service.c new file mode 100644 index 00000000000..172b5957b23 --- /dev/null +++ b/modules/hal_nordic/nrfs/backends/nrfs_backend_ipc_service.c @@ -0,0 +1,226 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "nrfs_backend_ipc_service.h" + +#include +#include + +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(NRFS_BACKEND, CONFIG_NRFS_BACKEND_LOG_LEVEL); + +#define MAX_PACKET_DATA_SIZE (CONFIG_NRFS_MAX_BACKEND_PACKET_SIZE) + +K_MSGQ_DEFINE(ipc_transmit_msgq, sizeof(struct ipc_data_packet), + CONFIG_NRFS_BACKEND_TX_MSG_QUEUE_SIZE, 4); + +static struct k_work backend_send_work; + +static struct ipc_data_packet rx_data; +static struct ipc_data_packet tx_data; + +static void ipc_sysctrl_ept_bound(void *priv); +static void ipc_sysctrl_ept_recv(const void *data, size_t size, void *priv); + +static K_EVENT_DEFINE(ipc_connected_event); + +#define IPC_INIT_DONE_EVENT (0x01) + +struct ipc_channel_config { + const struct device *ipc_instance; + struct ipc_ept_cfg *endpoint_config; + struct ipc_ept ipc_ept; + atomic_t status; + bool enabled; +}; + +static struct ipc_ept_cfg ipc_sysctrl_ept_cfg = { + .name = "ipc_to_sysctrl", + .cb = { + .bound = ipc_sysctrl_ept_bound, + .received = ipc_sysctrl_ept_recv, + }, +}; + +static struct ipc_channel_config ipc_cpusys_channel_config = { + .ipc_instance = DEVICE_DT_GET(DT_ALIAS(ipc_to_cpusys)), + .endpoint_config = &ipc_sysctrl_ept_cfg, + .status = ATOMIC_INIT(NOT_CONNECTED), + .enabled = true +}; + +/** + * @brief nrfs backend error handler + * + * @param error_id The id of an error to handle. + * @param error additional error code if needed, if not needed use 0. + * @param fatal true if fatal error and needs special handling + */ +__weak void nrfs_backend_error_handler(enum nrfs_backend_error error_id, int error, bool fatal) +{ + switch (error_id) { + case NRFS_ERROR_EPT_RECEIVE_DATA_TOO_LONG: + LOG_ERR("Received data is too long. Config error."); + break; + + case NRFS_ERROR_NO_DATA_RECEIVED: + LOG_ERR("No data in received message!"); + break; + + case NRFS_ERROR_IPC_OPEN_INSTANCE: + LOG_ERR("IPC open instance failure with error: %d", error); + break; + + case NRFS_ERROR_IPC_REGISTER_ENDPOINT: + LOG_ERR("IPC register endpoint failure with error: %d", error); + break; + + default: + LOG_ERR("Undefined error id: %d, error cause: %d", error_id, error); + break; + } + + if (fatal) { + nrfs_backend_fatal_error_handler(error_id); + } +} + +static void ipc_sysctrl_ept_bound(void *priv) +{ + LOG_INF("Bound to sysctrl."); + k_event_post(&ipc_connected_event, IPC_INIT_DONE_EVENT); + atomic_set(&ipc_cpusys_channel_config.status, CONNECTED); +} + +static void ipc_sysctrl_ept_recv(const void *data, size_t size, void *priv) +{ + __ASSERT(size <= MAX_PACKET_DATA_SIZE, "Received data is too long. Config error."); + if (size <= MAX_PACKET_DATA_SIZE) { + rx_data.channel_id = IPC_CPUSYS_CHANNEL_ID; + rx_data.size = size; + if (data) { + memcpy(rx_data.data, (uint8_t *)data, size); + nrfs_dispatcher_notify(&rx_data.data, rx_data.size); + } else { + nrfs_backend_error_handler(NRFS_ERROR_NO_DATA_RECEIVED, 0, false); + } + } else { + nrfs_backend_error_handler(NRFS_ERROR_EPT_RECEIVE_DATA_TOO_LONG, 0, true); + } +} + +static void nrfs_backend_send_work(struct k_work *item) +{ + static struct ipc_data_packet data_to_send; + + LOG_DBG("Sending data from workqueue"); + while (k_msgq_get(&ipc_transmit_msgq, &data_to_send, K_NO_WAIT) == 0) { + ipc_service_send(&ipc_cpusys_channel_config.ipc_ept, &tx_data.data, tx_data.size); + } +} + +/** + * @brief Initialize ipc channel + * + * @return -EINVAL when instance configuration is invalid. + * @return -EIO when no backend is registered. + * @return -EALREADY when the instance is already opened (or being opened). + * @return -EBUSY when the instance is busy. + * @return 0 on success + */ +static int ipc_channel_init(void) +{ + struct ipc_channel_config *ch_cfg; + int ret = 0; + + k_work_init(&backend_send_work, nrfs_backend_send_work); + ch_cfg = &ipc_cpusys_channel_config; + + ret = ipc_service_open_instance(ch_cfg->ipc_instance); + if ((ret < 0) && (ret != -EALREADY)) { + nrfs_backend_error_handler(NRFS_ERROR_IPC_OPEN_INSTANCE, ret, false); + return ret; + } + + LOG_INF("ipc_service_open_instance() done."); + + ret = ipc_service_register_endpoint(ch_cfg->ipc_instance, + &ch_cfg->ipc_ept, + ch_cfg->endpoint_config); + if (ret < 0) { + nrfs_backend_error_handler(NRFS_ERROR_IPC_REGISTER_ENDPOINT, ret, false); + return ret; + } + + LOG_INF("ipc_service_register_endpoint() done."); + + return ret; +} + +nrfs_err_t nrfs_backend_send(void *message, size_t size) +{ + return nrfs_backend_send_ex(message, size, K_NO_WAIT, false); +} + +nrfs_err_t nrfs_backend_send_ex(void *message, size_t size, k_timeout_t timeout, bool high_prio) +{ + if (atomic_get(&ipc_cpusys_channel_config.status) != CONNECTED) { + LOG_WRN("Backend not yet connected to sysctrl"); + return NRFS_ERR_INVALID_STATE; + } + + if (size <= MAX_PACKET_DATA_SIZE) { + int err; + + tx_data.channel_id = IPC_CPUSYS_CHANNEL_ID; + tx_data.size = size; + memcpy(tx_data.data, (uint8_t *)message, size); + + err = k_msgq_put(&ipc_transmit_msgq, &tx_data, timeout); + if (err) { + return NRFS_ERR_IPC; + } + + err = k_work_submit(&backend_send_work); + + return err >= 0 ? 0 : NRFS_ERR_IPC; + } + + LOG_ERR("Trying to send %d bytes where max is %d.", size, MAX_PACKET_DATA_SIZE); + + return NRFS_ERR_IPC; +} + +bool nrfs_backend_connected(void) +{ + return atomic_get(&ipc_cpusys_channel_config.status) == CONNECTED; +} + +int nrfs_backend_wait_for_connection(k_timeout_t timeout) +{ + uint32_t events; + + if (nrfs_backend_connected()) { + return 0; + } + + events = k_event_wait(&ipc_connected_event, IPC_INIT_DONE_EVENT, false, timeout); + + return (events == IPC_INIT_DONE_EVENT ? 0 : (-EAGAIN)); +} + +__weak void nrfs_backend_fatal_error_handler(enum nrfs_backend_error error_id) +{ + LOG_ERR("Fatal error: %d rebooting...", error_id); + sys_reboot(SYS_REBOOT_WARM); +} + +SYS_INIT(ipc_channel_init, POST_KERNEL, CONFIG_NRFS_BACKEND_IPC_SERVICE_INIT_PRIO); diff --git a/modules/hal_nordic/nrfs/backends/nrfs_backend_ipc_service.h b/modules/hal_nordic/nrfs/backends/nrfs_backend_ipc_service.h new file mode 100644 index 00000000000..572c05e864c --- /dev/null +++ b/modules/hal_nordic/nrfs/backends/nrfs_backend_ipc_service.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef NRFS_BACKEND_IPC_SERVICE_H +#define NRFS_BACKEND_IPC_SERVICE_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct __packed ipc_data_packet { + uint16_t channel_id; + uint16_t size; + uint8_t data[CONFIG_NRFS_MAX_BACKEND_PACKET_SIZE]; +}; + +enum ipc_channel_status { + NOT_CONNECTED = 0, + CONNECTED = 1 +}; + +enum nrfs_backend_error { + NRFS_ERROR_EPT_RECEIVE_QUEUE_ERROR = 0, + NRFS_ERROR_EPT_RECEIVE_DATA_TOO_LONG, + NRFS_ERROR_IPC_CHANNEL_INIT, + NRFS_ERROR_SEND_DATA, + NRFS_ERROR_NO_DATA_RECEIVED, + NRFS_ERROR_IPC_OPEN_INSTANCE, + NRFS_ERROR_IPC_REGISTER_ENDPOINT, + NRFS_ERROR_BACKEND_NOT_CONNECTED, + NRFS_ERROR_COUNT +}; + +#define IPC_CPUSYS_CHANNEL_ID 0x5C + +/** + * @brief function to check if backend is connected to sysctrl + * + * @return true Backend connected. + * @return false Backend not connected. + */ +bool nrfs_backend_connected(void); + +/** + * @brief this function will block until connection or timeout expires + * + * @param timeout + * + * @return 0 Connection done. + * @return -EAGAIN Waiting period timed out. + */ +int nrfs_backend_wait_for_connection(k_timeout_t timeout); + +/** + * @brief Extended function for sending a message over the chosen transport backend. + * + * This function is used by services to send requests to the System Controller. + * + * @param[in] message Pointer to the message payload. + * @param[in] size Message payload size. + * @param[in] timeout Non-negative waiting period to add the message, + * or one of the special values K_NO_WAIT and K_FOREVER. + * @param[in] high_prio True if message should be sent with higher priority. + * + * @retval NRFS_SUCCESS Message sent successfully. + * @retval NRFS_ERR_IPC Backend returned error during message sending. + */ +nrfs_err_t nrfs_backend_send_ex(void *message, size_t size, k_timeout_t timeout, bool high_prio); + +/** + * @brief Fatal error handler for unrecoverable errors + * + * This is weak function so it can be overridden if needed. + * Error is considered fatal when there is no option to send message to sysctrl + * even after retry. Communication with sysctrl is crucial for system to work properly. + * + * @param error_id parameter to identify error. + */ +void nrfs_backend_fatal_error_handler(enum nrfs_backend_error error_id); + +#ifdef __cplusplus +} +#endif + +#endif /* NRFS_BACKEND_IPC_SERVICE_H */ diff --git a/modules/hal_nordic/nrfs/dvfs/CMakeLists.txt b/modules/hal_nordic/nrfs/dvfs/CMakeLists.txt new file mode 100644 index 00000000000..4512a91b36a --- /dev/null +++ b/modules/hal_nordic/nrfs/dvfs/CMakeLists.txt @@ -0,0 +1,5 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library_sources_ifdef(CONFIG_NRFS_DVFS_LOCAL_DOMAIN ld_dvfs.c + ld_dvfs_handler.c) diff --git a/modules/hal_nordic/nrfs/dvfs/Kconfig b/modules/hal_nordic/nrfs/dvfs/Kconfig new file mode 100644 index 00000000000..0a6078a0db0 --- /dev/null +++ b/modules/hal_nordic/nrfs/dvfs/Kconfig @@ -0,0 +1,40 @@ +# +# Copyright (c) 2024 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +menu "Local domain DVFS library" + +module = LOCAL_DOMAIN_DVFS_LIB +module-str = Local domain DVFS library +source "subsys/logging/Kconfig.template.log_config" + +config NRFS_LOCAL_DOMAIN_DVFS_TEST + bool "Local domain DVFS test" + help + Disable hw registers interaction for testing. + +config NRFS_LOCAL_DOMAIN_DVFS_SCALE_DOWN_AFTER_INIT + bool "Local domain scale down after init" + help + Request lowest oppoint after DVFS initialization. + +config NRFS_LOCAL_DOMAIN_DOWNSCALE_SAFETY_TIMEOUT_US + int "Voltage downscale procedure safety timeout in us" + range 1 10000000 + default 1000000 if (NRFS_LOCAL_DOMAIN_DVFS_TEST || LOG) + default 1500 + +config NRFS_LOCAL_DOMAIN_DVFS_HANDLER_TASK_STACK_SIZE + int "Stack size used for DVFS handling task" + range 256 2048 + default 1024 if LOG + default 512 + +config NRFS_LOCAL_DOMAIN_DVFS_HANDLER_TASK_PRIORITY + int "Priority of DVFS handling task" + range -16 NUM_PREEMPT_PRIORITIES + default 0 + +endmenu diff --git a/modules/hal_nordic/nrfs/dvfs/ld_dvfs.c b/modules/hal_nordic/nrfs/dvfs/ld_dvfs.c new file mode 100644 index 00000000000..883161e9f92 --- /dev/null +++ b/modules/hal_nordic/nrfs/dvfs/ld_dvfs.c @@ -0,0 +1,354 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "ld_dvfs.h" + +#include +#include + +#include +#include +LOG_MODULE_REGISTER(LD_DVFS_LIB, CONFIG_LOCAL_DOMAIN_DVFS_LIB_LOG_LEVEL); + +#define TRANSIENT_ZBB_ABB_SLOT 0 +#define CURR_TARG_ABB_SLOT 1 +#define LD_ABB_CLR_ZBB 0 +/* TODO: this values needs to be provided by HW team */ +/* for now reset value will be used */ +#define LD_ABB_CTRL4_NORMAL_OPERATION 0x10800UL +#define LD_ABB_CTRL4_TRANSITION_OPERATION 0x10800UL + +/* + * wait max 500ms with 10us intervals for hsfll freq change event + */ +#define HSFLL_FREQ_CHANGE_MAX_DELAY_MS 500UL +#define HSFLL_FREQ_CHANGE_CHECK_INTERVAL_US 10 +#define HSFLL_FREQ_CHANGE_CHECK_MAX_ATTEMPTS \ + ((HSFLL_FREQ_CHANGE_MAX_DELAY_MS) * (USEC_PER_MSEC) / (HSFLL_FREQ_CHANGE_CHECK_INTERVAL_US)) + +#define ABB_STATUS_CHANGE_MAX_DELAY_MS 5000UL +#define ABB_STATUS_CHANGE_CHECK_INTERVAL_US 10 +#define ABB_STATUS_CHANGE_CHECK_MAX_ATTEMPTS \ + ((ABB_STATUS_CHANGE_MAX_DELAY_MS) * (USEC_PER_MSEC) / (ABB_STATUS_CHANGE_CHECK_INTERVAL_US)) + +void ld_dvfs_init(void) +{ +#if defined(NRF_SECURE) + + const struct dvfs_oppoint_data *opp_data = get_dvfs_oppoint_data(DVFS_FREQ_HIGH); + +#if defined(CONFIG_NRFS_LOCAL_DOMAIN_DVFS_TEST) + LOG_DBG("%s", __func__); + LOG_DBG("REGW: NRF_ABB->TRIM.RINGO[%d] 0x%x, V: 0x%x", + CURR_TARG_ABB_SLOT, + (uint32_t)&NRF_ABB->TRIM.RINGO[CURR_TARG_ABB_SLOT], + opp_data->abb_ringo); + LOG_DBG("REGW: NRF_ABB->TRIM.LOCKRANGE[%d] 0x%x, V: 0x%x", + CURR_TARG_ABB_SLOT, + (uint32_t)&NRF_ABB->TRIM.LOCKRANGE[CURR_TARG_ABB_SLOT], + opp_data->abb_lockrange); + LOG_DBG("REGW: NRF_ABB->TRIM.PVTMONCYCLES[%d] 0x%x, V: 0x%x", + CURR_TARG_ABB_SLOT, + (uint32_t)&NRF_ABB->TRIM.PVTMONCYCLES[CURR_TARG_ABB_SLOT], + opp_data->abb_pvtmoncycles); + + /*For app core.*/ + LOG_DBG("REGW: NRF_APPLICATION_ABB->TRIM.RINGO[%d] 0x%x, V: 0x%x", + CURR_TARG_ABB_SLOT, + (uint32_t)&NRF_APPLICATION_ABB->TRIM.RINGO[CURR_TARG_ABB_SLOT], + opp_data->abb_ringo); + LOG_DBG("REGW: NRF_APPLICATION_ABB->TRIM.LOCKRANGE[%d] 0x%x, V: 0x%x", + CURR_TARG_ABB_SLOT, + (uint32_t)&NRF_APPLICATION_ABB->TRIM.LOCKRANGE[CURR_TARG_ABB_SLOT], + opp_data->abb_lockrange); + LOG_DBG("REGW: NRF_APPLICATION_ABB->TRIM.PVTMONCYCLES[%d] 0x%x, V: 0x%x", + CURR_TARG_ABB_SLOT, + (uint32_t)&NRF_APPLICATION_ABB->TRIM.PVTMONCYCLES[CURR_TARG_ABB_SLOT], + opp_data->abb_pvtmoncycles); +#else + /* TODO: Change to NRFX Hal function when available. */ + NRF_ABB->TRIM.RINGO[CURR_TARG_ABB_SLOT] = opp_data->abb_ringo; + NRF_ABB->TRIM.LOCKRANGE[CURR_TARG_ABB_SLOT] = opp_data->abb_lockrange; + NRF_ABB->TRIM.PVTMONCYCLES[CURR_TARG_ABB_SLOT] = opp_data->abb_pvtmoncycles; + + NRF_APPLICATION_ABB->TRIM.RINGO[CURR_TARG_ABB_SLOT] = opp_data->abb_ringo; + NRF_APPLICATION_ABB->TRIM.LOCKRANGE[CURR_TARG_ABB_SLOT] = opp_data->abb_lockrange; + NRF_APPLICATION_ABB->TRIM.PVTMONCYCLES[CURR_TARG_ABB_SLOT] = opp_data->abb_pvtmoncycles; +#endif +#endif +} + +void ld_dvfs_clear_zbb(void) +{ +#if defined(NRF_SECURE) +#if defined(CONFIG_NRFS_LOCAL_DOMAIN_DVFS_TEST) + LOG_DBG("%s", __func__); + LOG_DBG("REGW: NRF_ABB->CONFIG.CTRL1.MODE 0x%x, V: 0x%x", + (uint32_t)&NRF_ABB->CONFIG.CTRL1, + LD_ABB_CLR_ZBB); +#else + /* TODO: Change to NRFX Hal function when available. */ + NRF_ABB->CONFIG.CTRL1 &= ~(ABB_CONFIG_CTRL1_MODE_Msk); + NRF_APPLICATION_ABB->CONFIG.CTRL1 &= ~(ABB_CONFIG_CTRL1_MODE_Msk); +#endif +#endif +} + +#if defined(NRF_SECURE) + +#define DOWNSCALE_SAFETY_TIMEOUT (K_USEC(CONFIG_NRFS_LOCAL_DOMAIN_DOWNSCALE_SAFETY_TIMEOUT_US)) + +atomic_t increased_power_consumption; + +/** + * @brief Secure domain needs to check if downscale is done in defined time + * window. This is needed to avoid battery drain if dvfs procedure + * takes to much time (some failure?). + */ +__weak void ld_dvfs_secure_downscale_timeout(struct k_timer *timer) +{ + ARG_UNUSED(timer); + + LOG_ERR("Downscale timeout expired, reset board."); + atomic_set(&increased_power_consumption, 0); +} + +K_TIMER_DEFINE(dvfs_downscale_secure_timer, ld_dvfs_secure_downscale_timeout, NULL); + +/** + * @brief Secure domain starts increased power consumption, needed by dvfs sequence. + * This function can be reimplemented in other module if needed. + */ +__weak void ld_dvfs_secure_start_increased_power_consumption(void) +{ + LOG_INF("Start increased power consumption for DVFS sequence and start safety timer."); + k_timer_start(&dvfs_downscale_secure_timer, DOWNSCALE_SAFETY_TIMEOUT, K_NO_WAIT); + atomic_set(&increased_power_consumption, 1); + + volatile uint8_t idle_counter = 0; + + while (atomic_get(&increased_power_consumption)) { + if (idle_counter < 100) { + k_yield(); + idle_counter++; + } else { + idle_counter = 0; + k_usleep(1); + } + } +} + +/** + * @brief Secure domain stops increased power consumption at the end of downscale. + * This function can be reimplemented in other module if needed. + */ +__weak void ld_dvfs_secure_stop_increased_power_consumption(void) +{ + LOG_INF("Stop increased power consumption for DVFS sequence."); + k_timer_stop(&dvfs_downscale_secure_timer); + atomic_set(&increased_power_consumption, 0); +} + +#endif + +void ld_dvfs_configure_abb_for_transition(enum dvfs_frequency_setting transient_opp, + enum dvfs_frequency_setting curr_targ_opp) +{ +#if defined(NRF_SECURE) + const struct dvfs_oppoint_data *opp_data = get_dvfs_oppoint_data(transient_opp); + +#if defined(CONFIG_NRFS_LOCAL_DOMAIN_DVFS_TEST) + LOG_DBG("%s", __func__); + LOG_DBG("transient_opp: %d, curr_targ_opp: %d", transient_opp, curr_targ_opp); + LOG_DBG("REGW: NRF_ABB->TRIM.RINGO[%d] 0x%x, V: 0x%x", + TRANSIENT_ZBB_ABB_SLOT, + (uint32_t)&NRF_ABB->TRIM.RINGO[TRANSIENT_ZBB_ABB_SLOT], + opp_data->abb_ringo); + LOG_DBG("REGW: NRF_ABB->TRIM.LOCKRANGE[%d] 0x%x, V: 0x%x", + TRANSIENT_ZBB_ABB_SLOT, + (uint32_t)&NRF_ABB->TRIM.LOCKRANGE[TRANSIENT_ZBB_ABB_SLOT], + opp_data->abb_lockrange); + LOG_DBG("REGW: NRF_ABB->TRIM.PVTMONCYCLES[%d] 0x%x, V: 0x%x", + TRANSIENT_ZBB_ABB_SLOT, + (uint32_t)&NRF_ABB->TRIM.PVTMONCYCLES[TRANSIENT_ZBB_ABB_SLOT], + opp_data->abb_pvtmoncycles); + + /* For app core.*/ + LOG_DBG("REGW: NRF_APPLICATION_ABB->TRIM.RINGO[%d] 0x%x, V: 0x%x", + TRANSIENT_ZBB_ABB_SLOT, + (uint32_t)&NRF_APPLICATION_ABB->TRIM.RINGO[TRANSIENT_ZBB_ABB_SLOT], + opp_data->abb_ringo); + LOG_DBG("REGW: NRF_APPLICATION_ABB->TRIM.LOCKRANGE[%d] 0x%x, V: 0x%x", + TRANSIENT_ZBB_ABB_SLOT, + (uint32_t)&NRF_APPLICATION_ABB->TRIM.LOCKRANGE[TRANSIENT_ZBB_ABB_SLOT], + opp_data->abb_lockrange); + LOG_DBG("REGW: NRF_APPLICATION_ABB->TRIM.PVTMONCYCLES[%d] 0x%x, V: 0x%x", + TRANSIENT_ZBB_ABB_SLOT, + (uint32_t)&NRF_APPLICATION_ABB->TRIM.PVTMONCYCLES[TRANSIENT_ZBB_ABB_SLOT], + opp_data->abb_pvtmoncycles); +#else + + NRF_ABB->TRIM.RINGO[TRANSIENT_ZBB_ABB_SLOT] = opp_data->abb_ringo; + NRF_ABB->TRIM.LOCKRANGE[TRANSIENT_ZBB_ABB_SLOT] = opp_data->abb_lockrange; + NRF_ABB->TRIM.PVTMONCYCLES[TRANSIENT_ZBB_ABB_SLOT] = opp_data->abb_pvtmoncycles; + + NRF_APPLICATION_ABB->TRIM.RINGO[TRANSIENT_ZBB_ABB_SLOT] = opp_data->abb_ringo; + NRF_APPLICATION_ABB->TRIM.LOCKRANGE[TRANSIENT_ZBB_ABB_SLOT] = opp_data->abb_lockrange; + NRF_APPLICATION_ABB->TRIM.PVTMONCYCLES[TRANSIENT_ZBB_ABB_SLOT] = opp_data->abb_pvtmoncycles; +#endif + opp_data = get_dvfs_oppoint_data(curr_targ_opp); + +#if defined(CONFIG_NRFS_LOCAL_DOMAIN_DVFS_TEST) + LOG_DBG("REGW: NRF_ABB->TRIM.RINGO[%d] 0x%x, V: 0x%x", + CURR_TARG_ABB_SLOT, + (uint32_t)&NRF_ABB->TRIM.RINGO[CURR_TARG_ABB_SLOT], + opp_data->abb_ringo); + LOG_DBG("REGW: NRF_ABB->TRIM.LOCKRANGE[%d] 0x%x, V: 0x%x", + CURR_TARG_ABB_SLOT, + (uint32_t)&NRF_ABB->TRIM.LOCKRANGE[CURR_TARG_ABB_SLOT], + opp_data->abb_lockrange); + LOG_DBG("REGW: NRF_ABB->TRIM.PVTMONCYCLES[%d] 0x%x, V: 0x%x", + CURR_TARG_ABB_SLOT, + (uint32_t)&NRF_ABB->TRIM.PVTMONCYCLES[CURR_TARG_ABB_SLOT], + opp_data->abb_pvtmoncycles); + + LOG_DBG("REGW: TODO: NRF_ABB->CONFIG.CTRL4 0x%x, V: 0x%lx", + (uint32_t)&NRF_ABB->CONFIG.CTRL4, + LD_ABB_CTRL4_TRANSITION_OPERATION); + + /* For app core */ + LOG_DBG("REGW: NRF_APPLICATION_ABB->TRIM.RINGO[%d] 0x%x, V: 0x%x", + CURR_TARG_ABB_SLOT, + (uint32_t)&NRF_APPLICATION_ABB->TRIM.RINGO[CURR_TARG_ABB_SLOT], + opp_data->abb_ringo); + LOG_DBG("REGW: NRF_APPLICATION_ABB->TRIM.LOCKRANGE[%d] 0x%x, V: 0x%x", + CURR_TARG_ABB_SLOT, + (uint32_t)&NRF_APPLICATION_ABB->TRIM.LOCKRANGE[CURR_TARG_ABB_SLOT], + opp_data->abb_lockrange); + LOG_DBG("REGW: NRF_APPLICATION_ABB->TRIM.PVTMONCYCLES[%d] 0x%x, V: 0x%x", + CURR_TARG_ABB_SLOT, + (uint32_t)&NRF_APPLICATION_ABB->TRIM.PVTMONCYCLES[CURR_TARG_ABB_SLOT], + opp_data->abb_pvtmoncycles); + + LOG_DBG("REGW: TODO: NRF_APPLICATION_ABB->CONFIG.CTRL4 0x%x, V: 0x%lx", + (uint32_t)&NRF_APPLICATION_ABB->CONFIG.CTRL4, + LD_ABB_CTRL4_TRANSITION_OPERATION); +#else + NRF_ABB->TRIM.RINGO[CURR_TARG_ABB_SLOT] = opp_data->abb_ringo; + NRF_ABB->TRIM.LOCKRANGE[CURR_TARG_ABB_SLOT] = opp_data->abb_lockrange; + NRF_ABB->TRIM.PVTMONCYCLES[CURR_TARG_ABB_SLOT] = opp_data->abb_pvtmoncycles; + + NRF_ABB->CONFIG.CTRL4 = LD_ABB_CTRL4_TRANSITION_OPERATION; + + NRF_APPLICATION_ABB->TRIM.RINGO[CURR_TARG_ABB_SLOT] = opp_data->abb_ringo; + NRF_APPLICATION_ABB->TRIM.LOCKRANGE[CURR_TARG_ABB_SLOT] = opp_data->abb_lockrange; + NRF_APPLICATION_ABB->TRIM.PVTMONCYCLES[CURR_TARG_ABB_SLOT] = opp_data->abb_pvtmoncycles; + + NRF_APPLICATION_ABB->CONFIG.CTRL4 = LD_ABB_CTRL4_TRANSITION_OPERATION; + +#endif +#endif +} + +int32_t ld_dvfs_configure_hsfll(enum dvfs_frequency_setting oppoint) +{ + nrf_hsfll_trim_t hsfll_trim = {}; + + if (oppoint >= DVFS_FREQ_COUNT) { + LOG_ERR("Not valid oppoint %d", oppoint); + return -EINVAL; + } + + uint8_t freq_trim = get_dvfs_oppoint_data(oppoint)->new_f_trim_entry; + +#ifdef CONFIG_SOC_NRF54H20_CPUAPP + hsfll_trim.vsup = NRF_FICR->TRIM.APPLICATION.HSFLL.TRIM.VSUP; + hsfll_trim.coarse = NRF_FICR->TRIM.APPLICATION.HSFLL.TRIM.COARSE[freq_trim]; + hsfll_trim.fine = NRF_FICR->TRIM.APPLICATION.HSFLL.TRIM.FINE[freq_trim]; +#else + hsfll_trim.vsup = NRF_FICR->TRIM.SECURE.HSFLL.TRIM.VSUP; + hsfll_trim.coarse = NRF_FICR->TRIM.SECURE.HSFLL.TRIM.COARSE[freq_trim]; + hsfll_trim.fine = NRF_FICR->TRIM.SECURE.HSFLL.TRIM.FINE[freq_trim]; +#endif + +#if defined(CONFIG_NRFS_LOCAL_DOMAIN_DVFS_TEST) + LOG_DBG("%s oppoint: %d", __func__, oppoint); + LOG_DBG("REGW: NRF_HSFLL->MIRROR 0x%x, V: 0x%x", (uint32_t)&NRF_HSFLL->MIRROR, 1); + LOG_DBG("REGW: NRF_HSFLL->TRIM.COARSE 0x%x, V: 0x%x", + (uint32_t)&NRF_HSFLL->TRIM.COARSE, + hsfll_trim.coarse); + LOG_DBG("REGW: NRF_HSFLL->TRIM.FINE 0x%x, V: 0x%x", + (uint32_t)&NRF_HSFLL->TRIM.FINE, + hsfll_trim.fine); + LOG_DBG("REGW: NRF_HSFLL->MIRROR 0x%x, V: 0x%x", (uint32_t)&NRF_HSFLL->MIRROR, 0); + + LOG_DBG("REGW: NRF_HSFLL->CLOCKCTRL.MULT 0x%x, V: 0x%x", + (uint32_t)&NRF_HSFLL->CLOCKCTRL.MULT, + get_dvfs_oppoint_data(oppoint)->new_f_mult); + + LOG_DBG("REGW: NRF_HSFLL->NRF_HSFLL_TASK_FREQ_CHANGE 0x%x, V: 0x%x", + (uint32_t)NRF_HSFLL + NRF_HSFLL_TASK_FREQ_CHANGE, + 0x1); + return 0; +#else + + nrf_hsfll_trim_set(NRF_HSFLL, &hsfll_trim); + nrf_barrier_w(); + + nrf_hsfll_clkctrl_mult_set(NRF_HSFLL, get_dvfs_oppoint_data(oppoint)->new_f_mult); + nrf_hsfll_task_trigger(NRF_HSFLL, NRF_HSFLL_TASK_FREQ_CHANGE); + /* Trigger hsfll task one more time, SEE PAC-4078 */ + nrf_hsfll_task_trigger(NRF_HSFLL, NRF_HSFLL_TASK_FREQ_CHANGE); + + bool hsfll_freq_changed = false; + + NRFX_WAIT_FOR(nrf_hsfll_event_check(NRF_HSFLL, NRF_HSFLL_EVENT_FREQ_CHANGED), + HSFLL_FREQ_CHANGE_CHECK_MAX_ATTEMPTS, + HSFLL_FREQ_CHANGE_CHECK_INTERVAL_US, + hsfll_freq_changed); + + if (hsfll_freq_changed) { + return 0; + } + + return -ETIMEDOUT; +#endif +} + +void ld_dvfs_scaling_background_process(bool downscaling) +{ +#if defined(NRF_SECURE) + if (NRF_DOMAIN == NRF_DOMAIN_SECURE) { + if (downscaling) { + ld_dvfs_secure_start_increased_power_consumption(); + } + } +#endif +} + +void ld_dvfs_scaling_finish(bool downscaling) +{ +#if defined(NRF_SECURE) +#if defined(CONFIG_NRFS_LOCAL_DOMAIN_DVFS_TEST) + LOG_DBG("%s", __func__); + LOG_DBG("REGW: NRF_ABB->CONFIG.CTRL4 0x%x, V: 0x%lx", + (uint32_t)&NRF_ABB->CONFIG.CTRL4, + LD_ABB_CTRL4_NORMAL_OPERATION); + LOG_DBG("REGW: NRF_APPLICATION_ABB->CONFIG.CTRL4 0x%x, V: 0x%lx", + (uint32_t)&NRF_APPLICATION_ABB->CONFIG.CTRL4, + LD_ABB_CTRL4_NORMAL_OPERATION); +#else + NRF_ABB->CONFIG.CTRL4 = LD_ABB_CTRL4_NORMAL_OPERATION; + NRF_APPLICATION_ABB->CONFIG.CTRL4 = LD_ABB_CTRL4_NORMAL_OPERATION; +#endif + + if (NRF_DOMAIN == NRF_DOMAIN_SECURE) { + if (downscaling) { + ld_dvfs_secure_stop_increased_power_consumption(); + } + } +#endif +} diff --git a/modules/hal_nordic/nrfs/dvfs/ld_dvfs.h b/modules/hal_nordic/nrfs/dvfs/ld_dvfs.h new file mode 100644 index 00000000000..947a9b5a1af --- /dev/null +++ b/modules/hal_nordic/nrfs/dvfs/ld_dvfs.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef LD_DVFS_H +#define LD_DVFS_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Function for initializing the Dynamic Voltage and Frequency Scaling service + * from LD perspective.. + * + */ +void ld_dvfs_init(void); + +/** + * @brief Function for clearing the zero bias + * + */ +void ld_dvfs_clear_zbb(void); + +/** + * @brief Configure ABB registers to transition process. + * + * @param transient_opp current operation point + * @param curr_targ_opp target operation point + */ +void ld_dvfs_configure_abb_for_transition(enum dvfs_frequency_setting transient_opp, + enum dvfs_frequency_setting curr_targ_opp); + +/** + * @brief Configure hsfll depending on selected oppoint + * + * @param enum oppoint target operation point + * @return 0 value indicates no error. + * @return -EINVAL invalid oppoint or domain. + * @return -ETIMEDOUT frequency change took more than HSFLL_FREQ_CHANGE_MAX_DELAY_MS + */ +int32_t ld_dvfs_configure_hsfll(enum dvfs_frequency_setting oppoint); + +/** + * @brief Background process during scaling. + * + * @param downscaling indicates if down-scaling is running + */ +void ld_dvfs_scaling_background_process(bool downscaling); + +/** + * @brief Last step for local domain in downscale procedure + * + * @param downscaling indicates if down-scaling is running + */ +void ld_dvfs_scaling_finish(bool downscaling); + +#ifdef __cplusplus +} +#endif + +#endif /* LD_DVFS_H */ diff --git a/modules/hal_nordic/nrfs/dvfs/ld_dvfs_handler.c b/modules/hal_nordic/nrfs/dvfs/ld_dvfs_handler.c new file mode 100644 index 00000000000..20e879c4f73 --- /dev/null +++ b/modules/hal_nordic/nrfs/dvfs/ld_dvfs_handler.c @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "ld_dvfs_handler.h" +#include "ld_dvfs.h" + +#include +#include +#include + +#include +#include +LOG_MODULE_DECLARE(LD_DVFS_LIB, CONFIG_LOCAL_DOMAIN_DVFS_LIB_LOG_LEVEL); + +static K_SEM_DEFINE(dvfs_service_sync_sem, 0, 1); +static K_SEM_DEFINE(dvfs_service_idle_sem, 0, 1); + +#define DVFS_SERV_HDL_INIT_DONE_BIT_POS (0) +#define DVFS_SERV_HDL_FREQ_CHANGE_IN_PROGRESS_BIT_POS (1) + +static atomic_t dvfs_service_handler_state_bits; +static enum dvfs_frequency_setting current_freq_setting; + +static void dvfs_service_handler_set_state_bit(uint32_t bit_pos) +{ + atomic_set_bit(&dvfs_service_handler_state_bits, bit_pos); +} + +static void dvfs_service_handler_clear_state_bit(uint32_t bit_pos) +{ + atomic_clear_bit(&dvfs_service_handler_state_bits, bit_pos); +} + +static bool dvfs_service_handler_get_state_bit(uint32_t bit_pos) +{ + return atomic_test_bit(&dvfs_service_handler_state_bits, bit_pos); +} + +static bool dvfs_service_handler_init_done(void) +{ + return dvfs_service_handler_get_state_bit(DVFS_SERV_HDL_INIT_DONE_BIT_POS); +} + +static bool dvfs_service_handler_freq_change_in_progress(void) +{ + return dvfs_service_handler_get_state_bit(DVFS_SERV_HDL_FREQ_CHANGE_IN_PROGRESS_BIT_POS); +} + +static void dvfs_service_handler_nrfs_error_check(nrfs_err_t err) +{ + if (err != NRFS_SUCCESS) { + LOG_ERR("Failed with nrfs error: %d", err); + } +} + +static void dvfs_service_handler_error(int err) +{ + if (err != 0) { + LOG_ERR("Failed with error: %d", err); + } +} + +static uint32_t *get_next_context(void) +{ + static uint32_t ctx; + + ctx++; + return &ctx; +} + +static bool dvfs_service_handler_freq_setting_allowed(enum dvfs_frequency_setting freq_setting) +{ + if (freq_setting == DVFS_FREQ_HIGH || freq_setting == DVFS_FREQ_MEDLOW || + freq_setting == DVFS_FREQ_LOW) { + return true; + } + + return false; +} + +static enum dvfs_frequency_setting dvfs_service_handler_get_current_oppoint(void) +{ + LOG_INF("Current LD freq setting: %d", current_freq_setting); + return current_freq_setting; +} + +/* Function to check if current operation is down-scaling */ +static bool dvfs_service_handler_is_downscaling(enum dvfs_frequency_setting target_freq_setting) +{ + if (dvfs_service_handler_freq_setting_allowed(target_freq_setting)) { + LOG_DBG("Checking if downscaling %s", + (dvfs_service_handler_get_current_oppoint() < target_freq_setting) ? "YES" : + "NO"); + return dvfs_service_handler_get_current_oppoint() < target_freq_setting; + } + + return false; +} + +/* Function handling steps for scaling preparation. */ +static void dvfs_service_handler_prepare_to_scale(enum dvfs_frequency_setting oppoint_freq) +{ + LOG_INF("Prepare to scale, oppoint freq %d", oppoint_freq); + enum dvfs_frequency_setting new_oppoint = oppoint_freq; + enum dvfs_frequency_setting current_oppoint = dvfs_service_handler_get_current_oppoint(); + + if (new_oppoint == current_oppoint) { + LOG_INF("New oppoint is same as previous, no change"); + } else { + ld_dvfs_configure_abb_for_transition(current_oppoint, new_oppoint); + + if (dvfs_service_handler_is_downscaling(new_oppoint)) { + int32_t err = ld_dvfs_configure_hsfll(new_oppoint); + + if (err != 0) { + dvfs_service_handler_error(err); + } + } + } +} + +/* Do background job during scaling process (e.g. increased power consumption during down-scale). */ +static void dvfs_service_handler_scaling_background_job(enum dvfs_frequency_setting oppoint_freq) +{ + LOG_INF("Perform scaling background job if needed."); + if (dvfs_service_handler_is_downscaling(oppoint_freq)) { + k_sem_give(&dvfs_service_idle_sem); + } +} + +/* Perform scaling finnish procedure. */ +static void dvfs_service_handler_scaling_finish(enum dvfs_frequency_setting oppoint_freq) +{ + LOG_INF("Scaling finnish oppoint freq %d", oppoint_freq); + ld_dvfs_scaling_finish(dvfs_service_handler_is_downscaling(oppoint_freq)); + if (!dvfs_service_handler_is_downscaling(oppoint_freq)) { + int32_t err = ld_dvfs_configure_hsfll(oppoint_freq); + + if (err != 0) { + dvfs_service_handler_error(err); + } + } + current_freq_setting = oppoint_freq; +} + +/* Function to set hsfll to highest frequency when switched to ABB. */ +static void dvfs_service_handler_set_initial_hsfll_config(void) +{ + int32_t err = ld_dvfs_configure_hsfll(DVFS_FREQ_HIGH); + + current_freq_setting = DVFS_FREQ_HIGH; + if (err != 0) { + dvfs_service_handler_error(err); + } +} + +/* DVFS event handler callback function.*/ +static void nrfs_dvfs_evt_handler(nrfs_dvfs_evt_t const *p_evt, void *context) +{ + LOG_INF("%s", __func__); + switch (p_evt->type) { + case NRFS_DVFS_EVT_INIT_PREPARATION: + LOG_INF("DVFS handler EVT_INIT_PREPARATION"); +#if defined(NRF_SECURE) + ld_dvfs_clear_zbb(); + dvfs_service_handler_nrfs_error_check( + nrfs_dvfs_init_complete_request(get_next_context())); + LOG_INF("DVFS handler EVT_INIT_PREPARATION handled"); +#else + LOG_ERR("DVFS handler - unexpected EVT_INIT_PREPARATION"); +#endif + break; + case NRFS_DVFS_EVT_INIT_DONE: + LOG_INF("DVFS handler EVT_INIT_DONE"); + dvfs_service_handler_set_initial_hsfll_config(); + dvfs_service_handler_set_state_bit(DVFS_SERV_HDL_INIT_DONE_BIT_POS); + k_sem_give(&dvfs_service_sync_sem); + LOG_INF("DVFS handler EVT_INIT_DONE handled"); + break; + case NRFS_DVFS_EVT_OPPOINT_REQ_CONFIRMED: + /* Optional confirmation from sysctrl, wait for oppoint.*/ + LOG_INF("DVFS handler EVT_OPPOINT_REQ_CONFIRMED"); + break; + case NRFS_DVFS_EVT_OPPOINT_SCALING_PREPARE: + /*Target oppoint will be received here.*/ + LOG_INF("DVFS handler EVT_OPPOINT_SCALING_PREPARE"); +#if !defined(NRF_SECURE) + if (dvfs_service_handler_is_downscaling(p_evt->freq)) { +#endif + dvfs_service_handler_prepare_to_scale(p_evt->freq); + dvfs_service_handler_nrfs_error_check( + nrfs_dvfs_ready_to_scale(get_next_context())); + dvfs_service_handler_scaling_background_job(p_evt->freq); + LOG_INF("DVFS handler EVT_OPPOINT_SCALING_PREPARE handled"); +#if !defined(NRF_SECURE) + current_freq_setting = p_evt->freq; + } else { + LOG_ERR("DVFS handler - unexpected EVT_OPPOINT_SCALING_PREPARE"); + } +#endif + break; + case NRFS_DVFS_EVT_OPPOINT_SCALING_DONE: + LOG_INF("DVFS handler EVT_OPPOINT_SCALING_DONE"); + dvfs_service_handler_clear_state_bit(DVFS_SERV_HDL_FREQ_CHANGE_IN_PROGRESS_BIT_POS); + dvfs_service_handler_scaling_finish(p_evt->freq); + LOG_INF("DVFS handler EVT_OPPOINT_SCALING_DONE handled"); + break; + case NRFS_DVFS_EVT_REJECT: + LOG_ERR("DVFS handler - request rejected"); + break; + default: + LOG_ERR("DVFS handler - unexpected event: 0x%x", p_evt->type); + break; + } +} + +/* Task to handle dvfs init procedure. */ +static void dvfs_service_handler_task(void *dummy0, void *dummy1, void *dummy2) +{ + ARG_UNUSED(dummy0); + ARG_UNUSED(dummy1); + ARG_UNUSED(dummy2); + + LOG_INF("Trim ABB for default voltage."); + ld_dvfs_init(); + + LOG_INF("Waiting for backend init"); + /* Wait for ipc initialization */ + nrfs_backend_wait_for_connection(K_FOREVER); + + nrfs_err_t status; + + LOG_INF("nrfs_dvfs_init"); + status = nrfs_dvfs_init(nrfs_dvfs_evt_handler); + dvfs_service_handler_nrfs_error_check(status); + + LOG_INF("nrfs_dvfs_init_prepare_request"); + status = nrfs_dvfs_init_prepare_request(get_next_context()); + dvfs_service_handler_nrfs_error_check(status); + + /* Wait for init*/ + k_sem_take(&dvfs_service_sync_sem, K_FOREVER); + + LOG_INF("DVFS init done."); + +#if defined(CONFIG_NRFS_LOCAL_DOMAIN_DVFS_SCALE_DOWN_AFTER_INIT) + LOG_INF("Requesting lowest frequency oppoint."); + dvfs_service_handler_change_freq_setting(DVFS_FREQ_LOW); +#endif + + while (1) { + k_sem_take(&dvfs_service_idle_sem, K_FOREVER); + /* perform background processing */ + ld_dvfs_scaling_background_process(true); + } +} + +K_THREAD_DEFINE(dvfs_service_handler_task_id, + CONFIG_NRFS_LOCAL_DOMAIN_DVFS_HANDLER_TASK_STACK_SIZE, + dvfs_service_handler_task, + NULL, + NULL, + NULL, + CONFIG_NRFS_LOCAL_DOMAIN_DVFS_HANDLER_TASK_PRIORITY, + 0, + 0); + +int32_t dvfs_service_handler_change_freq_setting(enum dvfs_frequency_setting freq_setting) +{ + if (!dvfs_service_handler_init_done()) { + LOG_INF("Init not done!"); + return -EAGAIN; + } + + if (dvfs_service_handler_freq_change_in_progress()) { + LOG_INF("Frequency change in progress."); + return -EBUSY; + } + + if (!dvfs_service_handler_freq_setting_allowed(freq_setting)) { + return -ENXIO; + } + + nrfs_err_t status = nrfs_dvfs_oppoint_request(freq_setting, get_next_context()); + + dvfs_service_handler_nrfs_error_check(status); + + return status; +} diff --git a/modules/hal_nordic/nrfs/dvfs/ld_dvfs_handler.h b/modules/hal_nordic/nrfs/dvfs/ld_dvfs_handler.h new file mode 100644 index 00000000000..b15e630eb2c --- /dev/null +++ b/modules/hal_nordic/nrfs/dvfs/ld_dvfs_handler.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef LD_DVFS_HANDLER_H +#define LD_DVFS_HANDLER_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Function to request LD frequency change. + * + * @param frequency requested frequency setting from enum dvfs_frequency_setting. + * @return EBUSY Frequency change in progress. + * @return EAGAIN DVFS init in progress. + * @return ENXIO Not supported frequency settings. + * @return NRFS_SUCCESS Request sent successfully. + * @return NRFS_ERR_INVALID_STATE Service is uninitialized. + * @return NRFS_ERR_IPC Backend returned error during request sending. + */ +int32_t dvfs_service_handler_change_freq_setting(enum dvfs_frequency_setting freq_setting); + +#ifdef __cplusplus +} +#endif + +#endif /* LD_DVFS_HANDLER_H */ diff --git a/modules/hal_nordic/nrfs/nrfs_config.h b/modules/hal_nordic/nrfs/nrfs_config.h new file mode 100644 index 00000000000..20cf6cece0e --- /dev/null +++ b/modules/hal_nordic/nrfs/nrfs_config.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef NRFS_CONFIG_H +#define NRFS_CONFIG_H + + +#ifdef CONFIG_NRFS_TEMP_SERVICE_ENABLED +#define NRFS_TEMP_SERVICE_ENABLED +#endif + +#ifdef CONFIG_NRFS_MRAM_SERVICE_ENABLED +#define NRFS_MRAM_SERVICE_ENABLED +#endif + +#ifdef CONFIG_NRFS_RESET_SERVICE_ENABLED +#define NRFS_RESET_SERVICE_ENABLED +#endif + +#ifdef CONFIG_NRFS_VBUS_DETECTOR_SERVICE_ENABLED +#define NRFS_VBUS_DETECTOR_SERVICE_ENABLED +#endif + +#ifdef CONFIG_NRFS_PMIC_SERVICE_ENABLED +#define NRFS_PMIC_SERVICE_ENABLED +#endif + +#ifdef CONFIG_NRFS_DVFS_SERVICE_ENABLED +#define NRFS_DVFS_SERVICE_ENABLED +#endif + +#ifdef CONFIG_NRFS_DIAG_SERVICE_ENABLED +#define NRFS_DIAG_SERVICE_ENABLED +#endif + +#ifdef CONFIG_NRFS_CLOCK_SERVICE_ENABLED +#define NRFS_CLOCK_SERVICE_ENABLED +#endif + +#ifdef CONFIG_SOC_POSIX +#define NRFS_UNIT_TESTS_ENABLED +#endif + +#endif /* NRFS_CONFIG_H */ diff --git a/modules/hal_nordic/nrfx/CMakeLists.txt b/modules/hal_nordic/nrfx/CMakeLists.txt index 557f3df0cab..2313c3f311d 100644 --- a/modules/hal_nordic/nrfx/CMakeLists.txt +++ b/modules/hal_nordic/nrfx/CMakeLists.txt @@ -44,6 +44,9 @@ zephyr_compile_definitions_ifdef(CONFIG_SOC_NRF54H20_CPUPPR NRF54H20_XXAA NRF_PPR) 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_NRF54L15_ENGA_CPUFLPR NRF_FLPR) +zephyr_compile_definitions_ifdef(CONFIG_SOC_COMPATIBLE_NRF54L15 NRF54L15_XXAA) +zephyr_compile_definitions_ifdef(CONFIG_SOC_COMPATIBLE_NRF54L15_CPUAPP NRF_APPLICATION) zephyr_compile_definitions_ifdef(CONFIG_SOC_NRF9120 NRF9120_XXAA) zephyr_compile_definitions_ifdef(CONFIG_SOC_NRF9160 NRF9160_XXAA) @@ -107,6 +110,7 @@ zephyr_library_sources_ifdef(CONFIG_NRFX_PWM ${SRC_DIR}/nrfx_pwm.c) zephyr_library_sources_ifdef(CONFIG_NRFX_QDEC ${SRC_DIR}/nrfx_qdec.c) zephyr_library_sources_ifdef(CONFIG_NRFX_QSPI ${SRC_DIR}/nrfx_qspi.c) zephyr_library_sources_ifdef(CONFIG_NRFX_RNG ${SRC_DIR}/nrfx_rng.c) +zephyr_library_sources_ifdef(CONFIG_NRFX_RRAMC ${SRC_DIR}/nrfx_rramc.c) zephyr_library_sources_ifdef(CONFIG_NRFX_RTC ${SRC_DIR}/nrfx_rtc.c) zephyr_library_sources_ifdef(CONFIG_NRFX_SAADC ${SRC_DIR}/nrfx_saadc.c) zephyr_library_sources_ifdef(CONFIG_NRFX_SPI ${SRC_DIR}/nrfx_spi.c) @@ -160,7 +164,7 @@ if(DEFINED uicr_path) endif() endif() -if(CONFIG_SOC_NRF54L15) +if(CONFIG_SOC_NRF54L15_ENGA_CPUAPP) 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}") @@ -203,5 +207,7 @@ mdk_svd_ifdef(CONFIG_SOC_NRF5340_CPUNET nrf5340_network.svd) mdk_svd_ifdef(CONFIG_SOC_NRF54H20_CPUAPP nrf54h20_application.svd) mdk_svd_ifdef(CONFIG_SOC_NRF54H20_CPUPPR nrf54h20_ppr.svd) mdk_svd_ifdef(CONFIG_SOC_NRF54H20_CPURAD nrf54h20_radiocore.svd) +mdk_svd_ifdef(CONFIG_SOC_NRF54L15_ENGA_CPUAPP nrf54l15_enga_application.svd) +mdk_svd_ifdef(CONFIG_SOC_NRF54L15_ENGA_CPUFLPR nrf54l15_enga_flpr.svd) mdk_svd_ifdef(CONFIG_SOC_NRF9120 nrf9120.svd) mdk_svd_ifdef(CONFIG_SOC_NRF9160 nrf9160.svd) diff --git a/modules/hal_nordic/nrfx/Kconfig b/modules/hal_nordic/nrfx/Kconfig index 37059183891..10ecd585ef3 100644 --- a/modules/hal_nordic/nrfx/Kconfig +++ b/modules/hal_nordic/nrfx/Kconfig @@ -265,6 +265,10 @@ config NRFX_RNG bool "RNG driver" depends on $(dt_has_compat,$(DT_COMPAT_NORDIC_NRF_RNG)) +config NRFX_RRAMC + bool "RRAMC driver" + depends on $(dt_has_compat,$(DT_COMPAT_NORDIC_RRAM_CONTROLLER)) + config NRFX_RTC bool @@ -946,7 +950,6 @@ config NRFX_UARTE_CONFIG_TX_LINK config NRFX_UARTE_CONFIG_RX_CACHE_ENABLED bool "UARTE RX caching support" - default y if $(dt_nodelabel_has_compat,shared_ram3x_region,$(DT_COMPAT_NORDIC_OWNED_MEMORY)) depends on NRFX_UARTE help Feature might be enabled on platforms which has limitations regarding addresses diff --git a/modules/hal_nordic/nrfx/nrfx_config.h b/modules/hal_nordic/nrfx/nrfx_config.h index 6072f3634f4..a54866252a5 100644 --- a/modules/hal_nordic/nrfx/nrfx_config.h +++ b/modules/hal_nordic/nrfx/nrfx_config.h @@ -312,6 +312,10 @@ #define NRFX_RNG_CONFIG_LOG_ENABLED 1 #endif +#ifdef CONFIG_NRFX_RRAMC +#define NRFX_RRAMC_ENABLED 1 +#endif + #ifdef CONFIG_NRFX_RTC #define NRFX_RTC_ENABLED 1 #endif @@ -1017,6 +1021,8 @@ #include #elif (defined(NRF54L15_XXAA) || defined(NRF54L15_ENGA_XXAA)) && defined(NRF_APPLICATION) #include +#elif (defined(NRF54L15_XXAA) || defined(NRF54L15_ENGA_XXAA)) && defined(NRF_FLPR) + #include #elif defined(NRF9120_XXAA) || defined(NRF9160_XXAA) #include #else diff --git a/modules/hal_nordic/nrfx/nrfx_config_nrf54l15_enga_application.h b/modules/hal_nordic/nrfx/nrfx_config_nrf54l15_enga_application.h index 57e469686ec..dcf7cde2de2 100644 --- a/modules/hal_nordic/nrfx/nrfx_config_nrf54l15_enga_application.h +++ b/modules/hal_nordic/nrfx/nrfx_config_nrf54l15_enga_application.h @@ -4,17 +4,27 @@ * SPDX-License-Identifier: Apache-2.0 */ -#ifndef NRFX_CONFIG_NRF54L15_APPLICATION_H__ -#define NRFX_CONFIG_NRF54L15_APPLICATION_H__ +#ifndef NRFX_CONFIG_NRF54L15_ENGA_APPLICATION_H__ +#define NRFX_CONFIG_NRF54L15_ENGA_APPLICATION_H__ #ifndef NRFX_CONFIG_H__ #error "This file should not be included directly. Include nrfx_config.h instead." #endif + +/** + * @brief NRFX_DEFAULT_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_DEFAULT_IRQ_PRIORITY +#define NRFX_DEFAULT_IRQ_PRIORITY 0 +#endif + /** * @brief NRFX_CLOCK_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_CLOCK_ENABLED #define NRFX_CLOCK_ENABLED 0 @@ -30,13 +40,13 @@ * - Synth = 2 */ #ifndef NRFX_CLOCK_CONFIG_LF_SRC -#define NRFX_CLOCK_CONFIG_LF_SRC 0 +#define NRFX_CLOCK_CONFIG_LF_SRC 1 #endif /** * @brief NRFX_CLOCK_CONFIG_LF_CAL_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_CLOCK_CONFIG_LF_CAL_ENABLED #define NRFX_CLOCK_CONFIG_LF_CAL_ENABLED 0 @@ -45,7 +55,7 @@ /** * @brief NRFX_CLOCK_CONFIG_LFXO_TWO_STAGE_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_CLOCK_CONFIG_LFXO_TWO_STAGE_ENABLED #define NRFX_CLOCK_CONFIG_LFXO_TWO_STAGE_ENABLED 0 @@ -54,16 +64,16 @@ /** * @brief NRFX_CLOCK_DEFAULT_CONFIG_IRQ_PRIORITY * - * Integer value. Minimum: 0 Maximum: 7 + * Integer value. Minimum: 0. Maximum: 7. */ #ifndef NRFX_CLOCK_DEFAULT_CONFIG_IRQ_PRIORITY -#define NRFX_CLOCK_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#define NRFX_CLOCK_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY #endif /** * @brief NRFX_CLOCK_CONFIG_LOG_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_CLOCK_CONFIG_LOG_ENABLED #define NRFX_CLOCK_CONFIG_LOG_ENABLED 0 @@ -87,7 +97,7 @@ /** * @brief NRFX_COMP_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_COMP_ENABLED #define NRFX_COMP_ENABLED 0 @@ -96,16 +106,16 @@ /** * @brief NRFX_COMP_DEFAULT_CONFIG_IRQ_PRIORITY * - * Integer value. Minimum: 0 Maximum: 7 + * Integer value. Minimum: 0. Maximum: 7. */ #ifndef NRFX_COMP_DEFAULT_CONFIG_IRQ_PRIORITY -#define NRFX_COMP_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#define NRFX_COMP_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY #endif /** * @brief NRFX_COMP_CONFIG_LOG_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_COMP_CONFIG_LOG_ENABLED #define NRFX_COMP_CONFIG_LOG_ENABLED 0 @@ -129,7 +139,7 @@ /** * @brief NRFX_DPPI_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_DPPI_ENABLED #define NRFX_DPPI_ENABLED 0 @@ -138,7 +148,7 @@ /** * @brief NRFX_DPPI_CONFIG_LOG_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_DPPI_CONFIG_LOG_ENABLED #define NRFX_DPPI_CONFIG_LOG_ENABLED 0 @@ -147,7 +157,13 @@ /** * @brief NRFX_DPPI_CONFIG_LOG_LEVEL * - * Boolean. Accepted values 0 and 1. + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 */ #ifndef NRFX_DPPI_CONFIG_LOG_LEVEL #define NRFX_DPPI_CONFIG_LOG_LEVEL 0 @@ -156,16 +172,25 @@ /** * @brief NRFX_EGU_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_EGU_ENABLED #define NRFX_EGU_ENABLED 0 #endif +/** + * @brief NRFX_EGU_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_EGU_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_EGU_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + /** * @brief NRFX_EGU10_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_EGU10_ENABLED #define NRFX_EGU10_ENABLED 0 @@ -174,52 +199,43 @@ /** * @brief NRFX_EGU20_ENABLED * - * Boolean. Accepted values 0 and 1. + * 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. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_GPIOTE_ENABLED #define NRFX_GPIOTE_ENABLED 0 #endif /** - * @brief NRFX_GPIOTE_CONFIG_NUM_OF_EVT_HANDLERS + * @brief NRFX_GPIOTE_DEFAULT_CONFIG_IRQ_PRIORITY * - * Integer value. Minimum: 0 Maximum: 15 + * Integer value. Minimum: 0. Maximum: 7. */ -#ifndef NRFX_GPIOTE_CONFIG_NUM_OF_EVT_HANDLERS -#define NRFX_GPIOTE_CONFIG_NUM_OF_EVT_HANDLERS 0 +#ifndef NRFX_GPIOTE_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_GPIOTE_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY #endif /** - * @brief NRFX_GPIOTE_DEFAULT_CONFIG_IRQ_PRIORITY + * @brief NRFX_GPIOTE_CONFIG_NUM_OF_EVT_HANDLERS * - * Integer value. Minimum: 0 Maximum: 7 + * Integer value. Minimum: 0. Maximum: 15. */ -#ifndef NRFX_GPIOTE_DEFAULT_CONFIG_IRQ_PRIORITY -#define NRFX_GPIOTE_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#ifndef NRFX_GPIOTE_CONFIG_NUM_OF_EVT_HANDLERS +#define NRFX_GPIOTE_CONFIG_NUM_OF_EVT_HANDLERS 2 #endif /** * @brief NRFX_GPIOTE_CONFIG_LOG_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_GPIOTE_CONFIG_LOG_ENABLED #define NRFX_GPIOTE_CONFIG_LOG_ENABLED 0 @@ -240,10 +256,28 @@ #define NRFX_GPIOTE_CONFIG_LOG_LEVEL 0 #endif +/** + * @brief NRFX_GPIOTE20_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_GPIOTE20_ENABLED +#define NRFX_GPIOTE20_ENABLED 0 +#endif + +/** + * @brief NRFX_GPIOTE30_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_GPIOTE30_ENABLED +#define NRFX_GPIOTE30_ENABLED 0 +#endif + /** * @brief NRFX_GRTC_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_GRTC_ENABLED #define NRFX_GRTC_ENABLED 0 @@ -282,29 +316,53 @@ * Integer value. */ #ifndef NRFX_GRTC_CONFIG_NUM_OF_CC_CHANNELS -#define NRFX_GRTC_CONFIG_NUM_OF_CC_CHANNELS 11 +#define NRFX_GRTC_CONFIG_NUM_OF_CC_CHANNELS 10 #endif /** - * @brief GRTC CC channels ownership mask. + * @brief NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK */ #ifndef NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK -#define NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK 0x000007ff +#define NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK 0x00000fe7 #endif /** * @brief NRFX_GRTC_DEFAULT_CONFIG_IRQ_PRIORITY * - * Boolean. Accepted values 0 and 1. + * Integer value. Minimum: 0. Maximum: 7. */ #ifndef NRFX_GRTC_DEFAULT_CONFIG_IRQ_PRIORITY -#define NRFX_GRTC_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#define NRFX_GRTC_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_GRTC_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_GRTC_CONFIG_LOG_ENABLED +#define NRFX_GRTC_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_GRTC_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_GRTC_CONFIG_LOG_LEVEL +#define NRFX_GRTC_CONFIG_LOG_LEVEL 0 #endif /** * @brief NRFX_I2S_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_I2S_ENABLED #define NRFX_I2S_ENABLED 0 @@ -313,16 +371,16 @@ /** * @brief NRFX_I2S_DEFAULT_CONFIG_IRQ_PRIORITY * - * Integer value. Minimum: 0 Maximum: 7 + * Integer value. Minimum: 0. Maximum: 7. */ #ifndef NRFX_I2S_DEFAULT_CONFIG_IRQ_PRIORITY -#define NRFX_I2S_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#define NRFX_I2S_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY #endif /** * @brief NRFX_I2S_CONFIG_LOG_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_I2S_CONFIG_LOG_ENABLED #define NRFX_I2S_CONFIG_LOG_ENABLED 0 @@ -343,10 +401,19 @@ #define NRFX_I2S_CONFIG_LOG_LEVEL 0 #endif +/** + * @brief NRFX_I2S20_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_I2S20_ENABLED +#define NRFX_I2S20_ENABLED 0 +#endif + /** * @brief NRFX_LPCOMP_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_LPCOMP_ENABLED #define NRFX_LPCOMP_ENABLED 0 @@ -355,16 +422,16 @@ /** * @brief NRFX_LPCOMP_DEFAULT_CONFIG_IRQ_PRIORITY * - * Integer value. Minimum: 0 Maximum: 7 + * Integer value. Minimum: 0. Maximum: 7. */ #ifndef NRFX_LPCOMP_DEFAULT_CONFIG_IRQ_PRIORITY -#define NRFX_LPCOMP_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#define NRFX_LPCOMP_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY #endif /** * @brief NRFX_LPCOMP_CONFIG_LOG_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_LPCOMP_CONFIG_LOG_ENABLED #define NRFX_LPCOMP_CONFIG_LOG_ENABLED 0 @@ -388,7 +455,7 @@ /** * @brief NRFX_NFCT_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_NFCT_ENABLED #define NRFX_NFCT_ENABLED 0 @@ -397,16 +464,16 @@ /** * @brief NRFX_NFCT_DEFAULT_CONFIG_IRQ_PRIORITY * - * Integer value. Minimum: 0 Maximum: 7 + * Integer value. Minimum: 0. Maximum: 7. */ #ifndef NRFX_NFCT_DEFAULT_CONFIG_IRQ_PRIORITY -#define NRFX_NFCT_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#define NRFX_NFCT_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY #endif /** - * @brief NRFX_NFCT_CONFIG_TIMER_INSTANCE_ID + * @brief NRFX_NFCT_CONFIG_TIMER_INSTANCE_ID - Timer instance used for workarounds in the driver. * - * Boolean. Accepted values 0 and 1. + * Integer value. Minimum: 0. Maximum: 5. */ #ifndef NRFX_NFCT_CONFIG_TIMER_INSTANCE_ID #define NRFX_NFCT_CONFIG_TIMER_INSTANCE_ID 0 @@ -415,7 +482,7 @@ /** * @brief NRFX_NFCT_CONFIG_LOG_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_NFCT_CONFIG_LOG_ENABLED #define NRFX_NFCT_CONFIG_LOG_ENABLED 0 @@ -481,7 +548,7 @@ /** * @brief NRFX_POWER_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_POWER_ENABLED #define NRFX_POWER_ENABLED 0 @@ -490,25 +557,49 @@ /** * @brief NRFX_POWER_DEFAULT_CONFIG_IRQ_PRIORITY * - * Integer value. Minimum: 0 Maximum: 7 + * Integer value. Minimum: 0. Maximum: 7. */ #ifndef NRFX_POWER_DEFAULT_CONFIG_IRQ_PRIORITY -#define NRFX_POWER_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#define NRFX_POWER_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY #endif /** * @brief NRFX_PRS_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_PRS_ENABLED #define NRFX_PRS_ENABLED 0 #endif +/** + * @brief NRFX_PRS_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_CONFIG_LOG_ENABLED +#define NRFX_PRS_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_PRS_CONFIG_LOG_LEVEL +#define NRFX_PRS_CONFIG_LOG_LEVEL 0 +#endif + /** * @brief NRFX_PRS_BOX_0_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_PRS_BOX_0_ENABLED #define NRFX_PRS_BOX_0_ENABLED 0 @@ -517,7 +608,7 @@ /** * @brief NRFX_PRS_BOX_1_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_PRS_BOX_1_ENABLED #define NRFX_PRS_BOX_1_ENABLED 0 @@ -526,7 +617,7 @@ /** * @brief NRFX_PRS_BOX_2_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_PRS_BOX_2_ENABLED #define NRFX_PRS_BOX_2_ENABLED 0 @@ -535,7 +626,7 @@ /** * @brief NRFX_PRS_BOX_3_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_PRS_BOX_3_ENABLED #define NRFX_PRS_BOX_3_ENABLED 0 @@ -544,7 +635,7 @@ /** * @brief NRFX_PRS_BOX_4_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_PRS_BOX_4_ENABLED #define NRFX_PRS_BOX_4_ENABLED 0 @@ -553,7 +644,7 @@ /** * @brief NRFX_PRS_BOX_5_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_PRS_BOX_5_ENABLED #define NRFX_PRS_BOX_5_ENABLED 0 @@ -655,7 +746,7 @@ /** * @brief NRFX_QDEC_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_QDEC_ENABLED #define NRFX_QDEC_ENABLED 0 @@ -682,16 +773,16 @@ /** * @brief NRFX_QDEC_DEFAULT_CONFIG_IRQ_PRIORITY * - * Integer value. Minimum: 0 Maximum: 7 + * Integer value. Minimum: 0. Maximum: 7. */ #ifndef NRFX_QDEC_DEFAULT_CONFIG_IRQ_PRIORITY -#define NRFX_QDEC_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#define NRFX_QDEC_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY #endif /** * @brief NRFX_QDEC_CONFIG_LOG_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_QDEC_CONFIG_LOG_ENABLED #define NRFX_QDEC_CONFIG_LOG_ENABLED 0 @@ -713,45 +804,87 @@ #endif /** - * @brief NRFX_RTC_ENABLED + * @brief NRFX_QDEC20_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ -#ifndef NRFX_RTC_ENABLED -#define NRFX_RTC_ENABLED 0 +#ifndef NRFX_QDEC20_ENABLED +#define NRFX_QDEC20_ENABLED 0 #endif /** - * @brief NRFX_RTC10_ENABLED + * @brief NRFX_QDEC21_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ -#ifndef NRFX_RTC10_ENABLED -#define NRFX_RTC10_ENABLED 0 +#ifndef NRFX_QDEC21_ENABLED +#define NRFX_QDEC21_ENABLED 0 #endif /** - * @brief NRFX_RTC30_ENABLED + * @brief NRFX_RRAMC_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ -#ifndef NRFX_RTC30_ENABLED -#define NRFX_RTC30_ENABLED 0 +#ifndef NRFX_RRAMC_ENABLED +#define NRFX_RRAMC_ENABLED 0 +#endif + +/** + * @brief NRFX_RRAMC_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_RRAMC_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_RRAMC_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_RRAMC_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_RRAMC_CONFIG_LOG_ENABLED +#define NRFX_RRAMC_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_RRAMC_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_RRAMC_CONFIG_LOG_LEVEL +#define NRFX_RRAMC_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_RTC_DEFAULT_CONFIG_IRQ_PRIORITY * - * Integer value. Minimum: 0 Maximum: 7 + * Integer value. Minimum: 0. Maximum: 7. */ #ifndef NRFX_RTC_DEFAULT_CONFIG_IRQ_PRIORITY -#define NRFX_RTC_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#define NRFX_RTC_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY #endif /** * @brief NRFX_RTC_CONFIG_LOG_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_RTC_CONFIG_LOG_ENABLED #define NRFX_RTC_CONFIG_LOG_ENABLED 0 @@ -772,10 +905,28 @@ #define NRFX_RTC_CONFIG_LOG_LEVEL 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_SAADC_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_SAADC_ENABLED #define NRFX_SAADC_ENABLED 0 @@ -784,16 +935,16 @@ /** * @brief NRFX_SAADC_DEFAULT_CONFIG_IRQ_PRIORITY * - * Integer value. Minimum: 0 Maximum: 7 + * Integer value. Minimum: 0. Maximum: 7. */ #ifndef NRFX_SAADC_DEFAULT_CONFIG_IRQ_PRIORITY -#define NRFX_SAADC_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#define NRFX_SAADC_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY #endif /** * @brief NRFX_SAADC_CONFIG_LOG_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_SAADC_CONFIG_LOG_ENABLED #define NRFX_SAADC_CONFIG_LOG_ENABLED 0 @@ -815,79 +966,43 @@ #endif /** - * @brief NRFX_SPI_ENABLED + * @brief NRFX_SPIM_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ -#ifndef NRFX_SPI_ENABLED -#define NRFX_SPI_ENABLED 0 +#ifndef NRFX_SPIM_ENABLED +#define NRFX_SPIM_ENABLED 0 #endif /** - * @brief NRFX_SPI00_ENABLED + * @brief NRFX_SPIM_EXTENDED_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ -#ifndef NRFX_SPI00_ENABLED -#define NRFX_SPI00_ENABLED 0 +#ifndef NRFX_SPIM_EXTENDED_ENABLED +#define NRFX_SPIM_EXTENDED_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 + * @brief NRFX_SPIM_DEFAULT_CONFIG_IRQ_PRIORITY * - * Integer value. Minimum: 0 Maximum: 7 + * Integer value. Minimum: 0. Maximum: 7. */ -#ifndef NRFX_SPI_DEFAULT_CONFIG_IRQ_PRIORITY -#define NRFX_SPI_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#ifndef NRFX_SPIM_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_SPIM_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY #endif /** - * @brief NRFX_SPI_CONFIG_LOG_ENABLED + * @brief NRFX_SPIM_CONFIG_LOG_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ -#ifndef NRFX_SPI_CONFIG_LOG_ENABLED -#define NRFX_SPI_CONFIG_LOG_ENABLED 0 +#ifndef NRFX_SPIM_CONFIG_LOG_ENABLED +#define NRFX_SPIM_CONFIG_LOG_ENABLED 0 #endif /** - * @brief NRFX_SPI_CONFIG_LOG_LEVEL + * @brief NRFX_SPIM_CONFIG_LOG_LEVEL * * Integer value. * Supported values: @@ -897,23 +1012,14 @@ * - 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 +#ifndef NRFX_SPIM_CONFIG_LOG_LEVEL +#define NRFX_SPIM_CONFIG_LOG_LEVEL 0 #endif /** * @brief NRFX_SPIM00_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_SPIM00_ENABLED #define NRFX_SPIM00_ENABLED 0 @@ -922,7 +1028,7 @@ /** * @brief NRFX_SPIM20_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_SPIM20_ENABLED #define NRFX_SPIM20_ENABLED 0 @@ -931,7 +1037,7 @@ /** * @brief NRFX_SPIM21_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_SPIM21_ENABLED #define NRFX_SPIM21_ENABLED 0 @@ -940,7 +1046,7 @@ /** * @brief NRFX_SPIM22_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_SPIM22_ENABLED #define NRFX_SPIM22_ENABLED 0 @@ -949,41 +1055,41 @@ /** * @brief NRFX_SPIM30_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_SPIM30_ENABLED #define NRFX_SPIM30_ENABLED 0 #endif /** - * @brief NRFX_SPIM_EXTENDED_ENABLED + * @brief NRFX_SPIS_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ -#ifndef NRFX_SPIM_EXTENDED_ENABLED -#define NRFX_SPIM_EXTENDED_ENABLED 0 +#ifndef NRFX_SPIS_ENABLED +#define NRFX_SPIS_ENABLED 0 #endif /** - * @brief NRFX_SPIM_DEFAULT_CONFIG_IRQ_PRIORITY + * @brief NRFX_SPIS_DEFAULT_CONFIG_IRQ_PRIORITY * - * Integer value. Minimum: 0 Maximum: 7 + * Integer value. Minimum: 0. Maximum: 7. */ -#ifndef NRFX_SPIM_DEFAULT_CONFIG_IRQ_PRIORITY -#define NRFX_SPIM_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#ifndef NRFX_SPIS_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_SPIS_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY #endif /** - * @brief NRFX_SPIM_CONFIG_LOG_ENABLED + * @brief NRFX_SPIS_CONFIG_LOG_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ -#ifndef NRFX_SPIM_CONFIG_LOG_ENABLED -#define NRFX_SPIM_CONFIG_LOG_ENABLED 0 +#ifndef NRFX_SPIS_CONFIG_LOG_ENABLED +#define NRFX_SPIS_CONFIG_LOG_ENABLED 0 #endif /** - * @brief NRFX_SPIM_CONFIG_LOG_LEVEL + * @brief NRFX_SPIS_CONFIG_LOG_LEVEL * * Integer value. * Supported values: @@ -993,23 +1099,14 @@ * - 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 +#ifndef NRFX_SPIS_CONFIG_LOG_LEVEL +#define NRFX_SPIS_CONFIG_LOG_LEVEL 0 #endif /** * @brief NRFX_SPIS00_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_SPIS00_ENABLED #define NRFX_SPIS00_ENABLED 0 @@ -1018,7 +1115,7 @@ /** * @brief NRFX_SPIS20_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_SPIS20_ENABLED #define NRFX_SPIS20_ENABLED 0 @@ -1027,7 +1124,7 @@ /** * @brief NRFX_SPIS21_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_SPIS21_ENABLED #define NRFX_SPIS21_ENABLED 0 @@ -1036,7 +1133,7 @@ /** * @brief NRFX_SPIS22_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_SPIS22_ENABLED #define NRFX_SPIS22_ENABLED 0 @@ -1045,32 +1142,50 @@ /** * @brief NRFX_SPIS30_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_SPIS30_ENABLED #define NRFX_SPIS30_ENABLED 0 #endif /** - * @brief NRFX_SPIS_DEFAULT_CONFIG_IRQ_PRIORITY + * @brief NRFX_SYSTICK_ENABLED * - * Integer value. Minimum: 0 Maximum: 7 + * Boolean. Accepted values: 0 and 1. */ -#ifndef NRFX_SPIS_DEFAULT_CONFIG_IRQ_PRIORITY -#define NRFX_SPIS_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#ifndef NRFX_SYSTICK_ENABLED +#define NRFX_SYSTICK_ENABLED 0 #endif /** - * @brief NRFX_SPIS_CONFIG_LOG_ENABLED + * @brief NRFX_TEMP_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ -#ifndef NRFX_SPIS_CONFIG_LOG_ENABLED -#define NRFX_SPIS_CONFIG_LOG_ENABLED 0 +#ifndef NRFX_TEMP_ENABLED +#define NRFX_TEMP_ENABLED 0 #endif /** - * @brief NRFX_SPIS_CONFIG_LOG_LEVEL + * @brief NRFX_TEMP_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_TEMP_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_TEMP_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_TEMP_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TEMP_CONFIG_LOG_ENABLED +#define NRFX_TEMP_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_TEMP_CONFIG_LOG_LEVEL * * Integer value. * Supported values: @@ -1080,50 +1195,65 @@ * - Info = 3 * - Debug = 4 */ -#ifndef NRFX_SPIS_CONFIG_LOG_LEVEL -#define NRFX_SPIS_CONFIG_LOG_LEVEL 0 +#ifndef NRFX_TEMP_CONFIG_LOG_LEVEL +#define NRFX_TEMP_CONFIG_LOG_LEVEL 0 #endif /** - * @brief NRFX_SYSTICK_ENABLED + * @brief NRFX_TIMER_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ -#ifndef NRFX_SYSTICK_ENABLED -#define NRFX_SYSTICK_ENABLED 0 +#ifndef NRFX_TIMER_ENABLED +#define NRFX_TIMER_ENABLED 0 #endif /** - * @brief NRFX_TEMP_ENABLED + * @brief NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY * - * Boolean. Accepted values 0 and 1. + * Integer value. Minimum: 0. Maximum: 7. */ -#ifndef NRFX_TEMP_ENABLED -#define NRFX_TEMP_ENABLED 0 +#ifndef NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY #endif /** - * @brief NRFX_TEMP_DEFAULT_CONFIG_IRQ_PRIORITY + * @brief NRFX_TIMER_CONFIG_LOG_ENABLED * - * Integer value. Minimum: 0 Maximum: 7 + * Boolean. Accepted values: 0 and 1. */ -#ifndef NRFX_TEMP_DEFAULT_CONFIG_IRQ_PRIORITY -#define NRFX_TEMP_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#ifndef NRFX_TIMER_CONFIG_LOG_ENABLED +#define NRFX_TIMER_CONFIG_LOG_ENABLED 0 #endif /** - * @brief NRFX_TIMER_ENABLED + * @brief NRFX_TIMER_CONFIG_LOG_LEVEL * - * Boolean. Accepted values 0 and 1. + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 */ -#ifndef NRFX_TIMER_ENABLED -#define NRFX_TIMER_ENABLED 0 +#ifndef NRFX_TIMER_CONFIG_LOG_LEVEL +#define NRFX_TIMER_CONFIG_LOG_LEVEL 0 +#endif + +/** + * @brief NRFX_TIMER00_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER00_ENABLED +#define NRFX_TIMER00_ENABLED 0 #endif /** * @brief NRFX_TIMER10_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_TIMER10_ENABLED #define NRFX_TIMER10_ENABLED 0 @@ -1132,7 +1262,7 @@ /** * @brief NRFX_TIMER20_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_TIMER20_ENABLED #define NRFX_TIMER20_ENABLED 0 @@ -1141,7 +1271,7 @@ /** * @brief NRFX_TIMER21_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_TIMER21_ENABLED #define NRFX_TIMER21_ENABLED 0 @@ -1150,7 +1280,7 @@ /** * @brief NRFX_TIMER22_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_TIMER22_ENABLED #define NRFX_TIMER22_ENABLED 0 @@ -1159,7 +1289,7 @@ /** * @brief NRFX_TIMER23_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_TIMER23_ENABLED #define NRFX_TIMER23_ENABLED 0 @@ -1168,32 +1298,41 @@ /** * @brief NRFX_TIMER24_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_TIMER24_ENABLED #define NRFX_TIMER24_ENABLED 0 #endif /** - * @brief NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY + * @brief NRFX_TWIM_ENABLED * - * Integer value. Minimum: 0 Maximum: 7 + * Boolean. Accepted values: 0 and 1. */ -#ifndef NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY -#define NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#ifndef NRFX_TWIM_ENABLED +#define NRFX_TWIM_ENABLED 0 #endif /** - * @brief NRFX_TIMER_CONFIG_LOG_ENABLED + * @brief NRFX_TWIM_DEFAULT_CONFIG_IRQ_PRIORITY * - * Boolean. Accepted values 0 and 1. + * Integer value. Minimum: 0. Maximum: 7. */ -#ifndef NRFX_TIMER_CONFIG_LOG_ENABLED -#define NRFX_TIMER_CONFIG_LOG_ENABLED 0 +#ifndef NRFX_TWIM_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_TWIM_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY #endif /** - * @brief NRFX_TIMER_CONFIG_LOG_LEVEL + * @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: @@ -1203,23 +1342,14 @@ * - 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 +#ifndef NRFX_TWIM_CONFIG_LOG_LEVEL +#define NRFX_TWIM_CONFIG_LOG_LEVEL 0 #endif /** * @brief NRFX_TWIM20_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_TWIM20_ENABLED #define NRFX_TWIM20_ENABLED 0 @@ -1228,7 +1358,7 @@ /** * @brief NRFX_TWIM21_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_TWIM21_ENABLED #define NRFX_TWIM21_ENABLED 0 @@ -1237,7 +1367,7 @@ /** * @brief NRFX_TWIM22_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_TWIM22_ENABLED #define NRFX_TWIM22_ENABLED 0 @@ -1246,67 +1376,77 @@ /** * @brief NRFX_TWIM30_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_TWIM30_ENABLED #define NRFX_TWIM30_ENABLED 0 #endif /** - * @brief NRFX_TWIM_DEFAULT_CONFIG_IRQ_PRIORITY + * @brief NRFX_TWIS_ENABLED * - * Integer value. Minimum: 0 Maximum: 7 + * Boolean. Accepted values: 0 and 1. */ -#ifndef NRFX_TWIM_DEFAULT_CONFIG_IRQ_PRIORITY -#define NRFX_TWIM_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#ifndef NRFX_TWIS_ENABLED +#define NRFX_TWIS_ENABLED 0 #endif /** - * @brief NRFX_TWIM_CONFIG_LOG_ENABLED + * @brief NRFX_TWIS_DEFAULT_CONFIG_IRQ_PRIORITY * - * Boolean. Accepted values 0 and 1. + * Integer value. Minimum: 0. Maximum: 7. */ -#ifndef NRFX_TWIM_CONFIG_LOG_ENABLED -#define NRFX_TWIM_CONFIG_LOG_ENABLED 0 +#ifndef NRFX_TWIS_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_TWIS_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY #endif /** - * @brief NRFX_TWIM_CONFIG_LOG_LEVEL + * @brief NRFX_TWIS_CONFIG_LOG_ENABLED * - * Integer value. - * Supported values: - * - Off = 0 - * - Error = 1 - * - Warning = 2 - * - Info = 3 - * - Debug = 4 + * Boolean. Accepted values: 0 and 1. */ -#ifndef NRFX_TWIM_CONFIG_LOG_LEVEL -#define NRFX_TWIM_CONFIG_LOG_LEVEL 0 +#ifndef NRFX_TWIS_CONFIG_LOG_ENABLED +#define NRFX_TWIS_CONFIG_LOG_ENABLED 0 #endif /** - * @brief NRFX_TWIS_ENABLED + * @brief NRFX_TWIS_ASSUME_INIT_AFTER_RESET_ONLY + * Assume that any instance would be initialized only once. * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ -#ifndef NRFX_TWIS_ENABLED -#define NRFX_TWIS_ENABLED 0 +#ifndef NRFX_TWIS_ASSUME_INIT_AFTER_RESET_ONLY +#define NRFX_TWIS_ASSUME_INIT_AFTER_RESET_ONLY 0 #endif /** - * @brief NRFX_TWIS00_ENABLED + * @brief NRFX_TWIS_NO_SYNC_MODE - Remove support for synchronous mode. * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS_NO_SYNC_MODE +#define NRFX_TWIS_NO_SYNC_MODE 0 +#endif + +/** + * @brief NRFX_TWIS_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 */ -#ifndef NRFX_TWIS00_ENABLED -#define NRFX_TWIS00_ENABLED 0 +#ifndef NRFX_TWIS_CONFIG_LOG_LEVEL +#define NRFX_TWIS_CONFIG_LOG_LEVEL 0 #endif /** * @brief NRFX_TWIS20_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_TWIS20_ENABLED #define NRFX_TWIS20_ENABLED 0 @@ -1315,7 +1455,7 @@ /** * @brief NRFX_TWIS21_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_TWIS21_ENABLED #define NRFX_TWIS21_ENABLED 0 @@ -1324,7 +1464,7 @@ /** * @brief NRFX_TWIS22_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_TWIS22_ENABLED #define NRFX_TWIS22_ENABLED 0 @@ -1333,50 +1473,79 @@ /** * @brief NRFX_TWIS30_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_TWIS30_ENABLED #define NRFX_TWIS30_ENABLED 0 #endif /** - * @brief NRFX_TWIS_ASSUME_INIT_AFTER_RESET_ONLY + * @brief NRFX_UARTE_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ -#ifndef NRFX_TWIS_ASSUME_INIT_AFTER_RESET_ONLY -#define NRFX_TWIS_ASSUME_INIT_AFTER_RESET_ONLY 0 +#ifndef NRFX_UARTE_ENABLED +#define NRFX_UARTE_ENABLED 0 #endif /** - * @brief NRFX_TWIS_NO_SYNC_MODE + * @brief NRFX_UARTE_CONFIG_SKIP_GPIO_CONFIG + * If enabled, support for configuring GPIO pins is removed from the driver * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ -#ifndef NRFX_TWIS_NO_SYNC_MODE -#define NRFX_TWIS_NO_SYNC_MODE 0 +#ifndef NRFX_UARTE_CONFIG_SKIP_GPIO_CONFIG +#define NRFX_UARTE_CONFIG_SKIP_GPIO_CONFIG 0 #endif /** - * @brief NRFX_TWIS_DEFAULT_CONFIG_IRQ_PRIORITY + * @brief NRFX_UARTE_CONFIG_SKIP_PSEL_CONFIG + * If enabled, support for configuring PSEL registers is removed from the driver * - * Integer value. Minimum: 0 Maximum: 7 + * Boolean. Accepted values: 0 and 1. */ -#ifndef NRFX_TWIS_DEFAULT_CONFIG_IRQ_PRIORITY -#define NRFX_TWIS_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#ifndef NRFX_UARTE_CONFIG_SKIP_PSEL_CONFIG +#define NRFX_UARTE_CONFIG_SKIP_PSEL_CONFIG 0 #endif /** - * @brief NRFX_TWIS_CONFIG_LOG_ENABLED + * @brief NRFX_UARTE_CONFIG_TX_LINK - If enabled, driver supports linking of TX transfers. * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ -#ifndef NRFX_TWIS_CONFIG_LOG_ENABLED -#define NRFX_TWIS_CONFIG_LOG_ENABLED 0 +#ifndef NRFX_UARTE_CONFIG_TX_LINK +#define NRFX_UARTE_CONFIG_TX_LINK 1 #endif /** - * @brief NRFX_TWIS_CONFIG_LOG_LEVEL + * @brief NRFX_UARTE_CONFIG_RX_CACHE_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE_CONFIG_RX_CACHE_ENABLED +#define NRFX_UARTE_CONFIG_RX_CACHE_ENABLED 1 +#endif + +/** + * @brief NRFX_UARTE_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_UARTE_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_UARTE_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_UARTE_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE_CONFIG_LOG_ENABLED +#define NRFX_UARTE_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE_CONFIG_LOG_LEVEL * * Integer value. * Supported values: @@ -1386,23 +1555,14 @@ * - 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 +#ifndef NRFX_UARTE_CONFIG_LOG_LEVEL +#define NRFX_UARTE_CONFIG_LOG_LEVEL 0 #endif /** * @brief NRFX_UARTE00_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_UARTE00_ENABLED #define NRFX_UARTE00_ENABLED 0 @@ -1411,7 +1571,7 @@ /** * @brief NRFX_UARTE20_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_UARTE20_ENABLED #define NRFX_UARTE20_ENABLED 0 @@ -1420,7 +1580,7 @@ /** * @brief NRFX_UARTE21_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_UARTE21_ENABLED #define NRFX_UARTE21_ENABLED 0 @@ -1429,7 +1589,7 @@ /** * @brief NRFX_UARTE22_ENABLED * - * Boolean. Accepted values 0 and 1. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_UARTE22_ENABLED #define NRFX_UARTE22_ENABLED 0 @@ -1438,94 +1598,43 @@ /** * @brief NRFX_UARTE30_ENABLED * - * Boolean. Accepted values 0 and 1. + * 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. + * 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 + * @brief NRFX_WDT_DEFAULT_CONFIG_IRQ_PRIORITY * - * Boolean. Accepted values 0 and 1. + * Integer value. Minimum: 0. Maximum: 7. */ -#ifndef NRFX_WDT31_ENABLED -#define NRFX_WDT31_ENABLED 0 +#ifndef NRFX_WDT_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_WDT_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY #endif /** - * @brief NRFX_WDT_CONFIG_NO_IRQ + * @brief NRFX_WDT_CONFIG_NO_IRQ - Remove WDT IRQ handling from WDT driver * - * Boolean. Accepted values 0 and 1. + * 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. + * Boolean. Accepted values: 0 and 1. */ #ifndef NRFX_WDT_CONFIG_LOG_ENABLED #define NRFX_WDT_CONFIG_LOG_ENABLED 0 @@ -1546,4 +1655,22 @@ #define NRFX_WDT_CONFIG_LOG_LEVEL 0 #endif -#endif /* NRFX_CONFIG_NRF54L15_APPLICATION_H__ */ +/** + * @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 + +#endif /* NRFX_CONFIG_NRF54L15_ENGA_APPLICATION_H__ */ diff --git a/modules/hal_nordic/nrfx/nrfx_config_nrf54l15_enga_flpr.h b/modules/hal_nordic/nrfx/nrfx_config_nrf54l15_enga_flpr.h new file mode 100644 index 00000000000..fde8904d9c7 --- /dev/null +++ b/modules/hal_nordic/nrfx/nrfx_config_nrf54l15_enga_flpr.h @@ -0,0 +1,1677 @@ +/* + * Copyright (c) 2024, Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef NRFX_CONFIG_NRF54L15_ENGA_FLPR_H__ +#define NRFX_CONFIG_NRF54L15_ENGA_FLPR_H__ + +#ifndef NRFX_CONFIG_H__ +#error "This file should not be included directly. Include nrfx_config.h instead." +#endif + + +/** + * @brief NRFX_DEFAULT_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 3. + */ +#ifndef NRFX_DEFAULT_IRQ_PRIORITY +#define NRFX_DEFAULT_IRQ_PRIORITY 0 +#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 1 +#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: 3. + */ +#ifndef NRFX_CLOCK_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_CLOCK_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#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: 3. + */ +#ifndef NRFX_COMP_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_COMP_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_COMP_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_COMP_CONFIG_LOG_ENABLED +#define NRFX_COMP_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_COMP_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_COMP_CONFIG_LOG_LEVEL +#define NRFX_COMP_CONFIG_LOG_LEVEL 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 + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_DPPI_CONFIG_LOG_LEVEL +#define NRFX_DPPI_CONFIG_LOG_LEVEL 0 +#endif + +/** + * @brief NRFX_EGU_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_EGU_ENABLED +#define NRFX_EGU_ENABLED 0 +#endif + +/** + * @brief NRFX_EGU_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 3. + */ +#ifndef NRFX_EGU_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_EGU_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#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_GPIOTE_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_GPIOTE_ENABLED +#define NRFX_GPIOTE_ENABLED 0 +#endif + +/** + * @brief NRFX_GPIOTE_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 3. + */ +#ifndef NRFX_GPIOTE_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_GPIOTE_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_GPIOTE_CONFIG_NUM_OF_EVT_HANDLERS + * + * Integer value. Minimum: 0. Maximum: 15. + */ +#ifndef NRFX_GPIOTE_CONFIG_NUM_OF_EVT_HANDLERS +#define NRFX_GPIOTE_CONFIG_NUM_OF_EVT_HANDLERS 2 +#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_GPIOTE20_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_GPIOTE20_ENABLED +#define NRFX_GPIOTE20_ENABLED 0 +#endif + +/** + * @brief NRFX_GPIOTE30_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_GPIOTE30_ENABLED +#define NRFX_GPIOTE30_ENABLED 0 +#endif + +/** + * @brief NRFX_GRTC_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_GRTC_ENABLED +#define NRFX_GRTC_ENABLED 0 +#endif + +/** + * @brief NRFX_GRTC_CONFIG_SLEEP_ALLOWED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_GRTC_CONFIG_SLEEP_ALLOWED +#define NRFX_GRTC_CONFIG_SLEEP_ALLOWED 0 +#endif + +/** + * @brief NRFX_GRTC_CONFIG_AUTOEN + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_GRTC_CONFIG_AUTOEN +#define NRFX_GRTC_CONFIG_AUTOEN 0 +#endif + +/** + * @brief NRFX_GRTC_CONFIG_AUTOSTART + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_GRTC_CONFIG_AUTOSTART +#define NRFX_GRTC_CONFIG_AUTOSTART 0 +#endif + +/** + * @brief NRFX_GRTC_CONFIG_NUM_OF_CC_CHANNELS + * + * Integer value. + */ +#ifndef NRFX_GRTC_CONFIG_NUM_OF_CC_CHANNELS +#define NRFX_GRTC_CONFIG_NUM_OF_CC_CHANNELS 2 +#endif + +/** + * @brief NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK + */ +#ifndef NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK +#define NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK 0x00000018 +#endif + +/** + * @brief NRFX_GRTC_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 3. + */ +#ifndef NRFX_GRTC_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_GRTC_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_GRTC_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_GRTC_CONFIG_LOG_ENABLED +#define NRFX_GRTC_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_GRTC_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_GRTC_CONFIG_LOG_LEVEL +#define NRFX_GRTC_CONFIG_LOG_LEVEL 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: 3. + */ +#ifndef NRFX_I2S_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_I2S_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_I2S_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_I2S_CONFIG_LOG_ENABLED +#define NRFX_I2S_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_I2S_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_I2S_CONFIG_LOG_LEVEL +#define NRFX_I2S_CONFIG_LOG_LEVEL 0 +#endif + +/** + * @brief NRFX_I2S20_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_I2S20_ENABLED +#define NRFX_I2S20_ENABLED 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: 3. + */ +#ifndef NRFX_LPCOMP_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_LPCOMP_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_LPCOMP_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_LPCOMP_CONFIG_LOG_ENABLED +#define NRFX_LPCOMP_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_LPCOMP_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_LPCOMP_CONFIG_LOG_LEVEL +#define NRFX_LPCOMP_CONFIG_LOG_LEVEL 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: 3. + */ +#ifndef NRFX_NFCT_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_NFCT_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_NFCT_CONFIG_TIMER_INSTANCE_ID - Timer instance used for workarounds in the driver. + * + * Integer value. Minimum: 0. Maximum: 5. + */ +#ifndef NRFX_NFCT_CONFIG_TIMER_INSTANCE_ID +#define NRFX_NFCT_CONFIG_TIMER_INSTANCE_ID 0 +#endif + +/** + * @brief NRFX_NFCT_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_NFCT_CONFIG_LOG_ENABLED +#define NRFX_NFCT_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_NFCT_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_NFCT_CONFIG_LOG_LEVEL +#define NRFX_NFCT_CONFIG_LOG_LEVEL 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: 3 + */ +#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: 3. + */ +#ifndef NRFX_POWER_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_POWER_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_PRS_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_ENABLED +#define NRFX_PRS_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_CONFIG_LOG_ENABLED +#define NRFX_PRS_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_PRS_CONFIG_LOG_LEVEL +#define NRFX_PRS_CONFIG_LOG_LEVEL 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: 3 + */ +#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: 3. + */ +#ifndef NRFX_QDEC_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_QDEC_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_QDEC_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_QDEC_CONFIG_LOG_ENABLED +#define NRFX_QDEC_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_QDEC_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_QDEC_CONFIG_LOG_LEVEL +#define NRFX_QDEC_CONFIG_LOG_LEVEL 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_RRAMC_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_RRAMC_ENABLED +#define NRFX_RRAMC_ENABLED 0 +#endif + +/** + * @brief NRFX_RRAMC_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 3. + */ +#ifndef NRFX_RRAMC_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_RRAMC_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_RRAMC_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_RRAMC_CONFIG_LOG_ENABLED +#define NRFX_RRAMC_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_RRAMC_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_RRAMC_CONFIG_LOG_LEVEL +#define NRFX_RRAMC_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_RTC_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 3. + */ +#ifndef NRFX_RTC_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_RTC_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_RTC_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_RTC_CONFIG_LOG_ENABLED +#define NRFX_RTC_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_RTC_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_RTC_CONFIG_LOG_LEVEL +#define NRFX_RTC_CONFIG_LOG_LEVEL 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_SAADC_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SAADC_ENABLED +#define NRFX_SAADC_ENABLED 0 +#endif + +/** + * @brief NRFX_SAADC_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 3. + */ +#ifndef NRFX_SAADC_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_SAADC_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_SAADC_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SAADC_CONFIG_LOG_ENABLED +#define NRFX_SAADC_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_SAADC_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_SAADC_CONFIG_LOG_LEVEL +#define NRFX_SAADC_CONFIG_LOG_LEVEL 0 +#endif + +/** + * @brief NRFX_SPIM_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM_ENABLED +#define NRFX_SPIM_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: 3. + */ +#ifndef NRFX_SPIM_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_SPIM_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_SPIM_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM_CONFIG_LOG_ENABLED +#define NRFX_SPIM_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_SPIM_CONFIG_LOG_LEVEL +#define NRFX_SPIM_CONFIG_LOG_LEVEL 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_SPIS_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS_ENABLED +#define NRFX_SPIS_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 3. + */ +#ifndef NRFX_SPIS_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_SPIS_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_SPIS_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS_CONFIG_LOG_ENABLED +#define NRFX_SPIS_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_SPIS_CONFIG_LOG_LEVEL +#define NRFX_SPIS_CONFIG_LOG_LEVEL 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_TEMP_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TEMP_ENABLED +#define NRFX_TEMP_ENABLED 0 +#endif + +/** + * @brief NRFX_TEMP_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 3. + */ +#ifndef NRFX_TEMP_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_TEMP_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_TEMP_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TEMP_CONFIG_LOG_ENABLED +#define NRFX_TEMP_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_TEMP_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_TEMP_CONFIG_LOG_LEVEL +#define NRFX_TEMP_CONFIG_LOG_LEVEL 0 +#endif + +/** + * @brief NRFX_TIMER_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER_ENABLED +#define NRFX_TIMER_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 3. + */ +#ifndef NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_TIMER_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER_CONFIG_LOG_ENABLED +#define NRFX_TIMER_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_TIMER_CONFIG_LOG_LEVEL +#define NRFX_TIMER_CONFIG_LOG_LEVEL 0 +#endif + +/** + * @brief NRFX_TIMER00_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER00_ENABLED +#define NRFX_TIMER00_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_TWIM_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM_ENABLED +#define NRFX_TWIM_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 3. + */ +#ifndef NRFX_TWIM_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_TWIM_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_TWIM_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM_CONFIG_LOG_ENABLED +#define NRFX_TWIM_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_TWIM_CONFIG_LOG_LEVEL +#define NRFX_TWIM_CONFIG_LOG_LEVEL 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_TWIS_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS_ENABLED +#define NRFX_TWIS_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 3. + */ +#ifndef NRFX_TWIS_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_TWIS_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_TWIS_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS_CONFIG_LOG_ENABLED +#define NRFX_TWIS_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS_ASSUME_INIT_AFTER_RESET_ONLY + * Assume that any instance would be initialized only once. + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS_ASSUME_INIT_AFTER_RESET_ONLY +#define NRFX_TWIS_ASSUME_INIT_AFTER_RESET_ONLY 0 +#endif + +/** + * @brief NRFX_TWIS_NO_SYNC_MODE - Remove support for synchronous mode. + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS_NO_SYNC_MODE +#define NRFX_TWIS_NO_SYNC_MODE 0 +#endif + +/** + * @brief NRFX_TWIS_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_TWIS_CONFIG_LOG_LEVEL +#define NRFX_TWIS_CONFIG_LOG_LEVEL 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_UARTE_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE_ENABLED +#define NRFX_UARTE_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE_CONFIG_SKIP_GPIO_CONFIG + * If enabled, support for configuring GPIO pins is removed from the driver + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE_CONFIG_SKIP_GPIO_CONFIG +#define NRFX_UARTE_CONFIG_SKIP_GPIO_CONFIG 0 +#endif + +/** + * @brief NRFX_UARTE_CONFIG_SKIP_PSEL_CONFIG + * If enabled, support for configuring PSEL registers is removed from the driver + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE_CONFIG_SKIP_PSEL_CONFIG +#define NRFX_UARTE_CONFIG_SKIP_PSEL_CONFIG 0 +#endif + +/** + * @brief NRFX_UARTE_CONFIG_TX_LINK + * If enabled, driver supports linking of TX transfers. + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE_CONFIG_TX_LINK +#define NRFX_UARTE_CONFIG_TX_LINK 1 +#endif + +/** + * @brief NRFX_UARTE_CONFIG_RX_CACHE_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE_CONFIG_RX_CACHE_ENABLED +#define NRFX_UARTE_CONFIG_RX_CACHE_ENABLED 1 +#endif + +/** + * @brief NRFX_UARTE_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 3. + */ +#ifndef NRFX_UARTE_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_UARTE_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_UARTE_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE_CONFIG_LOG_ENABLED +#define NRFX_UARTE_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_UARTE_CONFIG_LOG_LEVEL +#define NRFX_UARTE_CONFIG_LOG_LEVEL 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_VEVIF_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_VEVIF_ENABLED +#define NRFX_VEVIF_ENABLED 0 +#endif + +/** + * @brief NRFX_WDT_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_WDT_ENABLED +#define NRFX_WDT_ENABLED 0 +#endif + +/** + * @brief NRFX_WDT_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 3. + */ +#ifndef NRFX_WDT_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_WDT_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_WDT_CONFIG_NO_IRQ - Remove WDT IRQ handling from WDT driver + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_WDT_CONFIG_NO_IRQ +#define NRFX_WDT_CONFIG_NO_IRQ 0 +#endif + +/** + * @brief NRFX_WDT_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_WDT_CONFIG_LOG_ENABLED +#define NRFX_WDT_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_WDT_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_WDT_CONFIG_LOG_LEVEL +#define NRFX_WDT_CONFIG_LOG_LEVEL 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 + +#endif /* NRFX_CONFIG_NRF54L15_ENGA_FLPR_H__ */ diff --git a/modules/hal_nordic/nrfx/nrfx_glue.h b/modules/hal_nordic/nrfx/nrfx_glue.h index 593aff6fcc7..15a1f076063 100644 --- a/modules/hal_nordic/nrfx/nrfx_glue.h +++ b/modules/hal_nordic/nrfx/nrfx_glue.h @@ -368,6 +368,10 @@ void nrfx_busy_wait(uint32_t usec_to_wait); #include <../src/nrf_802154_peripherals_nrf54l.h> #define NRFX_PPI_CHANNELS_USED_BY_802154_DRV NRF_802154_DPPI_CHANNELS_USED_MASK #define NRFX_PPI_GROUPS_USED_BY_802154_DRV NRF_802154_DPPI_GROUPS_USED_MASK +#elif defined(NRF54H_SERIES) +#include <../src/nrf_802154_peripherals_nrf54h.h> +#define NRFX_PPI_CHANNELS_USED_BY_802154_DRV NRF_802154_DPPI_CHANNELS_USED_MASK +#define NRFX_PPI_GROUPS_USED_BY_802154_DRV NRF_802154_DPPI_GROUPS_USED_MASK #else #error Unsupported chip family #endif diff --git a/modules/hostap/Kconfig b/modules/hostap/Kconfig index 686c65695c2..473b6278055 100644 --- a/modules/hostap/Kconfig +++ b/modules/hostap/Kconfig @@ -112,19 +112,18 @@ config WIFI_NM_WPA_SUPPLICANT_CRYPTO select MBEDTLS select MBEDTLS_CIPHER_MODE_CTR_ENABLED select MBEDTLS_CIPHER_MODE_CBC_ENABLED - select MBEDTLS_PK_WRITE_C select MBEDTLS_ECP_C select MBEDTLS_ECP_ALL_ENABLED - select MBEDTLS_PKCS5_C select MBEDTLS_MAC_CMAC_ENABLED -# select MBEDTLS_PK_C -# select MBEDTLS_CIPHER_PADDING_PKCS7 -# select MBEDTLS_CIPHER_MODE_CBC -# select MBEDTLS_CIPHER_MODE_CTR -# select MBEDTLS_LEGACY_CRYPTO_C -# select MBEDTLS_CTR_DRBG_C -# select MBEDTLS_PK_WRITE_C -# select MBEDTLS_KEY_EXCHANGE_ALL_ENABLED + select MBEDTLS_PKCS5_C + select MBEDTLS_PK_WRITE_C + select MBEDTLS_ECDH_C + select MBEDTLS_ECDSA_C + select MBEDTLS_ECJPAKE_C + select MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED + select MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED + select MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED + select MBEDTLS_KEY_EXCHANGE_ALL_ENABLED config WIFI_NM_WPA_SUPPLICANT_CRYPTO_NONE bool "No Crypto support for WiFi" diff --git a/modules/hostap/src/supp_api.c b/modules/hostap/src/supp_api.c index 305c27f3546..c1b748c4640 100644 --- a/modules/hostap/src/supp_api.c +++ b/modules/hostap/src/supp_api.c @@ -269,11 +269,15 @@ static inline int chan_to_freq(int chan) * op_class for 5GHz channels as there is no user input * for these (yet). */ - int freq; + int freq = -1; + int op_classes[] = {81, 82, 128}; + int op_classes_size = ARRAY_SIZE(op_classes); - freq = ieee80211_chan_to_freq(NULL, 81, chan); - if (freq <= 0) { - freq = ieee80211_chan_to_freq(NULL, 128, chan); + for (int i = 0; i < op_classes_size; i++) { + freq = ieee80211_chan_to_freq(NULL, op_classes[i], chan); + if (freq > 0) { + break; + } } if (freq <= 0) { @@ -322,6 +326,7 @@ static int wpas_add_and_config_network(struct wpa_supplicant *wpa_s, { struct add_network_resp resp = {0}; char *chan_list = NULL; + struct net_eth_addr mac = {0}; int ret = 0; if (!wpa_cli_cmd_v("remove_network all")) { @@ -483,6 +488,28 @@ static int wpas_add_and_config_network(struct wpa_supplicant *wpa_s, } } + memcpy((void *)&mac, params->bssid, WIFI_MAC_ADDR_LEN); + if (net_eth_is_addr_broadcast(&mac) || + net_eth_is_addr_multicast(&mac)) { + wpa_printf(MSG_ERROR, "Invalid BSSID. Configuration " + "of multicast or broadcast MAC is not allowed."); + ret = -EINVAL; + goto rem_net; + } + + if (!net_eth_is_addr_unspecified(&mac)) { + char bssid_str[MAC_STR_LEN] = {0}; + + snprintf(bssid_str, MAC_STR_LEN, "%02x:%02x:%02x:%02x:%02x:%02x", + params->bssid[0], params->bssid[1], params->bssid[2], + params->bssid[3], params->bssid[4], params->bssid[5]); + + if (!wpa_cli_cmd_v("set_network %d bssid %s", + resp.network_id, bssid_str)) { + goto out; + } + } + /* enable and select network */ if (!wpa_cli_cmd_v("enable_network %d", resp.network_id)) { goto out; diff --git a/modules/hostap/src/supp_api.h b/modules/hostap/src/supp_api.h index 04d720d7509..e4f92e0b969 100644 --- a/modules/hostap/src/supp_api.h +++ b/modules/hostap/src/supp_api.h @@ -16,6 +16,7 @@ #define MAC_ADDR_LEN 6 #endif +#define MAC_STR_LEN 18 /* for ':' or '-' separated MAC address string */ #define CHAN_NUM_LEN 6 /* for space-separated channel numbers string */ /** diff --git a/modules/hostap/src/supp_events.c b/modules/hostap/src/supp_events.c index 31a1e55e793..48a4f58c5ee 100644 --- a/modules/hostap/src/supp_events.c +++ b/modules/hostap/src/supp_events.c @@ -36,6 +36,7 @@ static const struct wpa_supp_event_info { { "CTRL-EVENT-BSS-REMOVED", SUPPLICANT_EVENT_BSS_REMOVED }, { "CTRL-EVENT-TERMINATING", SUPPLICANT_EVENT_TERMINATING }, { "CTRL-EVENT-SCAN-STARTED", SUPPLICANT_EVENT_SCAN_STARTED }, + { "CTRL-EVENT-SCAN-RESULTS", SUPPLICANT_EVENT_SCAN_RESULTS }, { "CTRL-EVENT-SCAN-FAILED", SUPPLICANT_EVENT_SCAN_FAILED }, { "CTRL-EVENT-NETWORK-NOT-FOUND", SUPPLICANT_EVENT_NETWORK_NOT_FOUND }, { "CTRL-EVENT-NETWORK-ADDED", SUPPLICANT_EVENT_NETWORK_ADDED }, @@ -67,7 +68,7 @@ static enum wifi_conn_status wpas_to_wifi_mgmt_conn_status(int status) } } -static enum wifi_disconn_reason wpas_to_wifi_mgmt_diconn_status(int status) +static enum wifi_disconn_reason wpas_to_wifi_mgmt_disconn_status(int status) { switch (status) { case WLAN_REASON_DEAUTH_LEAVING: @@ -172,6 +173,7 @@ static int supplicant_process_status(struct supplicant_int_event_data *event_dat break; case SUPPLICANT_EVENT_TERMINATING: case SUPPLICANT_EVENT_SCAN_STARTED: + case SUPPLICANT_EVENT_SCAN_RESULTS: case SUPPLICANT_EVENT_SCAN_FAILED: case SUPPLICANT_EVENT_NETWORK_NOT_FOUND: case SUPPLICANT_EVENT_NETWORK_ADDED: @@ -219,7 +221,7 @@ int supplicant_send_wifi_mgmt_conn_event(void *ctx, int status_code) int supplicant_send_wifi_mgmt_disc_event(void *ctx, int reason_code) { struct wpa_supplicant *wpa_s = ctx; - int status = wpas_to_wifi_mgmt_diconn_status(reason_code); + int status = wpas_to_wifi_mgmt_disconn_status(reason_code); enum net_event_wifi_cmd event; if (!wpa_s || !wpa_s->current_ssid) { diff --git a/modules/loramac-node/CMakeLists.txt b/modules/loramac-node/CMakeLists.txt index 1a84a5f6ac4..9e0bdbc9877 100644 --- a/modules/loramac-node/CMakeLists.txt +++ b/modules/loramac-node/CMakeLists.txt @@ -30,6 +30,8 @@ if(${CONFIG_HAS_SEMTECH_LORAMAC}) zephyr_library_include_directories( ${ZEPHYR_LORAMAC_NODE_MODULE_DIR}/src/mac ${ZEPHYR_LORAMAC_NODE_MODULE_DIR}/src/mac/region + # required for FUOTA FragDecoder.h + ${ZEPHYR_LORAMAC_NODE_MODULE_DIR}/src/apps/LoRaMac/common/LmHandler/packages ) endif() @@ -53,6 +55,10 @@ zephyr_library_sources_ifdef(CONFIG_HAS_SEMTECH_LORAMAC ${ZEPHYR_LORAMAC_NODE_MODULE_DIR}/src/mac/LoRaMacSerializer.c ) +zephyr_library_sources_ifdef(CONFIG_LORAWAN_FRAG_TRANSPORT + ${ZEPHYR_LORAMAC_NODE_MODULE_DIR}/src/apps/LoRaMac/common/LmHandler/packages/FragDecoder.c +) + zephyr_library_sources_ifdef(CONFIG_HAS_SEMTECH_LORAMAC ${ZEPHYR_LORAMAC_NODE_MODULE_DIR}/src/mac/region/Region.c ${ZEPHYR_LORAMAC_NODE_MODULE_DIR}/src/mac/region/RegionCommon.c diff --git a/modules/lvgl/input/lvgl_keypad_input.c b/modules/lvgl/input/lvgl_keypad_input.c index 92066478f56..fb131f47a29 100644 --- a/modules/lvgl/input/lvgl_keypad_input.c +++ b/modules/lvgl/input/lvgl_keypad_input.c @@ -40,8 +40,7 @@ static void lvgl_keypad_process_event(const struct device *dev, struct input_eve } 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) { + 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"); } } diff --git a/modules/lvgl/input/lvgl_pointer_input.c b/modules/lvgl/input/lvgl_pointer_input.c index 1abfd69d29a..e1b12243750 100644 --- a/modules/lvgl/input/lvgl_pointer_input.c +++ b/modules/lvgl/input/lvgl_pointer_input.c @@ -21,24 +21,39 @@ struct lvgl_pointer_input_config { bool invert_y; }; +struct lvgl_pointer_input_data { + struct lvgl_common_input_data common_data; + uint32_t point_x; + uint32_t point_y; +}; + static void lvgl_pointer_process_event(const struct device *dev, struct input_event *evt) { const struct lvgl_pointer_input_config *cfg = dev->config; - struct lvgl_common_input_data *data = dev->data; + struct lvgl_pointer_input_data *data = dev->data; lv_disp_t *disp = lv_disp_get_default(); struct lvgl_disp_data *disp_data = disp->driver->user_data; struct display_capabilities *cap = &disp_data->cap; - lv_point_t *point = &data->pending_event.point; + lv_point_t *point = &data->common_data.pending_event.point; switch (evt->code) { case INPUT_ABS_X: - point->x = evt->value; + if (cfg->swap_xy) { + data->point_y = evt->value; + } else { + data->point_x = evt->value; + } break; case INPUT_ABS_Y: - point->y = evt->value; + if (cfg->swap_xy) { + data->point_x = evt->value; + } else { + data->point_y = evt->value; + } break; case INPUT_BTN_TOUCH: - data->pending_event.state = evt->value ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL; + data->common_data.pending_event.state = + evt->value ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL; break; } @@ -46,49 +61,37 @@ static void lvgl_pointer_process_event(const struct device *dev, struct input_ev return; } - /* adjust coordinates */ - if (cfg->swap_xy) { - lv_coord_t tmp; - - tmp = point->x; - point->x = point->y; - point->y = tmp; - } + point->x = data->point_x; + point->y = data->point_y; if (cfg->invert_x) { if (cap->current_orientation == DISPLAY_ORIENTATION_NORMAL || cap->current_orientation == DISPLAY_ORIENTATION_ROTATED_180) { - point->x = cap->x_resolution - point->x; + point->x = cap->x_resolution - data->point_x; } else { - point->x = cap->y_resolution - point->x; + point->x = cap->y_resolution - data->point_x; } } if (cfg->invert_y) { if (cap->current_orientation == DISPLAY_ORIENTATION_NORMAL || cap->current_orientation == DISPLAY_ORIENTATION_ROTATED_180) { - point->y = cap->y_resolution - point->y; + point->y = cap->y_resolution - data->point_y; } else { - point->y = cap->x_resolution - point->y; + point->y = cap->x_resolution - data->point_y; } } /* rotate touch point to match display rotation */ if (cap->current_orientation == DISPLAY_ORIENTATION_ROTATED_90) { - lv_coord_t tmp; - - tmp = point->x; - point->x = point->y; - point->y = cap->y_resolution - tmp; + point->x = data->point_y; + point->y = cap->y_resolution - data->point_x; } else if (cap->current_orientation == DISPLAY_ORIENTATION_ROTATED_180) { - point->x = cap->x_resolution - point->x; - point->y = cap->y_resolution - point->y; + point->x = cap->x_resolution - data->point_x; + point->y = cap->y_resolution - data->point_y; } else if (cap->current_orientation == DISPLAY_ORIENTATION_ROTATED_270) { - lv_coord_t tmp; - - tmp = point->x; - point->x = cap->x_resolution - point->y; - point->y = tmp; + point->x = cap->x_resolution - data->point_y; + point->y = data->point_x; } /* filter readings within display */ @@ -104,7 +107,8 @@ static void lvgl_pointer_process_event(const struct device *dev, struct input_ev point->y = cap->y_resolution - 1; } - if (k_msgq_put(cfg->common_config.event_msgq, &data->pending_event, K_NO_WAIT) != 0) { + if (k_msgq_put(cfg->common_config.event_msgq, &data->common_data.pending_event, + K_NO_WAIT) != 0) { LOG_WRN("Could not put input data into queue"); } } @@ -123,8 +127,8 @@ int lvgl_pointer_input_init(const struct device *dev) .invert_x = DT_INST_PROP(inst, invert_x), \ .invert_y = DT_INST_PROP(inst, invert_y), \ }; \ - static struct lvgl_common_input_data lvgl_common_input_data_##inst; \ - DEVICE_DT_INST_DEFINE(inst, NULL, NULL, &lvgl_common_input_data_##inst, \ + static struct lvgl_pointer_input_data lvgl_pointer_input_data_##inst; \ + DEVICE_DT_INST_DEFINE(inst, NULL, NULL, &lvgl_pointer_input_data_##inst, \ &lvgl_pointer_input_config_##inst, POST_KERNEL, \ CONFIG_INPUT_INIT_PRIORITY, NULL); diff --git a/modules/mbedtls/CMakeLists.txt b/modules/mbedtls/CMakeLists.txt index a6277f654b5..ca17eb0c44f 100644 --- a/modules/mbedtls/CMakeLists.txt +++ b/modules/mbedtls/CMakeLists.txt @@ -121,6 +121,7 @@ zephyr_interface_library_named(mbedTLS) ${ZEPHYR_CURRENT_MODULE_DIR}/library/psa_crypto_cipher.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_ffdh.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/psa_crypto_hash.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/psa_crypto_mac.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/psa_crypto_rsa.c diff --git a/modules/mbedtls/Kconfig b/modules/mbedtls/Kconfig index 99eb3bcf859..1c80cd68669 100644 --- a/modules/mbedtls/Kconfig +++ b/modules/mbedtls/Kconfig @@ -14,6 +14,8 @@ config MBEDTLS_PROMPTLESS mbed TLS menu prompt and instead handle the selection of MBEDTLS from dependent sub-configurations and thus prevent stuck symbol behavior. +rsource "Kconfig.psa" + menuconfig MBEDTLS bool "mbed TLS Support" if !MBEDTLS_PROMPTLESS help @@ -246,6 +248,3 @@ config APP_LINK_WITH_MBEDTLS issues for 'app'. endif # MBEDTLS - -# Add PSA configurations -rsource "Kconfig.psa" diff --git a/modules/mbedtls/Kconfig.psa b/modules/mbedtls/Kconfig.psa index 27e50381779..c032239040a 100644 --- a/modules/mbedtls/Kconfig.psa +++ b/modules/mbedtls/Kconfig.psa @@ -1,8 +1,18 @@ -# -# Copyright (c) 2022 Nordic Semiconductor -# +# Copyright (c) 2024 Nordic Semiconductor ASA # SPDX-License-Identifier: Apache-2.0 -# + +config MBEDTLS_PSA_CRYPTO_CLIENT + bool + default y + depends on BUILD_WITH_TFM || MBEDTLS_PSA_CRYPTO_C + +if MBEDTLS_PSA_CRYPTO_CLIENT + +config PSA_WANT_ALG_SHA_256 + bool "SHA-256 hash algorithm through PSA" + +endif # MBEDTLS_PSA_CRYPTO_CLIENT + menu "PSA RNG support" config PSA_WANT_GENERATE_RANDOM @@ -397,10 +407,6 @@ config PSA_WANT_ALG_SHA_224 bool prompt "PSA SHA-224 support" if !PSA_PROMPTLESS -config PSA_WANT_ALG_SHA_256 - bool - prompt "PSA SHA-256 support" if !PSA_PROMPTLESS - config PSA_WANT_ALG_SHA_384 bool prompt "PSA SHA-384 support" if !PSA_PROMPTLESS diff --git a/modules/mbedtls/Kconfig.tls-generic b/modules/mbedtls/Kconfig.tls-generic index d629c1b1d2a..1846e3ae597 100644 --- a/modules/mbedtls/Kconfig.tls-generic +++ b/modules/mbedtls/Kconfig.tls-generic @@ -128,6 +128,9 @@ config MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED bool "ECJPAKE based ciphersuite modes" depends on MBEDTLS_ECJPAKE_C +config MBEDTLS_HKDF_C + bool "HMAC-based Extract-and-Expand Key Derivation Function" + comment "Elliptic curve libraries" config MBEDTLS_ECDH_C @@ -223,17 +226,14 @@ config MBEDTLS_HASH_ALL_ENABLED select MBEDTLS_HASH_SHA512_ENABLED config MBEDTLS_HASH_SHA256_ENABLED - bool "SHA256 hash" - default y if !NET_L2_OPENTHREAD + bool "SHA224 and SHA256 hashes" config MBEDTLS_HASH_SHA384_ENABLED bool "SHA384 hash" - default y if !NET_L2_OPENTHREAD select MBEDTLS_HASH_SHA512_ENABLED config MBEDTLS_HASH_SHA512_ENABLED bool "SHA512 hash" - default y if !NET_L2_OPENTHREAD comment "Supported cipher modes" @@ -334,11 +334,9 @@ config MBEDTLS_MAC_MD4_ENABLED config MBEDTLS_MAC_MD5_ENABLED bool "MD5 hash algorithm" - default y if !NET_L2_OPENTHREAD config MBEDTLS_MAC_SHA1_ENABLED bool "SHA1 hash algorithm" - default y if !NET_L2_OPENTHREAD config MBEDTLS_MAC_SHA256_ENABLED bool "SHA-224 and SHA-256 hash algorithms" @@ -493,16 +491,43 @@ config MBEDTLS_SSL_EXTENDED_MASTER_SECRET which ensures that master secrets are different for every connection and every session. +choice MBEDTLS_PSA_CRYPTO_RND_SOURCE + prompt "Select random source for built-in PSA crypto" + depends on MBEDTLS_PSA_CRYPTO_C + default MBEDTLS_PSA_CRYPTO_LEGACY_RNG + +config MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG + bool "Use a cryptographically secure driver as random source" + depends on CSPRNG_ENABLED + help + Use cryptographically secure random generator to provide random data + instead of legacy MbedTLS modules (ENTROPY + CTR_DRBG/HMAC_DRBG). + +config MBEDTLS_PSA_CRYPTO_LEGACY_RNG + bool "Use legacy modules to generate random data" + select MBEDTLS_ENTROPY_ENABLED + select MBEDTLS_CTR_DRBG_ENABLED if !MBEDTLS_HMAC_DRBG_ENABLED + help + Use legacy MbedTLS modules (ENTROPY + CTR_DRBG/HMAC_DRBG) as random + source generators. + +endchoice + config MBEDTLS_PSA_CRYPTO_C bool "Platform Security Architecture cryptography API" - depends on MBEDTLS_ENTROPY_ENABLED - depends on MBEDTLS_CTR_DRBG_ENABLED || MBEDTLS_HMAC_DRBG_ENABLED default y if UOSCORE || UEDHOC +config MBEDTLS_USE_PSA_CRYPTO + bool "Use PSA APIs instead of legacy MbedTLS when possible" + help + Use PSA APIs instead of legacy MbedTLS functions in TLS/DTLS and other + "intermediate" modules such as PK, MD and Cipher. + config MBEDTLS_LMS bool "Support LMS signature schemes" - depends on MBEDTLS_PSA_CRYPTO_C + depends on MBEDTLS_PSA_CRYPTO_CLIENT depends on MBEDTLS_HASH_SHA256_ENABLED + select PSA_WANT_ALG_SHA_256 config MBEDTLS_SSL_DTLS_CONNECTION_ID bool "DTLS Connection ID extension" diff --git a/modules/mbedtls/configs/config-tls-generic.h b/modules/mbedtls/configs/config-tls-generic.h index 7a7294aba89..6a731d4f61a 100644 --- a/modules/mbedtls/configs/config-tls-generic.h +++ b/modules/mbedtls/configs/config-tls-generic.h @@ -35,7 +35,6 @@ #if defined(CONFIG_MBEDTLS_LMS) #define MBEDTLS_LMS_C -#define PSA_WANT_ALG_SHA_256 1 #endif #if defined(CONFIG_MBEDTLS_HAVE_TIME_DATE) @@ -138,6 +137,10 @@ #define MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED #endif +#if defined(CONFIG_MBEDTLS_HKDF_C) +#define MBEDTLS_HKDF_C +#endif + /* Supported cipher modes */ #if defined(CONFIG_MBEDTLS_CIPHER_AES_ENABLED) @@ -390,7 +393,7 @@ #define MBEDTLS_X509_CRT_PARSE_C #endif -#if defined (CONFIG_MBEDTLS_PEM_CERTIFICATE_FORMAT) && \ +#if defined(CONFIG_MBEDTLS_PEM_CERTIFICATE_FORMAT) && \ defined(MBEDTLS_X509_CRT_PARSE_C) #define MBEDTLS_PEM_PARSE_C #define MBEDTLS_BASE64_C @@ -425,11 +428,11 @@ #define MBEDTLS_PK_C #endif -#if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_ECDSA_C) +#if defined(MBEDTLS_ECDSA_C) || defined(MBEDTLS_RSA_C) || defined(MBEDTLS_X509_USE_C) #define MBEDTLS_ASN1_PARSE_C #endif -#if defined(MBEDTLS_ECDSA_C) || defined(MBEDTLS_PK_WRITE_C) +#if defined(MBEDTLS_ECDSA_C) || defined(MBEDTLS_RSA_C) || defined(MBEDTLS_PK_WRITE_C) #define MBEDTLS_ASN1_WRITE_C #endif @@ -464,17 +467,28 @@ #define MBEDTLS_SSL_EXTENDED_MASTER_SECRET #endif +#if defined(CONFIG_MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) +#define MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG +#endif + #if defined(CONFIG_MBEDTLS_PSA_CRYPTO_C) #define MBEDTLS_PSA_CRYPTO_C + +#if defined(CONFIG_MBEDTLS_USE_PSA_CRYPTO) #define MBEDTLS_USE_PSA_CRYPTO +#endif -#if defined(CONFIG_ARCH_POSIX) +#if defined(CONFIG_ARCH_POSIX) && !defined(CONFIG_PICOLIBC) #define MBEDTLS_PSA_KEY_SLOT_COUNT 64 #define MBEDTLS_PSA_CRYPTO_STORAGE_C #define MBEDTLS_PSA_ITS_FILE_C #define MBEDTLS_FS_IO #endif +#endif /* CONFIG_MBEDTLS_PSA_CRYPTO_C */ + +#if defined(CONFIG_MBEDTLS_PSA_CRYPTO_CLIENT) +#define MBEDTLS_PSA_CRYPTO_CLIENT #endif #if defined(CONFIG_MBEDTLS_TLS_VERSION_1_2) && defined(CONFIG_MBEDTLS_PSA_CRYPTO_C) @@ -485,10 +499,16 @@ #define MBEDTLS_SSL_DTLS_CONNECTION_ID #endif -/* User config file */ - #if defined(CONFIG_MBEDTLS_USER_CONFIG_FILE) #include CONFIG_MBEDTLS_USER_CONFIG_FILE #endif +#if defined(CONFIG_BUILD_WITH_TFM) +#undef MBEDTLS_PSA_CRYPTO_C +#endif + +#if defined(CONFIG_PSA_WANT_ALG_SHA_256) +#define PSA_WANT_ALG_SHA_256 1 +#endif + #endif /* MBEDTLS_CONFIG_H */ diff --git a/modules/mbedtls/zephyr_init.c b/modules/mbedtls/zephyr_init.c index 49c9ffc8aff..26ae1761698 100644 --- a/modules/mbedtls/zephyr_init.c +++ b/modules/mbedtls/zephyr_init.c @@ -115,3 +115,26 @@ mbedtls_ms_time_t mbedtls_ms_time(void) { return (mbedtls_ms_time_t)k_uptime_get(); } + +#if defined(CONFIG_MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) +/* MBEDTLS_PSA_CRYPTO_C requires a random generator to work and this can + * be achieved through either legacy MbedTLS modules + * (ENTROPY + CTR_DRBG/HMAC_DRBG) or provided externally by enabling the + * CONFIG_MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG. In the latter case the following + * callback functions needs to be defined. + */ +psa_status_t mbedtls_psa_external_get_random( + mbedtls_psa_external_random_context_t *context, + uint8_t *output, size_t output_size, size_t *output_length) +{ + (void) context; + + if (sys_csrand_get(output, output_size) != 0) { + return PSA_ERROR_GENERIC_ERROR; + } + + *output_length = output_size; + + return PSA_SUCCESS; +} +#endif diff --git a/modules/nanopb/Kconfig b/modules/nanopb/Kconfig index 41030eac6b3..85c6ede9782 100644 --- a/modules/nanopb/Kconfig +++ b/modules/nanopb/Kconfig @@ -6,6 +6,8 @@ config ZEPHYR_NANOPB_MODULE menuconfig NANOPB bool "Nanopb Support" + # Nanopb requires c_std_11 compiler features like _Static_assert + select REQUIRES_STD_C11 help This option enables the Nanopb library and generator. diff --git a/modules/nanopb/nanopb.cmake b/modules/nanopb/nanopb.cmake index 5158090aae9..c57f89c6ed8 100644 --- a/modules/nanopb/nanopb.cmake +++ b/modules/nanopb/nanopb.cmake @@ -4,6 +4,7 @@ include_guard(GLOBAL) +set(NANOPB_SRC_ROOT_FOLDER ${ZEPHYR_NANOPB_MODULE_DIR}) list(APPEND CMAKE_MODULE_PATH ${ZEPHYR_NANOPB_MODULE_DIR}/extra) find_package(Nanopb REQUIRED) diff --git a/modules/segger/Kconfig b/modules/segger/Kconfig index 04a2a813b98..8591d2601e7 100644 --- a/modules/segger/Kconfig +++ b/modules/segger/Kconfig @@ -79,6 +79,9 @@ config SEGGER_RTT_SECTION_NONE config SEGGER_RTT_SECTION_DTCM bool "Place RTT data in the DTCM linker section" +config SEGGER_RTT_SECTION_CCM + bool "Place RTT data in the CCM linker section" + endchoice endif diff --git a/modules/trusted-firmware-m/CMakeLists.txt b/modules/trusted-firmware-m/CMakeLists.txt index d70e0121f75..5e551777080 100644 --- a/modules/trusted-firmware-m/CMakeLists.txt +++ b/modules/trusted-firmware-m/CMakeLists.txt @@ -15,21 +15,6 @@ set(TFM_VALID_PARTITIONS TFM_PARTITION_FIRMWARE_UPDATE ) -# List of all crypto modules that can be enabled/disabled -# Corresponds to the *_MODULE_DISABLED configs in 'trusted-firmware-m/secure_fw/partitions/crypto/Kconfig' -set(TFM_CRYPTO_MODULES - CRYPTO_RNG_MODULE - CRYPTO_KEY_MODULE - CRYPTO_AEAD_MODULE - CRYPTO_MAC_MODULE - CRYPTO_HASH_MODULE - CRYPTO_CIPHER_MODULE - CRYPTO_ASYM_SIGN_MODULE - CRYPTO_ASYM_ENCRYPT_MODULE - CRYPTO_KEY_DERIVATION_MODULE - ) - - if (CONFIG_BUILD_WITH_TFM) # PSA API awareness for the Non-Secure application target_compile_definitions(app PRIVATE "TFM_PSA_API") @@ -148,14 +133,6 @@ if (CONFIG_BUILD_WITH_TFM) list(APPEND TFM_CMAKE_ARGS -D${partition}=${val}) endforeach() - # Enable TFM crypto modules as specified in Kconfig - foreach(module ${TFM_CRYPTO_MODULES}) - if (CONFIG_TFM_${module}_ENABLED) - # list(APPEND TFM_ENABLED_CRYPTO_MODULES_ARG ${module}) - list(APPEND TFM_CMAKE_ARGS -D${module}_ENABLED=True) - endif() - endforeach() - set(TFM_BINARY_DIR ${CMAKE_BINARY_DIR}/tfm) set(PSA_ARCH_TESTS_PATH ${ZEPHYR_CURRENT_MODULE_DIR}/../psa-arch-tests) @@ -264,6 +241,7 @@ if (CONFIG_BUILD_WITH_TFM) -DCMAKE_BUILD_TYPE=${TFM_CMAKE_BUILD_TYPE} -DTFM_PLATFORM=${CONFIG_TFM_BOARD} -DCONFIG_TFM_BUILD_LOG_QUIET=ON + -DSILENCE_TFM_VERSION_WARNING=ON -DCONFIG_TFM_MEMORY_USAGE_QUIET=OFF -DPython3_EXECUTABLE=${Python3_EXECUTABLE} ${TFM_CMAKE_ARGS} @@ -362,9 +340,14 @@ if (CONFIG_BUILD_WITH_TFM) zephyr_library_sources_ifdef(CONFIG_TFM_PARTITION_PLATFORM ${TFM_INTERFACE_SOURCE_DIR}/tfm_ioctl_core_ns_api.c) endif() - target_include_directories(tfm_api PRIVATE + target_include_directories(tfm_api PUBLIC ${TFM_INTERFACE_INCLUDE_DIR} ${TFM_INTERFACE_INCLUDE_DIR}/crypto_keys + ${ZEPHYR_BASE}/modules/mbedtls/configs + ) + # Pass down the MbedTLS configuration file to use. + target_compile_definitions(tfm_api PUBLIC + MBEDTLS_CONFIG_FILE="${CONFIG_MBEDTLS_CFG_FILE}" ) zephyr_library_link_libraries( diff --git a/modules/trusted-firmware-m/Kconfig.tfm b/modules/trusted-firmware-m/Kconfig.tfm index 171ad654307..1c11a997cf7 100644 --- a/modules/trusted-firmware-m/Kconfig.tfm +++ b/modules/trusted-firmware-m/Kconfig.tfm @@ -32,6 +32,7 @@ menuconfig BUILD_WITH_TFM select BUILD_OUTPUT_HEX imply INIT_ARCH_HW_AT_BOOT imply ARM_NONSECURE_PREEMPTIBLE_SECURE_CALLS + imply MBEDTLS help When enabled, this option instructs the Zephyr build process to additionally generate a TF-M image for the Secure Execution diff --git a/modules/trusted-firmware-m/nordic/CMakeLists.txt b/modules/trusted-firmware-m/nordic/CMakeLists.txt index d75b34a8109..c351f97f906 100644 --- a/modules/trusted-firmware-m/nordic/CMakeLists.txt +++ b/modules/trusted-firmware-m/nordic/CMakeLists.txt @@ -14,7 +14,6 @@ set(partition_includes set(board_includes ${CMAKE_BINARY_DIR}/../zephyr/misc/generated/syscalls_links/include - ${ZEPHYR_BASE}/include ) target_include_directories(platform_region_defs diff --git a/modules/trusted-firmware-m/nordic/ns/CMakeLists.txt b/modules/trusted-firmware-m/nordic/ns/CMakeLists.txt index 5bb8cb5bd94..67ee755c25e 100644 --- a/modules/trusted-firmware-m/nordic/ns/CMakeLists.txt +++ b/modules/trusted-firmware-m/nordic/ns/CMakeLists.txt @@ -17,7 +17,6 @@ set(partition_includes set(board_includes ${CMAKE_BINARY_DIR}/../zephyr/misc/generated/syscalls_links/include - ${ZEPHYR_BASE}/include ) target_include_directories(platform_region_defs diff --git a/samples/application_development/code_relocation_nocopy/README.rst b/samples/application_development/code_relocation_nocopy/README.rst index f8ac178a7e9..2e0f49f520f 100644 --- a/samples/application_development/code_relocation_nocopy/README.rst +++ b/samples/application_development/code_relocation_nocopy/README.rst @@ -10,18 +10,14 @@ using a custom linker script. Differently from the code relocation sample, this sample is relocating the content of the ext_code.c file to a different FLASH section and the code is XIP -directly from there without the need to copy / relocate the code. +directly from there without the need to copy / relocate the code. All other code +(e.g. main(), Zephyr kernel) stays in the internal flash. nRF5340 DK platform instructions ******************************** The nRF5340 DK has a 64 Mb external flash memory supporting Quad SPI. It is -possible to do XIP from the external flash memory. - -The external flash memory is mapped to 0x10000000. - -In this sample we relocate some of the code to the external flash memory with -the remaining Zephyr kernel in the internal flash. +mapped to 0x10000000. To build and flash the application (including the external memory part): @@ -31,7 +27,20 @@ To build and flash the application (including the external memory part): :goals: build flash :compact: -Execution output: +STM32F769I-Discovery platform instructions +****************************************** + +The stm32f769i_disco has 64MB of external flash attached via QSPI. It is mapped +to 0x90000000. + +.. zephyr-app-commands:: + :zephyr-app: samples/application_development/code_relocation_nocopy + :board: stm32f769i_disco + :goals: build flash + :compact: + +Execution output +**************** .. code-block:: console diff --git a/samples/application_development/code_relocation_nocopy/boards/stm32f769i_disco.conf b/samples/application_development/code_relocation_nocopy/boards/stm32f769i_disco.conf new file mode 100644 index 00000000000..eac2504a785 --- /dev/null +++ b/samples/application_development/code_relocation_nocopy/boards/stm32f769i_disco.conf @@ -0,0 +1,2 @@ +CONFIG_FLASH=y +CONFIG_STM32_MEMMAP=y 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 7ead7f6bae4..4bf540a7211 100644 --- a/samples/application_development/code_relocation_nocopy/linker_arm_nocopy.ld +++ b/samples/application_development/code_relocation_nocopy/linker_arm_nocopy.ld @@ -26,6 +26,13 @@ #define EXTFLASH_SIZE DT_PROP_OR(EXTFLASH_NODE, size_in_bytes, \ DT_PROP(EXTFLASH_NODE, size) / 8) +#elif defined(CONFIG_STM32_MEMMAP) && DT_NODE_EXISTS(DT_INST(0, st_stm32_qspi_nor)) +/* On stm32 QSPI, external flash is mapped in XIP region at address given by the reg property. */ + +#define EXTFLASH_NODE DT_INST(0, st_stm32_qspi_nor) +#define EXTFLASH_ADDR DT_REG_ADDR(DT_INST(0, st_stm32_qspi_nor)) +#define EXTFLASH_SIZE DT_REG_ADDR_BY_IDX(DT_INST(0, st_stm32_qspi_nor), 1) + #else /* diff --git a/samples/application_development/code_relocation_nocopy/sample.yaml b/samples/application_development/code_relocation_nocopy/sample.yaml index b9415221e24..a583ea3b44f 100644 --- a/samples/application_development/code_relocation_nocopy/sample.yaml +++ b/samples/application_development/code_relocation_nocopy/sample.yaml @@ -6,6 +6,7 @@ tests: platform_allow: - qemu_cortex_m3 - nrf5340dk/nrf5340/cpuapp + - stm32f769i_disco integration_platforms: - qemu_cortex_m3 tags: linker diff --git a/samples/application_development/sysbuild/with_mcuboot/sample.yaml b/samples/application_development/sysbuild/with_mcuboot/sample.yaml deleted file mode 100644 index 785bc0d2400..00000000000 --- a/samples/application_development/sysbuild/with_mcuboot/sample.yaml +++ /dev/null @@ -1,20 +0,0 @@ -sample: - description: Sample with MCUboot built through sysbuild - name: with mcuboot -tests: - sample.application_development.sysbuild.with_mcuboot: - sysbuild: true - # Platform allowed is used as twister using sysbuild still lacks proper - # filtering support, see discussion in #49552. - platform_allow: - - reel_board - - nrf52840dk/nrf52840 - integration_platforms: - - nrf52840dk/nrf52840 - tags: mcuboot - harness: console - harness_config: - type: multi_line - regex: - - "Address of sample(.*)" - - "Hello sysbuild with mcuboot!(.*)" diff --git a/samples/arch/smp/pktqueue/src/main.c b/samples/arch/smp/pktqueue/src/main.c index 009cd2de966..cfffd813a8b 100644 --- a/samples/arch/smp/pktqueue/src/main.c +++ b/samples/arch/smp/pktqueue/src/main.c @@ -5,7 +5,27 @@ */ #include "pktqueue.h" -#include "main.h" + +/* Amount of parallel processed sender/receiver queues of packet headers */ +#define QUEUE_NUM 2 + +/* Amount of execution threads per pair of queues*/ +#define THREADS_NUM (CONFIG_MP_MAX_NUM_CPUS+1) + +/* Amount of packet headers in a queue */ +#define SIZE_OF_QUEUE 5000 + +/* Size of packet header (in bytes) */ +#define SIZE_OF_HEADER 24 + +/* CRC16 polynomial */ +#define POLYNOMIAL 0x8005 + +/* CRC bytes in the packet */ +#define CRC_BYTE_1 10 +#define CRC_BYTE_2 11 + +#define STACK_SIZE 2048 static struct k_thread tthread[THREADS_NUM*QUEUE_NUM]; static struct k_thread qthread[QUEUE_NUM]; diff --git a/samples/arch/smp/pktqueue/src/main.h b/samples/arch/smp/pktqueue/src/main.h deleted file mode 100644 index 20020563ca1..00000000000 --- a/samples/arch/smp/pktqueue/src/main.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2020 Synopsys, Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include -#include - - -/* Amount of parallel processed sender/receiver queues of packet headers */ -#define QUEUE_NUM 2 - -/* Amount of execution threads per pair of queues*/ -#define THREADS_NUM (CONFIG_MP_MAX_NUM_CPUS+1) - -/* Amount of packet headers in a queue */ -#define SIZE_OF_QUEUE 5000 - -/* Size of packet header (in bytes) */ -#define SIZE_OF_HEADER 24 - -/* CRC16 polynomial */ -#define POLYNOMIAL 0x8005 - -/* CRC bytes in the packet */ -#define CRC_BYTE_1 10 -#define CRC_BYTE_2 11 - -#define STACK_SIZE 2048 diff --git a/samples/basic/blinky_pwm/boards/esp32s3_devkitm.overlay b/samples/basic/blinky_pwm/boards/esp32s3_devkitm_procpu.overlay similarity index 100% rename from samples/basic/blinky_pwm/boards/esp32s3_devkitm.overlay rename to samples/basic/blinky_pwm/boards/esp32s3_devkitm_procpu.overlay diff --git a/samples/basic/blinky_pwm/boards/esp32s3_luatos_core.overlay b/samples/basic/blinky_pwm/boards/esp32s3_luatos_core_procpu.overlay similarity index 100% rename from samples/basic/blinky_pwm/boards/esp32s3_luatos_core.overlay rename to samples/basic/blinky_pwm/boards/esp32s3_luatos_core_procpu.overlay diff --git a/samples/basic/blinky_pwm/boards/esp32s3_luatos_core_esp32s3_procpu_usb.overlay b/samples/basic/blinky_pwm/boards/esp32s3_luatos_core_procpu_usb.overlay similarity index 100% rename from samples/basic/blinky_pwm/boards/esp32s3_luatos_core_esp32s3_procpu_usb.overlay rename to samples/basic/blinky_pwm/boards/esp32s3_luatos_core_procpu_usb.overlay diff --git a/samples/basic/blinky_pwm/boards/ucans32k1sic.overlay b/samples/basic/blinky_pwm/boards/ucans32k1sic.overlay new file mode 100644 index 00000000000..cd2ba599c4f --- /dev/null +++ b/samples/basic/blinky_pwm/boards/ucans32k1sic.overlay @@ -0,0 +1,11 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&ftm0 { + clock-source = "fixed"; + clocks = <&clock NXP_S32_RTC_CLK>; + prescaler = <1>; +}; diff --git a/samples/basic/blinky_pwm/boards/xiao_esp32s3.overlay b/samples/basic/blinky_pwm/boards/xiao_esp32s3_procpu.overlay similarity index 100% rename from samples/basic/blinky_pwm/boards/xiao_esp32s3.overlay rename to samples/basic/blinky_pwm/boards/xiao_esp32s3_procpu.overlay diff --git a/samples/basic/fade_led/boards/ucans32k1sic.overlay b/samples/basic/fade_led/boards/ucans32k1sic.overlay new file mode 100644 index 00000000000..cd2ba599c4f --- /dev/null +++ b/samples/basic/fade_led/boards/ucans32k1sic.overlay @@ -0,0 +1,11 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&ftm0 { + clock-source = "fixed"; + clocks = <&clock NXP_S32_RTC_CLK>; + prescaler = <1>; +}; diff --git a/samples/basic/hash_map/src/main.c b/samples/basic/hash_map/src/main.c index 3c919283963..b0861bcbb2e 100644 --- a/samples/basic/hash_map/src/main.c +++ b/samples/basic/hash_map/src/main.c @@ -47,7 +47,7 @@ int main(void) LOG_DBG("Inserted %zu", i); - if (k_uptime_get() / MSEC_PER_SEC > CONFIG_TEST_LIB_HASH_MAP_DURATION_S) { + if (k_uptime_seconds() > CONFIG_TEST_LIB_HASH_MAP_DURATION_S) { goto out; } } @@ -60,7 +60,7 @@ int main(void) LOG_DBG("Replaced %zu", i); - if (k_uptime_get() / MSEC_PER_SEC > CONFIG_TEST_LIB_HASH_MAP_DURATION_S) { + if (k_uptime_seconds() > CONFIG_TEST_LIB_HASH_MAP_DURATION_S) { goto out; } } @@ -72,7 +72,7 @@ int main(void) LOG_DBG("Removed %zu", i - 1); - if (k_uptime_get() / MSEC_PER_SEC > CONFIG_TEST_LIB_HASH_MAP_DURATION_S) { + if (k_uptime_seconds() > CONFIG_TEST_LIB_HASH_MAP_DURATION_S) { goto out; } } diff --git a/samples/basic/rgb_led/boards/ucans32k1sic.overlay b/samples/basic/rgb_led/boards/ucans32k1sic.overlay new file mode 100644 index 00000000000..cd2ba599c4f --- /dev/null +++ b/samples/basic/rgb_led/boards/ucans32k1sic.overlay @@ -0,0 +1,11 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&ftm0 { + clock-source = "fixed"; + clocks = <&clock NXP_S32_RTC_CLK>; + prescaler = <1>; +}; diff --git a/samples/bluetooth/broadcast_audio_sink/sample.yaml b/samples/bluetooth/broadcast_audio_sink/sample.yaml index d44b5585f79..ef88ecc4bb2 100644 --- a/samples/bluetooth/broadcast_audio_sink/sample.yaml +++ b/samples/bluetooth/broadcast_audio_sink/sample.yaml @@ -18,7 +18,6 @@ tests: harness: bluetooth platform_allow: - nrf52_bsim - - nrf52833dk/nrf52820 - nrf52833dk/nrf52833 - nrf52840dongle/nrf52840 integration_platforms: diff --git a/samples/bluetooth/broadcast_audio_sink/src/main.c b/samples/bluetooth/broadcast_audio_sink/src/main.c index d34a373a4b5..860434d428a 100644 --- a/samples/bluetooth/broadcast_audio_sink/src/main.c +++ b/samples/bluetooth/broadcast_audio_sink/src/main.c @@ -64,6 +64,7 @@ BUILD_ASSERT(IS_ENABLED(CONFIG_SCAN_SELF) || IS_ENABLED(CONFIG_SCAN_OFFLOAD), #define USB_RING_BUF_SIZE (5 * LC3_MAX_NUM_SAMPLES_STEREO) /* 5 SDUs*/ #endif /* defined(CONFIG_USB_DEVICE_AUDIO) */ +static K_SEM_DEFINE(sem_broadcast_sink_stopped, 0U, 1U); static K_SEM_DEFINE(sem_connected, 0U, 1U); static K_SEM_DEFINE(sem_disconnected, 0U, 1U); static K_SEM_DEFINE(sem_broadcaster_found, 0U, 1U); @@ -75,7 +76,9 @@ static K_SEM_DEFINE(sem_broadcast_code_received, 0U, 1U); static K_SEM_DEFINE(sem_pa_request, 0U, 1U); static K_SEM_DEFINE(sem_past_request, 0U, 1U); static K_SEM_DEFINE(sem_bis_sync_requested, 0U, 1U); -static K_SEM_DEFINE(sem_bis_synced, 0U, CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT); +static K_SEM_DEFINE(sem_stream_connected, 0U, CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT); +static K_SEM_DEFINE(sem_stream_started, 0U, CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT); +static K_SEM_DEFINE(sem_big_synced, 0U, 1U); /* Sample assumes that we only have a single Scan Delegator receive state */ static const struct bt_bap_scan_delegator_recv_state *req_recv_state; @@ -107,8 +110,11 @@ static struct broadcast_sink_stream { } streams[CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT]; static struct bt_bap_stream *streams_p[ARRAY_SIZE(streams)]; +static volatile bool big_synced; +static volatile bool base_received; static struct bt_conn *broadcast_assistant_conn; static struct bt_le_ext_adv *ext_adv; +static volatile uint8_t stream_count; static const struct bt_audio_codec_cap codec_cap = BT_AUDIO_CODEC_CAP_LC3( BT_AUDIO_CODEC_CAP_FREQ_16KHZ | BT_AUDIO_CODEC_CAP_FREQ_24KHZ, @@ -480,6 +486,25 @@ static void usb_data_written_cb(const struct device *dev, struct net_buf *buf, s } #endif /* defined(CONFIG_USB_DEVICE_AUDIO) */ +static void stream_connected_cb(struct bt_bap_stream *stream) +{ + printk("Stream %p connected\n", stream); + + k_sem_give(&sem_stream_connected); +} + +static void stream_disconnected_cb(struct bt_bap_stream *stream, uint8_t reason) +{ + int err; + + printk("Stream %p disconnected with reason 0x%02X\n", stream, reason); + + err = k_sem_take(&sem_stream_connected, K_NO_WAIT); + if (err != 0) { + printk("Failed to take sem_stream_connected: %d\n", err); + } +} + static void stream_started_cb(struct bt_bap_stream *stream) { struct broadcast_sink_stream *sink_stream = @@ -509,7 +534,11 @@ static void stream_started_cb(struct bt_bap_stream *stream) } #endif /* CONFIG_LIBLC3 */ - k_sem_give(&sem_bis_synced); + k_sem_give(&sem_stream_started); + if (k_sem_count_get(&sem_stream_started) == stream_count) { + big_synced = true; + k_sem_give(&sem_big_synced); + } } static void stream_stopped_cb(struct bt_bap_stream *stream, uint8_t reason) @@ -518,9 +547,13 @@ static void stream_stopped_cb(struct bt_bap_stream *stream, uint8_t reason) printk("Stream %p stopped with reason 0x%02X\n", stream, reason); - err = k_sem_take(&sem_bis_synced, K_NO_WAIT); + err = k_sem_take(&sem_stream_started, K_NO_WAIT); if (err != 0) { - printk("Failed to take sem_bis_synced: %d\n", err); + printk("Failed to take sem_stream_started: %d\n", err); + } + + if (k_sem_count_get(&sem_stream_started) != stream_count) { + big_synced = false; } } @@ -563,6 +596,8 @@ static void stream_recv_cb(struct bt_bap_stream *stream, const struct bt_iso_rec } static struct bt_bap_stream_ops stream_ops = { + .connected = stream_connected_cb, + .disconnected = stream_disconnected_cb, .started = stream_started_cb, .stopped = stream_stopped_cb, .recv = stream_recv_cb, @@ -794,7 +829,7 @@ static void base_recv_cb(struct bt_bap_broadcast_sink *sink, const struct bt_bap uint32_t base_bis_index_bitfield = 0U; int err; - if (k_sem_count_get(&sem_base_received) != 0U) { + if (base_received) { return; } @@ -817,17 +852,23 @@ static void base_recv_cb(struct bt_bap_broadcast_sink *sink, const struct bt_bap bis_index_bitfield = base_bis_index_bitfield & bis_index_mask; + printk("bis_index_bitfield = 0x%08x\n", bis_index_bitfield); + if (broadcast_assistant_conn == NULL) { /* No broadcast assistant requesting anything */ requested_bis_sync = BT_BAP_BIS_SYNC_NO_PREF; k_sem_give(&sem_bis_sync_requested); } + base_received = true; k_sem_give(&sem_base_received); } static void syncable_cb(struct bt_bap_broadcast_sink *sink, const struct bt_iso_biginfo *biginfo) { + printk("Broadcast sink (%p) is syncable, BIG %s\n", (void *)sink, + biginfo->encryption ? "encrypted" : "not encrypted"); + k_sem_give(&sem_syncable); if (!biginfo->encryption) { @@ -903,6 +944,18 @@ static int pa_sync_past(struct bt_conn *conn, uint16_t pa_interval) return err; } +static void recv_state_updated_cb(struct bt_conn *conn, + const struct bt_bap_scan_delegator_recv_state *recv_state) +{ + printk("Receive state updated, pa sync state: %u\n", recv_state->pa_sync_state); + + for (uint8_t i = 0; i < recv_state->num_subgroups; i++) { + printk("subgroup %d bis_sync: 0x%08x\n", i, recv_state->subgroups[i].bis_sync); + } + + req_recv_state = recv_state; +} + static int pa_sync_req_cb(struct bt_conn *conn, const struct bt_bap_scan_delegator_recv_state *recv_state, bool past_avail, uint16_t pa_interval) @@ -951,15 +1004,22 @@ static int pa_sync_term_req_cb(struct bt_conn *conn, { int err; + printk("PA sync termination req, pa sync state: %u\n", recv_state->pa_sync_state); + + for (uint8_t i = 0; i < recv_state->num_subgroups; i++) { + printk("subgroup %d bis_sync: 0x%08x\n", i, recv_state->subgroups[i].bis_sync); + } + req_recv_state = recv_state; - err = bt_bap_broadcast_sink_delete(broadcast_sink); + printk("Delete periodic advertising sync\n"); + err = bt_le_per_adv_sync_delete(pa_sync); if (err != 0) { + printk("Could not delete per adv sync: %d\n", err); + return err; } - broadcast_sink = NULL; - return 0; } @@ -982,13 +1042,12 @@ static int bis_sync_req_cb(struct bt_conn *conn, const struct bt_bap_scan_delegator_recv_state *recv_state, const uint32_t bis_sync_req[CONFIG_BT_BAP_BASS_MAX_SUBGROUPS]) { - const bool bis_synced = k_sem_count_get(&sem_bis_synced) > 0U; - - printk("BIS sync request received for %p: 0x%08x\n", - recv_state, bis_sync_req[0]); + printk("BIS sync request received for %p: 0x%08x->0x%08x, broadcast id: 0x%06x, (%s)\n", + recv_state, requested_bis_sync, bis_sync_req[0], recv_state->broadcast_id, + big_synced ? "BIG synced" : "BIG not synced"); /* We only care about a single subgroup in this sample */ - if (bis_synced && requested_bis_sync != bis_sync_req[0]) { + if (big_synced && requested_bis_sync != bis_sync_req[0]) { /* If the BIS sync request is received while we are already * synced, it means that the requested BIS sync has changed. */ @@ -996,8 +1055,8 @@ static int bis_sync_req_cb(struct bt_conn *conn, /* The stream stopped callback will be called as part of this, * and we do not need to wait for any events from the - * controller. Thus, when this returns, the `sem_bis_synced` - * is back to 0. + * controller. Thus, when this returns, the `big_synced` + * is back to false. */ err = bt_bap_broadcast_sink_stop(broadcast_sink); if (err != 0) { @@ -1005,6 +1064,8 @@ static int bis_sync_req_cb(struct bt_conn *conn, return err; } + + k_sem_give(&sem_broadcast_sink_stopped); } requested_bis_sync = bis_sync_req[0]; @@ -1017,6 +1078,7 @@ static int bis_sync_req_cb(struct bt_conn *conn, } static struct bt_bap_scan_delegator_cb scan_delegator_cbs = { + .recv_state_updated = recv_state_updated_cb, .pa_sync_req = pa_sync_req_cb, .pa_sync_term_req = pa_sync_term_req_cb, .broadcast_code = broadcast_code_cb, @@ -1099,21 +1161,19 @@ static bool scan_check_and_sync_broadcast(struct bt_data *data, void *user_data) printk("Found broadcaster with ID 0x%06X and addr %s and sid 0x%02X\n", broadcast_id, le_addr, info->sid); - if (broadcast_assistant_conn == NULL) { - /* Not requested by Broadcast Assistant */ - k_sem_give(&sem_broadcaster_found); - } else if (req_recv_state != NULL && - bt_addr_le_eq(info->addr, &req_recv_state->addr) && - info->sid == req_recv_state->adv_sid && - broadcast_id == req_recv_state->broadcast_id) { + if (broadcast_assistant_conn == NULL /* Not requested by Broadcast Assistant */ || + (req_recv_state != NULL && bt_addr_le_eq(info->addr, &req_recv_state->addr) && + info->sid == req_recv_state->adv_sid && + broadcast_id == req_recv_state->broadcast_id)) { + + /* Store info for PA sync parameters */ + memcpy(&broadcaster_info, info, sizeof(broadcaster_info)); + bt_addr_le_copy(&broadcaster_addr, info->addr); + broadcaster_broadcast_id = broadcast_id; + printk("broadcaster_broadcast_id = 0x%06X\n", broadcaster_broadcast_id); k_sem_give(&sem_broadcaster_found); } - /* Store info for PA sync parameters */ - memcpy(&broadcaster_info, info, sizeof(broadcaster_info)); - bt_addr_le_copy(&broadcaster_addr, info->addr); - broadcaster_broadcast_id = broadcast_id; - /* Stop parsing */ return false; } @@ -1160,11 +1220,11 @@ static void broadcast_scan_recv(const struct bt_le_scan_recv_info *info, struct if (info->interval != 0U) { /* call to bt_data_parse consumes netbufs so shallow clone for verbose output */ - /* If req_recv_state is NULL then we have been requested by a broadcast assistant to - * sync to a specific broadcast source. In that case we do not apply our own - * broadcast name filter. + /* If req_recv_state is not NULL then we have been requested by a broadcast + * assistant to sync to a specific broadcast source. In that case we do not apply + * our own broadcast name filter. */ - if (req_recv_state != NULL && strlen(CONFIG_TARGET_BROADCAST_NAME) > 0U) { + if (req_recv_state == NULL && strlen(CONFIG_TARGET_BROADCAST_NAME) > 0U) { struct net_buf_simple buf_copy; char name[NAME_LEN] = {0}; @@ -1271,9 +1331,14 @@ static int reset(void) { int err; + printk("Reset\n"); + bis_index_bitfield = 0U; requested_bis_sync = 0U; req_recv_state = NULL; + big_synced = false; + base_received = false; + stream_count = 0U; (void)memset(sink_broadcast_code, 0, sizeof(sink_broadcast_code)); (void)memset(&broadcaster_info, 0, sizeof(broadcaster_info)); (void)memset(&broadcaster_addr, 0, sizeof(broadcaster_addr)); @@ -1301,35 +1366,6 @@ static int reset(void) pa_sync = NULL; } - if (IS_ENABLED(CONFIG_SCAN_OFFLOAD)) { - if (broadcast_assistant_conn != NULL) { - err = bt_conn_disconnect(broadcast_assistant_conn, - BT_HCI_ERR_REMOTE_USER_TERM_CONN); - if (err) { - printk("Disconnecting Broadcast Assistant failed (err %d)\n", - err); - - return err; - } - - err = k_sem_take(&sem_disconnected, SEM_TIMEOUT); - if (err != 0) { - printk("Failed to take sem_disconnected: %d\n", err); - - return err; - } - } - - if (ext_adv != NULL) { - stop_adv(); - } - - k_sem_reset(&sem_connected); - k_sem_reset(&sem_disconnected); - k_sem_reset(&sem_pa_request); - k_sem_reset(&sem_past_request); - } - k_sem_reset(&sem_broadcaster_found); k_sem_reset(&sem_pa_synced); k_sem_reset(&sem_base_received); @@ -1337,7 +1373,10 @@ static int reset(void) k_sem_reset(&sem_pa_sync_lost); k_sem_reset(&sem_broadcast_code_received); k_sem_reset(&sem_bis_sync_requested); - k_sem_reset(&sem_bis_synced); + k_sem_reset(&sem_stream_connected); + k_sem_reset(&sem_stream_started); + k_sem_reset(&sem_broadcast_sink_stopped); + return 0; } @@ -1349,11 +1388,13 @@ static int start_adv(void) BT_UUID_16_ENCODE(BT_UUID_BASS_VAL), BT_UUID_16_ENCODE(BT_UUID_PACS_VAL)), BT_DATA_BYTES(BT_DATA_SVC_DATA16, BT_UUID_16_ENCODE(BT_UUID_BASS_VAL)), + BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, + sizeof(CONFIG_BT_DEVICE_NAME) - 1), }; int err; /* Create a non-connectable non-scannable advertising set */ - err = bt_le_ext_adv_create(BT_LE_EXT_ADV_CONN_NAME, NULL, &ext_adv); + err = bt_le_ext_adv_create(BT_LE_EXT_ADV_CONN, NULL, &ext_adv); if (err != 0) { printk("Failed to create advertising set (err %d)\n", err); @@ -1441,28 +1482,46 @@ int main(void) } if (IS_ENABLED(CONFIG_SCAN_OFFLOAD)) { - printk("Starting advertising\n"); - err = start_adv(); - if (err != 0) { - printk("Unable to start advertising connectable: %d\n", - err); + if (broadcast_assistant_conn == NULL) { + k_sem_reset(&sem_connected); - return 0; - } - - printk("Waiting for Broadcast Assistant\n"); - err = k_sem_take(&sem_connected, ADV_TIMEOUT); - if (err != 0) { - printk("No Broadcast Assistant connected\n"); + printk("Starting advertising\n"); + /* Stop advertising before starting if needed */ + if (ext_adv != NULL) { + err = stop_adv(); + if (err != 0) { + printk("Unable to stop advertising: %d\n", err); - err = stop_adv(); + return 0; + } + } + err = start_adv(); if (err != 0) { - printk("Unable to stop advertising: %d\n", + printk("Unable to start advertising connectable: %d\n", err); return 0; } - } else { + + printk("Waiting for Broadcast Assistant\n"); + err = k_sem_take(&sem_connected, ADV_TIMEOUT); + if (err != 0) { + printk("No Broadcast Assistant connected\n"); + + err = stop_adv(); + if (err != 0) { + printk("Unable to stop advertising: %d\n", err); + + return 0; + } + } + } + + if (broadcast_assistant_conn != NULL) { + k_sem_reset(&sem_pa_request); + k_sem_reset(&sem_past_request); + k_sem_reset(&sem_disconnected); + /* Wait for the PA request to determine if we * should start scanning, or wait for PAST */ @@ -1481,8 +1540,8 @@ int main(void) } if (strlen(CONFIG_TARGET_BROADCAST_NAME) > 0U) { - printk("Scanning for broadcast sources containing`" - CONFIG_TARGET_BROADCAST_NAME "`\n"); + printk("Scanning for broadcast sources containing " + "`" CONFIG_TARGET_BROADCAST_NAME "`\n"); } else { printk("Scanning for broadcast sources\n"); } @@ -1494,12 +1553,12 @@ int main(void) return 0; } + printk("Waiting for Broadcaster\n"); err = k_sem_take(&sem_broadcaster_found, SEM_TIMEOUT); if (err != 0) { printk("sem_broadcaster_found timed out, resetting\n"); continue; } - printk("Broadcast source found, waiting for PA sync\n"); err = bt_le_scan_stop(); if (err != 0) { @@ -1537,8 +1596,8 @@ int main(void) printk("sem_base_received timed out, resetting\n"); continue; } - printk("BASE received, waiting for syncable\n"); + printk("BASE received, waiting for syncable\n"); err = k_sem_take(&sem_syncable, SEM_TIMEOUT); if (err != 0) { printk("sem_syncable timed out, resetting\n"); @@ -1563,7 +1622,17 @@ int main(void) } sync_bitfield = bis_index_bitfield & requested_bis_sync; - printk("Syncing to broadcast with bitfield: 0x%08x\n", sync_bitfield); + stream_count = 0; + for (int i = 1; i < BT_ISO_MAX_GROUP_ISO_COUNT; i++) { + if ((sync_bitfield & BIT(i)) != 0) { + stream_count++; + } + } + + printk("Syncing to broadcast with bitfield: 0x%08x = 0x%08x (bis_index) & 0x%08x " + "(req_bis_sync), stream_count = %u\n", + sync_bitfield, bis_index_bitfield, requested_bis_sync, stream_count); + err = bt_bap_broadcast_sink_sync(broadcast_sink, sync_bitfield, streams_p, sink_broadcast_code); if (err != 0) { @@ -1571,15 +1640,23 @@ int main(void) return 0; } - printk("Waiting for BIG sync\n"); - err = k_sem_take(&sem_bis_synced, SEM_TIMEOUT); + printk("Waiting for stream(s) started\n"); + err = k_sem_take(&sem_big_synced, SEM_TIMEOUT); if (err != 0) { - printk("sem_bis_synced timed out, resetting\n"); + printk("sem_big_synced timed out, resetting\n"); continue; } printk("Waiting for PA disconnected\n"); k_sem_take(&sem_pa_sync_lost, K_FOREVER); + + printk("Wainting for sink to stop\n"); + err = k_sem_take(&sem_broadcast_sink_stopped, SEM_TIMEOUT); + if (err != 0) { + printk("sem_broadcast_sink_stopped timed out, resetting\n"); + continue; + } } + return 0; } diff --git a/samples/bluetooth/broadcast_audio_source/overlay-bt_ll_sw_split.conf b/samples/bluetooth/broadcast_audio_source/overlay-bt_ll_sw_split.conf index c73ff9c3ea9..3711a349213 100644 --- a/samples/bluetooth/broadcast_audio_source/overlay-bt_ll_sw_split.conf +++ b/samples/bluetooth/broadcast_audio_source/overlay-bt_ll_sw_split.conf @@ -14,11 +14,7 @@ CONFIG_BT_CTLR_ADV_ISO_PDU_LEN_MAX=155 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) +# Support the highest SDU size required by any BAP LC3 presets (155) + 8 bytes of HCI ISO Data +# packet overhead (the Packet_Sequence_Number, ISO_SDU_Length, Packet_Status_Flag fields; and +# the optional Time_Stamp field, if supplied) CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=163 diff --git a/samples/bluetooth/broadcast_audio_source/src/main.c b/samples/bluetooth/broadcast_audio_source/src/main.c index c63a1337992..e6f2c85b8b4 100644 --- a/samples/bluetooth/broadcast_audio_source/src/main.c +++ b/samples/bluetooth/broadcast_audio_source/src/main.c @@ -23,7 +23,7 @@ BUILD_ASSERT(strlen(CONFIG_BROADCAST_CODE) <= BT_AUDIO_BROADCAST_CODE_SIZE, * 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) + BT_LE_ADV_PARAM(BT_LE_ADV_OPT_EXT_ADV, 0x0080, 0x0080, NULL) /* When BROADCAST_ENQUEUE_COUNT > 1 we can enqueue enough buffers to ensure that * the controller is never idle @@ -489,7 +489,7 @@ int main(void) NET_BUF_SIMPLE_DEFINE(ad_buf, BT_UUID_SIZE_16 + BT_AUDIO_BROADCAST_ID_SIZE); NET_BUF_SIMPLE_DEFINE(base_buf, 128); - struct bt_data ext_ad; + struct bt_data ext_ad[2]; struct bt_data per_ad; uint32_t broadcast_id; @@ -525,10 +525,12 @@ int main(void) /* Setup extended advertising data */ net_buf_simple_add_le16(&ad_buf, BT_UUID_BROADCAST_AUDIO_VAL); net_buf_simple_add_le24(&ad_buf, broadcast_id); - ext_ad.type = BT_DATA_SVC_DATA16; - ext_ad.data_len = ad_buf.len; - ext_ad.data = ad_buf.data; - err = bt_le_ext_adv_set_data(adv, &ext_ad, 1, NULL, 0); + ext_ad[0].type = BT_DATA_SVC_DATA16; + ext_ad[0].data_len = ad_buf.len; + ext_ad[0].data = ad_buf.data; + ext_ad[1] = (struct bt_data)BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, + sizeof(CONFIG_BT_DEVICE_NAME) - 1); + err = bt_le_ext_adv_set_data(adv, ext_ad, 2, NULL, 0); if (err != 0) { printk("Failed to set extended advertising data: %d\n", err); diff --git a/samples/bluetooth/broadcaster_multiple/src/broadcaster_multiple.c b/samples/bluetooth/broadcaster_multiple/src/broadcaster_multiple.c index d4ce51c4f25..8da6984ee55 100644 --- a/samples/bluetooth/broadcaster_multiple/src/broadcaster_multiple.c +++ b/samples/bluetooth/broadcaster_multiple/src/broadcaster_multiple.c @@ -59,6 +59,7 @@ static const struct bt_data ad[] = { #if CONFIG_BT_CTLR_ADV_DATA_LEN_MAX > 255 BT_DATA(BT_DATA_MANUFACTURER_DATA, mfg_data, sizeof(mfg_data)), #endif + BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1), }; static struct bt_le_ext_adv *adv[CONFIG_BT_EXT_ADV_MAX_ADV_SET]; @@ -69,7 +70,7 @@ int broadcaster_multiple(void) .id = BT_ID_DEFAULT, .sid = 0U, /* Supply unique SID when creating advertising set */ .secondary_max_skip = 0U, - .options = (BT_LE_ADV_OPT_EXT_ADV | BT_LE_ADV_OPT_USE_NAME), + .options = BT_LE_ADV_OPT_EXT_ADV, .interval_min = BT_GAP_ADV_FAST_INT_MIN_2, .interval_max = BT_GAP_ADV_FAST_INT_MAX_2, .peer = NULL, diff --git a/samples/bluetooth/central_hr/Kconfig.sysbuild b/samples/bluetooth/central_hr/Kconfig.sysbuild new file mode 100644 index 00000000000..61836cb8855 --- /dev/null +++ b/samples/bluetooth/central_hr/Kconfig.sysbuild @@ -0,0 +1,15 @@ +# Copyright 2023-2024 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" + default "nrf5340_audio_dk/nrf5340/cpunet" if $(BOARD) = "nrf5340_audio_dk" + default "nrf5340bsim/nrf5340/cpunet" if $(BOARD_TARGET_STRING) = "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/central_hr/boards/nrf5340bsim_nrf5340_cpuapp.conf b/samples/bluetooth/central_hr/boards/nrf5340bsim_nrf5340_cpuapp.conf new file mode 100644 index 00000000000..7ffe275701c --- /dev/null +++ b/samples/bluetooth/central_hr/boards/nrf5340bsim_nrf5340_cpuapp.conf @@ -0,0 +1,3 @@ +# Set same the ACL RX buffer size as in hci_ipc on netcore so that +# HCI Controller to Host Flowcontrol is supported. +CONFIG_BT_BUF_ACL_RX_SIZE=255 diff --git a/samples/bluetooth/central_hr/overlay-extended.conf b/samples/bluetooth/central_hr/overlay-extended.conf new file mode 100644 index 00000000000..54f501f4006 --- /dev/null +++ b/samples/bluetooth/central_hr/overlay-extended.conf @@ -0,0 +1,6 @@ +CONFIG_BT_EXT_ADV=y + +# Increase Scan Data Length, as Complete Local Name is placed in the +# AUX_ADV_IND PDU compared to when it is placed in ADV_SCAN_IND PDU in the case +# of legacy advertising. +CONFIG_BT_CTLR_SCAN_DATA_LEN_MAX=36 diff --git a/samples/bluetooth/central_hr/overlay-phy_coded.conf b/samples/bluetooth/central_hr/overlay-phy_coded.conf new file mode 100644 index 00000000000..17d46e52ed2 --- /dev/null +++ b/samples/bluetooth/central_hr/overlay-phy_coded.conf @@ -0,0 +1,12 @@ +CONFIG_BT_EXT_ADV=y + +# Enable Coded PHY support +CONFIG_BT_CTLR_PHY_CODED=y + +# Disable auto PHY update, to switch to 2M PHY +CONFIG_BT_AUTO_PHY_UPDATE=n + +# Increase Scan Data Length, as Complete Local Name is placed in the +# AUX_ADV_IND PDU compared to when it is placed in ADV_SCAN_IND PDU in the case +# of legacy advertising. +CONFIG_BT_CTLR_SCAN_DATA_LEN_MAX=36 diff --git a/samples/bluetooth/central_hr/sample.yaml b/samples/bluetooth/central_hr/sample.yaml index 8dabb7121b0..8a53401860b 100644 --- a/samples/bluetooth/central_hr/sample.yaml +++ b/samples/bluetooth/central_hr/sample.yaml @@ -5,3 +5,35 @@ tests: arch_allow: x86 harness: bluetooth tags: bluetooth + sample.bluetooth.central_hr.bt_ll_sw_split.extended: + harness: bluetooth + platform_allow: + - nrf52_bsim + - nrf5340bsim/nrf5340/cpuapp + - nrf52dk/nrf52832 + - nrf52840dk/nrf52840 + - nrf5340dk/nrf5340/cpuapp + integration_platforms: + - nrf52_bsim + - nrf5340bsim/nrf5340/cpuapp + - nrf52dk/nrf52832 + - nrf52840dk/nrf52840 + - nrf5340dk/nrf5340/cpuapp + extra_args: EXTRA_CONF_FILE=overlay-extended.conf + tags: bluetooth + sample.bluetooth.central_hr.bt_ll_sw_split.phy_coded: + harness: bluetooth + platform_allow: + - nrf52_bsim + - nrf5340bsim/nrf5340/cpuapp + - nrf52dk/nrf52832 + - nrf52840dk/nrf52840 + - nrf5340dk/nrf5340/cpuapp + integration_platforms: + - nrf52_bsim + - nrf5340bsim/nrf5340/cpuapp + - nrf52dk/nrf52832 + - nrf52840dk/nrf52840 + - nrf5340dk/nrf5340/cpuapp + extra_args: EXTRA_CONF_FILE=overlay-phy_coded.conf + tags: bluetooth diff --git a/samples/bluetooth/central_hr/src/main.c b/samples/bluetooth/central_hr/src/main.c index 305066bccd6..95f45f7c140 100644 --- a/samples/bluetooth/central_hr/src/main.c +++ b/samples/bluetooth/central_hr/src/main.c @@ -27,6 +27,8 @@ static struct bt_uuid_16 discover_uuid = BT_UUID_INIT_16(0); static struct bt_gatt_discover_params discover_params; static struct bt_gatt_subscribe_params subscribe_params; +uint64_t total_rx_count; /* This value is exposed to test code */ + static uint8_t notify_func(struct bt_conn *conn, struct bt_gatt_subscribe_params *params, const void *data, uint16_t length) @@ -39,6 +41,8 @@ static uint8_t notify_func(struct bt_conn *conn, printk("[NOTIFICATION] data %p length %u\n", data, length); + total_rx_count++; + return BT_GATT_ITER_CONTINUE; } @@ -112,6 +116,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_conn_le_create_param *create_param; struct bt_le_conn_param *param; const struct bt_uuid *uuid; uint16_t u16; @@ -129,12 +134,24 @@ static bool eir_found(struct bt_data *data, void *user_data) continue; } + printk("Creating connection with Coded PHY support\n"); param = BT_LE_CONN_PARAM_DEFAULT; - err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, - param, &default_conn); + create_param = BT_CONN_LE_CREATE_CONN; + create_param->options |= BT_CONN_LE_OPT_CODED; + err = bt_conn_le_create(addr, create_param, param, + &default_conn); if (err) { - printk("Create conn failed (err %d)\n", err); - start_scan(); + printk("Create connection with Coded PHY support failed (err %d)\n", + err); + + printk("Creating non-Coded PHY connection\n"); + create_param->options &= ~BT_CONN_LE_OPT_CODED; + err = bt_conn_le_create(addr, create_param, + param, &default_conn); + if (err) { + printk("Create connection failed (err %d)\n", err); + start_scan(); + } } return false; @@ -153,9 +170,12 @@ static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type, printk("[DEVICE]: %s, AD evt type %u, AD data len %u, RSSI %i\n", dev, type, ad->len, rssi); - /* We're only interested in connectable events */ + /* We're only interested in legacy connectable events or + * possible extended advertising that are connectable. + */ if (type == BT_GAP_ADV_TYPE_ADV_IND || - type == BT_GAP_ADV_TYPE_ADV_DIRECT_IND) { + type == BT_GAP_ADV_TYPE_ADV_DIRECT_IND || + type == BT_GAP_ADV_TYPE_EXT_ADV) { bt_data_parse(ad, eir_found, (void *)addr); } } @@ -168,15 +188,22 @@ static void start_scan(void) * devices that might update their advertising data at runtime. */ struct bt_le_scan_param scan_param = { .type = BT_LE_SCAN_TYPE_ACTIVE, - .options = BT_LE_SCAN_OPT_NONE, + .options = BT_LE_SCAN_OPT_CODED, .interval = BT_GAP_SCAN_FAST_INTERVAL, .window = BT_GAP_SCAN_FAST_WINDOW, }; err = bt_le_scan_start(&scan_param, device_found); if (err) { - printk("Scanning failed to start (err %d)\n", err); - return; + printk("Scanning with Coded PHY support failed (err %d)\n", err); + + printk("Scanning without Coded PHY\n"); + scan_param.options &= ~BT_LE_SCAN_OPT_CODED; + err = bt_le_scan_start(&scan_param, device_found); + if (err) { + printk("Scanning failed to start (err %d)\n", err); + return; + } } printk("Scanning successfully started\n"); @@ -201,6 +228,8 @@ static void connected(struct bt_conn *conn, uint8_t conn_err) printk("Connected: %s\n", addr); + total_rx_count = 0U; + if (conn == default_conn) { memcpy(&discover_uuid, BT_UUID_HRS, sizeof(discover_uuid)); discover_params.uuid = &discover_uuid.uuid; diff --git a/samples/bluetooth/central_hr/sysbuild.cmake b/samples/bluetooth/central_hr/sysbuild.cmake new file mode 100644 index 00000000000..2523aac8ea7 --- /dev/null +++ b/samples/bluetooth/central_hr/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/central_iso/overlay-bt_ll_sw_split.conf b/samples/bluetooth/central_iso/overlay-bt_ll_sw_split.conf new file mode 100644 index 00000000000..320c5c352b1 --- /dev/null +++ b/samples/bluetooth/central_iso/overlay-bt_ll_sw_split.conf @@ -0,0 +1,33 @@ +# Zephyr Bluetooth Controller +CONFIG_BT_LL_SW_SPLIT=y + +# Zephyr Bluetooth LE Controller needs 16 event buffers to generate Extended +# Advertising Report for receiving the complete 1650 bytes of data +CONFIG_BT_BUF_EVT_RX_COUNT=16 + +# Set maximum scan data length for Extended Scanning in Bluetooth LE Controller +CONFIG_BT_CTLR_SCAN_DATA_LEN_MAX=1650 + +# Increase Zephyr Bluetooth LE Controller Rx buffer to receive complete chain +# of PDUs +CONFIG_BT_CTLR_RX_BUFFERS=9 + +# Sufficient ISO SDU and PDU length for this sample with ISO_TX_MTU of 247 +CONFIG_BT_CTLR_CONN_ISO_SDU_LEN_MAX=247 +CONFIG_BT_CTLR_CONN_ISO_PDU_LEN_MAX=251 + +# Number of supported streami sources and sinks +CONFIG_BT_CTLR_ISOAL_SOURCES=2 +CONFIG_BT_CTLR_ISOAL_SINKS=1 + +# Support the highest SDU size required by this sample 247 + 8 bytes of HCI ISO Data +# packet overhead (timestamp and HCI ISO Data packet header) +CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=255 +CONFIG_BT_CTLR_ISO_TX_BUFFERS=4 + +# Use Low Latency Connected ISO policy +CONFIG_BT_CTLR_ADVANCED_FEATURES=y +CONFIG_BT_CTLR_CONN_ISO_LOW_LATENCY_POLICY=y + +# Use the below if the sample is sending stale packet sequence number +# CONFIG_BT_CTLR_ISOAL_SN_STRICT=n diff --git a/samples/bluetooth/central_iso/sample.yaml b/samples/bluetooth/central_iso/sample.yaml index 0cdbb7a501c..455ff8fcb00 100644 --- a/samples/bluetooth/central_iso/sample.yaml +++ b/samples/bluetooth/central_iso/sample.yaml @@ -8,3 +8,14 @@ tests: integration_platforms: - qemu_x86 tags: bluetooth + sample.bluetooth.central_iso.bt_ll_sw_split: + harness: bluetooth + platform_allow: + - qemu_cortex_m3 + - qemu_x86 + - nrf52_bsim + - nrf52833dk/nrf52833 + integration_platforms: + - nrf52833dk/nrf52833 + extra_args: OVERLAY_CONFIG=overlay-bt_ll_sw_split.conf + tags: bluetooth diff --git a/samples/bluetooth/central_past/src/main.c b/samples/bluetooth/central_past/src/main.c index 8646c549f9d..fd40ed5e296 100644 --- a/samples/bluetooth/central_past/src/main.c +++ b/samples/bluetooth/central_past/src/main.c @@ -16,6 +16,7 @@ static bool per_adv_found; static bt_addr_le_t per_addr; static uint8_t per_sid; static struct bt_conn *default_conn; +static uint32_t per_adv_interval_ms; static K_SEM_DEFINE(sem_conn, 0, 1); static K_SEM_DEFINE(sem_conn_lost, 0, 1); @@ -105,6 +106,7 @@ static void scan_recv(const struct bt_le_scan_recv_info *info, /* If info->interval it is a periodic advertiser, mark for sync */ if (!per_adv_found && info->interval) { per_adv_found = true; + per_adv_interval_ms = BT_GAP_PER_ADV_INTERVAL_TO_MS(info->interval); per_sid = info->sid; bt_addr_le_copy(&per_addr, info->addr); @@ -293,7 +295,7 @@ int main(void) sync_create_param.options = 0; sync_create_param.sid = per_sid; sync_create_param.skip = 0; - sync_create_param.timeout = 0xaa; + sync_create_param.timeout = per_adv_interval_ms * 10 / 10; /* 10 attempts */ err = bt_le_per_adv_sync_create(&sync_create_param, &sync); if (err != 0) { printk("failed (err %d)\n", err); diff --git a/samples/bluetooth/direct_adv/src/main.c b/samples/bluetooth/direct_adv/src/main.c index c8ebda0df9b..b277cd4205a 100644 --- a/samples/bluetooth/direct_adv/src/main.c +++ b/samples/bluetooth/direct_adv/src/main.c @@ -76,6 +76,7 @@ BT_GATT_SERVICE_DEFINE(primary_service, 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_UUID128_ALL, BT_UUID_CUSTOM_SERVICE_VAL), + BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1), }; static void connected(struct bt_conn *conn, uint8_t err) @@ -127,7 +128,7 @@ static void bt_ready(void) adv_param.options |= BT_LE_ADV_OPT_DIR_ADDR_RPA; err = bt_le_adv_start(&adv_param, NULL, 0, NULL, 0); } else { - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0); + err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), NULL, 0); } if (err) { diff --git a/samples/bluetooth/direction_finding_connectionless_rx/src/main.c b/samples/bluetooth/direction_finding_connectionless_rx/src/main.c index d20750e4404..a3f99d2cce9 100644 --- a/samples/bluetooth/direction_finding_connectionless_rx/src/main.c +++ b/samples/bluetooth/direction_finding_connectionless_rx/src/main.c @@ -263,7 +263,7 @@ static void create_sync(void) sync_create_param.options = BT_LE_PER_ADV_SYNC_OPT_SYNC_ONLY_CONST_TONE_EXT; sync_create_param.sid = per_sid; sync_create_param.skip = 0; - sync_create_param.timeout = 0xaa; + sync_create_param.timeout = sync_create_timeout_ms * 10 / 10; /* 10 attempts */ err = bt_le_per_adv_sync_create(&sync_create_param, &adv_sync); if (err != 0) { printk("failed (err %d)\n", err); diff --git a/samples/bluetooth/direction_finding_connectionless_tx/src/main.c b/samples/bluetooth/direction_finding_connectionless_tx/src/main.c index f00d42d5ab5..ef6a89b8852 100644 --- a/samples/bluetooth/direction_finding_connectionless_tx/src/main.c +++ b/samples/bluetooth/direction_finding_connectionless_tx/src/main.c @@ -31,8 +31,7 @@ static struct bt_le_ext_adv *adv_set; static struct bt_le_adv_param param = BT_LE_ADV_PARAM_INIT(BT_LE_ADV_OPT_EXT_ADV | - BT_LE_ADV_OPT_USE_IDENTITY | - BT_LE_ADV_OPT_USE_NAME, + BT_LE_ADV_OPT_USE_IDENTITY, BT_GAP_ADV_FAST_INT_MIN_2, BT_GAP_ADV_FAST_INT_MAX_2, NULL); @@ -65,6 +64,10 @@ struct bt_df_adv_cte_tx_param cte_params = { .cte_len = CTE_LEN, #endif /* CONFIG_BT_DF_CTE_TX_AOD */ }; +static const struct bt_data ad[] = { + BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1), +}; + static void adv_sent_cb(struct bt_le_ext_adv *adv, struct bt_le_ext_adv_sent_info *info) { @@ -97,6 +100,12 @@ int main(void) } printk("success\n"); + err = bt_le_ext_adv_set_data(adv_set, ad, ARRAY_SIZE(ad), NULL, 0); + if (err) { + printk("failed (err %d)\n", err); + return 0; + } + printk("Update CTE params..."); err = bt_df_set_adv_cte_tx_param(adv_set, &cte_params); if (err) { diff --git a/samples/bluetooth/direction_finding_peripheral/src/main.c b/samples/bluetooth/direction_finding_peripheral/src/main.c index 3f921d21485..c122ae21a14 100644 --- a/samples/bluetooth/direction_finding_peripheral/src/main.c +++ b/samples/bluetooth/direction_finding_peripheral/src/main.c @@ -26,6 +26,7 @@ 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_LE_SUPPORTED_FEATURES, BT_LE_SUPP_FEAT_24_ENCODE(DF_FEAT_ENABLED)), + BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1), }; /* Latency set to zero, to enforce PDU exchange every connection event */ @@ -99,7 +100,7 @@ static void bt_ready(void) printk("Bluetooth initialized\n"); - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0); + err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), NULL, 0); if (err) { printk("Advertising failed to start (err %d)\n", err); return; diff --git a/samples/bluetooth/eddystone/src/main.c b/samples/bluetooth/eddystone/src/main.c index 86a99aaac4c..b649e636ab6 100644 --- a/samples/bluetooth/eddystone/src/main.c +++ b/samples/bluetooth/eddystone/src/main.c @@ -38,6 +38,10 @@ static const struct bt_data ad[] = { 0xdf, 0x4b, 0xd3, 0x8e, 0x00, 0x75, 0xc8, 0xa3), }; +static const struct bt_data sd[] = { + BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1), +}; + /* Eddystone Service Variables */ /* Service UUID a3c87500-8ed3-4bdf-8a39-a01bebede295 */ static const struct bt_uuid_128 eds_uuid = BT_UUID_INIT_128( @@ -427,7 +431,7 @@ static int eds_slot_restart(struct eds_slot *slot, uint8_t type) addr = oob.addr; } - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), + err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), NULL, 0); } else { size_t count = 1; @@ -631,7 +635,7 @@ static void bt_ready(int err) printk("Bluetooth initialized\n"); /* Start advertising */ - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0); + err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd)); if (err) { printk("Advertising failed to start (err %d)\n", err); return; diff --git a/samples/bluetooth/extended_adv/advertiser/src/main.c b/samples/bluetooth/extended_adv/advertiser/src/main.c index 915e61b9366..be51694fd1a 100644 --- a/samples/bluetooth/extended_adv/advertiser/src/main.c +++ b/samples/bluetooth/extended_adv/advertiser/src/main.c @@ -84,6 +84,10 @@ static int start_advertising(struct bt_le_ext_adv *adv) return err; } +static const struct bt_data ad[] = { + BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1), +}; + int main(void) { int err; @@ -99,12 +103,19 @@ int main(void) } /* Create a non-connectable non-scannable advertising set */ - err = bt_le_ext_adv_create(BT_LE_EXT_ADV_CONN_NAME, NULL, &adv); + err = bt_le_ext_adv_create(BT_LE_EXT_ADV_CONN, NULL, &adv); if (err) { printk("Failed to create advertising set (err %d)\n", err); return err; } + /* Set advertising data to have complete local name set */ + err = bt_le_ext_adv_set_data(adv, ad, ARRAY_SIZE(ad), NULL, 0); + if (err) { + printk("Failed to set advertising data (err %d)\n", err); + return 0; + } + err = start_advertising(adv); if (err) { return err; diff --git a/samples/bluetooth/handsfree_ag/CMakeLists.txt b/samples/bluetooth/handsfree_ag/CMakeLists.txt new file mode 100644 index 00000000000..af90adf8b82 --- /dev/null +++ b/samples/bluetooth/handsfree_ag/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(handsfree_ag) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) + +zephyr_library_include_directories(${ZEPHYR_BASE}/samples/bluetooth) diff --git a/samples/bluetooth/handsfree_ag/Kconfig b/samples/bluetooth/handsfree_ag/Kconfig new file mode 100644 index 00000000000..f3a1edbcdc9 --- /dev/null +++ b/samples/bluetooth/handsfree_ag/Kconfig @@ -0,0 +1,24 @@ +# +# Copyright 2024 NXP +# +# SPDX-License-Identifier: Apache-2.0 +# + +mainmenu "Bluetooth: handsfree AG" + +config BT_HFP_AG_DISCOVER_RESULT_COUNT + int "Maximum result count per device discovery" + default 10 + +config BT_HFP_AG_CALL_OUTGOING + bool "The simulate call: outgoing (y), incoming (n)" + +config BT_HFP_AG_START_CALL_DELAY_TIME + int "The delay time used to start simulating a call after AG connection" + default 5000 + help + The Delay time is used to wait for the peer to start dialing. If the + peer does not dial within the timeout period, AG satrt simulating a + call. The unit is ms. + +source "Kconfig.zephyr" diff --git a/samples/bluetooth/handsfree_ag/README.rst b/samples/bluetooth/handsfree_ag/README.rst new file mode 100644 index 00000000000..9d2e2d9343a --- /dev/null +++ b/samples/bluetooth/handsfree_ag/README.rst @@ -0,0 +1,23 @@ +.. _bt_handsfree_ag: + +Bluetooth: Handsfree Audio Gateway +################################## + +Overview +******** + +Application demonstrating usage of the Hands-free Audio Gateway (AG) APIs. + +Requirements +************ + +* Running on the host with Bluetooth BR/EDR (Classic) support, or +* A board with Bluetooth BR/EDR (Classic) support + +Building and Running +******************** + +This sample can be found under :zephyr_file:`samples/bluetooth/handsfree_ag` in +the Zephyr tree. + +See :ref:`bluetooth samples section ` for details. diff --git a/samples/bluetooth/handsfree_ag/prj.conf b/samples/bluetooth/handsfree_ag/prj.conf new file mode 100644 index 00000000000..cd315ed26b8 --- /dev/null +++ b/samples/bluetooth/handsfree_ag/prj.conf @@ -0,0 +1,6 @@ +CONFIG_BT=y +CONFIG_BT_CLASSIC=y +CONFIG_BT_RFCOMM=y +CONFIG_BT_HFP_AG=y +CONFIG_BT_CENTRAL=y +CONFIG_BT_DEVICE_NAME="Handsfree-ag" diff --git a/samples/bluetooth/handsfree_ag/sample.yaml b/samples/bluetooth/handsfree_ag/sample.yaml new file mode 100644 index 00000000000..416834fc191 --- /dev/null +++ b/samples/bluetooth/handsfree_ag/sample.yaml @@ -0,0 +1,13 @@ +sample: + name: Bluetooth Handsfree Audio Gateway +tests: + sample.bluetooth.handsfree.ag: + harness: bluetooth + platform_allow: + - qemu_cortex_m3 + - qemu_x86 + tags: bluetooth + integration_platforms: + - qemu_cortex_m3 + extra_configs: + - CONFIG_BT_HFP_AG_CALL_OUTGOING=y diff --git a/samples/bluetooth/handsfree_ag/src/main.c b/samples/bluetooth/handsfree_ag/src/main.c new file mode 100644 index 00000000000..03c76eb0805 --- /dev/null +++ b/samples/bluetooth/handsfree_ag/src/main.c @@ -0,0 +1,384 @@ +/* main.c - Application main entry point */ + +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +static struct bt_conn *default_conn; +struct bt_hfp_ag *hfp_ag; + +static struct bt_br_discovery_param br_discover; + +static struct bt_br_discovery_param br_discover; +static struct bt_br_discovery_result scan_result[CONFIG_BT_HFP_AG_DISCOVER_RESULT_COUNT]; + +struct k_work discover_work; +struct k_work_delayable call_connect_work; +struct k_work_delayable call_disconnect_work; + +struct k_work_delayable call_remote_ringing_work; +struct k_work_delayable call_remote_accept_work; + +NET_BUF_POOL_DEFINE(sdp_discover_pool, 10, BT_L2CAP_BUF_SIZE(CONFIG_BT_L2CAP_TX_MTU), + CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); + +static void ag_connected(struct bt_hfp_ag *ag) +{ + printk("HFP AG connected!\n"); + k_work_schedule(&call_connect_work, K_MSEC(CONFIG_BT_HFP_AG_START_CALL_DELAY_TIME)); +} + +static void ag_disconnected(struct bt_hfp_ag *ag) +{ + printk("HFP AG disconnected!\n"); +} + +static void ag_sco_connected(struct bt_hfp_ag *ag, struct bt_conn *sco_conn) +{ + printk("HFP AG SCO connected!\n"); +} + +static void ag_sco_disconnected(struct bt_hfp_ag *ag) +{ + printk("HFP AG SCO disconnected!\n"); +} + +static void ag_ringing(struct bt_hfp_ag *ag, bool in_band) +{ + printk("Ringing (in bond? %s)\n", in_band ? "Yes" : "No"); +} + +static void ag_accept(struct bt_hfp_ag *ag) +{ + printk("Call Accepted\n"); + k_work_schedule(&call_disconnect_work, K_SECONDS(10)); +} + +static void ag_reject(struct bt_hfp_ag *ag) +{ + printk("Call Rejected\n"); + k_work_schedule(&call_disconnect_work, K_SECONDS(1)); +} + +static void ag_terminate(struct bt_hfp_ag *ag) +{ + printk("Call terminated\n"); + k_work_schedule(&call_disconnect_work, K_SECONDS(1)); +} + +static void ag_outgoing(struct bt_hfp_ag *ag, const char *number) +{ + printk("Call outgoing, remote number %s\n", number); + k_work_cancel_delayable(&call_connect_work); + k_work_schedule(&call_remote_ringing_work, K_SECONDS(1)); +} + +static void ag_incoming(struct bt_hfp_ag *ag, const char *number) +{ + printk("Incoming call, remote number %s\n", number); + k_work_cancel_delayable(&call_connect_work); +} + +static struct bt_hfp_ag_cb ag_cb = { + .connected = ag_connected, + .disconnected = ag_disconnected, + .sco_connected = ag_sco_connected, + .sco_disconnected = ag_sco_disconnected, + .outgoing = ag_outgoing, + .incoming = ag_incoming, + .ringing = ag_ringing, + .accept = ag_accept, + .reject = ag_reject, + .terminate = ag_terminate, +}; + +static uint8_t sdp_discover_cb(struct bt_conn *conn, struct bt_sdp_client_result *result) +{ + int err; + uint16_t value; + + printk("Discover done\n"); + + if (result->resp_buf != NULL) { + err = bt_sdp_get_proto_param(result->resp_buf, BT_SDP_PROTO_RFCOMM, &value); + + if (err != 0) { + printk("Fail to parser RFCOMM the SDP response!\n"); + } else { + printk("The server channel is %d\n", value); + err = bt_hfp_ag_connect(conn, &hfp_ag, value); + if (err != 0) { + printk("Fail to create hfp AG connection (err %d)\n", err); + } + } + } + + return BT_SDP_DISCOVER_UUID_STOP; +} + +static struct bt_sdp_discover_params sdp_discover = { + .func = sdp_discover_cb, + .pool = &sdp_discover_pool, + .uuid = BT_UUID_DECLARE_16(BT_SDP_HANDSFREE_SVCLASS), +}; + +static void connected(struct bt_conn *conn, uint8_t err) +{ + int res; + + if (err) { + if (default_conn != NULL) { + default_conn = NULL; + } + printk("Connection failed (err 0x%02x)\n", err); + } else { + if (default_conn == conn) { + struct bt_conn_info info; + + bt_conn_get_info(conn, &info); + if (info.type != BT_CONN_TYPE_BR) { + return; + } + + /* + * Do an SDP Query on Successful ACL connection complete with the + * required device + */ + res = bt_sdp_discover(default_conn, &sdp_discover); + if (res) { + printk("SDP discovery failed (err %d)\r\n", res); + } else { + printk("SDP discovery started\r\n"); + } + printk("Connected\n"); + } + } +} + +static void disconnected(struct bt_conn *conn, uint8_t reason) +{ + printk("Disconnected (reason 0x%02x)\n", reason); + + if (default_conn != conn) { + return; + } + + if (default_conn) { + default_conn = NULL; + } else { + return; + } +} + +static void security_changed(struct bt_conn *conn, bt_security_t level, enum bt_security_err err) +{ + char addr[BT_ADDR_LE_STR_LEN]; + struct bt_conn_info info; + + bt_conn_get_info(conn, &info); + + bt_addr_to_str(info.br.dst, addr, sizeof(addr)); + + printk("Security changed: %s level %u (err %d)\n", addr, level, err); +} + +static struct bt_conn_cb conn_callbacks = { + .connected = connected, + .disconnected = disconnected, + .security_changed = security_changed, +}; + +static void scan_discovery_cb(struct bt_br_discovery_result *results, size_t count) +{ + char addr[BT_ADDR_LE_STR_LEN]; + uint8_t *eir; + bool cod_hf = false; + static uint8_t temp[240]; + size_t len = sizeof(results->eir); + uint8_t major_device; + uint8_t minor_device; + size_t i; + + for (i = 0; i < count; i++) { + bt_addr_to_str(&results[i].addr, addr, sizeof(addr)); + printk("Device[%d]: %s, rssi %d, cod 0x%X%X%X", i, addr, results[i].rssi, + results[i].cod[0], results[i].cod[1], results[i].cod[2]); + + major_device = (uint8_t)BT_COD_MAJOR_DEVICE_CLASS(results[i].cod); + minor_device = (uint8_t)BT_COD_MINOR_DEVICE_CLASS(results[i].cod); + + if ((major_device & BT_COD_MAJOR_AUDIO_VIDEO) && + (minor_device & BT_COD_MAJOR_AUDIO_VIDEO_MINOR_HANDS_FREE)) { + cod_hf = true; + } + + eir = results[i].eir; + + while ((eir[0] > 2) && (len > eir[0])) { + switch (eir[1]) { + case BT_DATA_NAME_SHORTENED: + case BT_DATA_NAME_COMPLETE: + memcpy(temp, &eir[2], eir[0] - 1); + temp[eir[0] - 1] = '\0'; /* Set end flag */ + printk(", name %s", temp); + break; + } + len = len - eir[0] - 1; + eir = eir + eir[0] + 1; + } + printk("\n"); + + if (cod_hf) { + break; + } + } + + if (!cod_hf) { + (void)k_work_submit(&discover_work); + } else { + (void)k_work_cancel(&discover_work); + default_conn = bt_conn_create_br(&results[i].addr, BT_BR_CONN_PARAM_DEFAULT); + + if (default_conn == NULL) { + printk("Fail to create the connecton\n"); + } else { + bt_conn_unref(default_conn); + } + } +} + +static void discover_work_handler(struct k_work *work) +{ + int err; + + br_discover.length = 10; + br_discover.limited = false; + + err = bt_br_discovery_start(&br_discover, scan_result, + CONFIG_BT_HFP_AG_DISCOVER_RESULT_COUNT, scan_discovery_cb); + if (err) { + printk("Fail to start discovery (err %d)\n", err); + return; + } +} + +static void call_connect_work_handler(struct k_work *work) +{ +#if CONFIG_BT_HFP_AG_CALL_OUTGOING + int err; + + printk("Dialing\n"); + + err = bt_hfp_ag_outgoing(hfp_ag, "test_hf"); + + if (err != 0) { + printk("Fail to dial a call (err %d)\n", err); + } +#else + int err = bt_hfp_ag_remote_incoming(hfp_ag, "test_hf"); + + if (err != 0) { + printk("Fail to set remote incoming call (err %d)\n", err); + } +#endif /* CONFIG_BT_HFP_AG_CALL_OUTGOING */ +} + +static void call_disconnect_work_handler(struct k_work *work) +{ + int err; + + if (default_conn != NULL) { + err = bt_conn_disconnect(default_conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + + if (err != 0) { + printk("Fail to disconnect acl connection (err %d)\n", err); + } + } +} + +static void call_remote_ringing_work_handler(struct k_work *work) +{ + int err; + + printk("Remote starts ringing\n"); + + err = bt_hfp_ag_remote_ringing(hfp_ag); + + if (err != 0) { + printk("Fail to notify hfp unit that the remote starts ringing (err %d)\n", err); + } else { + k_work_schedule(&call_remote_accept_work, K_SECONDS(1)); + } +} + +static void call_remote_accept_work_handler(struct k_work *work) +{ + int err; + + printk("Remote accepts the call\n"); + + err = bt_hfp_ag_remote_accept(hfp_ag); + + if (err != 0) { + printk("Fail to notify hfp unit that the remote accepts call (err %d)\n", err); + } +} + +static void bt_ready(int err) +{ + if (err) { + printk("Bluetooth init failed (err %d)\n", err); + return; + } + + if (IS_ENABLED(CONFIG_SETTINGS)) { + settings_load(); + } + + printk("Bluetooth initialized\n"); + + bt_conn_cb_register(&conn_callbacks); + + bt_hfp_ag_register(&ag_cb); + + k_work_init(&discover_work, discover_work_handler); + + (void)k_work_submit(&discover_work); + + k_work_init_delayable(&call_connect_work, call_connect_work_handler); + k_work_init_delayable(&call_disconnect_work, call_disconnect_work_handler); + + k_work_init_delayable(&call_remote_ringing_work, call_remote_ringing_work_handler); + k_work_init_delayable(&call_remote_accept_work, call_remote_accept_work_handler); +} + +int main(void) +{ + int err; + + printk("Bluetooth Handsfree AG demo start...\n"); + + err = bt_enable(bt_ready); + if (err) { + printk("Bluetooth init failed (err %d)\n", err); + } + return 0; +} diff --git a/samples/bluetooth/hap_ha/prj.conf b/samples/bluetooth/hap_ha/prj.conf index ca019bbafb4..c492cdeb1ec 100644 --- a/samples/bluetooth/hap_ha/prj.conf +++ b/samples/bluetooth/hap_ha/prj.conf @@ -1,5 +1,6 @@ CONFIG_BT=y CONFIG_BT_PERIPHERAL=y +CONFIG_BT_ISO_PERIPHERAL=y CONFIG_BT_PRIVACY=y CONFIG_BT_SMP=y @@ -16,6 +17,7 @@ CONFIG_BT_ATT_PREPARE_COUNT=1 CONFIG_BT_AUDIO=y CONFIG_BT_BAP_UNICAST_SERVER=y +CONFIG_BT_ASCS=y CONFIG_BT_ASCS_ASE_SNK_COUNT=1 CONFIG_BT_ASCS_ASE_SRC_COUNT=1 # Support an ISO channel per ASE diff --git a/samples/bluetooth/hap_ha/src/main.c b/samples/bluetooth/hap_ha/src/main.c index 9c57bbefbcb..205feceb0b8 100644 --- a/samples/bluetooth/hap_ha/src/main.c +++ b/samples/bluetooth/hap_ha/src/main.c @@ -45,6 +45,7 @@ static const struct bt_data ad[] = { BT_DATA(BT_DATA_CSIS_RSI, csis_rsi_addata, ARRAY_SIZE(csis_rsi_addata)), #endif /* CONFIG_BT_CSIP_SET_MEMBER */ BT_DATA(BT_DATA_SVC_DATA16, unicast_server_addata, ARRAY_SIZE(unicast_server_addata)), + BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1), }; static struct k_work_delayable adv_work; @@ -100,7 +101,7 @@ static void adv_work_handler(struct k_work *work) if (ext_adv == NULL) { /* Create a non-connectable non-scannable advertising set */ - err = bt_le_ext_adv_create(BT_LE_EXT_ADV_CONN_NAME, &adv_cb, &ext_adv); + err = bt_le_ext_adv_create(BT_LE_EXT_ADV_CONN, &adv_cb, &ext_adv); if (err) { printk("Failed to create advertising set (err %d)\n", err); } diff --git a/samples/bluetooth/hci_ipc/dts/arm/nordic/override.dtsi b/samples/bluetooth/hci_ipc/dts/arm/nordic/override.dtsi index 51d065dee0d..31f20b802ce 100644 --- a/samples/bluetooth/hci_ipc/dts/arm/nordic/override.dtsi +++ b/samples/bluetooth/hci_ipc/dts/arm/nordic/override.dtsi @@ -1,2 +1,5 @@ -/* Keep default IRQ priority low for peripherals to reduce Radio ISR latency */ +/* Keep default IRQ priority low for peripherals to reduce Radio ISR latency. + * ARM Cortex-M4 lowest priority value of 5, i.e. considering Zephyr reserved 2 + * levels for Exceptions and ZLI (if enabled). + */ #define NRF_DEFAULT_IRQ_PRIORITY 5 diff --git a/samples/bluetooth/hci_ipc/nrf5340_cpunet_bis-bt_ll_sw_split.conf b/samples/bluetooth/hci_ipc/nrf5340_cpunet_bis-bt_ll_sw_split.conf index 6b407a208f7..27f7b9b80ea 100644 --- a/samples/bluetooth/hci_ipc/nrf5340_cpunet_bis-bt_ll_sw_split.conf +++ b/samples/bluetooth/hci_ipc/nrf5340_cpunet_bis-bt_ll_sw_split.conf @@ -10,7 +10,6 @@ CONFIG_HEAP_MEM_POOL_SIZE=8192 CONFIG_BT=y CONFIG_BT_HCI_RAW=y -CONFIG_BT_HCI_RAW_RESERVE=1 CONFIG_BT_MAX_CONN=2 # Workaround: Unable to allocate command buffer when using K_NO_WAIT since @@ -78,7 +77,7 @@ CONFIG_BT_CTLR_LLCP_LOCAL_PROC_CTX_BUF_NUM=6 CONFIG_BT_CTLR_ADV_EXT=y CONFIG_BT_CTLR_ADV_PERIODIC=y CONFIG_BT_CTLR_ADV_ISO=y -CONFIG_BT_CTLR_ADV_ISO_PDU_LEN_MAX=251 +CONFIG_BT_CTLR_ADV_ISO_PDU_LEN_MAX=247 CONFIG_BT_CTLR_ADV_ISO_STREAM_MAX=2 # ISO Receive Controller @@ -90,7 +89,7 @@ CONFIG_BT_CTLR_SYNC_ISO_STREAM_MAX=2 # ISO Transmissions CONFIG_BT_CTLR_ISO_TX_BUFFERS=8 -CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=251 +CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=255 CONFIG_BT_CTLR_ISOAL_SOURCES=2 # ISO Receptions diff --git a/samples/bluetooth/hci_ipc/nrf5340_cpunet_bt_mesh-bt_ll_sw_split.conf b/samples/bluetooth/hci_ipc/nrf5340_cpunet_bt_mesh-bt_ll_sw_split.conf index 37e29435d49..0d78cf862ee 100644 --- a/samples/bluetooth/hci_ipc/nrf5340_cpunet_bt_mesh-bt_ll_sw_split.conf +++ b/samples/bluetooth/hci_ipc/nrf5340_cpunet_bt_mesh-bt_ll_sw_split.conf @@ -8,7 +8,6 @@ CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=512 CONFIG_BT=y CONFIG_BT_HCI_RAW=y -CONFIG_BT_HCI_RAW_RESERVE=1 CONFIG_BT_MAX_CONN=16 diff --git a/samples/bluetooth/hci_ipc/nrf5340_cpunet_cis-bt_ll_sw_split.conf b/samples/bluetooth/hci_ipc/nrf5340_cpunet_cis-bt_ll_sw_split.conf index 6dd49214caa..040e1db6b4f 100644 --- a/samples/bluetooth/hci_ipc/nrf5340_cpunet_cis-bt_ll_sw_split.conf +++ b/samples/bluetooth/hci_ipc/nrf5340_cpunet_cis-bt_ll_sw_split.conf @@ -10,7 +10,6 @@ CONFIG_HEAP_MEM_POOL_SIZE=8192 CONFIG_BT=y CONFIG_BT_HCI_RAW=y -CONFIG_BT_HCI_RAW_RESERVE=1 CONFIG_BT_MAX_CONN=2 # Workaround: Unable to allocate command buffer when using K_NO_WAIT since @@ -78,12 +77,12 @@ CONFIG_BT_CTLR_LLCP_LOCAL_PROC_CTX_BUF_NUM=6 # ISO Connection Oriented CONFIG_BT_CTLR_CENTRAL_ISO=y CONFIG_BT_CTLR_PERIPHERAL_ISO=y -CONFIG_BT_CTLR_CONN_ISO_SDU_LEN_MAX=251 +CONFIG_BT_CTLR_CONN_ISO_SDU_LEN_MAX=247 CONFIG_BT_CTLR_CONN_ISO_PDU_LEN_MAX=251 # ISO Transmissions CONFIG_BT_CTLR_ISO_TX_BUFFERS=8 -CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=251 +CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=255 CONFIG_BT_CTLR_ISOAL_SOURCES=2 # ISO Receptions diff --git a/samples/bluetooth/hci_ipc/nrf5340_cpunet_df-bt_ll_sw_split.conf b/samples/bluetooth/hci_ipc/nrf5340_cpunet_df-bt_ll_sw_split.conf index ab87866b19a..403501a5810 100644 --- a/samples/bluetooth/hci_ipc/nrf5340_cpunet_df-bt_ll_sw_split.conf +++ b/samples/bluetooth/hci_ipc/nrf5340_cpunet_df-bt_ll_sw_split.conf @@ -10,7 +10,6 @@ CONFIG_HEAP_MEM_POOL_SIZE=8192 CONFIG_BT=y CONFIG_BT_HCI_RAW=y -CONFIG_BT_HCI_RAW_RESERVE=1 CONFIG_BT_MAX_CONN=2 # Workaround: Unable to allocate command buffer when using K_NO_WAIT since diff --git a/samples/bluetooth/hci_ipc/nrf5340_cpunet_iso-bt_ll_sw_split.conf b/samples/bluetooth/hci_ipc/nrf5340_cpunet_iso-bt_ll_sw_split.conf index 0bb34dfa790..8fbd3d3af2d 100644 --- a/samples/bluetooth/hci_ipc/nrf5340_cpunet_iso-bt_ll_sw_split.conf +++ b/samples/bluetooth/hci_ipc/nrf5340_cpunet_iso-bt_ll_sw_split.conf @@ -9,9 +9,11 @@ CONFIG_IPC_SERVICE_BACKEND_RPMSG_WQ_STACK_SIZE=512 CONFIG_HEAP_MEM_POOL_SIZE=8192 CONFIG_CBPRINTF_REDUCED_INTEGRAL=y +CONFIG_ISR_TABLES_LOCAL_DECLARATION=y +CONFIG_LTO=y + CONFIG_BT=y CONFIG_BT_HCI_RAW=y -CONFIG_BT_HCI_RAW_RESERVE=1 CONFIG_BT_MAX_CONN=2 # Workaround: Unable to allocate command buffer when using K_NO_WAIT since @@ -83,7 +85,7 @@ CONFIG_BT_CTLR_LLCP_LOCAL_PROC_CTX_BUF_NUM=6 CONFIG_BT_CTLR_ADV_EXT=y CONFIG_BT_CTLR_ADV_PERIODIC=y CONFIG_BT_CTLR_ADV_ISO=y -CONFIG_BT_CTLR_ADV_ISO_PDU_LEN_MAX=251 +CONFIG_BT_CTLR_ADV_ISO_PDU_LEN_MAX=247 CONFIG_BT_CTLR_ADV_ISO_STREAM_MAX=2 # ISO Receive Controller @@ -96,12 +98,12 @@ CONFIG_BT_CTLR_SYNC_ISO_STREAM_MAX=2 # ISO Connection Oriented CONFIG_BT_CTLR_CENTRAL_ISO=y CONFIG_BT_CTLR_PERIPHERAL_ISO=y -CONFIG_BT_CTLR_CONN_ISO_SDU_LEN_MAX=251 +CONFIG_BT_CTLR_CONN_ISO_SDU_LEN_MAX=247 CONFIG_BT_CTLR_CONN_ISO_PDU_LEN_MAX=251 # ISO Transmissions CONFIG_BT_CTLR_ISO_TX_BUFFERS=8 -CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=251 +CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=255 CONFIG_BT_CTLR_ISOAL_SOURCES=2 # ISO Receptions diff --git a/samples/bluetooth/hci_ipc/nrf5340_cpunet_iso_broadcast-bt_ll_sw_split.conf b/samples/bluetooth/hci_ipc/nrf5340_cpunet_iso_broadcast-bt_ll_sw_split.conf index 12f3b8a1147..05645663bc4 100644 --- a/samples/bluetooth/hci_ipc/nrf5340_cpunet_iso_broadcast-bt_ll_sw_split.conf +++ b/samples/bluetooth/hci_ipc/nrf5340_cpunet_iso_broadcast-bt_ll_sw_split.conf @@ -10,7 +10,6 @@ CONFIG_HEAP_MEM_POOL_SIZE=8192 CONFIG_BT=y CONFIG_BT_HCI_RAW=y -CONFIG_BT_HCI_RAW_RESERVE=1 # Workaround: Unable to allocate command buffer when using K_NO_WAIT since # Host number of completed commands does not follow normal flow control. @@ -32,8 +31,8 @@ CONFIG_BT_CTLR_ADV_PERIODIC=y CONFIG_BT_CTLR_ADV_DATA_LEN_MAX=191 CONFIG_BT_CTLR_ADV_ISO=y CONFIG_BT_CTLR_ISO_TX_BUFFERS=16 -CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=251 -CONFIG_BT_CTLR_ADV_ISO_PDU_LEN_MAX=251 +CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=255 +CONFIG_BT_CTLR_ADV_ISO_PDU_LEN_MAX=247 CONFIG_BT_CTLR_ADV_ISO_STREAM_MAX=2 CONFIG_BT_CTLR_ISOAL_SOURCES=2 diff --git a/samples/bluetooth/hci_ipc/nrf5340_cpunet_iso_central-bt_ll_sw_split.conf b/samples/bluetooth/hci_ipc/nrf5340_cpunet_iso_central-bt_ll_sw_split.conf index e7ec0c140d6..56e80860f32 100644 --- a/samples/bluetooth/hci_ipc/nrf5340_cpunet_iso_central-bt_ll_sw_split.conf +++ b/samples/bluetooth/hci_ipc/nrf5340_cpunet_iso_central-bt_ll_sw_split.conf @@ -10,7 +10,6 @@ CONFIG_HEAP_MEM_POOL_SIZE=8192 CONFIG_BT=y CONFIG_BT_HCI_RAW=y -CONFIG_BT_HCI_RAW_RESERVE=1 # Workaround: Unable to allocate command buffer when using K_NO_WAIT since # Host number of completed commands does not follow normal flow control. @@ -45,12 +44,12 @@ CONFIG_BT_CTLR_SCAN_DATA_LEN_MAX=191 # ISO Connection Oriented CONFIG_BT_CTLR_CENTRAL_ISO=y CONFIG_BT_CTLR_PERIPHERAL_ISO=n -CONFIG_BT_CTLR_CONN_ISO_SDU_LEN_MAX=251 +CONFIG_BT_CTLR_CONN_ISO_SDU_LEN_MAX=247 CONFIG_BT_CTLR_CONN_ISO_PDU_LEN_MAX=251 # ISO Transmissions CONFIG_BT_CTLR_ISO_TX_BUFFERS=16 -CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=251 +CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=255 CONFIG_BT_CTLR_ISOAL_SOURCES=2 # ISO Receptions diff --git a/samples/bluetooth/hci_ipc/nrf5340_cpunet_iso_peripheral-bt_ll_sw_split.conf b/samples/bluetooth/hci_ipc/nrf5340_cpunet_iso_peripheral-bt_ll_sw_split.conf index fa3d303604e..b72aaa624f1 100644 --- a/samples/bluetooth/hci_ipc/nrf5340_cpunet_iso_peripheral-bt_ll_sw_split.conf +++ b/samples/bluetooth/hci_ipc/nrf5340_cpunet_iso_peripheral-bt_ll_sw_split.conf @@ -10,7 +10,6 @@ CONFIG_HEAP_MEM_POOL_SIZE=8192 CONFIG_BT=y CONFIG_BT_HCI_RAW=y -CONFIG_BT_HCI_RAW_RESERVE=1 # Workaround: Unable to allocate command buffer when using K_NO_WAIT since # Host number of completed commands does not follow normal flow control. @@ -45,12 +44,12 @@ CONFIG_BT_CTLR_ADV_DATA_LEN_MAX=191 # ISO Connection Oriented CONFIG_BT_CTLR_CENTRAL_ISO=n CONFIG_BT_CTLR_PERIPHERAL_ISO=y -CONFIG_BT_CTLR_CONN_ISO_SDU_LEN_MAX=251 +CONFIG_BT_CTLR_CONN_ISO_SDU_LEN_MAX=247 CONFIG_BT_CTLR_CONN_ISO_PDU_LEN_MAX=251 # ISO Transmissions CONFIG_BT_CTLR_ISO_TX_BUFFERS=16 -CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=251 +CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=255 CONFIG_BT_CTLR_ISOAL_SOURCES=2 # ISO Receptions diff --git a/samples/bluetooth/hci_ipc/nrf5340_cpunet_iso_receive-bt_ll_sw_split.conf b/samples/bluetooth/hci_ipc/nrf5340_cpunet_iso_receive-bt_ll_sw_split.conf index d139e83996a..cc3b5adecdd 100644 --- a/samples/bluetooth/hci_ipc/nrf5340_cpunet_iso_receive-bt_ll_sw_split.conf +++ b/samples/bluetooth/hci_ipc/nrf5340_cpunet_iso_receive-bt_ll_sw_split.conf @@ -10,7 +10,6 @@ CONFIG_HEAP_MEM_POOL_SIZE=8192 CONFIG_BT=y CONFIG_BT_HCI_RAW=y -CONFIG_BT_HCI_RAW_RESERVE=1 # Workaround: Unable to allocate command buffer when using K_NO_WAIT since # Host number of completed commands does not follow normal flow control. diff --git a/samples/bluetooth/hci_ipc/prj.conf b/samples/bluetooth/hci_ipc/prj.conf index 755a1f4ac1e..39c20b23cab 100644 --- a/samples/bluetooth/hci_ipc/prj.conf +++ b/samples/bluetooth/hci_ipc/prj.conf @@ -8,7 +8,6 @@ CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=512 CONFIG_BT=y CONFIG_BT_HCI_RAW=y -CONFIG_BT_HCI_RAW_RESERVE=1 CONFIG_BT_MAX_CONN=16 diff --git a/samples/bluetooth/hci_pwr_ctrl/src/main.c b/samples/bluetooth/hci_pwr_ctrl/src/main.c index b18501016da..74318525753 100644 --- a/samples/bluetooth/hci_pwr_ctrl/src/main.c +++ b/samples/bluetooth/hci_pwr_ctrl/src/main.c @@ -29,6 +29,10 @@ static const struct bt_data ad[] = { BT_DATA_BYTES(BT_DATA_UUID16_ALL, BT_UUID_16_ENCODE(BT_UUID_HRS_VAL)), }; +static const struct bt_data sd[] = { + BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1), +}; + #define DEVICE_NAME CONFIG_BT_DEVICE_NAME #define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1) #define DEVICE_BEACON_TXPOWER_NUM 8 @@ -39,7 +43,7 @@ static K_THREAD_STACK_DEFINE(pwr_thread_stack, 512); static const int8_t txpower[DEVICE_BEACON_TXPOWER_NUM] = {4, 0, -3, -8, -15, -18, -23, -30}; static const struct bt_le_adv_param *param = - BT_LE_ADV_PARAM(BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_USE_NAME, + BT_LE_ADV_PARAM(BT_LE_ADV_OPT_CONNECTABLE, 0x0020, 0x0020, NULL); static void read_conn_rssi(uint16_t handle, int8_t *rssi) @@ -206,7 +210,7 @@ static void bt_ready(int err) /* Start advertising */ err = bt_le_adv_start(param, ad, ARRAY_SIZE(ad), - NULL, 0); + sd, ARRAY_SIZE(sd)); if (err) { printk("Advertising failed to start (err %d)\n", err); return; diff --git a/samples/bluetooth/hci_spi/prj.conf b/samples/bluetooth/hci_spi/prj.conf index 33ceb26eb77..65ce21c799c 100644 --- a/samples/bluetooth/hci_spi/prj.conf +++ b/samples/bluetooth/hci_spi/prj.conf @@ -6,7 +6,6 @@ CONFIG_BT=y CONFIG_BT_HCI_RAW=y CONFIG_BT_MAX_CONN=16 CONFIG_BT_TINYCRYPT_ECC=n -CONFIG_BT_HCI_RAW_RESERVE=1 # Workaround: Unable to allocate command buffer when using K_NO_WAIT since # Host number of completed commands does not follow normal flow control. diff --git a/samples/bluetooth/hci_uart/boards/nrf9160dk_nrf52840.overlay b/samples/bluetooth/hci_uart/boards/nrf9160dk_nrf52840.overlay index 4209320fcff..8ec74170f94 100644 --- a/samples/bluetooth/hci_uart/boards/nrf9160dk_nrf52840.overlay +++ b/samples/bluetooth/hci_uart/boards/nrf9160dk_nrf52840.overlay @@ -4,9 +4,9 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include -#include +#include &uart1 { current-speed = <1000000>; diff --git a/samples/bluetooth/hci_uart/boards/nrf9160dk_nrf52840_0_14_0.overlay b/samples/bluetooth/hci_uart/boards/nrf9160dk_nrf52840_0_14_0.overlay index 409d3bada63..692d2a5749b 100644 --- a/samples/bluetooth/hci_uart/boards/nrf9160dk_nrf52840_0_14_0.overlay +++ b/samples/bluetooth/hci_uart/boards/nrf9160dk_nrf52840_0_14_0.overlay @@ -5,4 +5,4 @@ */ /* Use the reset line that is available starting from v0.14.0 of the DK. */ -#include +#include diff --git a/samples/bluetooth/hci_uart/boards/yd_esp32.conf b/samples/bluetooth/hci_uart/boards/yd_esp32_procpu.conf similarity index 100% rename from samples/bluetooth/hci_uart/boards/yd_esp32.conf rename to samples/bluetooth/hci_uart/boards/yd_esp32_procpu.conf diff --git a/samples/bluetooth/hci_uart/boards/yd_esp32.overlay b/samples/bluetooth/hci_uart/boards/yd_esp32_procpu.overlay similarity index 100% rename from samples/bluetooth/hci_uart/boards/yd_esp32.overlay rename to samples/bluetooth/hci_uart/boards/yd_esp32_procpu.overlay diff --git a/samples/bluetooth/hci_uart/overlay-all-bt_ll_sw_split.conf b/samples/bluetooth/hci_uart/overlay-all-bt_ll_sw_split.conf index 3774532c424..8d6dbdd87b0 100644 --- a/samples/bluetooth/hci_uart/overlay-all-bt_ll_sw_split.conf +++ b/samples/bluetooth/hci_uart/overlay-all-bt_ll_sw_split.conf @@ -80,7 +80,7 @@ CONFIG_BT_CTLR_DF_CONN_CTE_REQ=y CONFIG_BT_CTLR_ADV_EXT=y CONFIG_BT_CTLR_ADV_PERIODIC=y CONFIG_BT_CTLR_ADV_ISO=y -CONFIG_BT_CTLR_ADV_ISO_PDU_LEN_MAX=251 +CONFIG_BT_CTLR_ADV_ISO_PDU_LEN_MAX=247 CONFIG_BT_CTLR_ADV_ISO_STREAM_MAX=2 # ISO Receive Controller @@ -93,12 +93,12 @@ CONFIG_BT_CTLR_SYNC_ISO_STREAM_MAX=2 # ISO Connection Oriented CONFIG_BT_CTLR_CENTRAL_ISO=y CONFIG_BT_CTLR_PERIPHERAL_ISO=y -CONFIG_BT_CTLR_CONN_ISO_SDU_LEN_MAX=251 +CONFIG_BT_CTLR_CONN_ISO_SDU_LEN_MAX=247 CONFIG_BT_CTLR_CONN_ISO_PDU_LEN_MAX=251 # ISO Transmissions CONFIG_BT_CTLR_ISO_TX_BUFFERS=8 -CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=251 +CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=255 CONFIG_BT_CTLR_ISOAL_SOURCES=2 # ISO Receptions diff --git a/samples/bluetooth/hci_uart_async/src/hci_uart_async.c b/samples/bluetooth/hci_uart_async/src/hci_uart_async.c index cf9cc600d5c..e3e32eba4af 100644 --- a/samples/bluetooth/hci_uart_async/src/hci_uart_async.c +++ b/samples/bluetooth/hci_uart_async/src/hci_uart_async.c @@ -37,14 +37,6 @@ static const struct device *const hci_uart_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_ static K_THREAD_STACK_DEFINE(h2c_thread_stack, CONFIG_BT_HCI_TX_STACK_SIZE); static struct k_thread h2c_thread; -enum h4_type { - H4_CMD = 0x01, - H4_ACL = 0x02, - H4_SCO = 0x03, - H4_EVT = 0x04, - H4_ISO = 0x05, -}; - struct k_poll_signal uart_h2c_rx_sig; struct k_poll_signal uart_c2h_tx_sig; @@ -82,33 +74,33 @@ static int uart_c2h_tx(const uint8_t *data, size_t size) } /* Function expects that type is validated and only CMD, ISO or ACL will be used. */ -static uint32_t hci_payload_size(const uint8_t *hdr_buf, enum h4_type type) +static uint32_t hci_payload_size(const uint8_t *hdr_buf, uint8_t h4_type) { - switch (type) { - case H4_CMD: + switch (h4_type) { + case BT_HCI_H4_CMD: return ((const struct bt_hci_cmd_hdr *)hdr_buf)->param_len; - case H4_ACL: + case BT_HCI_H4_ACL: return sys_le16_to_cpu(((const struct bt_hci_acl_hdr *)hdr_buf)->len); - case H4_ISO: + case BT_HCI_H4_ISO: return bt_iso_hdr_len( sys_le16_to_cpu(((const struct bt_hci_iso_hdr *)hdr_buf)->len)); default: - LOG_ERR("Invalid type: %u", type); + LOG_ERR("Invalid type: %u", h4_type); return 0; } } -static uint8_t hci_hdr_size(enum h4_type type) +static uint8_t hci_hdr_size(uint8_t h4_type) { - switch (type) { - case H4_CMD: + switch (h4_type) { + case BT_HCI_H4_CMD: return sizeof(struct bt_hci_cmd_hdr); - case H4_ACL: + case BT_HCI_H4_ACL: return sizeof(struct bt_hci_acl_hdr); - case H4_ISO: + case BT_HCI_H4_ISO: return sizeof(struct bt_hci_iso_hdr); default: - LOG_ERR("Unexpected h4 type: %u", type); + LOG_ERR("Unexpected h4 type: %u", h4_type); return 0; } } @@ -171,7 +163,7 @@ static void send_hw_error(void) static void recover_sync_by_reset_pattern(void) { - /* { H4_CMD, le_16(HCI_CMD_OP_RESET), len=0 } */ + /* { BT_HCI_H4_CMD, le_16(HCI_CMD_OP_RESET), len=0 } */ const uint8_t h4_cmd_reset[] = {0x01, 0x03, 0x0C, 0x00}; const uint32_t reset_pattern = sys_get_be32(h4_cmd_reset); int err; @@ -367,7 +359,7 @@ const struct { struct bt_hci_evt_hdr hdr; struct bt_hci_evt_cmd_complete cc; } __packed cc_evt = { - .h4 = H4_EVT, + .h4 = BT_HCI_H4_EVT, .hdr = {.evt = BT_HCI_EVT_CMD_COMPLETE, .len = sizeof(struct bt_hci_evt_cmd_complete)}, .cc = {.ncmd = 1, .opcode = sys_cpu_to_le16(BT_OP_NOP)}, }; diff --git a/samples/bluetooth/hci_vs_scan_req/CMakeLists.txt b/samples/bluetooth/hci_vs_scan_req/CMakeLists.txt new file mode 100644 index 00000000000..dfd126a454e --- /dev/null +++ b/samples/bluetooth/hci_vs_scan_req/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(hci_vs_scan_req) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/bluetooth/hci_vs_scan_req/README.rst b/samples/bluetooth/hci_vs_scan_req/README.rst new file mode 100644 index 00000000000..a05f91ae613 --- /dev/null +++ b/samples/bluetooth/hci_vs_scan_req/README.rst @@ -0,0 +1,30 @@ +.. _bluetooth-hci-vs-scan-req-sample: + +Bluetooth: HCI VS Scan Request +############################## + +Overview +******** + +This simple application is a usage example to manage HCI VS commands to obtain +scan equest events even using legacy advertisements, while may result in lower +RAM usage than using extended advertising. +This is quite important in applications in which the broadcaster role is added +to the central role, where the RAM saving can be bigger. +This sample implements only the broadcaster role; the peripheral role with +connection can also be added, depending on configuration choices. + +Requirements +************ + +* A board with BLE support +* A central device & monitor (e.g. nRF Connect) to check the advertiments and + send scan requests. + +Building and Running +******************** + +This sample can be found under :zephyr_file:`samples/bluetooth/hci_vs_scan_req` +in the Zephyr tree. + +See :ref:`bluetooth samples section ` for details. diff --git a/samples/bluetooth/hci_vs_scan_req/prj.conf b/samples/bluetooth/hci_vs_scan_req/prj.conf new file mode 100644 index 00000000000..3d46f1c4c39 --- /dev/null +++ b/samples/bluetooth/hci_vs_scan_req/prj.conf @@ -0,0 +1,6 @@ +CONFIG_BT=y +CONFIG_LOG=y +CONFIG_BT_BROADCASTER=y +CONFIG_BT_DEVICE_NAME="VS Scan Notify" +CONFIG_BT_HCI_VS_EVT_USER=y +CONFIG_BT_CTLR_VS_SCAN_REQ_RX=y diff --git a/samples/bluetooth/hci_vs_scan_req/sample.yaml b/samples/bluetooth/hci_vs_scan_req/sample.yaml new file mode 100644 index 00000000000..245a83aa0d9 --- /dev/null +++ b/samples/bluetooth/hci_vs_scan_req/sample.yaml @@ -0,0 +1,12 @@ +sample: + name: Bluetooth HCI Vendor-Specific Scan Request +tests: + sample.bluetooth.hci_vs_scan_req: + harness: bluetooth + platform_allow: + - nrf52dk/nrf52832 + integration_platforms: + - nrf52dk/nrf52832 + extra_configs: + - CONFIG_BT_LL_SW_SPLIT=y + tags: bluetooth diff --git a/samples/bluetooth/hci_vs_scan_req/src/main.c b/samples/bluetooth/hci_vs_scan_req/src/main.c new file mode 100644 index 00000000000..d43ae8b1034 --- /dev/null +++ b/samples/bluetooth/hci_vs_scan_req/src/main.c @@ -0,0 +1,152 @@ +/* main.c - Application main entry point */ + +/* + * Copyright (c) 2024 Giancarlo Stasi + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#define DEVICE_NAME CONFIG_BT_DEVICE_NAME +#define DEVICE_NAME_LENGTH (sizeof(DEVICE_NAME) - 1) + +/* Advertising Interval: the longer, the less energy consumption. + * Units: 0.625 milliseconds. + * The Minimum Advertising Interval and Maximum Advertising Interval should not be the same value + * (as stated in Bluetooth Core Spec 5.2, section 7.8.5) + */ +#define ADV_MIN_INTERVAL BT_GAP_ADV_SLOW_INT_MIN +#define ADV_MAX_INTERVAL BT_GAP_ADV_SLOW_INT_MAX + +#define ADV_OPTIONS (BT_LE_ADV_OPT_SCANNABLE | BT_LE_ADV_OPT_NOTIFY_SCAN_REQ) + +static uint8_t scan_data[] = {'V', 'S', ' ', 'S', 'a', 'm', 'p', 'l', 'e'}; + +static const struct bt_le_adv_param parameters = { + .options = ADV_OPTIONS, + .interval_min = ADV_MIN_INTERVAL, + .interval_max = ADV_MAX_INTERVAL, +}; + +static const struct bt_data adv_data[] = { + 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_LENGTH), +}; + +static const struct bt_data scan_rsp_data[] = { + BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), + BT_DATA(BT_DATA_MANUFACTURER_DATA, scan_data, sizeof(scan_data)), +}; + +static const char *bt_addr_le_str(const bt_addr_le_t *addr) +{ + static char str[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(addr, str, sizeof(str)); + + return str; +} + +/* Bluetooth specification doesn't allow the scan request event with legacy advertisements. + * Ref: Bluetooth Core Specification v5.4, section 7.7.65.19 "LE Scan Request Received event" : + * "This event shall only be generated if advertising was enabled using the + * HCI_LE_Set_Extended_Advertising_Enable command." + * Added a Vendor Specific command to add this feature and save RAM. + */ +static void enable_legacy_adv_scan_request_event(bool enable) +{ + struct bt_hci_cp_vs_set_scan_req_reports *cp; + struct net_buf *buf; + int err; + + buf = bt_hci_cmd_create(BT_HCI_OP_VS_SET_SCAN_REQ_REPORTS, sizeof(*cp)); + if (!buf) { + printk("%s: Unable to allocate HCI command buffer\n", __func__); + return; + } + + cp = net_buf_add(buf, sizeof(*cp)); + cp->enable = (uint8_t) enable; + + err = bt_hci_cmd_send(BT_HCI_OP_VS_SET_SCAN_REQ_REPORTS, buf); + if (err) { + printk("Set legacy cb err: %d\n", err); + return; + } +} + +static bool vs_scanned(struct net_buf_simple *buf) +{ + struct bt_hci_evt_vs_scan_req_rx *evt; + struct bt_hci_evt_vs *vs; + + vs = net_buf_simple_pull_mem(buf, sizeof(*vs)); + evt = (void *)buf->data; + + printk("%s subevent 0x%02x peer %s rssi %d\n", __func__, + vs->subevent, bt_addr_le_str(&evt->addr), evt->rssi); + + return true; +} + +static int start_advertising(void) +{ + int err; + + err = bt_hci_register_vnd_evt_cb(vs_scanned); + if (err) { + printk("VS user callback register err %d\n", err); + return err; + } + + enable_legacy_adv_scan_request_event(true); + err = bt_le_adv_start(¶meters, adv_data, ARRAY_SIZE(adv_data), + scan_rsp_data, ARRAY_SIZE(scan_rsp_data)); + if (err) { + printk("Start legacy adv err %d\n", err); + return err; + } + + printk("Advertising successfully started (%s)\n", CONFIG_BT_DEVICE_NAME); + + return 0; +} + +static void bt_ready(int err) +{ + if (err) { + printk("Bluetooth init failed (err %d)\n", err); + return; + } + + printk("Bluetooth initialized\n"); + + err = start_advertising(); + + if (err) { + printk("Advertising failed to start (err %d)\n", err); + return; + } + + printk("Vendor-Specific Scan Request sample started\n"); +} + +int main(void) +{ + int err; + + printk("Starting Vendor-Specific Scan Request sample\n"); + + /* Initialize the Bluetooth Subsystem */ + err = bt_enable(bt_ready); + if (err) { + printk("Bluetooth init failed (err %d)\n", err); + } + + printk("Main function end, leave stack running for scans\n"); + + return 0; +} diff --git a/samples/bluetooth/ipsp/CMakeLists.txt b/samples/bluetooth/ipsp/CMakeLists.txt deleted file mode 100644 index 28352541c14..00000000000 --- a/samples/bluetooth/ipsp/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(ipsp) - -target_sources(app PRIVATE - src/main.c -) diff --git a/samples/bluetooth/ipsp/README.rst b/samples/bluetooth/ipsp/README.rst deleted file mode 100644 index 2ec160d2a22..00000000000 --- a/samples/bluetooth/ipsp/README.rst +++ /dev/null @@ -1,216 +0,0 @@ -.. _bluetooth-ipsp-sample: - -Bluetooth: IPSP Sample -###################### - -Overview -******** -Application demonstrating the IPSP (Internet Protocol Support Profile) Node -role. IPSP is the Bluetooth profile that underneath utilizes 6LoWPAN, i.e. gives -you IPv6 connectivity over BLE. - -Building and Running -******************** - -This sample can be found under :zephyr_file:`samples/bluetooth/ipsp` in the -Zephyr tree. -Sample can be built and executed for the nRF52840 DK NRF52840 as follows: - -.. zephyr-app-commands:: - :zephyr-app: samples/bluetooth/ipsp - :board: nrf52840dk/nrf52840 - :goals: build flash - :compact: - -To build a debug version, with logging and shell support, use the config file -:file:`prj_dbg.conf`: - -.. zephyr-app-commands:: - :zephyr-app: samples/bluetooth/ipsp - :board: nrf52840dk/nrf52840 - :conf: prj_dbg.conf - :goals: build flash - :compact: - -Building and Running for Linux kernels released before 4.12 -=========================================================== -.. note:: - - For hosts using kernels released before 4.12, - option :kconfig:option:`CONFIG_NET_L2_BT_ZEP1656` - must be selected. For more information, see :github:`Zephyr issue #3111 - <3111>`. - -.. zephyr-app-commands:: - :zephyr-app: samples/bluetooth/ipsp - :board: nrf52840dk/nrf52840 - :conf: "prj_zep1656.conf" - :goals: build flash - :compact: - -Testing with a Linux host -========================= - -Make sure the Linux kernel has been built with Bluetooth 6LoWPAN module -(CONFIG_BT_6LOWPAN=y) then proceed to enable it with with the following commands -(as root): - -.. code-block:: console - - # modprobe bluetooth_6lowpan - # echo 1 > /sys/kernel/debug/bluetooth/6lowpan_enable - -If you connected your board to a UART console, you will see an output similar to -(may vary slightly by application and Zephyr versions): - -.. code-block:: console - - [bt] [WRN] set_static_addr: Using temporary static random address - [bt] [INF] show_dev_info: Identity: cb:af:14:57:d8:6e (random) - [bt] [INF] show_dev_info: HCI: version 5.0 (0x09) revision 0x0000, manufacturer 0xffff - [bt] [INF] show_dev_info: LMP: version 5.0 (0x09) subver 0xffff - [bt] [WRN] bt_pub_key_gen: ECC HCI commands not available - [ipsp] [INF] init_app: Run IPSP sample - [ipsp] [INF] listen: Starting to wait - -The output above shows the BLE address assigned to your board for the -current session; the address will be different on subsequent sessions. - -Alternatively, you may scan for your board on the host. The modern way to do -that is using ``bluetoothctl`` utility (included in the recent versions of -BlueZ package) and its ``scan on`` command: - -.. code-block:: console - - $ bluetoothctl - [NEW] Controller A3:24:97:EB:D6:23 ubuntu-0 [default] - [NEW] Device D7:5C:D6:18:14:87 Zephyr - [NEW] Device E1:E7:F9:56:EC:06 Zephyr - [NEW] Device C8:12:C5:08:86:E1 Zephyr - [bluetooth]# scan on - Discovery started - [NEW] Device DC:98:FB:22:CA:3A Zephyr - -When started, ``bluetoothctl`` shows all BLE (and likely, BT/EDR) devices it -knows about. As discussed above, the IPSP uses static random addresses, so -entries for previously connected devices, as shown above, can accumulate and -become stale. You need to be extra careful to find an entry for the active -address. The best approach may be to reset your board after issuing -``scan on`` command. This way it will reinitialize with the BLE address -which will be discovered after the command. - -As an alternative to ``bluetoothctl``, you can use the legacy ``hcitool`` -utility which talks directly to hardware and always shows fresh scan results: - -.. code-block:: console - - $ sudo hcitool lescan - LE Scan ... - CB:AF:14:57:D8:6E (unknown) - CB:AF:14:57:D8:6E Test IPSP node - -After you have found the board's BLE address, connect to the board (as root): - -.. code-block:: console - - # echo "connect " > /sys/kernel/debug/bluetooth/6lowpan_control - -Where ```` is the BLE address and ```` is BLE address type: -1 for public address and 2 for random address. As you can see from -the IPSP sample output above, it uses a static random address. So, with the -sample output above, the command will be: - -.. code-block:: console - - # echo "connect CB:AF:14:57:D8:6E 2" > /sys/kernel/debug/bluetooth/6lowpan_control - -Once connected a dedicated interface will be created, usually bt0. You can verify this -with the following command: - -.. code-block:: console - - # ifconfig - bt0 Link encap:UNSPEC HWaddr F8-2F-A8-FF-FE-EB-6D-8C-00-00-00-00-00-00-00-00 - inet6 addr: fe80::fa2f:a8ff:feeb:6d8c/64 Scope:Link - UP POINTOPOINT RUNNING MULTICAST MTU:1280 Metric:1 - RX packets:2 errors:0 dropped:3 overruns:0 frame:0 - TX packets:6 errors:0 dropped:0 overruns:0 carrier:0 - collisions:0 txqueuelen:1000 - RX bytes:92 (92.0 B) TX bytes:233 (233.0 B) - -As can be seen from the output, only a link-local IPv6 address was assigned -to the interface. - -At this point, you can test IPv6 connectivity (and discover your board's IPv6 -address) by pinging "All local-link nodes" IPv6 address: - -.. code-block:: console - - # ping6 -I bt0 ff02::1 - PING ff02::1(ff02::1) from fe80::fa54:a8ff:feeb:218f bt0: 56 data bytes - 64 bytes from fe80::fa54:a8ff:feeb:218f: icmp_seq=1 ttl=64 time=0.088 ms - 64 bytes from fe80::c9af:14ff:fe57:d86e: icmp_seq=1 ttl=64 time=285 ms (DUP!) - -For each ping packet, both your host and the BLE board send a reply. You -can see the board's reply marked as ``(DUP!)``. You can ping the board -directly with: - -.. code-block:: console - - # ping6 fe80::c9af:14ff:fe57:d86e%bt0 - PING fe80::c9af:14ff:fe57:d86e%bt0(fe80::c9af:14ff:fe57:d86e) 56 data bytes - 64 bytes from fe80::c9af:14ff:fe57:d86e: icmp_seq=1 ttl=64 time=177 ms - 64 bytes from fe80::c9af:14ff:fe57:d86e: icmp_seq=2 ttl=64 time=53.0 ms - -Note that the command uses a "scoped IPv6 address", where the scope is -defined by the networking interface, with ``%bt0`` appended in this case. -A specification like that is an alternative to passing ``-I bt0`` to -``ping6`` (and works with other networking tools like ``telnet``, ``nc``, -``curl``, etc.) - -While we can use a link-local address, it's not very convenient, as it must be -scoped and will change on each run. Instead, the IPSP sample is configured with -``2001:db8::1`` static address and we'll configure the host's interface to -access that address by configuring ``bt0`` with the complementary address -``2001:db8::2``: - -.. code-block:: console - - # ip address add 2001:db8::2/64 dev bt0 - -Now we can ping the board's static address with: - -.. code-block:: console - - # ping6 2001:db8::1 - PING 2001:db8::1(2001:db8::1) 56 data bytes - 64 bytes from 2001:db8::1: icmp_seq=1 ttl=64 time=282 ms - -The IPSP sample includes builtin echo server for UDP and TCP on a port 4242, -which we can test with: - -.. code-block:: console - - $ telnet 2001:db8::1 4242 - Trying 2001:db8::1... - Connected to 2001:db8::1. - Escape character is '^]'. - test - test - test2 - test2 - ^] - telnet> quit - Connection closed. - -In the output above, first ``test`` line was typed, next was echoed back by -the board. Likewise for ``test2``. To quit telnet tool, type Ctrl+], then -"quit" at the prompt. - -As an alternative to using well-known networking tools above, and also to -test both TCP and UDP echo, you can use Zephyr's helper tool in the GitHub -``zephyrproject-rtos/net-tools`` repository: - -.. code-block:: console - - $ echo-client -i bt0 diff --git a/samples/bluetooth/ipsp/boards/rv32m1_vega_openisa_rv32m1_ri5cy.overlay b/samples/bluetooth/ipsp/boards/rv32m1_vega_openisa_rv32m1_ri5cy.overlay deleted file mode 100644 index e53f6265deb..00000000000 --- a/samples/bluetooth/ipsp/boards/rv32m1_vega_openisa_rv32m1_ri5cy.overlay +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2019 NXP - * - * SPDX-License-Identifier: Apache-2.0 - */ - -&lptmr1 { - interrupt-parent = <&intmux0_ch2>; -}; - -&intmux0_ch2 { - status = "okay"; -}; - -&intmux0_ch3 { - status = "okay"; -}; - -&generic_fsk { - interrupt-parent = <&intmux0_ch3>; - status = "okay"; -}; diff --git a/samples/bluetooth/ipsp/prj.conf b/samples/bluetooth/ipsp/prj.conf deleted file mode 100644 index 8ba24abb30c..00000000000 --- a/samples/bluetooth/ipsp/prj.conf +++ /dev/null @@ -1,28 +0,0 @@ -CONFIG_BT=y -CONFIG_LOG=y -CONFIG_BT_SMP=y -CONFIG_BT_PERIPHERAL=y -CONFIG_BT_CENTRAL=y -CONFIG_BT_L2CAP_DYNAMIC_CHANNEL=y -CONFIG_BT_DEVICE_NAME="Test IPSP node" -CONFIG_NETWORKING=y -CONFIG_NET_IPV6=y -CONFIG_NET_IPV4=n -CONFIG_NET_UDP=y -CONFIG_NET_TCP=y -CONFIG_TEST_RANDOM_GENERATOR=y -CONFIG_NET_L2_BT=y -CONFIG_INIT_STACKS=y -CONFIG_NET_PKT_RX_COUNT=10 -CONFIG_NET_PKT_TX_COUNT=10 -CONFIG_NET_BUF_RX_COUNT=20 -CONFIG_NET_BUF_TX_COUNT=20 -CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=3 -CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=4 -CONFIG_NET_MAX_CONTEXTS=6 - -CONFIG_NET_CONFIG_AUTO_INIT=y -CONFIG_NET_CONFIG_SETTINGS=y -CONFIG_NET_CONFIG_MY_IPV6_ADDR="2001:db8::1" -CONFIG_NET_CONFIG_PEER_IPV6_ADDR="2001:db8::2" -CONFIG_NET_CONFIG_BT_NODE=y diff --git a/samples/bluetooth/ipsp/prj_dbg.conf b/samples/bluetooth/ipsp/prj_dbg.conf deleted file mode 100644 index 10f258092a0..00000000000 --- a/samples/bluetooth/ipsp/prj_dbg.conf +++ /dev/null @@ -1,33 +0,0 @@ -CONFIG_BT=y -CONFIG_LOG=y -CONFIG_BT_SMP=y -CONFIG_BT_PERIPHERAL=y -CONFIG_BT_CENTRAL=y -CONFIG_BT_L2CAP_DYNAMIC_CHANNEL=y -CONFIG_BT_DEVICE_NAME="Test IPSP node" -CONFIG_NETWORKING=y -CONFIG_NET_IPV6=y -CONFIG_NET_IPV4=n -CONFIG_NET_UDP=y -CONFIG_NET_TCP=y -CONFIG_TEST_RANDOM_GENERATOR=y -CONFIG_NET_LOG=y -CONFIG_NET_L2_BT=y -CONFIG_INIT_STACKS=y -CONFIG_NET_STATISTICS=y -CONFIG_NET_PKT_RX_COUNT=10 -CONFIG_NET_PKT_TX_COUNT=10 -CONFIG_NET_BUF_RX_COUNT=20 -CONFIG_NET_BUF_TX_COUNT=20 -CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=3 -CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=4 -CONFIG_NET_MAX_CONTEXTS=6 - -CONFIG_NET_SHELL=y -CONFIG_BT_SHELL=y - -CONFIG_NET_CONFIG_AUTO_INIT=y -CONFIG_NET_CONFIG_SETTINGS=y -CONFIG_NET_CONFIG_MY_IPV6_ADDR="2001:db8::1" -CONFIG_NET_CONFIG_PEER_IPV6_ADDR="2001:db8::2" -CONFIG_NET_CONFIG_BT_NODE=y diff --git a/samples/bluetooth/ipsp/prj_zep1656.conf b/samples/bluetooth/ipsp/prj_zep1656.conf deleted file mode 100644 index d0a6f666170..00000000000 --- a/samples/bluetooth/ipsp/prj_zep1656.conf +++ /dev/null @@ -1,29 +0,0 @@ -CONFIG_BT=y -CONFIG_LOG=y -CONFIG_BT_SMP=y -CONFIG_BT_PERIPHERAL=y -CONFIG_BT_CENTRAL=y -CONFIG_BT_L2CAP_DYNAMIC_CHANNEL=y -CONFIG_BT_DEVICE_NAME="Test IPSP node" -CONFIG_NETWORKING=y -CONFIG_NET_IPV6=y -CONFIG_NET_IPV4=n -CONFIG_NET_UDP=y -CONFIG_NET_TCP=y -CONFIG_TEST_RANDOM_GENERATOR=y -CONFIG_NET_L2_BT=y -CONFIG_NET_L2_BT_ZEP1656=y -CONFIG_INIT_STACKS=y -CONFIG_NET_PKT_RX_COUNT=10 -CONFIG_NET_PKT_TX_COUNT=10 -CONFIG_NET_BUF_RX_COUNT=20 -CONFIG_NET_BUF_TX_COUNT=20 -CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=3 -CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=4 -CONFIG_NET_MAX_CONTEXTS=6 - -CONFIG_NET_CONFIG_AUTO_INIT=y -CONFIG_NET_CONFIG_SETTINGS=y -CONFIG_NET_CONFIG_MY_IPV6_ADDR="2001:db8::1" -CONFIG_NET_CONFIG_PEER_IPV6_ADDR="2001:db8::2" -CONFIG_NET_CONFIG_BT_NODE=y diff --git a/samples/bluetooth/ipsp/sample.yaml b/samples/bluetooth/ipsp/sample.yaml deleted file mode 100644 index afac5d31a17..00000000000 --- a/samples/bluetooth/ipsp/sample.yaml +++ /dev/null @@ -1,25 +0,0 @@ -sample: - name: Bluetooth IPSP Sample - description: IPSP (Internet Protocol Support Profile) Node role sample -tests: - sample.bluetooth.ipsp: - harness: bluetooth - platform_allow: - - qemu_x86 - - qemu_cortex_m3 - tags: - - bluetooth - - net - integration_platforms: - - qemu_x86 - sample.bluetooth.ipsp.zep1656: - harness: bluetooth - extra_args: CONF_FILE="prj_zep1656.conf" - platform_allow: - - qemu_x86 - - qemu_cortex_m3 - tags: - - bluetooth - - net - integration_platforms: - - qemu_x86 diff --git a/samples/bluetooth/ipsp/src/main.c b/samples/bluetooth/ipsp/src/main.c deleted file mode 100644 index a8c017140c3..00000000000 --- a/samples/bluetooth/ipsp/src/main.c +++ /dev/null @@ -1,323 +0,0 @@ -/* main.c - Application main entry point */ - -/* - * Copyright (c) 2015-2016 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include - -#define LOG_LEVEL CONFIG_LOG_DEFAULT_LEVEL -LOG_MODULE_REGISTER(ipsp); - -/* Preventing log module registration in net_core.h */ -#define NET_LOG_ENABLED 0 - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -/* Define my IP address where to expect messages */ -#define MY_IP6ADDR { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0, 0, 0, 0x1 } } } -#define MY_PREFIX_LEN 64 - -static struct in6_addr in6addr_my = MY_IP6ADDR; - -#define MY_PORT 4242 - -#define STACKSIZE 2000 -K_THREAD_STACK_DEFINE(thread_stack, STACKSIZE); -static struct k_thread thread_data; - -static uint8_t buf_tx[NET_IPV6_MTU]; - -#define MAX_DBG_PRINT 64 - -NET_PKT_TX_SLAB_DEFINE(echo_tx_tcp, 15); -NET_PKT_DATA_POOL_DEFINE(echo_data_tcp, 30); - -static struct k_mem_slab *tx_tcp_pool(void) -{ - return &echo_tx_tcp; -} - -static struct net_buf_pool *data_tcp_pool(void) -{ - return &echo_data_tcp; -} - -static struct k_sem quit_lock; - -static inline void quit(void) -{ - k_sem_give(&quit_lock); -} - -static inline void init_app(void) -{ - LOG_INF("Run IPSP sample"); - - k_sem_init(&quit_lock, 0, K_SEM_MAX_LIMIT); - - if (net_addr_pton(AF_INET6, - CONFIG_NET_CONFIG_MY_IPV6_ADDR, - &in6addr_my) < 0) { - LOG_ERR("Invalid IPv6 address %s", - CONFIG_NET_CONFIG_MY_IPV6_ADDR); - } - - do { - struct net_if_addr *ifaddr; - - ifaddr = net_if_ipv6_addr_add(net_if_get_default(), - &in6addr_my, NET_ADDR_MANUAL, 0); - } while (0); -} - -static inline bool get_context(struct net_context **udp_recv6, - struct net_context **tcp_recv6) -{ - int ret; - struct sockaddr_in6 my_addr6 = { 0 }; - - my_addr6.sin6_family = AF_INET6; - my_addr6.sin6_port = htons(MY_PORT); - - ret = net_context_get(AF_INET6, SOCK_DGRAM, IPPROTO_UDP, udp_recv6); - if (ret < 0) { - LOG_ERR("Cannot get network context for IPv6 UDP (%d)", ret); - return false; - } - - ret = net_context_bind(*udp_recv6, (struct sockaddr *)&my_addr6, - sizeof(struct sockaddr_in6)); - if (ret < 0) { - LOG_ERR("Cannot bind IPv6 UDP port %d (%d)", - ntohs(my_addr6.sin6_port), ret); - return false; - } - - ret = net_context_get(AF_INET6, SOCK_STREAM, IPPROTO_TCP, tcp_recv6); - if (ret < 0) { - LOG_ERR("Cannot get network context for IPv6 TCP (%d)", ret); - return false; - } - - net_context_setup_pools(*tcp_recv6, tx_tcp_pool, data_tcp_pool); - - ret = net_context_bind(*tcp_recv6, (struct sockaddr *)&my_addr6, - sizeof(struct sockaddr_in6)); - if (ret < 0) { - LOG_ERR("Cannot bind IPv6 TCP port %d (%d)", - ntohs(my_addr6.sin6_port), ret); - return false; - } - - ret = net_context_listen(*tcp_recv6, 0); - if (ret < 0) { - LOG_ERR("Cannot listen IPv6 TCP (%d)", ret); - return false; - } - - return true; -} - -static int build_reply(const char *name, - struct net_pkt *pkt, - uint8_t *buf) -{ - int reply_len = net_pkt_remaining_data(pkt); - int ret; - - LOG_DBG("%s received %d bytes", name, reply_len); - - ret = net_pkt_read(pkt, buf, reply_len); - if (ret < 0) { - LOG_ERR("cannot read packet: %d", ret); - return ret; - } - - LOG_DBG("sending %d bytes", reply_len); - - return reply_len; -} - -static inline void pkt_sent(struct net_context *context, - int status, - void *user_data) -{ - if (status >= 0) { - LOG_DBG("Sent %d bytes", status); - } -} - -static inline void set_dst_addr(sa_family_t family, - struct net_pkt *pkt, - struct net_ipv6_hdr *ipv6_hdr, - struct net_udp_hdr *udp_hdr, - struct sockaddr *dst_addr) -{ - net_ipv6_addr_copy_raw((uint8_t *)&net_sin6(dst_addr)->sin6_addr, - ipv6_hdr->src); - net_sin6(dst_addr)->sin6_family = AF_INET6; - net_sin6(dst_addr)->sin6_port = udp_hdr->src_port; -} - -static void udp_received(struct net_context *context, - struct net_pkt *pkt, - union net_ip_header *ip_hdr, - union net_proto_header *proto_hdr, - int status, - void *user_data) -{ - struct sockaddr dst_addr; - sa_family_t family = net_pkt_family(pkt); - static char dbg[MAX_DBG_PRINT + 1]; - int ret; - - snprintf(dbg, MAX_DBG_PRINT, "UDP IPv%c", - family == AF_INET6 ? '6' : '4'); - - set_dst_addr(family, pkt, ip_hdr->ipv6, proto_hdr->udp, &dst_addr); - - ret = build_reply(dbg, pkt, buf_tx); - if (ret < 0) { - LOG_ERR("Cannot send data to peer (%d)", ret); - return; - } - - net_pkt_unref(pkt); - - ret = net_context_sendto(context, buf_tx, ret, &dst_addr, - family == AF_INET6 ? - sizeof(struct sockaddr_in6) : - sizeof(struct sockaddr_in), - pkt_sent, K_NO_WAIT, user_data); - if (ret < 0) { - LOG_ERR("Cannot send data to peer (%d)", ret); - } -} - -static void setup_udp_recv(struct net_context *udp_recv6) -{ - int ret; - - ret = net_context_recv(udp_recv6, udp_received, K_NO_WAIT, NULL); - if (ret < 0) { - LOG_ERR("Cannot receive IPv6 UDP packets"); - } -} - -static void tcp_received(struct net_context *context, - struct net_pkt *pkt, - union net_ip_header *ip_hdr, - union net_proto_header *proto_hdr, - int status, - void *user_data) -{ - static char dbg[MAX_DBG_PRINT + 1]; - sa_family_t family; - int ret, len; - - if (!pkt) { - /* EOF condition */ - return; - } - - family = net_pkt_family(pkt); - len = net_pkt_remaining_data(pkt); - - snprintf(dbg, MAX_DBG_PRINT, "TCP IPv%c", - family == AF_INET6 ? '6' : '4'); - - ret = build_reply(dbg, pkt, buf_tx); - if (ret < 0) { - LOG_ERR("Cannot send data to peer (%d)", ret); - return; - } - - (void)net_context_update_recv_wnd(context, len); - net_pkt_unref(pkt); - - ret = net_context_send(context, buf_tx, ret, pkt_sent, - K_NO_WAIT, NULL); - if (ret < 0) { - LOG_ERR("Cannot send data to peer (%d)", ret); - quit(); - } -} - -static void tcp_accepted(struct net_context *context, - struct sockaddr *addr, - socklen_t addrlen, - int error, - void *user_data) -{ - int ret; - - NET_DBG("Accept called, context %p error %d", context, error); - - net_context_set_accepting(context, false); - - ret = net_context_recv(context, tcp_received, K_NO_WAIT, NULL); - if (ret < 0) { - LOG_ERR("Cannot receive TCP packet (family %d)", - net_context_get_family(context)); - } -} - -static void setup_tcp_accept(struct net_context *tcp_recv6) -{ - int ret; - - ret = net_context_accept(tcp_recv6, tcp_accepted, K_NO_WAIT, NULL); - if (ret < 0) { - LOG_ERR("Cannot receive IPv6 TCP packets (%d)", ret); - } -} - -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 }; - - if (!get_context(&udp_recv6, &tcp_recv6)) { - LOG_ERR("Cannot get network contexts"); - return; - } - - LOG_INF("Starting to wait"); - - setup_tcp_accept(tcp_recv6); - setup_udp_recv(udp_recv6); - - k_sem_take(&quit_lock, K_FOREVER); - - LOG_INF("Stopping..."); - - net_context_put(udp_recv6); - net_context_put(tcp_recv6); -} - -int main(void) -{ - init_app(); - - k_thread_create(&thread_data, thread_stack, STACKSIZE, - listen, - NULL, NULL, NULL, K_PRIO_COOP(7), 0, K_NO_WAIT); - return 0; -} diff --git a/samples/bluetooth/iso_broadcast/overlay-bt_ll_sw_split.conf b/samples/bluetooth/iso_broadcast/overlay-bt_ll_sw_split.conf index a5f8b3cc1c5..19264a9d041 100644 --- a/samples/bluetooth/iso_broadcast/overlay-bt_ll_sw_split.conf +++ b/samples/bluetooth/iso_broadcast/overlay-bt_ll_sw_split.conf @@ -1,13 +1,20 @@ +# 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 this sample CONFIG_BT_CTLR_ADV_ISO_PDU_LEN_MAX=4 -CONFIG_BT_CTLR_ADV_ISO_STREAM_MAX=2 +# 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. +# Support the highest SDU size required by any BAP LC3 presets (155) + 8 bytes of HCI ISO Data +# packet overhead (the Packet_Sequence_Number, ISO_SDU_Length, Packet_Status_Flag fields; and +# the optional Time_Stamp field, if supplied) CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=12 diff --git a/samples/bluetooth/iso_broadcast/sample.yaml b/samples/bluetooth/iso_broadcast/sample.yaml index 10fb481688c..92bde54d7a0 100644 --- a/samples/bluetooth/iso_broadcast/sample.yaml +++ b/samples/bluetooth/iso_broadcast/sample.yaml @@ -17,8 +17,8 @@ tests: - qemu_cortex_m3 - qemu_x86 - nrf52_bsim - - nrf52dk/nrf52832 + - nrf52833dk/nrf52833 integration_platforms: - - nrf52dk/nrf52832 + - nrf52833dk/nrf52833 extra_args: OVERLAY_CONFIG=overlay-bt_ll_sw_split.conf tags: bluetooth diff --git a/samples/bluetooth/iso_broadcast/src/main.c b/samples/bluetooth/iso_broadcast/src/main.c index 1503dde2197..e0ff7dd306e 100644 --- a/samples/bluetooth/iso_broadcast/src/main.c +++ b/samples/bluetooth/iso_broadcast/src/main.c @@ -82,6 +82,10 @@ static struct bt_iso_big_create_param big_create_param = { .framing = 0, /* 0 - unframed, 1 - framed */ }; +static const struct bt_data ad[] = { + BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1), +}; + int main(void) { uint32_t timeout_counter = INITIAL_TIMEOUT_COUNTER; @@ -102,12 +106,19 @@ int main(void) } /* 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_NCONN, NULL, &adv); if (err) { printk("Failed to create advertising set (err %d)\n", err); return 0; } + /* Set advertising data to have complete local name set */ + err = bt_le_ext_adv_set_data(adv, ad, ARRAY_SIZE(ad), NULL, 0); + if (err) { + printk("Failed to set advertising data (err %d)\n", err); + return 0; + } + /* Set periodic advertising parameters */ err = bt_le_per_adv_set_param(adv, BT_LE_PER_ADV_DEFAULT); if (err) { diff --git a/samples/bluetooth/iso_broadcast_benchmark/src/broadcaster.c b/samples/bluetooth/iso_broadcast_benchmark/src/broadcaster.c index 7ced3382fff..1040f0cd214 100644 --- a/samples/bluetooth/iso_broadcast_benchmark/src/broadcaster.c +++ b/samples/bluetooth/iso_broadcast_benchmark/src/broadcaster.c @@ -60,6 +60,10 @@ static struct bt_iso_big_create_param big_create_param = { #endif /* CONFIG_BT_ISO_TEST_PARAMS */ }; +static const struct bt_data ad[] = { + BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1), +}; + static void iso_connected(struct bt_iso_chan *chan) { LOG_INF("ISO Channel %p connected", chan); @@ -615,12 +619,19 @@ static int create_big(struct bt_le_ext_adv **adv, struct bt_iso_big **big) /* Create a non-connectable non-scannable advertising set */ LOG_INF("Creating Extended 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_NCONN, NULL, adv); if (err != 0) { LOG_ERR("Failed to create advertising set (err %d)", err); return err; } + /* Set advertising data to have complete local name set */ + err = bt_le_ext_adv_set_data(*adv, ad, ARRAY_SIZE(ad), NULL, 0); + if (err) { + LOG_ERR("Failed to set advertising data (err %d)", err); + return 0; + } + LOG_INF("Setting Periodic Advertising parameters"); /* Set periodic advertising parameters */ err = bt_le_per_adv_set_param(*adv, BT_LE_PER_ADV_DEFAULT); diff --git a/samples/bluetooth/iso_connected_benchmark/src/main.c b/samples/bluetooth/iso_connected_benchmark/src/main.c index a647421510e..9873a4c71f4 100644 --- a/samples/bluetooth/iso_connected_benchmark/src/main.c +++ b/samples/bluetooth/iso_connected_benchmark/src/main.c @@ -137,6 +137,10 @@ static struct bt_iso_cig_param cig_create_param = { #endif /* CONFIG_BT_ISO_TEST_PARAMS */ }; +static const struct bt_data sd[] = { + BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1), +}; + static enum benchmark_role device_role_select(void) { char role_char; @@ -1275,11 +1279,9 @@ static int run_peripheral(void) LOG_INF("Starting advertising"); err = bt_le_adv_start( - BT_LE_ADV_PARAM(BT_LE_ADV_OPT_ONE_TIME | BT_LE_ADV_OPT_CONNECTABLE | - BT_LE_ADV_OPT_USE_NAME | - BT_LE_ADV_OPT_FORCE_NAME_IN_AD, + BT_LE_ADV_PARAM(BT_LE_ADV_OPT_ONE_TIME | BT_LE_ADV_OPT_CONNECTABLE, BT_GAP_ADV_FAST_INT_MIN_2, BT_GAP_ADV_FAST_INT_MAX_2, NULL), - NULL, 0, NULL, 0); + NULL, 0, sd, ARRAY_SIZE(sd)); if (err != 0) { LOG_ERR("Advertising failed to start: %d", err); return err; 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 66af1bf86b5..7e87dd5dfdf 100644 --- a/samples/bluetooth/mtu_update/peripheral/src/peripheral_mtu_update.c +++ b/samples/bluetooth/mtu_update/peripheral/src/peripheral_mtu_update.c @@ -23,7 +23,9 @@ static const struct bt_uuid_128 notify_characteristic_uuid = static const struct bt_data adv_ad_data[] = { BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), - BT_DATA_BYTES(BT_DATA_UUID128_ALL, MTU_TEST_SERVICE_TYPE)}; + BT_DATA_BYTES(BT_DATA_UUID128_ALL, MTU_TEST_SERVICE_TYPE), + BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1), +}; static void ccc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value) { @@ -61,8 +63,7 @@ void run_peripheral_sample(uint8_t *notify_data, size_t notify_data_size, uint16 struct bt_gatt_attr *notify_crch = bt_gatt_find_by_uuid(mtu_test.attrs, 0xffff, ¬ify_characteristic_uuid.uuid); - /* Advertise. Auto include name in adv data. Connectable. */ - bt_le_adv_start(BT_LE_ADV_CONN_NAME, adv_ad_data, ARRAY_SIZE(adv_ad_data), NULL, 0); + bt_le_adv_start(BT_LE_ADV_CONN, adv_ad_data, ARRAY_SIZE(adv_ad_data), NULL, 0); bool infinite = seconds == 0; diff --git a/samples/bluetooth/periodic_adv/src/main.c b/samples/bluetooth/periodic_adv/src/main.c index bb009e62a44..9b584966ce7 100644 --- a/samples/bluetooth/periodic_adv/src/main.c +++ b/samples/bluetooth/periodic_adv/src/main.c @@ -8,10 +8,14 @@ static uint8_t mfg_data[] = { 0xff, 0xff, 0x00 }; -static const struct bt_data ad[] = { +static const struct bt_data per_adv_ad[] = { BT_DATA(BT_DATA_MANUFACTURER_DATA, mfg_data, 3), }; +static const struct bt_data ad[] = { + BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1), +}; + int main(void) { struct bt_le_ext_adv *adv; @@ -27,12 +31,19 @@ int main(void) } /* 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_NCONN, NULL, &adv); if (err) { printk("Failed to create advertising set (err %d)\n", err); return 0; } + /* Set advertising data to have complete local name set */ + err = bt_le_ext_adv_set_data(adv, ad, ARRAY_SIZE(ad), NULL, 0); + if (err) { + printk("Failed to set advertising data (err %d)\n", err); + return 0; + } + /* Set periodic advertising parameters */ err = bt_le_per_adv_set_param(adv, BT_LE_PER_ADV_DEFAULT); if (err) { @@ -64,7 +75,7 @@ int main(void) mfg_data[2]++; printk("Set Periodic Advertising Data..."); - err = bt_le_per_adv_set_data(adv, ad, ARRAY_SIZE(ad)); + err = bt_le_per_adv_set_data(adv, per_adv_ad, ARRAY_SIZE(per_adv_ad)); if (err) { printk("Failed (err %d)\n", err); return 0; diff --git a/samples/bluetooth/periodic_adv_conn/src/main.c b/samples/bluetooth/periodic_adv_conn/src/main.c index 00464b43ead..63818ddbeea 100644 --- a/samples/bluetooth/periodic_adv_conn/src/main.c +++ b/samples/bluetooth/periodic_adv_conn/src/main.c @@ -160,6 +160,11 @@ static void init_bufs(void) } } +static const struct bt_data ad[] = { + BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1), +}; + + int main(void) { int err; @@ -177,12 +182,19 @@ int main(void) } /* Create a non-connectable non-scannable advertising set */ - err = bt_le_ext_adv_create(BT_LE_EXT_ADV_NCONN_NAME, &adv_cb, &pawr_adv); + err = bt_le_ext_adv_create(BT_LE_EXT_ADV_NCONN, &adv_cb, &pawr_adv); if (err) { printk("Failed to create advertising set (err %d)\n", err); return 0; } + /* Set advertising data to have complete local name set */ + err = bt_le_ext_adv_set_data(pawr_adv, ad, ARRAY_SIZE(ad), NULL, 0); + if (err) { + printk("Failed to set advertising data (err %d)\n", err); + return 0; + } + /* Set periodic advertising parameters */ err = bt_le_per_adv_set_param(pawr_adv, &per_adv_params); if (err) { diff --git a/samples/bluetooth/periodic_sync/src/main.c b/samples/bluetooth/periodic_sync/src/main.c index 472a21073c9..44c5a8530b4 100644 --- a/samples/bluetooth/periodic_sync/src/main.c +++ b/samples/bluetooth/periodic_sync/src/main.c @@ -14,6 +14,7 @@ static bool per_adv_found; static bt_addr_le_t per_addr; +static uint32_t per_adv_interval_ms; static uint8_t per_sid; static K_SEM_DEFINE(sem_per_adv, 0, 1); @@ -97,6 +98,7 @@ static void scan_recv(const struct bt_le_scan_recv_info *info, if (!per_adv_found && info->interval) { per_adv_found = true; + per_adv_interval_ms = BT_GAP_PER_ADV_INTERVAL_TO_MS(info->interval); per_sid = info->sid; bt_addr_le_copy(&per_addr, info->addr); @@ -233,7 +235,7 @@ int main(void) sync_create_param.options = 0; sync_create_param.sid = per_sid; sync_create_param.skip = 0; - sync_create_param.timeout = 0xaa; + sync_create_param.timeout = per_adv_interval_ms * 10 / 10; /* 10 attempts */ err = bt_le_per_adv_sync_create(&sync_create_param, &sync); if (err) { printk("failed (err %d)\n", err); diff --git a/samples/bluetooth/periodic_sync_rsp/src/main.c b/samples/bluetooth/periodic_sync_rsp/src/main.c index 24be636d8c9..8f8b1a61e6b 100644 --- a/samples/bluetooth/periodic_sync_rsp/src/main.c +++ b/samples/bluetooth/periodic_sync_rsp/src/main.c @@ -195,6 +195,10 @@ BT_CONN_CB_DEFINE(conn_cb) = { .disconnected = disconnected, }; +static const struct bt_data sd[] = { + BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1), +}; + int main(void) { struct bt_le_per_adv_sync_transfer_param past_param; @@ -223,11 +227,9 @@ int main(void) do { err = bt_le_adv_start( - BT_LE_ADV_PARAM(BT_LE_ADV_OPT_ONE_TIME | BT_LE_ADV_OPT_CONNECTABLE | - BT_LE_ADV_OPT_USE_NAME | - BT_LE_ADV_OPT_FORCE_NAME_IN_AD, + BT_LE_ADV_PARAM(BT_LE_ADV_OPT_ONE_TIME | BT_LE_ADV_OPT_CONNECTABLE, BT_GAP_ADV_FAST_INT_MIN_2, BT_GAP_ADV_FAST_INT_MAX_2, NULL), - NULL, 0, NULL, 0); + NULL, 0, sd, ARRAY_SIZE(sd)); if (err && err != -EALREADY) { printk("Advertising failed to start (err %d)\n", err); diff --git a/samples/bluetooth/peripheral/src/main.c b/samples/bluetooth/peripheral/src/main.c index 7cd65636037..d0c62ec48e3 100644 --- a/samples/bluetooth/peripheral/src/main.c +++ b/samples/bluetooth/peripheral/src/main.c @@ -226,6 +226,10 @@ static const struct bt_data ad[] = { BT_DATA_BYTES(BT_DATA_UUID128_ALL, BT_UUID_CUSTOM_SERVICE_VAL), }; +static const struct bt_data sd[] = { + BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1), +}; + void mtu_updated(struct bt_conn *conn, uint16_t tx, uint16_t rx) { printk("Updated MTU: TX: %d RX: %d bytes\n", tx, rx); @@ -287,7 +291,7 @@ static void bt_ready(void) settings_load(); } - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0); + err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd)); if (err) { printk("Advertising failed to start (err %d)\n", err); return; diff --git a/samples/bluetooth/peripheral_accept_list/src/main.c b/samples/bluetooth/peripheral_accept_list/src/main.c index f185bfdd6c8..ddf390cb063 100644 --- a/samples/bluetooth/peripheral_accept_list/src/main.c +++ b/samples/bluetooth/peripheral_accept_list/src/main.c @@ -74,7 +74,8 @@ static const struct bt_data ad[] = { }; static const struct bt_data sd[] = { - BT_DATA_BYTES(BT_DATA_UUID128_ALL, BT_UUID_CUSTOM_SERVICE_VAL) + BT_DATA_BYTES(BT_DATA_UUID128_ALL, BT_UUID_CUSTOM_SERVICE_VAL), + BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1), }; static void connected(struct bt_conn *conn, uint8_t err) @@ -119,7 +120,7 @@ static void bt_ready(void) bond_count = 0; bt_foreach_bond(BT_ID_DEFAULT, add_bonded_addr_to_filter_list, NULL); - adv_param = *BT_LE_ADV_CONN_NAME; + adv_param = *BT_LE_ADV_CONN; /* If we have got at least one bond, activate the filter */ if (bond_count) { diff --git a/samples/bluetooth/peripheral_csc/src/main.c b/samples/bluetooth/peripheral_csc/src/main.c index d6a2f3d01e5..1a9970adb26 100644 --- a/samples/bluetooth/peripheral_csc/src/main.c +++ b/samples/bluetooth/peripheral_csc/src/main.c @@ -368,13 +368,17 @@ static const struct bt_data ad[] = { BT_UUID_16_ENCODE(BT_UUID_BAS_VAL)) }; +static const struct bt_data sd[] = { + BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1), +}; + static void bt_ready(void) { int err; printk("Bluetooth initialized\n"); - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0); + err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd)); if (err) { printk("Advertising failed to start (err %d)\n", err); return; diff --git a/samples/bluetooth/peripheral_dis/src/main.c b/samples/bluetooth/peripheral_dis/src/main.c index 922177ee57a..f17bbc7c51e 100644 --- a/samples/bluetooth/peripheral_dis/src/main.c +++ b/samples/bluetooth/peripheral_dis/src/main.c @@ -26,6 +26,10 @@ static const struct bt_data ad[] = { BT_DATA_BYTES(BT_DATA_UUID16_ALL, BT_UUID_16_ENCODE(BT_UUID_DIS_VAL)), }; +static const struct bt_data sd[] = { + BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1), +}; + static void connected(struct bt_conn *conn, uint8_t err) { if (err) { @@ -96,7 +100,7 @@ int main(void) printk("Bluetooth initialized\n"); - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0); + err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd)); if (err) { printk("Advertising failed to start (err %d)\n", err); return 0; diff --git a/samples/bluetooth/peripheral_esp/src/main.c b/samples/bluetooth/peripheral_esp/src/main.c index 1375b130172..88ae192ce90 100644 --- a/samples/bluetooth/peripheral_esp/src/main.c +++ b/samples/bluetooth/peripheral_esp/src/main.c @@ -392,6 +392,10 @@ static const struct bt_data ad[] = { BT_UUID_16_ENCODE(BT_UUID_BAS_VAL)), }; +static const struct bt_data sd[] = { + BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1), +}; + static void connected(struct bt_conn *conn, uint8_t err) { if (err) { @@ -417,7 +421,7 @@ static void bt_ready(void) printk("Bluetooth initialized\n"); - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0); + err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd)); if (err) { printk("Advertising failed to start (err %d)\n", err); return; diff --git a/samples/bluetooth/peripheral_gatt_write/src/peripheral_gatt_write.c b/samples/bluetooth/peripheral_gatt_write/src/peripheral_gatt_write.c index 7dcae853f01..019f8262cd6 100644 --- a/samples/bluetooth/peripheral_gatt_write/src/peripheral_gatt_write.c +++ b/samples/bluetooth/peripheral_gatt_write/src/peripheral_gatt_write.c @@ -20,6 +20,10 @@ static const struct bt_data ad[] = { BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), }; +static const struct bt_data sd[] = { + BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1), +}; + static void mtu_updated(struct bt_conn *conn, uint16_t tx, uint16_t rx) { printk("Updated MTU: TX: %d RX: %d bytes\n", tx, rx); @@ -62,7 +66,7 @@ uint32_t peripheral_gatt_write(uint32_t count) (void)bt_conn_auth_cb_register(&auth_callbacks); #endif /* CONFIG_BT_SMP */ - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0); + err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd)); if (err) { printk("Advertising failed to start (err %d)\n", err); return 0U; diff --git a/samples/bluetooth/peripheral_hids/src/main.c b/samples/bluetooth/peripheral_hids/src/main.c index 13109d40d94..ef743b7c57d 100644 --- a/samples/bluetooth/peripheral_hids/src/main.c +++ b/samples/bluetooth/peripheral_hids/src/main.c @@ -31,6 +31,10 @@ static const struct bt_data ad[] = { BT_UUID_16_ENCODE(BT_UUID_BAS_VAL)), }; +static const struct bt_data sd[] = { + BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1), +}; + static void connected(struct bt_conn *conn, uint8_t err) { char addr[BT_ADDR_LE_STR_LEN]; @@ -94,7 +98,7 @@ static void bt_ready(int err) settings_load(); } - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0); + err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd)); if (err) { printk("Advertising failed to start (err %d)\n", err); return; diff --git a/samples/bluetooth/peripheral_hr/Kconfig.sysbuild b/samples/bluetooth/peripheral_hr/Kconfig.sysbuild new file mode 100644 index 00000000000..61836cb8855 --- /dev/null +++ b/samples/bluetooth/peripheral_hr/Kconfig.sysbuild @@ -0,0 +1,15 @@ +# Copyright 2023-2024 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" + default "nrf5340_audio_dk/nrf5340/cpunet" if $(BOARD) = "nrf5340_audio_dk" + default "nrf5340bsim/nrf5340/cpunet" if $(BOARD_TARGET_STRING) = "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/peripheral_hr/boards/nrf5340bsim_nrf5340_cpuapp.conf b/samples/bluetooth/peripheral_hr/boards/nrf5340bsim_nrf5340_cpuapp.conf new file mode 100644 index 00000000000..7ffe275701c --- /dev/null +++ b/samples/bluetooth/peripheral_hr/boards/nrf5340bsim_nrf5340_cpuapp.conf @@ -0,0 +1,3 @@ +# Set same the ACL RX buffer size as in hci_ipc on netcore so that +# HCI Controller to Host Flowcontrol is supported. +CONFIG_BT_BUF_ACL_RX_SIZE=255 diff --git a/samples/bluetooth/peripheral_hr/overlay-extended.conf b/samples/bluetooth/peripheral_hr/overlay-extended.conf new file mode 100644 index 00000000000..69e5e49082b --- /dev/null +++ b/samples/bluetooth/peripheral_hr/overlay-extended.conf @@ -0,0 +1,6 @@ +CONFIG_BT_EXT_ADV=y + +# Increase Advertising Data Length, as Complete Local Name too needs to be +# placed in the AUX_ADV_IND PDU compared to when it is placed in ADV_SCAN_IND +# PDU in the case of legacy advertising. +CONFIG_BT_CTLR_ADV_DATA_LEN_MAX=36 diff --git a/samples/bluetooth/peripheral_hr/overlay-phy_coded.conf b/samples/bluetooth/peripheral_hr/overlay-phy_coded.conf new file mode 100644 index 00000000000..31805e66d4c --- /dev/null +++ b/samples/bluetooth/peripheral_hr/overlay-phy_coded.conf @@ -0,0 +1,12 @@ +CONFIG_BT_EXT_ADV=y + +# Enable Coded PHY support +CONFIG_BT_CTLR_PHY_CODED=y + +# Disable auto PHY update, to switch to 2M PHY +CONFIG_BT_AUTO_PHY_UPDATE=n + +# Increase Advertising Data Length, as Complete Local Name too needs to be +# placed in the AUX_ADV_IND PDU compared to when it is placed in ADV_SCAN_IND +# PDU in the case of legacy advertising. +CONFIG_BT_CTLR_ADV_DATA_LEN_MAX=36 diff --git a/samples/bluetooth/peripheral_hr/prj_minimal.conf b/samples/bluetooth/peripheral_hr/prj_minimal.conf index a9feeb48cb0..bb759ccfdf8 100644 --- a/samples/bluetooth/peripheral_hr/prj_minimal.conf +++ b/samples/bluetooth/peripheral_hr/prj_minimal.conf @@ -91,7 +91,7 @@ CONFIG_BT_GATT_CACHING=n CONFIG_BT_GATT_SERVICE_CHANGED=n CONFIG_BT_GAP_PERIPHERAL_PREF_PARAMS=n CONFIG_BT_SETTINGS_CCC_LAZY_LOADING=y -CONFIG_BT_HCI_VS_EXT=n +CONFIG_BT_HCI_VS=n # Disable Bluetooth controller features not needed CONFIG_BT_CTLR_PRIVACY=n diff --git a/samples/bluetooth/peripheral_hr/sample.yaml b/samples/bluetooth/peripheral_hr/sample.yaml index 71a19327c60..afc3077ac15 100644 --- a/samples/bluetooth/peripheral_hr/sample.yaml +++ b/samples/bluetooth/peripheral_hr/sample.yaml @@ -10,6 +10,38 @@ tests: integration_platforms: - qemu_cortex_m3 tags: bluetooth + sample.bluetooth.peripheral_hr.bt_ll_sw_split.extended: + harness: bluetooth + platform_allow: + - nrf52_bsim + - nrf5340bsim/nrf5340/cpuapp + - nrf52dk/nrf52832 + - nrf52840dk/nrf52840 + - nrf5340dk/nrf5340/cpuapp + integration_platforms: + - nrf52_bsim + - nrf5340bsim/nrf5340/cpuapp + - nrf52dk/nrf52832 + - nrf52840dk/nrf52840 + - nrf5340dk/nrf5340/cpuapp + extra_args: EXTRA_CONF_FILE=overlay-extended.conf + tags: bluetooth + sample.bluetooth.peripheral_hr.bt_ll_sw_split.phy_coded: + harness: bluetooth + platform_allow: + - nrf52_bsim + - nrf5340bsim/nrf5340/cpuapp + - nrf52dk/nrf52832 + - nrf52840dk/nrf52840 + - nrf5340dk/nrf5340/cpuapp + integration_platforms: + - nrf52_bsim + - nrf5340bsim/nrf5340/cpuapp + - nrf52dk/nrf52832 + - nrf52840dk/nrf52840 + - nrf5340dk/nrf5340/cpuapp + extra_args: EXTRA_CONF_FILE=overlay-phy_coded.conf + tags: bluetooth sample.bluetooth.peripheral_hr_rv32m1_vega_openisa_rv32m1_ri5cy: platform_allow: rv32m1_vega/openisa_rv32m1/ri5cy tags: bluetooth diff --git a/samples/bluetooth/peripheral_hr/src/main.c b/samples/bluetooth/peripheral_hr/src/main.c index 135f41667e2..03279c0840f 100644 --- a/samples/bluetooth/peripheral_hr/src/main.c +++ b/samples/bluetooth/peripheral_hr/src/main.c @@ -1,18 +1,14 @@ /* main.c - Application main entry point */ /* + * Copyright (c) 2024 Nordic Semiconductor ASA * Copyright (c) 2015-2016 Intel Corporation * * SPDX-License-Identifier: Apache-2.0 */ -#include -#include -#include -#include -#include -#include -#include +#include +#include #include #include @@ -29,21 +25,40 @@ static const struct bt_data ad[] = { BT_DATA_BYTES(BT_DATA_UUID16_ALL, BT_UUID_16_ENCODE(BT_UUID_HRS_VAL), BT_UUID_16_ENCODE(BT_UUID_BAS_VAL), - BT_UUID_16_ENCODE(BT_UUID_DIS_VAL)) + BT_UUID_16_ENCODE(BT_UUID_DIS_VAL)), +#if defined(CONFIG_BT_EXT_ADV) + BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1), +#endif /* CONFIG_BT_EXT_ADV */ }; +#if !defined(CONFIG_BT_EXT_ADV) +static const struct bt_data sd[] = { + BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1), +}; +#endif /* !CONFIG_BT_EXT_ADV */ + +/* Use atomic variable, 2 bits for connection and disconnection state */ +static ATOMIC_DEFINE(state, 2U); + +#define STATE_CONNECTED 1U +#define STATE_DISCONNECTED 2U + static void connected(struct bt_conn *conn, uint8_t err) { if (err) { printk("Connection failed (err 0x%02x)\n", err); } else { printk("Connected\n"); + + (void)atomic_set_bit(state, STATE_CONNECTED); } } static void disconnected(struct bt_conn *conn, uint8_t reason) { printk("Disconnected (reason 0x%02x)\n", reason); + + (void)atomic_set_bit(state, STATE_DISCONNECTED); } BT_CONN_CB_DEFINE(conn_callbacks) = { @@ -55,36 +70,14 @@ static void hrs_ntf_changed(bool enabled) { hrf_ntf_enabled = enabled; - printk("HRS notification status changed: %s\n", enabled ? "enabled" : "disabled"); + 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; - - printk("Bluetooth initialized\n"); - - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0); - if (err) { - printk("Advertising failed to start (err %d)\n", err); - return; - } - - printk("Advertising successfully started\n"); -} - static void auth_cancel(struct bt_conn *conn) { char addr[BT_ADDR_LE_STR_LEN]; @@ -126,6 +119,73 @@ static void hrs_notify(void) } } +#if defined(CONFIG_GPIO) +/* The devicetree node identifier for the "led0" alias. */ +#define LED0_NODE DT_ALIAS(led0) + +#if DT_NODE_HAS_STATUS(LED0_NODE, okay) +#include +#define HAS_LED 1 +static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED0_NODE, gpios); +#define BLINK_ONOFF K_MSEC(500) + +static struct k_work_delayable blink_work; +static bool led_is_on; + +static void blink_timeout(struct k_work *work) +{ + led_is_on = !led_is_on; + gpio_pin_set(led.port, led.pin, (int)led_is_on); + + k_work_schedule(&blink_work, BLINK_ONOFF); +} + +static int blink_setup(void) +{ + int err; + + printk("Checking LED device..."); + if (!gpio_is_ready_dt(&led)) { + printk("failed.\n"); + return -EIO; + } + printk("done.\n"); + + printk("Configuring GPIO pin..."); + err = gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE); + if (err) { + printk("failed.\n"); + return -EIO; + } + printk("done.\n"); + + k_work_init_delayable(&blink_work, blink_timeout); + + return 0; +} + +static void blink_start(void) +{ + printk("Start blinking LED...\n"); + led_is_on = false; + gpio_pin_set(led.port, led.pin, (int)led_is_on); + k_work_schedule(&blink_work, BLINK_ONOFF); +} + +static void blink_stop(void) +{ + struct k_work_sync work_sync; + + printk("Stop blinking LED.\n"); + k_work_cancel_delayable_sync(&blink_work, &work_sync); + + /* Keep LED on */ + led_is_on = true; + gpio_pin_set(led.port, led.pin, (int)led_is_on); +} +#endif /* LED0_NODE */ +#endif /* CONFIG_GPIO */ + int main(void) { int err; @@ -136,14 +196,75 @@ int main(void) return 0; } - bt_ready(); + printk("Bluetooth initialized\n"); 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 - */ + +#if !defined(CONFIG_BT_EXT_ADV) + printk("Starting Legacy Advertising (connectable and scannable)\n"); + err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd)); + if (err) { + printk("Advertising failed to start (err %d)\n", err); + return 0; + } + +#else /* CONFIG_BT_EXT_ADV */ + struct bt_le_adv_param adv_param = { + .id = BT_ID_DEFAULT, + .sid = 0U, + .secondary_max_skip = 0U, + .options = (BT_LE_ADV_OPT_EXT_ADV | + BT_LE_ADV_OPT_CONNECTABLE | + BT_LE_ADV_OPT_CODED), + .interval_min = BT_GAP_ADV_FAST_INT_MIN_2, + .interval_max = BT_GAP_ADV_FAST_INT_MAX_2, + .peer = NULL, + }; + struct bt_le_ext_adv *adv; + + printk("Creating a Coded PHY connectable non-scannable advertising set\n"); + err = bt_le_ext_adv_create(&adv_param, NULL, &adv); + if (err) { + printk("Failed to create Coded PHY extended advertising set (err %d)\n", err); + + printk("Creating a non-Coded PHY connectable non-scannable advertising set\n"); + adv_param.options &= ~BT_LE_ADV_OPT_CODED; + err = bt_le_ext_adv_create(&adv_param, NULL, &adv); + if (err) { + printk("Failed to create extended advertising set (err %d)\n", err); + return 0; + } + } + + printk("Setting extended advertising data\n"); + err = bt_le_ext_adv_set_data(adv, ad, ARRAY_SIZE(ad), NULL, 0); + if (err) { + printk("Failed to set extended advertising data (err %d)\n", err); + return 0; + } + + printk("Starting Extended Advertising (connectable non-scannable)\n"); + err = bt_le_ext_adv_start(adv, BT_LE_EXT_ADV_START_DEFAULT); + if (err) { + printk("Failed to start extended advertising set (err %d)\n", err); + return 0; + } +#endif /* CONFIG_BT_EXT_ADV */ + + printk("Advertising successfully started\n"); + +#if defined(HAS_LED) + err = blink_setup(); + if (err) { + return 0; + } + + blink_start(); +#endif /* HAS_LED */ + + /* Implement notification. */ while (1) { k_sleep(K_SECONDS(1)); @@ -152,6 +273,28 @@ int main(void) /* Battery level simulation */ bas_notify(); + + if (atomic_test_and_clear_bit(state, STATE_CONNECTED)) { + /* Connected callback executed */ + +#if defined(HAS_LED) + blink_stop(); +#endif /* HAS_LED */ + } else if (atomic_test_and_clear_bit(state, STATE_DISCONNECTED)) { +#if defined(CONFIG_BT_EXT_ADV) + printk("Starting Extended Advertising (connectable and non-scannable)\n"); + err = bt_le_ext_adv_start(adv, BT_LE_EXT_ADV_START_DEFAULT); + if (err) { + printk("Failed to start extended advertising set (err %d)\n", err); + return 0; + } +#endif /* CONFIG_BT_EXT_ADV */ + +#if defined(HAS_LED) + blink_start(); +#endif /* HAS_LED */ + } } + return 0; } diff --git a/samples/bluetooth/peripheral_hr/sysbuild.cmake b/samples/bluetooth/peripheral_hr/sysbuild.cmake new file mode 100644 index 00000000000..2523aac8ea7 --- /dev/null +++ b/samples/bluetooth/peripheral_hr/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/peripheral_ht/src/main.c b/samples/bluetooth/peripheral_ht/src/main.c index 3f547652af6..197ee1cdaec 100644 --- a/samples/bluetooth/peripheral_ht/src/main.c +++ b/samples/bluetooth/peripheral_ht/src/main.c @@ -31,6 +31,10 @@ static const struct bt_data ad[] = { BT_UUID_16_ENCODE(BT_UUID_BAS_VAL)), }; +static const struct bt_data sd[] = { + BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1), +}; + static void connected(struct bt_conn *conn, uint8_t err) { if (err) { @@ -58,7 +62,7 @@ static void bt_ready(void) hts_init(); - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0); + err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd)); if (err) { printk("Advertising failed to start (err %d)\n", err); return; diff --git a/samples/bluetooth/peripheral_identity/src/peripheral_identity.c b/samples/bluetooth/peripheral_identity/src/peripheral_identity.c index ee35533b371..57956081fe3 100644 --- a/samples/bluetooth/peripheral_identity/src/peripheral_identity.c +++ b/samples/bluetooth/peripheral_identity/src/peripheral_identity.c @@ -22,6 +22,10 @@ static const struct bt_data ad[] = { BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), }; +static const struct bt_data sd[] = { + BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1), +}; + static void adv_start(struct k_work *work) { struct bt_le_adv_param adv_param = { @@ -29,7 +33,6 @@ static void adv_start(struct k_work *work) .sid = 0, .secondary_max_skip = 0, .options = (BT_LE_ADV_OPT_CONNECTABLE | - BT_LE_ADV_OPT_USE_NAME | BT_LE_ADV_OPT_ONE_TIME), .interval_min = 0x0020, /* 20 ms */ .interval_max = 0x0020, /* 20 ms */ @@ -57,7 +60,7 @@ static void adv_start(struct k_work *work) printk("Using current id: %u\n", id_current); adv_param.id = id_current; - err = bt_le_adv_start(&adv_param, ad, ARRAY_SIZE(ad), NULL, 0); + err = bt_le_adv_start(&adv_param, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd)); if (err) { printk("Advertising failed to start (err %d)\n", err); return; diff --git a/samples/bluetooth/peripheral_iso/src/main.c b/samples/bluetooth/peripheral_iso/src/main.c index 95f415e9503..e93b11bcf7f 100644 --- a/samples/bluetooth/peripheral_iso/src/main.c +++ b/samples/bluetooth/peripheral_iso/src/main.c @@ -22,6 +22,10 @@ static const struct bt_data ad[] = { BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), }; +static const struct bt_data sd[] = { + BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1), +}; + static void connected(struct bt_conn *conn, uint8_t err) { char addr[BT_ADDR_LE_STR_LEN]; @@ -172,7 +176,7 @@ int main(void) return 0; } - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0); + err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd)); if (err) { printk("Advertising failed to start (err %d)\n", err); return 0; diff --git a/samples/bluetooth/peripheral_past/src/main.c b/samples/bluetooth/peripheral_past/src/main.c index a3058af1755..398e691cf61 100644 --- a/samples/bluetooth/peripheral_past/src/main.c +++ b/samples/bluetooth/peripheral_past/src/main.c @@ -110,6 +110,10 @@ static struct bt_conn_cb conn_callbacks = { .disconnected = disconnected, }; +static const struct bt_data sd[] = { + BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1), +}; + int main(void) { struct bt_le_per_adv_sync_transfer_param past_param; @@ -142,7 +146,7 @@ int main(void) return 0; } - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, NULL, 0, NULL, 0); + err = bt_le_adv_start(BT_LE_ADV_CONN, NULL, 0, sd, ARRAY_SIZE(sd)); if (err) { printk("Advertising failed to start (err %d)\n", err); return 0; diff --git a/samples/bluetooth/peripheral_sc_only/src/main.c b/samples/bluetooth/peripheral_sc_only/src/main.c index d9e8f646236..0b75d552427 100644 --- a/samples/bluetooth/peripheral_sc_only/src/main.c +++ b/samples/bluetooth/peripheral_sc_only/src/main.c @@ -24,6 +24,10 @@ static const struct bt_data ad[] = { BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), }; +static const struct bt_data sd[] = { + BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1), +}; + static void connected(struct bt_conn *conn, uint8_t err) { char addr[BT_ADDR_LE_STR_LEN]; @@ -141,7 +145,7 @@ int main(void) bt_conn_auth_cb_register(&auth_cb_display); bt_conn_auth_info_cb_register(&auth_cb_info); - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0); + err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd)); if (err) { printk("Advertising failed to start (err %d)\n", err); return 0; 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 index c73ff9c3ea9..3711a349213 100644 --- a/samples/bluetooth/public_broadcast_source/overlay-bt_ll_sw_split.conf +++ b/samples/bluetooth/public_broadcast_source/overlay-bt_ll_sw_split.conf @@ -14,11 +14,7 @@ CONFIG_BT_CTLR_ADV_ISO_PDU_LEN_MAX=155 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) +# Support the highest SDU size required by any BAP LC3 presets (155) + 8 bytes of HCI ISO Data +# packet overhead (the Packet_Sequence_Number, ISO_SDU_Length, Packet_Status_Flag fields; and +# the optional Time_Stamp field, if supplied) CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=163 diff --git a/samples/bluetooth/public_broadcast_source/src/main.c b/samples/bluetooth/public_broadcast_source/src/main.c index b9377e9f312..5ffb94d785f 100644 --- a/samples/bluetooth/public_broadcast_source/src/main.c +++ b/samples/bluetooth/public_broadcast_source/src/main.c @@ -49,6 +49,10 @@ 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); +static const struct bt_data ad[] = { + BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1), +}; + 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; @@ -124,13 +128,21 @@ 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); + err = bt_le_ext_adv_create(BT_LE_EXT_ADV_NCONN, NULL, adv); if (err != 0) { printk("Unable to create extended advertising set: %d\n", err); return err; } + /* Set advertising data to have complete local name set */ + err = bt_le_ext_adv_set_data(*adv, ad, ARRAY_SIZE(ad), NULL, 0); + if (err) { + printk("Failed to set advertising data (err %d)\n", err); + + return 0; + } + /* Set periodic advertising parameters */ err = bt_le_per_adv_set_param(*adv, BT_LE_PER_ADV_DEFAULT); if (err) { diff --git a/samples/bluetooth/tmap_bmr/boards/nrf52840dk_nrf52840.conf b/samples/bluetooth/tmap_bmr/boards/nrf52840dk_nrf52840.conf deleted file mode 100644 index 3c7c698c48b..00000000000 --- a/samples/bluetooth/tmap_bmr/boards/nrf52840dk_nrf52840.conf +++ /dev/null @@ -1,4 +0,0 @@ -CONFIG_BT_CTLR_PERIPHERAL_ISO=y - -# Supports the highest SDU size required by any BAP LC3 presets (155) -CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=155 diff --git a/samples/bluetooth/tmap_bms/boards/nrf52840dk_nrf52840.conf b/samples/bluetooth/tmap_bms/boards/nrf52840dk_nrf52840.conf deleted file mode 100644 index 57d674179ff..00000000000 --- a/samples/bluetooth/tmap_bms/boards/nrf52840dk_nrf52840.conf +++ /dev/null @@ -1,4 +0,0 @@ -CONFIG_BT_CTLR_CENTRAL_ISO=y - -# Supports the highest SDU size required by any BAP LC3 presets (155) -CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=155 diff --git a/samples/bluetooth/tmap_bms/src/cap_initiator.c b/samples/bluetooth/tmap_bms/src/cap_initiator.c index 249d31d49da..2c0019e234c 100644 --- a/samples/bluetooth/tmap_bms/src/cap_initiator.c +++ b/samples/bluetooth/tmap_bms/src/cap_initiator.c @@ -107,17 +107,28 @@ static struct bt_bap_stream_ops broadcast_stream_ops = { .sent = broadcast_sent_cb }; +static const struct bt_data ad[] = { + BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1), +}; + 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); + err = bt_le_ext_adv_create(BT_LE_EXT_ADV_NCONN, NULL, adv); if (err != 0) { printk("Unable to create extended advertising set: %d\n", err); return err; } + /* Set advertising data to have complete local name set */ + err = bt_le_ext_adv_set_data(*adv, ad, ARRAY_SIZE(ad), NULL, 0); + if (err) { + printk("Failed to set advertising data (err %d)\n", err); + return 0; + } + /* Set periodic advertising parameters */ err = bt_le_per_adv_set_param(*adv, BT_LE_PER_ADV_DEFAULT); if (err) { diff --git a/samples/bluetooth/tmap_central/boards/nrf52840dk_nrf52840.conf b/samples/bluetooth/tmap_central/boards/nrf52840dk_nrf52840.conf deleted file mode 100644 index 57d674179ff..00000000000 --- a/samples/bluetooth/tmap_central/boards/nrf52840dk_nrf52840.conf +++ /dev/null @@ -1,4 +0,0 @@ -CONFIG_BT_CTLR_CENTRAL_ISO=y - -# Supports the highest SDU size required by any BAP LC3 presets (155) -CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=155 diff --git a/samples/bluetooth/tmap_central/src/cap_initiator.c b/samples/bluetooth/tmap_central/src/cap_initiator.c index dc7e54c439d..fd20fadaa71 100644 --- a/samples/bluetooth/tmap_central/src/cap_initiator.c +++ b/samples/bluetooth/tmap_central/src/cap_initiator.c @@ -98,6 +98,7 @@ static struct bt_bap_lc3_preset unicast_preset_48_2_1 = BT_AUDIO_CONTEXT_TYPE_MEDIA); static void cap_discovery_complete_cb(struct bt_conn *conn, int err, + const struct bt_csip_set_coordinator_set_member *member, const struct bt_csip_set_coordinator_csis_inst *csis_inst) { if (err != 0) { diff --git a/samples/bluetooth/tmap_peripheral/boards/nrf52840dk_nrf52840.conf b/samples/bluetooth/tmap_peripheral/boards/nrf52840dk_nrf52840.conf deleted file mode 100644 index 3c7c698c48b..00000000000 --- a/samples/bluetooth/tmap_peripheral/boards/nrf52840dk_nrf52840.conf +++ /dev/null @@ -1,4 +0,0 @@ -CONFIG_BT_CTLR_PERIPHERAL_ISO=y - -# Supports the highest SDU size required by any BAP LC3 presets (155) -CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=155 diff --git a/samples/bluetooth/tmap_peripheral/prj.conf b/samples/bluetooth/tmap_peripheral/prj.conf index 79725aaba2b..35f5d15502c 100644 --- a/samples/bluetooth/tmap_peripheral/prj.conf +++ b/samples/bluetooth/tmap_peripheral/prj.conf @@ -1,6 +1,7 @@ CONFIG_BT=y CONFIG_LOG=y CONFIG_BT_PERIPHERAL=y +CONFIG_BT_ISO_PERIPHERAL=y CONFIG_BT_PRIVACY=y CONFIG_BT_AUDIO=y CONFIG_UTF8=y @@ -27,6 +28,7 @@ CONFIG_BT_VCP_VOL_REND=y CONFIG_BT_MCC=y # Support an ISO channel per ASE +CONFIG_BT_ASCS=y CONFIG_BT_ASCS_ASE_SNK_COUNT=1 CONFIG_BT_ASCS_ASE_SRC_COUNT=1 # Support an ISO channel per ASE diff --git a/samples/bluetooth/tmap_peripheral/src/main.c b/samples/bluetooth/tmap_peripheral/src/main.c index 59aa8c70ef0..2a7ecc61759 100644 --- a/samples/bluetooth/tmap_peripheral/src/main.c +++ b/samples/bluetooth/tmap_peripheral/src/main.c @@ -62,6 +62,7 @@ static const struct bt_data ad[] = { BT_DATA(BT_DATA_SVC_DATA16, tmap_addata, ARRAY_SIZE(tmap_addata)), BT_DATA(BT_DATA_SVC_DATA16, cap_addata, ARRAY_SIZE(cap_addata)), BT_DATA(BT_DATA_SVC_DATA16, unicast_server_addata, ARRAY_SIZE(unicast_server_addata)), + BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1), }; static K_SEM_DEFINE(sem_connected, 0, 1); @@ -243,7 +244,7 @@ int main(void) } printk("BAP initialized\n"); - err = bt_le_ext_adv_create(BT_LE_EXT_ADV_CONN_NAME, &adv_cb, &adv); + err = bt_le_ext_adv_create(BT_LE_EXT_ADV_CONN, &adv_cb, &adv); if (err) { printk("Failed to create advertising set (err %d)\n", err); return err; diff --git a/samples/bluetooth/unicast_audio_client/boards/nrf52840dk_nrf52840.conf b/samples/bluetooth/unicast_audio_client/boards/nrf52840dk_nrf52840.conf deleted file mode 100644 index 57d674179ff..00000000000 --- a/samples/bluetooth/unicast_audio_client/boards/nrf52840dk_nrf52840.conf +++ /dev/null @@ -1,4 +0,0 @@ -CONFIG_BT_CTLR_CENTRAL_ISO=y - -# Supports the highest SDU size required by any BAP LC3 presets (155) -CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=155 diff --git a/samples/bluetooth/unicast_audio_client/overlay-bt_ll_sw_split.conf b/samples/bluetooth/unicast_audio_client/overlay-bt_ll_sw_split.conf index 1c29b28e2dd..755e7fafa78 100644 --- a/samples/bluetooth/unicast_audio_client/overlay-bt_ll_sw_split.conf +++ b/samples/bluetooth/unicast_audio_client/overlay-bt_ll_sw_split.conf @@ -1,9 +1,14 @@ CONFIG_BT_LL_SW_SPLIT=y CONFIG_BT_CTLR_SCAN_DATA_LEN_MAX=1650 CONFIG_BT_CTLR_ISO_TX_BUFFERS=4 -CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=155 CONFIG_BT_CTLR_ISOAL_SOURCES=2 CONFIG_BT_CTLR_ISOAL_SINKS=1 + +# Support the highest SDU size required by any BAP LC3 presets (155) + 8 bytes of HCI ISO Data +# packet overhead (the Packet_Sequence_Number, ISO_SDU_Length, Packet_Status_Flag fields; and +# the optional Time_Stamp field, if supplied) +CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=163 + CONFIG_BT_CTLR_ADVANCED_FEATURES=y CONFIG_BT_CTLR_CONN_ISO_LOW_LATENCY_POLICY=y diff --git a/samples/bluetooth/unicast_audio_server/boards/nrf52840dk_nrf52840.conf b/samples/bluetooth/unicast_audio_server/boards/nrf52840dk_nrf52840.conf deleted file mode 100644 index 3c7c698c48b..00000000000 --- a/samples/bluetooth/unicast_audio_server/boards/nrf52840dk_nrf52840.conf +++ /dev/null @@ -1,4 +0,0 @@ -CONFIG_BT_CTLR_PERIPHERAL_ISO=y - -# Supports the highest SDU size required by any BAP LC3 presets (155) -CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=155 diff --git a/samples/bluetooth/unicast_audio_server/overlay-bt_ll_sw_split.conf b/samples/bluetooth/unicast_audio_server/overlay-bt_ll_sw_split.conf index 1499e379d4e..8c6d99253a6 100644 --- a/samples/bluetooth/unicast_audio_server/overlay-bt_ll_sw_split.conf +++ b/samples/bluetooth/unicast_audio_server/overlay-bt_ll_sw_split.conf @@ -1,10 +1,14 @@ CONFIG_BT_LL_SW_SPLIT=y CONFIG_BT_CTLR_ADV_DATA_LEN_MAX=191 CONFIG_BT_CTLR_ISO_TX_BUFFERS=2 -CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=155 CONFIG_BT_CTLR_ISOAL_SOURCES=1 CONFIG_BT_CTLR_ISOAL_SINKS=2 +# Support the highest SDU size required by any BAP LC3 presets (155) + 8 bytes of HCI ISO Data +# packet overhead (the Packet_Sequence_Number, ISO_SDU_Length, Packet_Status_Flag fields; and +# the optional Time_Stamp field, if supplied) +CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=163 + # Use the below if the sample is sending stale packet sequence number # CONFIG_BT_CTLR_ADVANCED_FEATURES=y # CONFIG_BT_CTLR_ISOAL_SN_STRICT=n diff --git a/samples/bluetooth/unicast_audio_server/prj.conf b/samples/bluetooth/unicast_audio_server/prj.conf index 3aec74ddbcc..2705d0c1895 100644 --- a/samples/bluetooth/unicast_audio_server/prj.conf +++ b/samples/bluetooth/unicast_audio_server/prj.conf @@ -1,8 +1,10 @@ CONFIG_BT=y CONFIG_LOG=y CONFIG_BT_PERIPHERAL=y +CONFIG_BT_ISO_PERIPHERAL=y CONFIG_BT_AUDIO=y CONFIG_BT_BAP_UNICAST_SERVER=y +CONFIG_BT_ASCS=y CONFIG_BT_ASCS_ASE_SNK_COUNT=2 CONFIG_BT_ASCS_ASE_SRC_COUNT=1 CONFIG_BT_ISO_TX_BUF_COUNT=2 diff --git a/samples/bluetooth/unicast_audio_server/src/main.c b/samples/bluetooth/unicast_audio_server/src/main.c index 350f672b0c4..db2a76fbab6 100644 --- a/samples/bluetooth/unicast_audio_server/src/main.c +++ b/samples/bluetooth/unicast_audio_server/src/main.c @@ -67,6 +67,7 @@ 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, BT_UUID_16_ENCODE(BT_UUID_ASCS_VAL)), BT_DATA(BT_DATA_SVC_DATA16, unicast_server_addata, ARRAY_SIZE(unicast_server_addata)), + BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1), }; #define AUDIO_DATA_TIMEOUT_US 1000000UL /* Send data every 1 second */ @@ -750,7 +751,7 @@ int main(void) } /* Create a non-connectable non-scannable advertising set */ - err = bt_le_ext_adv_create(BT_LE_EXT_ADV_CONN_NAME, NULL, &adv); + err = bt_le_ext_adv_create(BT_LE_EXT_ADV_CONN, NULL, &adv); if (err) { printk("Failed to create advertising set (err %d)\n", err); return 0; diff --git a/samples/boards/bbc_microbit/pong/src/ble.c b/samples/boards/bbc_microbit/pong/src/ble.c index 89f34f3585f..9f86a8e8712 100644 --- a/samples/boards/bbc_microbit/pong/src/ble.c +++ b/samples/boards/bbc_microbit/pong/src/ble.c @@ -42,6 +42,10 @@ static const struct bt_data ad[] = { BT_DATA_BYTES(BT_DATA_UUID128_ALL, PONG_SVC_UUID), }; +static const struct bt_data sd[] = { + BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1), +}; + static struct bt_conn *default_conn; static const struct bt_gatt_attr *local_attr; @@ -467,8 +471,8 @@ static void ble_timeout(struct k_work *work) k_work_reschedule(&ble_work, K_NO_WAIT); break; case BLE_ADV_START: - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), - NULL, 0); + err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), + sd, ARRAY_SIZE(sd)); if (err) { printk("Advertising failed to start (err %d)\n", err); return; diff --git a/samples/boards/esp32/deep_sleep/boards/yd_esp32.conf b/samples/boards/esp32/deep_sleep/boards/yd_esp32_procpu.conf similarity index 100% rename from samples/boards/esp32/deep_sleep/boards/yd_esp32.conf rename to samples/boards/esp32/deep_sleep/boards/yd_esp32_procpu.conf diff --git a/samples/boards/esp32/ethernet/boards/esp32_ethernet_kit.overlay b/samples/boards/esp32/ethernet/boards/esp32_ethernet_kit_procpu.overlay similarity index 100% rename from samples/boards/esp32/ethernet/boards/esp32_ethernet_kit.overlay rename to samples/boards/esp32/ethernet/boards/esp32_ethernet_kit_procpu.overlay diff --git a/samples/boards/esp32/flash_encryption/boards/yd_esp32.overlay b/samples/boards/esp32/flash_encryption/boards/yd_esp32_procpu.overlay similarity index 100% rename from samples/boards/esp32/flash_encryption/boards/yd_esp32.overlay rename to samples/boards/esp32/flash_encryption/boards/yd_esp32_procpu.overlay diff --git a/samples/boards/mec15xxevb_assy6853/power_management/sample.yaml b/samples/boards/mec15xxevb_assy6853/power_management/sample.yaml index 578477ba689..b03b441e172 100644 --- a/samples/boards/mec15xxevb_assy6853/power_management/sample.yaml +++ b/samples/boards/mec15xxevb_assy6853/power_management/sample.yaml @@ -13,4 +13,3 @@ tests: regex: - "Wake from Light Sleep" - "Wake from Deep Sleep" - repeat: 3 diff --git a/samples/boards/nrf/mesh/onoff-app/prj.conf b/samples/boards/nrf/mesh/onoff-app/prj.conf index 0fdf19b8cfc..8c74fc50e39 100644 --- a/samples/boards/nrf/mesh/onoff-app/prj.conf +++ b/samples/boards/nrf/mesh/onoff-app/prj.conf @@ -79,8 +79,6 @@ CONFIG_BT_MESH_LOG_LEVEL_DBG=y #CONFIG_BT_MESH_ADV_LOG_LEVEL_DBG=y #CONFIG_BT_MESH_SELF_TEST=y -#CONFIG_BT_HCI_VS_EXT=n - #CONFIG_STACK_USAGE=y CONFIG_BT_RX_STACK_SIZE=4096 diff --git a/samples/boards/nrf/nrfx_prs/sample.yaml b/samples/boards/nrf/nrfx_prs/sample.yaml index 149dd172483..95c772d7d89 100644 --- a/samples/boards/nrf/nrfx_prs/sample.yaml +++ b/samples/boards/nrf/nrfx_prs/sample.yaml @@ -17,3 +17,8 @@ tests: - "nrfx PRS example on .*" - "-> press \".*\" to trigger a transfer" - "-> press \".*\" to switch the type of peripheral" + - "Switched to SPIM" + - "-- Background transfer on \".*\" --" + - "Tx: 4E 6F 72 64 69 63 20 53 65 6D 69 63 6F 6E 64 75 63 74 6F 72 00" + - "Rx:" + - "-- Background transfer on \".*\" --" diff --git a/samples/boards/nrf/nrfx_prs/src/main.c b/samples/boards/nrf/nrfx_prs/src/main.c index 934bbbe834d..cf989b4c4c9 100644 --- a/samples/boards/nrf/nrfx_prs/src/main.c +++ b/samples/boards/nrf/nrfx_prs/src/main.c @@ -13,6 +13,7 @@ #include #include #include +#include #define TRANSFER_LENGTH 10 @@ -133,6 +134,8 @@ static bool switch_to_spim(void) */ if (uarte_initialized) { nrfx_uarte_uninit(&uarte); + /* Workaround: uninit does not clear events, make sure all events are cleared. */ + nrfy_uarte_int_init(uarte.p_reg, 0xFFFFFFFF, 0, false); uarte_initialized = false; } @@ -141,7 +144,7 @@ static bool switch_to_spim(void) NRF_SPIM_PIN_NOT_CONNECTED, NRF_SPIM_PIN_NOT_CONNECTED, NRF_DT_GPIOS_TO_PSEL(SPIM_NODE, cs_gpios)); - spim_config.frequency = NRF_SPIM_FREQ_1M; + spim_config.frequency = MHZ(1); spim_config.skip_gpio_cfg = true; spim_config.skip_psel_cfg = true; @@ -151,6 +154,10 @@ static bool switch_to_spim(void) return ret; } + /* Set initial state of SCK according to the SPI mode. */ + nrfy_gpio_pin_write(nrfy_spim_sck_pin_get(spim.p_reg), + (spim_config.mode <= NRF_SPIM_MODE_1) ? 0 : 1); + err = nrfx_spim_init(&spim, &spim_config, spim_handler, NULL); if (err != NRFX_SUCCESS) { printk("nrfx_spim_init() failed: 0x%08x\n", err); @@ -215,6 +222,8 @@ static bool switch_to_uarte(void) */ if (spim_initialized) { nrfx_spim_uninit(&spim); + /* Workaround: uninit does not clear events, make sure all events are cleared. */ + nrfy_spim_int_init(spim.p_reg, 0xFFFFFFFF, 0, false); spim_initialized = false; } @@ -291,7 +300,7 @@ static bool background_transfer(const struct device *spi_dev) static const struct spi_config spi_dev_cfg = { .operation = SPI_OP_MODE_MASTER | SPI_WORD_SET(8) | SPI_TRANSFER_MSB, - .frequency = 1000000, + .frequency = MHZ(1), .cs = { .gpio = GPIO_DT_SPEC_GET(SPI_DEV_NODE, cs_gpios), }, diff --git a/samples/boards/reel_board/mesh_badge/src/main.c b/samples/boards/reel_board/mesh_badge/src/main.c index 49dd110ec0e..932e25f2d89 100644 --- a/samples/boards/reel_board/mesh_badge/src/main.c +++ b/samples/boards/reel_board/mesh_badge/src/main.c @@ -22,6 +22,10 @@ static const struct bt_data ad[] = { BT_DATA_BYTES(BT_DATA_FLAGS, BT_LE_AD_NO_BREDR), }; +static const struct bt_data sd[] = { + BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1), +}; + static ssize_t read_name(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { @@ -176,8 +180,7 @@ static void bt_ready(int err) if (!mesh_is_initialized()) { /* Start advertising */ - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, - ad, ARRAY_SIZE(ad), NULL, 0); + err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd)); if (err) { printk("Advertising failed to start (err %d)\n", err); return; diff --git a/samples/boards/stm32/power_mgmt/suspend_to_ram/README.rst b/samples/boards/stm32/power_mgmt/suspend_to_ram/README.rst index 246ac96ea10..29590134f19 100644 --- a/samples/boards/stm32/power_mgmt/suspend_to_ram/README.rst +++ b/samples/boards/stm32/power_mgmt/suspend_to_ram/README.rst @@ -9,6 +9,8 @@ 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. +SPI loopback is also available but not yet implemented for Suspend To RAM PM +mode. .. _stm32-pm-suspend-to-ram-sample-requirements: 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 index a3d46e95fb7..5976dfdbc76 100644 --- 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 @@ -50,3 +50,18 @@ zephyr,resolution = <12>; }; }; + +&spi1 { + dmas = <&gpdma1 0 2 (STM32_DMA_PERIPH_TX | STM32_DMA_PRIORITY_HIGH) + &gpdma1 1 1 (STM32_DMA_PERIPH_RX | STM32_DMA_PRIORITY_HIGH)>; + dma-names = "tx", "rx"; + fast@0 { + compatible = "test-spi-loopback"; + reg = <0>; + spi-max-frequency = <500000>; + }; +}; + +&gpdma1 { + status = "okay"; +}; diff --git a/samples/boards/stm32/power_mgmt/suspend_to_ram/dts/bindings/test-spi-loopback.yaml b/samples/boards/stm32/power_mgmt/suspend_to_ram/dts/bindings/test-spi-loopback.yaml new file mode 100644 index 00000000000..48043c088b7 --- /dev/null +++ b/samples/boards/stm32/power_mgmt/suspend_to_ram/dts/bindings/test-spi-loopback.yaml @@ -0,0 +1,13 @@ +# +# Copyright (c) 2024 STMicroelectronics +# +# SPDX-License-Identifier: Apache-2.0 +# + +description: | + This binding provides resources required to build and run an SPI + loopback test under power management conditions + +compatible: "test-spi-loopback" + +include: [spi-device.yaml] diff --git a/samples/boards/stm32/power_mgmt/suspend_to_ram/prj.conf b/samples/boards/stm32/power_mgmt/suspend_to_ram/prj.conf index acef64bb9a8..78963168c5a 100644 --- a/samples/boards/stm32/power_mgmt/suspend_to_ram/prj.conf +++ b/samples/boards/stm32/power_mgmt/suspend_to_ram/prj.conf @@ -5,4 +5,7 @@ CONFIG_PM_DEVICE_RUNTIME_EXCLUSIVE=n CONFIG_PM_S2RAM=y CONFIG_ADC=y CONFIG_ENTROPY_GENERATOR=y -#CONFIG_DEBUG=y +CONFIG_SPI=y +CONFIG_SPI_STM32_DMA=y +CONFIG_SPI_STM32_INTERRUPT=n +CONFIG_SPI_ASYNC=n 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 index bb1ca9dbb55..0f77e7d85d9 100644 --- a/samples/boards/stm32/power_mgmt/suspend_to_ram/src/main.c +++ b/samples/boards/stm32/power_mgmt/suspend_to_ram/src/main.c @@ -13,7 +13,10 @@ #include #include #include +#include #include +#include +#include #define SLEEP_TIME_STOP0_MS 800 #define SLEEP_TIME_STOP1_MS 1500 @@ -21,7 +24,7 @@ #define SLEEP_TIME_BUSY_MS 2000 static const struct gpio_dt_spec led = - GPIO_DT_SPEC_GET(DT_ALIAS(led0), gpios); + GPIO_DT_SPEC_GET(DT_ALIAS(led2), gpios); #if !DT_NODE_EXISTS(DT_PATH(zephyr_user)) || \ !DT_NODE_HAS_PROP(DT_PATH(zephyr_user), io_channels) @@ -43,6 +46,86 @@ const struct device *rng_dev; static uint8_t entropy_buffer[BUFFER_LENGTH] = {0}; +#define SPI_TEST_DEV DT_COMPAT_GET_ANY_STATUS_OKAY(test_spi_loopback) + +#define FRAME_SIZE (8) + +#define SPI_OP(frame_size) SPI_OP_MODE_MASTER | SPI_MODE_CPOL | \ + SPI_MODE_CPHA | SPI_WORD_SET(frame_size) | SPI_LINES_SINGLE + +static struct spi_dt_spec spi_test_dev = SPI_DT_SPEC_GET(SPI_TEST_DEV, SPI_OP(FRAME_SIZE), 0); + +#define SPI_BUF_SIZE 18 + +static const char spi_tx_data[SPI_BUF_SIZE] = "0123456789abcdef-\0"; +static __aligned(32) char spi_buffer_tx[SPI_BUF_SIZE] __used; +static __aligned(32) char spi_buffer_rx[SPI_BUF_SIZE] __used; + +static uint8_t spi_buffer_print_tx[SPI_BUF_SIZE * 5 + 1]; +static uint8_t spi_buffer_print_rx[SPI_BUF_SIZE * 5 + 1]; + +static void to_display_format(const uint8_t *src, size_t size, char *dst) +{ + size_t i; + + for (i = 0; i < size; i++) { + sprintf(dst + 5 * i, "0x%02x,", src[i]); + } +} + +static int spi_test(void) +{ + const struct spi_buf tx_bufs[] = { + { + .buf = spi_buffer_tx, + .len = SPI_BUF_SIZE, + }, + }; + const struct spi_buf rx_bufs[] = { + { + .buf = spi_buffer_rx, + .len = SPI_BUF_SIZE, + }, + }; + const struct spi_buf_set tx = { + .buffers = tx_bufs, + .count = ARRAY_SIZE(tx_bufs) + }; + const struct spi_buf_set rx = { + .buffers = rx_bufs, + .count = ARRAY_SIZE(rx_bufs) + }; + + int ret; + + ret = spi_transceive_dt(&spi_test_dev, &tx, &rx); + if (ret) { + printk("SPI transceive failed: %d\n", ret); + return ret; + } + + if (memcmp(spi_buffer_tx, spi_buffer_rx, SPI_BUF_SIZE)) { + to_display_format(spi_buffer_tx, SPI_BUF_SIZE, spi_buffer_print_tx); + to_display_format(spi_buffer_rx, SPI_BUF_SIZE, spi_buffer_print_rx); + printk("Buffer contents are different\n"); + printk("tx: %s\n", spi_buffer_print_tx); + printk("rx: %s\n", spi_buffer_print_rx); + return -1; + } + + return 0; +} + +static void spi_setup(void) +{ + memset(spi_buffer_tx, 0, sizeof(spi_buffer_tx)); + memcpy(spi_buffer_tx, spi_tx_data, sizeof(spi_tx_data)); + + if (!spi_is_ready_dt(&spi_test_dev)) { + printk("Fast spi lookback device is not ready\n"); + } +} + static int adc_test(void) { int err; @@ -122,6 +205,17 @@ void print_buf(uint8_t *buffer) printk("\n"); } +static void loop(void) +{ + gpio_pin_set_dt(&led, 1); + adc_test(); + if (!IS_ENABLED(CONFIG_PM_S2RAM)) { + spi_test(); + } + k_busy_wait(SLEEP_TIME_BUSY_MS*1000); + gpio_pin_set_dt(&led, 0); +} + int main(void) { __ASSERT_NO_MSG(gpio_is_ready_dt(&led)); @@ -131,20 +225,17 @@ int main(void) printk("error: random device not ready"); } + spi_setup(); + 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); + loop(); 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); + loop(); k_msleep(SLEEP_TIME_STOP1_MS); printk("Exit Stop1\n"); @@ -153,9 +244,7 @@ int main(void) printk("Sync entropy: "); print_buf(entropy_buffer); - gpio_pin_set_dt(&led, 1); - adc_test(); - k_busy_wait(SLEEP_TIME_BUSY_MS*1000); + loop(); gpio_pin_configure_dt(&led, GPIO_DISCONNECTED); k_msleep(SLEEP_TIME_STANDBY_MS); printk("Exit Standby\n"); diff --git a/samples/boards/up_squared/gpio_counter/CMakeLists.txt b/samples/boards/up_squared/gpio_counter/CMakeLists.txt deleted file mode 100644 index be34f4fe1fd..00000000000 --- a/samples/boards/up_squared/gpio_counter/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(gpio_counter) - -target_sources(app PRIVATE src/main.c) diff --git a/samples/boards/up_squared/gpio_counter/README.rst b/samples/boards/up_squared/gpio_counter/README.rst deleted file mode 100644 index 449be17b93a..00000000000 --- a/samples/boards/up_squared/gpio_counter/README.rst +++ /dev/null @@ -1,94 +0,0 @@ -.. _up_squared gpio_counter: - -UP Squared GPIO Counter -####################### - -Overview -******** -This sample provides an example of how to configure GPIO input and output to -the UP Squared board. - -The sample enables a pin as GPIO input (active high) that triggers the increment -of a counter (range is 0x0 to 0xf). The counter increments for -each change from 0 to 1 on HAT Pin 16 (BIOS Pin 19). The value of the counter is -represented on GPIO output (active high) as a 4-bit value -(bin 0, 1, 2, 3 -> HAT Pin 35, 37, 38, 40). - -+------------+-----------------------------+ -| Element | Mapping (by column) | -+============+=====+=====+=====+=====+=====+ -| Bit (bin) | n/a | 3 | 2 | 1 | 0 | -+------------+-----+-----+-----+-----+-----+ -| HAT Pin | 16 | 40 | 39 | 37 | 35 | -+------------+-----+-----+-----+-----+-----+ -| BIOS Pin | 19 | 38 | 27 | 15 | 14 | -+------------+-----+-----+-----+-----+-----+ -| Direction | IN | OUT | OUT | OUT | OUT | -+------------+-----+-----+-----+-----+-----+ -| Active | H | H | H | H | H | -+------------+-----+-----+-----+-----+-----+ - -For example, a counter value of 0xc (hex) is represented in 0b1100 (binary) -on the GPIO output pins. - -Requirements -************ - -The application requires an UP Squared board connected to the PC through USB -for serial console. The BIOS settings must be updated as specified in the -source code comments for HAT Configurations (see table above). - - -References -********** - -- :ref:`up_squared` board documentation - - -Building and Running -******************** - -Build the sample in the following way: - -.. zephyr-app-commands:: - :zephyr-app: samples/boards/up_squared/gpio_counter - :board: up_squared - :goals: build - -Prepare the boot device (USB storage drive) as described for the :ref:`UP Squared ` -board. Insert the USB boot device containing the prepared software binary of the sample. - -Connect the board to a host computer and open a serial connection for serial -console interface:: - - $ minicom -D -b 115200 - -Replace :code:`` with the port where the UP Squared board -can be found. For example, under Linux, :code:`/dev/ttyUSB0`. -The ``-b`` option sets baud rate. - -Power On the board. The board will boot then enter GRUB boot loader unless BIOS -option is selected. Enter the BIOS configuration menu, modify the required HAT -configurations (above) and then select to save the BIOS settings and reset. - -The board will reboot and then enter GRUB boot loader. Select to boot Zephyr and -the board will start to execute the sample. Apply input to trigger the increment -of the value of the counter. - -There are several ways to observe the sample behavior in addition to serial -console display of the counter value. For example, the input signal can be -implemented with an analog button on a breakout breadboard, or with a basic pulse -provided by a GPIO output (active High) pin of another GPIO device (eg Arduino -Uno). The Up Squared GPIO output signals can each be connected to a simple LED -circuit on a breakout breadboard to illuminate the 4-bit counter value, as -shown in the example below:: - - o----> to Up Squared - | GPIO Output Pin - _|_ - \ / - --- - | - R1 - | - +---> GND diff --git a/samples/boards/up_squared/gpio_counter/prj.conf b/samples/boards/up_squared/gpio_counter/prj.conf deleted file mode 100644 index 91c3c15b37d..00000000000 --- a/samples/boards/up_squared/gpio_counter/prj.conf +++ /dev/null @@ -1 +0,0 @@ -CONFIG_GPIO=y diff --git a/samples/boards/up_squared/gpio_counter/sample.yaml b/samples/boards/up_squared/gpio_counter/sample.yaml deleted file mode 100644 index 199f5dcb207..00000000000 --- a/samples/boards/up_squared/gpio_counter/sample.yaml +++ /dev/null @@ -1,9 +0,0 @@ -sample: - description: Example of using GPIOs on UP Squared board - name: Example of using GPIOs on UP Squared board -tests: - sample.board.up_squared.gpio_counter: - platform_allow: up_squared - tags: gpio - integration_platforms: - - up_squared diff --git a/samples/boards/up_squared/gpio_counter/src/main.c b/samples/boards/up_squared/gpio_counter/src/main.c deleted file mode 100644 index 107190f724f..00000000000 --- a/samples/boards/up_squared/gpio_counter/src/main.c +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (c) 2018 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include - -#include -#include -#include - -#include -#include - -/** - * @file - * - * @brief Example of using GPIOs on UP Squared board - * - * This example outputs the value of a counter via 4 GPIO lines - * as a 4-bit value (bin 0, 1, 2, 3 -> HAT Pin 35, 37, 38, 40). - * The counter increments for each change from 0 to 1 on HAT Pin 16. - * - * Note: - * Need to change the BIOS settings: - * () Advanced -> HAT Configurations: - * - HD-Audio / I2S6 Selec -> Disabled - * - GPIO / PWM3 Selection -> GPIO - * - GPIO / I2S2 Selection -> GPIO - * - * - GPIO 19 (Pin16) Confi -> Input - * - * - GPIO 14 (Pin35) Confi -> Output - * - GPIO 15 (Pin37) Confi -> Output - * - GPIO 27 (Pin38) Confi -> Output - * - GPIO 28 (Pin40) Confi -> Output - */ - -struct _pin { - uint32_t hat_num; - uint32_t pin; - const struct device *gpio_dev; -}; - -struct _pin counter_pins[] = { - { - .hat_num = 35, - .pin = UP2_HAT_PIN_35, - .gpio_dev = DEVICE_DT_GET(UP2_HAT_PIN_35_DEV), - }, - { - .hat_num = 37, - .pin = UP2_HAT_PIN_37, - .gpio_dev = DEVICE_DT_GET(UP2_HAT_PIN_37_DEV), - }, - { - .hat_num = 38, - .pin = UP2_HAT_PIN_38, - .gpio_dev = DEVICE_DT_GET(UP2_HAT_PIN_38_DEV), - }, - { - .hat_num = 40, - .pin = UP2_HAT_PIN_40, - .gpio_dev = DEVICE_DT_GET(UP2_HAT_PIN_40_DEV), - }, -}; - -struct _pin intr_pin = { - .hat_num = 16, - .pin = UP2_HAT_PIN_16, - .gpio_dev = DEVICE_DT_GET(UP2_HAT_PIN_16_DEV), -}; - -static struct gpio_callback gpio_cb; - -static volatile uint32_t counter; - -K_SEM_DEFINE(counter_sem, 0, 1); - -#define NUM_PINS ARRAY_SIZE(counter_pins) -#define MASK (BIT(NUM_PINS) - 1) - -void button_cb(const struct device *gpiodev, struct gpio_callback *cb, - uint32_t pin) -{ - counter++; - k_sem_give(&counter_sem); -} - -int get_gpio_dev(struct _pin *pin) -{ - if (!device_is_ready(pin->gpio_dev)) { - printk("ERROR: GPIO device is not ready for %s\n", pin->gpio_dev->name); - return -1; - } - - return 0; -} - -int main(void) -{ - uint32_t val; - int i, ret; - - for (i = 0; i < NUM_PINS; i++) { - if (get_gpio_dev(&counter_pins[i]) != 0) { - return 0; - } - } - - if (get_gpio_dev(&intr_pin) != 0) { - return 0; - } - - /* Set pins to output */ - for (i = 0; i < NUM_PINS; i++) { - ret = gpio_pin_configure(counter_pins[i].gpio_dev, - counter_pins[i].pin, - GPIO_OUTPUT_LOW); - if (ret) { - printk("ERROR: cannot set HAT pin %d to OUT (%d)\n", - counter_pins[i].hat_num, ret); - return 0; - } - } - - /* Setup input pin */ - ret = gpio_pin_configure(intr_pin.gpio_dev, intr_pin.pin, - GPIO_INPUT); - if (ret) { - printk("ERROR: cannot set HAT pin %d to IN (%d)\n", - intr_pin.hat_num, ret); - return 0; - } - - - /* Callback uses pin_mask, so need bit shifting */ - gpio_init_callback(&gpio_cb, button_cb, (1 << intr_pin.pin)); - gpio_add_callback(intr_pin.gpio_dev, &gpio_cb); - - /* Setup input pin for interrupt */ - ret = gpio_pin_interrupt_configure(intr_pin.gpio_dev, intr_pin.pin, - GPIO_INT_EDGE_RISING); - if (ret) { - printk("ERROR: cannot config interrupt on HAT pin %d (%d)\n", - intr_pin.hat_num, ret); - return 0; - } - - /* main loop */ - val = 0U; - while (1) { - printk("counter: 0x%x\n", val); - - for (i = 0; i < NUM_PINS; i++) { - ret = gpio_pin_set(counter_pins[i].gpio_dev, - counter_pins[i].pin, - (val & BIT(i))); - if (ret) { - printk("ERROR: cannot set HAT pin %d value (%d)\n", - counter_pins[i].hat_num, ret); - return 0; - } - } - - k_sem_take(&counter_sem, K_FOREVER); - val = counter & MASK; - } - return 0; -} diff --git a/samples/drivers/adc/README.rst b/samples/drivers/adc/README.rst deleted file mode 100644 index b91867e2ff0..00000000000 --- a/samples/drivers/adc/README.rst +++ /dev/null @@ -1,62 +0,0 @@ -.. zephyr:code-sample:: adc - :name: Analog-to-Digital Converter (ADC) - :relevant-api: adc_interface - - Read analog inputs from ADC channels. - -Overview -******** - -This sample demonstrates how to use the :ref:`ADC driver API `. - -Depending on the target board, it reads ADC samples from one or more channels -and prints the readings on the console. If voltage of the used reference can -be obtained, the raw readings are converted to millivolts. - -The pins of the ADC channels are board-specific. Please refer to the board -or MCU datasheet for further details. - -Building and Running -******************** - -The ADC peripheral and pinmux is configured in the board's ``.dts`` file. Make -sure that the ADC is enabled (``status = "okay";``). - -In addition to that, this sample requires an ADC channel specified in the -``io-channels`` property of the ``zephyr,user`` node. This is usually done with -a devicetree overlay. The example overlay in the ``boards`` subdirectory for -the ``nucleo_l073rz`` board can be easily adjusted for other boards. - -Configuration of channels (settings like gain, reference, or acquisition time) -also needs to be specified in devicetree, in ADC controller child nodes. Also -the ADC resolution and oversampling setting (if used) need to be specified -there. See :zephyr_file:`boards/nrf52840dk_nrf52840.overlay -` for an example of -such setup. - -Building and Running for ST Nucleo L073RZ -========================================= - -The sample can be built and executed for the -:ref:`nucleo_l073rz_board` as follows: - -.. zephyr-app-commands:: - :zephyr-app: samples/drivers/adc - :board: nucleo_l073rz - :goals: build flash - :compact: - -To build for another board, change "nucleo_l073rz" above to that board's name -and provide a corresponding devicetree overlay. - -Sample output -============= - -You should get a similar output as below, repeated every second: - -.. code-block:: console - - ADC reading: - - ADC_0, channel 7: 36 = 65mV - -.. note:: If the ADC is not supported, the output will be an error message. diff --git a/samples/drivers/adc/CMakeLists.txt b/samples/drivers/adc/adc_dt/CMakeLists.txt similarity index 100% rename from samples/drivers/adc/CMakeLists.txt rename to samples/drivers/adc/adc_dt/CMakeLists.txt diff --git a/samples/drivers/adc/adc_dt/README.rst b/samples/drivers/adc/adc_dt/README.rst new file mode 100644 index 00000000000..af185f5caa0 --- /dev/null +++ b/samples/drivers/adc/adc_dt/README.rst @@ -0,0 +1,62 @@ +.. zephyr:code-sample:: adc_dt + :name: Analog-to-Digital Converter (ADC) with devicetree + :relevant-api: adc_interface + + Read analog inputs from ADC channels. + +Overview +******** + +This sample demonstrates how to use the :ref:`ADC driver API `. + +Depending on the target board, it reads ADC samples from one or more channels +and prints the readings on the console. If voltage of the used reference can +be obtained, the raw readings are converted to millivolts. + +The pins of the ADC channels are board-specific. Please refer to the board +or MCU datasheet for further details. + +Building and Running +******************** + +The ADC peripheral and pinmux is configured in the board's ``.dts`` file. Make +sure that the ADC is enabled (``status = "okay";``). + +In addition to that, this sample requires an ADC channel specified in the +``io-channels`` property of the ``zephyr,user`` node. This is usually done with +a devicetree overlay. The example overlay in the ``boards`` subdirectory for +the ``nucleo_l073rz`` board can be easily adjusted for other boards. + +Configuration of channels (settings like gain, reference, or acquisition time) +also needs to be specified in devicetree, in ADC controller child nodes. Also +the ADC resolution and oversampling setting (if used) need to be specified +there. See :zephyr_file:`boards/nrf52840dk_nrf52840.overlay +` for an example of +such setup. + +Building and Running for ST Nucleo L073RZ +========================================= + +The sample can be built and executed for the +:ref:`nucleo_l073rz_board` as follows: + +.. zephyr-app-commands:: + :zephyr-app: samples/drivers/adc/adc_dt + :board: nucleo_l073rz + :goals: build flash + :compact: + +To build for another board, change "nucleo_l073rz" above to that board's name +and provide a corresponding devicetree overlay. + +Sample output +============= + +You should get a similar output as below, repeated every second: + +.. code-block:: console + + ADC reading: + - ADC_0, channel 7: 36 = 65mV + +.. note:: If the ADC is not supported, the output will be an error message. diff --git a/samples/drivers/adc/boards/cc1352r1_launchxl.overlay b/samples/drivers/adc/adc_dt/boards/cc1352r1_launchxl.overlay similarity index 100% rename from samples/drivers/adc/boards/cc1352r1_launchxl.overlay rename to samples/drivers/adc/adc_dt/boards/cc1352r1_launchxl.overlay diff --git a/samples/drivers/adc/boards/cc1352r_sensortag.overlay b/samples/drivers/adc/adc_dt/boards/cc1352r_sensortag.overlay similarity index 100% rename from samples/drivers/adc/boards/cc1352r_sensortag.overlay rename to samples/drivers/adc/adc_dt/boards/cc1352r_sensortag.overlay diff --git a/samples/drivers/adc/boards/cc26x2r1_launchxl.overlay b/samples/drivers/adc/adc_dt/boards/cc26x2r1_launchxl.overlay similarity index 100% rename from samples/drivers/adc/boards/cc26x2r1_launchxl.overlay rename to samples/drivers/adc/adc_dt/boards/cc26x2r1_launchxl.overlay diff --git a/samples/drivers/adc/boards/cc3220sf_launchxl.overlay b/samples/drivers/adc/adc_dt/boards/cc3220sf_launchxl.overlay similarity index 100% rename from samples/drivers/adc/boards/cc3220sf_launchxl.overlay rename to samples/drivers/adc/adc_dt/boards/cc3220sf_launchxl.overlay diff --git a/samples/drivers/adc/boards/cc3235sf_launchxl.overlay b/samples/drivers/adc/adc_dt/boards/cc3235sf_launchxl.overlay similarity index 100% rename from samples/drivers/adc/boards/cc3235sf_launchxl.overlay rename to samples/drivers/adc/adc_dt/boards/cc3235sf_launchxl.overlay diff --git a/samples/drivers/adc/boards/cy8cproto_062_4343w.overlay b/samples/drivers/adc/adc_dt/boards/cy8cproto_062_4343w.overlay similarity index 100% rename from samples/drivers/adc/boards/cy8cproto_062_4343w.overlay rename to samples/drivers/adc/adc_dt/boards/cy8cproto_062_4343w.overlay diff --git a/samples/drivers/adc/boards/cy8cproto_063_ble.overlay b/samples/drivers/adc/adc_dt/boards/cy8cproto_063_ble.overlay similarity index 100% rename from samples/drivers/adc/boards/cy8cproto_063_ble.overlay rename to samples/drivers/adc/adc_dt/boards/cy8cproto_063_ble.overlay diff --git a/samples/drivers/adc/boards/da1469x_dk_pro.overlay b/samples/drivers/adc/adc_dt/boards/da1469x_dk_pro.overlay similarity index 100% rename from samples/drivers/adc/boards/da1469x_dk_pro.overlay rename to samples/drivers/adc/adc_dt/boards/da1469x_dk_pro.overlay diff --git a/samples/drivers/adc/boards/disco_l475_iot1.overlay b/samples/drivers/adc/adc_dt/boards/disco_l475_iot1.overlay similarity index 100% rename from samples/drivers/adc/boards/disco_l475_iot1.overlay rename to samples/drivers/adc/adc_dt/boards/disco_l475_iot1.overlay diff --git a/samples/drivers/adc/boards/efm32pg_stk3402a.overlay b/samples/drivers/adc/adc_dt/boards/efm32pg_stk3402a.overlay similarity index 100% rename from samples/drivers/adc/boards/efm32pg_stk3402a.overlay rename to samples/drivers/adc/adc_dt/boards/efm32pg_stk3402a.overlay diff --git a/samples/drivers/adc/boards/esp32_devkitc_wroom_procpu.overlay b/samples/drivers/adc/adc_dt/boards/esp32_devkitc_wroom_procpu.overlay similarity index 100% rename from samples/drivers/adc/boards/esp32_devkitc_wroom_procpu.overlay rename to samples/drivers/adc/adc_dt/boards/esp32_devkitc_wroom_procpu.overlay diff --git a/samples/drivers/adc/boards/esp32_devkitc_wrover_procpu.overlay b/samples/drivers/adc/adc_dt/boards/esp32_devkitc_wrover_procpu.overlay similarity index 100% rename from samples/drivers/adc/boards/esp32_devkitc_wrover_procpu.overlay rename to samples/drivers/adc/adc_dt/boards/esp32_devkitc_wrover_procpu.overlay diff --git a/samples/drivers/adc/boards/esp32c3_devkitm.overlay b/samples/drivers/adc/adc_dt/boards/esp32c3_devkitm.overlay similarity index 100% rename from samples/drivers/adc/boards/esp32c3_devkitm.overlay rename to samples/drivers/adc/adc_dt/boards/esp32c3_devkitm.overlay diff --git a/samples/drivers/adc/boards/esp32c3_luatos_core.overlay b/samples/drivers/adc/adc_dt/boards/esp32c3_luatos_core.overlay similarity index 100% rename from samples/drivers/adc/boards/esp32c3_luatos_core.overlay rename to samples/drivers/adc/adc_dt/boards/esp32c3_luatos_core.overlay diff --git a/samples/drivers/adc/boards/esp32c3_luatos_core_esp32c3_usb.overlay b/samples/drivers/adc/adc_dt/boards/esp32c3_luatos_core_esp32c3_usb.overlay similarity index 100% rename from samples/drivers/adc/boards/esp32c3_luatos_core_esp32c3_usb.overlay rename to samples/drivers/adc/adc_dt/boards/esp32c3_luatos_core_esp32c3_usb.overlay diff --git a/samples/drivers/adc/boards/esp32s2_saola.overlay b/samples/drivers/adc/adc_dt/boards/esp32s2_saola.overlay similarity index 100% rename from samples/drivers/adc/boards/esp32s2_saola.overlay rename to samples/drivers/adc/adc_dt/boards/esp32s2_saola.overlay diff --git a/samples/drivers/adc/boards/esp32s3_devkitm.overlay b/samples/drivers/adc/adc_dt/boards/esp32s3_devkitm_procpu.overlay similarity index 100% rename from samples/drivers/adc/boards/esp32s3_devkitm.overlay rename to samples/drivers/adc/adc_dt/boards/esp32s3_devkitm_procpu.overlay diff --git a/samples/drivers/adc/boards/esp32s3_luatos_core.overlay b/samples/drivers/adc/adc_dt/boards/esp32s3_luatos_core_procpu.overlay similarity index 100% rename from samples/drivers/adc/boards/esp32s3_luatos_core.overlay rename to samples/drivers/adc/adc_dt/boards/esp32s3_luatos_core_procpu.overlay diff --git a/samples/drivers/adc/boards/esp32s3_luatos_core_esp32s3_procpu_usb.overlay b/samples/drivers/adc/adc_dt/boards/esp32s3_luatos_core_procpu_usb.overlay similarity index 100% rename from samples/drivers/adc/boards/esp32s3_luatos_core_esp32s3_procpu_usb.overlay rename to samples/drivers/adc/adc_dt/boards/esp32s3_luatos_core_procpu_usb.overlay diff --git a/samples/drivers/adc/adc_dt/boards/esp32s3_touch_lcd_1_28.overlay b/samples/drivers/adc/adc_dt/boards/esp32s3_touch_lcd_1_28.overlay new file mode 100644 index 00000000000..de057062019 --- /dev/null +++ b/samples/drivers/adc/adc_dt/boards/esp32s3_touch_lcd_1_28.overlay @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2024 Joel Guittet + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + zephyr,user { + io-channels = <&adc0 0>; + }; +}; + +&adc0 { + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + channel@0 { + reg = <0>; + zephyr,gain = "ADC_GAIN_1_4"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; +}; diff --git a/samples/drivers/adc/boards/ev11l78a.overlay b/samples/drivers/adc/adc_dt/boards/ev11l78a.overlay similarity index 100% rename from samples/drivers/adc/boards/ev11l78a.overlay rename to samples/drivers/adc/adc_dt/boards/ev11l78a.overlay diff --git a/samples/drivers/adc/boards/frdm_k64f.overlay b/samples/drivers/adc/adc_dt/boards/frdm_k64f.overlay similarity index 100% rename from samples/drivers/adc/boards/frdm_k64f.overlay rename to samples/drivers/adc/adc_dt/boards/frdm_k64f.overlay diff --git a/samples/drivers/adc/adc_dt/boards/frdm_mcxn947_mcxn947_cpu0.overlay b/samples/drivers/adc/adc_dt/boards/frdm_mcxn947_mcxn947_cpu0.overlay new file mode 100644 index 00000000000..051e3c1a3a4 --- /dev/null +++ b/samples/drivers/adc/adc_dt/boards/frdm_mcxn947_mcxn947_cpu0.overlay @@ -0,0 +1,50 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + zephyr,user { + /* adjust channel number according to pinmux in board.dts */ + io-channels = <&lpadc0 0>, <&lpadc0 1>; + }; +}; + +&lpadc0 { + #address-cells = <1>; + #size-cells = <0>; + + /* + * To use this sample: + * LPADC0 CH1A and CH1B are set up in differential mode (B-A) + * - Connect LPADC0 CH1A signal to voltage between 0~1.8V (J8 pin 20) + * - Connect LPADC0 CH1B signal to voltage between 0~1.8V (J8 pin 24) + * LPADC0 CH2A is set up in single ended mode + * - Connect LPADC0 CH2A signal to voltage between 0~1.8V (J8 pin 28) + */ + + channel@0 { + reg = <0>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_EXTERNAL1"; + zephyr,vref-mv = <1800>; + zephyr,acquisition-time = ; + zephyr,resolution = <13>; + zephyr,input-positive = ; + zephyr,input-negative = ; + }; + + channel@1 { + reg = <1>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_EXTERNAL1"; + zephyr,vref-mv = <1800>; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + zephyr,input-positive = ; + }; +}; diff --git a/samples/drivers/adc/boards/gd32a503v_eval.overlay b/samples/drivers/adc/adc_dt/boards/gd32a503v_eval.overlay similarity index 100% rename from samples/drivers/adc/boards/gd32a503v_eval.overlay rename to samples/drivers/adc/adc_dt/boards/gd32a503v_eval.overlay diff --git a/samples/drivers/adc/boards/gd32f350r_eval.overlay b/samples/drivers/adc/adc_dt/boards/gd32f350r_eval.overlay similarity index 100% rename from samples/drivers/adc/boards/gd32f350r_eval.overlay rename to samples/drivers/adc/adc_dt/boards/gd32f350r_eval.overlay diff --git a/samples/drivers/adc/boards/gd32f403z_eval.overlay b/samples/drivers/adc/adc_dt/boards/gd32f403z_eval.overlay similarity index 100% rename from samples/drivers/adc/boards/gd32f403z_eval.overlay rename to samples/drivers/adc/adc_dt/boards/gd32f403z_eval.overlay diff --git a/samples/drivers/adc/boards/gd32f450i_eval.overlay b/samples/drivers/adc/adc_dt/boards/gd32f450i_eval.overlay similarity index 100% rename from samples/drivers/adc/boards/gd32f450i_eval.overlay rename to samples/drivers/adc/adc_dt/boards/gd32f450i_eval.overlay diff --git a/samples/drivers/adc/boards/gd32l233r_eval.overlay b/samples/drivers/adc/adc_dt/boards/gd32l233r_eval.overlay similarity index 100% rename from samples/drivers/adc/boards/gd32l233r_eval.overlay rename to samples/drivers/adc/adc_dt/boards/gd32l233r_eval.overlay diff --git a/samples/drivers/adc/boards/gd32vf103v_eval.overlay b/samples/drivers/adc/adc_dt/boards/gd32vf103v_eval.overlay similarity index 100% rename from samples/drivers/adc/boards/gd32vf103v_eval.overlay rename to samples/drivers/adc/adc_dt/boards/gd32vf103v_eval.overlay diff --git a/samples/drivers/adc/boards/longan_nano.overlay b/samples/drivers/adc/adc_dt/boards/longan_nano.overlay similarity index 100% rename from samples/drivers/adc/boards/longan_nano.overlay rename to samples/drivers/adc/adc_dt/boards/longan_nano.overlay diff --git a/samples/drivers/adc/boards/longan_nano_gd32vf103_lite.overlay b/samples/drivers/adc/adc_dt/boards/longan_nano_gd32vf103_lite.overlay similarity index 100% rename from samples/drivers/adc/boards/longan_nano_gd32vf103_lite.overlay rename to samples/drivers/adc/adc_dt/boards/longan_nano_gd32vf103_lite.overlay diff --git a/samples/drivers/adc/boards/lpcxpresso55s36.overlay b/samples/drivers/adc/adc_dt/boards/lpcxpresso55s36.overlay similarity index 87% rename from samples/drivers/adc/boards/lpcxpresso55s36.overlay rename to samples/drivers/adc/adc_dt/boards/lpcxpresso55s36.overlay index 6d38272b5ce..692ced7b7e5 100644 --- a/samples/drivers/adc/boards/lpcxpresso55s36.overlay +++ b/samples/drivers/adc/adc_dt/boards/lpcxpresso55s36.overlay @@ -1,7 +1,7 @@ /* * SPDX-License-Identifier: Apache-2.0 * - * Copyright 2023 NXP + * Copyright 2023-2024 NXP */ #include @@ -26,7 +26,7 @@ reg = <0>; zephyr,gain = "ADC_GAIN_1"; zephyr,reference = "ADC_REF_EXTERNAL0"; - zephyr,acquisition-time = ; + zephyr,acquisition-time = ; zephyr,vref-mv = <3300>; zephyr,resolution = <12>; zephyr,input-positive = ; diff --git a/samples/drivers/adc/adc_dt/boards/lpcxpresso55s69_lpc55s69_cpu0.overlay b/samples/drivers/adc/adc_dt/boards/lpcxpresso55s69_lpc55s69_cpu0.overlay new file mode 100644 index 00000000000..f6c0d74b2d6 --- /dev/null +++ b/samples/drivers/adc/adc_dt/boards/lpcxpresso55s69_lpc55s69_cpu0.overlay @@ -0,0 +1,75 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2022-2024 NXP + */ + +#include + +/ { + zephyr,user { + io-channels = <&adc0 0 &adc0 1 &adc0 2>; + }; +}; + +&adc0 { + #address-cells = <1>; + #size-cells = <0>; + + /* + * To use this sample: + * - Connect VREFN_TARGET to GND, and VREFP_TARGET to 3v3 + * (Resistors J8 and J9, should be populated by default) + * LPADC0 CH0A and CH0B are set up in differential mode + * - Connect LPADC0 CH0A signal to voltage between 0~3.3V (P19 pin 4) + * - Connect LPADC0 CH0B signal to voltage between 0~3.3V (P19 pin 2) + * LPADC0 CH4A is set up in single ended mode + * - Connect LPADC0 CH4A signal to voltage between 0~3.3V (P17 pin 19) + * LPADC0 CH4B is set up in single ended mode + * - Connect LPADC0 CH4B signal to voltage between 0~3.3V (P18 pin 1) + */ + + /* + * Channel 0 is used for differential mode, with 13 bit resolution + * CH0A (plus side) is routed to P19 pin 4 + * CH0B (minus side) is routed to P19 pin 2 + */ + channel@0 { + reg = <0>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_EXTERNAL0"; + zephyr,vref-mv = <3300>; + zephyr,acquisition-time = ; + zephyr,resolution = <13>; + zephyr,input-positive = ; + zephyr,input-negative = ; + }; + + /* + * Channel 1 is used in single ended mode, with 16 bit resolution + * CH4A is routed to P17 pin 19 + */ + channel@1 { + reg = <1>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_EXTERNAL0"; + zephyr,vref-mv = <3300>; + zephyr,acquisition-time = ; + zephyr,resolution = <16>; + zephyr,input-positive = ; + }; + + /* + * Channel 2 is used in single ended mode, with 12 bit resolution + * CH4B is routed to P18 pin 1 + */ + channel@2 { + reg = <2>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_EXTERNAL0"; + zephyr,vref-mv = <3300>; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + zephyr,input-positive = ; + }; +}; diff --git a/samples/drivers/adc/boards/mec15xxevb_assy6853.overlay b/samples/drivers/adc/adc_dt/boards/mec15xxevb_assy6853.overlay similarity index 100% rename from samples/drivers/adc/boards/mec15xxevb_assy6853.overlay rename to samples/drivers/adc/adc_dt/boards/mec15xxevb_assy6853.overlay diff --git a/samples/drivers/adc/boards/mec172xevb_assy6906.overlay b/samples/drivers/adc/adc_dt/boards/mec172xevb_assy6906.overlay similarity index 100% rename from samples/drivers/adc/boards/mec172xevb_assy6906.overlay rename to samples/drivers/adc/adc_dt/boards/mec172xevb_assy6906.overlay diff --git a/samples/drivers/adc/boards/mimxrt1010_evk.overlay b/samples/drivers/adc/adc_dt/boards/mimxrt1010_evk.overlay similarity index 100% rename from samples/drivers/adc/boards/mimxrt1010_evk.overlay rename to samples/drivers/adc/adc_dt/boards/mimxrt1010_evk.overlay diff --git a/samples/drivers/adc/boards/mimxrt1015_evk.overlay b/samples/drivers/adc/adc_dt/boards/mimxrt1015_evk.overlay similarity index 100% rename from samples/drivers/adc/boards/mimxrt1015_evk.overlay rename to samples/drivers/adc/adc_dt/boards/mimxrt1015_evk.overlay diff --git a/samples/drivers/adc/boards/mimxrt1020_evk.overlay b/samples/drivers/adc/adc_dt/boards/mimxrt1020_evk.overlay similarity index 100% rename from samples/drivers/adc/boards/mimxrt1020_evk.overlay rename to samples/drivers/adc/adc_dt/boards/mimxrt1020_evk.overlay diff --git a/samples/drivers/adc/boards/mimxrt1024_evk.overlay b/samples/drivers/adc/adc_dt/boards/mimxrt1024_evk.overlay similarity index 100% rename from samples/drivers/adc/boards/mimxrt1024_evk.overlay rename to samples/drivers/adc/adc_dt/boards/mimxrt1024_evk.overlay diff --git a/samples/drivers/adc/boards/mimxrt1040_evk.overlay b/samples/drivers/adc/adc_dt/boards/mimxrt1040_evk.overlay similarity index 100% rename from samples/drivers/adc/boards/mimxrt1040_evk.overlay rename to samples/drivers/adc/adc_dt/boards/mimxrt1040_evk.overlay diff --git a/samples/drivers/adc/boards/mimxrt1050_evk.overlay b/samples/drivers/adc/adc_dt/boards/mimxrt1050_evk.overlay similarity index 100% rename from samples/drivers/adc/boards/mimxrt1050_evk.overlay rename to samples/drivers/adc/adc_dt/boards/mimxrt1050_evk.overlay diff --git a/samples/drivers/adc/boards/mimxrt1060_evk.overlay b/samples/drivers/adc/adc_dt/boards/mimxrt1060_evk.overlay similarity index 100% rename from samples/drivers/adc/boards/mimxrt1060_evk.overlay rename to samples/drivers/adc/adc_dt/boards/mimxrt1060_evk.overlay diff --git a/samples/drivers/adc/boards/mimxrt1064_evk.overlay b/samples/drivers/adc/adc_dt/boards/mimxrt1064_evk.overlay similarity index 100% rename from samples/drivers/adc/boards/mimxrt1064_evk.overlay rename to samples/drivers/adc/adc_dt/boards/mimxrt1064_evk.overlay diff --git a/samples/drivers/adc/adc_dt/boards/mimxrt1160_evk_mimxrt1166_cm7.overlay b/samples/drivers/adc/adc_dt/boards/mimxrt1160_evk_mimxrt1166_cm7.overlay new file mode 100644 index 00000000000..d257f272f60 --- /dev/null +++ b/samples/drivers/adc/adc_dt/boards/mimxrt1160_evk_mimxrt1166_cm7.overlay @@ -0,0 +1,34 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2021,2023-2024 NXP + */ + +#include + +/ { + zephyr,user { + /* adjust channel number according to pinmux in board.dts */ + io-channels = <&lpadc0 0>; + }; +}; + +&lpadc0 { + #address-cells = <1>; + #size-cells = <0>; + + /* + * To use this sample: + * - Connect LPADC0 CH0 signal to voltage between 0~1.8V (J9 pin 10) + */ + + channel@0 { + reg = <0>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_EXTERNAL0"; + zephyr,vref-mv = <1800>; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + zephyr,input-positive = ; + }; +}; diff --git a/samples/drivers/adc/boards/mimxrt1170_evk_mimxrt1176_cm7_A.overlay b/samples/drivers/adc/adc_dt/boards/mimxrt1170_evk_mimxrt1176_cm7_A.overlay similarity index 86% rename from samples/drivers/adc/boards/mimxrt1170_evk_mimxrt1176_cm7_A.overlay rename to samples/drivers/adc/adc_dt/boards/mimxrt1170_evk_mimxrt1176_cm7_A.overlay index 9164f2f945e..b07fe80528b 100644 --- a/samples/drivers/adc/boards/mimxrt1170_evk_mimxrt1176_cm7_A.overlay +++ b/samples/drivers/adc/adc_dt/boards/mimxrt1170_evk_mimxrt1176_cm7_A.overlay @@ -2,7 +2,7 @@ * SPDX-License-Identifier: Apache-2.0 * * Copyright (c) 2020 Linaro Limited - * Copyright 2023 NXP + * Copyright 2023-2024 NXP */ #include @@ -28,7 +28,7 @@ zephyr,gain = "ADC_GAIN_1"; zephyr,reference = "ADC_REF_EXTERNAL0"; zephyr,vref-mv = <1800>; - zephyr,acquisition-time = ; + zephyr,acquisition-time = ; zephyr,resolution = <12>; zephyr,input-positive = ; }; diff --git a/samples/drivers/adc/adc_dt/boards/mimxrt1170_evk_mimxrt1176_cm7_B.overlay b/samples/drivers/adc/adc_dt/boards/mimxrt1170_evk_mimxrt1176_cm7_B.overlay new file mode 100644 index 00000000000..598639cc0e6 --- /dev/null +++ b/samples/drivers/adc/adc_dt/boards/mimxrt1170_evk_mimxrt1176_cm7_B.overlay @@ -0,0 +1,34 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2023-2024 NXP + */ + +#include + +/ { + zephyr,user { + /* adjust channel number according to pinmux in board.dts */ + io-channels = <&lpadc0 0>; + }; +}; + +&lpadc0 { + #address-cells = <1>; + #size-cells = <0>; + + /* + * To use this sample: + * - Connect LPADC0 CH0 signal to voltage between 0~1.8V (J9 pin 10) + */ + + channel@0 { + reg = <0>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_EXTERNAL0"; + zephyr,vref-mv = <1800>; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + zephyr,input-positive = ; + }; +}; diff --git a/samples/drivers/adc/boards/mimxrt595_evk_mimxrt595s_cm33.overlay b/samples/drivers/adc/adc_dt/boards/mimxrt595_evk_mimxrt595s_cm33.overlay similarity index 87% rename from samples/drivers/adc/boards/mimxrt595_evk_mimxrt595s_cm33.overlay rename to samples/drivers/adc/adc_dt/boards/mimxrt595_evk_mimxrt595s_cm33.overlay index 85124266908..4e85310bf63 100644 --- a/samples/drivers/adc/boards/mimxrt595_evk_mimxrt595s_cm33.overlay +++ b/samples/drivers/adc/adc_dt/boards/mimxrt595_evk_mimxrt595s_cm33.overlay @@ -2,7 +2,7 @@ * SPDX-License-Identifier: Apache-2.0 * * Copyright (c) 2020 Linaro Limited - * Copyright 2023 NXP + * Copyright 2023-2024 NXP */ #include @@ -32,7 +32,7 @@ zephyr,gain = "ADC_GAIN_1"; zephyr,reference = "ADC_REF_EXTERNAL0"; zephyr,vref-mv = <1800>; - zephyr,acquisition-time = ; + zephyr,acquisition-time = ; zephyr,resolution = <13>; zephyr,input-positive = ; zephyr,input-negative = ; @@ -43,7 +43,7 @@ zephyr,gain = "ADC_GAIN_1"; zephyr,reference = "ADC_REF_EXTERNAL0"; zephyr,vref-mv = <1800>; - zephyr,acquisition-time = ; + zephyr,acquisition-time = ; zephyr,resolution = <12>; zephyr,input-positive = ; }; diff --git a/samples/drivers/adc/boards/mimxrt685_evk_mimxrt685s_cm33.overlay b/samples/drivers/adc/adc_dt/boards/mimxrt685_evk_mimxrt685s_cm33.overlay similarity index 85% rename from samples/drivers/adc/boards/mimxrt685_evk_mimxrt685s_cm33.overlay rename to samples/drivers/adc/adc_dt/boards/mimxrt685_evk_mimxrt685s_cm33.overlay index 77aa0421544..0ad78c193d2 100644 --- a/samples/drivers/adc/boards/mimxrt685_evk_mimxrt685s_cm33.overlay +++ b/samples/drivers/adc/adc_dt/boards/mimxrt685_evk_mimxrt685s_cm33.overlay @@ -2,7 +2,7 @@ * SPDX-License-Identifier: Apache-2.0 * * Copyright (c) 2020 Linaro Limited - * Copyright 2023 NXP + * Copyright 2023-2024 NXP */ #include @@ -30,7 +30,7 @@ zephyr,gain = "ADC_GAIN_1"; zephyr,reference = "ADC_REF_EXTERNAL0"; zephyr,vref-mv = <1800>; - zephyr,acquisition-time = ; + zephyr,acquisition-time = ; zephyr,resolution = <12>; zephyr,input-positive = ; }; @@ -40,7 +40,7 @@ zephyr,gain = "ADC_GAIN_1"; zephyr,reference = "ADC_REF_EXTERNAL0"; zephyr,vref-mv = <1800>; - zephyr,acquisition-time = ; + zephyr,acquisition-time = ; zephyr,resolution = <12>; zephyr,input-positive = ; }; diff --git a/samples/drivers/adc/boards/mr_canhubk3.overlay b/samples/drivers/adc/adc_dt/boards/mr_canhubk3.overlay similarity index 100% rename from samples/drivers/adc/boards/mr_canhubk3.overlay rename to samples/drivers/adc/adc_dt/boards/mr_canhubk3.overlay diff --git a/samples/drivers/adc/boards/nrf51dk_nrf51822.overlay b/samples/drivers/adc/adc_dt/boards/nrf51dk_nrf51822.overlay similarity index 100% rename from samples/drivers/adc/boards/nrf51dk_nrf51822.overlay rename to samples/drivers/adc/adc_dt/boards/nrf51dk_nrf51822.overlay diff --git a/samples/drivers/adc/boards/nrf52840dk_nrf52840.overlay b/samples/drivers/adc/adc_dt/boards/nrf52840dk_nrf52840.overlay similarity index 100% rename from samples/drivers/adc/boards/nrf52840dk_nrf52840.overlay rename to samples/drivers/adc/adc_dt/boards/nrf52840dk_nrf52840.overlay diff --git a/samples/drivers/adc/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay b/samples/drivers/adc/adc_dt/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay similarity index 100% rename from samples/drivers/adc/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay rename to samples/drivers/adc/adc_dt/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay diff --git a/samples/drivers/adc/boards/nucleo_c031c6.overlay b/samples/drivers/adc/adc_dt/boards/nucleo_c031c6.overlay similarity index 100% rename from samples/drivers/adc/boards/nucleo_c031c6.overlay rename to samples/drivers/adc/adc_dt/boards/nucleo_c031c6.overlay diff --git a/samples/drivers/adc/boards/nucleo_h7a3zi_q.overlay b/samples/drivers/adc/adc_dt/boards/nucleo_h7a3zi_q.overlay similarity index 100% rename from samples/drivers/adc/boards/nucleo_h7a3zi_q.overlay rename to samples/drivers/adc/adc_dt/boards/nucleo_h7a3zi_q.overlay diff --git a/samples/drivers/adc/boards/nucleo_l073rz.overlay b/samples/drivers/adc/adc_dt/boards/nucleo_l073rz.overlay similarity index 100% rename from samples/drivers/adc/boards/nucleo_l073rz.overlay rename to samples/drivers/adc/adc_dt/boards/nucleo_l073rz.overlay diff --git a/samples/drivers/adc/boards/nucleo_l552ze_q.overlay b/samples/drivers/adc/adc_dt/boards/nucleo_l552ze_q.overlay similarity index 100% rename from samples/drivers/adc/boards/nucleo_l552ze_q.overlay rename to samples/drivers/adc/adc_dt/boards/nucleo_l552ze_q.overlay diff --git a/samples/drivers/adc/boards/nucleo_u575zi_q.overlay b/samples/drivers/adc/adc_dt/boards/nucleo_u575zi_q.overlay similarity index 100% rename from samples/drivers/adc/boards/nucleo_u575zi_q.overlay rename to samples/drivers/adc/adc_dt/boards/nucleo_u575zi_q.overlay diff --git a/samples/drivers/adc/boards/nucleo_wba52cg.overlay b/samples/drivers/adc/adc_dt/boards/nucleo_wba52cg.overlay similarity index 100% rename from samples/drivers/adc/boards/nucleo_wba52cg.overlay rename to samples/drivers/adc/adc_dt/boards/nucleo_wba52cg.overlay diff --git a/samples/drivers/adc/boards/nucleo_wl55jc.overlay b/samples/drivers/adc/adc_dt/boards/nucleo_wl55jc.overlay similarity index 100% rename from samples/drivers/adc/boards/nucleo_wl55jc.overlay rename to samples/drivers/adc/adc_dt/boards/nucleo_wl55jc.overlay diff --git a/samples/drivers/adc/adc_dt/boards/rd_rw612_bga.overlay b/samples/drivers/adc/adc_dt/boards/rd_rw612_bga.overlay new file mode 100644 index 00000000000..32098b10883 --- /dev/null +++ b/samples/drivers/adc/adc_dt/boards/rd_rw612_bga.overlay @@ -0,0 +1,38 @@ +/* + * Copyright 2022 NXP + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + zephyr,user { + /* adjust channel number according to pinmux in board.dts */ + io-channels = <&adc0 0 &adc0 1>; + }; +}; + +&adc0 { + #address-cells = <1>; + #size-cells = <0>; + + channel@0 { + reg = <0>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_VDD_1"; + zephyr,vref-mv = <1800>; + zephyr,acquisition-time = ; + zephyr,resolution = <16>; + zephyr,input-positive = ; + }; + + channel@1 { + reg = <1>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_VDD_1"; + zephyr,vref-mv = <1800>; + zephyr,acquisition-time = ; + zephyr,resolution = <16>; + zephyr,input-positive = ; + }; +}; diff --git a/samples/drivers/adc/boards/robokit1.overlay b/samples/drivers/adc/adc_dt/boards/robokit1.overlay similarity index 100% rename from samples/drivers/adc/boards/robokit1.overlay rename to samples/drivers/adc/adc_dt/boards/robokit1.overlay diff --git a/samples/drivers/adc/boards/rpi_pico.overlay b/samples/drivers/adc/adc_dt/boards/rpi_pico.overlay similarity index 100% rename from samples/drivers/adc/boards/rpi_pico.overlay rename to samples/drivers/adc/adc_dt/boards/rpi_pico.overlay diff --git a/samples/drivers/adc/boards/sam4e_xpro.overlay b/samples/drivers/adc/adc_dt/boards/sam4e_xpro.overlay similarity index 100% rename from samples/drivers/adc/boards/sam4e_xpro.overlay rename to samples/drivers/adc/adc_dt/boards/sam4e_xpro.overlay diff --git a/samples/drivers/adc/boards/sam4s_xplained.overlay b/samples/drivers/adc/adc_dt/boards/sam4s_xplained.overlay similarity index 100% rename from samples/drivers/adc/boards/sam4s_xplained.overlay rename to samples/drivers/adc/adc_dt/boards/sam4s_xplained.overlay diff --git a/samples/drivers/adc/boards/sam_e70_xplained_same70q21.overlay b/samples/drivers/adc/adc_dt/boards/sam_e70_xplained_same70q21.overlay similarity index 100% rename from samples/drivers/adc/boards/sam_e70_xplained_same70q21.overlay rename to samples/drivers/adc/adc_dt/boards/sam_e70_xplained_same70q21.overlay diff --git a/samples/drivers/adc/boards/sam_v71_xult_samv71q21.overlay b/samples/drivers/adc/adc_dt/boards/sam_v71_xult_samv71q21.overlay similarity index 100% rename from samples/drivers/adc/boards/sam_v71_xult_samv71q21.overlay rename to samples/drivers/adc/adc_dt/boards/sam_v71_xult_samv71q21.overlay diff --git a/samples/drivers/adc/boards/samc21n_xpro.overlay b/samples/drivers/adc/adc_dt/boards/samc21n_xpro.overlay similarity index 100% rename from samples/drivers/adc/boards/samc21n_xpro.overlay rename to samples/drivers/adc/adc_dt/boards/samc21n_xpro.overlay diff --git a/samples/drivers/adc/boards/samd21_xpro.overlay b/samples/drivers/adc/adc_dt/boards/samd21_xpro.overlay similarity index 100% rename from samples/drivers/adc/boards/samd21_xpro.overlay rename to samples/drivers/adc/adc_dt/boards/samd21_xpro.overlay diff --git a/samples/drivers/adc/boards/same54_xpro.overlay b/samples/drivers/adc/adc_dt/boards/same54_xpro.overlay similarity index 100% rename from samples/drivers/adc/boards/same54_xpro.overlay rename to samples/drivers/adc/adc_dt/boards/same54_xpro.overlay diff --git a/samples/drivers/adc/boards/saml21_xpro.overlay b/samples/drivers/adc/adc_dt/boards/saml21_xpro.overlay similarity index 100% rename from samples/drivers/adc/boards/saml21_xpro.overlay rename to samples/drivers/adc/adc_dt/boards/saml21_xpro.overlay diff --git a/samples/drivers/adc/boards/samr21_xpro.overlay b/samples/drivers/adc/adc_dt/boards/samr21_xpro.overlay similarity index 100% rename from samples/drivers/adc/boards/samr21_xpro.overlay rename to samples/drivers/adc/adc_dt/boards/samr21_xpro.overlay diff --git a/samples/drivers/adc/boards/samr34_xpro.overlay b/samples/drivers/adc/adc_dt/boards/samr34_xpro.overlay similarity index 100% rename from samples/drivers/adc/boards/samr34_xpro.overlay rename to samples/drivers/adc/adc_dt/boards/samr34_xpro.overlay diff --git a/samples/drivers/adc/boards/stm32h573i_dk.overlay b/samples/drivers/adc/adc_dt/boards/stm32h573i_dk.overlay similarity index 100% rename from samples/drivers/adc/boards/stm32h573i_dk.overlay rename to samples/drivers/adc/adc_dt/boards/stm32h573i_dk.overlay diff --git a/samples/drivers/adc/boards/stm32h735g_disco.overlay b/samples/drivers/adc/adc_dt/boards/stm32h735g_disco.overlay similarity index 100% rename from samples/drivers/adc/boards/stm32h735g_disco.overlay rename to samples/drivers/adc/adc_dt/boards/stm32h735g_disco.overlay diff --git a/samples/drivers/adc/boards/stm32l496g_disco.overlay b/samples/drivers/adc/adc_dt/boards/stm32l496g_disco.overlay similarity index 100% rename from samples/drivers/adc/boards/stm32l496g_disco.overlay rename to samples/drivers/adc/adc_dt/boards/stm32l496g_disco.overlay diff --git a/samples/drivers/adc/boards/stm32l562e_dk.overlay b/samples/drivers/adc/adc_dt/boards/stm32l562e_dk.overlay similarity index 100% rename from samples/drivers/adc/boards/stm32l562e_dk.overlay rename to samples/drivers/adc/adc_dt/boards/stm32l562e_dk.overlay diff --git a/samples/drivers/adc/boards/tlsr9518adk80d.overlay b/samples/drivers/adc/adc_dt/boards/tlsr9518adk80d.overlay similarity index 100% rename from samples/drivers/adc/boards/tlsr9518adk80d.overlay rename to samples/drivers/adc/adc_dt/boards/tlsr9518adk80d.overlay diff --git a/samples/drivers/adc/boards/xiao_esp32s3.overlay b/samples/drivers/adc/adc_dt/boards/xiao_esp32s3_procpu.overlay similarity index 100% rename from samples/drivers/adc/boards/xiao_esp32s3.overlay rename to samples/drivers/adc/adc_dt/boards/xiao_esp32s3_procpu.overlay diff --git a/samples/drivers/adc/boards/xmc45_relax_kit.overlay b/samples/drivers/adc/adc_dt/boards/xmc45_relax_kit.overlay similarity index 100% rename from samples/drivers/adc/boards/xmc45_relax_kit.overlay rename to samples/drivers/adc/adc_dt/boards/xmc45_relax_kit.overlay diff --git a/samples/drivers/adc/boards/yd_esp32.overlay b/samples/drivers/adc/adc_dt/boards/yd_esp32_procpu.overlay similarity index 100% rename from samples/drivers/adc/boards/yd_esp32.overlay rename to samples/drivers/adc/adc_dt/boards/yd_esp32_procpu.overlay diff --git a/samples/drivers/adc/prj.conf b/samples/drivers/adc/adc_dt/prj.conf similarity index 100% rename from samples/drivers/adc/prj.conf rename to samples/drivers/adc/adc_dt/prj.conf diff --git a/samples/drivers/adc/adc_dt/sample.yaml b/samples/drivers/adc/adc_dt/sample.yaml new file mode 100644 index 00000000000..2096ad78eb9 --- /dev/null +++ b/samples/drivers/adc/adc_dt/sample.yaml @@ -0,0 +1,42 @@ +sample: + name: ADC devicetree driver sample +tests: + sample.drivers.adc.adc_dt: + tags: + - adc + depends_on: adc + platform_allow: + - nucleo_l073rz + - disco_l475_iot1 + - cc3220sf_launchxl + - cc3235sf_launchxl + - cy8cproto_063_ble + - stm32l496g_disco + - stm32h735g_disco + - nrf51dk/nrf51822 + - nrf52840dk/nrf52840 + - mec172xevb_assy6906 + - gd32f350r_eval + - gd32f450i_eval + - gd32vf103v_eval + - gd32f403z_eval + - esp32_devkitc_wroom/esp32/procpu + - esp32_devkitc_wrover/esp32/procpu + - esp32s2_saola + - esp32c3_devkitm + - gd32l233r_eval + - lpcxpresso55s36 + - mr_canhubk3 + - longan_nano + - longan_nano/gd32vf103/lite + - rd_rw612_bga + integration_platforms: + - nucleo_l073rz + - nrf52840dk/nrf52840 + harness: console + timeout: 10 + harness_config: + type: multi_line + regex: + - "ADC reading\\[\\d+\\]:" + - "- .+, channel \\d+: -?\\d+" diff --git a/samples/drivers/adc/src/main.c b/samples/drivers/adc/adc_dt/src/main.c similarity index 100% rename from samples/drivers/adc/src/main.c rename to samples/drivers/adc/adc_dt/src/main.c diff --git a/samples/drivers/adc/adc_sequence/CMakeLists.txt b/samples/drivers/adc/adc_sequence/CMakeLists.txt new file mode 100644 index 00000000000..044d7363302 --- /dev/null +++ b/samples/drivers/adc/adc_sequence/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(ADC) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/drivers/adc/adc_sequence/Kconfig b/samples/drivers/adc/adc_sequence/Kconfig new file mode 100644 index 00000000000..c8351a5e712 --- /dev/null +++ b/samples/drivers/adc/adc_sequence/Kconfig @@ -0,0 +1,12 @@ +# Copyright (c) 2024 Centro de Inovacao EDGE. +# SPDX-License-Identifier: Apache-2.0 + +config SEQUENCE_SAMPLES + int "Number of samples to be made on the sequence for each channel." + default 5 + +config SEQUENCE_RESOLUTION + int "Set the resolution of the sequence readings." + default 12 + +source "Kconfig.zephyr" diff --git a/samples/drivers/adc/adc_sequence/README.rst b/samples/drivers/adc/adc_sequence/README.rst new file mode 100644 index 00000000000..1227f44d9a1 --- /dev/null +++ b/samples/drivers/adc/adc_sequence/README.rst @@ -0,0 +1,66 @@ +.. zephyr:code-sample:: adc_sequence + :name: Analog-to-Digital Converter (ADC) sequence sample + :relevant-api: adc_interface + + Read analog inputs from ADC channels, using a sequence. + +Overview +******** + +This sample demonstrates how to use the :ref:`ADC driver API ` using sequences. + +Depending on the target board, it reads ADC samples from two channels +and prints the readings on the console, based on the sequence specifications. +Notice how for the whole sequence reading, only one call to the :c:func:`adc_read` API is made. +If voltage of the used reference can be obtained, the raw readings are converted to millivolts. + +This example constructs an adc device and setups its channels, according to the +given devicetree configuration. + +Building and Running +******************** + +Make sure that the ADC is enabled (``status = "okay";``) and has each channel as a +child node, with your desired settings like gain, reference, or acquisition time and +oversampling setting (if used). It is also needed to provide an alias ``adc0`` for the +desired adc. See :zephyr_file:`boards/nrf52840dk_nrf52840.overlay +` for an example of +such setup. + +Building and Running for Nordic nRF52840 +======================================== + +The sample can be built and executed for the +:ref:`nrf52840dk_nrf52840` as follows: + +.. zephyr-app-commands:: + :zephyr-app: samples/drivers/adc/adc_sequence + :board: nrf52840dk/nrf52840 + :goals: build flash + :compact: + +To build for another board, change "nrf52840dk/nrf52840" above to that board's name +and provide a corresponding devicetree overlay. + +Sample output +============= + +You should get a similar output as below, repeated every second: + +.. code-block:: console + + ADC sequence reading [1]: + - ADC_0, channel 0, 5 sequence samples: + - - 36 = 65mV + - - 35 = 63mV + - - 36 = 65mV + - - 35 = 63mV + - - 36 = 65mV + - ADC_0, channel 1, 5 sequence samples: + - - 0 = 0mV + - - 0 = 0mV + - - 1 = 1mV + - - 0 = 0mV + - - 1 = 1mV + +.. note:: If the ADC is not supported, the output will be an error message. diff --git a/samples/drivers/adc/adc_sequence/boards/cy8cproto_062_4343w.conf b/samples/drivers/adc/adc_sequence/boards/cy8cproto_062_4343w.conf new file mode 100644 index 00000000000..65f176fd23b --- /dev/null +++ b/samples/drivers/adc/adc_sequence/boards/cy8cproto_062_4343w.conf @@ -0,0 +1 @@ +CONFIG_SEQUENCE_RESOLUTION=12 diff --git a/samples/drivers/adc/adc_sequence/boards/cy8cproto_062_4343w.overlay b/samples/drivers/adc/adc_sequence/boards/cy8cproto_062_4343w.overlay new file mode 100644 index 00000000000..b91102738df --- /dev/null +++ b/samples/drivers/adc/adc_sequence/boards/cy8cproto_062_4343w.overlay @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2024 Centro de Inovacao EDGE + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + aliases { + adc0 = &adc0; + }; +}; + +&adc0 { + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + channel@0 { + reg = <0>; + zephyr,acquisition-time = ; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,input-positive = <0>; /* P10.0 */ + }; + + channel@1 { + reg = <1>; + zephyr,acquisition-time = ; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,input-positive = <1>; /* P10.1 */ + }; +}; diff --git a/samples/drivers/adc/adc_sequence/boards/cy8cproto_063_ble.conf b/samples/drivers/adc/adc_sequence/boards/cy8cproto_063_ble.conf new file mode 100644 index 00000000000..65f176fd23b --- /dev/null +++ b/samples/drivers/adc/adc_sequence/boards/cy8cproto_063_ble.conf @@ -0,0 +1 @@ +CONFIG_SEQUENCE_RESOLUTION=12 diff --git a/samples/drivers/adc/adc_sequence/boards/cy8cproto_063_ble.overlay b/samples/drivers/adc/adc_sequence/boards/cy8cproto_063_ble.overlay new file mode 100644 index 00000000000..429739fcce0 --- /dev/null +++ b/samples/drivers/adc/adc_sequence/boards/cy8cproto_063_ble.overlay @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2024 Centro de Inovacao EDGE + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + aliases { + adc0 = &adc0; + }; +}; + +&adc0 { + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + channel@0 { + reg = <0>; + zephyr,acquisition-time = ; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,input-positive = <2>; /* P10.2 */ + }; + + channel@1 { + reg = <1>; + zephyr,acquisition-time = ; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,input-positive = <3>; /* P10.3 */ + }; +}; diff --git a/samples/drivers/adc/adc_sequence/boards/lpcxpresso55s69_cpu0.conf b/samples/drivers/adc/adc_sequence/boards/lpcxpresso55s69_cpu0.conf new file mode 100644 index 00000000000..65f176fd23b --- /dev/null +++ b/samples/drivers/adc/adc_sequence/boards/lpcxpresso55s69_cpu0.conf @@ -0,0 +1 @@ +CONFIG_SEQUENCE_RESOLUTION=12 diff --git a/samples/drivers/adc/adc_sequence/boards/lpcxpresso55s69_cpu0.overlay b/samples/drivers/adc/adc_sequence/boards/lpcxpresso55s69_cpu0.overlay new file mode 100644 index 00000000000..bdedee26af2 --- /dev/null +++ b/samples/drivers/adc/adc_sequence/boards/lpcxpresso55s69_cpu0.overlay @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2024 Centro de Inovacao EDGE + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + aliases { + adc0 = &adc0; + }; +}; + +&adc0 { + #address-cells = <1>; + #size-cells = <0>; + + /* + * To use this sample: + * - Connect VREFN_TARGET to GND, and VREFP_TARGET to 3v3 + * (Resistors J8 and J9, should be populated by default) + * LPADC0 CH0A and CH0B are set up in differential mode + * - Connect LPADC0 CH0A signal to voltage between 0~3.3V (P19 pin 4) + * - Connect LPADC0 CH0B signal to voltage between 0~3.3V (P19 pin 2) + * LPADC0 CH4A is set up in single ended mode + * - Connect LPADC0 CH4A signal to voltage between 0~3.3V (P17 pin 19) + * LPADC0 CH4B is set up in single ended mode + * - Connect LPADC0 CH4B signal to voltage between 0~3.3V (P18 pin 1) + */ + + /* + * Channel 0 is used for differential mode, with 13 bit resolution + * CH0A (plus side) is routed to P19 pin 4 + * CH0B (minus side) is routed to P19 pin 2 + */ + channel@0 { + reg = <0>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_EXTERNAL0"; + zephyr,vref-mv = <3300>; + zephyr,acquisition-time = ; + zephyr,input-positive = ; + zephyr,input-negative = ; + }; + + /* + * Channel 1 is used in single ended mode, with 16 bit resolution + * CH4A is routed to P17 pin 19 + */ + channel@1 { + reg = <1>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_EXTERNAL0"; + zephyr,vref-mv = <3300>; + zephyr,acquisition-time = ; + zephyr,input-positive = ; + }; + + /* + * Channel 2 is used in single ended mode, with 12 bit resolution + * CH4B is routed to P18 pin 1 + */ +}; diff --git a/samples/drivers/adc/adc_sequence/boards/mec15xxevb_assy6853.conf b/samples/drivers/adc/adc_sequence/boards/mec15xxevb_assy6853.conf new file mode 100644 index 00000000000..65f176fd23b --- /dev/null +++ b/samples/drivers/adc/adc_sequence/boards/mec15xxevb_assy6853.conf @@ -0,0 +1 @@ +CONFIG_SEQUENCE_RESOLUTION=12 diff --git a/samples/drivers/adc/adc_sequence/boards/mec15xxevb_assy6853.overlay b/samples/drivers/adc/adc_sequence/boards/mec15xxevb_assy6853.overlay new file mode 100644 index 00000000000..3bf503121e3 --- /dev/null +++ b/samples/drivers/adc/adc_sequence/boards/mec15xxevb_assy6853.overlay @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2024 Centro de Inovacao EDGE + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + adc0 = &adc0; + }; +}; + +&adc0 { + #address-cells = <1>; + #size-cells = <0>; + + channel@4 { + reg = <4>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = <0>; + }; + + channel@5 { + reg = <5>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = <0>; + }; +}; diff --git a/samples/drivers/adc/adc_sequence/boards/mec172xevb_assy6906.conf b/samples/drivers/adc/adc_sequence/boards/mec172xevb_assy6906.conf new file mode 100644 index 00000000000..65f176fd23b --- /dev/null +++ b/samples/drivers/adc/adc_sequence/boards/mec172xevb_assy6906.conf @@ -0,0 +1 @@ +CONFIG_SEQUENCE_RESOLUTION=12 diff --git a/samples/drivers/adc/adc_sequence/boards/mec172xevb_assy6906.overlay b/samples/drivers/adc/adc_sequence/boards/mec172xevb_assy6906.overlay new file mode 100644 index 00000000000..a1ca287b812 --- /dev/null +++ b/samples/drivers/adc/adc_sequence/boards/mec172xevb_assy6906.overlay @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2024 Centro de Inovacao EDGE + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + adc0 = &adc0; + }; +}; + +&adc0 { + #address-cells = <1>; + #size-cells = <0>; + + channel@0 { + reg = <0>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = <0>; + }; + + channel@3 { + reg = <3>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = <0>; + }; +}; diff --git a/samples/drivers/adc/adc_sequence/boards/mimxrt1040_evk.conf b/samples/drivers/adc/adc_sequence/boards/mimxrt1040_evk.conf new file mode 100644 index 00000000000..65f176fd23b --- /dev/null +++ b/samples/drivers/adc/adc_sequence/boards/mimxrt1040_evk.conf @@ -0,0 +1 @@ +CONFIG_SEQUENCE_RESOLUTION=12 diff --git a/samples/drivers/adc/adc_sequence/boards/mimxrt1040_evk.overlay b/samples/drivers/adc/adc_sequence/boards/mimxrt1040_evk.overlay new file mode 100644 index 00000000000..509473ec918 --- /dev/null +++ b/samples/drivers/adc/adc_sequence/boards/mimxrt1040_evk.overlay @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2024 Centro de Inovacao EDGE + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + adc0 = &adc1; + }; +}; + +&adc1 { + #address-cells = <1>; + #size-cells = <0>; + + /* + * To use this sample connect + * J33.1 (ADC1 CH3) and J33.2 (ADC1 CH4) to voltages between 0 and 3.3V + */ + channel@3 { + reg = <3>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + }; + + channel@4 { + reg = <4>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + }; +}; diff --git a/samples/drivers/adc/adc_sequence/boards/mimxrt595_evk_cm33.conf b/samples/drivers/adc/adc_sequence/boards/mimxrt595_evk_cm33.conf new file mode 100644 index 00000000000..65f176fd23b --- /dev/null +++ b/samples/drivers/adc/adc_sequence/boards/mimxrt595_evk_cm33.conf @@ -0,0 +1 @@ +CONFIG_SEQUENCE_RESOLUTION=12 diff --git a/samples/drivers/adc/adc_sequence/boards/mimxrt595_evk_cm33.overlay b/samples/drivers/adc/adc_sequence/boards/mimxrt595_evk_cm33.overlay new file mode 100644 index 00000000000..35046128688 --- /dev/null +++ b/samples/drivers/adc/adc_sequence/boards/mimxrt595_evk_cm33.overlay @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2024 Centro de Inovacao EDGE + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + aliases { + adc0 = &lpadc0; + }; +}; + +&lpadc0 { + #address-cells = <1>; + #size-cells = <0>; + + /* + * To use this sample: + * LPADC0 CH0A and CH0B are set up in differential mode (B-A) + * - Connect LPADC0 CH0A signal to voltage between 0~1.8V (J30 pin 1) + * - Connect LPADC0 CH0B signal to voltage between 0~1.8V (J30 pin 2) + * LPADC0 CH2A is set up in single ended mode + * - Connect LPADC0 CH2A signal to voltage between 0~1.8V (J30 pin 3) + */ + + channel@0 { + reg = <0>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_EXTERNAL0"; + zephyr,vref-mv = <1800>; + zephyr,acquisition-time = ; + zephyr,input-positive = ; + zephyr,input-negative = ; + }; + + channel@1 { + reg = <1>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_EXTERNAL0"; + zephyr,vref-mv = <1800>; + zephyr,acquisition-time = ; + zephyr,input-positive = ; + }; +}; diff --git a/samples/drivers/adc/adc_sequence/boards/mr_canhubk3.conf b/samples/drivers/adc/adc_sequence/boards/mr_canhubk3.conf new file mode 100644 index 00000000000..65f176fd23b --- /dev/null +++ b/samples/drivers/adc/adc_sequence/boards/mr_canhubk3.conf @@ -0,0 +1 @@ +CONFIG_SEQUENCE_RESOLUTION=12 diff --git a/samples/drivers/adc/adc_sequence/boards/mr_canhubk3.overlay b/samples/drivers/adc/adc_sequence/boards/mr_canhubk3.overlay new file mode 100644 index 00000000000..c2fd0e11ca2 --- /dev/null +++ b/samples/drivers/adc/adc_sequence/boards/mr_canhubk3.overlay @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2024 Centro de Inovacao EDGE + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + aliases { + adc0 = &adc2; + }; +}; + +&adc2 { + group-channel = "precision"; + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + channel@3 { + reg = <3>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + }; + + channel@4 { + reg = <4>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + }; +}; diff --git a/samples/drivers/adc/adc_sequence/boards/nrf52840dk_nrf52840.conf b/samples/drivers/adc/adc_sequence/boards/nrf52840dk_nrf52840.conf new file mode 100644 index 00000000000..65f176fd23b --- /dev/null +++ b/samples/drivers/adc/adc_sequence/boards/nrf52840dk_nrf52840.conf @@ -0,0 +1 @@ +CONFIG_SEQUENCE_RESOLUTION=12 diff --git a/samples/drivers/adc/adc_sequence/boards/nrf52840dk_nrf52840.overlay b/samples/drivers/adc/adc_sequence/boards/nrf52840dk_nrf52840.overlay new file mode 100644 index 00000000000..34107d84748 --- /dev/null +++ b/samples/drivers/adc/adc_sequence/boards/nrf52840dk_nrf52840.overlay @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2024 Centro de Inovacao EDGE + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + adc0 = &adc; + }; +}; + +&adc { + #address-cells = <1>; + #size-cells = <0>; + + channel@0 { + reg = <0>; + zephyr,gain = "ADC_GAIN_1_6"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,input-positive = ; /* P0.03 */ + }; + + channel@1 { + reg = <1>; + zephyr,gain = "ADC_GAIN_1_6"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,input-positive = ; + zephyr,oversampling = <8>; + }; +}; diff --git a/samples/drivers/adc/adc_sequence/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay b/samples/drivers/adc/adc_sequence/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay new file mode 100644 index 00000000000..a0639a405c4 --- /dev/null +++ b/samples/drivers/adc/adc_sequence/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay @@ -0,0 +1,51 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2024 Nordic Semiconductor ASA + */ + +/ { + zephyr,user { + io-channels = <&adc 0>, <&adc 1>, <&adc 7>; + }; +}; + +/ { + aliases { + adc0 = &adc; + }; +}; + +&adc { + #address-cells = <1>; + #size-cells = <0>; + + channel@0 { + reg = <0>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,input-positive = ; /* P1.11 */ + zephyr,resolution = <10>; + }; + + channel@1 { + reg = <1>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,input-positive = ; /* P1.06 */ + zephyr,resolution = <12>; + zephyr,oversampling = <8>; + }; + + channel@7 { + reg = <7>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,input-positive = ; /* P1.13 */ + zephyr,input-negative = ; /* P1.14 */ + zephyr,resolution = <12>; + }; +}; diff --git a/samples/drivers/adc/adc_sequence/boards/nucleo_c031c6.conf b/samples/drivers/adc/adc_sequence/boards/nucleo_c031c6.conf new file mode 100644 index 00000000000..65f176fd23b --- /dev/null +++ b/samples/drivers/adc/adc_sequence/boards/nucleo_c031c6.conf @@ -0,0 +1 @@ +CONFIG_SEQUENCE_RESOLUTION=12 diff --git a/samples/drivers/adc/adc_sequence/boards/nucleo_c031c6.overlay b/samples/drivers/adc/adc_sequence/boards/nucleo_c031c6.overlay new file mode 100644 index 00000000000..937de101ee1 --- /dev/null +++ b/samples/drivers/adc/adc_sequence/boards/nucleo_c031c6.overlay @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2024 Centro de Inovacao EDGE + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + adc0 = &adc1; + }; +}; + +&adc1 { + #address-cells = <1>; + #size-cells = <0>; + + channel@0 { + reg = <0>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + }; + + channel@1 { + reg = <1>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + }; +}; diff --git a/samples/drivers/adc/adc_sequence/boards/sam4s_xplained.conf b/samples/drivers/adc/adc_sequence/boards/sam4s_xplained.conf new file mode 100644 index 00000000000..65f176fd23b --- /dev/null +++ b/samples/drivers/adc/adc_sequence/boards/sam4s_xplained.conf @@ -0,0 +1 @@ +CONFIG_SEQUENCE_RESOLUTION=12 diff --git a/samples/drivers/adc/adc_sequence/boards/sam4s_xplained.overlay b/samples/drivers/adc/adc_sequence/boards/sam4s_xplained.overlay new file mode 100644 index 00000000000..5eedbb6fc65 --- /dev/null +++ b/samples/drivers/adc/adc_sequence/boards/sam4s_xplained.overlay @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2024 Centro de Inovacao EDGE + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + adc0 = &adc0; + }; +}; + +&adc0 { + #address-cells = <1>; + #size-cells = <0>; + + /* External ADC(+) */ + channel@5 { + reg = <5>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_EXTERNAL0"; + zephyr,acquisition-time = ; + zephyr,input-positive = <5>; + }; + + /* Internal temperature sensor */ + channel@f { + reg = <15>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_EXTERNAL0"; + zephyr,acquisition-time = ; + zephyr,input-positive = <15>; + }; +}; diff --git a/samples/drivers/adc/adc_sequence/boards/sam_e70_xplained.conf b/samples/drivers/adc/adc_sequence/boards/sam_e70_xplained.conf new file mode 100644 index 00000000000..65f176fd23b --- /dev/null +++ b/samples/drivers/adc/adc_sequence/boards/sam_e70_xplained.conf @@ -0,0 +1 @@ +CONFIG_SEQUENCE_RESOLUTION=12 diff --git a/samples/drivers/adc/adc_sequence/boards/sam_e70_xplained.overlay b/samples/drivers/adc/adc_sequence/boards/sam_e70_xplained.overlay new file mode 100644 index 00000000000..3da0d7d4c83 --- /dev/null +++ b/samples/drivers/adc/adc_sequence/boards/sam_e70_xplained.overlay @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2024 Centro de Inovacao EDGE + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + adc0 = &afec0; + }; +}; + +&afec0 { + #address-cells = <1>; + #size-cells = <0>; + + channel@0 { + reg = <0>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + }; + + channel@8 { + reg = <8>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + }; +}; diff --git a/samples/drivers/adc/adc_sequence/boards/sam_v71_xult.conf b/samples/drivers/adc/adc_sequence/boards/sam_v71_xult.conf new file mode 100644 index 00000000000..65f176fd23b --- /dev/null +++ b/samples/drivers/adc/adc_sequence/boards/sam_v71_xult.conf @@ -0,0 +1 @@ +CONFIG_SEQUENCE_RESOLUTION=12 diff --git a/samples/drivers/adc/adc_sequence/boards/sam_v71_xult.overlay b/samples/drivers/adc/adc_sequence/boards/sam_v71_xult.overlay new file mode 100644 index 00000000000..3da0d7d4c83 --- /dev/null +++ b/samples/drivers/adc/adc_sequence/boards/sam_v71_xult.overlay @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2024 Centro de Inovacao EDGE + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + adc0 = &afec0; + }; +}; + +&afec0 { + #address-cells = <1>; + #size-cells = <0>; + + channel@0 { + reg = <0>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + }; + + channel@8 { + reg = <8>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + }; +}; diff --git a/samples/drivers/adc/adc_sequence/prj.conf b/samples/drivers/adc/adc_sequence/prj.conf new file mode 100644 index 00000000000..488a81dca52 --- /dev/null +++ b/samples/drivers/adc/adc_sequence/prj.conf @@ -0,0 +1 @@ +CONFIG_ADC=y diff --git a/samples/drivers/adc/adc_sequence/sample.yaml b/samples/drivers/adc/adc_sequence/sample.yaml new file mode 100644 index 00000000000..5f6436c076d --- /dev/null +++ b/samples/drivers/adc/adc_sequence/sample.yaml @@ -0,0 +1,21 @@ +sample: + name: ADC driver sequence sample +tests: + sample.drivers.adc.adc_sequence: + tags: + - adc + depends_on: adc + platform_allow: + - cy8cproto_063_ble + - cy8cproto_062_4343w + - nrf52840dk/nrf52840 + integration_platforms: + - nrf52840dk/nrf52840 + harness: console + timeout: 10 + harness_config: + type: multi_line + regex: + - "ADC sequence reading \\[\\d+\\]:" + - "- .+, channel \\d+, \\d+ sequence samples:" + - "- - \\d+ (= \\d+mV)|(\\(value in mV not available\\))" diff --git a/samples/drivers/adc/adc_sequence/src/main.c b/samples/drivers/adc/adc_sequence/src/main.c new file mode 100644 index 00000000000..9dda1acfb46 --- /dev/null +++ b/samples/drivers/adc/adc_sequence/src/main.c @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2024 Centro de Inovacao EDGE + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/* ADC node from the devicetree. */ +#define ADC_NODE DT_ALIAS(adc0) + +/* Data of ADC device specified in devicetree. */ +static const struct device *adc = DEVICE_DT_GET(ADC_NODE); + +/* Data array of ADC channels for the specified ADC. */ +static const struct adc_channel_cfg channel_cfgs[] = { + DT_FOREACH_CHILD_SEP(ADC_NODE, ADC_CHANNEL_CFG_DT, (,))}; + +/* Get the number of channels defined on the DTS. */ +#define CHANNEL_COUNT ARRAY_SIZE(channel_cfgs) + +int main(void) +{ + int err; + uint32_t count = 0; + uint16_t channel_reading[CONFIG_SEQUENCE_SAMPLES][CHANNEL_COUNT]; + + /* Options for the sequence sampling. */ + const struct adc_sequence_options options = { + .extra_samplings = CONFIG_SEQUENCE_SAMPLES - 1, + .interval_us = 0, + }; + + /* Configure the sampling sequence to be made. */ + struct adc_sequence sequence = { + .buffer = channel_reading, + /* buffer size in bytes, not number of samples */ + .buffer_size = sizeof(channel_reading), + .resolution = CONFIG_SEQUENCE_RESOLUTION, + .options = &options, + }; + + if (!device_is_ready(adc)) { + printf("ADC controller device %s not ready\n", adc->name); + return 0; + } + + /* Configure channels individually prior to sampling. */ + for (size_t i = 0U; i < CHANNEL_COUNT; i++) { + sequence.channels |= BIT(channel_cfgs[i].channel_id); + err = adc_channel_setup(adc, &channel_cfgs[i]); + if (err < 0) { + printf("Could not setup channel #%d (%d)\n", i, err); + return 0; + } + } + + while (1) { + printf("ADC sequence reading [%u]:\n", count++); + k_msleep(1000); + + err = adc_read(adc, &sequence); + if (err < 0) { + printf("Could not read (%d)\n", err); + continue; + } + + for (size_t channel_index = 0U; channel_index < CHANNEL_COUNT; channel_index++) { + int32_t val_mv; + + printf("- %s, channel %" PRId32 ", %" PRId32 " sequence samples:\n", + adc->name, channel_cfgs[channel_index].channel_id, + CONFIG_SEQUENCE_SAMPLES); + for (size_t sample_index = 0U; sample_index < CONFIG_SEQUENCE_SAMPLES; + sample_index++) { + + val_mv = channel_reading[sample_index][channel_index]; + + printf("- - %" PRId32, val_mv); + err = adc_raw_to_millivolts(channel_cfgs[channel_index].reference, + channel_cfgs[channel_index].gain, + CONFIG_SEQUENCE_RESOLUTION, &val_mv); + + /* conversion to mV may not be supported, skip if not */ + if ((err < 0) || channel_cfgs[channel_index].reference == 0) { + printf(" (value in mV not available)\n"); + } else { + printf(" = %" PRId32 "mV\n", val_mv); + } + } + } + } + + return 0; +} diff --git a/samples/drivers/adc/boards/lpcxpresso55s69_lpc55s69_cpu0.overlay b/samples/drivers/adc/boards/lpcxpresso55s69_lpc55s69_cpu0.overlay deleted file mode 100644 index a8bb9b57e85..00000000000 --- a/samples/drivers/adc/boards/lpcxpresso55s69_lpc55s69_cpu0.overlay +++ /dev/null @@ -1,75 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * Copyright 2022-2023 NXP - */ - -#include - -/ { - zephyr,user { - io-channels = <&adc0 0 &adc0 1 &adc0 2>; - }; -}; - -&adc0 { - #address-cells = <1>; - #size-cells = <0>; - - /* - * To use this sample: - * - Connect VREFN_TARGET to GND, and VREFP_TARGET to 3v3 - * (Resistors J8 and J9, should be populated by default) - * LPADC0 CH0A and CH0B are set up in differential mode - * - Connect LPADC0 CH0A signal to voltage between 0~3.3V (P19 pin 4) - * - Connect LPADC0 CH0B signal to voltage between 0~3.3V (P19 pin 2) - * LPADC0 CH4A is set up in single ended mode - * - Connect LPADC0 CH4A signal to voltage between 0~3.3V (P17 pin 19) - * LPADC0 CH4B is set up in single ended mode - * - Connect LPADC0 CH4B signal to voltage between 0~3.3V (P18 pin 1) - */ - - /* - * Channel 0 is used for differential mode, with 13 bit resolution - * CH0A (plus side) is routed to P19 pin 4 - * CH0B (minus side) is routed to P19 pin 2 - */ - channel@0 { - reg = <0>; - zephyr,gain = "ADC_GAIN_1"; - zephyr,reference = "ADC_REF_EXTERNAL0"; - zephyr,vref-mv = <3300>; - zephyr,acquisition-time = ; - zephyr,resolution = <13>; - zephyr,input-positive = ; - zephyr,input-negative = ; - }; - - /* - * Channel 1 is used in single ended mode, with 16 bit resolution - * CH4A is routed to P17 pin 19 - */ - channel@1 { - reg = <1>; - zephyr,gain = "ADC_GAIN_1"; - zephyr,reference = "ADC_REF_EXTERNAL0"; - zephyr,vref-mv = <3300>; - zephyr,acquisition-time = ; - zephyr,resolution = <16>; - zephyr,input-positive = ; - }; - - /* - * Channel 2 is used in single ended mode, with 12 bit resolution - * CH4B is routed to P18 pin 1 - */ - channel@2 { - reg = <2>; - zephyr,gain = "ADC_GAIN_1"; - zephyr,reference = "ADC_REF_EXTERNAL0"; - zephyr,vref-mv = <3300>; - zephyr,acquisition-time = ; - zephyr,resolution = <12>; - zephyr,input-positive = ; - }; -}; diff --git a/samples/drivers/adc/boards/mimxrt1160_evk_mimxrt1166_cm7.overlay b/samples/drivers/adc/boards/mimxrt1160_evk_mimxrt1166_cm7.overlay deleted file mode 100644 index a27042020df..00000000000 --- a/samples/drivers/adc/boards/mimxrt1160_evk_mimxrt1166_cm7.overlay +++ /dev/null @@ -1,34 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * Copyright 2021,2023 NXP - */ - -#include - -/ { - zephyr,user { - /* adjust channel number according to pinmux in board.dts */ - io-channels = <&lpadc0 0>; - }; -}; - -&lpadc0 { - #address-cells = <1>; - #size-cells = <0>; - - /* - * To use this sample: - * - Connect LPADC0 CH0 signal to voltage between 0~1.8V (J9 pin 10) - */ - - channel@0 { - reg = <0>; - zephyr,gain = "ADC_GAIN_1"; - zephyr,reference = "ADC_REF_EXTERNAL0"; - zephyr,vref-mv = <1800>; - zephyr,acquisition-time = ; - zephyr,resolution = <12>; - zephyr,input-positive = ; - }; -}; diff --git a/samples/drivers/adc/boards/mimxrt1170_evk_mimxrt1176_cm7_B.overlay b/samples/drivers/adc/boards/mimxrt1170_evk_mimxrt1176_cm7_B.overlay deleted file mode 100644 index 490660fb3c6..00000000000 --- a/samples/drivers/adc/boards/mimxrt1170_evk_mimxrt1176_cm7_B.overlay +++ /dev/null @@ -1,34 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * Copyright 2023 NXP - */ - -#include - -/ { - zephyr,user { - /* adjust channel number according to pinmux in board.dts */ - io-channels = <&lpadc0 0>; - }; -}; - -&lpadc0 { - #address-cells = <1>; - #size-cells = <0>; - - /* - * To use this sample: - * - Connect LPADC0 CH0 signal to voltage between 0~1.8V (J9 pin 10) - */ - - channel@0 { - reg = <0>; - zephyr,gain = "ADC_GAIN_1"; - zephyr,reference = "ADC_REF_EXTERNAL0"; - zephyr,vref-mv = <1800>; - zephyr,acquisition-time = ; - zephyr,resolution = <12>; - zephyr,input-positive = ; - }; -}; diff --git a/samples/drivers/adc/sample.yaml b/samples/drivers/adc/sample.yaml deleted file mode 100644 index 7b523ea062c..00000000000 --- a/samples/drivers/adc/sample.yaml +++ /dev/null @@ -1,41 +0,0 @@ -sample: - name: ADC driver sample -tests: - sample.drivers.adc: - tags: - - adc - depends_on: adc - platform_allow: - - nucleo_l073rz - - disco_l475_iot1 - - cc3220sf_launchxl - - cc3235sf_launchxl - - cy8cproto_063_ble - - stm32l496g_disco - - stm32h735g_disco - - nrf51dk/nrf51822 - - nrf52840dk/nrf52840 - - mec172xevb_assy6906 - - gd32f350r_eval - - gd32f450i_eval - - gd32vf103v_eval - - gd32f403z_eval - - esp32_devkitc_wroom/esp32/procpu - - esp32_devkitc_wrover/esp32/procpu - - esp32s2_saola - - esp32c3_devkitm - - gd32l233r_eval - - lpcxpresso55s36 - - mr_canhubk3 - - longan_nano - - longan_nano/gd32vf103/lite - integration_platforms: - - nucleo_l073rz - - nrf52840dk/nrf52840 - harness: console - timeout: 10 - harness_config: - type: multi_line - regex: - - "ADC reading\\[\\d+\\]:" - - "- .+, channel \\d+: -?\\d+" diff --git a/samples/drivers/auxdisplay/boards/esp_wrover_kit.overlay b/samples/drivers/auxdisplay/boards/esp_wrover_kit.overlay new file mode 100644 index 00000000000..f34539044ca --- /dev/null +++ b/samples/drivers/auxdisplay/boards/esp_wrover_kit.overlay @@ -0,0 +1,34 @@ +/* + * Character HD44780 module driven by the PCF8574 gpio. + */ + +&i2c0 { + aux_display_gpio: pcf8574@27 { + compatible = "nxp,pcf857x"; + reg = <0x27>; + gpio-controller; + ngpios = <8>; + #gpio-cells = <2>; + }; +}; + +/ { + auxdisplay_0: hd44780 { + compatible = "hit,hd44780"; + columns = <16>; + rows = <2>; + mode = <4>; + boot-delay-ms = <100>; + enable-line-rise-delay-us = <1000>; + enable-line-fall-delay-us = <500>; + register-select-gpios = <&aux_display_gpio 0 (GPIO_ACTIVE_HIGH)>; + read-write-gpios = <&aux_display_gpio 1 (GPIO_ACTIVE_HIGH)>; + enable-gpios = <&aux_display_gpio 2 (GPIO_ACTIVE_HIGH)>; + backlight-gpios = <&aux_display_gpio 3 (GPIO_ACTIVE_HIGH)>; + data-bus-gpios = <0>, <0>, <0>, <0>, + <&aux_display_gpio 4 (GPIO_ACTIVE_HIGH)>, + <&aux_display_gpio 5 (GPIO_ACTIVE_HIGH)>, + <&aux_display_gpio 6 (GPIO_ACTIVE_HIGH)>, + <&aux_display_gpio 7 (GPIO_ACTIVE_HIGH)>; + }; +}; diff --git a/samples/drivers/counter/alarm/boards/esp32s3_devkitm.overlay b/samples/drivers/counter/alarm/boards/esp32s3_devkitm_procpu.overlay similarity index 100% rename from samples/drivers/counter/alarm/boards/esp32s3_devkitm.overlay rename to samples/drivers/counter/alarm/boards/esp32s3_devkitm_procpu.overlay diff --git a/samples/drivers/counter/alarm/boards/esp32s3_luatos_core.overlay b/samples/drivers/counter/alarm/boards/esp32s3_luatos_core_procpu.overlay similarity index 100% rename from samples/drivers/counter/alarm/boards/esp32s3_luatos_core.overlay rename to samples/drivers/counter/alarm/boards/esp32s3_luatos_core_procpu.overlay diff --git a/samples/drivers/counter/alarm/boards/esp32s3_luatos_core_esp32s3_procpu_usb.overlay b/samples/drivers/counter/alarm/boards/esp32s3_luatos_core_procpu_usb.overlay similarity index 100% rename from samples/drivers/counter/alarm/boards/esp32s3_luatos_core_esp32s3_procpu_usb.overlay rename to samples/drivers/counter/alarm/boards/esp32s3_luatos_core_procpu_usb.overlay diff --git a/samples/drivers/counter/alarm/boards/yd_esp32.overlay b/samples/drivers/counter/alarm/boards/yd_esp32_procpu.overlay similarity index 100% rename from samples/drivers/counter/alarm/boards/yd_esp32.overlay rename to samples/drivers/counter/alarm/boards/yd_esp32_procpu.overlay diff --git a/samples/drivers/crypto/src/main.c b/samples/drivers/crypto/src/main.c index 38205ef5df6..76481eb69ad 100644 --- a/samples/drivers/crypto/src/main.c +++ b/samples/drivers/crypto/src/main.c @@ -65,7 +65,7 @@ static void print_buffer_comparison(const uint8_t *wanted_result, } } - printk("\n But got:\n"); + printk("\nBut got:\n"); for (i = 0, j = 1; i < length; i++, j++) { printk("0x%02x ", result[i]); diff --git a/samples/drivers/dac/boards/rd_rw612_bga.overlay b/samples/drivers/dac/boards/rd_rw612_bga.overlay new file mode 100644 index 00000000000..55409f2be18 --- /dev/null +++ b/samples/drivers/dac/boards/rd_rw612_bga.overlay @@ -0,0 +1,12 @@ +/ { + zephyr,user { + dac = <&dac0>; + dac-channel-id = <0>; + dac-resolution = <10>; + }; +}; + +&dac0 { + nxp,conversion-rate = "500K"; + nxp,output-voltage-range = "large"; +}; diff --git a/samples/drivers/dac/boards/yd_esp32.overlay b/samples/drivers/dac/boards/yd_esp32_procpu.overlay similarity index 100% rename from samples/drivers/dac/boards/yd_esp32.overlay rename to samples/drivers/dac/boards/yd_esp32_procpu.overlay diff --git a/samples/drivers/dac/sample.yaml b/samples/drivers/dac/sample.yaml index e83c20d5fc0..9c7a53beef1 100644 --- a/samples/drivers/dac/sample.yaml +++ b/samples/drivers/dac/sample.yaml @@ -43,6 +43,7 @@ tests: - stm32l562e_dk - twr_ke18f - lpcxpresso55s36 + - rd_rw612_bga depends_on: dac integration_platforms: - nucleo_l152re diff --git a/samples/drivers/display/src/main.c b/samples/drivers/display/src/main.c index a9267b51c74..fb81955c78a 100644 --- a/samples/drivers/display/src/main.c +++ b/samples/drivers/display/src/main.c @@ -298,6 +298,14 @@ int main(void) buf_desc.height = h_step; for (int idx = 0; idx < capabilities.y_resolution; idx += h_step) { + /* + * Tweaking the height value not to draw outside of the display. + * It is required when using a monochrome display whose vertical + * resolution can not be divided by 8. + */ + if ((capabilities.y_resolution - idx) < h_step) { + buf_desc.height = (capabilities.y_resolution - idx); + } display_write(display_dev, 0, idx, &buf_desc, buf); } diff --git a/samples/drivers/espi/boards/mec172xmodular_assy6930.conf b/samples/drivers/espi/boards/mec172xmodular_assy6930.conf new file mode 100644 index 00000000000..a384c652521 --- /dev/null +++ b/samples/drivers/espi/boards/mec172xmodular_assy6930.conf @@ -0,0 +1,10 @@ +# eSPI + mec172xevb_assy6906 +CONFIG_ESPI=y +CONFIG_LOG=y +CONFIG_LOG_BUFFER_SIZE=4096 +CONFIG_LOG_PROCESS_THREAD_SLEEP_MS=100 +# Disable only for this board to check notifications +CONFIG_ESPI_AUTOMATIC_WARNING_ACKNOWLEDGE=n +# Sample code doesn't handle ACPI host communication +CONFIG_ESPI_PERIPHERAL_HOST_IO=n +# Test SAF flash portal read/erase/write on EVB diff --git a/samples/drivers/espi/boards/mec172xmodular_assy6930.overlay b/samples/drivers/espi/boards/mec172xmodular_assy6930.overlay new file mode 100644 index 00000000000..f5b7e5483f2 --- /dev/null +++ b/samples/drivers/espi/boards/mec172xmodular_assy6930.overlay @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2020 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + board_power: resources { + compatible = "microchip,mec172x-board-power"; + /* MCHP_GPIO_012 */ + pwrg-gpios = <&gpio_000_036 10 GPIO_ACTIVE_HIGH>; + /* MCHP_GPIO_0054 */ + rsm-gpios = <&gpio_040_076 12 GPIO_ACTIVE_HIGH>; + }; +}; + + +/* Enable Target to Controller Virtual Wires GPIO 0 - 3 */ +&vw_t2c_gpio_0 { + status = "okay"; + reset-state = "1"; + reset-source = "ESPI_RESET"; +}; + +&vw_t2c_gpio_1 { + status = "okay"; + reset-state = "1"; + reset-source = "ESPI_RESET"; +}; + +&vw_t2c_gpio_2 { + status = "okay"; + reset-state = "1"; + reset-source = "ESPI_RESET"; +}; + +&vw_t2c_gpio_3 { + status = "okay"; + reset-state = "1"; + reset-source = "ESPI_RESET"; +}; + +&spi0 { + status = "okay"; + clock-frequency = <24000000>; + chip-select = <0>; + lines = <4>; +}; + +/* Disable unwanted VWs notifications + * Refer to include/zephyr/drivers/espi.h + */ +&vw_sus_stat_n { + status = "disabled"; +}; + +&vw_smiout_n { + status = "disabled"; +}; + +&vw_nmiout_n { + status = "disabled"; +}; + +&vw_slp_lan_n { + status = "disabled"; +}; + +&vw_slp_wlan_n { + status = "disabled"; +}; + +&vw_host_c10 { + status = "disabled"; +}; diff --git a/samples/drivers/espi/src/main.c b/samples/drivers/espi/src/main.c index ce6cb08c322..a51b79776af 100644 --- a/samples/drivers/espi/src/main.c +++ b/samples/drivers/espi/src/main.c @@ -881,11 +881,11 @@ 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, + LOG_ERR("Failed to configure eSPI target channels:%x err: %d", cfg.channel_caps, ret); return ret; } else { - LOG_INF("eSPI slave configured successfully!"); + LOG_INF("eSPI target configured successfully!"); } LOG_INF("eSPI test - callbacks initialization... "); @@ -1145,20 +1145,20 @@ static int espi_flash_test(uint32_t start_flash_addr, uint8_t blocks) } #endif /* CONFIG_ESPI_FLASH_CHANNEL */ -#ifndef CONFIG_ESPI_AUTOMATIC_BOOT_DONE_ACKNOWLEDGE -static void send_slave_bootdone(void) +#ifndef CONFIG_ESPI_AUTOMATIC_WARNING_ACKNOWLEDGE +static void send_target_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_TARGET_BOOT_DONE, &boot_done); LOG_INF("%s boot_done: %d", __func__, boot_done); if (ret) { - LOG_WRN("Fail to retrieve slave boot done"); + LOG_WRN("Fail to retrieve target boot done"); } else if (!boot_done) { - /* SLAVE_BOOT_DONE & SLAVE_LOAD_STS have to be sent together */ - espi_send_vwire(espi_dev, ESPI_VWIRE_SIGNAL_SLV_BOOT_STS, 1); - espi_send_vwire(espi_dev, ESPI_VWIRE_SIGNAL_SLV_BOOT_DONE, 1); + /* TARGET_BOOT_DONE & TARGET_LOAD_STS have to be sent together */ + espi_send_vwire(espi_dev, ESPI_VWIRE_SIGNAL_TARGET_BOOT_STS, 1); + espi_send_vwire(espi_dev, ESPI_VWIRE_SIGNAL_TARGET_BOOT_DONE, 1); } } #endif @@ -1271,9 +1271,9 @@ int espi_test(void) return ret; } -#ifndef CONFIG_ESPI_AUTOMATIC_BOOT_DONE_ACKNOWLEDGE +#ifndef CONFIG_ESPI_AUTOMATIC_WARNING_ACKNOWLEDGE /* When automatic acknowledge is disabled to perform lengthy operations - * in the eSPI slave, need to explicitly send slave boot + * in the eSPI target, need to explicitly send target boot virtual wires */ bool vw_ch_sts; @@ -1285,7 +1285,7 @@ int espi_test(void) k_busy_wait(100); } while (!vw_ch_sts); - send_slave_bootdone(); + send_target_bootdone(); #endif #ifdef CONFIG_ESPI_FLASH_CHANNEL diff --git a/samples/drivers/gnss/boards/mimxrt1062_fmurt6.overlay b/samples/drivers/gnss/boards/mimxrt1062_fmurt6.overlay index 37942aed9ba..d4420c42393 100644 --- a/samples/drivers/gnss/boards/mimxrt1062_fmurt6.overlay +++ b/samples/drivers/gnss/boards/mimxrt1062_fmurt6.overlay @@ -6,7 +6,7 @@ / { aliases { - gnss = &lpuart2; + gnss = &gnss; }; }; @@ -17,7 +17,7 @@ pinctrl-1 = <&pinmux_lpuart2_sleep>; pinctrl-names = "default", "sleep"; - u_blox_m10: u-blox,m10 { + gnss: u_blox_m10 { status = "okay"; compatible = "u-blox,m10"; uart-baudrate = <115200>; diff --git a/samples/drivers/gnss/prj.conf b/samples/drivers/gnss/prj.conf index 5ed72c140c2..9cad2be8abe 100644 --- a/samples/drivers/gnss/prj.conf +++ b/samples/drivers/gnss/prj.conf @@ -3,7 +3,10 @@ CONFIG_GNSS=y CONFIG_GNSS_SATELLITES=y + CONFIG_LOG=y CONFIG_LOG_BUFFER_SIZE=8192 CONFIG_GNSS_DUMP_TO_LOG=y +CONFIG_GNSS_DUMP_TO_LOG_BUF_SIZE=1024 CONFIG_GNSS_LOG_LEVEL_DBG=y +CONFIG_MODEM_MODULES_LOG_LEVEL_DBG=y diff --git a/samples/drivers/gnss/src/main.c b/samples/drivers/gnss/src/main.c index 16b812f3f84..91bd427e236 100644 --- a/samples/drivers/gnss/src/main.c +++ b/samples/drivers/gnss/src/main.c @@ -7,25 +7,34 @@ #include #include #include +#include + +#define GNSS_MODEM DEVICE_DT_GET(DT_ALIAS(gnss)) + +LOG_MODULE_REGISTER(gnss_sample, CONFIG_GNSS_LOG_LEVEL); 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); + printf("Got a fix!\n"); } } - -GNSS_DATA_CALLBACK_DEFINE(DEVICE_DT_GET(DT_ALIAS(gnss)), gnss_data_cb); +GNSS_DATA_CALLBACK_DEFINE(GNSS_MODEM, 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); + unsigned int tracked_count = 0; + + for (unsigned int i = 0; i != size; ++i) { + tracked_count += satellites[i].is_tracked; + } + printf("%u satellite%s reported (of which %u tracked)!\n", + size, size > 1 ? "s" : "", tracked_count); } #endif - -GNSS_SATELLITES_CALLBACK_DEFINE(DEVICE_DT_GET(DT_ALIAS(gnss)), gnss_satellites_cb); +GNSS_SATELLITES_CALLBACK_DEFINE(GNSS_MODEM, gnss_satellites_cb); int main(void) { diff --git a/samples/drivers/ht16k33/boards/nrf52840dk_nrf52840.overlay b/samples/drivers/ht16k33/boards/nrf52840dk_nrf52840.overlay index 8618745dcf5..c9f820cdb58 100644 --- a/samples/drivers/ht16k33/boards/nrf52840dk_nrf52840.overlay +++ b/samples/drivers/ht16k33/boards/nrf52840dk_nrf52840.overlay @@ -13,8 +13,8 @@ /* Uncomment to use IRQ instead of polling: */ /* irq-gpios = <&gpio1 8 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; */ - keyscan { - compatible = "holtek,ht16k33-keyscan"; + kscan-input { + compatible = "zephyr,kscan-input"; }; }; }; diff --git a/samples/drivers/ht16k33/prj.conf b/samples/drivers/ht16k33/prj.conf index 462075dc5f6..fb580b93002 100644 --- a/samples/drivers/ht16k33/prj.conf +++ b/samples/drivers/ht16k33/prj.conf @@ -2,5 +2,5 @@ CONFIG_LOG=y CONFIG_I2C=y CONFIG_LED=y CONFIG_KSCAN=y -CONFIG_KSCAN_INIT_PRIORITY=95 +CONFIG_INPUT=y CONFIG_HT16K33_KEYSCAN=y diff --git a/samples/drivers/ht16k33/src/main.c b/samples/drivers/ht16k33/src/main.c index 72ef587cb39..7ede8c6a0d3 100644 --- a/samples/drivers/ht16k33/src/main.c +++ b/samples/drivers/ht16k33/src/main.c @@ -13,7 +13,7 @@ LOG_MODULE_REGISTER(main, CONFIG_LOG_DEFAULT_LEVEL); #define LED_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(holtek_ht16k33) -#define KEY_NODE DT_CHILD(LED_NODE, keyscan) +#define KEY_NODE DT_CHILD(LED_NODE, kscan_input) static void keyscan_callback(const struct device *dev, uint32_t row, uint32_t column, bool pressed) diff --git a/samples/drivers/i2c/custom_target/CMakeLists.txt b/samples/drivers/i2c/custom_target/CMakeLists.txt new file mode 100644 index 00000000000..1a1702c4216 --- /dev/null +++ b/samples/drivers/i2c/custom_target/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(i2c_custom_target) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/drivers/i2c/custom_target/README.rst b/samples/drivers/i2c/custom_target/README.rst new file mode 100644 index 00000000000..a3d86482888 --- /dev/null +++ b/samples/drivers/i2c/custom_target/README.rst @@ -0,0 +1,31 @@ +.. zephyr:code-sample:: i2c-custom-target + :name: I2C Custom Target + :relevant-api: i2c_interface + + Setup a custom I2C target on the I2C interface. + +Overview +******** + +This sample demonstrates how to setup an I2C custom target on the I2C interface +using the :ref:`i2c-target-api`. + +Requirements +************ + +This sample requires an I2C peripheral which is capable of acting as a target. + +This sample has been tested on :ref:`lpcxpresso55s69`. + +Building and Running +******************** + +The code for this sample can be found in :zephyr_file:`samples/drivers/i2c_target`. + +To build and flash the application: + +.. zephyr-app-commands:: + :zephyr-app: samples/drivers/i2c_target + :board: lpcxpresso55s69/lpc55s69/cpu0 + :goals: flash + :compact: diff --git a/samples/drivers/i2c/custom_target/boards/lpcxpresso55s69_lpc55s69_cpu0.overlay b/samples/drivers/i2c/custom_target/boards/lpcxpresso55s69_lpc55s69_cpu0.overlay new file mode 100644 index 00000000000..8826b80c552 --- /dev/null +++ b/samples/drivers/i2c/custom_target/boards/lpcxpresso55s69_lpc55s69_cpu0.overlay @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2024 Open Pixel Systems + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&flexcomm4 { + status = "okay"; +}; diff --git a/samples/drivers/i2c/custom_target/prj.conf b/samples/drivers/i2c/custom_target/prj.conf new file mode 100644 index 00000000000..f3d64527b85 --- /dev/null +++ b/samples/drivers/i2c/custom_target/prj.conf @@ -0,0 +1,2 @@ +CONFIG_I2C=y +CONFIG_I2C_TARGET=y diff --git a/samples/drivers/i2c/custom_target/sample.yaml b/samples/drivers/i2c/custom_target/sample.yaml new file mode 100644 index 00000000000..dd8cc903dbb --- /dev/null +++ b/samples/drivers/i2c/custom_target/sample.yaml @@ -0,0 +1,8 @@ +sample: + name: I2C custom target sample +tests: + sample.drivers.i2c.custom_target: + tags: i2c_target + platform_allow: + - lpcxpresso55s69/lpc55s69/cpu0 + harness: TBD diff --git a/samples/drivers/i2c/custom_target/src/main.c b/samples/drivers/i2c/custom_target/src/main.c new file mode 100644 index 00000000000..83a0003cb34 --- /dev/null +++ b/samples/drivers/i2c/custom_target/src/main.c @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2024 Open Pixel Systems + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +static const struct device *bus = DEVICE_DT_GET(DT_NODELABEL(flexcomm4)); +static char last_byte; + +/* + * @brief Callback which is called when a write request is received from the master. + * @param config Pointer to the target configuration. + */ +int sample_target_write_requested_cb(struct i2c_target_config *config) +{ + printk("sample target write requested\n"); + return 0; +} + +/* + * @brief Callback which is called when a write is received from the master. + * @param config Pointer to the target configuration. + * @param val The byte received from the master. + */ +int sample_target_write_received_cb(struct i2c_target_config *config, uint8_t val) +{ + printk("sample target write received: 0x%02x\n", val); + last_byte = val; + return 0; +} + +/* + * @brief Callback which is called when a read request is received from the master. + * @param config Pointer to the target configuration. + * @param val Pointer to the byte to be sent to the master. + */ +int sample_target_read_requested_cb(struct i2c_target_config *config, uint8_t *val) +{ + printk("sample target read request: 0x%02x\n", *val); + *val = 0x42; + return 0; +} + +/* + * @brief Callback which is called when a read is processed from the master. + * @param config Pointer to the target configuration. + * @param val Pointer to the next byte to be sent to the master. + */ +int sample_target_read_processed_cb(struct i2c_target_config *config, uint8_t *val) +{ + printk("sample target read processed: 0x%02x\n", *val); + *val = 0x43; + return 0; +} + +/* + * @brief Callback which is called when the master sends a stop condition. + * @param config Pointer to the target configuration. + */ +int sample_target_stop_cb(struct i2c_target_config *config) +{ + printk("sample target stop callback\n"); + return 0; +} + +static struct i2c_target_callbacks sample_target_callbacks = { + .write_requested = sample_target_write_requested_cb, + .write_received = sample_target_write_received_cb, + .read_requested = sample_target_read_requested_cb, + .read_processed = sample_target_read_processed_cb, + .stop = sample_target_stop_cb, +}; + +int main(void) +{ + struct i2c_target_config target_cfg = { + .address = 0x60, + .callbacks = &sample_target_callbacks, + }; + + printk("i2c custom target sample\n"); + + if (i2c_target_register(bus, &target_cfg) < 0) { + printk("Failed to register target\n"); + return -1; + } + + k_msleep(5000); + + if (i2c_target_unregister(bus, &target_cfg) < 0) { + printk("Failed to unregister target\n"); + return -1; + } + + return 0; +} diff --git a/samples/drivers/i2c/target_eeprom/CMakeLists.txt b/samples/drivers/i2c/target_eeprom/CMakeLists.txt new file mode 100644 index 00000000000..ecac4629ac0 --- /dev/null +++ b/samples/drivers/i2c/target_eeprom/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(i2c_target) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/drivers/i2c/target_eeprom/README.rst b/samples/drivers/i2c/target_eeprom/README.rst new file mode 100644 index 00000000000..6b91aa0c1f5 --- /dev/null +++ b/samples/drivers/i2c/target_eeprom/README.rst @@ -0,0 +1,31 @@ +.. zephyr:code-sample:: i2c-eeprom-target + :name: I2C Target + :relevant-api: i2c_interface + + Setup an I2C target on the I2C interface. + +Overview +******** + +This sample demonstrates how to setup and use the :ref:`i2c-target-api` using the +:dtcompatible:`zephyr,i2c-target-eeprom` device. + +Requirements +************ + +This sample requires an I2C peripheral which is capable of acting as a target. + +This sample has been tested on :ref:`lpcxpresso55s69`. + +Building and Running +******************** + +The code for this sample can be found in :zephyr_file:`samples/drivers/i2c_target`. + +To build and flash the application: + +.. zephyr-app-commands:: + :zephyr-app: samples/drivers/i2c_target + :board: lpcxpresso55s69/lpc55s69/cpu0 + :goals: flash + :compact: diff --git a/samples/drivers/i2c/target_eeprom/boards/lpcxpresso55s69_lpc55s69_cpu0.overlay b/samples/drivers/i2c/target_eeprom/boards/lpcxpresso55s69_lpc55s69_cpu0.overlay new file mode 100644 index 00000000000..ab2cc09bcaf --- /dev/null +++ b/samples/drivers/i2c/target_eeprom/boards/lpcxpresso55s69_lpc55s69_cpu0.overlay @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2024 Open Pixel Systems + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&flexcomm4 { + status = "okay"; + + eeprom0: eeprom@50 { + reg = <0x50>; + size = <256>; + compatible = "zephyr,i2c-target-eeprom"; + status = "okay"; + }; +}; diff --git a/samples/drivers/i2c/target_eeprom/prj.conf b/samples/drivers/i2c/target_eeprom/prj.conf new file mode 100644 index 00000000000..03350edd923 --- /dev/null +++ b/samples/drivers/i2c/target_eeprom/prj.conf @@ -0,0 +1,3 @@ +CONFIG_I2C=y +CONFIG_I2C_TARGET=y +CONFIG_I2C_EEPROM_TARGET=y diff --git a/samples/drivers/i2c/target_eeprom/sample.yaml b/samples/drivers/i2c/target_eeprom/sample.yaml new file mode 100644 index 00000000000..ed61e564b51 --- /dev/null +++ b/samples/drivers/i2c/target_eeprom/sample.yaml @@ -0,0 +1,9 @@ +sample: + name: I2C target sample +tests: + sample.drivers.i2c.target: + tags: i2c_target + filter: dt_nodelabel_enabled("target_eeprom") + platform_allow: + - lpcxpresso55s69/lpc55s69/cpu0 + harness: TBD diff --git a/samples/drivers/i2c/target_eeprom/src/main.c b/samples/drivers/i2c/target_eeprom/src/main.c new file mode 100644 index 00000000000..d1c42f9a401 --- /dev/null +++ b/samples/drivers/i2c/target_eeprom/src/main.c @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2024 Open Pixel Systems + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +static const struct device *eeprom = DEVICE_DT_GET(DT_NODELABEL(eeprom0)); + +int main(void) +{ + printk("i2c target sample\n"); + + if (!device_is_ready(eeprom)) { + printk("eeprom device not ready\n"); + return 0; + } + + if (i2c_target_driver_register(eeprom) < 0) { + printk("Failed to register i2c target driver\n"); + return 0; + } + + printk("i2c target driver registered\n"); + + k_msleep(1000); + + if (i2c_target_driver_unregister(eeprom) < 0) { + printk("Failed to unregister i2c target driver\n"); + return 0; + } + + printk("i2c target driver unregistered\n"); + + return 0; +} diff --git a/samples/drivers/ipm/ipm_esp32/boards/esp32_devkitc_wroom_esp32_procpu.overlay b/samples/drivers/ipm/ipm_esp32/boards/esp32_devkitc_wroom_procpu.overlay similarity index 100% rename from samples/drivers/ipm/ipm_esp32/boards/esp32_devkitc_wroom_esp32_procpu.overlay rename to samples/drivers/ipm/ipm_esp32/boards/esp32_devkitc_wroom_procpu.overlay diff --git a/samples/drivers/ipm/ipm_esp32/boards/esp32_devkitc_wrover_esp32_procpu.overlay b/samples/drivers/ipm/ipm_esp32/boards/esp32_devkitc_wrover_procpu.overlay similarity index 100% rename from samples/drivers/ipm/ipm_esp32/boards/esp32_devkitc_wrover_esp32_procpu.overlay rename to samples/drivers/ipm/ipm_esp32/boards/esp32_devkitc_wrover_procpu.overlay diff --git a/samples/drivers/ipm/ipm_esp32/boards/esp32s3_devkitm_esp32s3_procpu.overlay b/samples/drivers/ipm/ipm_esp32/boards/esp32s3_devkitm_procpu.overlay similarity index 100% rename from samples/drivers/ipm/ipm_esp32/boards/esp32s3_devkitm_esp32s3_procpu.overlay rename to samples/drivers/ipm/ipm_esp32/boards/esp32s3_devkitm_procpu.overlay diff --git a/samples/drivers/ipm/ipm_esp32/boards/yd_esp32_esp32_procpu.overlay b/samples/drivers/ipm/ipm_esp32/boards/yd_esp32_procpu.overlay similarity index 100% rename from samples/drivers/ipm/ipm_esp32/boards/yd_esp32_esp32_procpu.overlay rename to samples/drivers/ipm/ipm_esp32/boards/yd_esp32_procpu.overlay diff --git a/samples/drivers/jesd216/sample.yaml b/samples/drivers/jesd216/sample.yaml index 4ab18259153..c2742a68d46 100644 --- a/samples/drivers/jesd216/sample.yaml +++ b/samples/drivers/jesd216/sample.yaml @@ -29,5 +29,7 @@ tests: integration_platforms: - nrf52840dk/nrf52840 sample.drivers.stm32.jesd216: - filter: dt_compat_enabled("st,stm32-ospi-nor") or dt_compat_enabled("st,stm32-qspi-nor") + filter: dt_compat_enabled("st,stm32-xspi-nor") + or dt_compat_enabled("st,stm32-ospi-nor") + or dt_compat_enabled("st,stm32-qspi-nor") depends_on: spi diff --git a/samples/drivers/jesd216/src/main.c b/samples/drivers/jesd216/src/main.c index 92dd10208dd..7450df86ed2 100644 --- a/samples/drivers/jesd216/src/main.c +++ b/samples/drivers/jesd216/src/main.c @@ -20,6 +20,8 @@ #define FLASH_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(st_stm32_qspi_nor) #elif DT_HAS_COMPAT_STATUS_OKAY(st_stm32_ospi_nor) #define FLASH_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(st_stm32_ospi_nor) +#elif DT_HAS_COMPAT_STATUS_OKAY(st_stm32_xspi_nor) +#define FLASH_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(st_stm32_xspi_nor) #elif DT_HAS_COMPAT_STATUS_OKAY(nxp_s32_qspi_nor) #define FLASH_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(nxp_s32_qspi_nor) #elif DT_HAS_COMPAT_STATUS_OKAY(nxp_imx_flexspi_nor) diff --git a/samples/drivers/led_pwm/boards/ucans32k1sic.overlay b/samples/drivers/led_pwm/boards/ucans32k1sic.overlay new file mode 100644 index 00000000000..cd2ba599c4f --- /dev/null +++ b/samples/drivers/led_pwm/boards/ucans32k1sic.overlay @@ -0,0 +1,11 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&ftm0 { + clock-source = "fixed"; + clocks = <&clock NXP_S32_RTC_CLK>; + prescaler = <1>; +}; diff --git a/samples/drivers/led_strip/Kconfig b/samples/drivers/led_strip/Kconfig index 2931d4cc929..fdf12abde24 100644 --- a/samples/drivers/led_strip/Kconfig +++ b/samples/drivers/led_strip/Kconfig @@ -9,14 +9,6 @@ config SAMPLE_LED_UPDATE_DELAY help Delay between LED updates in ms. -config SAMPLE_LED_STRIP_LENGTH - int "LED strip length" - default 0 - help - Number of LEDs in the strip. - If the value is zero, use the 'chain-length' property in - devicetree instead to determine LED numbers. - endmenu source "Kconfig.zephyr" diff --git a/samples/drivers/led_strip/README.rst b/samples/drivers/led_strip/README.rst index a6b00327926..27c211e24e4 100644 --- a/samples/drivers/led_strip/README.rst +++ b/samples/drivers/led_strip/README.rst @@ -65,9 +65,6 @@ Building and Running The sample updates the LED strip periodically. The update frequency can be modified by changing the :kconfig:option:`CONFIG_SAMPLE_LED_UPDATE_DELAY`. -If there is no chain-length property in the devicetree node, you need to set -the number of LEDs in the :kconfig:option:`CONFIG_SAMPLE_LED_STRIP_LENGTH` option. - Then build and flash the application: .. zephyr-app-commands:: diff --git a/samples/drivers/led_strip/boards/96b_carbon_stm32f401xe.conf b/samples/drivers/led_strip/boards/96b_carbon_stm32f401xe.conf index 49fc84a0a95..0232f7d97c3 100644 --- a/samples/drivers/led_strip/boards/96b_carbon_stm32f401xe.conf +++ b/samples/drivers/led_strip/boards/96b_carbon_stm32f401xe.conf @@ -1,3 +1 @@ CONFIG_SPI_STM32_INTERRUPT=y - -CONFIG_SAMPLE_LED_STRIP_LENGTH=1 diff --git a/samples/drivers/led_strip/boards/96b_carbon_stm32f401xe.overlay b/samples/drivers/led_strip/boards/96b_carbon_stm32f401xe.overlay index b4be11a83a9..49bee930cca 100644 --- a/samples/drivers/led_strip/boards/96b_carbon_stm32f401xe.overlay +++ b/samples/drivers/led_strip/boards/96b_carbon_stm32f401xe.overlay @@ -4,12 +4,18 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include + &spi2 { lpd8806: lpd8806@0 { compatible = "greeled,lpd8806"; reg = <0>; spi-max-frequency = <2000000>; + chain-length = <1>; + color-mapping = ; }; }; diff --git a/samples/drivers/led_strip/boards/adafruit_itsybitsy.conf b/samples/drivers/led_strip/boards/adafruit_itsybitsy.conf deleted file mode 100644 index 9c347a35588..00000000000 --- a/samples/drivers/led_strip/boards/adafruit_itsybitsy.conf +++ /dev/null @@ -1 +0,0 @@ -CONFIG_SAMPLE_LED_STRIP_LENGTH=4 diff --git a/samples/drivers/led_strip/boards/adafruit_trinket_m0.conf b/samples/drivers/led_strip/boards/adafruit_trinket_m0.conf deleted file mode 100644 index af9d53eddc0..00000000000 --- a/samples/drivers/led_strip/boards/adafruit_trinket_m0.conf +++ /dev/null @@ -1 +0,0 @@ -CONFIG_SAMPLE_LED_STRIP_LENGTH=1 diff --git a/samples/drivers/led_strip/boards/blueclover_plt_demo_v2_nrf52832.conf b/samples/drivers/led_strip/boards/blueclover_plt_demo_v2_nrf52832.conf index e4aff43aee8..a97acd9ffab 100644 --- a/samples/drivers/led_strip/boards/blueclover_plt_demo_v2_nrf52832.conf +++ b/samples/drivers/led_strip/boards/blueclover_plt_demo_v2_nrf52832.conf @@ -1,3 +1,2 @@ # Enable LED 5V Regulator CONFIG_REGULATOR=y -CONFIG_SAMPLE_LED_STRIP_LENGTH=4 diff --git a/samples/drivers/led_strip/boards/esp32s3_devkitm_esp32s3_procpu.overlay b/samples/drivers/led_strip/boards/esp32s3_devkitm_procpu.overlay similarity index 100% rename from samples/drivers/led_strip/boards/esp32s3_devkitm_esp32s3_procpu.overlay rename to samples/drivers/led_strip/boards/esp32s3_devkitm_procpu.overlay diff --git a/samples/drivers/led_strip/boards/nucleo_l432kc.conf b/samples/drivers/led_strip/boards/nucleo_l432kc.conf deleted file mode 100644 index af9d53eddc0..00000000000 --- a/samples/drivers/led_strip/boards/nucleo_l432kc.conf +++ /dev/null @@ -1 +0,0 @@ -CONFIG_SAMPLE_LED_STRIP_LENGTH=1 diff --git a/samples/drivers/led_strip/boards/nucleo_l432kc.overlay b/samples/drivers/led_strip/boards/nucleo_l432kc.overlay index 0a7fce2fe75..383637d7717 100644 --- a/samples/drivers/led_strip/boards/nucleo_l432kc.overlay +++ b/samples/drivers/led_strip/boards/nucleo_l432kc.overlay @@ -4,12 +4,18 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include + &spi1 { apa102: apa102@0 { compatible = "apa,apa102"; reg = <0>; spi-max-frequency = <5250000>; + chain-length = <1>; + color-mapping = ; }; }; diff --git a/samples/drivers/led_strip/src/main.c b/samples/drivers/led_strip/src/main.c index d6dafcd68ea..45e8fad35cd 100644 --- a/samples/drivers/led_strip/src/main.c +++ b/samples/drivers/led_strip/src/main.c @@ -21,9 +21,7 @@ LOG_MODULE_REGISTER(main); #define STRIP_NODE DT_ALIAS(led_strip) -#if CONFIG_SAMPLE_LED_STRIP_LENGTH != 0 -#define STRIP_NUM_PIXELS CONFIG_SAMPLE_LED_STRIP_LENGTH -#elif DT_NODE_HAS_PROP(DT_ALIAS(led_strip), chain_length) +#if DT_NODE_HAS_PROP(DT_ALIAS(led_strip), chain_length) #define STRIP_NUM_PIXELS DT_PROP(DT_ALIAS(led_strip), chain_length) #else #error Unable to determine length of LED strip diff --git a/samples/drivers/mbox_data/remote/boards/lpcxpresso55s69_lpc55s69_cpu1.overlay b/samples/drivers/mbox_data/remote/boards/lpcxpresso55s69_lpc55s69_cpu1.overlay index a1cfbf7224d..c0d1a027087 100644 --- a/samples/drivers/mbox_data/remote/boards/lpcxpresso55s69_lpc55s69_cpu1.overlay +++ b/samples/drivers/mbox_data/remote/boards/lpcxpresso55s69_lpc55s69_cpu1.overlay @@ -29,7 +29,7 @@ mbox-consumer { compatible = "vnd,mbox-consumer"; - mboxes = <&mbox 2>, <&mbox 3>; + mboxes = <&mbox 3>, <&mbox 2>; mbox-names = "tx", "rx"; }; }; diff --git a/samples/drivers/mbox_data/remote/boards/mimxrt1160_evk_mimxrt1166_cm4.overlay b/samples/drivers/mbox_data/remote/boards/mimxrt1160_evk_mimxrt1166_cm4.overlay index c4cbef58d77..42453413134 100644 --- a/samples/drivers/mbox_data/remote/boards/mimxrt1160_evk_mimxrt1166_cm4.overlay +++ b/samples/drivers/mbox_data/remote/boards/mimxrt1160_evk_mimxrt1166_cm4.overlay @@ -43,7 +43,7 @@ mbox-consumer { compatible = "vnd,mbox-consumer"; - mboxes = <&mbox 3>, <&mbox 2>; + mboxes = <&mbox 2>, <&mbox 3>; mbox-names = "tx", "rx"; }; }; diff --git a/samples/drivers/mbox_data/remote/boards/mimxrt1170_evk_mimxrt1176_cm4.overlay b/samples/drivers/mbox_data/remote/boards/mimxrt1170_evk_mimxrt1176_cm4.overlay index c4cbef58d77..42453413134 100644 --- a/samples/drivers/mbox_data/remote/boards/mimxrt1170_evk_mimxrt1176_cm4.overlay +++ b/samples/drivers/mbox_data/remote/boards/mimxrt1170_evk_mimxrt1176_cm4.overlay @@ -43,7 +43,7 @@ mbox-consumer { compatible = "vnd,mbox-consumer"; - mboxes = <&mbox 3>, <&mbox 2>; + mboxes = <&mbox 2>, <&mbox 3>; mbox-names = "tx", "rx"; }; }; diff --git a/samples/drivers/mbox_data/remote/boards/mimxrt1170_evk_mimxrt1176_cm4_B.overlay b/samples/drivers/mbox_data/remote/boards/mimxrt1170_evk_mimxrt1176_cm4_B.overlay index c4cbef58d77..42453413134 100644 --- a/samples/drivers/mbox_data/remote/boards/mimxrt1170_evk_mimxrt1176_cm4_B.overlay +++ b/samples/drivers/mbox_data/remote/boards/mimxrt1170_evk_mimxrt1176_cm4_B.overlay @@ -43,7 +43,7 @@ mbox-consumer { compatible = "vnd,mbox-consumer"; - mboxes = <&mbox 3>, <&mbox 2>; + mboxes = <&mbox 2>, <&mbox 3>; mbox-names = "tx", "rx"; }; }; diff --git a/samples/drivers/memc/boards/rd_rw612_bga.conf b/samples/drivers/memc/boards/rd_rw612_bga.conf new file mode 100644 index 00000000000..f76b8554671 --- /dev/null +++ b/samples/drivers/memc/boards/rd_rw612_bga.conf @@ -0,0 +1,22 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +# In order to safely access the PSRAM on port B of the RW FlexSPI peripheral, +# the QSPI flash on port A must be configured by the application. Otherwise, +# the PSRAM configuration will overwrite the LUT entries for the QSPI flash, +# and the application will no longer be able to XIP from the flash. +# To make sure the QSPI flash is configured, enable flash drivers. +CONFIG_FLASH=y + +# Initialization priorities are critical here. The FlexSPI MEMC driver must +# initialize first. Then, the QSPI flash driver must initialize to program +# the LUT table for port A. Finally, the PSRAM driver can initialize and +# program the LUT table for port B +CONFIG_MEMC_MCUX_FLEXSPI_INIT_PRIORITY=0 +CONFIG_FLASH_INIT_PRIORITY=50 +CONFIG_MEMC_INIT_PRIORITY=60 + +# This board has the PSRAM attached to the same FLEXSPI device as the flash +# chip used for XIP, so we must explicitly enable the FLEXSPI MEMC driver +# to reconfigure the flash device it is executing from +CONFIG_MEMC_MCUX_FLEXSPI_INIT_XIP=y diff --git a/samples/drivers/memc/boards/rd_rw612_bga.overlay b/samples/drivers/memc/boards/rd_rw612_bga.overlay new file mode 100644 index 00000000000..e32be713e3b --- /dev/null +++ b/samples/drivers/memc/boards/rd_rw612_bga.overlay @@ -0,0 +1,42 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + sram-ext = &is66wvq8m4; + }; +}; + +&is66wvq8m4 { + status = "okay"; +}; + +&pinctrl { + pinmux_flexspi_safe: pinmux-flexspi-safe { + group0 { + pinmux = ; + slew-rate = "normal"; + }; + + group1 { + pinmux = ; + slew-rate = "normal"; + bias-pull-down; + }; + }; +}; + +/* Override pin control state to use one that only changes the PSRAM pin + * configuration + */ +&flexspi { + pinctrl-0 = <&pinmux_flexspi_safe>; +}; diff --git a/samples/drivers/memc/src/main.c b/samples/drivers/memc/src/main.c index 1347cce2b12..901eb064fb1 100644 --- a/samples/drivers/memc/src/main.c +++ b/samples/drivers/memc/src/main.c @@ -12,8 +12,14 @@ #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_BASE ((void *)memc_flexspi_get_ahb_address(FLEXSPI_DEV, MEMC_PORT, 0)) #define MEMC_SIZE (DT_PROP(DT_ALIAS(sram_ext), size) / 8) +#elif DT_HAS_COMPAT_STATUS_OKAY(renesas_smartbond_nor_psram) +#include +#define MEMC_BASE ((void *)MCU_QSPIR_M_BASE) +#define MEMC_SIZE (DT_PROP(DT_ALIAS(sram_ext), dev_size) / 8) +#else +#error At least one driver should be selected! #endif void dump_memory(uint8_t *p, uint32_t size) diff --git a/samples/drivers/spi_flash/boards/nrf54h20dk_nrf54h20_cpuapp.overlay b/samples/drivers/spi_flash/boards/nrf54h20dk_nrf54h20_cpuapp.overlay new file mode 100644 index 00000000000..d03419690bd --- /dev/null +++ b/samples/drivers/spi_flash/boards/nrf54h20dk_nrf54h20_cpuapp.overlay @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&mx25uw63 { + status = "okay"; +}; + + +/ { + aliases { + spi-flash0 = &mx25uw63; + }; +}; diff --git a/samples/drivers/spi_flash/sample.yaml b/samples/drivers/spi_flash/sample.yaml index b3bec006e9c..b7c7a069243 100644 --- a/samples/drivers/spi_flash/sample.yaml +++ b/samples/drivers/spi_flash/sample.yaml @@ -6,7 +6,7 @@ tests: - spi - 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("st,stm32-ospi-nor") or dt_compat_enabled("st,stm32-xspi-nor") or (dt_compat_enabled("nordic,qspi-nor") and CONFIG_NORDIC_QSPI_NOR) platform_exclude: hifive_unmatched harness: console diff --git a/samples/drivers/spi_flash/src/main.c b/samples/drivers/spi_flash/src/main.c index 2faadd309c6..e456b511030 100644 --- a/samples/drivers/spi_flash/src/main.c +++ b/samples/drivers/spi_flash/src/main.c @@ -26,7 +26,9 @@ #endif #define SPI_FLASH_SECTOR_SIZE 4096 -#if defined(CONFIG_FLASH_STM32_OSPI) || defined(CONFIG_FLASH_STM32_QSPI) +#if defined(CONFIG_FLASH_STM32_OSPI) || \ + defined(CONFIG_FLASH_STM32_QSPI) || \ + defined(CONFIG_FLASH_STM32_XSPI) #define SPI_FLASH_MULTI_SECTOR_TEST #endif diff --git a/samples/drivers/watchdog/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay b/samples/drivers/watchdog/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay index 66157d79fb3..5c765a8a896 100644 --- a/samples/drivers/watchdog/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay +++ b/samples/drivers/watchdog/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay @@ -3,6 +3,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -&wdt30 { +&wdt31 { status = "okay"; }; diff --git a/samples/drivers/watchdog/boards/nrf54l15pdk_nrf54l15_cpuflpr.overlay b/samples/drivers/watchdog/boards/nrf54l15pdk_nrf54l15_cpuflpr.overlay index 66157d79fb3..5c765a8a896 100644 --- a/samples/drivers/watchdog/boards/nrf54l15pdk_nrf54l15_cpuflpr.overlay +++ b/samples/drivers/watchdog/boards/nrf54l15pdk_nrf54l15_cpuflpr.overlay @@ -3,6 +3,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -&wdt30 { +&wdt31 { status = "okay"; }; diff --git a/samples/drivers/watchdog/boards/nrf54l15pdk_nrf54l15_cpuflpr_xip.overlay b/samples/drivers/watchdog/boards/nrf54l15pdk_nrf54l15_cpuflpr_xip.overlay index 66157d79fb3..5c765a8a896 100644 --- a/samples/drivers/watchdog/boards/nrf54l15pdk_nrf54l15_cpuflpr_xip.overlay +++ b/samples/drivers/watchdog/boards/nrf54l15pdk_nrf54l15_cpuflpr_xip.overlay @@ -3,6 +3,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -&wdt30 { +&wdt31 { status = "okay"; }; diff --git a/samples/index.rst b/samples/index.rst index 8581a330d40..0120c87769d 100644 --- a/samples/index.rst +++ b/samples/index.rst @@ -13,6 +13,7 @@ Samples and Demos classic basic/* userspace/* + sysbuild/* subsys/subsys.rst net/net.rst bluetooth/bluetooth.rst diff --git a/samples/modules/canopennode/sample.yaml b/samples/modules/canopennode/sample.yaml index 7cc95c0ed17..f85c50138bd 100644 --- a/samples/modules/canopennode/sample.yaml +++ b/samples/modules/canopennode/sample.yaml @@ -15,15 +15,10 @@ common: - "(.*)CANopen stack initialized" tests: sample.modules.canopennode: - filter: dt_label_with_parent_compat_enabled("storage_partition", "fixed-partitions") - and dt_chosen_enabled("zephyr,flash-controller") and CONFIG_FLASH_HAS_DRIVER_ENABLED - platform_exclude: - - nucleo_h723zg - - nucleo_h743zi - - nucleo_h745zi_q/stm32h745xx/m7 - - nucleo_h753zi + depends_on: nvs sample.modules.canopennode.program_download: sysbuild: true + depends_on: nvs platform_allow: - frdm_k64f - twr_ke18f diff --git a/samples/modules/canopennode/src/main.c b/samples/modules/canopennode/src/main.c index c470e1f1732..60c3ebaa6df 100644 --- a/samples/modules/canopennode/src/main.c +++ b/samples/modules/canopennode/src/main.c @@ -15,7 +15,8 @@ LOG_MODULE_REGISTER(app); #define CAN_INTERFACE DEVICE_DT_GET(DT_CHOSEN(zephyr_canbus)) -#define CAN_BITRATE (DT_PROP(DT_CHOSEN(zephyr_canbus), bus_speed) / 1000) +#define CAN_BITRATE (DT_PROP_OR(DT_CHOSEN(zephyr_canbus), bus_speed, \ + CONFIG_CAN_DEFAULT_BITRATE) / 1000) static struct gpio_dt_spec led_green_gpio = GPIO_DT_SPEC_GET_OR( DT_ALIAS(green_led), gpios, {0}); diff --git a/samples/modules/lvgl/demos/boards/m5stack_core2.conf b/samples/modules/lvgl/demos/boards/m5stack_core2_procpu.conf similarity index 100% rename from samples/modules/lvgl/demos/boards/m5stack_core2.conf rename to samples/modules/lvgl/demos/boards/m5stack_core2_procpu.conf diff --git a/samples/net/cellular_modem/boards/nrf9160dk_nrf52840.overlay b/samples/net/cellular_modem/boards/nrf9160dk_nrf52840.overlay index c639ec8b305..6fd249e01c4 100644 --- a/samples/net/cellular_modem/boards/nrf9160dk_nrf52840.overlay +++ b/samples/net/cellular_modem/boards/nrf9160dk_nrf52840.overlay @@ -1,4 +1,4 @@ -#include +#include / { aliases { diff --git a/samples/net/cellular_modem/prj.conf b/samples/net/cellular_modem/prj.conf index 345d49bf463..4656fe52d65 100644 --- a/samples/net/cellular_modem/prj.conf +++ b/samples/net/cellular_modem/prj.conf @@ -26,6 +26,10 @@ CONFIG_MODEM=y CONFIG_PM_DEVICE=y CONFIG_MODEM_CELLULAR=y +# Statistics +CONFIG_MODEM_STATS=y +CONFIG_SHELL=y + # Logging CONFIG_LOG=y CONFIG_MODEM_MODULES_LOG_LEVEL_DBG=y diff --git a/samples/net/cloud/mqtt_azure/src/main.c b/samples/net/cloud/mqtt_azure/src/main.c index 46ee6c66820..841c1fb7ebe 100644 --- a/samples/net/cloud/mqtt_azure/src/main.c +++ b/samples/net/cloud/mqtt_azure/src/main.c @@ -8,6 +8,7 @@ LOG_MODULE_REGISTER(mqtt_azure, LOG_LEVEL_DBG); #include +#include #include #include diff --git a/samples/net/dns_resolve/sample.yaml b/samples/net/dns_resolve/sample.yaml index f5808607b57..cafc9beac83 100644 --- a/samples/net/dns_resolve/sample.yaml +++ b/samples/net/dns_resolve/sample.yaml @@ -4,6 +4,9 @@ common: tags: - net - dns + platform_exclude: + - native_posix + - native_posix/native/64 sample: description: DNS resolver, mDNS and LLMNR responder name: DNS resolver and responder sample application diff --git a/samples/net/dsa/boards/ip_k66f.overlay b/samples/net/dsa/boards/ip_k66f.overlay index 3089ccb6850..94af8499b83 100644 --- a/samples/net/dsa/boards/ip_k66f.overlay +++ b/samples/net/dsa/boards/ip_k66f.overlay @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -&enet { +&enet_mac { local-mac-address = [00 00 12 13 00 10]; }; diff --git a/samples/net/dsa/prj.conf b/samples/net/dsa/prj.conf index 153ae38526b..84a2317555f 100644 --- a/samples/net/dsa/prj.conf +++ b/samples/net/dsa/prj.conf @@ -57,8 +57,6 @@ CONFIG_NET_CONFIG_MY_IPV4_ADDR="192.168.0.2" CONFIG_NET_CONFIG_MY_IPV4_GW="192.168.0.1" CONFIG_NET_CONFIG_MY_IPV6_ADDR="2001:db8::1" -CONFIG_ETH_MCUX_PROMISCUOUS_MODE=y - # Add RTT SHELL support -> Instead of LOG_BACKEND_RTT # Shell can be used to test the DSA operation with e.g. # 'net ping -I3 192.168.0.1' diff --git a/samples/net/gptp/boards/frdm_k64f.conf b/samples/net/gptp/boards/frdm_k64f.conf index a73c4f17a8f..77feba887e4 100644 --- a/samples/net/gptp/boards/frdm_k64f.conf +++ b/samples/net/gptp/boards/frdm_k64f.conf @@ -1,5 +1,3 @@ -# MCUX driver settings -CONFIG_PTP_CLOCK_MCUX=y CONFIG_NET_CONFIG_MY_IPV6_ADDR="2001:db8::2" CONFIG_NET_CONFIG_PEER_IPV6_ADDR="2001:db8::1" CONFIG_NET_CONFIG_MY_IPV4_ADDR="192.0.2.2" diff --git a/samples/net/gptp/boards/mimxrt1020_evk.conf b/samples/net/gptp/boards/mimxrt1020_evk.conf deleted file mode 100644 index 8842768510b..00000000000 --- a/samples/net/gptp/boards/mimxrt1020_evk.conf +++ /dev/null @@ -1,2 +0,0 @@ -CONFIG_PTP_CLOCK_MCUX=y -CONFIG_ETH_MCUX_PTP_CLOCK_SRC_HZ=25000000 diff --git a/samples/net/gptp/boards/mimxrt1050_evk.conf b/samples/net/gptp/boards/mimxrt1050_evk.conf index 2819d3afd66..ac370d355e1 100644 --- a/samples/net/gptp/boards/mimxrt1050_evk.conf +++ b/samples/net/gptp/boards/mimxrt1050_evk.conf @@ -1,11 +1,9 @@ -CONFIG_PTP_CLOCK_MCUX=y CONFIG_NET_CONFIG_MY_IPV6_ADDR="2001:db8::2" CONFIG_NET_CONFIG_PEER_IPV6_ADDR="2001:db8::1" CONFIG_NET_CONFIG_MY_IPV4_ADDR="192.0.2.2" CONFIG_NET_CONFIG_PEER_IPV4_ADDR="192.0.2.1" -CONFIG_ETH_MCUX_PTP_CLOCK_SRC_HZ=25000000 -CONFIG_ETH_MCUX_RX_BUFFERS=6 -CONFIG_ETH_MCUX_TX_BUFFERS=4 +CONFIG_ETH_NXP_ENET_RX_BUFFERS=6 +CONFIG_ETH_NXP_ENET_TX_BUFFERS=4 CONFIG_NET_GPTP_STATISTICS=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 114cebd8fe8..8217ac210c7 100644 --- a/samples/net/gptp/boards/mimxrt1060_evk.conf +++ b/samples/net/gptp/boards/mimxrt1060_evk.conf @@ -1,10 +1,8 @@ -CONFIG_PTP_CLOCK_MCUX=y -CONFIG_ETH_MCUX_PTP_CLOCK_SRC_HZ=25000000 CONFIG_NET_GPTP_NEIGHBOR_PROP_DELAY_THR=1000000 CONFIG_NET_GPTP_PROBE_CLOCK_SOURCE_ON_DEMAND=y CONFIG_NET_GPTP_CLOCK_ACCURACY_25MS=y -#CONFIG_ETH_MCUX_RX_BUFFERS=6 -#CONFIG_ETH_MCUX_TX_BUFFERS=8 +#CONFIG_ETH_NXP_ENET_RX_BUFFERS=6 +#CONFIG_ETH_NXP_ENET_TX_BUFFERS=8 CONFIG_NET_GPTP_STATISTICS=y CONFIG_REQUIRES_FLOAT_PRINTF=y CONFIG_REQUIRES_FULL_LIBC=y diff --git a/samples/net/gptp/sample.yaml b/samples/net/gptp/sample.yaml index 93d1d9aa498..b0a49d24139 100644 --- a/samples/net/gptp/sample.yaml +++ b/samples/net/gptp/sample.yaml @@ -21,10 +21,3 @@ tests: depends_on: eth integration_platforms: - frdm_k64f - sample.net.gpt.nxp_enet_experimental: - extra_args: EXTRA_DTC_OVERLAY_FILE="nxp,enet-experimental.overlay" - platform_allow: - - mimxrt1050_evk - - mimxrt1060_evk - - mimxrt1064_evk - - mimxrt1024_evk diff --git a/samples/net/lwm2m_client/README.rst b/samples/net/lwm2m_client/README.rst index 2225f789c0c..42759f6b204 100644 --- a/samples/net/lwm2m_client/README.rst +++ b/samples/net/lwm2m_client/README.rst @@ -49,9 +49,6 @@ samples/net/lwm2m_client directory: * - :file:`overlay-dtls.conf` - This overlay config can be added for DTLS support via MBEDTLS. - * - :file:`overlay-bt.conf` - - This overlay config can be added to enable Bluetooth networking support. - * - :file:`overlay-queue.conf` - This overlay config can be added to enable LWM2M Queue Mode support. @@ -179,32 +176,6 @@ the overlay file for Bootstrap over DTLS (5784 in case of Leshan Demo Bootstrap Server) and to configure correct security mode in the ``LWM2M Bootstrap Server`` tab in the web UI (Pre-shared Key). -Bluetooth Support -================= - -To build the lwm2m-client sample for hardware requiring Bluetooth for -networking (IPSP node connected via 6lowpan) do the following: - -.. zephyr-app-commands:: - :zephyr-app: samples/net/lwm2m_client - :host-os: unix - :board: - :conf: "prj.conf overlay-bt.conf" - :goals: build - :compact: - -The overlay-\*.conf files can also be combined. For example, you could build a -DTLS-enabled LwM2M client sample for BLENano2 hardware by using the following -commands (requires Bluetooth for networking): - -.. zephyr-app-commands:: - :zephyr-app: samples/net/lwm2m_client - :host-os: unix - :board: nrf52_blenano2 - :conf: "prj.conf overlay-bt.conf overlay-dtls.conf" - :goals: build - :compact: - OpenThread Support ================== diff --git a/samples/net/lwm2m_client/overlay-bt.conf b/samples/net/lwm2m_client/overlay-bt.conf deleted file mode 100644 index 01c59b599eb..00000000000 --- a/samples/net/lwm2m_client/overlay-bt.conf +++ /dev/null @@ -1,13 +0,0 @@ -CONFIG_BT=y -CONFIG_LOG=y -CONFIG_BT_SMP=y -CONFIG_BT_PERIPHERAL=y -CONFIG_BT_CENTRAL=y -CONFIG_BT_L2CAP_DYNAMIC_CHANNEL=y -CONFIG_BT_DEVICE_NAME="LwM2M IPSP node" -CONFIG_NET_L2_BT=y -CONFIG_NET_CONFIG_BT_NODE=y - -# raise bluetooth RX buffer settings for 6lowpan traffic -CONFIG_BT_BUF_ACL_RX_COUNT=20 -CONFIG_BT_BUF_ACL_RX_SIZE=124 diff --git a/samples/net/lwm2m_client/sample.yaml b/samples/net/lwm2m_client/sample.yaml index 29fccca4416..f70290d287e 100644 --- a/samples/net/lwm2m_client/sample.yaml +++ b/samples/net/lwm2m_client/sample.yaml @@ -52,17 +52,6 @@ tests: tags: - net - lwm2m - sample.net.lwm2m_client.bt: - harness: net - extra_args: OVERLAY_CONFIG=overlay-bt.conf - platform_allow: - - nrf52840dk/nrf52840 - - disco_l475_iot1 - tags: - - net - - lwm2m - integration_platforms: - - disco_l475_iot1 sample.net.lwm2m_client.queue_mode: harness: net depends_on: netif diff --git a/samples/net/lwm2m_client/src/firmware_update.c b/samples/net/lwm2m_client/src/firmware_update.c index dd6dcd8d599..5ef2e1cf127 100644 --- a/samples/net/lwm2m_client/src/firmware_update.c +++ b/samples/net/lwm2m_client/src/firmware_update.c @@ -38,13 +38,13 @@ static void *firmware_get_buf(uint16_t obj_inst_id, uint16_t res_id, return firmware_buf; } -static int firmware_block_received_cb(uint16_t obj_inst_id, - uint16_t res_id, uint16_t res_inst_id, - uint8_t *data, uint16_t data_len, - bool last_block, size_t total_size) +static int firmware_block_received_cb(uint16_t obj_inst_id, uint16_t res_id, + uint16_t res_inst_id, uint8_t *data, + uint16_t data_len, bool last_block, + size_t total_size, size_t offset) { - LOG_INF("FIRMWARE: BLOCK RECEIVED: len:%u last_block:%d", - data_len, last_block); + LOG_INF("FIRMWARE: BLOCK RECEIVED: offset:%zd len:%u last_block:%d", + offset, data_len, last_block); return 0; } diff --git a/samples/net/lwm2m_client/src/led.c b/samples/net/lwm2m_client/src/led.c index 98055baa580..d4aa6388890 100644 --- a/samples/net/lwm2m_client/src/led.c +++ b/samples/net/lwm2m_client/src/led.c @@ -22,7 +22,7 @@ static uint32_t led_state; /* TODO: Move to a pre write hook that can handle ret codes once available */ static int led_on_off_cb(uint16_t obj_inst_id, uint16_t res_id, uint16_t res_inst_id, uint8_t *data, - uint16_t data_len, bool last_block, size_t total_size) + uint16_t data_len, bool last_block, size_t total_size, size_t offset) { int ret = 0; uint32_t led_val; diff --git a/samples/net/lwm2m_client/src/timer.c b/samples/net/lwm2m_client/src/timer.c index 17814ae134c..86107451344 100644 --- a/samples/net/lwm2m_client/src/timer.c +++ b/samples/net/lwm2m_client/src/timer.c @@ -17,7 +17,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); /* An example data validation callback. */ static int timer_on_off_validate_cb(uint16_t obj_inst_id, uint16_t res_id, uint16_t res_inst_id, uint8_t *data, uint16_t data_len, bool last_block, - size_t total_size) + size_t total_size, size_t offset) { LOG_INF("Validating On/Off data"); @@ -34,7 +34,7 @@ static int timer_on_off_validate_cb(uint16_t obj_inst_id, uint16_t res_id, uint1 static int timer_digital_state_cb(uint16_t obj_inst_id, uint16_t res_id, uint16_t res_inst_id, uint8_t *data, uint16_t data_len, bool last_block, - size_t total_size) + size_t total_size, size_t offset) { bool *digital_state = (bool *)data; diff --git a/samples/net/mdns_responder/overlay-bt.conf b/samples/net/mdns_responder/overlay-bt.conf deleted file mode 100644 index ad6ca65e38e..00000000000 --- a/samples/net/mdns_responder/overlay-bt.conf +++ /dev/null @@ -1,17 +0,0 @@ -CONFIG_BT=y -CONFIG_LOG=y -CONFIG_BT_SMP=y -CONFIG_BT_PERIPHERAL=y -CONFIG_BT_CENTRAL=y -CONFIG_BT_L2CAP_DYNAMIC_CHANNEL=y -CONFIG_BT_DEVICE_NAME="Zephyr Echo Server" -CONFIG_NET_L2_BT=y -CONFIG_NET_IPV4=n -CONFIG_NET_IPV6=y -CONFIG_NET_CONFIG_BT_NODE=y -CONFIG_NET_CONFIG_NEED_IPV6=y -CONFIG_NET_IPV4=n -CONFIG_NET_CONFIG_NEED_IPV4=n -CONFIG_NET_CONFIG_MY_IPV4_ADDR="" -CONFIG_NET_CONFIG_PEER_IPV4_ADDR="" -CONFIG_NET_CONFIG_MY_IPV4_GW="" diff --git a/samples/net/mdns_responder/prj.conf b/samples/net/mdns_responder/prj.conf index db58992f3f8..644067671b4 100644 --- a/samples/net/mdns_responder/prj.conf +++ b/samples/net/mdns_responder/prj.conf @@ -27,6 +27,7 @@ CONFIG_PRINTK=y CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=3 CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=5 +CONFIG_NET_IF_MCAST_IPV4_ADDR_COUNT=3 CONFIG_NET_PKT_RX_COUNT=10 CONFIG_NET_PKT_TX_COUNT=10 diff --git a/samples/net/mqtt_publisher/overlay-bt.conf b/samples/net/mqtt_publisher/overlay-bt.conf deleted file mode 100644 index 9151d577057..00000000000 --- a/samples/net/mqtt_publisher/overlay-bt.conf +++ /dev/null @@ -1,15 +0,0 @@ -CONFIG_BT=y -CONFIG_LOG=y -CONFIG_BT_SMP=y -CONFIG_BT_PERIPHERAL=y -CONFIG_BT_CENTRAL=y -CONFIG_BT_L2CAP_DYNAMIC_CHANNEL=y -CONFIG_BT_DEVICE_NAME="Zephyr MQTT" -CONFIG_NET_L2_BT=y -CONFIG_NET_IPV4=n -CONFIG_NET_IPV6=y -CONFIG_NET_CONFIG_BT_NODE=y -CONFIG_NET_CONFIG_NEED_IPV6=y -CONFIG_NET_CONFIG_NEED_IPV4=n -CONFIG_NET_CONFIG_MY_IPV4_ADDR="" -CONFIG_NET_CONFIG_PEER_IPV4_ADDR="" diff --git a/samples/net/secure_mqtt_sensor_actuator/CMakeLists.txt b/samples/net/secure_mqtt_sensor_actuator/CMakeLists.txt new file mode 100644 index 00000000000..af4feece2dc --- /dev/null +++ b/samples/net/secure_mqtt_sensor_actuator/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(secure_mqtt_sensor_actuator) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) + +zephyr_include_directories(${APPLICATION_SOURCE_DIR}/src/tls_config) diff --git a/samples/net/secure_mqtt_sensor_actuator/Kconfig b/samples/net/secure_mqtt_sensor_actuator/Kconfig new file mode 100644 index 00000000000..19d15187acf --- /dev/null +++ b/samples/net/secure_mqtt_sensor_actuator/Kconfig @@ -0,0 +1,58 @@ +# Copyright (c) 2024 Analog Devices, Inc. +# SPDX-License-Identifier: Apache-2.0 + +mainmenu "Secure MQTT Sensor Actuator Sample Application" + +config NET_SAMPLE_MQTT_BROKER_HOSTNAME + string "Hostname of MQTT broker" + default "test.mosquitto.org" + help + MQTT broker's hostname or IP address. + +config NET_SAMPLE_MQTT_BROKER_PORT + string "MQTT Broker Connection Port" + default "8883" + help + Port through which the application should connect to the MQTT broker. + Secure MQTT uses port 8883. + +config NET_SAMPLE_MQTT_PUB_TOPIC + string "The MQTT topic the application should publish data to" + default "zephyr_sample/sensor" + +config NET_SAMPLE_MQTT_SUB_TOPIC_CMD + string "The MQTT topic the application will receive commands on" + default "zephyr_sample/command" + +config NET_SAMPLE_MQTT_PUBLISH_INTERVAL + int "Interval between MQTT publishes (in seconds)" + default 3 + help + This config determines the frequency at which MQTT publishes occur. + +choice NET_SAMPLE_MQTT_QOS + prompt "Quality of Service level used for MQTT publish and subscribe" + default NET_SAMPLE_MQTT_QOS_1_AT_LEAST_ONCE + +config NET_SAMPLE_MQTT_QOS_0_AT_MOST_ONCE + bool "QoS 0 / At most once delivery" + help + No acknowledgment needed for published message. + +config NET_SAMPLE_MQTT_QOS_1_AT_LEAST_ONCE + bool "QoS 1 / At least once delivery" + help + If acknowledgment expected for published message, duplicate messages permitted. + +config NET_SAMPLE_MQTT_QOS_2_EXACTLY_ONCE + bool "QoS 2 / Exactly once delivery" + help + Acknowledgment expected and message shall be published only once. + +endchoice + +config NET_SAMPLE_MQTT_PAYLOAD_SIZE + int "Size of MQTT payload in bytes" + default 128 + +source "Kconfig.zephyr" diff --git a/samples/net/secure_mqtt_sensor_actuator/README.rst b/samples/net/secure_mqtt_sensor_actuator/README.rst new file mode 100644 index 00000000000..b2ff6a1573c --- /dev/null +++ b/samples/net/secure_mqtt_sensor_actuator/README.rst @@ -0,0 +1,219 @@ +.. zephyr:code-sample:: secure-mqtt-sensor-actuator + :name: Secure MQTT Sensor/Actuator + :relevant-api: mqtt_socket sensor_interface + + Implement an MQTT-based IoT sensor/actuator device + +Overview +******** + +This sample demonstrates the implementation of an IoT sensor/actuator device. +The application uses the MQTT protocol to securely send sensor data +to a remote MQTT broker, while responding to commands received over MQTT. + +Features: + +- Establishing network connectivity using a DHCPv4 lease +- Establishing a secure MQTT connection (using TLS 1.2) to MQTT broker +- Publishing temperature sensor data in JSON format to the MQTT broker at a user-defined interval +- Subscribing to user-defined topic(s) on MQTT broker +- Responding to commands received over the network (LED control) +- Handling of MQTT connection, re-connecting and keep-alive +- Network status LED + +Requirements +************ +- Board with network capability (tested with adi_eval_adin1110ebz) +- `Eclipse Mosquitto`_ MQTT broker +- DHCP server +- Network connection between the board and Mosquitto broker + +Build and Running +***************** +This application relies on an network connection between the board and an MQTT broker. +This broker can exist locally (e.g. on a host PC) or a publicly available MQTT broker + can be used. +For quick sampling/testing, a configuration is provided to connect to a local MQTT broker +without security, using a static IP address. + +Hardware Setup +============== +If using Ethernet, connect the board to the MQTT broker. This may be your host PC +(for locally hosted Mosquitto broker) or your internet router +(to connect to the public Mosquitto broker). +If required, connect a temperature sensor to the board. + +Software Setup +============== +The temperature sensor should be aliased in devicetree as ``ambient-temp0``. +If a board does not include an on-board temperature sensor, one can be connected externally +and a board overlay file used to add the sensor and alias: + +.. code-block:: devicetree + + / { + aliases { + ambient-temp0 = &adt7420; + }; + }; + }; + +It is possible to use other types of sensors, by adding them in devicetree and by changing +``SENSOR_CHAN`` :file:`in device.c` to match the desired sensor type. + +There are a few ways to configure the application: + +.. list-table:: + + * - :file:`prj.conf` + - Default config: Secure MQTT, dynamic IP address (DHCP) + + * - :file:`overlay-static.conf` + - Secure MQTT, static IP address + + * - :file:`overlay-static-insecure.conf` + - Unsecure MQTT, static IP address + +**Default Config:** + +Using the default config, the application will use DHCP to acquire an IP address and attempt +to securely connect to an MQTT broker using TLS 1.2. + +- The MQTT broker to which the board will connect is specified by + ``CONFIG_NET_SAMPLE_MQTT_BROKER_HOSTNAME``. + By default, this is set to test.mosquitto.org. +- Connecting securely using TLS, requires the inclusion of the broker's CA certificate + in the application. +- Download the CA certificate in DER or PEM format from https://test.mosquitto.org +- In :file:`tls_config/cert.h`, set ``ca_certificate[]`` to the contents of the cert. +- By connecting the board to your internet router, it should automatically be assigned + an IPv4 address using DHCP. +- The application will then attempt to connect to the public Mosquitto broker + and begin publishing data. +- It is also possible to connect securely to a locally hosted MQTT broker. + This will require provisioning of certificates. + The CA cert should be included in the build as described above. + ``CONFIG_NET_SAMPLE_MQTT_BROKER_HOSTNAME`` should be configured to match the + local broker hostname/IP address. + Depending on the CA cert being used, additional MbedTLS config options may need to be enabled. + This can be done using Kconfig or using a custom MbedTLS config file + (see modules/mbedtls/Kconfig). + See https://mosquitto.org/man/mosquitto-tls-7.html for more info on setting up + TLS support for Mosquitto locally. +- A DHCP server can be installed on the host PC to handle assigning an IP to the board + e.g. dnsmasq (Linux) or DHCP Server for Windows (Windows). +- Build the sample with default config: + +.. zephyr-app-commands:: + :zephyr-app: samples/net/secure_mqtt_sensor_actuator + :board: adi_eval_adin1110ebz + :goals: build + :compact: + +**Static IP Config:** + +Use the :file:`overlay-static.conf` Kconfig overlay to disable DHCP and use +a static IP address config. +The device, gateway, and DNS server IP addresses should be set according to +your local network configuration. + +.. zephyr-app-commands:: + :zephyr-app: samples/net/secure_mqtt_sensor_actuator + :board: adi_eval_adin1110ebz + :conf: "prj.conf overlay-static.conf" + :goals: build + :compact: + +**Static IP/Unsecure MQTT Config:** + +Use the :file:`overlay-static-insecure.conf` Kconfig overlay to disable TLS and DHCP. +This config requires connecting to a locally hosted Mosquitto MQTT broker. + +- In :file:`overlay-static-insecure.conf`, set the IP address of the board and the Mosquitto + broker (i.e. IP address of Ethernet port on host PC). These addresses should be in the + same subnet e.g. 192.0.2.1 and 192.0.2.2. +- On your host PC, install Mosquitto. +- Create a file called ``unsecure.conf`` with the following content: + +.. code-block:: console + + listener 1883 0.0.0.0 + allow_anonymous true + + +- Start a Mosquitto broker using the configuration file: + +.. code-block:: console + + $ sudo mosquitto -v -c unsecure.conf + +- Build the sample with quick test config: + +.. zephyr-app-commands:: + :zephyr-app: samples/net/secure_mqtt_sensor_actuator + :board: adi_eval_adin1110ebz + :conf: "prj.conf overlay-static-insecure.conf" + :goals: build + :compact: + +Using the Sample +================ +- Once the board establishes an MQTT connection with the Mosquitto broker, the network + LED will turn on and the board will begin publishing sensor readings in JSON format + at a regular interval determined by ``CONFIG_NET_SAMPLE_MQTT_PUBLISH_INTERVAL``. + +- Use Mosquitto to subscribe to the sensor data being sent from the board: + +.. code-block:: console + + $ mosquitto_sub -d -h -t zephyr_sample/sensor + +- The application will subscribe to a topic determined by ``CONFIG_NET_SAMPLE_MQTT_SUB_TOPIC_CMD``. + If a supported command string is received by the board on this topic, the board will execute + an associated command handler function. + Supported commands (defined in :file:`device.c`): + + - ``led_on``, turn on board LED + - ``led_off``, turn off board LED + +- Use Mosquitto to publish these commands to the MQTT broker: + +.. code-block:: console + + $ mosquitto_pub -d -h --cafile -t zephyr_sample/command -m "led_on" + +- The Quality of Service (QoS) level that is used for MQTT publishing and + subscriptions can be configured using Kconfig. + +Sample output +============= + +.. code-block:: console + + *** Booting Zephyr OS build v3.6.0-2212-g2c9c4f3733e9 *** + [00:00:00.181,000] app_device: Device adt7420@48 is ready + [00:00:00.181,000] app_device: Device leds is ready + [00:00:00.181,000] app_main: MAC Address: 00:E0:FE:FE:DA:C8 + [00:00:00.181,000] app_main: Bringing up network.. + [00:00:00.801,000] net_dhcpv4: Received: 192.168.1.17 + [00:00:00.801,000] app_main: Network connectivity up! + [00:00:00.818,000] app_mqtt: Connecting to MQTT broker @ 91.121.93.94 + [00:00:01.154,000] net_mqtt: Connect completed + [00:00:01.197,000] app_mqtt: Connected to MQTT broker! + [00:00:01.197,000] app_mqtt: Hostname: test.mosquitto.org + [00:00:01.198,000] app_mqtt: Client ID: adi_eval_adin1110ebz_9a + [00:00:01.198,000] app_mqtt: Port: 8883 + [00:00:01.198,000] app_mqtt: TLS: Enabled + [00:00:01.198,000] app_mqtt: Subscribing to 1 topic(s) + [00:00:01.238,000] app_mqtt: SUBACK packet ID: 5841 + [00:00:04.200,000] app_mqtt: Published to topic 'zephyr_sample/sensor', QoS 1 + [00:00:04.319,000] app_mqtt: PUBACK packet ID: 1 + [00:00:07.202,000] app_mqtt: Published to topic 'zephyr_sample/sensor', QoS 1 + [00:00:07.323,000] app_mqtt: PUBACK packet ID: 2 + [00:00:10.204,000] app_mqtt: Published to topic 'zephyr_sample/sensor', QoS 1 + [00:00:10.322,000] app_mqtt: PUBACK packet ID: 3 + [00:00:12.769,000] app_mqtt: MQTT payload received! + [00:00:12.769,000] app_mqtt: topic: 'zephyr_sample/command', payload: led_on + [00:00:12.770,000] app_device: Executing device command: led_on + +.. _Eclipse Mosquitto: https://mosquitto.org/download/ diff --git a/samples/net/secure_mqtt_sensor_actuator/boards/adi_eval_adin1110ebz.overlay b/samples/net/secure_mqtt_sensor_actuator/boards/adi_eval_adin1110ebz.overlay new file mode 100644 index 00000000000..8182bb8b230 --- /dev/null +++ b/samples/net/secure_mqtt_sensor_actuator/boards/adi_eval_adin1110ebz.overlay @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2024 Analog Devices, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&adin1110 { + mdio { + /* Enable link status LED */ + ethernet-phy@1 { + led0-en; + led1-en; + }; + }; +}; diff --git a/samples/net/secure_mqtt_sensor_actuator/overlay-static-insecure.conf b/samples/net/secure_mqtt_sensor_actuator/overlay-static-insecure.conf new file mode 100644 index 00000000000..33655bfe4e1 --- /dev/null +++ b/samples/net/secure_mqtt_sensor_actuator/overlay-static-insecure.conf @@ -0,0 +1,18 @@ +# Config to disable TLS and DHCPv4, allowing insecure MQTT and a static IP address. +# This allows quick testing of the application without need for a DHCP server or secure MQTT broker set up. +# Only recommended for quick sampling/testing. +# Usage: west build -b -- -DOVERLAY_CONFIG=overlay-static-insecure.conf + +# Disable MQTT with TLS +CONFIG_MQTT_LIB_TLS=n + +# Disable DHCP +CONFIG_NET_DHCPV4=n + +# Insecure MQTT uses port 1883 +CONFIG_NET_SAMPLE_MQTT_BROKER_PORT="1883" + +# Static IP address config +CONFIG_NET_CONFIG_SETTINGS=y +CONFIG_NET_CONFIG_MY_IPV4_ADDR="192.0.2.1" +CONFIG_NET_SAMPLE_MQTT_BROKER_HOSTNAME="192.0.2.2" diff --git a/samples/net/secure_mqtt_sensor_actuator/overlay-static.conf b/samples/net/secure_mqtt_sensor_actuator/overlay-static.conf new file mode 100644 index 00000000000..69737f64078 --- /dev/null +++ b/samples/net/secure_mqtt_sensor_actuator/overlay-static.conf @@ -0,0 +1,8 @@ +CONFIG_NET_DHCPV4=n +CONFIG_NET_CONFIG_SETTINGS=y +CONFIG_NET_CONFIG_NEED_IPV4=y +CONFIG_NET_CONFIG_MY_IPV4_ADDR="192.0.2.1" +CONFIG_NET_CONFIG_MY_IPV4_GW="192.0.2.2" +CONFIG_DNS_RESOLVER=y +CONFIG_DNS_SERVER_IP_ADDRESSES=y +CONFIG_DNS_SERVER1="192.0.2.2" diff --git a/samples/net/secure_mqtt_sensor_actuator/prj.conf b/samples/net/secure_mqtt_sensor_actuator/prj.conf new file mode 100644 index 00000000000..b87eaa2c348 --- /dev/null +++ b/samples/net/secure_mqtt_sensor_actuator/prj.conf @@ -0,0 +1,59 @@ +# Enable network stack +CONFIG_NETWORKING=y +CONFIG_NET_LOG=y + +# Enable IPv4 +CONFIG_NET_IPV4=y + +# Enable IPv6 +CONFIG_NET_IPV6=y + +# Enable TCP +CONFIG_NET_TCP=y + +# Enable DHCP +CONFIG_NET_DHCPV4=y + +# Enable Sockets (used by MQTT lib) +CONFIG_NET_SOCKETS=y +CONFIG_NET_SOCKETS_SOCKOPT_TLS=y + +# Enable MQTT +CONFIG_MQTT_LIB=y +CONFIG_MQTT_LIB_TLS=y + +# Enable Mbed TLS +CONFIG_MBEDTLS=y +CONFIG_MBEDTLS_BUILTIN=y +CONFIG_MBEDTLS_ENABLE_HEAP=y +CONFIG_MBEDTLS_HEAP_SIZE=60000 +CONFIG_MBEDTLS_SSL_MAX_CONTENT_LEN=16384 +CONFIG_MBEDTLS_PEM_CERTIFICATE_FORMAT=y +CONFIG_MBEDTLS_SERVER_NAME_INDICATION=y + +# Enable JSON +CONFIG_JSON_LIBRARY=y + +# Enable net conn manager +CONFIG_NET_CONNECTION_MANAGER=y + +# Enable device hostname +CONFIG_NET_HOSTNAME_ENABLE=y + +# Enable Posix API functionality +CONFIG_POSIX_API=y + +# Enable sensor API +CONFIG_SENSOR=y + +# Enable LED API +CONFIG_LED=y + +# Main stack size +CONFIG_MAIN_STACK_SIZE=2048 + +# System work queue stack size +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048 + +# Increase Rx net buffers +CONFIG_NET_BUF_RX_COUNT=100 diff --git a/samples/net/secure_mqtt_sensor_actuator/sample.yaml b/samples/net/secure_mqtt_sensor_actuator/sample.yaml new file mode 100644 index 00000000000..44b9a4d7d2a --- /dev/null +++ b/samples/net/secure_mqtt_sensor_actuator/sample.yaml @@ -0,0 +1,33 @@ +sample: + name: Secure MQTT Sensor/Actuator Sample +tests: + sample.net.secure_mqtt_sensor_actuator: + harness: net + tags: + - net + - mqtt + - sensors + filter: dt_alias_exists("ambient-temp0") + integration_platforms: + - adi_eval_adin1110ebz + sample.net.secure_mqtt_sensor_actuator.staticip: + harness: net + extra_args: OVERLAY_CONFIG="overlay-static.conf" + tags: + - net + - mqtt + - sensors + filter: dt_alias_exists("ambient-temp0") + integration_platforms: + - native_sim + sample.net.secure_mqtt_sensor_actuator.staticip_insecure: + harness: net + extra_args: OVERLAY_CONFIG="overlay-static-insecure.conf" + tags: + - net + - mqtt + - sensors + filter: dt_alias_exists("ambient-temp0") + integration_platforms: + - adi_eval_adin1110ebz + - native_sim diff --git a/samples/net/secure_mqtt_sensor_actuator/src/device.c b/samples/net/secure_mqtt_sensor_actuator/src/device.c new file mode 100644 index 00000000000..7ac800e43e2 --- /dev/null +++ b/samples/net/secure_mqtt_sensor_actuator/src/device.c @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2024 Analog Devices, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +LOG_MODULE_REGISTER(app_device, LOG_LEVEL_DBG); + +#include +#include +#include +#include + +#include "device.h" + +#define SENSOR_CHAN SENSOR_CHAN_AMBIENT_TEMP +#define SENSOR_UNIT "Celsius" + +/* Devices */ +static const struct device *sensor = DEVICE_DT_GET_OR_NULL(DT_ALIAS(ambient_temp0)); +static const struct device *leds = DEVICE_DT_GET_OR_NULL(DT_INST(0, gpio_leds)); + +/* Command handlers */ +static void led_on_handler(void) +{ + device_write_led(LED_USER, LED_ON); +} + +static void led_off_handler(void) +{ + device_write_led(LED_USER, LED_OFF); +} + +/* Supported device commands */ +struct device_cmd device_commands[] = { + {"led_on", led_on_handler}, + {"led_off", led_off_handler} +}; + +const size_t num_device_commands = ARRAY_SIZE(device_commands); + +/* Command dispatcher */ +void device_command_handler(uint8_t *command) +{ + for (int i = 0; i < num_device_commands; i++) { + if (strcmp(command, device_commands[i].command) == 0) { + LOG_INF("Executing device command: %s", device_commands[i].command); + return device_commands[i].handler(); + } + } + LOG_ERR("Unknown command: %s", command); +} + +int device_read_sensor(struct sensor_sample *sample) +{ + int rc; + struct sensor_value sensor_val; + + /* Read sample only if a real sensor device is present + * otherwise return a dummy value + */ + if (sensor == NULL) { + sample->unit = SENSOR_UNIT; + sample->value = 20.0 + (double)sys_rand32_get() / UINT32_MAX * 5.0; + return 0; + } + + rc = sensor_sample_fetch(sensor); + if (rc) { + LOG_ERR("Failed to fetch sensor sample [%d]", rc); + return rc; + } + + rc = sensor_channel_get(sensor, SENSOR_CHAN, &sensor_val); + if (rc) { + LOG_ERR("Failed to get sensor channel [%d]", rc); + return rc; + } + + sample->unit = SENSOR_UNIT; + sample->value = sensor_value_to_double(&sensor_val); + return rc; +} + +int device_write_led(enum led_id led_idx, enum led_state state) +{ + int rc; + + switch (state) { + case LED_OFF: + if (leds == NULL) { + LOG_INF("LED %d OFF", led_idx); + break; + } + led_off(leds, led_idx); + break; + case LED_ON: + if (leds == NULL) { + LOG_INF("LED %d ON", led_idx); + break; + } + led_on(leds, led_idx); + break; + default: + LOG_ERR("Invalid LED state setting"); + rc = -EINVAL; + break; + } + + return rc; +} + +bool devices_ready(void) +{ + bool rc = true; + + /* Check readiness only if a real sensor device is present */ + if (sensor != NULL) { + if (!device_is_ready(sensor)) { + LOG_ERR("Device %s is not ready", sensor->name); + rc = false; + } else { + LOG_INF("Device %s is ready", sensor->name); + } + } + + if (leds != NULL) { + if (!device_is_ready(leds)) { + LOG_ERR("Device %s is not ready", leds->name); + rc = false; + } else { + LOG_INF("Device %s is ready", leds->name); + } + } + + return rc; +} diff --git a/samples/net/secure_mqtt_sensor_actuator/src/device.h b/samples/net/secure_mqtt_sensor_actuator/src/device.h new file mode 100644 index 00000000000..ad09b9d3efa --- /dev/null +++ b/samples/net/secure_mqtt_sensor_actuator/src/device.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2024 Analog Devices, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __DEVICE_H__ +#define __DEVICE_H__ + +/** @brief Sensor sample structure */ +struct sensor_sample { + const char *unit; + int value; +}; + +/** @brief Available board LEDs */ +enum led_id { + LED_NET, /* Network status LED*/ + LED_USER /* User LED */ +}; + +/** @brief LED states */ +enum led_state { + LED_OFF, + LED_ON +}; + +/** @brief Device command consisting of a command string + * and associated handler function pointer + */ +struct device_cmd { + const char *command; + void (*handler)(); +}; + +/** + * @brief Check if all devices are ready + */ +bool devices_ready(void); + +/** + * @brief Read sample from the sensor + */ +int device_read_sensor(struct sensor_sample *sample); + +/** + * @brief Write to a board LED + */ +int device_write_led(enum led_id led_idx, enum led_state state); + +/** + * @brief Handler function for commands received over MQTT + */ +void device_command_handler(uint8_t *command); + +#endif /* __DEVICE_H__ */ diff --git a/samples/net/secure_mqtt_sensor_actuator/src/main.c b/samples/net/secure_mqtt_sensor_actuator/src/main.c new file mode 100644 index 00000000000..64993139e90 --- /dev/null +++ b/samples/net/secure_mqtt_sensor_actuator/src/main.c @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2024 Analog Devices, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +LOG_MODULE_REGISTER(app_main, LOG_LEVEL_DBG); + +#include +#include +#include +#include +#include + +#include "mqtt_client.h" +#include "device.h" + +#define NET_L4_EVENT_MASK (NET_EVENT_L4_CONNECTED | NET_EVENT_L4_DISCONNECTED) + +/* MQTT client struct */ +static struct mqtt_client client_ctx; + +/* MQTT publish work item */ +struct k_work_delayable mqtt_publish_work; + +static struct net_mgmt_event_callback net_l4_mgmt_cb; + +/* Network connection semaphore */ +K_SEM_DEFINE(net_conn_sem, 0, 1); + +static void net_l4_evt_handler(struct net_mgmt_event_callback *cb, + uint32_t mgmt_event, struct net_if *iface) +{ + switch (mgmt_event) { + case NET_EVENT_L4_CONNECTED: + k_sem_give(&net_conn_sem); + LOG_INF("Network connectivity up!"); + break; + case NET_EVENT_L4_DISCONNECTED: + LOG_INF("Network connectivity down!"); + break; + default: + break; + } +} + +/** Print the device's MAC address to console */ +void log_mac_addr(struct net_if *iface) +{ + struct net_linkaddr *mac; + + mac = net_if_get_link_addr(iface); + + LOG_INF("MAC Address: %02X:%02X:%02X:%02X:%02X:%02X", + mac->addr[0], mac->addr[1], mac->addr[3], + mac->addr[3], mac->addr[4], mac->addr[5]); +} + +/** The system work queue is used to handle periodic MQTT publishing. + * Work queuing begins when the MQTT connection is established. + * Use CONFIG_NET_SAMPLE_MQTT_PUBLISH_INTERVAL to set the publish frequency. + */ + +static void publish_work_handler(struct k_work *work) +{ + int rc; + + if (mqtt_connected) { + rc = app_mqtt_publish(&client_ctx); + if (rc != 0) { + LOG_INF("MQTT Publish failed [%d]", rc); + } + k_work_reschedule(&mqtt_publish_work, + K_SECONDS(CONFIG_NET_SAMPLE_MQTT_PUBLISH_INTERVAL)); + } else { + k_work_cancel_delayable(&mqtt_publish_work); + } +} + +int main(void) +{ + int rc; + struct net_if *iface; + + devices_ready(); + + iface = net_if_get_default(); + if (iface == NULL) { + LOG_ERR("No network interface configured"); + return -ENETDOWN; + } + + log_mac_addr(iface); + + /* Register callbacks for L4 events */ + net_mgmt_init_event_callback(&net_l4_mgmt_cb, &net_l4_evt_handler, NET_L4_EVENT_MASK); + net_mgmt_add_event_callback(&net_l4_mgmt_cb); + + LOG_INF("Bringing up network.."); + +#if defined(CONFIG_NET_DHCPV4) + net_dhcpv4_start(iface); +#else + /* If using static IP, L4 Connect callback will happen, + * before conn mgr is initialised, so resend events here + * to check for connectivity + */ + conn_mgr_mon_resend_status(); +#endif + + /* Wait for network to come up */ + while (k_sem_take(&net_conn_sem, K_MSEC(MSECS_NET_POLL_TIMEOUT)) != 0) { + LOG_INF("Waiting for network connection.."); + } + + rc = app_mqtt_init(&client_ctx); + if (rc != 0) { + LOG_ERR("MQTT Init failed [%d]", rc); + return rc; + } + + /* Initialise MQTT publish work item */ + k_work_init_delayable(&mqtt_publish_work, publish_work_handler); + + /* Thread main loop */ + while (1) { + /* Block until MQTT connection is up */ + app_mqtt_connect(&client_ctx); + + /* We are now connected, begin queueing periodic MQTT publishes */ + k_work_reschedule(&mqtt_publish_work, + K_SECONDS(CONFIG_NET_SAMPLE_MQTT_PUBLISH_INTERVAL)); + + /* Handle MQTT inputs and connection */ + app_mqtt_run(&client_ctx); + } + + return rc; +} diff --git a/samples/net/secure_mqtt_sensor_actuator/src/mqtt_client.c b/samples/net/secure_mqtt_sensor_actuator/src/mqtt_client.c new file mode 100644 index 00000000000..3fdb6f3abf4 --- /dev/null +++ b/samples/net/secure_mqtt_sensor_actuator/src/mqtt_client.c @@ -0,0 +1,510 @@ +/* + * Copyright (c) 2024 Analog Devices, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +LOG_MODULE_REGISTER(app_mqtt, LOG_LEVEL_DBG); + +#include +#include +#include +#include +#include + +#include "mqtt_client.h" +#include "device.h" + +/* Buffers for MQTT client */ +static uint8_t rx_buffer[CONFIG_NET_SAMPLE_MQTT_PAYLOAD_SIZE]; +static uint8_t tx_buffer[CONFIG_NET_SAMPLE_MQTT_PAYLOAD_SIZE]; + +/* MQTT payload buffer */ +static uint8_t payload_buf[CONFIG_NET_SAMPLE_MQTT_PAYLOAD_SIZE]; + +/* MQTT broker details */ +static struct sockaddr_storage broker; + +/* Socket descriptor */ +static struct zsock_pollfd fds[1]; +static int nfds; + +/* JSON payload format */ +static const struct json_obj_descr sensor_sample_descr[] = { + JSON_OBJ_DESCR_PRIM(struct sensor_sample, unit, JSON_TOK_STRING), + JSON_OBJ_DESCR_PRIM(struct sensor_sample, value, JSON_TOK_NUMBER), +}; + +/* MQTT connectivity status flag */ +bool mqtt_connected; + +/* MQTT client ID buffer */ +static uint8_t client_id[50]; + +#if defined(CONFIG_MQTT_LIB_TLS) +#include "tls_config/cert.h" + +/* This should match the CN field in the server's CA cert */ +#define TLS_SNI_HOSTNAME CONFIG_NET_SAMPLE_MQTT_BROKER_HOSTNAME +#define APP_CA_CERT_TAG 1 + +static const sec_tag_t m_sec_tags[] = { + APP_CA_CERT_TAG, +}; + +/** Register CA certificate for TLS */ +static int tls_init(void) +{ + int rc; + + rc = tls_credential_add(APP_CA_CERT_TAG, TLS_CREDENTIAL_CA_CERTIFICATE, + ca_certificate, sizeof(ca_certificate)); + if (rc < 0) { + LOG_ERR("Failed to register public certificate: %d", rc); + return rc; + } + + return rc; +} +#endif + +static void prepare_fds(struct mqtt_client *client) +{ + if (client->transport.type == MQTT_TRANSPORT_NON_SECURE) { + fds[0].fd = client->transport.tcp.sock; + } +#if defined(CONFIG_MQTT_LIB_TLS) + else if (client->transport.type == MQTT_TRANSPORT_SECURE) { + fds[0].fd = client->transport.tls.sock; + } +#endif + + fds[0].events = ZSOCK_POLLIN; + nfds = 1; +} + +static void clear_fds(void) +{ + nfds = 0; +} + +/** Initialise the MQTT client ID as the board name with random hex postfix */ +static void init_mqtt_client_id(void) +{ + snprintk(client_id, sizeof(client_id), CONFIG_BOARD"_%x", (uint8_t)sys_rand32_get()); +} + +static inline void on_mqtt_connect(void) +{ + mqtt_connected = true; + device_write_led(LED_NET, LED_ON); + LOG_INF("Connected to MQTT broker!"); + LOG_INF("Hostname: %s", CONFIG_NET_SAMPLE_MQTT_BROKER_HOSTNAME); + LOG_INF("Client ID: %s", client_id); + LOG_INF("Port: %s", CONFIG_NET_SAMPLE_MQTT_BROKER_PORT); + LOG_INF("TLS: %s", + IS_ENABLED(CONFIG_MQTT_LIB_TLS) ? "Enabled" : "Disabled"); +} + +static inline void on_mqtt_disconnect(void) +{ + mqtt_connected = false; + clear_fds(); + device_write_led(LED_NET, LED_OFF); + LOG_INF("Disconnected from MQTT broker"); +} + +/** Called when an MQTT payload is received. + * Reads the payload and calls the commands + * handler if a payloads is received on the + * command topic + */ +static void on_mqtt_publish(struct mqtt_client *const client, const struct mqtt_evt *evt) +{ + int rc; + uint8_t payload[CONFIG_NET_SAMPLE_MQTT_PAYLOAD_SIZE]; + + rc = mqtt_read_publish_payload(client, payload, + CONFIG_NET_SAMPLE_MQTT_PAYLOAD_SIZE); + if (rc < 0) { + LOG_ERR("Failed to read received MQTT payload [%d]", rc); + return; + } + /* Place null terminator at end of payload buffer */ + payload[rc] = '\0'; + + LOG_INF("MQTT payload received!"); + LOG_INF("topic: '%s', payload: %s", + evt->param.publish.message.topic.topic.utf8, payload); + + /* If the topic is a command, call the command handler */ + if (strcmp(evt->param.publish.message.topic.topic.utf8, + CONFIG_NET_SAMPLE_MQTT_SUB_TOPIC_CMD) == 0) { + device_command_handler(payload); + } +} + +/** Handler for asynchronous MQTT events */ +static void mqtt_event_handler(struct mqtt_client *const client, const struct mqtt_evt *evt) +{ + switch (evt->type) { + case MQTT_EVT_CONNACK: + if (evt->result != 0) { + LOG_ERR("MQTT Event Connect failed [%d]", evt->result); + break; + } + on_mqtt_connect(); + break; + + case MQTT_EVT_DISCONNECT: + on_mqtt_disconnect(); + break; + + case MQTT_EVT_PINGRESP: + LOG_INF("PINGRESP packet"); + break; + + case MQTT_EVT_PUBACK: + if (evt->result != 0) { + LOG_ERR("MQTT PUBACK error [%d]", evt->result); + break; + } + + LOG_INF("PUBACK packet ID: %u", evt->param.puback.message_id); + break; + + case MQTT_EVT_PUBREC: + if (evt->result != 0) { + LOG_ERR("MQTT PUBREC error [%d]", evt->result); + break; + } + + LOG_INF("PUBREC packet ID: %u", evt->param.pubrec.message_id); + + const struct mqtt_pubrel_param rel_param = { + .message_id = evt->param.pubrec.message_id + }; + + mqtt_publish_qos2_release(client, &rel_param); + break; + + case MQTT_EVT_PUBREL: + if (evt->result != 0) { + LOG_ERR("MQTT PUBREL error [%d]", evt->result); + break; + } + + LOG_INF("PUBREL packet ID: %u", evt->param.pubrel.message_id); + + const struct mqtt_pubcomp_param rec_param = { + .message_id = evt->param.pubrel.message_id + }; + + mqtt_publish_qos2_complete(client, &rec_param); + break; + + case MQTT_EVT_PUBCOMP: + if (evt->result != 0) { + LOG_ERR("MQTT PUBCOMP error %d", evt->result); + break; + } + + LOG_INF("PUBCOMP packet ID: %u", evt->param.pubcomp.message_id); + break; + + case MQTT_EVT_SUBACK: + if (evt->result == 0x80) { + LOG_ERR("MQTT SUBACK error [%d]", evt->result); + break; + } + + LOG_INF("SUBACK packet ID: %d", evt->param.suback.message_id); + break; + + case MQTT_EVT_PUBLISH: + const struct mqtt_publish_param *p = &evt->param.publish; + + if (p->message.topic.qos == MQTT_QOS_1_AT_LEAST_ONCE) { + const struct mqtt_puback_param ack_param = { + .message_id = p->message_id + }; + mqtt_publish_qos1_ack(client, &ack_param); + } else if (p->message.topic.qos == MQTT_QOS_2_EXACTLY_ONCE) { + const struct mqtt_pubrec_param rec_param = { + .message_id = p->message_id + }; + mqtt_publish_qos2_receive(client, &rec_param); + } + + on_mqtt_publish(client, evt); + + default: + break; + } +} + +/** Poll the MQTT socket for received data */ +static int poll_mqtt_socket(struct mqtt_client *client, int timeout) +{ + int rc; + + prepare_fds(client); + + if (nfds <= 0) { + return -EINVAL; + } + + rc = zsock_poll(fds, nfds, timeout); + if (rc < 0) { + LOG_ERR("Socket poll error [%d]", rc); + } + + return rc; +} + +/** Retrieves a sensor sample and encodes it in JSON format */ +static int get_mqtt_payload(struct mqtt_binstr *payload) +{ + int rc; + struct sensor_sample sample; + + rc = device_read_sensor(&sample); + if (rc != 0) { + LOG_ERR("Failed to get sensor sample [%d]", rc); + return rc; + } + + rc = json_obj_encode_buf(sensor_sample_descr, ARRAY_SIZE(sensor_sample_descr), + &sample, payload_buf, CONFIG_NET_SAMPLE_MQTT_PAYLOAD_SIZE); + if (rc != 0) { + LOG_ERR("Failed to encode JSON object [%d]", rc); + return rc; + } + + payload->data = payload_buf; + payload->len = strlen(payload->data); + + return rc; +} + +int app_mqtt_publish(struct mqtt_client *client) +{ + int rc; + struct mqtt_publish_param param; + struct mqtt_binstr payload; + static uint16_t msg_id = 1; + struct mqtt_topic topic = { + .topic = { + .utf8 = CONFIG_NET_SAMPLE_MQTT_PUB_TOPIC, + .size = strlen(topic.topic.utf8) + }, + .qos = IS_ENABLED(CONFIG_NET_SAMPLE_MQTT_QOS_0_AT_MOST_ONCE) ? 0 : + (IS_ENABLED(CONFIG_NET_SAMPLE_MQTT_QOS_1_AT_LEAST_ONCE) ? 1 : 2) + }; + + rc = get_mqtt_payload(&payload); + if (rc != 0) { + LOG_ERR("Failed to get MQTT payload [%d]", rc); + } + + param.message.topic = topic; + param.message.payload = payload; + param.message_id = msg_id++; + param.dup_flag = 0; + param.retain_flag = 0; + + rc = mqtt_publish(client, ¶m); + if (rc != 0) { + LOG_ERR("MQTT Publish failed [%d]", rc); + } + + LOG_INF("Published to topic '%s', QoS %d", + param.message.topic.topic.utf8, + param.message.topic.qos); + + return rc; +} + +int app_mqtt_subscribe(struct mqtt_client *client) +{ + int rc; + struct mqtt_topic sub_topics[] = { + { + .topic = { + .utf8 = CONFIG_NET_SAMPLE_MQTT_SUB_TOPIC_CMD, + .size = strlen(sub_topics->topic.utf8) + }, + .qos = IS_ENABLED(CONFIG_NET_SAMPLE_MQTT_QOS_0_AT_MOST_ONCE) ? 0 : + (IS_ENABLED(CONFIG_NET_SAMPLE_MQTT_QOS_1_AT_LEAST_ONCE) ? 1 : 2) + } + }; + const struct mqtt_subscription_list sub_list = { + .list = sub_topics, + .list_count = ARRAY_SIZE(sub_topics), + .message_id = 5841u + }; + + LOG_INF("Subscribing to %d topic(s)", sub_list.list_count); + + rc = mqtt_subscribe(client, &sub_list); + if (rc != 0) { + LOG_ERR("MQTT Subscribe failed [%d]", rc); + } + + return rc; +} + +/** Process incoming MQTT data and keep the connection alive*/ +int app_mqtt_process(struct mqtt_client *client) +{ + int rc; + + rc = poll_mqtt_socket(client, mqtt_keepalive_time_left(client)); + if (rc != 0) { + if (fds[0].revents & ZSOCK_POLLIN) { + /* MQTT data received */ + rc = mqtt_input(client); + if (rc != 0) { + LOG_ERR("MQTT Input failed [%d]", rc); + return rc; + } + /* Socket error */ + if (fds[0].revents & (ZSOCK_POLLHUP | ZSOCK_POLLERR)) { + LOG_ERR("MQTT socket closed / error"); + return -ENOTCONN; + } + } + } else { + /* Socket poll timed out, time to call mqtt_live() */ + rc = mqtt_live(client); + if (rc != 0) { + LOG_ERR("MQTT Live failed [%d]", rc); + return rc; + } + } + + return 0; +} + +void app_mqtt_run(struct mqtt_client *client) +{ + int rc; + + /* Subscribe to MQTT topics */ + app_mqtt_subscribe(client); + + /* Thread will primarily remain in this loop */ + while (mqtt_connected) { + rc = app_mqtt_process(client); + if (rc != 0) { + break; + } + } + /* Gracefully close connection */ + mqtt_disconnect(client); +} + +void app_mqtt_connect(struct mqtt_client *client) +{ + int rc = 0; + + mqtt_connected = false; + + /* Block until MQTT CONNACK event callback occurs */ + while (!mqtt_connected) { + rc = mqtt_connect(client); + if (rc != 0) { + LOG_ERR("MQTT Connect failed [%d]", rc); + k_msleep(MSECS_WAIT_RECONNECT); + continue; + } + + /* Poll MQTT socket for response */ + rc = poll_mqtt_socket(client, MSECS_NET_POLL_TIMEOUT); + if (rc > 0) { + mqtt_input(client); + } + + if (!mqtt_connected) { + mqtt_abort(client); + } + } +} + +int app_mqtt_init(struct mqtt_client *client) +{ + int rc; + uint8_t broker_ip[NET_IPV4_ADDR_LEN]; + struct sockaddr_in *broker4; + struct addrinfo *result; + const struct addrinfo hints = { + .ai_family = AF_INET, + .ai_socktype = SOCK_STREAM + }; + + /* Resolve IP address of MQTT broker */ + rc = getaddrinfo(CONFIG_NET_SAMPLE_MQTT_BROKER_HOSTNAME, + CONFIG_NET_SAMPLE_MQTT_BROKER_PORT, &hints, &result); + if (rc != 0) { + LOG_ERR("Failed to resolve broker hostname [%s]", gai_strerror(rc)); + return -EIO; + } + if (result == NULL) { + LOG_ERR("Broker address not found"); + return -ENOENT; + } + + broker4 = (struct sockaddr_in *)&broker; + broker4->sin_addr.s_addr = ((struct sockaddr_in *)result->ai_addr)->sin_addr.s_addr; + broker4->sin_family = AF_INET; + broker4->sin_port = ((struct sockaddr_in *)result->ai_addr)->sin_port; + freeaddrinfo(result); + + /* Log resolved IP address */ + inet_ntop(AF_INET, &broker4->sin_addr.s_addr, broker_ip, sizeof(broker_ip)); + LOG_INF("Connecting to MQTT broker @ %s", broker_ip); + + /* MQTT client configuration */ + init_mqtt_client_id(); + mqtt_client_init(client); + client->broker = &broker; + client->evt_cb = mqtt_event_handler; + client->client_id.utf8 = client_id; + client->client_id.size = strlen(client->client_id.utf8); + client->password = NULL; + client->user_name = NULL; + client->protocol_version = MQTT_VERSION_3_1_1; + + /* MQTT buffers configuration */ + client->rx_buf = rx_buffer; + client->rx_buf_size = sizeof(rx_buffer); + client->tx_buf = tx_buffer; + client->tx_buf_size = sizeof(tx_buffer); + + /* MQTT transport configuration */ +#if defined(CONFIG_MQTT_LIB_TLS) + struct mqtt_sec_config *tls_config; + + client->transport.type = MQTT_TRANSPORT_SECURE; + + rc = tls_init(); + if (rc != 0) { + LOG_ERR("TLS init error"); + return rc; + } + + tls_config = &client->transport.tls.config; + tls_config->peer_verify = TLS_PEER_VERIFY_REQUIRED; + tls_config->cipher_list = NULL; + tls_config->sec_tag_list = m_sec_tags; + tls_config->sec_tag_count = ARRAY_SIZE(m_sec_tags); +#if defined(CONFIG_MBEDTLS_SERVER_NAME_INDICATION) + tls_config->hostname = TLS_SNI_HOSTNAME; +#else + tls_config->hostname = NULL; +#endif /* CONFIG_MBEDTLS_SERVER_NAME_INDICATION */ +#endif /* CONFIG_MQTT_LIB_TLS */ + + return rc; +} diff --git a/samples/net/secure_mqtt_sensor_actuator/src/mqtt_client.h b/samples/net/secure_mqtt_sensor_actuator/src/mqtt_client.h new file mode 100644 index 00000000000..d78c2b05d34 --- /dev/null +++ b/samples/net/secure_mqtt_sensor_actuator/src/mqtt_client.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2024 Analog Devices, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __MQTT_CLIENT_H__ +#define __MQTT_CLIENT_H__ + +/** MQTT connection timeouts */ +#define MSECS_NET_POLL_TIMEOUT 5000 +#define MSECS_WAIT_RECONNECT 1000 + +/** MQTT connection status flag */ +extern bool mqtt_connected; + +/** + * @brief Initialise the MQTT client & broker configuration + */ +int app_mqtt_init(struct mqtt_client *client); + +/** + * @brief Blocking function that establishes connectivity to the MQTT broker + */ +void app_mqtt_connect(struct mqtt_client *client); + +/** + * @brief Subscribes to user-defined MQTT topics and continuously + * processes incoming data while the MQTT connection is active + */ +void app_mqtt_run(struct mqtt_client *client); + +/** + * @brief Subscribe to user-defined MQTT topics + */ +int app_mqtt_subscribe(struct mqtt_client *client); + +/** + * @brief Publish MQTT payload + */ +int app_mqtt_publish(struct mqtt_client *client); + +#endif /* __MQTT_CLIENT_H__ */ diff --git a/samples/net/secure_mqtt_sensor_actuator/src/tls_config/cert.h b/samples/net/secure_mqtt_sensor_actuator/src/tls_config/cert.h new file mode 100644 index 00000000000..e044f465b9e --- /dev/null +++ b/samples/net/secure_mqtt_sensor_actuator/src/tls_config/cert.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2024 Analog Devices, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __CERT_H__ +#define __CERT_H__ + +/* The CA certficate of the MQTT broker should be included here + * The certificate can either be in DER or PEM format. + * A DER certificate can be converted to a byte array using + * "cat ca.crt | sed -e '1d;$d' | base64 -d |xxd -i" + * If using a PEM certifificate, each line should be wrapped in "\r\n" + */ + +/* CA certificate for Mosquitto public broker + * (available from test.mosquitto.org, valid at time of development) + */ +static const unsigned char ca_certificate[] = "-----BEGIN CERTIFICATE-----\r\n" +"MIIEAzCCAuugAwIBAgIUBY1hlCGvdj4NhBXkZ/uLUZNILAwwDQYJKoZIhvcNAQEL\r\n" +"BQAwgZAxCzAJBgNVBAYTAkdCMRcwFQYDVQQIDA5Vbml0ZWQgS2luZ2RvbTEOMAwG\r\n" +"A1UEBwwFRGVyYnkxEjAQBgNVBAoMCU1vc3F1aXR0bzELMAkGA1UECwwCQ0ExFjAU\r\n" +"BgNVBAMMDW1vc3F1aXR0by5vcmcxHzAdBgkqhkiG9w0BCQEWEHJvZ2VyQGF0Y2hv\r\n" +"by5vcmcwHhcNMjAwNjA5MTEwNjM5WhcNMzAwNjA3MTEwNjM5WjCBkDELMAkGA1UE\r\n" +"BhMCR0IxFzAVBgNVBAgMDlVuaXRlZCBLaW5nZG9tMQ4wDAYDVQQHDAVEZXJieTES\r\n" +"MBAGA1UECgwJTW9zcXVpdHRvMQswCQYDVQQLDAJDQTEWMBQGA1UEAwwNbW9zcXVp\r\n" +"dHRvLm9yZzEfMB0GCSqGSIb3DQEJARYQcm9nZXJAYXRjaG9vLm9yZzCCASIwDQYJ\r\n" +"KoZIhvcNAQEBBQADggEPADCCAQoCggEBAME0HKmIzfTOwkKLT3THHe+ObdizamPg\r\n" +"UZmD64Tf3zJdNeYGYn4CEXbyP6fy3tWc8S2boW6dzrH8SdFf9uo320GJA9B7U1FW\r\n" +"Te3xda/Lm3JFfaHjkWw7jBwcauQZjpGINHapHRlpiCZsquAthOgxW9SgDgYlGzEA\r\n" +"s06pkEFiMw+qDfLo/sxFKB6vQlFekMeCymjLCbNwPJyqyhFmPWwio/PDMruBTzPH\r\n" +"3cioBnrJWKXc3OjXdLGFJOfj7pP0j/dr2LH72eSvv3PQQFl90CZPFhrCUcRHSSxo\r\n" +"E6yjGOdnz7f6PveLIB574kQORwt8ePn0yidrTC1ictikED3nHYhMUOUCAwEAAaNT\r\n" +"MFEwHQYDVR0OBBYEFPVV6xBUFPiGKDyo5V3+Hbh4N9YSMB8GA1UdIwQYMBaAFPVV\r\n" +"6xBUFPiGKDyo5V3+Hbh4N9YSMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL\r\n" +"BQADggEBAGa9kS21N70ThM6/Hj9D7mbVxKLBjVWe2TPsGfbl3rEDfZ+OKRZ2j6AC\r\n" +"6r7jb4TZO3dzF2p6dgbrlU71Y/4K0TdzIjRj3cQ3KSm41JvUQ0hZ/c04iGDg/xWf\r\n" +"+pp58nfPAYwuerruPNWmlStWAXf0UTqRtg4hQDWBuUFDJTuWuuBvEXudz74eh/wK\r\n" +"sMwfu1HFvjy5Z0iMDU8PUDepjVolOCue9ashlS4EB5IECdSR2TItnAIiIwimx839\r\n" +"LdUdRudafMu5T5Xma182OC0/u/xRlEm+tvKGGmfFcN0piqVl8OrSPBgIlb+1IKJE\r\n" +"m/XriWr/Cq4h/JfB7NTsezVslgkBaoU=\r\n" +"-----END CERTIFICATE-----\r\n"; + +#endif /* __CERT_H__ */ diff --git a/samples/net/sockets/big_http_download/sample.yaml b/samples/net/sockets/big_http_download/sample.yaml index b8777a4e871..683b8c5c52c 100644 --- a/samples/net/sockets/big_http_download/sample.yaml +++ b/samples/net/sockets/big_http_download/sample.yaml @@ -9,6 +9,9 @@ common: tags: - net - socket + platform_exclude: + - native_posix + - native_posix/native/64 tests: sample.net.sockets.big_http_download: extra_configs: diff --git a/samples/net/sockets/coap_server/CMakeLists.txt b/samples/net/sockets/coap_server/CMakeLists.txt index 17d20709825..932e3cfdeeb 100644 --- a/samples/net/sockets/coap_server/CMakeLists.txt +++ b/samples/net/sockets/coap_server/CMakeLists.txt @@ -8,4 +8,11 @@ FILE(GLOB app_sources src/*.c) target_sources(app PRIVATE ${app_sources}) target_include_directories(app PRIVATE ${ZEPHYR_BASE}/subsys/net/ip) +# Support LD linker template zephyr_linker_sources(DATA_SECTIONS sections-ram.ld) + +# Support CMake linker generator +zephyr_iterable_section( + NAME coap_resource_coap_server + GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} + SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) diff --git a/samples/net/sockets/coap_server/sections-ram.ld b/samples/net/sockets/coap_server/sections-ram.ld index 04534264195..cd954bd89c2 100644 --- a/samples/net/sockets/coap_server/sections-ram.ld +++ b/samples/net/sockets/coap_server/sections-ram.ld @@ -2,4 +2,4 @@ #include -ITERABLE_SECTION_RAM(coap_resource_coap_server, 4) +ITERABLE_SECTION_RAM(coap_resource_coap_server, Z_LINK_ITERABLE_SUBALIGN) diff --git a/samples/net/sockets/coap_server/src/separate.c b/samples/net/sockets/coap_server/src/separate.c index 68bba0bb473..7a5b1737cba 100644 --- a/samples/net/sockets/coap_server/src/separate.c +++ b/samples/net/sockets/coap_server/src/separate.c @@ -57,7 +57,7 @@ static int separate_get(struct coap_resource *resource, /* Re-use the buffer */ r = coap_packet_init(&response, data, sizeof(data), COAP_VERSION_1, type, tkl, token, - COAP_RESPONSE_CODE_CONTENT, id); + COAP_RESPONSE_CODE_CONTENT, coap_next_id()); if (r < 0) { return r; } diff --git a/samples/net/sockets/echo/src/socket_echo.c b/samples/net/sockets/echo/src/socket_echo.c index 5ebf954ff49..c8aad2bb068 100644 --- a/samples/net/sockets/echo/src/socket_echo.c +++ b/samples/net/sockets/echo/src/socket_echo.c @@ -26,7 +26,8 @@ int main(void) { - int opt, optlen = sizeof(int); + int opt; + socklen_t optlen = sizeof(int); int serv, ret; struct sockaddr_in6 bind_addr = { .sin6_family = AF_INET6, diff --git a/samples/net/sockets/echo_async/prj.conf b/samples/net/sockets/echo_async/prj.conf index 2b0e18a3d9d..0de41968710 100644 --- a/samples/net/sockets/echo_async/prj.conf +++ b/samples/net/sockets/echo_async/prj.conf @@ -23,4 +23,3 @@ 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" -CONFIG_NET_CONFIG_BT_NODE=y diff --git a/samples/net/sockets/echo_client/README.rst b/samples/net/sockets/echo_client/README.rst index e142cd8b02f..289a90acc39 100644 --- a/samples/net/sockets/echo_client/README.rst +++ b/samples/net/sockets/echo_client/README.rst @@ -41,9 +41,6 @@ echo-client directory: improve connection reliability, acknowledgments can be enabled with shell command: ``ieee802154 ack set``. -- :file:`overlay-bt.conf` - This overlay config enables support for Bluetooth IPSP connectivity. - - :file:`overlay-qemu_802154.conf` This overlay config enables support for two QEMU's when simulating IEEE 802.15.4 network that are connected together. diff --git a/samples/net/sockets/echo_client/overlay-802154-subg.conf b/samples/net/sockets/echo_client/overlay-802154-subg.conf index d9e479bfa43..fdacc3747cb 100644 --- a/samples/net/sockets/echo_client/overlay-802154-subg.conf +++ b/samples/net/sockets/echo_client/overlay-802154-subg.conf @@ -1,7 +1,6 @@ CONFIG_BT=n -# Disable TCP and IPv4 (TCP disabled to avoid heavy traffic) -CONFIG_NET_TCP=n +# Disable IPv4 CONFIG_NET_IPV4=n CONFIG_NET_CONFIG_NEED_IPV6=y diff --git a/samples/net/sockets/echo_client/overlay-bt.conf b/samples/net/sockets/echo_client/overlay-bt.conf deleted file mode 100644 index 2902c730025..00000000000 --- a/samples/net/sockets/echo_client/overlay-bt.conf +++ /dev/null @@ -1,16 +0,0 @@ -CONFIG_BT=y -CONFIG_LOG=y -CONFIG_BT_SMP=y -CONFIG_BT_PERIPHERAL=y -CONFIG_BT_CENTRAL=y -CONFIG_BT_L2CAP_DYNAMIC_CHANNEL=y -CONFIG_BT_DEVICE_NAME="Zephyr Echo Client" -CONFIG_NET_L2_BT=y -CONFIG_NET_IPV4=n -CONFIG_NET_IPV6=y -CONFIG_NET_CONFIG_BT_NODE=y -CONFIG_NET_CONFIG_NEED_IPV6=y -CONFIG_NET_CONFIG_NEED_IPV4=n -CONFIG_NET_CONFIG_MY_IPV4_ADDR="" -CONFIG_NET_CONFIG_PEER_IPV4_ADDR="" -CONFIG_NET_BUF_RX_COUNT=64 diff --git a/samples/net/sockets/echo_client/prj.conf b/samples/net/sockets/echo_client/prj.conf index 016911f5917..f73510d861e 100644 --- a/samples/net/sockets/echo_client/prj.conf +++ b/samples/net/sockets/echo_client/prj.conf @@ -15,6 +15,7 @@ CONFIG_MAIN_STACK_SIZE=2048 CONFIG_ENTROPY_GENERATOR=y CONFIG_TEST_RANDOM_GENERATOR=y CONFIG_INIT_STACKS=y +CONFIG_MAX_THREAD_BYTES=3 # Logging CONFIG_NET_LOG=y @@ -50,3 +51,5 @@ CONFIG_NET_CONFIG_NEED_IPV4=y CONFIG_NET_CONFIG_MY_IPV4_ADDR="192.0.2.2" CONFIG_NET_CONFIG_PEER_IPV4_ADDR="192.0.2.1" CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048 + +CONFIG_MAX_THREAD_BYTES=3 diff --git a/samples/net/sockets/echo_client/sample.yaml b/samples/net/sockets/echo_client/sample.yaml index 008920a33bf..2f3d58fb81c 100644 --- a/samples/net/sockets/echo_client/sample.yaml +++ b/samples/net/sockets/echo_client/sample.yaml @@ -62,10 +62,6 @@ tests: - SHIELD=atmel_rf2xx_mikrobus - OVERLAY_CONFIG="overlay-802154.conf" platform_allow: lpcxpresso55s69/lpc55s69/cpu0/ns - sample.net.sockets.echo_client.bt: - extra_args: OVERLAY_CONFIG="overlay-bt.conf" - platform_allow: qemu_x86 - tags: bluetooth sample.net.sockets.echo_client.mcr20a: extra_args: - SHIELD=frdm_cr20a diff --git a/samples/net/sockets/echo_client/src/common.h b/samples/net/sockets/echo_client/src/common.h index e0b06b7ee14..d7a8b6c69e5 100644 --- a/samples/net/sockets/echo_client/src/common.h +++ b/samples/net/sockets/echo_client/src/common.h @@ -12,6 +12,11 @@ #define PEER_PORT 4242 +/* Turn off the progress printing so that shell can be used. + * Set to true if you want to see progress output. + */ +#define PRINT_PROGRESS false + #if defined(CONFIG_USERSPACE) #include extern struct k_mem_partition app_partition; diff --git a/samples/net/sockets/echo_client/src/echo-client.c b/samples/net/sockets/echo_client/src/echo-client.c index 3e4aff0f2d0..59bc9be99f9 100644 --- a/samples/net/sockets/echo_client/src/echo-client.c +++ b/samples/net/sockets/echo_client/src/echo-client.c @@ -24,9 +24,11 @@ LOG_MODULE_REGISTER(net_echo_client_sample, LOG_LEVEL_DBG); #include #include +#include + #include #include - +#include #include #include #include @@ -46,6 +48,8 @@ struct k_mem_domain app_domain; #define EVENT_MASK (NET_EVENT_L4_CONNECTED | \ NET_EVENT_L4_DISCONNECTED) +#define IPV6_EVENT_MASK (NET_EVENT_IPV6_ADDR_ADD | \ + NET_EVENT_IPV6_ADDR_DEPRECATED) /* Generated by http://www.lipsum.com/ * 2 paragraphs, 179 words, 1160 bytes of Lorem Ipsum @@ -87,16 +91,26 @@ APP_DMEM struct configs conf = { }, }; -static APP_BMEM struct pollfd fds[4]; +static APP_BMEM struct pollfd fds[1 + 4]; static APP_BMEM int nfds; static APP_BMEM bool connected; +static APP_BMEM bool need_restart; + K_SEM_DEFINE(run_app, 0, 1); static struct net_mgmt_event_callback mgmt_cb; +static struct net_mgmt_event_callback ipv6_mgmt_cb; static void prepare_fds(void) { + nfds = 0; + + /* eventfd is used to trigger restart */ + fds[nfds].fd = eventfd(0, 0); + fds[nfds].events = POLLIN; + nfds++; + if (conf.ipv4.udp.sock >= 0) { fds[nfds].fd = conf.ipv4.udp.sock; fds[nfds].events = POLLIN; @@ -124,11 +138,29 @@ static void prepare_fds(void) static void wait(void) { + int ret; + /* Wait for event on any socket used. Once event occurs, * we'll check them all. */ - if (poll(fds, nfds, -1) < 0) { - LOG_ERR("Error in poll:%d", errno); + ret = poll(fds, nfds, -1); + if (ret < 0) { + static bool once; + + if (!once) { + once = true; + LOG_ERR("Error in poll:%d", errno); + } + + return; + } + + if (ret > 0 && fds[0].revents) { + eventfd_t value; + + eventfd_read(fds[0].fd, &value); + LOG_DBG("Received restart event."); + return; } } @@ -193,6 +225,99 @@ static void stop_udp_and_tcp(void) } } +static int check_our_ipv6_sockets(int sock, + struct in6_addr *deprecated_addr) +{ + struct sockaddr_in6 addr = { 0 }; + socklen_t addrlen = sizeof(addr); + int ret; + + if (sock < 0) { + return -EINVAL; + } + + ret = getsockname(sock, (struct sockaddr *)&addr, &addrlen); + if (ret != 0) { + return -errno; + } + + if (!net_ipv6_addr_cmp(deprecated_addr, &addr.sin6_addr)) { + return -ENOENT; + } + + need_restart = true; + + return 0; +} + +static void ipv6_event_handler(struct net_mgmt_event_callback *cb, + uint32_t mgmt_event, struct net_if *iface) +{ + static char addr_str[INET6_ADDRSTRLEN]; + + if (!IS_ENABLED(CONFIG_NET_IPV6_PE)) { + return; + } + + if ((mgmt_event & IPV6_EVENT_MASK) != mgmt_event) { + return; + } + + if (cb->info == NULL || + cb->info_length != sizeof(struct in6_addr)) { + return; + } + + if (mgmt_event == NET_EVENT_IPV6_ADDR_ADD) { + struct net_if_addr *ifaddr; + struct in6_addr added_addr; + + memcpy(&added_addr, cb->info, sizeof(struct in6_addr)); + + ifaddr = net_if_ipv6_addr_lookup(&added_addr, &iface); + if (ifaddr == NULL) { + return; + } + + /* Wait until we get a temporary address before continuing after + * boot. + */ + if (ifaddr->is_temporary) { + static bool once; + + LOG_INF("Temporary IPv6 address %s added", + inet_ntop(AF_INET6, &added_addr, addr_str, + sizeof(addr_str) - 1)); + + if (!once) { + k_sem_give(&run_app); + once = true; + } + } + } + + if (mgmt_event == NET_EVENT_IPV6_ADDR_DEPRECATED) { + struct in6_addr deprecated_addr; + + memcpy(&deprecated_addr, cb->info, sizeof(struct in6_addr)); + + LOG_INF("IPv6 address %s deprecated", + inet_ntop(AF_INET6, &deprecated_addr, addr_str, + sizeof(addr_str) - 1)); + + (void)check_our_ipv6_sockets(conf.ipv6.tcp.sock, + &deprecated_addr); + (void)check_our_ipv6_sockets(conf.ipv6.udp.sock, + &deprecated_addr); + + if (need_restart) { + eventfd_write(fds[0].fd, 1); + } + + return; + } +} + static void event_handler(struct net_mgmt_event_callback *cb, uint32_t mgmt_event, struct net_if *iface) { @@ -206,7 +331,10 @@ static void event_handler(struct net_mgmt_event_callback *cb, connected = true; conf.ipv4.udp.mtu = net_if_get_mtu(iface); conf.ipv6.udp.mtu = conf.ipv4.udp.mtu; - k_sem_give(&run_app); + + if (!IS_ENABLED(CONFIG_NET_IPV6_PE)) { + k_sem_give(&run_app); + } return; } @@ -275,6 +403,10 @@ static void init_app(void) conn_mgr_mon_resend_status(); } + net_mgmt_init_event_callback(&ipv6_mgmt_cb, + ipv6_event_handler, IPV6_EVENT_MASK); + net_mgmt_add_event_callback(&ipv6_mgmt_cb); + init_vlan(); init_udp(); } @@ -293,19 +425,35 @@ static void start_client(void *p1, void *p2, void *p3) /* Wait for the connection. */ k_sem_take(&run_app, K_FOREVER); - ret = start_udp_and_tcp(); + if (IS_ENABLED(CONFIG_NET_IPV6_PE)) { + /* Make sure that we have a temporary address */ + k_sleep(K_SECONDS(1)); + } - while (connected && (ret == 0)) { - ret = run_udp_and_tcp(); + do { + if (need_restart) { + /* Close all sockets and get a fresh restart */ + stop_udp_and_tcp(); + need_restart = false; + } - if (iterations > 0) { - i++; - if (i >= iterations) { - break; + ret = start_udp_and_tcp(); + + while (connected && (ret == 0)) { + ret = run_udp_and_tcp(); + if (iterations > 0) { + i++; + if (i >= iterations) { + break; + } + } + + if (need_restart) { + break; } } - } + } while (need_restart); stop_udp_and_tcp(); } diff --git a/samples/net/sockets/echo_client/src/tcp.c b/samples/net/sockets/echo_client/src/tcp.c index 5833d399088..eee8994425c 100644 --- a/samples/net/sockets/echo_client/src/tcp.c +++ b/samples/net/sockets/echo_client/src/tcp.c @@ -63,8 +63,10 @@ static int send_tcp_data(struct data *data) LOG_ERR("%s TCP: Failed to send data, errno %d", data->proto, errno); } else { - LOG_DBG("%s TCP: Sent %d bytes", data->proto, - data->tcp.expecting); + if (PRINT_PROGRESS) { + LOG_DBG("%s TCP: Sent %d bytes", data->proto, + data->tcp.expecting); + } } return ret; @@ -88,6 +90,7 @@ static int compare_tcp_data(struct data *data, const char *buf, uint32_t receive static int start_tcp_proto(struct data *data, struct sockaddr *addr, socklen_t addrlen) { + int optval; int ret; #if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS) @@ -159,6 +162,14 @@ static int start_tcp_proto(struct data *data, struct sockaddr *addr, } #endif + /* Prefer IPv6 temporary addresses */ + if (addr->sa_family == AF_INET6) { + optval = IPV6_PREFER_SRC_TMP; + (void)setsockopt(data->tcp.sock, IPPROTO_IPV6, + IPV6_ADDR_PREFERENCES, + &optval, sizeof(optval)); + } + ret = connect(data->tcp.sock, addr, addrlen); if (ret < 0) { LOG_ERR("Cannot connect to TCP remote (%s): %d", data->proto, @@ -201,10 +212,11 @@ static int process_tcp_proto(struct data *data) continue; } - /* Response complete */ - LOG_DBG("%s TCP: Received and compared %d bytes, all ok", - data->proto, data->tcp.received); - + if (PRINT_PROGRESS) { + /* Response complete */ + LOG_DBG("%s TCP: Received and compared %d bytes, all ok", + data->proto, data->tcp.received); + } if (++data->tcp.counter % 1000 == 0U) { LOG_INF("%s TCP: Exchanged %u packets", data->proto, @@ -230,7 +242,8 @@ int start_tcp(void) inet_pton(AF_INET6, CONFIG_NET_CONFIG_PEER_IPV6_ADDR, &addr6.sin6_addr); - ret = start_tcp_proto(&conf.ipv6, (struct sockaddr *)&addr6, + ret = start_tcp_proto(&conf.ipv6, + (struct sockaddr *)&addr6, sizeof(addr6)); if (ret < 0) { return ret; diff --git a/samples/net/sockets/echo_client/src/udp.c b/samples/net/sockets/echo_client/src/udp.c index e5b7ea1dae0..3055c2d03f2 100644 --- a/samples/net/sockets/echo_client/src/udp.c +++ b/samples/net/sockets/echo_client/src/udp.c @@ -147,7 +147,9 @@ static int send_udp_data(struct data *data) ret = send(data->udp.sock, lorem_ipsum, data->udp.expecting, 0); - LOG_DBG("%s UDP: Sent %d bytes", data->proto, data->udp.expecting); + if (PRINT_PROGRESS) { + LOG_DBG("%s UDP: Sent %d bytes", data->proto, data->udp.expecting); + } k_timer_start(&data->udp.ctrl->rx_timer, UDP_WAIT, K_NO_WAIT); @@ -191,6 +193,7 @@ static void wait_transmit(struct k_timer *timer) static int start_udp_proto(struct data *data, struct sockaddr *addr, socklen_t addrlen) { + int optval; int ret; #if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS) @@ -229,6 +232,14 @@ static int start_udp_proto(struct data *data, struct sockaddr *addr, } #endif + /* Prefer IPv6 temporary addresses */ + if (addr->sa_family == AF_INET6) { + optval = IPV6_PREFER_SRC_TMP; + (void)setsockopt(data->udp.sock, IPPROTO_IPV6, + IPV6_ADDR_PREFERENCES, + &optval, sizeof(optval)); + } + /* Call connect so we can use send and recv. */ ret = connect(data->udp.sock, addr, addrlen); if (ret < 0) { @@ -266,9 +277,11 @@ static int process_udp_proto(struct data *data) return 0; } - /* Correct response received */ - LOG_DBG("%s UDP: Received and compared %d bytes, all ok", - data->proto, received); + if (PRINT_PROGRESS) { + /* Correct response received */ + LOG_DBG("%s UDP: Received and compared %d bytes, all ok", + data->proto, received); + } if (++data->udp.counter % 1000 == 0U) { LOG_INF("%s UDP: Exchanged %u packets", data->proto, @@ -299,7 +312,8 @@ int start_udp(void) inet_pton(AF_INET6, CONFIG_NET_CONFIG_PEER_IPV6_ADDR, &addr6.sin6_addr); - ret = start_udp_proto(&conf.ipv6, (struct sockaddr *)&addr6, + ret = start_udp_proto(&conf.ipv6, + (struct sockaddr *)&addr6, sizeof(addr6)); if (ret < 0) { return ret; diff --git a/samples/net/sockets/echo_server/README.rst b/samples/net/sockets/echo_server/README.rst index 0d87359e7b1..cb4aa3756ae 100644 --- a/samples/net/sockets/echo_server/README.rst +++ b/samples/net/sockets/echo_server/README.rst @@ -42,9 +42,6 @@ echo-server directory: improve connection reliability, acknowledgments can be enabled with shell command: ``ieee802154 ack set``. -- :file:`overlay-bt.conf` - This overlay config enables support for Bluetooth IPSP connectivity. - - :file:`overlay-qemu_802154.conf` This overlay config enables support for two QEMU's when simulating IEEE 802.15.4 network that are connected together. diff --git a/samples/net/sockets/echo_server/overlay-802154-subg.conf b/samples/net/sockets/echo_server/overlay-802154-subg.conf index 66da936e300..cfa509d8cf4 100644 --- a/samples/net/sockets/echo_server/overlay-802154-subg.conf +++ b/samples/net/sockets/echo_server/overlay-802154-subg.conf @@ -1,7 +1,6 @@ CONFIG_BT=n -# Disable TCP and IPv4 (TCP disabled to avoid heavy traffic) -CONFIG_NET_TCP=n +# Disable IPv4 CONFIG_NET_IPV4=n CONFIG_NET_CONFIG_NEED_IPV6=y diff --git a/samples/net/sockets/echo_server/overlay-bt.conf b/samples/net/sockets/echo_server/overlay-bt.conf deleted file mode 100644 index 66b316c06c8..00000000000 --- a/samples/net/sockets/echo_server/overlay-bt.conf +++ /dev/null @@ -1,15 +0,0 @@ -CONFIG_BT=y -CONFIG_LOG=y -CONFIG_BT_SMP=y -CONFIG_BT_PERIPHERAL=y -CONFIG_BT_CENTRAL=y -CONFIG_BT_L2CAP_DYNAMIC_CHANNEL=y -CONFIG_BT_DEVICE_NAME="Zephyr Echo Server" -CONFIG_NET_L2_BT=y -CONFIG_NET_IPV4=n -CONFIG_NET_IPV6=y -CONFIG_NET_CONFIG_BT_NODE=y -CONFIG_NET_CONFIG_NEED_IPV6=y -CONFIG_NET_CONFIG_NEED_IPV4=n -CONFIG_NET_CONFIG_MY_IPV4_ADDR="" -CONFIG_NET_CONFIG_PEER_IPV4_ADDR="" diff --git a/samples/net/sockets/echo_server/sample.yaml b/samples/net/sockets/echo_server/sample.yaml index 748df44b5c2..15c9c271499 100644 --- a/samples/net/sockets/echo_server/sample.yaml +++ b/samples/net/sockets/echo_server/sample.yaml @@ -64,10 +64,6 @@ tests: - SHIELD=atmel_rf2xx_mikrobus - OVERLAY_CONFIG="overlay-802154.conf" platform_allow: lpcxpresso55s69/lpc55s69/cpu0/ns - sample.net.sockets.echo_server.bt: - extra_args: OVERLAY_CONFIG="overlay-bt.conf" - platform_allow: qemu_x86 - tags: bluetooth sample.net.sockets.echo_server.mcr20a: extra_args: - SHIELD=frdm_cr20a diff --git a/samples/net/sockets/echo_server/src/tcp.c b/samples/net/sockets/echo_server/src/tcp.c index 1a6555d43c3..c9d5cc68ebd 100644 --- a/samples/net/sockets/echo_server/src/tcp.c +++ b/samples/net/sockets/echo_server/src/tcp.c @@ -68,6 +68,7 @@ static int start_tcp_proto(struct data *data, struct sockaddr *bind_addr, socklen_t bind_addrlen) { + int optval; int ret; #if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS) @@ -100,6 +101,22 @@ static int start_tcp_proto(struct data *data, } #endif + if (bind_addr->sa_family == AF_INET6) { + /* Prefer IPv6 temporary addresses */ + optval = IPV6_PREFER_SRC_PUBLIC; + (void)setsockopt(data->tcp.sock, IPPROTO_IPV6, + IPV6_ADDR_PREFERENCES, + &optval, sizeof(optval)); + + /* + * Bind only to IPv6 without mapping to IPv4, since we bind to + * IPv4 using another socket + */ + optval = 1; + (void)setsockopt(data->tcp.sock, IPPROTO_IPV6, IPV6_V6ONLY, + &optval, sizeof(optval)); + } + ret = bind(data->tcp.sock, bind_addr, bind_addrlen); if (ret < 0) { LOG_ERR("Failed to bind TCP socket (%s): %d", data->proto, diff --git a/samples/net/sockets/echo_server/src/udp.c b/samples/net/sockets/echo_server/src/udp.c index 69affd53b69..3afe2930151 100644 --- a/samples/net/sockets/echo_server/src/udp.c +++ b/samples/net/sockets/echo_server/src/udp.c @@ -36,6 +36,7 @@ K_THREAD_DEFINE(udp6_thread_id, STACK_SIZE, static int start_udp_proto(struct data *data, struct sockaddr *bind_addr, socklen_t bind_addrlen) { + int optval; int ret; #if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS) @@ -77,6 +78,22 @@ static int start_udp_proto(struct data *data, struct sockaddr *bind_addr, } #endif + if (bind_addr->sa_family == AF_INET6) { + /* Prefer IPv6 temporary addresses */ + optval = IPV6_PREFER_SRC_PUBLIC; + (void)setsockopt(data->tcp.sock, IPPROTO_IPV6, + IPV6_ADDR_PREFERENCES, + &optval, sizeof(optval)); + + /* + * Bind only to IPv6 without mapping to IPv4, since we bind to + * IPv4 using another socket + */ + optval = 1; + (void)setsockopt(data->tcp.sock, IPPROTO_IPV6, IPV6_V6ONLY, + &optval, sizeof(optval)); + } + ret = bind(data->udp.sock, bind_addr, bind_addrlen); if (ret < 0) { NET_ERR("Failed to bind UDP socket (%s): %d", data->proto, diff --git a/samples/net/sockets/http_client/README.rst b/samples/net/sockets/http_client/README.rst index 855c36d068a..d360ae45edf 100644 --- a/samples/net/sockets/http_client/README.rst +++ b/samples/net/sockets/http_client/README.rst @@ -1,5 +1,5 @@ .. zephyr:code-sample:: sockets-http-client - :name: HTTP client + :name: HTTP Client :relevant-api: bsd_sockets http_client tls_credentials secure_sockets_options Implement an HTTP(S) client that issues a variety of HTTP requests. diff --git a/samples/net/sockets/http_get/overlay-tls.conf b/samples/net/sockets/http_get/overlay-tls.conf index 3dd9096519f..29bfc2372f8 100644 --- a/samples/net/sockets/http_get/overlay-tls.conf +++ b/samples/net/sockets/http_get/overlay-tls.conf @@ -6,5 +6,6 @@ CONFIG_MBEDTLS_BUILTIN=y CONFIG_MBEDTLS_ENABLE_HEAP=y CONFIG_MBEDTLS_HEAP_SIZE=60000 CONFIG_MBEDTLS_SSL_MAX_CONTENT_LEN=7168 +CONFIG_MBEDTLS_MAC_ALL_ENABLED=y CONFIG_NET_SOCKETS_SOCKOPT_TLS=y diff --git a/samples/net/sockets/http_get/sample.yaml b/samples/net/sockets/http_get/sample.yaml index 4e454da50a7..2d584cf5e99 100644 --- a/samples/net/sockets/http_get/sample.yaml +++ b/samples/net/sockets/http_get/sample.yaml @@ -8,6 +8,9 @@ common: tags: - net - socket + platform_exclude: + - native_posix + - native_posix/native/64 tests: sample.net.sockets.http_get: filter: not CONFIG_NET_SOCKETS_OFFLOAD and not CONFIG_NATIVE_LIBC diff --git a/samples/net/sockets/http_server/CMakeLists.txt b/samples/net/sockets/http_server/CMakeLists.txt new file mode 100644 index 00000000000..2a8d03ac9b2 --- /dev/null +++ b/samples/net/sockets/http_server/CMakeLists.txt @@ -0,0 +1,61 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +find_package(Python REQUIRED COMPONENTS Interpreter) + +project(http_server) + +if(CONFIG_NET_SOCKETS_SOCKOPT_TLS AND + CONFIG_MBEDTLS_KEY_EXCHANGE_PSK_ENABLED AND + (CONFIG_NET_SAMPLE_PSK_HEADER_FILE STREQUAL "dummy_psk.h")) + add_custom_target(development_psk + COMMAND ${CMAKE_COMMAND} -E echo "----------------------------------------------------------" + COMMAND ${CMAKE_COMMAND} -E echo "--- WARNING: Using dummy PSK! Only suitable for ---" + COMMAND ${CMAKE_COMMAND} -E echo "--- development. Set NET_SAMPLE_PSK_HEADER_FILE to use ---" + COMMAND ${CMAKE_COMMAND} -E echo "--- own pre-shared key. ---" + COMMAND ${CMAKE_COMMAND} -E echo "----------------------------------------------------------" + ) + add_dependencies(app development_psk) +endif() + +option(INCLUDE_HTML_CONTENT "Include the HTML content" ON) + +target_sources(app PRIVATE src/main.c) + +set(gen_dir ${ZEPHYR_BINARY_DIR}/include/generated/) + +set(source_file_index src/index.html) +generate_inc_file_for_target(app ${source_file_index} ${gen_dir}/index.html.gz.inc --gzip) + +set(source_file_not_found src/not_found_page.html) +generate_inc_file_for_target(app ${source_file_not_found} ${gen_dir}/not_found_page.html.gz.inc --gzip) + +target_sources_ifdef(CONFIG_NET_SAMPLE_WEBSOCKET_SERVICE app PRIVATE src/ws.c) + +target_link_libraries(app PRIVATE zephyr_interface zephyr) + +zephyr_linker_sources(SECTIONS sections-rom.ld) +zephyr_linker_section_ifdef(CONFIG_NET_SAMPLE_HTTPS_SERVICE NAME + http_resource_desc_test_https_service + KVMA RAM_REGION GROUP RODATA_REGION + SUBALIGN Z_LINK_ITERABLE_SUBALIGN) +zephyr_linker_section_ifdef(CONFIG_NET_SAMPLE_HTTP_SERVICE NAME + http_resource_desc_test_http_service + KVMA RAM_REGION GROUP RODATA_REGION + SUBALIGN Z_LINK_ITERABLE_SUBALIGN) + +foreach(inc_file + ca.der + server.der + server_privkey.der + https-server-cert.der + https-server-key.der + ) + generate_inc_file_for_target( + app + src/${inc_file} + ${gen_dir}/${inc_file}.inc + ) +endforeach() diff --git a/samples/net/sockets/http_server/Kconfig b/samples/net/sockets/http_server/Kconfig new file mode 100644 index 00000000000..ca55f9692e3 --- /dev/null +++ b/samples/net/sockets/http_server/Kconfig @@ -0,0 +1,53 @@ +# Config options for http2 server sample application + +# Copyright (c) 2023, Emna Rekik +# SPDX-License-Identifier: Apache-2.0 + +mainmenu "HTTP2 server sample application" + +config NET_SAMPLE_HTTP_SERVICE + bool "Enable http service" + default y + +config NET_SAMPLE_HTTP_SERVER_SERVICE_PORT + int "Port number for http service" + default 80 + depends on NET_SAMPLE_HTTP_SERVICE + +config NET_SAMPLE_HTTPS_SERVICE + bool "Enable https service" + depends on NET_SOCKETS_SOCKOPT_TLS || TLS_CREDENTIALS + +config NET_SAMPLE_HTTPS_SERVER_SERVICE_PORT + int "Port number for https service" + default 443 + depends on NET_SAMPLE_HTTPS_SERVICE + +config NET_SAMPLE_PSK_HEADER_FILE + string "Header file containing PSK" + default "dummy_psk.h" + depends on MBEDTLS_KEY_EXCHANGE_PSK_ENABLED + help + Name of a header file containing a + pre-shared key. + +config NET_SAMPLE_CERTS_WITH_SC + bool "Signed certificates" + depends on NET_SOCKETS_SOCKOPT_TLS + help + Enable this flag, if you are interested to run this + application with signed certificates and keys. + +config NET_SAMPLE_WEBSOCKET_SERVICE + bool "Enable websocket service" + default y if HTTP_SERVER_WEBSOCKET + +config NET_SAMPLE_NUM_WEBSOCKET_HANDLERS + int "How many websocket connections to serve at the same time" + depends on NET_SAMPLE_WEBSOCKET_SERVICE + default 1 + help + Each websocket connection is served by a thread which needs + memory. Only increase the value here if really needed. + +source "Kconfig.zephyr" diff --git a/samples/net/sockets/http_server/README.rst b/samples/net/sockets/http_server/README.rst new file mode 100644 index 00000000000..4d802ae1a35 --- /dev/null +++ b/samples/net/sockets/http_server/README.rst @@ -0,0 +1,149 @@ +.. zephyr:code-sample:: sockets-http-server + :name: HTTP Server + :relevant-api: http_service http_server tls_credentials + + Implement an HTTP(s) Server demonstrating various resource types. + +Overview +-------- + +This sample application demonstrates the use of the :ref:`http_server_interface` library. +This library provides high-level functions to simplify and abstract server implementation. +The server supports the HTTP/1.1 protocol which can also be upgraded to HTTP/2, +it also support native HTTP/2 protocol without upgrading. + +Requirement +----------- + +`QEMU Networking `_ + +Building and running the server +------------------------------- + +To build and run the application: + +.. code-block:: bash + + $ west build -p auto -b -t run samples/net/sockets/http_server + +When the server is up, we can make requests to the server using either HTTP/1.1 or +HTTP/2 protocol from the host machine. + +**With HTTP/1.1:** + +- Using a browser: ``http://192.0.2.1/`` +- Using curl: ``curl -v --compressed http://192.0.2.1/`` +- Using ab (Apache Bench): ``ab -n10 http://192.0.2.1/`` + +**With HTTP/2:** + +- Using nghttp client: ``nghttp -v --no-dep http://192.0.2.1/`` +- Using curl: ``curl --http2 -v --compressed http://192.0.2.1/`` +- Using h2load: ``h2load -n10 http://192.0.2.1/`` + +Server Customization +--------------------- + +The server sample contains several parameters that can be customized based on +the requirements. These are the configurable parameters: + +- ``CONFIG_NET_SAMPLE_HTTP_SERVER_SERVICE_PORT``: Configures the service port. + +- ``CONFIG_HTTP_SERVER_MAX_CLIENTS``: Defines the maximum number of HTTP/2 + clients that the server can handle simultaneously. + +- ``CONFIG_HTTP_SERVER_MAX_STREAMS``: Specifies the maximum number of HTTP/2 + streams that can be established per client. + +- ``CONFIG_HTTP_SERVER_CLIENT_BUFFER_SIZE``: Defines the buffer size allocated + for each client. This limits the maximum length of an individual HTTP header + supported. + +- ``CONFIG_HTTP_SERVER_MAX_URL_LENGTH``: Specifies the maximum length of an HTTP + URL that the server can process. + +- ``CONFIG_NET_SAMPLE_WEBSOCKET_SERVICE``: Enables Websocket service endpoint. + This allows a Websocket client to connect to ``/`` endpoint, all the data that + the client sends is echoed back. + +To customize these options, we can run ``west build -t menuconfig``, which provides +us with an interactive configuration interface. Then we could navigate from the top-level +menu to: ``-> Subsystems and OS Services -> Networking -> Network Protocols``. + +Websocket Connectivity +---------------------- + +You can use a simple Websocket client application like this to test the Websocket +connectivity. + +.. code-block:: python + + import websocket + + websocket.enableTrace(True) + ws = websocket.WebSocket() + ws.connect("ws://192.0.2.1/") + ws.send("Hello, Server") + print(ws.recv()) + while True: + line = input("> ") + if line == "quit": + break + ws.send(line) + print(ws.recv()) + ws.close() + + +Performance Analysis +-------------------- + +CPU Usage Profiling +******************* + +We can use ``perf`` to collect statistics about the CPU usage of our server +running in native_sim board with the ``stat`` command: + +.. code-block:: bash + + $ sudo perf stat -p + +``perf stat`` will then start monitoring our server. We can let it run while +sending requests to our server. Once we've collected enough data, we can +stop ``perf stat``, which will print a summary of the performance statistics. + +Hotspot Analysis +**************** + +``perf record`` and ``perf report`` can be used together to identify the +functions in our code that consume the most CPU time: + +.. code-block:: bash + + $ sudo perf record -g -p -o perf.data + +After running our server under load (For example, using ApacheBench tool), +we can stop the recording and analyze the data using: + +.. code-block:: bash + + $ sudo perf report -i perf.data + +After generating a file named ``perf.data`` which contains the profiling data, +we can visualize it using ``FlameGraph`` tool. It's particularly useful for +identifying the most expensive code-paths and inspect where our application is +spending the most time. + +To do this, we need to convert the ``perf.data`` to a format that ``FlameGraph`` +can understand: + +.. code-block:: bash + + $ sudo perf script | ~/FlameGraph/stackcollapse-perf.pl > out.perf-folded + +And, then, generate the ``FlameGraph``: + +.. code-block:: bash + + $ ~/FlameGraph/flamegraph.pl out.perf-folded > flamegraph.svg + +We can view flamegraph.svg using a web browser. diff --git a/samples/net/sockets/http_server/prj.conf b/samples/net/sockets/http_server/prj.conf new file mode 100644 index 00000000000..3d13a55cbf2 --- /dev/null +++ b/samples/net/sockets/http_server/prj.conf @@ -0,0 +1,72 @@ +# General config +CONFIG_MAIN_STACK_SIZE=3072 +CONFIG_SHELL=y +CONFIG_LOG=y +CONFIG_ENTROPY_GENERATOR=y +CONFIG_TEST_RANDOM_GENERATOR=y +CONFIG_INIT_STACKS=y +CONFIG_POSIX_MAX_FDS=32 +CONFIG_POSIX_API=y +CONFIG_FDTABLE=y +CONFIG_NET_SOCKETS_POLL_MAX=32 + +# Eventfd +CONFIG_EVENTFD=y + +# Networking config +CONFIG_NETWORKING=y +CONFIG_NET_IPV4=y +CONFIG_NET_IPV6=y +CONFIG_NET_TCP=y +CONFIG_NET_SOCKETS=y +CONFIG_NET_CONNECTION_MANAGER=y +CONFIG_NET_SHELL=y +CONFIG_NET_LOG=y + +# JSON +CONFIG_JSON_LIBRARY=y + +# HTTP parser +CONFIG_HTTP_PARSER_URL=y +CONFIG_HTTP_PARSER=y +CONFIG_HTTP_SERVER=y +CONFIG_HTTP_SERVER_WEBSOCKET=y + +# Network buffers +CONFIG_NET_PKT_RX_COUNT=16 +CONFIG_NET_PKT_TX_COUNT=16 +CONFIG_NET_BUF_RX_COUNT=128 +CONFIG_NET_BUF_TX_COUNT=128 +CONFIG_NET_CONTEXT_NET_PKT_POOL=y + +# IP address options +CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=3 +CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=4 +CONFIG_NET_MAX_CONTEXTS=32 +CONFIG_NET_MAX_CONN=32 + +# 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_IPV4_GW="192.0.2.2" +CONFIG_NET_CONFIG_MY_IPV6_ADDR="2001:db8::1" +CONFIG_NET_CONFIG_PEER_IPV6_ADDR="2001:db8::2" + +# TLS configuration +CONFIG_MBEDTLS=y +CONFIG_MBEDTLS_BUILTIN=y +CONFIG_MBEDTLS_ENABLE_HEAP=y +CONFIG_MBEDTLS_HEAP_SIZE=60000 +CONFIG_MBEDTLS_SSL_MAX_CONTENT_LEN=2048 +CONFIG_NET_SOCKETS_SOCKOPT_TLS=y +CONFIG_NET_SOCKETS_TLS_MAX_CONTEXTS=6 +CONFIG_TLS_CREDENTIALS=y +CONFIG_TLS_MAX_CREDENTIALS_NUMBER=5 + +# Networking tweaks +# Required to handle large number of consecutive connections, +# e.g. when testing with ApacheBench. +CONFIG_NET_TCP_TIME_WAIT_DELAY=0 diff --git a/samples/net/sockets/http_server/sample.yaml b/samples/net/sockets/http_server/sample.yaml new file mode 100644 index 00000000000..eeaca47d386 --- /dev/null +++ b/samples/net/sockets/http_server/sample.yaml @@ -0,0 +1,16 @@ +sample: + description: HTTP Server Sample + name: http_server_sample +common: + harness: net + min_ram: 192 + tags: + - http + - net + - server + - socket + platform_exclude: + - native_posix + - native_posix/native/64 +tests: + sample.net.sockets.http.server: {} diff --git a/samples/net/sockets/http_server/sections-rom.ld b/samples/net/sockets/http_server/sections-rom.ld new file mode 100644 index 00000000000..d51cad087f3 --- /dev/null +++ b/samples/net/sockets/http_server/sections-rom.ld @@ -0,0 +1,4 @@ +#include + +ITERABLE_SECTION_ROM(http_resource_desc_test_http_service, Z_LINK_ITERABLE_SUBALIGN) +ITERABLE_SECTION_ROM(http_resource_desc_test_https_service, Z_LINK_ITERABLE_SUBALIGN) diff --git a/samples/net/sockets/http_server/src/ca.der b/samples/net/sockets/http_server/src/ca.der new file mode 100644 index 00000000000..b1d3e097cad Binary files /dev/null and b/samples/net/sockets/http_server/src/ca.der differ diff --git a/samples/net/sockets/http_server/src/certificate.h b/samples/net/sockets/http_server/src/certificate.h new file mode 100644 index 00000000000..52a3fa9c8ea --- /dev/null +++ b/samples/net/sockets/http_server/src/certificate.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __CERTIFICATE_H__ +#define __CERTIFICATE_H__ + +enum tls_tag { + /** The Certificate Authority public key */ + HTTP_SERVER_CA_CERTIFICATE_TAG, + /** Used for both the public and private server keys */ + HTTP_SERVER_CERTIFICATE_TAG, + /** Used for both the public and private client keys */ + HTTP_SERVER_CLIENT_CERTIFICATE_TAG, + PSK_TAG, +}; + +#if !defined(CONFIG_NET_SAMPLE_CERTS_WITH_SC) +static const unsigned char server_certificate[] = { +#include "https-server-cert.der.inc" +}; + +/* This is the private key in pkcs#8 format. */ +static const unsigned char private_key[] = { +#include "https-server-key.der.inc" +}; + +#else + +static const unsigned char ca_certificate[] = { +#include "ca.der.inc" +}; + +static const unsigned char server_certificate[] = { +#include "server.der.inc" +}; + +/* This is the private key in pkcs#8 format. */ +static const unsigned char private_key[] = { +#include "server_privkey.der.inc" +}; +#endif + +#if defined(CONFIG_MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) +#include CONFIG_NET_SAMPLE_PSK_HEADER_FILE +#endif + +#endif /* __CERTIFICATE_H__ */ diff --git a/samples/net/sockets/http_server/src/dummy_psk.h b/samples/net/sockets/http_server/src/dummy_psk.h new file mode 100644 index 00000000000..e67107266fd --- /dev/null +++ b/samples/net/sockets/http_server/src/dummy_psk.h @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2019 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __DUMMY_PSK_H__ +#define __DUMMY_PSK_H__ + +static const unsigned char psk[] = {0x01, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, +0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}; +static const char psk_id[] = "PSK_identity"; + +#endif /* __DUMMY_PSK_H__ */ diff --git a/samples/net/sockets/http_server/src/https-server-cert.der b/samples/net/sockets/http_server/src/https-server-cert.der new file mode 100644 index 00000000000..bfcb335e31c Binary files /dev/null and b/samples/net/sockets/http_server/src/https-server-cert.der differ diff --git a/samples/net/sockets/http_server/src/https-server-key.der b/samples/net/sockets/http_server/src/https-server-key.der new file mode 100644 index 00000000000..5a4d67372ea Binary files /dev/null and b/samples/net/sockets/http_server/src/https-server-key.der differ diff --git a/samples/net/sockets/http_server/src/index.html b/samples/net/sockets/http_server/src/index.html new file mode 100644 index 00000000000..ad654e6a305 --- /dev/null +++ b/samples/net/sockets/http_server/src/index.html @@ -0,0 +1,10 @@ + + + + Zephyr HTTP Server + + +

Welcome to Zephyr HTTP Server!

+

This is a simple HTML file.

+ + diff --git a/samples/net/sockets/http_server/src/main.c b/samples/net/sockets/http_server/src/main.c new file mode 100644 index 00000000000..ff72f2ed5bb --- /dev/null +++ b/samples/net/sockets/http_server/src/main.c @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2023, Emna Rekik + * Copyright (c) 2024, Nordic Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(net_http_server_sample, LOG_LEVEL_DBG); + +static uint8_t index_html_gz[] = { +#include "index.html.gz.inc" +}; + +#if defined(CONFIG_NET_SAMPLE_HTTP_SERVICE) +static uint16_t test_http_service_port = CONFIG_NET_SAMPLE_HTTP_SERVER_SERVICE_PORT; +HTTP_SERVICE_DEFINE(test_http_service, CONFIG_NET_CONFIG_MY_IPV4_ADDR, &test_http_service_port, 1, + 10, NULL); + +struct http_resource_detail_static index_html_gz_resource_detail = { + .common = { + .type = HTTP_RESOURCE_TYPE_STATIC, + .bitmask_of_supported_http_methods = BIT(HTTP_GET), + .content_encoding = "gzip", + .content_type = "text/html", + }, + .static_data = index_html_gz, + .static_data_len = sizeof(index_html_gz), +}; + +HTTP_RESOURCE_DEFINE(index_html_gz_resource, test_http_service, "/", + &index_html_gz_resource_detail); + +static uint8_t recv_buffer[1024]; + +static int dyn_handler(struct http_client_ctx *client, enum http_data_status status, + uint8_t *buffer, size_t len, void *user_data) +{ +#define MAX_TEMP_PRINT_LEN 32 + static char print_str[MAX_TEMP_PRINT_LEN]; + enum http_method method = client->method; + static size_t processed; + + __ASSERT_NO_MSG(buffer != NULL); + + if (status == HTTP_SERVER_DATA_ABORTED) { + LOG_DBG("Transaction aborted after %zd bytes.", processed); + processed = 0; + return 0; + } + + processed += len; + + snprintf(print_str, sizeof(print_str), "%s received (%zd bytes)", + http_method_str(method), len); + LOG_HEXDUMP_DBG(buffer, len, print_str); + + if (status == HTTP_SERVER_DATA_FINAL) { + LOG_DBG("All data received (%zd bytes).", processed); + processed = 0; + } + + /* This will echo data back to client as the buffer and recv_buffer + * point to same area. + */ + return len; +} + +struct http_resource_detail_dynamic dyn_resource_detail = { + .common = { + .type = HTTP_RESOURCE_TYPE_DYNAMIC, + .bitmask_of_supported_http_methods = + BIT(HTTP_GET) | BIT(HTTP_POST), + }, + .cb = dyn_handler, + .data_buffer = recv_buffer, + .data_buffer_len = sizeof(recv_buffer), + .user_data = NULL, +}; + +HTTP_RESOURCE_DEFINE(dyn_resource, test_http_service, "/dynamic", + &dyn_resource_detail); + +#if defined(CONFIG_NET_SAMPLE_WEBSOCKET_SERVICE) +extern int ws_setup(int ws_socket, void *user_data); + +static uint8_t ws_recv_buffer[1024]; + +struct http_resource_detail_websocket ws_resource_detail = { + .common = { + .type = HTTP_RESOURCE_TYPE_WEBSOCKET, + + /* We need HTTP/1.1 Get method for upgrading */ + .bitmask_of_supported_http_methods = BIT(HTTP_GET), + }, + .cb = ws_setup, + .data_buffer = ws_recv_buffer, + .data_buffer_len = sizeof(ws_recv_buffer), + .user_data = NULL, /* Fill this for any user specific data */ +}; + +HTTP_RESOURCE_DEFINE(ws_resource, test_http_service, "/", &ws_resource_detail); + +#endif /* CONFIG_NET_SAMPLE_WEBSOCKET_SERVICE */ +#endif /* CONFIG_NET_SAMPLE_HTTP_SERVICE */ + +#if defined(CONFIG_NET_SAMPLE_HTTPS_SERVICE) +#include "certificate.h" + +static const sec_tag_t sec_tag_list_verify_none[] = { + HTTP_SERVER_CERTIFICATE_TAG, +#if defined(CONFIG_MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) + PSK_TAG, +#endif + }; + +static uint16_t test_https_service_port = CONFIG_NET_SAMPLE_HTTPS_SERVER_SERVICE_PORT; +HTTPS_SERVICE_DEFINE(test_https_service, CONFIG_NET_CONFIG_MY_IPV4_ADDR, + &test_https_service_port, 1, 10, NULL, + sec_tag_list_verify_none, sizeof(sec_tag_list_verify_none)); + +static struct http_resource_detail_static index_html_gz_resource_detail_https = { + .common = { + .type = HTTP_RESOURCE_TYPE_STATIC, + .bitmask_of_supported_http_methods = BIT(HTTP_GET), + .content_encoding = "gzip", + }, + .static_data = index_html_gz, + .static_data_len = sizeof(index_html_gz), +}; + +HTTP_RESOURCE_DEFINE(index_html_gz_resource_https, test_https_service, "/", + &index_html_gz_resource_detail_https); + +#endif /* CONFIG_NET_SAMPLE_HTTPS_SERVICE */ + +static void setup_tls(void) +{ +#if defined(CONFIG_NET_SAMPLE_HTTPS_SERVICE) +#if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS) + int err; + +#if defined(CONFIG_NET_SAMPLE_CERTS_WITH_SC) + err = tls_credential_add(HTTP_SERVER_CERTIFICATE_TAG, + TLS_CREDENTIAL_CA_CERTIFICATE, + ca_certificate, + sizeof(ca_certificate)); + if (err < 0) { + LOG_ERR("Failed to register CA certificate: %d", err); + } +#endif /* defined(CONFIG_NET_SAMPLE_CERTS_WITH_SC) */ + + err = tls_credential_add(HTTP_SERVER_CERTIFICATE_TAG, + TLS_CREDENTIAL_SERVER_CERTIFICATE, + server_certificate, + sizeof(server_certificate)); + if (err < 0) { + LOG_ERR("Failed to register public certificate: %d", err); + } + + err = tls_credential_add(HTTP_SERVER_CERTIFICATE_TAG, + TLS_CREDENTIAL_PRIVATE_KEY, + private_key, sizeof(private_key)); + if (err < 0) { + LOG_ERR("Failed to register private key: %d", err); + } + +#if defined(CONFIG_MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) + err = tls_credential_add(PSK_TAG, + TLS_CREDENTIAL_PSK, + psk, + sizeof(psk)); + if (err < 0) { + LOG_ERR("Failed to register PSK: %d", err); + } + + err = tls_credential_add(PSK_TAG, + TLS_CREDENTIAL_PSK_ID, + psk_id, + sizeof(psk_id) - 1); + if (err < 0) { + LOG_ERR("Failed to register PSK ID: %d", err); + } +#endif /* defined(CONFIG_MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) */ +#endif /* defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS) */ +#endif /* defined(CONFIG_NET_SAMPLE_HTTPS_SERVICE) */ +} + +int main(void) +{ + setup_tls(); + http_server_start(); + return 0; +} diff --git a/samples/net/sockets/http_server/src/not_found_page.html b/samples/net/sockets/http_server/src/not_found_page.html new file mode 100644 index 00000000000..c4bf66f08ee --- /dev/null +++ b/samples/net/sockets/http_server/src/not_found_page.html @@ -0,0 +1,10 @@ + + + + 404 Not Found + + +

404 Not Found

+

The requested resource was not found.

+ + diff --git a/samples/net/sockets/http_server/src/server.der b/samples/net/sockets/http_server/src/server.der new file mode 100644 index 00000000000..2b664a4bdb2 Binary files /dev/null and b/samples/net/sockets/http_server/src/server.der differ diff --git a/samples/net/sockets/http_server/src/server_privkey.der b/samples/net/sockets/http_server/src/server_privkey.der new file mode 100644 index 00000000000..2269293fe79 Binary files /dev/null and b/samples/net/sockets/http_server/src/server_privkey.der differ diff --git a/samples/net/sockets/http_server/src/ws.c b/samples/net/sockets/http_server/src/ws.c new file mode 100644 index 00000000000..d62283b5bbc --- /dev/null +++ b/samples/net/sockets/http_server/src/ws.c @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2024, Nordic Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +LOG_MODULE_DECLARE(net_http_server_sample, LOG_LEVEL_DBG); + +#if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS) || defined(CONFIG_COVERAGE_GCOV) +#define STACK_SIZE 4096 +#else +#define STACK_SIZE 2048 +#endif + +#if defined(CONFIG_NET_TC_THREAD_COOPERATIVE) +#define THREAD_PRIORITY K_PRIO_COOP(CONFIG_NUM_COOP_PRIORITIES - 1) +#else +#define THREAD_PRIORITY K_PRIO_PREEMPT(8) +#endif + +#if defined(CONFIG_USERSPACE) +#include +extern struct k_mem_partition app_partition; +extern struct k_mem_domain app_domain; +#define APP_BMEM K_APP_BMEM(app_partition) +#define APP_DMEM K_APP_DMEM(app_partition) +#else +#define APP_BMEM +#define APP_DMEM +#endif + +#define MAX_CLIENT_QUEUE CONFIG_NET_SAMPLE_NUM_WEBSOCKET_HANDLERS +#define RECV_BUFFER_SIZE 1280 + +K_THREAD_STACK_ARRAY_DEFINE(ws_handler_stack, + CONFIG_NET_SAMPLE_NUM_WEBSOCKET_HANDLERS, + STACK_SIZE); +static struct k_thread ws_handler_thread[CONFIG_NET_SAMPLE_NUM_WEBSOCKET_HANDLERS]; +static APP_BMEM bool ws_handler_in_use[CONFIG_NET_SAMPLE_NUM_WEBSOCKET_HANDLERS]; + +static struct data { + int sock; + uint32_t counter; + uint32_t bytes_received; + struct pollfd fds[1]; + char recv_buffer[RECV_BUFFER_SIZE]; +} config[CONFIG_NET_SAMPLE_NUM_WEBSOCKET_HANDLERS] = { + [0 ... (CONFIG_NET_SAMPLE_NUM_WEBSOCKET_HANDLERS - 1)] = { + .sock = -1, + .fds[0].fd = -1, + } +}; + +static int get_free_slot(struct data *cfg) +{ + for (int i = 0; i < CONFIG_NET_SAMPLE_NUM_WEBSOCKET_HANDLERS; i++) { + if (cfg[i].sock < 0) { + return i; + } + } + + return -1; +} + +static ssize_t sendall(int sock, const void *buf, size_t len) +{ + while (len) { + ssize_t out_len = send(sock, buf, len, 0); + + if (out_len < 0) { + return out_len; + } + buf = (const char *)buf + out_len; + len -= out_len; + } + + return 0; +} + +static void ws_handler(void *ptr1, void *ptr2, void *ptr3) +{ + int slot = POINTER_TO_INT(ptr1); + struct data *cfg = ptr2; + bool *in_use = ptr3; + int offset = 0; + int received; + int client; + int ret; + + client = cfg->sock; + + cfg->fds[0].fd = client; + cfg->fds[0].events = POLLIN; + + /* In this example, we start to receive data from the websocket + * and send it back to the client. Note that we could either use + * the BSD socket interface if we do not care about Websocket + * specific packets, or we could use the websocket_{send/recv}_msg() + * function to send websocket specific data. + */ + while (true) { + if (poll(cfg->fds, 1, -1) < 0) { + LOG_ERR("Error in poll:%d", errno); + continue; + } + + if (cfg->fds[0].fd < 0) { + continue; + } + + if (cfg->fds[0].revents & ZSOCK_POLLHUP) { + LOG_DBG("Client #%d has disconnected", client); + break; + } + + received = recv(client, + cfg->recv_buffer + offset, + sizeof(cfg->recv_buffer) - offset, + 0); + + if (received == 0) { + /* Connection closed */ + LOG_INF("[%d] Connection closed", slot); + break; + } else if (received < 0) { + /* Socket error */ + LOG_ERR("[%d] Connection error %d", slot, errno); + break; + } + + cfg->bytes_received += received; + offset += received; + +#if !defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS) + /* To prevent fragmentation of the response, reply only if + * buffer is full or there is no more data to read + */ + if (offset == sizeof(cfg->recv_buffer) || + (recv(client, cfg->recv_buffer + offset, + sizeof(cfg->recv_buffer) - offset, + MSG_PEEK | MSG_DONTWAIT) < 0 && + (errno == EAGAIN || errno == EWOULDBLOCK))) { +#endif + ret = sendall(client, cfg->recv_buffer, offset); + if (ret < 0) { + LOG_ERR("[%d] Failed to send data, closing socket", + slot); + break; + } + + LOG_DBG("[%d] Received and replied with %d bytes", + slot, offset); + + if (++cfg->counter % 1000 == 0U) { + LOG_INF("[%d] Sent %u packets", slot, cfg->counter); + } + + offset = 0; +#if !defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS) + } +#endif + } + + *in_use = false; + + (void)websocket_unregister(client); + + cfg->sock = -1; +} + +int ws_setup(int ws_socket, void *user_data) +{ + int slot; + + slot = get_free_slot(config); + if (slot < 0) { + LOG_ERR("Cannot accept more connections"); + /* The caller will close the connection in this case */ + return -ENOENT; + } + + config[slot].sock = ws_socket; + + LOG_INF("[%d] Accepted a Websocket connection", slot); + + k_thread_create(&ws_handler_thread[slot], + ws_handler_stack[slot], + K_THREAD_STACK_SIZEOF(ws_handler_stack[slot]), + ws_handler, + INT_TO_POINTER(slot), &config[slot], &ws_handler_in_use[slot], + THREAD_PRIORITY, + IS_ENABLED(CONFIG_USERSPACE) ? K_USER | + K_INHERIT_PERMS : 0, + K_NO_WAIT); + + if (IS_ENABLED(CONFIG_THREAD_NAME)) { +#define MAX_NAME_LEN sizeof("ws[xx]") + char name[MAX_NAME_LEN]; + + snprintk(name, sizeof(name), "ws[%d]", slot); + k_thread_name_set(&ws_handler_thread[slot], name); + } + + return 0; +} diff --git a/samples/net/telnet/overlay-bt.conf b/samples/net/telnet/overlay-bt.conf deleted file mode 100644 index 3b7eaaffbea..00000000000 --- a/samples/net/telnet/overlay-bt.conf +++ /dev/null @@ -1,16 +0,0 @@ -CONFIG_BT=y -CONFIG_LOG=y -CONFIG_BT_SMP=y -CONFIG_BT_PERIPHERAL=y -CONFIG_BT_CENTRAL=y -CONFIG_BT_L2CAP_DYNAMIC_CHANNEL=y -CONFIG_BT_DEVICE_NAME="Zephyr Telnet Shell" -CONFIG_NET_L2_BT=y -CONFIG_NET_IPV4=n -CONFIG_NET_IPV6=y -CONFIG_NET_CONFIG_BT_NODE=y -CONFIG_NET_CONFIG_NEED_IPV6=y -CONFIG_NET_CONFIG_NEED_IPV4=n -CONFIG_NET_CONFIG_MY_IPV4_ADDR="" -CONFIG_NET_CONFIG_PEER_IPV4_ADDR="" -CONFIG_NET_BUF_RX_COUNT=64 diff --git a/samples/net/tftp_client/boards/native_posix.conf b/samples/net/tftp_client/boards/native_posix.conf deleted file mode 100644 index 1e9e27b074e..00000000000 --- a/samples/net/tftp_client/boards/native_posix.conf +++ /dev/null @@ -1,3 +0,0 @@ -CONFIG_DNS_RESOLVER=y -CONFIG_DNS_SERVER_IP_ADDRESSES=y -CONFIG_DNS_SERVER1="192.0.2.2" diff --git a/samples/net/tftp_client/boards/qemu_cortex_m3.conf b/samples/net/tftp_client/boards/qemu_cortex_m3.conf index dc256b47832..944da5cca68 100644 --- a/samples/net/tftp_client/boards/qemu_cortex_m3.conf +++ b/samples/net/tftp_client/boards/qemu_cortex_m3.conf @@ -2,3 +2,4 @@ CONFIG_NET_L2_ETHERNET=y CONFIG_ETH_DRIVER=y CONFIG_ETH_STELLARIS=y CONFIG_NET_QEMU_ETHERNET=y +CONFIG_TEST_RANDOM_GENERATOR=y diff --git a/samples/net/tftp_client/sample.yaml b/samples/net/tftp_client/sample.yaml index 6e53b0f1881..fd4b2f2d0c0 100644 --- a/samples/net/tftp_client/sample.yaml +++ b/samples/net/tftp_client/sample.yaml @@ -7,6 +7,7 @@ tests: depends_on: netif platform_allow: - native_sim + - qemu_cortex_m3 integration_platforms: - native_sim tags: diff --git a/samples/net/wifi/boards/esp32c3_luatos_core.conf b/samples/net/wifi/boards/esp32c3_luatos_core.conf deleted file mode 100644 index a72fdf39efa..00000000000 --- a/samples/net/wifi/boards/esp32c3_luatos_core.conf +++ /dev/null @@ -1,11 +0,0 @@ -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/esp32c3_luatos_core_esp32c3_usb.conf b/samples/net/wifi/boards/esp32c3_luatos_core_esp32c3_usb.conf deleted file mode 100644 index a72fdf39efa..00000000000 --- a/samples/net/wifi/boards/esp32c3_luatos_core_esp32c3_usb.conf +++ /dev/null @@ -1,11 +0,0 @@ -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/esp32c3_luatos_core_esp32c3_usb.overlay b/samples/net/wifi/boards/esp32c3_luatos_core_esp32c3_usb.overlay deleted file mode 100644 index ea9865cf5f8..00000000000 --- a/samples/net/wifi/boards/esp32c3_luatos_core_esp32c3_usb.overlay +++ /dev/null @@ -1,9 +0,0 @@ -/* - * Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -&wifi { - status = "okay"; -}; diff --git a/samples/net/wifi/boards/esp32s2_saola.overlay b/samples/net/wifi/boards/esp32s2_saola.overlay deleted file mode 100644 index ea9865cf5f8..00000000000 --- a/samples/net/wifi/boards/esp32s2_saola.overlay +++ /dev/null @@ -1,9 +0,0 @@ -/* - * Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -&wifi { - status = "okay"; -}; diff --git a/samples/net/wifi/boards/esp32s3_devkitm.conf b/samples/net/wifi/boards/esp32s3_devkitm.conf deleted file mode 100644 index a72fdf39efa..00000000000 --- a/samples/net/wifi/boards/esp32s3_devkitm.conf +++ /dev/null @@ -1,11 +0,0 @@ -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/esp32s3_devkitm.overlay b/samples/net/wifi/boards/esp32s3_devkitm.overlay deleted file mode 100644 index 4d69fe29493..00000000000 --- a/samples/net/wifi/boards/esp32s3_devkitm.overlay +++ /dev/null @@ -1,9 +0,0 @@ -/* - * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -&wifi { - status = "okay"; -}; diff --git a/samples/net/wifi/boards/esp32s3_luatos_core.conf b/samples/net/wifi/boards/esp32s3_luatos_core.conf deleted file mode 100644 index a72fdf39efa..00000000000 --- a/samples/net/wifi/boards/esp32s3_luatos_core.conf +++ /dev/null @@ -1,11 +0,0 @@ -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/esp32s3_luatos_core.overlay b/samples/net/wifi/boards/esp32s3_luatos_core.overlay deleted file mode 100644 index 4d69fe29493..00000000000 --- a/samples/net/wifi/boards/esp32s3_luatos_core.overlay +++ /dev/null @@ -1,9 +0,0 @@ -/* - * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -&wifi { - status = "okay"; -}; diff --git a/samples/net/wifi/boards/esp32s3_luatos_core_esp32s3_procpu_usb.conf b/samples/net/wifi/boards/esp32s3_luatos_core_esp32s3_procpu_usb.conf deleted file mode 100644 index a72fdf39efa..00000000000 --- a/samples/net/wifi/boards/esp32s3_luatos_core_esp32s3_procpu_usb.conf +++ /dev/null @@ -1,11 +0,0 @@ -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/esp32s3_luatos_core_esp32s3_procpu_usb.overlay b/samples/net/wifi/boards/esp32s3_luatos_core_esp32s3_procpu_usb.overlay deleted file mode 100644 index 4d69fe29493..00000000000 --- a/samples/net/wifi/boards/esp32s3_luatos_core_esp32s3_procpu_usb.overlay +++ /dev/null @@ -1,9 +0,0 @@ -/* - * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -&wifi { - status = "okay"; -}; diff --git a/samples/net/wifi/boards/xiao_esp32c3.conf b/samples/net/wifi/boards/xiao_esp32c3.conf deleted file mode 100644 index a72fdf39efa..00000000000 --- a/samples/net/wifi/boards/xiao_esp32c3.conf +++ /dev/null @@ -1,11 +0,0 @@ -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 deleted file mode 100644 index 4d69fe29493..00000000000 --- a/samples/net/wifi/boards/xiao_esp32c3.overlay +++ /dev/null @@ -1,9 +0,0 @@ -/* - * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -&wifi { - status = "okay"; -}; diff --git a/samples/net/wifi/boards/xiao_esp32s3.conf b/samples/net/wifi/boards/xiao_esp32s3.conf deleted file mode 100644 index a72fdf39efa..00000000000 --- a/samples/net/wifi/boards/xiao_esp32s3.conf +++ /dev/null @@ -1,11 +0,0 @@ -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_esp32s3.overlay b/samples/net/wifi/boards/xiao_esp32s3.overlay deleted file mode 100644 index 4d69fe29493..00000000000 --- a/samples/net/wifi/boards/xiao_esp32s3.overlay +++ /dev/null @@ -1,9 +0,0 @@ -/* - * 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 deleted file mode 100644 index a72fdf39efa..00000000000 --- a/samples/net/wifi/boards/yd_esp32.conf +++ /dev/null @@ -1,11 +0,0 @@ -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/yd_esp32.overlay b/samples/net/wifi/boards/yd_esp32.overlay deleted file mode 100644 index ea9865cf5f8..00000000000 --- a/samples/net/wifi/boards/yd_esp32.overlay +++ /dev/null @@ -1,9 +0,0 @@ -/* - * Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -&wifi { - status = "okay"; -}; diff --git a/samples/net/wifi/boards/esp32_devkitc_wroom_procpu.conf b/samples/net/wifi/socs/esp32_procpu.conf similarity index 100% rename from samples/net/wifi/boards/esp32_devkitc_wroom_procpu.conf rename to samples/net/wifi/socs/esp32_procpu.conf diff --git a/samples/net/wifi/boards/esp32_devkitc_wroom_procpu.overlay b/samples/net/wifi/socs/esp32_procpu.overlay similarity index 100% rename from samples/net/wifi/boards/esp32_devkitc_wroom_procpu.overlay rename to samples/net/wifi/socs/esp32_procpu.overlay diff --git a/samples/net/wifi/boards/esp32_devkitc_wrover_procpu.conf b/samples/net/wifi/socs/esp32c3.conf similarity index 100% rename from samples/net/wifi/boards/esp32_devkitc_wrover_procpu.conf rename to samples/net/wifi/socs/esp32c3.conf diff --git a/samples/net/wifi/boards/esp32_devkitc_wrover_procpu.overlay b/samples/net/wifi/socs/esp32c3.overlay similarity index 100% rename from samples/net/wifi/boards/esp32_devkitc_wrover_procpu.overlay rename to samples/net/wifi/socs/esp32c3.overlay diff --git a/samples/net/wifi/boards/esp32s2_saola.conf b/samples/net/wifi/socs/esp32s2.conf similarity index 100% rename from samples/net/wifi/boards/esp32s2_saola.conf rename to samples/net/wifi/socs/esp32s2.conf diff --git a/samples/net/wifi/boards/esp32c3_devkitm.overlay b/samples/net/wifi/socs/esp32s2.overlay similarity index 100% rename from samples/net/wifi/boards/esp32c3_devkitm.overlay rename to samples/net/wifi/socs/esp32s2.overlay diff --git a/samples/net/wifi/boards/esp32c3_devkitm.conf b/samples/net/wifi/socs/esp32s3_procpu.conf similarity index 100% rename from samples/net/wifi/boards/esp32c3_devkitm.conf rename to samples/net/wifi/socs/esp32s3_procpu.conf diff --git a/samples/net/wifi/boards/esp32c3_luatos_core.overlay b/samples/net/wifi/socs/esp32s3_procpu.overlay similarity index 100% rename from samples/net/wifi/boards/esp32c3_luatos_core.overlay rename to samples/net/wifi/socs/esp32s3_procpu.overlay diff --git a/samples/net/zperf/boards/mimxrt1050_evk.conf b/samples/net/zperf/boards/mimxrt1050_evk.conf index 287d55db122..10352a7d9d7 100644 --- a/samples/net/zperf/boards/mimxrt1050_evk.conf +++ b/samples/net/zperf/boards/mimxrt1050_evk.conf @@ -1,4 +1,4 @@ # Note: HW accleration does not support IPV6 -CONFIG_ETH_MCUX_HW_ACCELERATION=y +CONFIG_ETH_NXP_ENET_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.conf b/samples/net/zperf/boards/mimxrt1060_evk.conf index 287d55db122..10352a7d9d7 100644 --- a/samples/net/zperf/boards/mimxrt1060_evk.conf +++ b/samples/net/zperf/boards/mimxrt1060_evk.conf @@ -1,4 +1,4 @@ # Note: HW accleration does not support IPV6 -CONFIG_ETH_MCUX_HW_ACCELERATION=y +CONFIG_ETH_NXP_ENET_HW_ACCELERATION=y CONFIG_NET_SAMPLE_CODE_RELOCATE=y CONFIG_NET_SAMPLE_CODE_RAM_NAME="ITCM" diff --git a/samples/net/zperf/boards/mimxrt1064_evk.conf b/samples/net/zperf/boards/mimxrt1064_evk.conf index 287d55db122..10352a7d9d7 100644 --- a/samples/net/zperf/boards/mimxrt1064_evk.conf +++ b/samples/net/zperf/boards/mimxrt1064_evk.conf @@ -1,4 +1,4 @@ # Note: HW accleration does not support IPV6 -CONFIG_ETH_MCUX_HW_ACCELERATION=y +CONFIG_ETH_NXP_ENET_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_mimxrt1176_cm7_A.conf b/samples/net/zperf/boards/mimxrt1170_evk_mimxrt1176_cm7_A.conf index 287d55db122..10352a7d9d7 100644 --- a/samples/net/zperf/boards/mimxrt1170_evk_mimxrt1176_cm7_A.conf +++ b/samples/net/zperf/boards/mimxrt1170_evk_mimxrt1176_cm7_A.conf @@ -1,4 +1,4 @@ # Note: HW accleration does not support IPV6 -CONFIG_ETH_MCUX_HW_ACCELERATION=y +CONFIG_ETH_NXP_ENET_HW_ACCELERATION=y CONFIG_NET_SAMPLE_CODE_RELOCATE=y CONFIG_NET_SAMPLE_CODE_RAM_NAME="ITCM" diff --git a/samples/net/zperf/overlay-802154-subg.conf b/samples/net/zperf/overlay-802154-subg.conf new file mode 100644 index 00000000000..cfa509d8cf4 --- /dev/null +++ b/samples/net/zperf/overlay-802154-subg.conf @@ -0,0 +1,18 @@ +CONFIG_BT=n + +# Disable IPv4 +CONFIG_NET_IPV4=n + +CONFIG_NET_CONFIG_NEED_IPV6=y +CONFIG_NET_CONFIG_NEED_IPV4=n +CONFIG_NET_CONFIG_MY_IPV4_ADDR="" +CONFIG_NET_CONFIG_PEER_IPV4_ADDR="" + +CONFIG_NET_L2_IEEE802154=y +CONFIG_NET_L2_IEEE802154_SHELL=y +CONFIG_NET_L2_IEEE802154_LOG_LEVEL_INF=y + +# Uncomment for 868 MHz +#CONFIG_NET_CONFIG_IEEE802154_CHANNEL=0 +# Uncomment for 906 MHz: +CONFIG_NET_CONFIG_IEEE802154_CHANNEL=1 diff --git a/samples/net/zperf/overlay-bt.conf b/samples/net/zperf/overlay-bt.conf deleted file mode 100644 index 43378326544..00000000000 --- a/samples/net/zperf/overlay-bt.conf +++ /dev/null @@ -1,9 +0,0 @@ -CONFIG_BT=y -CONFIG_LOG=y -CONFIG_BT_SMP=y -CONFIG_BT_PERIPHERAL=y -CONFIG_BT_CENTRAL=y -CONFIG_BT_L2CAP_DYNAMIC_CHANNEL=y -CONFIG_NET_L2_BT=y -CONFIG_NET_L2_BT_SHELL=y -CONFIG_SHELL_CMDS_RESIZE=n diff --git a/samples/net/zperf/sample.yaml b/samples/net/zperf/sample.yaml index 9a2f30016e3..12c0cfd1bf2 100644 --- a/samples/net/zperf/sample.yaml +++ b/samples/net/zperf/sample.yaml @@ -98,16 +98,3 @@ 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/mimxrt1176/cm7 - - mimxrt1160_evk/mimxrt1166/cm7 diff --git a/samples/posix/env/sample.yaml b/samples/posix/env/sample.yaml index c276b6b55f1..39ad4f08809 100644 --- a/samples/posix/env/sample.yaml +++ b/samples/posix/env/sample.yaml @@ -7,7 +7,7 @@ common: - native_posix - native_posix/native/64 integration_platforms: - - qemu_riscv32 + - native_sim harness: console harness_config: type: multi_line diff --git a/samples/posix/gettimeofday/sample.yaml b/samples/posix/gettimeofday/sample.yaml index a71d29f09c5..88748aab2a6 100644 --- a/samples/posix/gettimeofday/sample.yaml +++ b/samples/posix/gettimeofday/sample.yaml @@ -10,6 +10,9 @@ common: tags: - posix - net + platform_exclude: + - native_posix + - native_posix/native/64 tests: sample.posix.gettimeofday: harness: net diff --git a/samples/sensor/die_temp_polling/boards/esp32s3_devkitm.overlay b/samples/sensor/die_temp_polling/boards/esp32s3_devkitm_procpu.overlay similarity index 100% rename from samples/sensor/die_temp_polling/boards/esp32s3_devkitm.overlay rename to samples/sensor/die_temp_polling/boards/esp32s3_devkitm_procpu.overlay diff --git a/samples/sensor/grow_r502a/README.rst b/samples/sensor/grow_r502a/README.rst index 032be38bfff..06de5aabec5 100644 --- a/samples/sensor/grow_r502a/README.rst +++ b/samples/sensor/grow_r502a/README.rst @@ -8,18 +8,15 @@ Overview This sample has the below functionalities: +#. Sensor LED is controlled using led APIs from zephyr subsystem. #. Shows the number of fingerprints stored in the sensor. +#. Shows the sensor device's configurations like baud rate, library size, address and data packet size in UART frame. #. When SENSOR_ATTR_RECORD_FREE_IDX is set then it search for free index in sensor library. #. When SENSOR_ATTR_RECORD_ADD is set then it adds a new fingerprint to the sensor. #. When SENSOR_ATTR_RECORD_FIND is set then it tries to find a match for the input fingerprint. On finding a match it returns ID and confidence. #. When SENSOR_ATTR_RECORD_DEL is set then it deletes a fingerprint from the sensor. -Note: Fingerprint add & delete functionalities work only when SENSOR_TRIG_TOUCH is set. -Tricolored LED in the sensor hardware will, flash on the below conditions: - -#. On successful addition or deletion of fingerprint it will flash in blue three times. -#. On finding a match for the input fingerprint it will flash in purple. -#. In all other cases it will flash in red. +Note: Fingerprint add functionality work only when SENSOR_TRIG_TOUCH is set. Wiring ******* @@ -42,7 +39,7 @@ build this sample app using: .. zephyr-app-commands:: :zephyr-app: samples/sensor/grow_r502a - :board: nrf52840dk/nrf52840 + :board: esp32_devkitc_wroom/esp32/procpu :goals: build flash Sample Output @@ -50,20 +47,18 @@ Sample Output .. code-block:: console - *** Booting Zephyr OS build zephyr-v3.1.0-2640-g328bb73113d4 *** - template count : 0 + *** Booting Zephyr OS build v3.6.0-3147-g8ae1a2e2718e *** + template count : 4 + baud 57600 + addr 0xffffffff + lib_size 200 + data_pkt_size 128 Fingerprint Deleted at ID #3 - Fingerprint template free idx at ID #0 - Waiting for valid finger to enroll as ID #0 + Fingerprint template free idx at ID #3 + Waiting for valid finger to enroll as ID #3 Place your finger - Fingerprint successfully stored at #0 - template count : 1 - Matched ID : 0 - confidence : 170 - template count : 1 - Matched ID : 0 - confidence : 136 - template count : 1 - Matched ID : 0 - confidence : 318 + Fingerprint successfully stored at #3 + template count : 4 + Matched ID : 2 + confidence : 110 diff --git a/samples/sensor/grow_r502a/boards/esp32_devkitc_wroom_procpu.overlay b/samples/sensor/grow_r502a/boards/esp32_devkitc_wroom_procpu.overlay index 2fa0bb3197f..7add14e5350 100644 --- a/samples/sensor/grow_r502a/boards/esp32_devkitc_wroom_procpu.overlay +++ b/samples/sensor/grow_r502a/boards/esp32_devkitc_wroom_procpu.overlay @@ -25,4 +25,9 @@ int-gpios = <&gpio1 3 GPIO_ACTIVE_LOW>; }; }; + + led { + compatible = "hzgrow,r502a-led"; + status = "okay"; + }; }; diff --git a/samples/sensor/grow_r502a/boards/yd_esp32.overlay b/samples/sensor/grow_r502a/boards/yd_esp32_procpu.overlay similarity index 100% rename from samples/sensor/grow_r502a/boards/yd_esp32.overlay rename to samples/sensor/grow_r502a/boards/yd_esp32_procpu.overlay diff --git a/samples/sensor/grow_r502a/prj.conf b/samples/sensor/grow_r502a/prj.conf index 0f507ebe69d..5727d4c0ceb 100644 --- a/samples/sensor/grow_r502a/prj.conf +++ b/samples/sensor/grow_r502a/prj.conf @@ -2,4 +2,8 @@ CONFIG_SERIAL=y CONFIG_UART_INTERRUPT_DRIVEN=y CONFIG_SENSOR=y +CONFIG_LED=y CONFIG_GROW_R502A_TRIGGER_OWN_THREAD=y + +# Minimum stack size needed +CONFIG_GROW_R502A_THREAD_STACK_SIZE=1536 diff --git a/samples/sensor/grow_r502a/src/main.c b/samples/sensor/grow_r502a/src/main.c index 583d1ed3f6f..da8923e1fc2 100644 --- a/samples/sensor/grow_r502a/src/main.c +++ b/samples/sensor/grow_r502a/src/main.c @@ -9,34 +9,57 @@ #include #include #include +#include static bool enroll; -static struct sensor_value fid, val; +static struct sensor_value fid_get, count, find, del, param; -static void finger_match(const struct device *dev) +static void finger_find(const struct device *dev) { - struct sensor_value input; int ret; + ret = sensor_attr_set(dev, SENSOR_CHAN_FINGERPRINT, + SENSOR_ATTR_R502A_CAPTURE, NULL); + if (ret != 0) { + printk("Capture fingerprint failed %d\n", ret); + return; + } + ret = sensor_attr_get(dev, SENSOR_CHAN_FINGERPRINT, - SENSOR_ATTR_R502A_RECORD_FIND, &input); + SENSOR_ATTR_R502A_RECORD_FIND, &find); if (ret != 0) { - printk("Sensor attr get failed %d\n", ret); + printk("Find fingerprint failed %d\n", ret); return; } - printk("Matched ID : %d\n", input.val1); - printk("confidence : %d\n", input.val2); + printk("Matched ID : %d\n", find.val1); + printk("confidence : %d\n", find.val2); } static void finger_enroll(const struct device *dev) { int ret; - ret = sensor_attr_set(dev, SENSOR_CHAN_FINGERPRINT, SENSOR_ATTR_R502A_RECORD_ADD, &fid); + ret = sensor_attr_set(dev, SENSOR_CHAN_FINGERPRINT, + SENSOR_ATTR_R502A_CAPTURE, NULL); + if (ret != 0) { + printk("Capture fingerprint failed %d\n", ret); + return; + } - if (ret == 0) { - printk("Fingerprint successfully stored at #%d\n", fid.val1); + ret = sensor_attr_set(dev, SENSOR_CHAN_FINGERPRINT, + SENSOR_ATTR_R502A_TEMPLATE_CREATE, NULL); + if (ret != 0) { + printk("Create template failed %d\n", ret); + return; + } + + ret = sensor_attr_set(dev, SENSOR_CHAN_FINGERPRINT, + SENSOR_ATTR_R502A_RECORD_ADD, &fid_get); + if (!ret) { + printk("Fingerprint successfully stored at #%d\n", fid_get.val1); enroll = false; + } else { + printk("Fingerprint store failed %d\n", ret); } } @@ -49,12 +72,44 @@ static void template_count_get(const struct device *dev) printk("Sample Fetch Error %d\n", ret); return; } - ret = sensor_channel_get(dev, SENSOR_CHAN_FINGERPRINT, &val); + ret = sensor_channel_get(dev, SENSOR_CHAN_FINGERPRINT, &count); if (ret < 0) { printk("Channel Get Error %d\n", ret); return; } - printk("template count : %d\n", val.val1); + printk("template count : %d\n", count.val1); +} + +static int r502a_led(void) +{ + int ret; + const int led_num = 0; + const int led_color_a_inst = 1; + uint8_t led_color = R502A_LED_COLOR_PURPLE; + const struct device *led_dev = DEVICE_DT_GET_ONE(hzgrow_r502a_led); + + if (led_dev == NULL) { + printk("Error: no device found\n"); + return -ENODEV; + } + + if (!device_is_ready(led_dev)) { + printk("Error: Device %s is not ready\n", led_dev->name); + return -EAGAIN; + } + + ret = led_set_color(led_dev, led_num, led_color_a_inst, &led_color); + if (ret != 0) { + printk("led set color failed %d\n", ret); + return -1; + } + + ret = led_on(led_dev, led_num); + if (ret != 0) { + printk("led on failed %d\n", ret); + return -1; + } + return 0; } static void trigger_handler(const struct device *dev, @@ -64,13 +119,29 @@ static void trigger_handler(const struct device *dev, finger_enroll(dev); } else { template_count_get(dev); - finger_match(dev); + finger_find(dev); } } +static void read_fps_param(const struct device *dev) +{ + int ret = 0; + struct r502a_sys_param res; + + ret = r502a_read_sys_param(dev, &res); + if (ret != 0) { + printk("r502a read system parameter failed %d\n", ret); + return; + } + + printk("baud %d\n", res.baud); + printk("addr 0x%x\n", res.addr); + printk("lib_size %d\n", res.lib_size); + printk("data_pkt_size %d\n", res.data_pkt_size); +} + int main(void) { - static struct sensor_value del, fid_get; int ret; const struct device *dev = DEVICE_DT_GET_ONE(hzgrow_r502a); @@ -85,8 +156,16 @@ int main(void) return 0; } + ret = r502a_led(); + if (ret != 0) { + printk("Error: device led failed to set %d", ret); + return 0; + } + template_count_get(dev); + read_fps_param(dev); + del.val1 = 3; ret = sensor_attr_set(dev, SENSOR_CHAN_FINGERPRINT, SENSOR_ATTR_R502A_RECORD_DEL, &del); if (ret != 0) { @@ -103,9 +182,8 @@ int main(void) } printk("Fingerprint template free idx at ID #%d\n", fid_get.val1); - fid.val1 = fid_get.val1; printk("Waiting for valid finger to enroll as ID #%d\n" - "Place your finger\n", fid.val1); + "Place your finger\n", fid_get.val1); enroll = true; if (IS_ENABLED(CONFIG_GROW_R502A_TRIGGER)) { diff --git a/samples/sensor/mcux_acmp/boards/mimxrt1170_evk_cm4.overlay b/samples/sensor/mcux_acmp/boards/mimxrt1170_evk_cm4.overlay deleted file mode 100644 index b7aa1131ec7..00000000000 --- a/samples/sensor/mcux_acmp/boards/mimxrt1170_evk_cm4.overlay +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2022 NXP - * - * SPDX-License-Identifier: Apache-2.0 - */ - -&pinctrl { - acmp1_default: acmp1_default { - group0 { - pinmux = <&iomuxc_gpio_ad_01_acmp1_in2>; - drive-strength = "high"; - bias-pull-up; - slew-rate = "fast"; - }; - }; -}; - -&acmp1 { - status = "okay"; - pinctrl-0 = <&acmp1_default>; - pinctrl-names = "default"; -}; diff --git a/samples/sensor/qdec/boards/esp32s3_devkitm.overlay b/samples/sensor/qdec/boards/esp32s3_devkitm_procpu.overlay similarity index 100% rename from samples/sensor/qdec/boards/esp32s3_devkitm.overlay rename to samples/sensor/qdec/boards/esp32s3_devkitm_procpu.overlay diff --git a/samples/sensor/qdec/boards/esp32s3_luatos_core.overlay b/samples/sensor/qdec/boards/esp32s3_luatos_core_procpu.overlay similarity index 100% rename from samples/sensor/qdec/boards/esp32s3_luatos_core.overlay rename to samples/sensor/qdec/boards/esp32s3_luatos_core_procpu.overlay diff --git a/samples/sensor/qdec/boards/esp32s3_luatos_core_esp32s3_procpu_usb.overlay b/samples/sensor/qdec/boards/esp32s3_luatos_core_procpu_usb.overlay similarity index 100% rename from samples/sensor/qdec/boards/esp32s3_luatos_core_esp32s3_procpu_usb.overlay rename to samples/sensor/qdec/boards/esp32s3_luatos_core_procpu_usb.overlay diff --git a/samples/sensor/sensor_shell/CMakeLists.txt b/samples/sensor/sensor_shell/CMakeLists.txt index 1f13027d26b..597957beb61 100644 --- a/samples/sensor/sensor_shell/CMakeLists.txt +++ b/samples/sensor/sensor_shell/CMakeLists.txt @@ -7,4 +7,8 @@ project(sensor_shell) target_sources(app PRIVATE src/main.c) +target_sources_ifdef(CONFIG_SAMPLES_SENSOR_SHELL_FAKE_SENSOR app PRIVATE + src/fake_sensor.c +) + target_include_directories(app PRIVATE include) diff --git a/samples/sensor/sensor_shell/Kconfig b/samples/sensor/sensor_shell/Kconfig index 354385ee6ca..38fcdfa7eb6 100644 --- a/samples/sensor/sensor_shell/Kconfig +++ b/samples/sensor/sensor_shell/Kconfig @@ -1,4 +1,10 @@ # Copyright (c) 2023 Google LLC # SPDX-License-Identifier: Apache-2.0 +config SAMPLES_SENSOR_SHELL_FAKE_SENSOR + bool "Enable fake sensor" + help + On boards that do not have a sensor, enabling this will build a fake + sensor that can be interacted with via the sensor shell. + source "Kconfig.zephyr" diff --git a/samples/sensor/sensor_shell/README.rst b/samples/sensor/sensor_shell/README.rst index db9e3e2061f..d3146e5201d 100644 --- a/samples/sensor/sensor_shell/README.rst +++ b/samples/sensor/sensor_shell/README.rst @@ -18,6 +18,14 @@ enabled, for example: :board: reel_board :goals: build flash +For boards that do not have a sensor, a simple fake sensor driver is provided, for example: + +.. zephyr-app-commands:: + :zephyr-app: samples/sensor/sensor_shell + :board: qemu_riscv64 + :goals: run + :gen-args: -DCONFIG_SAMPLES_SENSOR_SHELL_FAKE_SENSOR=y + Shell Module Command Help ========================= diff --git a/samples/sensor/sensor_shell/app.overlay b/samples/sensor/sensor_shell/app.overlay new file mode 100644 index 00000000000..79d50cb6b2b --- /dev/null +++ b/samples/sensor/sensor_shell/app.overlay @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2024 Meta Platforms + * + * SPDX-License-Identifier: Apache-2.0 + */ + + / { + app { + #address-cells = <1>; + #size-cells = <0>; + + vsensor0: sensor@0 { + compatible = "vnd,fake-sensor"; + reg = <0>; + friendly-name = "Fake sensor 0"; + status = "okay"; + }; + + vsensor1: sensor@1 { + compatible = "vnd,fake-sensor"; + reg = <1>; + friendly-name = "Fake sensor 1"; + status = "okay"; + }; + }; +}; diff --git a/samples/sensor/sensor_shell/dts/bindings/vnd,sensor.yaml b/samples/sensor/sensor_shell/dts/bindings/vnd,sensor.yaml new file mode 100644 index 00000000000..50c32f17dba --- /dev/null +++ b/samples/sensor/sensor_shell/dts/bindings/vnd,sensor.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2024 Meta Platforms +# SPDX-License-Identifier: Apache-2.0 + +description: Fake sensor + +include: sensor-device.yaml + +compatible: "vnd,fake-sensor" diff --git a/samples/sensor/sensor_shell/pytest/test_sensor_shell.py b/samples/sensor/sensor_shell/pytest/test_sensor_shell.py new file mode 100644 index 00000000000..c13f888a285 --- /dev/null +++ b/samples/sensor/sensor_shell/pytest/test_sensor_shell.py @@ -0,0 +1,70 @@ +# Copyright (c) 2024 Meta Platforms +# SPDX-License-Identifier: Apache-2.0 + +import logging + +from twister_harness import Shell + +logger = logging.getLogger(__name__) + + +def test_sensor_shell_info(shell: Shell): + logger.info('send "sensor info" command') + + lines = shell.exec_command('sensor info') + assert any(['device name: sensor@0' in line for line in lines]), 'expected response not found' + assert any(['device name: sensor@1' in line for line in lines]), 'expected response not found' + + logger.info('response is valid') + + +def test_sensor_shell_get(shell: Shell): + logger.info('send "sensor get" command') + + lines = shell.exec_command('sensor get sensor@0 voltage') + assert any(['channel type=31(voltage)' in line for line in lines]), 'expected response not found' + + lines = shell.exec_command('sensor get sensor@1 53') + assert any(['channel type=53(gauge_time_to_empty)' in line for line in lines]), 'expected response not found' + + logger.info('response is valid') + + +def test_sensor_shell_attr_get(shell: Shell): + logger.info('send "sensor attr_get" command') + + lines = shell.exec_command('sensor attr_get sensor@0 co2 sampling_frequency') + assert any(['sensor@0(channel=co2, attr=sampling_frequency)' in line for line in lines]), 'expected response not found' + + lines = shell.exec_command('sensor attr_get sensor@1 53 3') + assert any(['sensor@1(channel=gauge_time_to_empty, attr=slope_th)' in line for line in lines]), 'expected response not found' + + logger.info('response is valid') + + +def test_sensor_shell_attr_set(shell: Shell): + logger.info('send "sensor attr_set" command') + + lines = shell.exec_command('sensor attr_set sensor@0 co2 sampling_frequency 1') + expected_line = 'sensor@0 channel=co2, attr=sampling_frequency set to value=1' + assert any([expected_line in line for line in lines]), 'expected response not found' + + lines = shell.exec_command('sensor attr_set sensor@1 53 3 1') + expected_line = 'sensor@1 channel=gauge_time_to_empty, attr=slope_th set to value=1' + assert any([expected_line in line for line in lines]), 'expected response not found' + + logger.info('response is valid') + + +def test_sensor_shell_trig(shell: Shell): + logger.info('send "sensor trig" command') + + lines = shell.exec_command('sensor trig sensor@0 on data_ready') + expected_line = 'Enabled trigger idx=1 data_ready on device sensor@0' + assert any([expected_line in line for line in lines]), 'expected response not found' + + lines = shell.exec_command('sensor trig sensor@0 off data_ready') + expected_line = 'Disabled trigger idx=1 data_ready on device sensor@0' + assert any([expected_line in line for line in lines]), 'expected response not found' + + logger.info('response is valid') diff --git a/samples/sensor/sensor_shell/sample.yaml b/samples/sensor/sensor_shell/sample.yaml index d89dfebc21a..51f57b10f6c 100644 --- a/samples/sensor/sensor_shell/sample.yaml +++ b/samples/sensor/sensor_shell/sample.yaml @@ -1,5 +1,10 @@ sample: name: Shell Sensor Module Sample +common: + tags: + - sensor + - shell + tests: sample.sensor.shell: integration_platforms: @@ -7,7 +12,15 @@ tests: # TODO Remove once #63414 is resolved platform_exclude: gd32l233r_eval filter: ( CONFIG_UART_CONSOLE and CONFIG_SERIAL_SUPPORT_INTERRUPT ) - tags: shell harness: keyboard min_ram: 20 min_flash: 33 + sample.sensor.shell.pytest: + filter: CONFIG_SERIAL and dt_chosen_enabled("zephyr,shell-uart") + min_ram: 40 + harness: pytest + extra_configs: + - arch:posix:CONFIG_NATIVE_UART_0_ON_STDINOUT=y + - CONFIG_SAMPLES_SENSOR_SHELL_FAKE_SENSOR=y + integration_platforms: + - native_sim diff --git a/samples/sensor/sensor_shell/src/fake_sensor.c b/samples/sensor/sensor_shell/src/fake_sensor.c new file mode 100644 index 00000000000..212ef5e0565 --- /dev/null +++ b/samples/sensor/sensor_shell/src/fake_sensor.c @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2024 Meta Platforms + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT vnd_fake_sensor + +#include +#include +#include + +LOG_MODULE_REGISTER(fake_sensor); + +static int init(const struct device *dev) +{ + ARG_UNUSED(dev); + + return 0; +} + +static int attr_set(const struct device *dev, enum sensor_channel chan, enum sensor_attribute attr, + const struct sensor_value *val) +{ + LOG_DBG("[%s] dev: %p, chan: %d, attr: %d, val1: %d, val2: %d", __func__, dev, chan, attr, + val->val1, val->val2); + + return 0; +} + +static int attr_get(const struct device *dev, enum sensor_channel chan, enum sensor_attribute attr, + struct sensor_value *val) +{ + LOG_DBG("[%s] dev: %p, chan: %d, attr: %d", __func__, dev, chan, attr); + + val->val1 = chan; + val->val2 = attr * 100000; + + return 0; +} + +static int sample_fetch(const struct device *dev, enum sensor_channel chan) +{ + LOG_DBG("[%s] dev: %p, chan: %d", __func__, dev, chan); + + return 0; +} + +static int channel_get(const struct device *dev, enum sensor_channel chan, struct sensor_value *val) +{ + LOG_DBG("[%s] dev: %p, chan: %d", __func__, dev, chan); + + switch (chan) { + case SENSOR_CHAN_ACCEL_XYZ: + __fallthrough; + case SENSOR_CHAN_GYRO_XYZ: + __fallthrough; + case SENSOR_CHAN_MAGN_XYZ: + for (int i = 0; i < 3; i++, val++) { + val->val1 = chan; + val->val2 = 1; + } + break; + default: + val->val1 = chan; + val->val2 = 1; + break; + } + + return 0; +} + +static int trigger_set(const struct device *dev, const struct sensor_trigger *trig, + sensor_trigger_handler_t handler) +{ + LOG_DBG("[%s - %s] dev: %p, trig->chan: %d, trig->type: %d, handler: %p", __func__, + (handler == NULL) ? "off" : "on", dev, trig->chan, trig->type, handler); + + return 0; +} + +static const struct sensor_driver_api api = { + .attr_get = attr_get, + .attr_set = attr_set, + .sample_fetch = sample_fetch, + .channel_get = channel_get, + .trigger_set = trigger_set, +}; + +#define VND_SENSOR_INIT(n) \ + SENSOR_DEVICE_DT_INST_DEFINE(n, init, NULL, NULL, NULL, POST_KERNEL, \ + CONFIG_SENSOR_INIT_PRIORITY, &api); + +DT_INST_FOREACH_STATUS_OKAY(VND_SENSOR_INIT) diff --git a/samples/sensor/veaa_x_3/CMakeLists.txt b/samples/sensor/veaa_x_3/CMakeLists.txt new file mode 100644 index 00000000000..e43b188ab7d --- /dev/null +++ b/samples/sensor/veaa_x_3/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(app) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/sensor/veaa_x_3/Kconfig b/samples/sensor/veaa_x_3/Kconfig new file mode 100644 index 00000000000..7eca02930fd --- /dev/null +++ b/samples/sensor/veaa_x_3/Kconfig @@ -0,0 +1,23 @@ +# +# Copyright (c) 2024 Vitrolife A/S +# +# SPDX-License-Identifier: Apache-2.0 +# + +mainmenu "VEAA sample application" + +config SAMPLE_USE_SHELL + bool "Use sensor shell and disable loop" + default n + select SHELL + select SENSOR_SHELL + +config SAMPLE_LOOP_INTERVAL + int "Sample loop delay in milliseconds" + default 200 + +config SAMPLE_LOOP_INCREMENT + int "Sample kPa increment per loop" + default 1 + +source "Kconfig.zephyr" diff --git a/samples/sensor/veaa_x_3/README.rst b/samples/sensor/veaa_x_3/README.rst new file mode 100644 index 00000000000..09d85eacacf --- /dev/null +++ b/samples/sensor/veaa_x_3/README.rst @@ -0,0 +1,38 @@ +.. veaa_x_3: + +VEAA-X-3 sample +########################## + +Overview +******** + +A sensor sample that demonstrates how to use a VEAA-X-3 device. + +Building and Running +******************** + +This sample sets the valve setpoint then reads the actual pressure. +This is done continuously. When the maximum supported pressure is reached the setpoint is reset to +the valve's minimum supported pressure value. + +.. zephyr-app-commands:: + :zephyr-app: samples/sensor/veaa_x_3 + :board: + :goals: build flash + :compact: + +Sample Output +============= + +.. code-block:: console + + Testing test_veaa_x_3 + Valve range: 1 to 200 kPa + Setpoint: 1 kPa, actual: 1 kPa + Setpoint: 2 kPa, actual: 2 kPa + Setpoint: 3 kPa, actual: 3 kPa + ... + Setpoint: 199 kPa, actual: 199 kPa + Setpoint: 200 kPa, actual: 200 kPa + Setpoint: 1 kPa, actual: 1 kPa + diff --git a/samples/sensor/veaa_x_3/boards/nucleo_h563zi.overlay b/samples/sensor/veaa_x_3/boards/nucleo_h563zi.overlay new file mode 100644 index 00000000000..10b9676ac80 --- /dev/null +++ b/samples/sensor/veaa_x_3/boards/nucleo_h563zi.overlay @@ -0,0 +1,35 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2024, Vitrolife A/S + */ + +/* spi1 sck conflicts with dac1 channel 3 */ +/delete-node/ &spi1; + +/ { + test_veaa_x_3: test_veaa_x_3 { + status = "okay"; + compatible = "festo,veaa-x-3"; + io-channels = <&adc1 3>; + dac = <&dac1>; + dac-channel-id = <2>; + dac-resolution = <12>; + pressure-range-type = "D2"; + }; + +}; + +&adc1 { + #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/sensor/veaa_x_3/prj.conf b/samples/sensor/veaa_x_3/prj.conf new file mode 100644 index 00000000000..e0bc48f5dfe --- /dev/null +++ b/samples/sensor/veaa_x_3/prj.conf @@ -0,0 +1,4 @@ +CONFIG_ADC=y +CONFIG_DAC=y +CONFIG_SENSOR=y +CONFIG_LOG=y diff --git a/samples/sensor/veaa_x_3/sample.yaml b/samples/sensor/veaa_x_3/sample.yaml new file mode 100644 index 00000000000..2039dd9e7ed --- /dev/null +++ b/samples/sensor/veaa_x_3/sample.yaml @@ -0,0 +1,8 @@ +sample: + name: VEAA-X-3 sensor sample +tests: + sample.sensor.veaa_x_3: + harness: sensor + tags: sensors + filter: dt_compat_enabled("festo,veaa-x-3") + depends_on: adc dac diff --git a/samples/sensor/veaa_x_3/src/main.c b/samples/sensor/veaa_x_3/src/main.c new file mode 100644 index 00000000000..db00cda8715 --- /dev/null +++ b/samples/sensor/veaa_x_3/src/main.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2024 Vitrolife A/S + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +static const struct device *const dev = DEVICE_DT_GET_ONE(festo_veaa_x_3); + +int main(void) +{ + int rc; + struct sensor_value range, setpoint, pressure; + + printk("Testing %s\n", dev->name); + + if (!device_is_ready(dev)) { + printk("%s not ready\n", dev->name); + return -ENODEV; + } + + rc = sensor_attr_get(dev, SENSOR_CHAN_PRESS, + (enum sensor_attribute)SENSOR_ATTR_VEAA_X_3_RANGE, &range); + if (rc != 0) { + printk("get range failed: %d\n", rc); + return rc; + } + printk("Valve range: %u to %u kPa\n", range.val1, range.val2); + + if (IS_ENABLED(CONFIG_SAMPLE_USE_SHELL)) { + printk("Loop is disabled. Use the `sensor` command to test %s", dev->name); + return 0; + } + + setpoint.val1 = range.val1; + while (1) { + rc = sensor_attr_set(dev, SENSOR_CHAN_PRESS, + (enum sensor_attribute)SENSOR_ATTR_VEAA_X_3_SETPOINT, + &setpoint); + if (rc != 0) { + printk("Set setpoint to %u failed: %d\n", setpoint.val1, rc); + } + + /* Sleep before get to allow DAC and ADC to stabilize */ + k_msleep(CONFIG_SAMPLE_LOOP_INTERVAL); + + rc = sensor_sample_fetch(dev); + if (rc != 0) { + printk("Fetch sample failed: %d", rc); + } + + rc = sensor_channel_get(dev, SENSOR_CHAN_PRESS, &pressure); + if (rc != 0) { + printk("Get sample failed: %d", rc); + } + + printk("Setpoint: %4u kPa, actual: %4u kPa\n", setpoint.val1, pressure.val1); + + setpoint.val1 += CONFIG_SAMPLE_LOOP_INCREMENT; + if (setpoint.val1 > range.val2) { + setpoint.val1 = range.val1; + } + } + + return 0; +} diff --git a/samples/subsys/debug/fuzz/Kconfig b/samples/subsys/debug/fuzz/Kconfig new file mode 100644 index 00000000000..f4917b7e59b --- /dev/null +++ b/samples/subsys/debug/fuzz/Kconfig @@ -0,0 +1,22 @@ +# Copyright (c) 2017 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +config ARCH_POSIX_FUZZ_IRQ + int "OS interrupt via which to deliver fuzz cases" + default 31 + help + In this sample, new fuzz cases are delivered to Zephyr + via interrupts. The IRQ should be otherwise unused, but can + be any value desired by the app. + +config ARCH_POSIX_FUZZ_TICKS + int "Ticks to allow for fuzz case processing" + default 2 + help + Fuzz interrupts are delivered, from the perspective of the + OS, at a steady cadence in simulated time. In general most + apps won't require much time to reach an idle state + following a unit-test style case, so the default is short to + prevent interaction with regular timer workloads. + +source "Kconfig.zephyr" diff --git a/samples/subsys/debug/fuzz/README.rst b/samples/subsys/debug/fuzz/README.rst index 126594436a3..0ee086c4493 100644 --- a/samples/subsys/debug/fuzz/README.rst +++ b/samples/subsys/debug/fuzz/README.rst @@ -24,7 +24,7 @@ toolchain is installed in your host environment, and build with: Thread model: posix InstalledDir: /usr/bin $ export ZEPHYR_TOOLCHAIN_VARIANT=llvm - $ west build -t run -b native_posix/native/64 samples/subsys/debug/fuzz + $ west build -t run -b native_sim/native/64 samples/subsys/debug/fuzz Over 10-20 seconds or so (runtimes can be quite variable) you will see it discover and recurse deeper into the test's deliberately @@ -43,7 +43,7 @@ Example output: INFO: Loaded 1 PC tables (2112 PCs): 2112 [0x55cbe336f498,0x55cbe3377898), INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 4096 bytes *** Booting Zephyr OS build zephyr-v3.1.0-3976-g806034e02865 *** - Hello World! native_posix/native/64 + Hello World! native_sim/native/64 INFO: A corpus is not provided, starting from an empty corpus #2 INITED cov: 101 ft: 102 corp: 1/1b exec/s: 0 rss: 30Mb # diff --git a/samples/subsys/debug/fuzz/src/main.c b/samples/subsys/debug/fuzz/src/main.c index ae486e93894..9d32301fb4a 100644 --- a/samples/subsys/debug/fuzz/src/main.c +++ b/samples/subsys/debug/fuzz/src/main.c @@ -4,6 +4,19 @@ #include #include #include +#include +#if defined(CONFIG_BOARD_NATIVE_SIM) +#include +#include +#elif defined(CONFIG_BOARD_NATIVE_POSIX) +/* Note: native_posix will be deprecated soon */ +extern void posix_init(int argc, char *argv[]); +extern void posix_exec_for(uint64_t us); +#define nsi_init posix_init +#define nsi_exec_for posix_exec_for +#else +#error "Platform not supported" +#endif /* Fuzz testing is coverage-based, so we want to hide a failure case * (a write through a null pointer in this case) down inside a call @@ -49,8 +62,8 @@ GEN_CHECK(5, 6) GEN_CHECK(6, 0) /* Fuzz input received from LLVM via "interrupt" */ -extern const uint8_t *posix_fuzz_buf; -extern size_t posix_fuzz_sz; +static const uint8_t *fuzz_buf; +static size_t fuzz_sz; K_SEM_DEFINE(fuzz_sem, 0, K_SEM_MAX_LIMIT); @@ -76,7 +89,42 @@ int main(void) /* Execute the fuzz case we got from LLVM and passed * through an interrupt to this thread. */ - check0(posix_fuzz_buf, posix_fuzz_sz); + check0(fuzz_buf, fuzz_sz); } return 0; } + +/** + * Entry point for fuzzing. Works by placing the data + * into two known symbols, triggering an app-visible interrupt, and + * then letting the simulator run for a fixed amount of time (intended to be + * "long enough" to handle the event and reach a quiescent state + * again) + */ +#if defined(CONFIG_BOARD_NATIVE_SIM) +NATIVE_SIMULATOR_IF /* We expose this function to the final runner link stage*/ +#endif +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t sz) +{ + static bool runner_initialized; + + if (!runner_initialized) { + nsi_init(0, NULL); + runner_initialized = true; + } + + /* Provide the fuzz data to the embedded OS as an interrupt, with + * "DMA-like" data placed into native_fuzz_buf/sz + */ + fuzz_buf = (void *)data; + fuzz_sz = sz; + + hw_irq_ctrl_set_irq(CONFIG_ARCH_POSIX_FUZZ_IRQ); + + /* Give the OS time to process whatever happened in that + * interrupt and reach an idle state. + */ + nsi_exec_for(k_ticks_to_us_ceil64(CONFIG_ARCH_POSIX_FUZZ_TICKS)); + + return 0; +} diff --git a/samples/subsys/display/lvgl/README.rst b/samples/subsys/display/lvgl/README.rst index a4e2f401bda..259413c4ac3 100644 --- a/samples/subsys/display/lvgl/README.rst +++ b/samples/subsys/display/lvgl/README.rst @@ -36,11 +36,12 @@ Requirements ************ Display shield and a board which provides a configuration -for Arduino connectors, for example: +for corresponding connectors, for example: - :ref:`adafruit_2_8_tft_touch_v2` and :ref:`nrf52840dk_nrf52840` - :ref:`buydisplay_2_8_tft_touch_arduino` and :ref:`nrf52840dk_nrf52840` - :ref:`ssd1306_128_shield` and :ref:`frdm_k64f` +- :ref:`seeed_xiao_round_display` and :ref:`xiao_ble` or a board with an integrated display: diff --git a/samples/subsys/display/lvgl/boards/esp32s3_touch_lcd_1_28.conf b/samples/subsys/display/lvgl/boards/esp32s3_touch_lcd_1_28.conf new file mode 100644 index 00000000000..5df721fba26 --- /dev/null +++ b/samples/subsys/display/lvgl/boards/esp32s3_touch_lcd_1_28.conf @@ -0,0 +1 @@ +CONFIG_MAIN_STACK_SIZE=4096 diff --git a/samples/subsys/display/lvgl/boards/m5stack_core2.conf b/samples/subsys/display/lvgl/boards/m5stack_core2_procpu.conf similarity index 100% rename from samples/subsys/display/lvgl/boards/m5stack_core2.conf rename to samples/subsys/display/lvgl/boards/m5stack_core2_procpu.conf diff --git a/samples/subsys/fs/fs_sample/boards/esp_wrover_kit_esp32_procpu.conf b/samples/subsys/fs/fs_sample/boards/esp_wrover_kit_esp32_procpu.conf deleted file mode 100644 index 83ac43fc39f..00000000000 --- a/samples/subsys/fs/fs_sample/boards/esp_wrover_kit_esp32_procpu.conf +++ /dev/null @@ -1,2 +0,0 @@ -CONFIG_SPI=y -CONFIG_DISK_DRIVER_SDMMC=y diff --git a/samples/subsys/fs/fs_sample/boards/esp_wrover_kit_esp32_procpu.overlay b/samples/subsys/fs/fs_sample/boards/esp_wrover_kit_esp32_procpu.overlay deleted file mode 100644 index 68cbe2013b2..00000000000 --- a/samples/subsys/fs/fs_sample/boards/esp_wrover_kit_esp32_procpu.overlay +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2021 Espressif Systems (Shanghai) Co., Ltd. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -&pinctrl { - - spim2_default: spim2_default { - group1 { - pinmux = , - , - ; - }; - }; - -}; - -&spi2 { - status = "okay"; - pinctrl-0 = <&spim2_default>; - pinctrl-names = "default"; - cs-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>; - - sdhc0: sdhc@0 { - compatible = "zephyr,sdhc-spi-slot"; - reg = <0>; - status = "okay"; - spi-max-frequency = <400000>; - mmc { - compatible = "zephyr,sdmmc-disk"; - status = "okay"; - }; - }; -}; diff --git a/samples/subsys/fs/fs_sample/boards/nrf52840dk_nrf52840_ram_disk.conf b/samples/subsys/fs/fs_sample/boards/nrf52840dk_nrf52840_ram_disk.conf new file mode 100644 index 00000000000..a4551f33181 --- /dev/null +++ b/samples/subsys/fs/fs_sample/boards/nrf52840dk_nrf52840_ram_disk.conf @@ -0,0 +1,13 @@ +# +# Copyright (c) 2024 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +CONFIG_DISK_DRIVERS=y +CONFIG_DISK_DRIVER_RAM=y +CONFIG_DISK_DRIVER_FLASH=n +# There may be no files on internal SoC flash, so this Kconfig +# options has ben enabled to create some if listing does not +# find in the first place. +CONFIG_FS_SAMPLE_CREATE_SOME_ENTRIES=y diff --git a/samples/subsys/fs/fs_sample/boards/nrf52840dk_nrf52840_ram_disk.overlay b/samples/subsys/fs/fs_sample/boards/nrf52840dk_nrf52840_ram_disk.overlay new file mode 100644 index 00000000000..99ad12dadb0 --- /dev/null +++ b/samples/subsys/fs/fs_sample/boards/nrf52840dk_nrf52840_ram_disk.overlay @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + msc_disk0 { + status="okay"; + compatible = "zephyr,ram-disk"; + /* Sample, to make things easier, mounts all FAT + * systems at "SD". + */ + disk-name = "SD"; + /* Disk size is 64kB, 128 sectors of 512B, the minimal + * required by FAT FS. + */ + sector-size = <512>; + sector-count = <128>; + }; +}; diff --git a/samples/subsys/fs/fs_sample/boards/nrf52840dk_nrf52840_ram_disk_region.overlay b/samples/subsys/fs/fs_sample/boards/nrf52840dk_nrf52840_ram_disk_region.overlay new file mode 100644 index 00000000000..63ec667505b --- /dev/null +++ b/samples/subsys/fs/fs_sample/boards/nrf52840dk_nrf52840_ram_disk_region.overlay @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* The SRAM is defined for nrf52840 in DTS to take entire 256KiB + * of RAM there is. We need some for the Disk, so we need to + * remove the original definition and replace it with smaller one. + */ +/delete-node/ &sram0; + +/ { + + soc { + /* This is defined based on dts and dtsi files for + * nrf52840 SoC; because we are not able to just + * change the size, what we have to do is to remove + * the sram0 definition, which is a combined result + * of all the sram0 referencing entries in included + * dts files, and replace it with our own. + * The first one is reduced in size original sram0: + */ + sram0: memory@20000000 { + compatible = "mmio-sram"; + reg = <0x20000000 DT_SIZE_K(192)>; + }; + /* The second one is 64kiB region taken out of SRAM, + * labeled here ram_disk, label can be anything, + * used later in disk definition. + */ + ram_disk: memory@20030000 { + compatible = "mmio-sram"; + reg = <0x20030000 DT_SIZE_K(64)>; + }; + }; + + msc_disk0 { + status="okay"; + compatible = "zephyr,ram-disk"; + /* Sample, to make things easier, mounts all FAT + * systems at "SD". + */ + disk-name = "SD"; + /* Disk size is 64kB, 128 sectors of 512B, the minimal + * required by FAT FS. + */ + sector-size = <512>; + sector-count = <128>; + /* Here is the reference to the memory reserved for our + * disk using a phandle; note that we reference the + * region by label we have defined it above. + */ + ram-region = <&ram_disk>; + }; +}; diff --git a/samples/subsys/fs/fs_sample/boards/stm32h747i_disco_stm32h747xx_m7.overlay b/samples/subsys/fs/fs_sample/boards/stm32h747i_disco_stm32h747xx_m7.overlay deleted file mode 100644 index d80aa5114fc..00000000000 --- a/samples/subsys/fs/fs_sample/boards/stm32h747i_disco_stm32h747xx_m7.overlay +++ /dev/null @@ -1,11 +0,0 @@ -/* - * 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 22d47ca3b26..55dc3d8677a 100644 --- a/samples/subsys/fs/fs_sample/sample.yaml +++ b/samples/subsys/fs/fs_sample/sample.yaml @@ -31,6 +31,18 @@ tests: sample.filesystem.fat_fs.nrf52840dk_nrf52840: build_only: true platform_allow: nrf52840dk/nrf52840 + sample.filesystem.fat_fs.nrf52840dk_nrf52840_ram_disk: + build_only: true + platform_allow: nrf52840dk/nrf52840 + extra_args: + - OVERLAY_CONFIG=boards/nrf52840dk_nrf52840_ram_disk.conf + - DTC_OVERLAY_FILE=boards/nrf52840dk_nrf52840_ram_disk.overlay + sample.filesystem.fat_fs.nrf52840dk_nrf52840_ram_disk_region: + build_only: true + platform_allow: nrf52840dk/nrf52840 + extra_args: + - OVERLAY_CONFIG=boards/nrf52840dk_nrf52840_ram_disk.conf + - DTC_OVERLAY_FILE=boards/nrf52840dk_nrf52840_ram_disk_region.overlay sample.filesystem.fat_fs.nrf52840dk_nrf52840.qspi: build_only: true platform_allow: nrf52840dk/nrf52840 diff --git a/samples/subsys/fs/littlefs/boards/rcar_h3ulcb_r8a77951_a57.overlay b/samples/subsys/fs/littlefs/boards/rcar_h3ulcb_r8a77951_a57.overlay new file mode 100644 index 00000000000..9442e02b45f --- /dev/null +++ b/samples/subsys/fs/littlefs/boards/rcar_h3ulcb_r8a77951_a57.overlay @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +&emmc2 { + disk { + status = "okay"; + }; + status = "okay"; +}; diff --git a/samples/subsys/fs/littlefs/boards/rcar_h3ulcb_r8a77951_a57_blk.conf b/samples/subsys/fs/littlefs/boards/rcar_h3ulcb_r8a77951_a57_blk.conf new file mode 100644 index 00000000000..6b4b57ac2a0 --- /dev/null +++ b/samples/subsys/fs/littlefs/boards/rcar_h3ulcb_r8a77951_a57_blk.conf @@ -0,0 +1,11 @@ +# +# Copyright (c) 2023 EPAM Systems +# +# SPDX-License-Identifier: Apache-2.0 +# +CONFIG_MAIN_STACK_SIZE=4096 +CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=8192 +CONFIG_FS_LITTLEFS_FC_HEAP_SIZE=8192 + +CONFIG_DISK_DRIVER_MMC=y +CONFIG_DISK_DRIVER_SDMMC=n diff --git a/samples/subsys/fs/littlefs/boards/rcar_salvator_xs.overlay b/samples/subsys/fs/littlefs/boards/rcar_salvator_xs.overlay new file mode 100644 index 00000000000..9442e02b45f --- /dev/null +++ b/samples/subsys/fs/littlefs/boards/rcar_salvator_xs.overlay @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +&emmc2 { + disk { + status = "okay"; + }; + status = "okay"; +}; diff --git a/samples/subsys/fs/littlefs/boards/rcar_salvator_xs_blk.conf b/samples/subsys/fs/littlefs/boards/rcar_salvator_xs_blk.conf new file mode 100644 index 00000000000..6b4b57ac2a0 --- /dev/null +++ b/samples/subsys/fs/littlefs/boards/rcar_salvator_xs_blk.conf @@ -0,0 +1,11 @@ +# +# Copyright (c) 2023 EPAM Systems +# +# SPDX-License-Identifier: Apache-2.0 +# +CONFIG_MAIN_STACK_SIZE=4096 +CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=8192 +CONFIG_FS_LITTLEFS_FC_HEAP_SIZE=8192 + +CONFIG_DISK_DRIVER_MMC=y +CONFIG_DISK_DRIVER_SDMMC=n diff --git a/samples/subsys/fs/littlefs/boards/stm32f746g_disco.overlay b/samples/subsys/fs/littlefs/boards/stm32f746g_disco.overlay index 66f9ebb3676..7626b92985a 100644 --- a/samples/subsys/fs/littlefs/boards/stm32f746g_disco.overlay +++ b/samples/subsys/fs/littlefs/boards/stm32f746g_disco.overlay @@ -4,12 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -&sdmmc1 { - sdmmc { - compatible = "zephyr,sdmmc-disk"; - }; -}; - / { fstab { compatible = "zephyr,fstab"; diff --git a/samples/subsys/fs/littlefs/boards/stm32h747i_disco_stm32h747xx_m7.overlay b/samples/subsys/fs/littlefs/boards/stm32h747i_disco_stm32h747xx_m7.overlay index 7479fac1257..b3f1639b396 100644 --- a/samples/subsys/fs/littlefs/boards/stm32h747i_disco_stm32h747xx_m7.overlay +++ b/samples/subsys/fs/littlefs/boards/stm32h747i_disco_stm32h747xx_m7.overlay @@ -5,12 +5,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -&sdmmc1 { - sdmmc { - compatible = "zephyr,sdmmc-disk"; - }; -}; - / { fstab { compatible = "zephyr,fstab"; diff --git a/samples/subsys/fs/littlefs/prj_blk.conf b/samples/subsys/fs/littlefs/prj_blk.conf index 011f919a568..b18b8cfe362 100644 --- a/samples/subsys/fs/littlefs/prj_blk.conf +++ b/samples/subsys/fs/littlefs/prj_blk.conf @@ -16,6 +16,7 @@ CONFIG_FILE_SYSTEM=y CONFIG_FILE_SYSTEM_LITTLEFS=y CONFIG_FS_LITTLEFS_BLK_DEV=y +CONFIG_FS_LITTLEFS_FMP_DEV=n CONFIG_APP_LITTLEFS_STORAGE_BLK_SDMMC=y CONFIG_NOCACHE_MEMORY=y diff --git a/samples/subsys/fs/littlefs/sample.yaml b/samples/subsys/fs/littlefs/sample.yaml index b78a070f1c9..4c53a55d591 100644 --- a/samples/subsys/fs/littlefs/sample.yaml +++ b/samples/subsys/fs/littlefs/sample.yaml @@ -26,6 +26,13 @@ tests: - stm32h750b_dk integration_platforms: - nrf52840dk/nrf52840 + sample.filesystem.littlefs.blk: + build_only: true + extra_args: + - CONF_FILE=prj_blk.conf + platform_allow: + - rcar_h3ulcb/r8a77951/a57 + - rcar_salvator_xs sample.filesystem.littlefs.nrf52840dk_spi: build_only: true platform_allow: nrf52840dk/nrf52840 diff --git a/samples/subsys/input/input_dump/boards/esp32s3_devkitm.overlay b/samples/subsys/input/input_dump/boards/esp32s3_devkitm_procpu.overlay similarity index 100% rename from samples/subsys/input/input_dump/boards/esp32s3_devkitm.overlay rename to samples/subsys/input/input_dump/boards/esp32s3_devkitm_procpu.overlay diff --git a/samples/subsys/ipc/ipc_service/static_vrings/CMakeLists.txt b/samples/subsys/ipc/ipc_service/static_vrings/CMakeLists.txt index 873a71f6ead..4deb07c4789 100644 --- a/samples/subsys/ipc/ipc_service/static_vrings/CMakeLists.txt +++ b/samples/subsys/ipc/ipc_service/static_vrings/CMakeLists.txt @@ -1,5 +1,6 @@ # # Copyright (c) 2021 Carlo Caione +# Copyright 2024 NXP # # SPDX-License-Identifier: Apache-2.0 # @@ -8,12 +9,24 @@ cmake_minimum_required(VERSION 3.20.0) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) -if(NOT CONFIG_BOARD_NRF5340DK_NRF5340_CPUAPP) +set(REMOTE_ZEPHYR_DIR ${CMAKE_CURRENT_BINARY_DIR}/../remote/zephyr) + +if(NOT (CONFIG_BOARD_NRF5340DK_NRF5340_CPUAPP OR + CONFIG_BOARD_LPCXPRESSO55S69_LPC55S69_CPU0 OR + CONFIG_BOARD_MIMXRT1160_EVK_MIMXRT1166_CM7 OR + CONFIG_BOARD_MIMXRT1170_EVK_MIMXRT1176_CM7 + ) + ) message(FATAL_ERROR "${BOARD} is not supported for this sample") endif() project(ipc_service) +if(CONFIG_INCLUDE_REMOTE_DIR) + target_include_directories(zephyr_interface + INTERFACE ${REMOTE_ZEPHYR_DIR}/include/public) +endif() + target_sources(app PRIVATE src/main.c) include(ExternalProject) diff --git a/samples/subsys/ipc/ipc_service/static_vrings/Kconfig b/samples/subsys/ipc/ipc_service/static_vrings/Kconfig new file mode 100644 index 00000000000..ee3874c39f9 --- /dev/null +++ b/samples/subsys/ipc/ipc_service/static_vrings/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/subsys/ipc/ipc_service/static_vrings/Kconfig.sysbuild b/samples/subsys/ipc/ipc_service/static_vrings/Kconfig.sysbuild index d0849e37dde..a1214db3284 100644 --- a/samples/subsys/ipc/ipc_service/static_vrings/Kconfig.sysbuild +++ b/samples/subsys/ipc/ipc_service/static_vrings/Kconfig.sysbuild @@ -1,4 +1,5 @@ # Copyright 2023 Nordic Semiconductor ASA +# Copyright 2024 NXP # # SPDX-License-Identifier: Apache-2.0 @@ -7,3 +8,7 @@ source "share/sysbuild/Kconfig" config NET_CORE_BOARD string default "nrf5340dk/nrf5340/cpunet" if $(BOARD) = "nrf5340dk" + default "lpcxpresso55s69/lpc55s69/cpu1" if $(BOARD) = "lpcxpresso55s69" + default "mimxrt1160_evk/mimxrt1166/cm4" if $(BOARD) = "mimxrt1160_evk" + default "mimxrt1170_evk/mimxrt1176/cm4" if $(BOARD) = "mimxrt1170_evk" + default "mimxrt1170_evkb/mimxrt1176/cm4" if $(BOARD) = "mimxrt1170_evkb" diff --git a/samples/subsys/ipc/ipc_service/static_vrings/README.rst b/samples/subsys/ipc/ipc_service/static_vrings/README.rst index 97cd8c823b2..8fe0591b786 100644 --- a/samples/subsys/ipc/ipc_service/static_vrings/README.rst +++ b/samples/subsys/ipc/ipc_service/static_vrings/README.rst @@ -20,6 +20,42 @@ Building the application for nrf5340dk/nrf5340/cpuapp :goals: debug :west-args: --sysbuild +Building the application for lpcxpresso55s69/lpc55s69/cpu0 +********************************************************** + +.. zephyr-app-commands:: + :zephyr-app: samples/subsys/ipc/ipc_service/static_vrings + :board: lpcxpresso55s69/lpc55s69/cpu0 + :goals: debug + :west-args: --sysbuild + +Building the application for mimxrt1160_evk/mimxrt1166/cm7 +********************************************************** + +.. zephyr-app-commands:: + :zephyr-app: samples/subsys/ipc/ipc_service/static_vrings + :board: mimxrt1160_evk/mimxrt1166/cm7 + :goals: debug + :west-args: --sysbuild + +Building the application for mimxrt1170_evk/mimxrt1176/cm7 +********************************************************** + +.. zephyr-app-commands:: + :zephyr-app: samples/subsys/ipc/ipc_service/static_vrings + :board: mimxrt1170_evk/mimxrt1176/cm7 + :goals: debug + :west-args: --sysbuild + +Building the application for mimxrt1170_evk@B/mimxrt1176/cm7 +************************************************************ + +.. zephyr-app-commands:: + :zephyr-app: samples/subsys/ipc/ipc_service/static_vrings + :board: mimxrt1170_evk@B/mimxrt1176/cm7 + :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/boards/lpcxpresso55s69_lpc55s69_cpu0.conf b/samples/subsys/ipc/ipc_service/static_vrings/boards/lpcxpresso55s69_lpc55s69_cpu0.conf new file mode 100644 index 00000000000..7e6904d56d5 --- /dev/null +++ b/samples/subsys/ipc/ipc_service/static_vrings/boards/lpcxpresso55s69_lpc55s69_cpu0.conf @@ -0,0 +1 @@ +CONFIG_SECOND_CORE_MCUX=y diff --git a/samples/subsys/ipc/ipc_service/static_vrings/boards/lpcxpresso55s69_lpc55s69_cpu0.overlay b/samples/subsys/ipc/ipc_service/static_vrings/boards/lpcxpresso55s69_lpc55s69_cpu0.overlay new file mode 100644 index 00000000000..462777a8fc6 --- /dev/null +++ b/samples/subsys/ipc/ipc_service/static_vrings/boards/lpcxpresso55s69_lpc55s69_cpu0.overlay @@ -0,0 +1,74 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + + / { + chosen { + /* Delete ipc chosen property where old IPM mailbox driver bellow is + * configured. + */ + /delete-property/ zephyr,ipc; + /delete-property/ zephyr,ipc_shm; + }; + + /* Define memory regions for IPC + * Note that shared memory must have specific MPU attributes set. + */ + sram4_ipc0: memory@20040000{ + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x20040000 DT_SIZE_K(8)>; + zephyr,memory-region="SRAM4_IPC0"; + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_IO))>; + }; + + sram4_ipc1: memory@20042000{ + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x20042000 DT_SIZE_K(8)>; + zephyr,memory-region="SRAM4_IPC1"; + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_IO))>; + }; + + soc { + /* Delete IPM Driver node nxp,lpc-mailbox */ + /delete-node/ mailbox@8b000; + + /* Attach MBOX driver to Mailbox Unit */ + mbox:mailbox0@5008b000 { + compatible = "nxp,mbox-mailbox"; + reg = <0x5008b000 0xEC>; + interrupts = <31 0>; + rx-channels = <4>; + #mbox-cells = <1>; + status = "okay"; + }; + }; + + ipc { + /delete-node/ ipc0; + + ipc0: ipc0 { + compatible = "zephyr,ipc-openamp-static-vrings"; + memory-region = <&sram4_ipc0>; + mboxes = <&mbox 0>, <&mbox 1>; + mbox-names = "tx", "rx"; + role = "host"; + status = "okay"; + }; + + ipc1: ipc1 { + compatible = "zephyr,ipc-openamp-static-vrings"; + memory-region = <&sram4_ipc1>; + mboxes = <&mbox 2>, <&mbox 3>; + mbox-names = "tx", "rx"; + role = "host"; + zephyr,priority = <1 PRIO_COOP>; + zephyr,buffer-size = <128>; + status = "okay"; + }; + }; + }; diff --git a/samples/subsys/ipc/ipc_service/static_vrings/boards/mimxrt1160_evk_mimxrt1166_cm7.conf b/samples/subsys/ipc/ipc_service/static_vrings/boards/mimxrt1160_evk_mimxrt1166_cm7.conf new file mode 100644 index 00000000000..0dfb100ed70 --- /dev/null +++ b/samples/subsys/ipc/ipc_service/static_vrings/boards/mimxrt1160_evk_mimxrt1166_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/subsys/ipc/ipc_service/static_vrings/boards/mimxrt1160_evk_mimxrt1166_cm7.overlay b/samples/subsys/ipc/ipc_service/static_vrings/boards/mimxrt1160_evk_mimxrt1166_cm7.overlay new file mode 100644 index 00000000000..0abcec2d647 --- /dev/null +++ b/samples/subsys/ipc/ipc_service/static_vrings/boards/mimxrt1160_evk_mimxrt1166_cm7.overlay @@ -0,0 +1,76 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + chosen { + /* Delete ipc chosen property where old IPM mailbox driver bellow is + * configured. + */ + /delete-property/ zephyr,ipc; + /delete-property/ zephyr,ipc_shm; + + zephyr,console = &lpuart1; + zephyr,shell-uart = &lpuart1; + }; + + /* Define memory regions for IPC + * Note that shared memory must have specific MPU attributes set. + */ + ocram2_ipc0: memory@202c0000{ + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x202c0000 DT_SIZE_K(32)>; + zephyr,memory-region="OCRAM2_IPC0"; + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_IO))>; + }; + ocram2_ipc1: memory@202c8000{ + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x202c8000 DT_SIZE_K(32)>; + zephyr,memory-region="OCRAM2_IPC1"; + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_IO))>; + }; + + 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"; + }; + }; + + ipc { + /delete-node/ ipc0; + + ipc0: ipc0 { + compatible = "zephyr,ipc-openamp-static-vrings"; + memory-region = <&ocram2_ipc0>; + mboxes = <&mbox 0>, <&mbox 1>; + mbox-names = "tx", "rx"; + role = "host"; + status = "okay"; + }; + + ipc1: ipc1 { + compatible = "zephyr,ipc-openamp-static-vrings"; + memory-region = <&ocram2_ipc1>; + mboxes = <&mbox 2>, <&mbox 3>; + mbox-names = "tx", "rx"; + role = "host"; + zephyr,priority = <1 PRIO_COOP>; + zephyr,buffer-size = <128>; + status = "okay"; + }; + }; +}; diff --git a/samples/subsys/ipc/ipc_service/static_vrings/boards/mimxrt1170_evk_mimxrt1176_cm7.conf b/samples/subsys/ipc/ipc_service/static_vrings/boards/mimxrt1170_evk_mimxrt1176_cm7.conf new file mode 100644 index 00000000000..0dfb100ed70 --- /dev/null +++ b/samples/subsys/ipc/ipc_service/static_vrings/boards/mimxrt1170_evk_mimxrt1176_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/subsys/ipc/ipc_service/static_vrings/boards/mimxrt1170_evk_mimxrt1176_cm7.overlay b/samples/subsys/ipc/ipc_service/static_vrings/boards/mimxrt1170_evk_mimxrt1176_cm7.overlay new file mode 100644 index 00000000000..132401362cb --- /dev/null +++ b/samples/subsys/ipc/ipc_service/static_vrings/boards/mimxrt1170_evk_mimxrt1176_cm7.overlay @@ -0,0 +1,76 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + chosen { + /* Delete ipc chosen property where old IPM mailbox driver bellow is + * configured. + */ + /delete-property/ zephyr,ipc; + /delete-property/ zephyr,ipc_shm; + + zephyr,console = &lpuart1; + zephyr,shell-uart = &lpuart1; + }; + + /* Define memory regions for IPC + * Note that shared memory must have specific MPU attributes set. + */ + ocram2_ipc0: memory@202c0000{ + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x202c0000 DT_SIZE_K(32)>; + zephyr,memory-region="OCRAM2_IPC0"; + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_IO))>; + }; + ocram2_ipc1: memory@202c8000{ + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x202c8000 DT_SIZE_K(32)>; + zephyr,memory-region="OCRAM2_IPC1"; + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_IO))>; + }; + + 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"; + }; + }; + + ipc { + /delete-node/ ipc0; + + ipc0: ipc0 { + compatible = "zephyr,ipc-openamp-static-vrings"; + memory-region = <&ocram2_ipc0>; + mboxes = <&mbox 0>, <&mbox 1>; + mbox-names = "tx", "rx"; + role = "host"; + status = "okay"; + }; + + ipc1: ipc1 { + compatible = "zephyr,ipc-openamp-static-vrings"; + memory-region = <&ocram2_ipc1>; + mboxes = <&mbox 2>, <&mbox 3>; + mbox-names = "tx", "rx"; + role = "host"; + zephyr,priority = <1 PRIO_COOP>; + zephyr,buffer-size = <128>; + status = "okay"; + }; + }; +}; diff --git a/samples/subsys/ipc/ipc_service/static_vrings/boards/mimxrt1170_evk_mimxrt1176_cm7_B.conf b/samples/subsys/ipc/ipc_service/static_vrings/boards/mimxrt1170_evk_mimxrt1176_cm7_B.conf new file mode 100644 index 00000000000..0dfb100ed70 --- /dev/null +++ b/samples/subsys/ipc/ipc_service/static_vrings/boards/mimxrt1170_evk_mimxrt1176_cm7_B.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/subsys/ipc/ipc_service/static_vrings/boards/mimxrt1170_evk_mimxrt1176_cm7_B.overlay b/samples/subsys/ipc/ipc_service/static_vrings/boards/mimxrt1170_evk_mimxrt1176_cm7_B.overlay new file mode 100644 index 00000000000..132401362cb --- /dev/null +++ b/samples/subsys/ipc/ipc_service/static_vrings/boards/mimxrt1170_evk_mimxrt1176_cm7_B.overlay @@ -0,0 +1,76 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + chosen { + /* Delete ipc chosen property where old IPM mailbox driver bellow is + * configured. + */ + /delete-property/ zephyr,ipc; + /delete-property/ zephyr,ipc_shm; + + zephyr,console = &lpuart1; + zephyr,shell-uart = &lpuart1; + }; + + /* Define memory regions for IPC + * Note that shared memory must have specific MPU attributes set. + */ + ocram2_ipc0: memory@202c0000{ + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x202c0000 DT_SIZE_K(32)>; + zephyr,memory-region="OCRAM2_IPC0"; + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_IO))>; + }; + ocram2_ipc1: memory@202c8000{ + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x202c8000 DT_SIZE_K(32)>; + zephyr,memory-region="OCRAM2_IPC1"; + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_IO))>; + }; + + 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"; + }; + }; + + ipc { + /delete-node/ ipc0; + + ipc0: ipc0 { + compatible = "zephyr,ipc-openamp-static-vrings"; + memory-region = <&ocram2_ipc0>; + mboxes = <&mbox 0>, <&mbox 1>; + mbox-names = "tx", "rx"; + role = "host"; + status = "okay"; + }; + + ipc1: ipc1 { + compatible = "zephyr,ipc-openamp-static-vrings"; + memory-region = <&ocram2_ipc1>; + mboxes = <&mbox 2>, <&mbox 3>; + mbox-names = "tx", "rx"; + role = "host"; + zephyr,priority = <1 PRIO_COOP>; + zephyr,buffer-size = <128>; + status = "okay"; + }; + }; +}; diff --git a/samples/subsys/ipc/ipc_service/static_vrings/remote/boards/lpcxpresso55s69_lpc55s69_cpu1.conf b/samples/subsys/ipc/ipc_service/static_vrings/remote/boards/lpcxpresso55s69_lpc55s69_cpu1.conf new file mode 100644 index 00000000000..b9e2b072ad4 --- /dev/null +++ b/samples/subsys/ipc/ipc_service/static_vrings/remote/boards/lpcxpresso55s69_lpc55s69_cpu1.conf @@ -0,0 +1,2 @@ +CONFIG_SECOND_CORE_MCUX=y +CONFIG_BUILD_OUTPUT_HEX=y diff --git a/samples/subsys/ipc/ipc_service/static_vrings/remote/boards/lpcxpresso55s69_lpc55s69_cpu1.overlay b/samples/subsys/ipc/ipc_service/static_vrings/remote/boards/lpcxpresso55s69_lpc55s69_cpu1.overlay new file mode 100644 index 00000000000..e0d1030c0a8 --- /dev/null +++ b/samples/subsys/ipc/ipc_service/static_vrings/remote/boards/lpcxpresso55s69_lpc55s69_cpu1.overlay @@ -0,0 +1,74 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + + / { + chosen { + /* Delete ipc chosen property where old IPM mailbox driver bellow is + * configured. + */ + /delete-property/ zephyr,ipc; + /delete-property/ zephyr,ipc_shm; + }; + + /* Define memory regions for IPC + * Note that shared memory must have specific MPU attributes set. + */ + sram4_ipc0: memory@20040000{ + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x20040000 DT_SIZE_K(8)>; + zephyr,memory-region="SRAM4_IPC0"; + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_IO))>; + }; + + sram4_ipc1: memory@20042000{ + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x20042000 DT_SIZE_K(8)>; + zephyr,memory-region="SRAM4_IPC1"; + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_IO))>; + }; + + soc { + /* Delete IPM Driver node nxp,lpc-mailbox */ + /delete-node/ mailbox@8b000; + + /* Attach MBOX driver to Mailbox Unit */ + mbox:mailbox0@5008b000 { + compatible = "nxp,mbox-mailbox"; + reg = <0x5008b000 0xEC>; + interrupts = <31 0>; + rx-channels = <4>; + #mbox-cells = <1>; + status = "okay"; + }; + }; + + ipc { + /delete-node/ ipc0; + + ipc0: ipc0 { + compatible = "zephyr,ipc-openamp-static-vrings"; + memory-region = <&sram4_ipc0>; + mboxes = <&mbox 0>, <&mbox 1>; + mbox-names = "rx", "tx"; + role = "remote"; + status = "okay"; + }; + + ipc1: ipc1 { + compatible = "zephyr,ipc-openamp-static-vrings"; + memory-region = <&sram4_ipc1>; + mboxes = <&mbox 2>, <&mbox 3>; + mbox-names = "rx", "tx"; + role = "remote"; + zephyr,priority = <1 PRIO_COOP>; + zephyr,buffer-size = <128>; + status = "okay"; + }; + }; +}; diff --git a/samples/subsys/ipc/ipc_service/static_vrings/remote/boards/mimxrt1160_evk_mimxrt1166_cm4.conf b/samples/subsys/ipc/ipc_service/static_vrings/remote/boards/mimxrt1160_evk_mimxrt1166_cm4.conf new file mode 100644 index 00000000000..0d36a72aec6 --- /dev/null +++ b/samples/subsys/ipc/ipc_service/static_vrings/remote/boards/mimxrt1160_evk_mimxrt1166_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/subsys/ipc/ipc_service/static_vrings/remote/boards/mimxrt1160_evk_mimxrt1166_cm4.overlay b/samples/subsys/ipc/ipc_service/static_vrings/remote/boards/mimxrt1160_evk_mimxrt1166_cm4.overlay new file mode 100644 index 00000000000..274700289bf --- /dev/null +++ b/samples/subsys/ipc/ipc_service/static_vrings/remote/boards/mimxrt1160_evk_mimxrt1166_cm4.overlay @@ -0,0 +1,98 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + 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; + /delete-property/ zephyr,ipc_shm; + }; + + /* Define memory regions for IPC + * Note that shared memory must have specific MPU attributes set. + */ + ocram2_ipc0: memory@202c0000{ + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x202c0000 DT_SIZE_K(32)>; + zephyr,memory-region="OCRAM2_IPC0"; + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_IO))>; + }; + ocram2_ipc1: memory@202c8000{ + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x202c8000 DT_SIZE_K(32)>; + zephyr,memory-region="OCRAM2_IPC1"; + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_IO))>; + }; + + 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"; + }; + }; + + ipc { + /delete-node/ ipc0; + + ipc0: ipc0 { + compatible = "zephyr,ipc-openamp-static-vrings"; + memory-region = <&ocram2_ipc0>; + mboxes = <&mbox 0>, <&mbox 1>; + mbox-names = "rx", "tx"; + role = "remote"; + status = "okay"; + }; + + ipc1: ipc1 { + compatible = "zephyr,ipc-openamp-static-vrings"; + memory-region = <&ocram2_ipc1>; + mboxes = <&mbox 2>, <&mbox 3>; + mbox-names = "rx", "tx"; + role = "remote"; + zephyr,priority = <1 PRIO_COOP>; + zephyr,buffer-size = <128>; + status = "okay"; + }; + }; +}; + +/* Enable secondary LPUART */ +&lpuart2 { + status = "okay"; + current-speed = <115200>; +}; + +/* Disable primary GPT timer */ +&gpt_hw_timer { + status = "disabled"; +}; diff --git a/samples/subsys/ipc/ipc_service/static_vrings/remote/boards/mimxrt1170_evk_mimxrt1176_cm4.conf b/samples/subsys/ipc/ipc_service/static_vrings/remote/boards/mimxrt1170_evk_mimxrt1176_cm4.conf new file mode 100644 index 00000000000..0d36a72aec6 --- /dev/null +++ b/samples/subsys/ipc/ipc_service/static_vrings/remote/boards/mimxrt1170_evk_mimxrt1176_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/subsys/ipc/ipc_service/static_vrings/remote/boards/mimxrt1170_evk_mimxrt1176_cm4.overlay b/samples/subsys/ipc/ipc_service/static_vrings/remote/boards/mimxrt1170_evk_mimxrt1176_cm4.overlay new file mode 100644 index 00000000000..274700289bf --- /dev/null +++ b/samples/subsys/ipc/ipc_service/static_vrings/remote/boards/mimxrt1170_evk_mimxrt1176_cm4.overlay @@ -0,0 +1,98 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + 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; + /delete-property/ zephyr,ipc_shm; + }; + + /* Define memory regions for IPC + * Note that shared memory must have specific MPU attributes set. + */ + ocram2_ipc0: memory@202c0000{ + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x202c0000 DT_SIZE_K(32)>; + zephyr,memory-region="OCRAM2_IPC0"; + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_IO))>; + }; + ocram2_ipc1: memory@202c8000{ + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x202c8000 DT_SIZE_K(32)>; + zephyr,memory-region="OCRAM2_IPC1"; + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_IO))>; + }; + + 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"; + }; + }; + + ipc { + /delete-node/ ipc0; + + ipc0: ipc0 { + compatible = "zephyr,ipc-openamp-static-vrings"; + memory-region = <&ocram2_ipc0>; + mboxes = <&mbox 0>, <&mbox 1>; + mbox-names = "rx", "tx"; + role = "remote"; + status = "okay"; + }; + + ipc1: ipc1 { + compatible = "zephyr,ipc-openamp-static-vrings"; + memory-region = <&ocram2_ipc1>; + mboxes = <&mbox 2>, <&mbox 3>; + mbox-names = "rx", "tx"; + role = "remote"; + zephyr,priority = <1 PRIO_COOP>; + zephyr,buffer-size = <128>; + status = "okay"; + }; + }; +}; + +/* Enable secondary LPUART */ +&lpuart2 { + status = "okay"; + current-speed = <115200>; +}; + +/* Disable primary GPT timer */ +&gpt_hw_timer { + status = "disabled"; +}; diff --git a/samples/subsys/ipc/ipc_service/static_vrings/remote/boards/mimxrt1170_evk_mimxrt1176_cm4_B.conf b/samples/subsys/ipc/ipc_service/static_vrings/remote/boards/mimxrt1170_evk_mimxrt1176_cm4_B.conf new file mode 100644 index 00000000000..0d36a72aec6 --- /dev/null +++ b/samples/subsys/ipc/ipc_service/static_vrings/remote/boards/mimxrt1170_evk_mimxrt1176_cm4_B.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/subsys/ipc/ipc_service/static_vrings/remote/boards/mimxrt1170_evk_mimxrt1176_cm4_B.overlay b/samples/subsys/ipc/ipc_service/static_vrings/remote/boards/mimxrt1170_evk_mimxrt1176_cm4_B.overlay new file mode 100644 index 00000000000..274700289bf --- /dev/null +++ b/samples/subsys/ipc/ipc_service/static_vrings/remote/boards/mimxrt1170_evk_mimxrt1176_cm4_B.overlay @@ -0,0 +1,98 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + 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; + /delete-property/ zephyr,ipc_shm; + }; + + /* Define memory regions for IPC + * Note that shared memory must have specific MPU attributes set. + */ + ocram2_ipc0: memory@202c0000{ + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x202c0000 DT_SIZE_K(32)>; + zephyr,memory-region="OCRAM2_IPC0"; + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_IO))>; + }; + ocram2_ipc1: memory@202c8000{ + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x202c8000 DT_SIZE_K(32)>; + zephyr,memory-region="OCRAM2_IPC1"; + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_IO))>; + }; + + 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"; + }; + }; + + ipc { + /delete-node/ ipc0; + + ipc0: ipc0 { + compatible = "zephyr,ipc-openamp-static-vrings"; + memory-region = <&ocram2_ipc0>; + mboxes = <&mbox 0>, <&mbox 1>; + mbox-names = "rx", "tx"; + role = "remote"; + status = "okay"; + }; + + ipc1: ipc1 { + compatible = "zephyr,ipc-openamp-static-vrings"; + memory-region = <&ocram2_ipc1>; + mboxes = <&mbox 2>, <&mbox 3>; + mbox-names = "rx", "tx"; + role = "remote"; + zephyr,priority = <1 PRIO_COOP>; + zephyr,buffer-size = <128>; + status = "okay"; + }; + }; +}; + +/* Enable secondary LPUART */ +&lpuart2 { + status = "okay"; + current-speed = <115200>; +}; + +/* Disable primary GPT timer */ +&gpt_hw_timer { + status = "disabled"; +}; diff --git a/samples/subsys/ipc/ipc_service/static_vrings/sample.yaml b/samples/subsys/ipc/ipc_service/static_vrings/sample.yaml index f776f90adb9..0189185c839 100644 --- a/samples/subsys/ipc/ipc_service/static_vrings/sample.yaml +++ b/samples/subsys/ipc/ipc_service/static_vrings/sample.yaml @@ -2,7 +2,12 @@ sample: name: IPC Service example integration (OpenAMP static_vrings backend) tests: sample.ipc.static_vrings: - platform_allow: nrf5340dk/nrf5340/cpuapp + platform_allow: + - nrf5340dk/nrf5340/cpuapp + - lpcxpresso55s69/lpc55s69/cpu0 + - mimxrt1160_evk/mimxrt1166/cm7 + - mimxrt1170_evk/mimxrt1176/cm7 + - mimxrt1170_evk@B/mimxrt1176/cm7 integration_platforms: - nrf5340dk/nrf5340/cpuapp tags: ipc diff --git a/samples/subsys/ipc/ipc_service/static_vrings/sysbuild.cmake b/samples/subsys/ipc/ipc_service/static_vrings/sysbuild.cmake index d0d79b8f240..2e99a95d3c3 100644 --- a/samples/subsys/ipc/ipc_service/static_vrings/sysbuild.cmake +++ b/samples/subsys/ipc/ipc_service/static_vrings/sysbuild.cmake @@ -1,4 +1,5 @@ # Copyright (c) 2023 Nordic Semiconductor ASA +# Copyright 2024 NXP # SPDX-License-Identifier: Apache-2.0 if("${SB_CONFIG_NET_CORE_BOARD}" STREQUAL "") @@ -7,8 +8,16 @@ if("${SB_CONFIG_NET_CORE_BOARD}" STREQUAL "") "There is no remote board selected in Kconfig.sysbuild") endif() +set(REMOTE_APP remote) + ExternalZephyrProject_Add( - APPLICATION remote - SOURCE_DIR ${APP_DIR}/remote + APPLICATION ${REMOTE_APP} + SOURCE_DIR ${APP_DIR}/${REMOTE_APP} BOARD ${SB_CONFIG_NET_CORE_BOARD} ) + +# Add dependencies so that the remote sample will be built first +# This is required because some primary cores need information from the +# remote core's build, such as the output image's LMA +add_dependencies(${DEFAULT_IMAGE} ${REMOTE_APP}) +sysbuild_add_dependencies(CONFIGURE ${DEFAULT_IMAGE} ${REMOTE_APP}) diff --git a/samples/subsys/ipc/rpmsg_service/Kconfig.sysbuild b/samples/subsys/ipc/rpmsg_service/Kconfig.sysbuild index b75f2d4b6f6..16f2901f901 100644 --- a/samples/subsys/ipc/rpmsg_service/Kconfig.sysbuild +++ b/samples/subsys/ipc/rpmsg_service/Kconfig.sysbuild @@ -8,3 +8,4 @@ config RPMSG_REMOTE_BOARD string default "mps2/an521/cpu1" if $(BOARD) = "mps2" default "v2m_musca_b1/musca_b1/ns" if $(BOARD) = "v2m_musca_b1" + default "stm32h747i_disco/stm32h747xx/m4" if $(BOARD) = "stm32h747i_disco" diff --git a/samples/subsys/ipc/rpmsg_service/README.rst b/samples/subsys/ipc/rpmsg_service/README.rst index 6ff5a61be80..034441f06ca 100644 --- a/samples/subsys/ipc/rpmsg_service/README.rst +++ b/samples/subsys/ipc/rpmsg_service/README.rst @@ -128,3 +128,26 @@ remote) will appear on the corresponding serial ports: ... Remote core received a message: 98 RPMsg Service demo ended. + +Building the application for stm32h747i_disco/stm32h7xx +******************************************************* + +.. zephyr-app-commands:: + :zephyr-app: samples/subsys/ipc/rpmsg_service + :board: stm32h747i_disco/stm32h7xx/m7 + :goals: debug + +The serial output should now look like this: + +.. code-block:: console + + *** Booting Zephyr OS build 15736b7415be *** + Starting application thread! + + RPMsg Service [master] demo started + Master core received a message: 1 + Master core received a message: 3 + Master core received a message: 5 + ... + Master core received a message: 99 + RPMsg Service demo ended. diff --git a/samples/subsys/ipc/rpmsg_service/boards/stm32h747i_disco_stm32h747xx_m7.overlay b/samples/subsys/ipc/rpmsg_service/boards/stm32h747i_disco_stm32h747xx_m7.overlay new file mode 100644 index 00000000000..43f791b9a2c --- /dev/null +++ b/samples/subsys/ipc/rpmsg_service/boards/stm32h747i_disco_stm32h747xx_m7.overlay @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2024 Celina Sophie Kalus + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + zephyr,ipc_shm = &sram4; + zephyr,ipc = &mailbox; + }; +}; + +&mailbox { + status = "okay"; +}; diff --git a/samples/subsys/ipc/rpmsg_service/remote/boards/stm32h747i_disco_stm32h747xx_m4.overlay b/samples/subsys/ipc/rpmsg_service/remote/boards/stm32h747i_disco_stm32h747xx_m4.overlay new file mode 100644 index 00000000000..43f791b9a2c --- /dev/null +++ b/samples/subsys/ipc/rpmsg_service/remote/boards/stm32h747i_disco_stm32h747xx_m4.overlay @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2024 Celina Sophie Kalus + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + zephyr,ipc_shm = &sram4; + zephyr,ipc = &mailbox; + }; +}; + +&mailbox { + status = "okay"; +}; diff --git a/samples/subsys/llext/edk/README.rst b/samples/subsys/llext/edk/README.rst new file mode 100644 index 00000000000..22e678c314d --- /dev/null +++ b/samples/subsys/llext/edk/README.rst @@ -0,0 +1,137 @@ +.. zephyr:code-sample:: llext-edk + :name: Linkable loadable extensions EDK + :relevant-api: llext + + Enable linkable loadable extension development outside the Zephyr tree using + LLEXT EDK (Extension Development Kit). + +Overview +******** + +This sample demonstrates how to use the Zephyr LLEXT EDK (Extension Development +Kit). It is composed of one Zephyr application, which provides APIs for the +extensions that it loads. The provided API is a simple publish/subscribe system, +based on :ref:`Zbus `, which extensions use to communicate with each other. + +The application is composed of a subscriber thread, which listens for events +published and republishes them via Zbus to the extensions that are +subscribers. There are four extensions, which are loaded by the application and +run in different contexts. Extensions ``ext1``, ``ext2`` and ``ext3`` run in +userspace, each demonstrating different application and Zephyr API usage, such as +semaphores, spawning threads to listen for events or simply publishing or +subscribing to events. Extension ``kext1`` runs in a kernel thread, albeit similar +to ``ext3``. + +The application also creates different memory domains for each extension, thus +providing some level of isolation - although the kernel one still has access +to all of Zephyr kernel. + +Note that the kernel extension is only available when the EDK is built with +the :kconfig:option:`CONFIG_LLEXT_EDK_USERSPACE_ONLY` option disabled. + + +The application is built using the Zephyr build system. The EDK is built using +the Zephyr build system as well, via ``llext-edk`` target. The EDK is then +extracted and the extensions are built using CMake. + +Finally, the way the application loads the extensions is by including them +during build time, which is not really practical. This sample is about the EDK +providing the ability to build extensions independently from the application. +One could build the extensions in different directories, not related to the +Zephyr application - even on different machines, using only the EDK. At the +limit, one could even imagine a scenario where the extensions are built by +different teams, using the EDK provided by the application developer. + +Building the EDK +**************** + +To build the EDK, use the ``llext-edk`` target. For example: + +.. zephyr-app-commands:: + :zephyr-app: samples/subsys/llext/edk/app + :board: qemu_cortex_r5 + :goals: build llext-edk + :west-args: -p=always + :compact: + +Copy the EDK to some place and extract it: + +.. code-block:: console + + mkdir /tmp/edk + cp build/zephyr/llext-edk.tar.xz /tmp/edk + cd /tmp/edk + tar -xf llext-edk.tar.xz + +Then set ``LLEXT_EDK_INSTALL_DIR`` to the extracted directory: + +.. code-block:: console + + export LLEXT_EDK_INSTALL_DIR=/tmp/edk/llext-edk + +This variable is used by the extensions to find the EDK. + +Building the extensions +*********************** + +The :envvar:`ZEPHYR_SDK_INSTALL_DIR` environment variable is used by the +extensions to find the Zephyr SDK, so you need to ensure it's properly set: + +.. code-block:: console + + export ZEPHYR_SDK_INSTALL_DIR=
+ +To build the extensions, in the ``ext1``, ``ext2``, ``ext3`` and ``kext1`` +directories: + +.. code-block:: console + + cmake -B build + make -C build + +Alternatively, you can set the ``LLEXT_EDK_INSTALL_DIR`` directly in the +CMake invocation: + +.. code-block:: console + + cmake -B build -DLLEXT_EDK_INSTALL_DIR=/tmp/edk/llext-edk + make -C build + +Building the application +************************ + +Now, build the application, including the extensions, and run it: + +.. zephyr-app-commands:: + :zephyr-app: samples/subsys/llext/edk/app + :board: qemu_cortex_r5 + :goals: build run + :west-args: -p=always + :compact: + +You should see something like: + +.. code-block:: console + + [app]Subscriber thread [0x20b28] started. + [app]Loading extension [kext1]. + [app]Thread 0x20840 created to run extension [kext1], at privileged mode. + [k-ext1]Waiting sem + [app]Thread [0x222a0] registered event [0x223c0] + [k-ext1]Waiting event + [app]Loading extension [ext1]. + [app]Thread 0x20a30 created to run extension [ext1], at userspace. + [app]Thread [0x20a30] registered event [0x26060] + [ext1]Waiting event + [app]Loading extension [ext2]. + [app]Thread 0x20938 created to run extension [ext2], at userspace. + [ext2]Publishing tick + [app][subscriber_thread]Got channel tick_chan + [ext1]Got event, reading channel + [ext1]Read val: 0 + [ext1]Waiting event + [k-ext1]Got event, giving sem + [k-ext1]Got sem, reading channel + [k-ext1]Read val: 0 + [k-ext1]Waiting sem + (...) diff --git a/samples/subsys/llext/edk/app/CMakeLists.txt b/samples/subsys/llext/edk/app/CMakeLists.txt new file mode 100644 index 00000000000..1afc133186e --- /dev/null +++ b/samples/subsys/llext/edk/app/CMakeLists.txt @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: Apache-2.0 + +# It seems llext currently doesn't support some Thumb32 relocation +# instructions generated when building the extensions with default +# flags. As a workaround, we remove these *unrelated* flags from the +# default flags. This allows the extensions to be built without the +# unsupported instructions. +# See issue #72832 for more details. +list(APPEND LLEXT_EDK_REMOVE_FLAGS -mcpu=cortex-r5 -mfloat-abi=hard) + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) + +project(app LANGUAGES C) + +target_sources(app PRIVATE src/main.c src/pubsub.c) +zephyr_include_directories(include) diff --git a/samples/subsys/llext/edk/app/include/app_api.h b/samples/subsys/llext/edk/app/include/app_api.h new file mode 100644 index 00000000000..bc6cb49dca8 --- /dev/null +++ b/samples/subsys/llext/edk/app/include/app_api.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2024 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _TEST_EDK_H_ +#define _TEST_EDK_H_ +#include +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + enum Channels { + CHAN_TICK = 1, + CHAN_LAST + }; + + struct channel_tick_data { + unsigned long l; + }; + + __syscall int publish(enum Channels channel, void *data, + size_t data_len); + __syscall int receive(enum Channels channel, void *data, + size_t data_len); + __syscall int register_subscriber(enum Channels channel, + struct k_event *evt); +#ifdef __cplusplus +} +#endif + +#include +#endif /* _TEST_EDK_H_ */ diff --git a/samples/subsys/llext/edk/app/prj.conf b/samples/subsys/llext/edk/app/prj.conf new file mode 100644 index 00000000000..c9c758f6767 --- /dev/null +++ b/samples/subsys/llext/edk/app/prj.conf @@ -0,0 +1,19 @@ +CONFIG_APPLICATION_DEFINED_SYSCALL=y +CONFIG_USERSPACE=y +CONFIG_LLEXT=y + +CONFIG_MAIN_STACK_SIZE=4096 + +CONFIG_DYNAMIC_OBJECTS=y +CONFIG_DYNAMIC_THREAD=y +CONFIG_DYNAMIC_THREAD_ALLOC=y +CONFIG_DYNAMIC_THREAD_PREFER_ALLOC=y +CONFIG_ZBUS=y +CONFIG_ZBUS_CHANNEL_NAME=y + +CONFIG_LLEXT_HEAP_SIZE=32 + +# Uncomment to disable kext1. +#CONFIG_LLEXT_EDK_USERSPACE_ONLY=y + +CONFIG_EVENTS=y diff --git a/samples/subsys/llext/edk/app/sample.yaml b/samples/subsys/llext/edk/app/sample.yaml new file mode 100644 index 00000000000..1bcfe288e4d --- /dev/null +++ b/samples/subsys/llext/edk/app/sample.yaml @@ -0,0 +1,12 @@ +common: + tags: llext edk + arch_allow: + - arm + filter: CONFIG_ARCH_HAS_USERSPACE +sample: + description: EDK sample application + name: EDK sample application +tests: + sample.edk.app: + build_only: true + tags: edk llext diff --git a/samples/subsys/llext/edk/app/src/main.c b/samples/subsys/llext/edk/app/src/main.c new file mode 100644 index 00000000000..502901d59bd --- /dev/null +++ b/samples/subsys/llext/edk/app/src/main.c @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2024 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#include + +#include + +/** + * Assume that if the extension 1 is not built, we are building the + * EDK. If others are not built, this will just fail. + */ +#if defined __has_include +# if __has_include("../../ext1/build/ext1.inc") +# undef EDK_BUILD +# else +# pragma message "Extension 1 not built, assuming EDK build." +# define EDK_BUILD +# endif +#endif + +#ifndef EDK_BUILD +#include "../../ext1/build/ext1.inc" +#define ext1_inc ext1_llext +#define ext1_len ext1_llext_len +#include "../../ext2/build/ext2.inc" +#define ext2_inc ext2_llext +#define ext2_len ext2_llext_len +#include "../../ext3/build/ext3.inc" +#define ext3_inc ext3_llext +#define ext3_len ext3_llext_len +#ifndef CONFIG_LLEXT_EDK_USERSPACE_ONLY +#include "../../k-ext1/build/kext1.inc" +#define kext1_inc kext1_llext +#define kext1_len kext1_llext_len +#endif +#endif + +#define USER_STACKSIZE 2048 +#define USER_HEAPSIZE 8192 +#define MAX_EXTENSIONS 4 + +extern k_tid_t start_subscriber_thread(void); + +/* Maybe make all this depend on MAX_EXTENSIONS? */ +struct k_thread user_thread1, user_thread2, user_thread3, kernel_thread1; +K_THREAD_STACK_DEFINE(user_stack1, USER_STACKSIZE); +K_THREAD_STACK_DEFINE(user_stack2, USER_STACKSIZE); +K_THREAD_STACK_DEFINE(user_stack3, USER_STACKSIZE); +K_THREAD_STACK_DEFINE(kernel_stack1, USER_STACKSIZE); + +K_HEAP_DEFINE(user_heap1, USER_HEAPSIZE); +K_HEAP_DEFINE(user_heap2, USER_HEAPSIZE); +K_HEAP_DEFINE(user_heap3, USER_HEAPSIZE); +K_HEAP_DEFINE(kernel_heap1, USER_HEAPSIZE); + +struct { + k_tid_t thread; + struct llext *ext; +} extension_threads[MAX_EXTENSIONS]; +int max_extension_thread_idx; + +static const void * const load(const char *name, struct llext **ext, void *buf, + size_t len) +{ +#ifndef EDK_BUILD + struct llext_buf_loader buf_loader = LLEXT_BUF_LOADER(buf, len); + struct llext_loader *loader = &buf_loader.loader; + struct llext_load_param ldr_parm = LLEXT_LOAD_PARAM_DEFAULT; + + llext_load(loader, name, ext, &ldr_parm); + + return llext_find_sym(&(*ext)->exp_tab, "start"); +#else + return NULL; +#endif +} + +static void unload(struct llext **ext) +{ + llext_unload(ext); +} + +static void user_function(void *p1, void *p2, void *p3) +{ + int (*start_fn)(void) = p1; + + printk("[app]Thread %p created to run extension [%s], at %s\n", + k_current_get(), (char *)p2, + k_is_user_context() ? "userspace." : "privileged mode."); + + start_fn(); + printk("[app]Thread %p done\n", k_current_get()); +} + +void k_sys_fatal_error_handler(unsigned int reason, const z_arch_esf_t *esf) +{ + int i; + + printk("[app]Fatal handler! Thread: %p\n", k_current_get()); + + for (i = 0; i < max_extension_thread_idx; i++) { + if (extension_threads[i].thread == k_current_get()) { + unload(&extension_threads[i].ext); + } + } +} + +void run_extension_on_thread(void *ext_inc, size_t ext_len, + struct k_mem_domain *domain, + struct k_thread *thread, + k_thread_stack_t *stack, + struct k_heap *heap, + const char *name, + k_tid_t subscriber_thread_id, + int flag) +{ + int (*start_fn)(void); + struct llext **ext = &extension_threads[max_extension_thread_idx].ext; + + printk("[app]Loading extension [%s].\n", name); + start_fn = load(name, ext, ext_inc, ext_len); + + llext_add_domain(*ext, domain); + + k_thread_create(thread, stack, USER_STACKSIZE, + user_function, start_fn, (void *)name, NULL, + -1, flag | K_INHERIT_PERMS, K_FOREVER); + k_mem_domain_add_thread(domain, thread); + k_mem_domain_add_thread(domain, subscriber_thread_id); + + k_thread_heap_assign(thread, heap); + + extension_threads[max_extension_thread_idx].thread = thread; + max_extension_thread_idx++; + + k_thread_start(thread); +} + +int main(void) +{ + struct k_mem_domain domain1, domain2, domain3, kdomain1; + +#ifndef EDK_BUILD + k_tid_t subscriber_thread_id = start_subscriber_thread(); +#endif + /* This and all other similar sleeps are here to provide a chance for + * the newly created thread to run. + */ + k_sleep(K_MSEC(1)); + + k_mem_domain_init(&domain1, 0, NULL); + k_mem_domain_init(&domain2, 0, NULL); + k_mem_domain_init(&domain3, 0, NULL); + k_mem_domain_init(&kdomain1, 0, NULL); + +#ifndef EDK_BUILD +#ifndef CONFIG_LLEXT_EDK_USERSPACE_ONLY + run_extension_on_thread(kext1_inc, kext1_len, &kdomain1, + &kernel_thread1, kernel_stack1, &kernel_heap1, + "kext1", subscriber_thread_id, 0); + k_sleep(K_MSEC(1)); +#endif + run_extension_on_thread(ext1_inc, ext1_len, &domain1, &user_thread1, + user_stack1, &user_heap1, "ext1", + subscriber_thread_id, K_USER); + k_sleep(K_MSEC(1)); + run_extension_on_thread(ext2_inc, ext2_len, &domain2, &user_thread2, + user_stack2, &user_heap2, "ext2", + subscriber_thread_id, K_USER); + k_sleep(K_MSEC(1)); + run_extension_on_thread(ext3_inc, ext3_len, &domain3, &user_thread3, + user_stack3, &user_heap3, "ext3", + subscriber_thread_id, K_USER); +#endif + + k_sleep(K_FOREVER); + + return 0; +} diff --git a/samples/subsys/llext/edk/app/src/pubsub.c b/samples/subsys/llext/edk/app/src/pubsub.c new file mode 100644 index 00000000000..fa7641be461 --- /dev/null +++ b/samples/subsys/llext/edk/app/src/pubsub.c @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2024 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include +#include +#include + +#include + +#define MAX_SUBSCRIBERS 64 +#define SUBSCRIBER_THREAD_STACK_SIZE 1024 +#define SUBSCRIBER_THREAD_PRIORITY K_PRIO_PREEMPT(1) + +ZBUS_CHAN_DEFINE(tick_chan, + struct channel_tick_data, + NULL, + NULL, + ZBUS_OBSERVERS(default_sub), + ZBUS_MSG_INIT(.l = 0)); + +ZBUS_SUBSCRIBER_DEFINE(default_sub, 4); + +K_THREAD_STACK_DEFINE(subscriber_thread_stack, SUBSCRIBER_THREAD_STACK_SIZE); +static struct k_thread subscriber_thread; + +static struct subs { + struct { + k_tid_t thread; + struct k_event *evt; + } subscribers[MAX_SUBSCRIBERS]; + struct k_mutex subscribers_mtx; + int subscribers_count; + const struct zbus_channel *chan; +} channel_subscribers[] = { + /* Empty one first, so no channel is zero (first item on enum == 1) */ + {{ }}, + { .chan = &tick_chan }, + {{ }} +}; + +static int remove_subscriber(k_tid_t thread, struct subs *sus) +{ + int i; + + for (i = 0; i < sus->subscribers_count; i++) { + if (sus->subscribers[i].thread == thread) { + sus->subscribers[i].thread = NULL; + sus->subscribers[i].evt = NULL; + break; + } + } + + if (i == sus->subscribers_count) { + return -ENOENT; + } + + /* Move all entries after excluded one, to keep things tidy */ + memmove(&sus->subscribers[i], &sus->subscribers[i + 1], + (sus->subscribers_count - i - 1) * + sizeof(sus->subscribers[0])); + sus->subscribers_count--; + + return 0; +} + +static int add_subscriber(k_tid_t thread, struct subs *sus, + struct k_event *evt) +{ + if (sus->subscribers_count >= MAX_SUBSCRIBERS) { + return -ENOMEM; + } + + sus->subscribers[sus->subscribers_count].thread = thread; + sus->subscribers[sus->subscribers_count].evt = evt; + sus->subscribers_count++; + + printk("[app]Thread [%p] registered event [%p]\n", thread, evt); + return 0; +} + +static void notify_subscribers(enum Channels channel) +{ + int i; + struct subs *subs = &channel_subscribers[channel]; + + for (i = 0; i < subs->subscribers_count; i++) { + k_event_post(subs->subscribers[i].evt, channel); + } +} + +static void subscriber_thread_fn(void *p0, void *p1, void *p2) +{ + const struct zbus_channel *chan; + int i; + + printk("[app]Subscriber thread [%p] started.\n", k_current_get()); + while (zbus_sub_wait(&default_sub, &chan, K_FOREVER) == 0) { + printk("[app][subscriber_thread]Got channel %s\n", + zbus_chan_name(chan)); + + for (i = 0; i < CHAN_LAST; i++) { + if (channel_subscribers[i].chan == chan) { + notify_subscribers((enum Channels)i); + break; + } + } + } +} + +k_tid_t start_subscriber_thread(void) +{ + return k_thread_create(&subscriber_thread, subscriber_thread_stack, + SUBSCRIBER_THREAD_STACK_SIZE, + subscriber_thread_fn, NULL, NULL, NULL, + SUBSCRIBER_THREAD_PRIORITY, 0, K_NO_WAIT); +} + +int z_impl_publish(enum Channels channel, void *data, size_t data_len) +{ + const struct zbus_channel *chan = channel_subscribers[channel].chan; + + if (channel == CHAN_LAST) { + return -EINVAL; + } + + return zbus_chan_pub(chan, data, K_NO_WAIT); +} +EXPORT_SYMBOL(z_impl_publish); + +#ifdef CONFIG_USERSPACE +static inline int z_vrfy_publish(enum Channels channel, void *data, + size_t data_len) +{ + int ret; + void *copy_data; + + copy_data = k_usermode_alloc_from_copy(data, data_len); + if (copy_data == NULL) { + return -EINVAL; + } + + ret = z_impl_publish(channel, copy_data, data_len); + + k_free(copy_data); + + return ret; +} +#include +#endif + +int z_impl_receive(enum Channels channel, void *data, size_t data_len) +{ + size_t msg_size; + + if (channel == CHAN_LAST || data == NULL) { + return -EINVAL; + } + + msg_size = channel_subscribers[channel].chan->message_size; + if (data_len < msg_size) { + return -EINVAL; + } + + return zbus_chan_read(channel_subscribers[channel].chan, data, + K_NO_WAIT); +} +EXPORT_SYMBOL(z_impl_receive); + +#ifdef CONFIG_USERSPACE +static inline int z_vrfy_receive(enum Channels channel, void *data, + size_t data_len) +{ + if (K_SYSCALL_MEMORY_WRITE(data, data_len)) { + return -EINVAL; + } + + return z_impl_receive(channel, data, data_len); +} +#include +#endif + +int z_impl_register_subscriber(enum Channels channel, struct k_event *evt) +{ + struct subs *subs = &channel_subscribers[channel]; + int ret; + + if (channel == CHAN_LAST) { + return -EINVAL; + } + + k_mutex_lock(&subs->subscribers_mtx, K_FOREVER); + + if (evt == NULL) { + ret = remove_subscriber(k_current_get(), subs); + } else { + ret = add_subscriber(k_current_get(), subs, evt); + } + + k_mutex_unlock(&subs->subscribers_mtx); + + return ret; +} +EXPORT_SYMBOL(z_impl_register_subscriber); + +#ifdef CONFIG_USERSPACE +static inline int z_vrfy_register_subscriber(enum Channels channel, + struct k_event *evt) +{ + if (K_SYSCALL_OBJ(evt, K_OBJ_EVENT)) { + return -EINVAL; + } + + return z_impl_register_subscriber(channel, evt); +} +#include +#endif diff --git a/samples/subsys/llext/edk/ext1/CMakeLists.txt b/samples/subsys/llext/edk/ext1/CMakeLists.txt new file mode 100644 index 00000000000..cfb25479765 --- /dev/null +++ b/samples/subsys/llext/edk/ext1/CMakeLists.txt @@ -0,0 +1,35 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +set(CMAKE_TOOLCHAIN_FILE toolchain.cmake) +set(CMAKE_C_COMPILER_FORCED TRUE) +set(CMAKE_CXX_COMPILER_FORCED TRUE) + +project(ext1) + +# Include EDK CFLAGS +if(NOT DEFINED LLEXT_EDK_INSTALL_DIR) + set(LLEXT_EDK_INSTALL_DIR $ENV{LLEXT_EDK_INSTALL_DIR}) +endif() +include(${LLEXT_EDK_INSTALL_DIR}/cmake.cflags) + +# Add LLEXT_CFLAGS to our flags +add_compile_options(${LLEXT_CFLAGS}) +add_compile_options("-c") + +# Get flags from COMPILE_OPTIONS +get_property(COMPILE_OPTIONS_PROP DIRECTORY PROPERTY COMPILE_OPTIONS) + +add_custom_command( + OUTPUT + ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.llext + ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.inc + COMMAND ${CMAKE_C_COMPILER} ${COMPILE_OPTIONS_PROP} + -o ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.llext + ${PROJECT_SOURCE_DIR}/src/main.c + COMMAND xxd -ip ${PROJECT_NAME}.llext + ${PROJECT_NAME}.inc +) + +add_custom_target(ext1 ALL DEPENDS ${PROJECT_BINARY_DIR}/ext1.llext) diff --git a/samples/subsys/llext/edk/ext1/src/main.c b/samples/subsys/llext/edk/ext1/src/main.c new file mode 100644 index 00000000000..d7f9c6aa71b --- /dev/null +++ b/samples/subsys/llext/edk/ext1/src/main.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2024 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include + +int start(void) +{ + /* Inside extensions, all kobjects need to be dynamically allocated */ + struct k_event *tick_evt = k_object_alloc(K_OBJ_EVENT); + + k_event_init(tick_evt); + + register_subscriber(CHAN_TICK, tick_evt); + + while (true) { + long l; + + printk("[ext1]Waiting event\n"); + k_event_wait(tick_evt, CHAN_TICK, true, K_FOREVER); + + printk("[ext1]Got event, reading channel\n"); + receive(CHAN_TICK, &l, sizeof(l)); + printk("[ext1]Read val: %ld\n", l); + } + + return 0; +} +LL_EXTENSION_SYMBOL(start); diff --git a/samples/subsys/llext/edk/ext1/toolchain.cmake b/samples/subsys/llext/edk/ext1/toolchain.cmake new file mode 100644 index 00000000000..c511cc4a6a0 --- /dev/null +++ b/samples/subsys/llext/edk/ext1/toolchain.cmake @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: Apache-2.0 + +set(CMAKE_C_COMPILER arm-zephyr-eabi-gcc) +set(CMAKE_FIND_ROOT_PATH $ENV{ZEPHYR_SDK_INSTALL_DIR}/arm-zephyr-eabi) diff --git a/samples/subsys/llext/edk/ext2/CMakeLists.txt b/samples/subsys/llext/edk/ext2/CMakeLists.txt new file mode 100644 index 00000000000..70ea00f0b61 --- /dev/null +++ b/samples/subsys/llext/edk/ext2/CMakeLists.txt @@ -0,0 +1,31 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +set(CMAKE_TOOLCHAIN_FILE toolchain.cmake) +set(CMAKE_C_COMPILER_FORCED TRUE) +set(CMAKE_CXX_COMPILER_FORCED TRUE) + +project(ext2) + +# Include EDK CFLAGS +if(NOT DEFINED LLEXT_EDK_INSTALL_DIR) + set(LLEXT_EDK_INSTALL_DIR $ENV{LLEXT_EDK_INSTALL_DIR}) +endif() +include(${LLEXT_EDK_INSTALL_DIR}/cmake.cflags) + +# Add LLEXT_CFLAGS to our flags +set(CMAKE_C_FLAGS ${LLEXT_CFLAGS} "-c") + +add_custom_command( + OUTPUT + ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.llext + ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.inc + COMMAND ${CMAKE_C_COMPILER} ${CMAKE_C_FLAGS} + -o ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.llext + ${PROJECT_SOURCE_DIR}/src/main.c + COMMAND xxd -ip ${PROJECT_NAME}.llext + ${PROJECT_NAME}.inc +) + +add_custom_target(ext2 ALL DEPENDS ${PROJECT_BINARY_DIR}/ext2.llext) diff --git a/samples/subsys/llext/edk/ext2/src/main.c b/samples/subsys/llext/edk/ext2/src/main.c new file mode 100644 index 00000000000..38a054a5ccb --- /dev/null +++ b/samples/subsys/llext/edk/ext2/src/main.c @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2024 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include + +int start(void) +{ + int i; + + for (i = 0; i < 5; i++) { + struct channel_tick_data ctd = { .l = i }; + + printk("[ext2]Publishing tick\n"); + publish(CHAN_TICK, &ctd, sizeof(ctd)); + k_sleep(K_SECONDS(1)); + } + + return 0; +} +LL_EXTENSION_SYMBOL(start); diff --git a/samples/subsys/llext/edk/ext2/toolchain.cmake b/samples/subsys/llext/edk/ext2/toolchain.cmake new file mode 100644 index 00000000000..c511cc4a6a0 --- /dev/null +++ b/samples/subsys/llext/edk/ext2/toolchain.cmake @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: Apache-2.0 + +set(CMAKE_C_COMPILER arm-zephyr-eabi-gcc) +set(CMAKE_FIND_ROOT_PATH $ENV{ZEPHYR_SDK_INSTALL_DIR}/arm-zephyr-eabi) diff --git a/samples/subsys/llext/edk/ext3/CMakeLists.txt b/samples/subsys/llext/edk/ext3/CMakeLists.txt new file mode 100644 index 00000000000..8f95956a255 --- /dev/null +++ b/samples/subsys/llext/edk/ext3/CMakeLists.txt @@ -0,0 +1,35 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +set(CMAKE_TOOLCHAIN_FILE toolchain.cmake) +set(CMAKE_C_COMPILER_FORCED TRUE) +set(CMAKE_CXX_COMPILER_FORCED TRUE) + +project(ext3) + +# Include EDK CFLAGS +if(NOT DEFINED LLEXT_EDK_INSTALL_DIR) + set(LLEXT_EDK_INSTALL_DIR $ENV{LLEXT_EDK_INSTALL_DIR}) +endif() +include(${LLEXT_EDK_INSTALL_DIR}/cmake.cflags) + +# Add LLEXT_CFLAGS to our flags +add_compile_options(${LLEXT_CFLAGS}) +add_compile_options("-c") + +# Get flags from COMPILE_OPTIONS +get_property(COMPILE_OPTIONS_PROP DIRECTORY PROPERTY COMPILE_OPTIONS) + +add_custom_command( + OUTPUT + ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.llext + ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.inc + COMMAND ${CMAKE_C_COMPILER} ${COMPILE_OPTIONS_PROP} + -o ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.llext + ${PROJECT_SOURCE_DIR}/src/main.c + COMMAND xxd -ip ${PROJECT_NAME}.llext + ${PROJECT_NAME}.inc +) + +add_custom_target(ext3 ALL DEPENDS ${PROJECT_BINARY_DIR}/ext3.llext) diff --git a/samples/subsys/llext/edk/ext3/src/main.c b/samples/subsys/llext/edk/ext3/src/main.c new file mode 100644 index 00000000000..19aff8352d9 --- /dev/null +++ b/samples/subsys/llext/edk/ext3/src/main.c @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2024 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include + +#define STACKSIZE 512 +#define PRIORITY 2 + +static struct k_sem *my_sem; + +static void tick_sub(void *p1, void *p2, void *p3) +{ + struct k_event *tick_evt = k_object_alloc(K_OBJ_EVENT); + + k_event_init(tick_evt); + + register_subscriber(CHAN_TICK, tick_evt); + + while (true) { + printk("[ext3]Waiting event\n"); + k_event_wait(tick_evt, CHAN_TICK, true, K_FOREVER); + printk("[ext3]Got event, giving sem\n"); + + k_sem_give(my_sem); + } +} + +int start(void) +{ + k_thread_stack_t *sub_stack; + struct k_thread *sub_thread; + + /* Currently, any kobjects need to be dynamic on extensions, + * so the semaphore, thread stack and thread objects are created + * dynamically. + */ + my_sem = k_object_alloc(K_OBJ_SEM); + k_sem_init(my_sem, 0, 1); + + sub_stack = k_thread_stack_alloc(STACKSIZE, K_USER); + sub_thread = k_object_alloc(K_OBJ_THREAD); + printk("[ext3]%p - %p\n", sub_stack, sub_thread); + k_thread_create(sub_thread, sub_stack, STACKSIZE, tick_sub, NULL, NULL, + NULL, PRIORITY, K_INHERIT_PERMS | K_USER, K_NO_WAIT); + + while (true) { + long l; + + printk("[ext3]Waiting sem\n"); + k_sem_take(my_sem, K_FOREVER); + + printk("[ext3]Got sem, reading channel\n"); + receive(CHAN_TICK, &l, sizeof(l)); + printk("[ext3]Read val: %ld\n", l); + } + + return 0; +} +LL_EXTENSION_SYMBOL(start); diff --git a/samples/subsys/llext/edk/ext3/toolchain.cmake b/samples/subsys/llext/edk/ext3/toolchain.cmake new file mode 100644 index 00000000000..c511cc4a6a0 --- /dev/null +++ b/samples/subsys/llext/edk/ext3/toolchain.cmake @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: Apache-2.0 + +set(CMAKE_C_COMPILER arm-zephyr-eabi-gcc) +set(CMAKE_FIND_ROOT_PATH $ENV{ZEPHYR_SDK_INSTALL_DIR}/arm-zephyr-eabi) diff --git a/samples/subsys/llext/edk/k-ext1/CMakeLists.txt b/samples/subsys/llext/edk/k-ext1/CMakeLists.txt new file mode 100644 index 00000000000..b1f4aae47e8 --- /dev/null +++ b/samples/subsys/llext/edk/k-ext1/CMakeLists.txt @@ -0,0 +1,35 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +set(CMAKE_TOOLCHAIN_FILE toolchain.cmake) +set(CMAKE_C_COMPILER_FORCED TRUE) +set(CMAKE_CXX_COMPILER_FORCED TRUE) + +project(kext1) + +# Include EDK CFLAGS +if(NOT DEFINED LLEXT_EDK_INSTALL_DIR) + set(LLEXT_EDK_INSTALL_DIR $ENV{LLEXT_EDK_INSTALL_DIR}) +endif() +include(${LLEXT_EDK_INSTALL_DIR}/cmake.cflags) + +# Add LLEXT_CFLAGS to our flags +add_compile_options(${LLEXT_CFLAGS}) +add_compile_options("-c") + +# Get flags from COMPILE_OPTIONS +get_property(COMPILE_OPTIONS_PROP DIRECTORY PROPERTY COMPILE_OPTIONS) + +add_custom_command( + OUTPUT + ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.llext + ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.inc + COMMAND ${CMAKE_C_COMPILER} ${COMPILE_OPTIONS_PROP} + -o ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.llext + ${PROJECT_SOURCE_DIR}/src/main.c + COMMAND xxd -ip ${PROJECT_NAME}.llext + ${PROJECT_NAME}.inc +) + +add_custom_target(kext1 ALL DEPENDS ${PROJECT_BINARY_DIR}/kext1.llext) diff --git a/samples/subsys/llext/edk/k-ext1/src/main.c b/samples/subsys/llext/edk/k-ext1/src/main.c new file mode 100644 index 00000000000..34dedc63728 --- /dev/null +++ b/samples/subsys/llext/edk/k-ext1/src/main.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2024 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include + +#define STACKSIZE 512 +#define PRIORITY 2 + +static struct k_sem *my_sem; + +static void tick_sub(void *p1, void *p2, void *p3) +{ + struct k_event *tick_evt = k_object_alloc(K_OBJ_EVENT); + + k_event_init(tick_evt); + + register_subscriber(CHAN_TICK, tick_evt); + + while (true) { + printk("[k-ext1]Waiting event\n"); + k_event_wait(tick_evt, CHAN_TICK, true, K_FOREVER); + printk("[k-ext1]Got event, giving sem\n"); + + k_sem_give(my_sem); + } +} + +int start(void) +{ + k_thread_stack_t *sub_stack; + struct k_thread *sub_thread; + + /* Currently, any kobjects need to be dynamic on extensions, + * so the semaphore, thread stack and thread objects are created + * dynamically. + */ + my_sem = k_object_alloc(K_OBJ_SEM); + k_sem_init(my_sem, 0, 1); + + sub_stack = k_thread_stack_alloc(STACKSIZE, 0); + sub_thread = k_object_alloc(K_OBJ_THREAD); + k_thread_create(sub_thread, sub_stack, STACKSIZE, tick_sub, NULL, NULL, + NULL, PRIORITY, K_INHERIT_PERMS, K_NO_WAIT); + + while (true) { + long l; + + printk("[k-ext1]Waiting sem\n"); + k_sem_take(my_sem, K_FOREVER); + + printk("[k-ext1]Got sem, reading channel\n"); + receive(CHAN_TICK, &l, sizeof(l)); + printk("[k-ext1]Read val: %ld\n", l); + } + + return 0; +} +LL_EXTENSION_SYMBOL(start); diff --git a/samples/subsys/llext/edk/k-ext1/toolchain.cmake b/samples/subsys/llext/edk/k-ext1/toolchain.cmake new file mode 100644 index 00000000000..c511cc4a6a0 --- /dev/null +++ b/samples/subsys/llext/edk/k-ext1/toolchain.cmake @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: Apache-2.0 + +set(CMAKE_C_COMPILER arm-zephyr-eabi-gcc) +set(CMAKE_FIND_ROOT_PATH $ENV{ZEPHYR_SDK_INSTALL_DIR}/arm-zephyr-eabi) diff --git a/samples/subsys/logging/ble_backend/src/main.c b/samples/subsys/logging/ble_backend/src/main.c index 843ad366b51..bd11b987634 100644 --- a/samples/subsys/logging/ble_backend/src/main.c +++ b/samples/subsys/logging/ble_backend/src/main.c @@ -17,11 +17,15 @@ static const struct bt_data ad[] = { BT_DATA_BYTES(BT_DATA_UUID128_ALL, LOGGER_BACKEND_BLE_ADV_UUID_DATA) }; +static const struct bt_data sd[] = { + BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1), +}; + static void start_adv(void) { int err; - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0); + err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd)); if (err) { LOG_ERR("Advertising failed to start (err %d)", err); return; diff --git a/samples/subsys/lorawan/class_a/README.rst b/samples/subsys/lorawan/class_a/README.rst index c29853ae064..22d9b8f3a48 100644 --- a/samples/subsys/lorawan/class_a/README.rst +++ b/samples/subsys/lorawan/class_a/README.rst @@ -25,30 +25,3 @@ The following commands build and flash the sample. :board: nucleo_wl55jc :goals: build flash :compact: - -Extended Configuration -********************** - -This sample can be configured to run the application-layer clock -synchronization service and/or the remote multicast setup service -in the background. - -The following commands build and flash the sample with clock synchronization -enabled. - -.. zephyr-app-commands:: - :zephyr-app: samples/subsys/lorawan/class_a - :board: nucleo_wl55jc - :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-clock-sync.conf b/samples/subsys/lorawan/class_a/overlay-clock-sync.conf deleted file mode 100644 index e19b01a42a6..00000000000 --- a/samples/subsys/lorawan/class_a/overlay-clock-sync.conf +++ /dev/null @@ -1,3 +0,0 @@ -CONFIG_LORAWAN_SERVICES=y -CONFIG_LORAWAN_SERVICES_LOG_LEVEL_DBG=y -CONFIG_LORAWAN_APP_CLOCK_SYNC=y diff --git a/samples/subsys/lorawan/class_a/overlay-multicast.conf b/samples/subsys/lorawan/class_a/overlay-multicast.conf deleted file mode 100644 index 6bd51655643..00000000000 --- a/samples/subsys/lorawan/class_a/overlay-multicast.conf +++ /dev/null @@ -1,9 +0,0 @@ -# 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 7a757da815d..c617ec5feb4 100644 --- a/samples/subsys/lorawan/class_a/sample.yaml +++ b/samples/subsys/lorawan/class_a/sample.yaml @@ -44,13 +44,3 @@ tests: extra_configs: - CONFIG_LORAMAC_REGION_EU868=y - CONFIG_LORAMAC_REGION_US915=y - sample.lorawan.class_a.clock_sync: - extra_args: OVERLAY_CONFIG="overlay-clock-sync.conf" - 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/lorawan/class_a/src/main.c b/samples/subsys/lorawan/class_a/src/main.c index 76ff5529f57..1e31baf36e4 100644 --- a/samples/subsys/lorawan/class_a/src/main.c +++ b/samples/subsys/lorawan/class_a/src/main.c @@ -99,10 +99,6 @@ int main(void) return 0; } -#ifdef CONFIG_LORAWAN_APP_CLOCK_SYNC - lorawan_clock_sync_run(); -#endif - LOG_INF("Sending data..."); while (1) { ret = lorawan_send(2, data, sizeof(data), diff --git a/samples/subsys/lorawan/fuota/CMakeLists.txt b/samples/subsys/lorawan/fuota/CMakeLists.txt new file mode 100644 index 00000000000..44d48475bb9 --- /dev/null +++ b/samples/subsys/lorawan/fuota/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(lorawan_fuota) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/samples/subsys/lorawan/fuota/README.rst b/samples/subsys/lorawan/fuota/README.rst new file mode 100644 index 00000000000..608a9f63dcc --- /dev/null +++ b/samples/subsys/lorawan/fuota/README.rst @@ -0,0 +1,41 @@ +.. zephyr:code-sample:: lorawan-fuota + :name: LoRaWAN FUOTA + :relevant-api: lorawan_api + + Perform a LoRaWAN firmware-upgrade over the air (FUOTA) operation. + +Overview +******** + +An application to demonstrate firmware-upgrade over the air (FUOTA) over LoRaWAN. + +The following services specified by the LoRa Alliance are used: + +- Application Layer Clock Synchronization (`TS003-2.0.0`_) +- Remote Multicast Setup (`TS005-1.0.0`_) +- Fragmented Data Block Transport (`TS004-1.0.0`_) + +The FUOTA process is started by the application and afterwards runs in the background in its own +work queue thread. After a firmware upgrade is successfully received, the application is notified +via a callback and can reboot the device into MCUboot to apply the upgrade. + +A LoRaWAN Application Server implementing the relevant services is required for this sample to work. + +.. _`TS003-2.0.0`: https://resources.lora-alliance.org/technical-specifications/ts003-2-0-0-application-layer-clock-synchronization +.. _`TS005-1.0.0`: https://resources.lora-alliance.org/technical-specifications/lorawan-remote-multicast-setup-specification-v1-0-0 +.. _`TS004-1.0.0`: https://resources.lora-alliance.org/technical-specifications/lorawan-fragmented-data-block-transport-specification-v1-0-0 + +Building and Running +******************** + +This sample can be found under :zephyr_file:`samples/subsys/lorawan/fuota` in the Zephyr tree. + +Before building the sample, make sure to select the correct region in the ``prj.conf`` file. + +The following commands build and flash the sample. + +.. zephyr-app-commands:: + :zephyr-app: samples/subsys/lorawan/fuota + :board: nucleo_wl55jc + :goals: build flash + :compact: diff --git a/samples/subsys/lorawan/fuota/boards/nucleo_wl55jc.conf b/samples/subsys/lorawan/fuota/boards/nucleo_wl55jc.conf new file mode 100644 index 00000000000..cbc1e847898 --- /dev/null +++ b/samples/subsys/lorawan/fuota/boards/nucleo_wl55jc.conf @@ -0,0 +1,5 @@ +# use fixed frag size (min and max 232 bytes) to avoid RAM overflow +CONFIG_LORAWAN_FRAG_TRANSPORT_MIN_FRAG_SIZE=232 + +# alternatively, the redundancy could be reduced +# CONFIG_LORAWAN_FRAG_TRANSPORT_MAX_REDUNDANCY=7 diff --git a/samples/subsys/lorawan/fuota/prj.conf b/samples/subsys/lorawan/fuota/prj.conf new file mode 100644 index 00000000000..884fa8da183 --- /dev/null +++ b/samples/subsys/lorawan/fuota/prj.conf @@ -0,0 +1,36 @@ +# General Zephyr settings +CONFIG_MAIN_STACK_SIZE=2048 +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048 +CONFIG_THREAD_NAME=y +CONFIG_LOG=y + +# LoRa PHY and required peripherals +CONFIG_LORA=y +CONFIG_SPI=y +CONFIG_GPIO=y + +# NVS required to store LoRaWAN DevNonce +CONFIG_NVS=y +CONFIG_SETTINGS=y + +# Random number generator required for several LoRaWAN services +CONFIG_ENTROPY_GENERATOR=y + +# LoRaWAN application layer +CONFIG_LORAWAN=y +CONFIG_LORAMAC_REGION_EU868=y +CONFIG_LORAWAN_NVM_SETTINGS=y + +# LoRaWAN services required for FUOTA +CONFIG_LORAWAN_SERVICES=y +CONFIG_LORAWAN_SERVICES_LOG_LEVEL_DBG=y +CONFIG_LORAWAN_APP_CLOCK_SYNC=y +CONFIG_LORAWAN_REMOTE_MULTICAST=y +CONFIG_LORAWAN_FRAG_TRANSPORT=y + +# Flash driver to store firmware image +CONFIG_FLASH=y +CONFIG_FLASH_MAP=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_STREAM_FLASH=y +CONFIG_IMG_MANAGER=y diff --git a/samples/subsys/lorawan/fuota/sample.yaml b/samples/subsys/lorawan/fuota/sample.yaml new file mode 100644 index 00000000000..1715e0ce2be --- /dev/null +++ b/samples/subsys/lorawan/fuota/sample.yaml @@ -0,0 +1,21 @@ +sample: + description: Demonstration of LoRaWAN Firmware Upgrade Over The Air + name: LoRaWAN FUOTA +common: + depends_on: lora + tags: lorawan + filter: dt_label_with_parent_compat_enabled("slot0_partition", "fixed-partitions") + and dt_label_with_parent_compat_enabled("slot1_partition", "fixed-partitions") + and dt_chosen_enabled("zephyr,flash-controller") and CONFIG_FLASH_HAS_DRIVER_ENABLED + harness: console + harness_config: + type: one_line + regex: + - " lorawan_fuota: Joining network over OTAA" +tests: + sample.lorawan.fuota: + integration_platforms: + - nucleo_wl55jc + # only allow selected boards which are known to have sufficient RAM for the given settings + platform_allow: + - nucleo_wl55jc diff --git a/samples/subsys/lorawan/fuota/src/main.c b/samples/subsys/lorawan/fuota/src/main.c new file mode 100644 index 00000000000..e6254bdf4b8 --- /dev/null +++ b/samples/subsys/lorawan/fuota/src/main.c @@ -0,0 +1,134 @@ +/* + * LoRaWAN FUOTA sample application + * + * Copyright (c) 2022-2024 Libre Solar Technologies GmbH + * Copyright (c) 2022-2024 tado GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +LOG_MODULE_REGISTER(lorawan_fuota, CONFIG_LORAWAN_SERVICES_LOG_LEVEL); + +/* Customize based on device configuration */ +#define LORAWAN_DEV_EUI { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define LORAWAN_JOIN_EUI { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define LORAWAN_APP_KEY { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } + +#define DELAY K_SECONDS(180) + +char data[] = {'h', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'l', 'd'}; + +static void downlink_info(uint8_t port, bool data_pending, int16_t rssi, int8_t snr, + uint8_t len, const uint8_t *data) +{ + LOG_INF("Received from port %d, pending %d, RSSI %ddB, SNR %ddBm", + port, data_pending, rssi, snr); + if (data) { + LOG_HEXDUMP_INF(data, len, "Payload: "); + } +} + +static void datarate_changed(enum lorawan_datarate dr) +{ + uint8_t unused, max_size; + + lorawan_get_payload_sizes(&unused, &max_size); + LOG_INF("New Datarate: DR %d, Max Payload %d", dr, max_size); +} + +static void fuota_finished(void) +{ + LOG_INF("FUOTA finished. Reset device to apply firmware upgrade."); + + /* + * In an actual application the firmware should be rebooted here if + * no important tasks are pending + */ +} + +int main(void) +{ + const struct device *lora_dev; + struct lorawan_join_config join_cfg; + uint8_t dev_eui[] = LORAWAN_DEV_EUI; + uint8_t join_eui[] = LORAWAN_JOIN_EUI; + uint8_t app_key[] = LORAWAN_APP_KEY; + int ret; + + struct lorawan_downlink_cb downlink_cb = { + .port = LW_RECV_PORT_ANY, + .cb = downlink_info + }; + + lora_dev = DEVICE_DT_GET(DT_ALIAS(lora0)); + if (!device_is_ready(lora_dev)) { + LOG_ERR("%s: device not ready.", lora_dev->name); + return -ENODEV; + } + + ret = lorawan_start(); + if (ret < 0) { + LOG_ERR("lorawan_start failed: %d", ret); + return ret; + } + + lorawan_register_downlink_callback(&downlink_cb); + lorawan_register_dr_changed_callback(datarate_changed); + + join_cfg.mode = LORAWAN_ACT_OTAA; + join_cfg.dev_eui = dev_eui; + join_cfg.otaa.join_eui = join_eui; + join_cfg.otaa.app_key = app_key; + join_cfg.otaa.nwk_key = app_key; + + LOG_INF("Joining network over OTAA"); + ret = lorawan_join(&join_cfg); + if (ret < 0) { + LOG_ERR("lorawan_join_network failed: %d", ret); + return ret; + } + + lorawan_enable_adr(true); + + /* + * Clock synchronization is required to schedule the multicast session + * in class C mode. It can also be used independent of FUOTA. + */ + lorawan_clock_sync_run(); + + /* + * The multicast session setup service is automatically started in the + * background. It is also responsible for switching to class C at a + * specified time. + */ + + /* + * The fragmented data transport transfers the actual firmware image. + * It could also be used in a class A session, but would take very long + * in that case. + */ + lorawan_frag_transport_run(fuota_finished); + + /* + * Regular uplinks are required to open downlink slots in class A for + * FUOTA setup by the server. + */ + while (1) { + ret = lorawan_send(2, data, sizeof(data), LORAWAN_MSG_UNCONFIRMED); + if (ret == 0) { + LOG_INF("Hello World sent!"); + } else { + LOG_ERR("lorawan_send failed: %d", ret); + } + + k_sleep(DELAY); + } + + return 0; +} diff --git a/samples/application_development/sysbuild/with_mcuboot/sysbuild.conf b/samples/subsys/lorawan/fuota/sysbuild.conf similarity index 100% rename from samples/application_development/sysbuild/with_mcuboot/sysbuild.conf rename to samples/subsys/lorawan/fuota/sysbuild.conf diff --git a/samples/subsys/lorawan/fuota/sysbuild/mcuboot.conf b/samples/subsys/lorawan/fuota/sysbuild/mcuboot.conf new file mode 100644 index 00000000000..c1f6021fbdb --- /dev/null +++ b/samples/subsys/lorawan/fuota/sysbuild/mcuboot.conf @@ -0,0 +1,4 @@ +# Kconfig changes when building sample with MCUboot using sysbuild. + +CONFIG_MCUBOOT_LOG_LEVEL_INF=y +CONFIG_MCUBOOT_IMG_MANAGER=y diff --git a/samples/subsys/mgmt/hawkbit/CMakeLists.txt b/samples/subsys/mgmt/hawkbit/CMakeLists.txt index 8fff29c67c3..1c48c7fe888 100644 --- a/samples/subsys/mgmt/hawkbit/CMakeLists.txt +++ b/samples/subsys/mgmt/hawkbit/CMakeLists.txt @@ -10,9 +10,7 @@ set(KCONFIG_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/Kconfig) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(hawkbit) -FILE(GLOB app_sources src/*.c) -target_sources(app PRIVATE ${app_sources}) -target_sources_ifdef(CONFIG_NET_DHCPV4 app PRIVATE src/dhcp.c) +target_sources(app PRIVATE src/main.c) include(${ZEPHYR_BASE}/samples/net/common/common.cmake) diff --git a/samples/subsys/mgmt/hawkbit/README.rst b/samples/subsys/mgmt/hawkbit/README.rst index b674b89a815..969fcc7f506 100644 --- a/samples/subsys/mgmt/hawkbit/README.rst +++ b/samples/subsys/mgmt/hawkbit/README.rst @@ -86,29 +86,24 @@ hawkBit can be built for the :ref:`Freedom-K64F ` as follows: :conf: "prj.conf" :goals: build -.. _hawkbit_sample_sign: - -Step 5: Sign and confirm the first image -======================================== - -From this section onwards you use a binary (``.bin``) image format. +If you want to build it with the ability to set the hawkBit server address +and port during runtime, you can use the following command: -.. code-block:: console +.. zephyr-app-commands:: + :zephyr-app: samples/subsys/mgmt/hawkbit + :board: frdm_k64f + :conf: "prj.conf overlay-runtime.conf" + :goals: build - west sign -t imgtool -- --key \ - ~/zephyrproject/bootloader/mcuboot/root-rsa-2048.pem --confirm \ - --version 1.0.0 +.. _hawkbit_sample_sign: -The command above creates a signed and confirmed image file called -:file:`zephyr.signed.confirmed.bin` in the build directory. It's important for -the first image to be confirmed as MCUboot isn't able to confirm an image that -is flashed using a hardware tool, and hawkBit will reboot to trigger a firmware -swap if it isn't able to confirm the running image on init. +The firmware will be signed automatically by the build system with the +``root-rsa-2048.pem`` key. The key is located in the MCUboot repository. -Step 6: Flash the first image +Step 5: Flash the first image ============================= -Upload the :file:`zephyr.signed.confirmed.bin` file from Step 5 to image slot-0 +Upload the :file:`zephyr.signed.confirmed.bin` file to image slot-0 of your board. .. code-block:: console @@ -120,22 +115,13 @@ time to the console. After it connects to the internet, in hawkbit server UI, you should see the ``frdm_k64f`` show up in the Targets pane. It's time to upload a firmware binary to the server, and update it using this UI. -Step 7: Building and signing the test image +Step 6: Building and signing the test image =========================================== The easiest way to test the functionality of hawkBit is to repeat step 4 to -build the sample again, so that the build time will be different. Then, similar -to step 5, sign the image and assign it a different version number but without -confirming it like so: +build the sample again, so that the build time will be different. -.. code-block:: console - - west sign -t imgtool -- --key \ - ~/zephyrproject/bootloader/mcuboot/root-rsa-2048.pem \ - --version 1.0.1 - -The command above creates a signed image file called -:file:`zephyr.signed.bin` in the build directory. +This time you need the file :file:`zephyr.signed.bin` from the build directory. Upload the signed image to the server. Click Upload icon in left pane of UI and create a new Software Module with type Apps (``name:hawkbit,version:1.0.1``). @@ -147,7 +133,7 @@ hawkBit software module to the created distribution. Click on Deployment icon in the left pane of UI and assign the ``frdm_k64f_update`` distribution to the target ``frdm_k64f``. -Step 8: Run the update +Step 7: Run the update ====================== Back in the terminal session that you used for debugging the board, type the @@ -159,24 +145,14 @@ following command: And then wait. The board will ping the server, check if there are any new updates, and then download the update you've just created. If everything goes -fine the message ``Image flashed successfully, you can reboot now`` will be -printed on the terminal. - -Step 9: Reboot the system -========================= - -In the terminal you used for debugging the board, type the following command: +fine the message ``Update installed`` will be printed on the terminal. -.. code-block:: console - - kernel reboot cold - -Your board will reboot and then start with the new image. After rebooting, the +Your board will reboot automatically and then start with the new image. After rebooting, the board will print a different image build time then automatically ping the server -again and the message ``No update available`` will be printed on the terminal. +again and the message ``Image is already updated`` will be printed on the terminal. -Step 10: Clone and build hawkbit with https -=========================================== +Step 8: Clone and build hawkbit with https +========================================== Below steps clone and build the hawkbit with self-signed certificate to support https. @@ -278,8 +254,8 @@ Change authentication security from false to true. java -jar ./hawkbit-runtime/hawkbit-update-server/target/ \ hawkbit-update-server-#version#-SNAPSHOT.jar -Step 11: Build hawkBit HTTPS -============================ +Step 9: Build hawkBit HTTPS +=========================== * Convert the server.pem file to self_sign.der and place the der file in hawkbit/src directory @@ -292,4 +268,4 @@ Step 11: Build hawkBit HTTPS :conf: "prj.conf overlay-tls.conf" :goals: build -Repeat the steps from 5 to 9, to update the device over https. +Repeat the steps from 5 to 7, to update the device over https. diff --git a/samples/subsys/mgmt/hawkbit/overlay-runtime.conf b/samples/subsys/mgmt/hawkbit/overlay-runtime.conf new file mode 100644 index 00000000000..2b1b004c71f --- /dev/null +++ b/samples/subsys/mgmt/hawkbit/overlay-runtime.conf @@ -0,0 +1 @@ +CONFIG_HAWKBIT_SET_SETTINGS_RUNTIME=y diff --git a/samples/subsys/mgmt/hawkbit/overlay-tls.conf b/samples/subsys/mgmt/hawkbit/overlay-tls.conf index e2b6db68494..c550fcbb89d 100644 --- a/samples/subsys/mgmt/hawkbit/overlay-tls.conf +++ b/samples/subsys/mgmt/hawkbit/overlay-tls.conf @@ -8,3 +8,4 @@ CONFIG_MBEDTLS_HEAP_SIZE=60000 CONFIG_MBEDTLS_SSL_MAX_CONTENT_LEN=16384 CONFIG_NET_SOCKETS_SOCKOPT_TLS=y +CONFIG_HAWKBIT_USE_TLS=y diff --git a/samples/subsys/mgmt/hawkbit/prj.conf b/samples/subsys/mgmt/hawkbit/prj.conf index 9c2362964cc..a47b5275f89 100644 --- a/samples/subsys/mgmt/hawkbit/prj.conf +++ b/samples/subsys/mgmt/hawkbit/prj.conf @@ -14,6 +14,10 @@ CONFIG_HTTP_CLIENT=y CONFIG_DNS_RESOLVER=y CONFIG_JSON_LIBRARY=y CONFIG_BOOTLOADER_MCUBOOT=y +CONFIG_SETTINGS=y +CONFIG_MCUBOOT_GENERATE_UNSIGNED_IMAGE=n +CONFIG_MCUBOOT_GENERATE_CONFIRMED_IMAGE=y +CONFIG_MCUBOOT_SIGNATURE_KEY_FILE="./bootloader/mcuboot/root-rsa-2048.pem" #Main Stack Size CONFIG_MAIN_STACK_SIZE=4096 @@ -22,6 +26,9 @@ CONFIG_MAIN_STACK_SIZE=4096 CONFIG_HEAP_MEM_POOL_SIZE=4096 CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=4096 +CONFIG_NET_CONFIG_SETTINGS=y +CONFIG_NET_CONFIG_NEED_IPV4=y + CONFIG_NET_IPV4=y CONFIG_NET_IPV6=n @@ -58,3 +65,6 @@ CONFIG_LOG_BUFFER_SIZE=4096 #Generate HEX output CONFIG_BUILD_OUTPUT_HEX=y + +#Use custom attributes for hawkBit +CONFIG_HAWKBIT_CUSTOM_ATTRIBUTES=y diff --git a/samples/subsys/mgmt/hawkbit/sample.yaml b/samples/subsys/mgmt/hawkbit/sample.yaml index 9644d620d52..4a7bf0db6c7 100644 --- a/samples/subsys/mgmt/hawkbit/sample.yaml +++ b/samples/subsys/mgmt/hawkbit/sample.yaml @@ -29,4 +29,8 @@ tests: - CONFIG_HAWKBIT_DDI_SECURITY_TOKEN="abcd1234" sample.net.hawkbit.tls: extra_configs: + - CONFIG_HAWKBIT_USE_TLS=y - CONFIG_NET_SOCKETS_SOCKOPT_TLS=y + sample.net.hawkbit.set_settings_runtime: + extra_configs: + - CONFIG_HAWKBIT_SET_SETTINGS_RUNTIME=y diff --git a/samples/subsys/mgmt/hawkbit/src/dhcp.c b/samples/subsys/mgmt/hawkbit/src/dhcp.c deleted file mode 100644 index b8dae6357a3..00000000000 --- a/samples/subsys/mgmt/hawkbit/src/dhcp.c +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2020 Linumiz - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include - -#include - -#include -#include -#include -#include - -static struct net_mgmt_event_callback mgmt_cb; - -/* Semaphore to indicate a lease has been acquired */ -static K_SEM_DEFINE(got_address, 0, 1); - -static void handler(struct net_mgmt_event_callback *cb, - uint32_t mgmt_event, - struct net_if *iface) -{ - bool notified = false; - - if (mgmt_event != NET_EVENT_IPV4_DHCP_BOUND) { - return; - } - - if (!notified) { - k_sem_give(&got_address); - notified = true; - } -} - -/** - * Start a DHCP client, and wait for a lease to be acquired. - */ -void app_dhcpv4_startup(void) -{ - struct net_if *iface; - - net_mgmt_init_event_callback(&mgmt_cb, handler, - NET_EVENT_IPV4_DHCP_BOUND); - net_mgmt_add_event_callback(&mgmt_cb); - - iface = net_if_get_default(); - - net_dhcpv4_start(iface); - - /* Wait for a lease */ - k_sem_take(&got_address, K_FOREVER); -} diff --git a/samples/subsys/mgmt/hawkbit/src/dhcp.h b/samples/subsys/mgmt/hawkbit/src/dhcp.h deleted file mode 100644 index db670869391..00000000000 --- a/samples/subsys/mgmt/hawkbit/src/dhcp.h +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright (c) 2020 Linumiz - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef __DHCP_H__ -#define __DHCP_H__ - -void app_dhcpv4_startup(void); - -#endif diff --git a/samples/subsys/mgmt/hawkbit/src/main.c b/samples/subsys/mgmt/hawkbit/src/main.c index 3e917f614a4..b8323b308a1 100644 --- a/samples/subsys/mgmt/hawkbit/src/main.c +++ b/samples/subsys/mgmt/hawkbit/src/main.c @@ -10,8 +10,7 @@ #include #include #include - -#include "dhcp.h" +#include #if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS) #include @@ -20,6 +19,40 @@ LOG_MODULE_REGISTER(main); +#ifdef CONFIG_HAWKBIT_CUSTOM_ATTRIBUTES +struct hawkbit_cfg_data { + const char *VIN; + const char *customAttr; +}; + +struct hawkbit_cfg { + const char *mode; + struct hawkbit_cfg_data data; +}; + +static const struct json_obj_descr json_cfg_data_descr[] = { + JSON_OBJ_DESCR_PRIM(struct hawkbit_cfg_data, VIN, JSON_TOK_STRING), + JSON_OBJ_DESCR_PRIM(struct hawkbit_cfg_data, customAttr, JSON_TOK_STRING), +}; + +static const struct json_obj_descr json_cfg_descr[] = { + JSON_OBJ_DESCR_PRIM(struct hawkbit_cfg, mode, JSON_TOK_STRING), + JSON_OBJ_DESCR_OBJECT(struct hawkbit_cfg, data, json_cfg_data_descr), +}; + +int hawkbit_new_config_data_cb(const char *device_id, uint8_t *buffer, const size_t buffer_size) +{ + struct hawkbit_cfg cfg = { + .mode = "merge", + .data.VIN = device_id, + .data.customAttr = "Hello World!", + }; + + return json_obj_encode_buf(json_cfg_descr, ARRAY_SIZE(json_cfg_descr), &cfg, buffer, + buffer_size); +} +#endif /* CONFIG_HAWKBIT_CUSTOM_ATTRIBUTES */ + int main(void) { int ret = -1; @@ -27,19 +60,27 @@ int main(void) LOG_INF("hawkBit sample app started"); LOG_INF("Image build time: " __DATE__ " " __TIME__); - app_dhcpv4_startup(); - #if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS) tls_credential_add(CA_CERTIFICATE_TAG, TLS_CREDENTIAL_CA_CERTIFICATE, ca_certificate, sizeof(ca_certificate)); #endif +#ifdef CONFIG_HAWKBIT_CUSTOM_ATTRIBUTES + ret = hawkbit_set_custom_data_cb(hawkbit_new_config_data_cb); + if (ret < 0) { + LOG_ERR("Failed to set custom data callback"); + } +#endif /* CONFIG_HAWKBIT_CUSTOM_ATTRIBUTES */ ret = hawkbit_init(); - if (ret < 0) { LOG_ERR("Failed to init hawkBit"); } +#ifdef CONFIG_HAWKBIT_SET_SETTINGS_RUNTIME + hawkbit_set_server_addr(CONFIG_HAWKBIT_SERVER); + hawkbit_set_server_port(CONFIG_HAWKBIT_PORT); +#endif + #if defined(CONFIG_HAWKBIT_POLLING) LOG_INF("Starting hawkBit polling mode"); hawkbit_autohandler(); diff --git a/samples/subsys/mgmt/mcumgr/smp_svr/src/bluetooth.c b/samples/subsys/mgmt/mcumgr/smp_svr/src/bluetooth.c index fa8e49ce351..7503c48a7fb 100644 --- a/samples/subsys/mgmt/mcumgr/smp_svr/src/bluetooth.c +++ b/samples/subsys/mgmt/mcumgr/smp_svr/src/bluetooth.c @@ -23,13 +23,17 @@ static const struct bt_data ad[] = { 0xd3, 0x4c, 0xb7, 0x1d, 0x1d, 0xdc, 0x53, 0x8d), }; +static const struct bt_data sd[] = { + BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1), +}; + static void advertise(struct k_work *work) { int rc; bt_le_adv_stop(); - rc = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0); + rc = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd)); if (rc) { LOG_ERR("Advertising failed to start (rc %d)", rc); return; diff --git a/samples/subsys/mgmt/updatehub/README.rst b/samples/subsys/mgmt/updatehub/README.rst index f502e1a1795..ab646da39d6 100644 --- a/samples/subsys/mgmt/updatehub/README.rst +++ b/samples/subsys/mgmt/updatehub/README.rst @@ -34,7 +34,7 @@ Caveats application should build and run for other platforms with same connectivity. * The sample provides overlay files to enable other technologies like WIFI, - modem, BLE IPSP, 802.15.4 or OpenThread. These technologies depends on + modem, 802.15.4 or OpenThread. These technologies depends on hardware resources and the correspondent overlay was designed to be generic instead full optimized. @@ -242,25 +242,6 @@ tested with both native linux driver and ``atusb`` and with ``wpanusb`` sample. :goals: build :compact: -Step 4.5: Build for BLE IPSP [experimental] -------------------------------------------- - -The BLE IPSP needs ``overlay-ipsp.conf``. This may requires two nodes: -one will be the host and the second one will be the device under test. The -validation needs a Linux kernel >= 4.9 with all 6loWPAN support. In this -particular case the Bluetooth 6LoWPAN module is needed. The start point is try -reproduce the Zephyr :ref:`bluetooth-ipsp-sample`. It is out of scope -at this moment provide support since it is experimental. The gateway was -tested with native linux driver and an USB dongle. - -.. zephyr-app-commands:: - :zephyr-app: zephyr/samples/subsys/mgmt/updatehub - :board: nrf52840dk/nrf52840 - :build-dir: app - :gen-args: -DEXTRA_CONF_FILE="overlay-ipsp.conf;overlay-prj.conf" - :goals: build - :compact: - Step 4.6: Build for OpenThread Network [experimental] ----------------------------------------------------- @@ -482,7 +463,6 @@ The below list of hardware have been used by UpdateHub team. 3, "MODEM (PPP)", "SIMCOM 808" 4, "IEEE 802.15.4 (6loWPAN)", "Native, :ref:`RF2XX `" - 5, "BLE IPSP (6loWPAN)", Native 6, "OpenThread Network", Native .. csv-table:: diff --git a/samples/subsys/mgmt/updatehub/overlay-802154.conf b/samples/subsys/mgmt/updatehub/overlay-802154.conf index 0af13d78c26..05820f8800f 100644 --- a/samples/subsys/mgmt/updatehub/overlay-802154.conf +++ b/samples/subsys/mgmt/updatehub/overlay-802154.conf @@ -1,5 +1,5 @@ # Copyright (c) 2020 O.S.Systems -# SPDX -License-Identifier: Apache-2.0 +# SPDX-License-Identifier: Apache-2.0 # Disable default configs CONFIG_BT=n diff --git a/samples/subsys/mgmt/updatehub/overlay-ipsp.conf b/samples/subsys/mgmt/updatehub/overlay-ipsp.conf deleted file mode 100644 index bc3cf342fa3..00000000000 --- a/samples/subsys/mgmt/updatehub/overlay-ipsp.conf +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright (c) 2020 O.S.Systems -# SPDX -License-Identifier: Apache-2.0 - -# Disable default configs -CONFIG_NET_L2_IEEE802154=n - -CONFIG_NET_IPV4=n -CONFIG_NET_DHCPV4=n -CONFIG_NET_TCP=n - -# Enable Bluetooth LE IPSP -CONFIG_BT=y -CONFIG_BT_SMP=y -CONFIG_BT_PERIPHERAL=y -CONFIG_BT_CENTRAL=y -CONFIG_BT_L2CAP_DYNAMIC_CHANNEL=y -CONFIG_BT_DEVICE_NAME="UpdateHub - IPSP" - -CONFIG_NET_CONFIG_BT_NODE=y -CONFIG_NET_CONFIG_AUTO_INIT=y - -CONFIG_NET_L2_BT=y -CONFIG_NET_L2_BT_SHELL=y - -CONFIG_NET_IPV6=y -CONFIG_NET_IPV6_FRAGMENT=y -CONFIG_NET_6LO_CONTEXT=y -CONFIG_NET_MAX_6LO_CONTEXTS=10 - -CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=3 -CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=2 -CONFIG_NET_MAX_CONTEXTS=10 - -CONFIG_NET_UDP=y - -# Add DNS Server -CONFIG_DNS_SERVER_IP_ADDRESSES=y -CONFIG_DNS_SERVER1="2001:de8::1" - -# UpdateHub -CONFIG_UPDATEHUB_SERVER="2001:de8::1" -CONFIG_UPDATEHUB_COAP_BLOCK_SIZE_EXP=2 diff --git a/samples/subsys/mgmt/updatehub/overlay-ot.conf b/samples/subsys/mgmt/updatehub/overlay-ot.conf index d425f950a31..cfd0742469e 100644 --- a/samples/subsys/mgmt/updatehub/overlay-ot.conf +++ b/samples/subsys/mgmt/updatehub/overlay-ot.conf @@ -1,5 +1,5 @@ # Copyright (c) 2020 O.S.Systems -# SPDX -License-Identifier: Apache-2.0 +# SPDX-License-Identifier: Apache-2.0 # Disable default configs CONFIG_BT=n diff --git a/samples/subsys/mgmt/updatehub/overlay-wifi.conf b/samples/subsys/mgmt/updatehub/overlay-wifi.conf index de1fc9b8616..4d3b3b9cf31 100644 --- a/samples/subsys/mgmt/updatehub/overlay-wifi.conf +++ b/samples/subsys/mgmt/updatehub/overlay-wifi.conf @@ -1,5 +1,5 @@ # Copyright (c) 2020 O.S.Systems -# SPDX -License-Identifier: Apache-2.0 +# SPDX-License-Identifier: Apache-2.0 # Disable default configs CONFIG_NET_L2_ETHERNET=n diff --git a/samples/subsys/mgmt/updatehub/prj.conf b/samples/subsys/mgmt/updatehub/prj.conf index 0ea9be14f7a..98a20203bdf 100644 --- a/samples/subsys/mgmt/updatehub/prj.conf +++ b/samples/subsys/mgmt/updatehub/prj.conf @@ -1,5 +1,5 @@ # Copyright (c) 2018-2020 O.S.Systems -# SPDX -License-Identifier: Apache-2.0 +# SPDX-License-Identifier: Apache-2.0 CONFIG_FLASH=y CONFIG_STREAM_FLASH=y CONFIG_FLASH_MAP=y @@ -44,3 +44,5 @@ CONFIG_NET_SHELL=y # Debug helpers CONFIG_LOG=y #CONFIG_UPDATEHUB_LOG_LEVEL_DBG=y + +CONFIG_MAX_THREAD_BYTES=3 diff --git a/samples/subsys/settings/boards/esp32s3_devkitm.conf b/samples/subsys/settings/boards/esp32s3_devkitm_procpu.conf similarity index 100% rename from samples/subsys/settings/boards/esp32s3_devkitm.conf rename to samples/subsys/settings/boards/esp32s3_devkitm_procpu.conf diff --git a/samples/subsys/settings/boards/esp32s3_luatos_core.conf b/samples/subsys/settings/boards/esp32s3_luatos_core_procpu.conf similarity index 100% rename from samples/subsys/settings/boards/esp32s3_luatos_core.conf rename to samples/subsys/settings/boards/esp32s3_luatos_core_procpu.conf diff --git a/samples/subsys/settings/boards/esp32s3_luatos_core_esp32s3_procpu_usb.conf b/samples/subsys/settings/boards/esp32s3_luatos_core_procpu_usb.conf similarity index 100% rename from samples/subsys/settings/boards/esp32s3_luatos_core_esp32s3_procpu_usb.conf rename to samples/subsys/settings/boards/esp32s3_luatos_core_procpu_usb.conf diff --git a/samples/subsys/settings/boards/native_posix_native_64.conf b/samples/subsys/settings/boards/native_posix_native_64.conf new file mode 100644 index 00000000000..21877f886f3 --- /dev/null +++ b/samples/subsys/settings/boards/native_posix_native_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_posix_native_64.overlay b/samples/subsys/settings/boards/native_posix_native_64.overlay new file mode 100644 index 00000000000..9fe8b9c2160 --- /dev/null +++ b/samples/subsys/settings/boards/native_posix_native_64.overlay @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "native_posix.overlay" diff --git a/samples/subsys/settings/boards/native_sim_native_64.conf b/samples/subsys/settings/boards/native_sim_native_64.conf new file mode 100644 index 00000000000..21877f886f3 --- /dev/null +++ b/samples/subsys/settings/boards/native_sim_native_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_native_64.overlay b/samples/subsys/settings/boards/native_sim_native_64.overlay new file mode 100644 index 00000000000..e4994493dd6 --- /dev/null +++ b/samples/subsys/settings/boards/native_sim_native_64.overlay @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "native_sim.overlay" diff --git a/samples/subsys/settings/boards/yd_esp32.conf b/samples/subsys/settings/boards/yd_esp32_procpu.conf similarity index 100% rename from samples/subsys/settings/boards/yd_esp32.conf rename to samples/subsys/settings/boards/yd_esp32_procpu.conf 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 b96ff81fe83..f05bf210213 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 @@ -5,9 +5,6 @@ CONFIG_HEAP_MEM_POOL_SIZE=16384 CONFIG_SHELL_STACK_SIZE=8192 -# Setting the Shell prompt -CONFIG_SHELL_PROMPT_UART="agilex5$ " - # Setting the max argc CONFIG_SHELL_ARGC_MAX=12 diff --git a/samples/subsys/shell/shell_module/boards/intel_socfpga_agilex_socdk.conf b/samples/subsys/shell/shell_module/boards/intel_socfpga_agilex_socdk.conf index 22a3788b1b8..bc86125f5d5 100644 --- a/samples/subsys/shell/shell_module/boards/intel_socfpga_agilex_socdk.conf +++ b/samples/subsys/shell/shell_module/boards/intel_socfpga_agilex_socdk.conf @@ -5,9 +5,6 @@ CONFIG_HEAP_MEM_POOL_SIZE=16384 CONFIG_SHELL_STACK_SIZE=8192 -# Setting the Shell prompt -CONFIG_SHELL_PROMPT_UART="agilex$ " - # Setting the max argc CONFIG_SHELL_ARGC_MAX=12 diff --git a/samples/subsys/shell/shell_module/overlay-usb.conf b/samples/subsys/shell/shell_module/overlay-usb.conf index 60249a6e52c..692287e23a1 100644 --- a/samples/subsys/shell/shell_module/overlay-usb.conf +++ b/samples/subsys/shell/shell_module/overlay-usb.conf @@ -2,5 +2,10 @@ CONFIG_USB_DEVICE_STACK=y CONFIG_USB_DEVICE_PRODUCT="Zephyr USB shell sample" CONFIG_SHELL_BACKEND_SERIAL_CHECK_DTR=y CONFIG_UART_LINE_CTRL=y -CONFIG_SHELL_BACKEND_SERIAL_INIT_PRIORITY=51 CONFIG_USB_DEVICE_INITIALIZE_AT_BOOT=n + +# POSIX_CLOCK requires an embedded C library while the native USB driver is incompatible with it. +# So let's disable it. Once USB_NATIVE_POSIX supports embedded C libraries this can be removed. +CONFIG_POSIX_CLOCK=n +# DATE_SHELL requires POSIX_CLOCK +CONFIG_DATE_SHELL=n diff --git a/samples/subsys/smf/hsm_psicc2/CMakeLists.txt b/samples/subsys/smf/hsm_psicc2/CMakeLists.txt new file mode 100644 index 00000000000..86586364114 --- /dev/null +++ b/samples/subsys/smf/hsm_psicc2/CMakeLists.txt @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(smf_hsm_psicc2) + +target_sources(app PRIVATE + src/main.c + src/hsm_psicc2_console_cmds.c + src/hsm_psicc2_thread.c +) diff --git a/samples/subsys/smf/hsm_psicc2/README.rst b/samples/subsys/smf/hsm_psicc2/README.rst new file mode 100644 index 00000000000..0b79cbb540c --- /dev/null +++ b/samples/subsys/smf/hsm_psicc2/README.rst @@ -0,0 +1,51 @@ +.. zephyr:code-sample:: smf_hsm_psicc2 + :name: Hierarchical State Machine Demo based on example from PSiCC2 + :relevant-api: smf + + Implement an event-driven hierarchical state machine using State Machine Framework (SMF). + +Overview +******** + +This sample demonstrates the :ref:`State Machine Framework ` subsystem. + +Building and Running +******************** + +It should be possible to build and run this sample on almost any board or emulator. + +Building and Running for ST Disco L475 IOT01 (B-L475E-IOT01A) +============================================================= +The sample can be built and executed for the :ref:`disco_l475_iot1_board` as follows: + +.. zephyr-app-commands:: + :zephyr-app: samples/subsys/smf/psicc2 + :board: disco_l475_iot1 + :goals: build flash + :compact: + +For other boards just replace the board name. + +Instructions for Use +==================== +This application implements the statechart shown in Figure 2.11 of +Practical UML Statecharts in C/C++, 2nd Edition, by Miro Samek (PSiCC2). Ebook available from +https://www.state-machine.com/psicc2 This demo was chosen as it contains all possible transition +topologies up to four levels of state nesting and is used with permission of the author. + +For each state, the entry, run, and exit actions are logged to the console, as well as logging +when a state handles an event, or explicitly ignores it and passes it up to the parent state. + +There are two shell commands defined for controlling the operation. + +* ``psicc2 event `` sends the event (from A to I) to the state machine. These correspond to + events A through I in PSiCC2 Figure 2.11 +* ``psicc2 terminate`` sends the ``EVENT_TERMINATE`` event to terminate the state machine. There + is no way to restart the state machine once terminated, and future events are ignored. + +Comparison to PSiCC2 Output +=========================== +Not all transitions modelled in UML may be supported by the :ref:`State Machine Framework `. +Unsupported transitions may lead to results different to the example run of the application in +PSiCC2 Section 2.3.15. The differences will not be listed here as it is hoped :ref:`SMF ` +will support these transitions in the future and the list would become outdated. diff --git a/samples/subsys/smf/hsm_psicc2/prj.conf b/samples/subsys/smf/hsm_psicc2/prj.conf new file mode 100644 index 00000000000..e2104b03a27 --- /dev/null +++ b/samples/subsys/smf/hsm_psicc2/prj.conf @@ -0,0 +1,11 @@ +CONFIG_LOG=y +CONFIG_SHELL=y + +# Needed for boards that enable RTT backends for logging +# e.g. nrf52840dk/nrf52840 and any others that enable it +CONFIG_LOG_BACKEND_RTT=n + +# Enable the state machine framework +CONFIG_SMF=y +CONFIG_SMF_ANCESTOR_SUPPORT=y +CONFIG_SMF_INITIAL_TRANSITION=y diff --git a/samples/subsys/smf/hsm_psicc2/sample.yaml b/samples/subsys/smf/hsm_psicc2/sample.yaml new file mode 100644 index 00000000000..ae32b7594af --- /dev/null +++ b/samples/subsys/smf/hsm_psicc2/sample.yaml @@ -0,0 +1,19 @@ +sample: + name: SMF HSM PSiCC2 Demo +common: + tags: + - smf + integration_platforms: + - native_sim + harness: console + harness_config: + type: multi_line + ordered: true + regex: + - ".* hsm_psicc2_thread: initial_entry.*" + - ".* hsm_psicc2_thread: s_entry.*" + - ".* hsm_psicc2_thread: s2_entry.*" + - ".* hsm_psicc2_thread: s21_entry.*" + - ".* hsm_psicc2_thread: s211_entry.*" +tests: + sample.smf.hsm_psicc2: {} diff --git a/samples/subsys/smf/hsm_psicc2/src/hsm_psicc2_console_cmds.c b/samples/subsys/smf/hsm_psicc2/src/hsm_psicc2_console_cmds.c new file mode 100644 index 00000000000..9e5e1ab82b7 --- /dev/null +++ b/samples/subsys/smf/hsm_psicc2/src/hsm_psicc2_console_cmds.c @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2023 Glenn Andrews + * State Machine example copyright (c) Miro Samek + * + * Implementation of the statechart in Figure 2.11 of + * Practical UML Statecharts in C/C++, 2nd Edition by Miro Samek + * https://www.state-machine.com/psicc2 + * Used with permission of the author. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "hsm_psicc2_thread.h" +#include +#include + +static int cmd_hsm_psicc2_event(const struct shell *sh, size_t argc, char **argv) +{ + struct hsm_psicc2_event event; + int event_id = toupper(argv[1][0]); + + switch (event_id) { + case 'A': + event.event_id = EVENT_A; + break; + case 'B': + event.event_id = EVENT_B; + break; + case 'C': + event.event_id = EVENT_C; + break; + case 'D': + event.event_id = EVENT_D; + break; + case 'E': + event.event_id = EVENT_E; + break; + case 'F': + event.event_id = EVENT_F; + break; + case 'G': + event.event_id = EVENT_G; + break; + case 'H': + event.event_id = EVENT_H; + break; + case 'I': + event.event_id = EVENT_I; + break; + default: + shell_error(sh, "Invalid argument %s", argv[1]); + return -1; + } + + int rc = k_msgq_put(&hsm_psicc2_msgq, &event, K_NO_WAIT); + + if (rc == 0) { + shell_print(sh, "Event %c posted", event_id); + } else { + shell_error(sh, "error posting event: %d", rc); + } + return rc; +} + +static int cmd_hsm_psicc2_terminate(const struct shell *sh, size_t argc, char **argv) +{ + struct hsm_psicc2_event event = {.event_id = EVENT_TERMINATE}; + int rc = k_msgq_put(&hsm_psicc2_msgq, &event, K_NO_WAIT); + + if (rc == 0) { + shell_print(sh, "Terminate event posted"); + } else { + shell_error(sh, "error posting terminate event: %d", rc); + } + return rc; +} + +/* Creating subcommands (level 1 command) array for command "demo". */ +SHELL_STATIC_SUBCMD_SET_CREATE(sub_hsm_psicc2, + SHELL_CMD_ARG(event, NULL, "Send event to State Machine", + cmd_hsm_psicc2_event, 2, 0), + SHELL_CMD_ARG(terminate, NULL, + "Send terminate event to State Machine", + cmd_hsm_psicc2_terminate, 1, 0), + SHELL_SUBCMD_SET_END); + +/* Creating root (level 0) command "demo" */ +SHELL_CMD_REGISTER(hsm_psicc2, &sub_hsm_psicc2, "PSICC2 demo hierarchical state machine commands", + NULL); diff --git a/samples/subsys/smf/hsm_psicc2/src/hsm_psicc2_thread.c b/samples/subsys/smf/hsm_psicc2/src/hsm_psicc2_thread.c new file mode 100644 index 00000000000..4a1118754d8 --- /dev/null +++ b/samples/subsys/smf/hsm_psicc2/src/hsm_psicc2_thread.c @@ -0,0 +1,336 @@ +/* + * Copyright (c) 2024 Glenn Andrews + * State Machine example copyright (c) Miro Samek + * + * Implementation of the statechart in Figure 2.11 of + * Practical UML Statecharts in C/C++, 2nd Edition by Miro Samek + * https://www.state-machine.com/psicc2 + * Used with permission of the author. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include "hsm_psicc2_thread.h" +#include + +LOG_MODULE_REGISTER(hsm_psicc2_thread); + +/* User defined object */ +struct s_object { + /* This must be first */ + struct smf_ctx ctx; + + /* Other state specific data add here */ + struct hsm_psicc2_event event; + int foo; +} s_obj; + +/* Declaration of possible states */ +enum demo_states { + STATE_INITIAL, + STATE_S, + STATE_S1, + STATE_S2, + STATE_S11, + STATE_S21, + STATE_S211, +}; + +/* Forward declaration of state table */ +static const struct smf_state demo_states[]; + +/********* STATE_INITIAL *********/ +static void initial_entry(void *o) +{ + LOG_INF("%s", __func__); + struct s_object *obj = (struct s_object *)o; + + obj->foo = false; +} + +static void initial_run(void *o) +{ + LOG_INF("%s", __func__); +} + +static void initial_exit(void *o) +{ + LOG_INF("%s", __func__); +} + +/********* STATE_S *********/ +static void s_entry(void *o) +{ + LOG_INF("%s", __func__); +} + +static void s_run(void *o) +{ + LOG_INF("%s", __func__); + struct s_object *obj = (struct s_object *)o; + + switch (obj->event.event_id) { + case EVENT_E: + LOG_INF("%s received EVENT_E", __func__); + smf_set_state(SMF_CTX(obj), &demo_states[STATE_S11]); + break; + case EVENT_I: + if (obj->foo) { + LOG_INF("%s received EVENT_I and set foo false", __func__); + obj->foo = false; + } else { + LOG_INF("%s received EVENT_I and did nothing", __func__); + } + smf_set_handled(SMF_CTX(obj)); + break; + case EVENT_TERMINATE: + LOG_INF("%s received SMF_EVENT_TERMINATE. Terminating", __func__); + smf_set_terminate(SMF_CTX(obj), -1); + } +} + +static void s_exit(void *o) +{ + LOG_INF("%s", __func__); +} + +/********* STATE_S1 *********/ +static void s1_entry(void *o) +{ + LOG_INF("%s", __func__); +} + +static void s1_run(void *o) +{ + LOG_INF("%s", __func__); + struct s_object *obj = (struct s_object *)o; + + switch (obj->event.event_id) { + case EVENT_A: + LOG_INF("%s received EVENT_A", __func__); + smf_set_state(SMF_CTX(obj), &demo_states[STATE_S1]); + break; + case EVENT_B: + LOG_INF("%s received EVENT_B", __func__); + smf_set_state(SMF_CTX(obj), &demo_states[STATE_S11]); + break; + case EVENT_C: + LOG_INF("%s received EVENT_C", __func__); + smf_set_state(SMF_CTX(obj), &demo_states[STATE_S2]); + break; + case EVENT_D: + if (!obj->foo) { + LOG_INF("%s received EVENT_D and acted on it", __func__); + obj->foo = true; + smf_set_state(SMF_CTX(obj), &demo_states[STATE_S]); + } else { + LOG_INF("%s received EVENT_D and ignored it", __func__); + } + break; + case EVENT_F: + LOG_INF("%s received EVENT_F", __func__); + smf_set_state(SMF_CTX(obj), &demo_states[STATE_S211]); + break; + case EVENT_I: + LOG_INF("%s received EVENT_I", __func__); + smf_set_handled(SMF_CTX(obj)); + break; + } +} + +static void s1_exit(void *o) +{ + LOG_INF("%s", __func__); +} + +/********* STATE_S11 *********/ +static void s11_entry(void *o) +{ + LOG_INF("%s", __func__); +} + +static void s11_run(void *o) +{ + LOG_INF("%s", __func__); + struct s_object *obj = (struct s_object *)o; + + switch (obj->event.event_id) { + case EVENT_D: + if (obj->foo) { + LOG_INF("%s received EVENT_D and acted upon it", __func__); + obj->foo = false; + smf_set_state(SMF_CTX(obj), &demo_states[STATE_S1]); + } else { + LOG_INF("%s received EVENT_D and ignored it", __func__); + } + break; + case EVENT_G: + LOG_INF("%s received EVENT_G", __func__); + smf_set_state(SMF_CTX(obj), &demo_states[STATE_S21]); + break; + case EVENT_H: + LOG_INF("%s received EVENT_H", __func__); + smf_set_state(SMF_CTX(obj), &demo_states[STATE_S]); + break; + } +} + +static void s11_exit(void *o) +{ + LOG_INF("%s", __func__); +} + +/********* STATE_S2 *********/ +static void s2_entry(void *o) +{ + LOG_INF("%s", __func__); +} + +static void s2_run(void *o) +{ + LOG_INF("%s", __func__); + struct s_object *obj = (struct s_object *)o; + + switch (obj->event.event_id) { + case EVENT_C: + LOG_INF("%s received EVENT_C", __func__); + smf_set_state(SMF_CTX(obj), &demo_states[STATE_S1]); + break; + case EVENT_F: + LOG_INF("%s received EVENT_F", __func__); + smf_set_state(SMF_CTX(obj), &demo_states[STATE_S11]); + break; + case EVENT_I: + if (!obj->foo) { + LOG_INF("%s received EVENT_I and set foo true", __func__); + obj->foo = true; + smf_set_handled(SMF_CTX(obj)); + } else { + LOG_INF("%s received EVENT_I and did nothing", __func__); + } + break; + } +} + +static void s2_exit(void *o) +{ + LOG_INF("%s", __func__); +} + +/********* STATE_S21 *********/ +static void s21_entry(void *o) +{ + LOG_INF("%s", __func__); +} + +static void s21_run(void *o) +{ + LOG_INF("%s", __func__); + struct s_object *obj = (struct s_object *)o; + + switch (obj->event.event_id) { + case EVENT_A: + LOG_INF("%s received EVENT_A", __func__); + smf_set_state(SMF_CTX(obj), &demo_states[STATE_S21]); + break; + case EVENT_B: + LOG_INF("%s received EVENT_B", __func__); + smf_set_state(SMF_CTX(obj), &demo_states[STATE_S211]); + break; + case EVENT_G: + LOG_INF("%s received EVENT_G", __func__); + smf_set_state(SMF_CTX(obj), &demo_states[STATE_S1]); + break; + } +} + +static void s21_exit(void *o) +{ + LOG_INF("%s", __func__); +} + +/********* STATE_S211 *********/ +static void s211_entry(void *o) +{ + LOG_INF("%s", __func__); +} + +static void s211_run(void *o) +{ + LOG_INF("%s", __func__); + struct s_object *obj = (struct s_object *)o; + + switch (obj->event.event_id) { + case EVENT_D: + LOG_INF("%s received EVENT_D", __func__); + smf_set_state(SMF_CTX(obj), &demo_states[STATE_S21]); + break; + case EVENT_H: + LOG_INF("%s received EVENT_H", __func__); + smf_set_state(SMF_CTX(obj), &demo_states[STATE_S]); + break; + } +} + +static void s211_exit(void *o) +{ + LOG_INF("%s", __func__); +} + +/* State storage: handler functions, parent states and initial transition states */ +static const struct smf_state demo_states[] = { + [STATE_INITIAL] = SMF_CREATE_STATE(initial_entry, initial_run, initial_exit, NULL, + &demo_states[STATE_S2]), + [STATE_S] = SMF_CREATE_STATE(s_entry, s_run, s_exit, &demo_states[STATE_INITIAL], + &demo_states[STATE_S11]), + [STATE_S1] = SMF_CREATE_STATE(s1_entry, s1_run, s1_exit, &demo_states[STATE_S], + &demo_states[STATE_S11]), + [STATE_S2] = SMF_CREATE_STATE(s2_entry, s2_run, s2_exit, &demo_states[STATE_S], + &demo_states[STATE_S211]), + [STATE_S11] = SMF_CREATE_STATE(s11_entry, s11_run, s11_exit, &demo_states[STATE_S1], NULL), + [STATE_S21] = SMF_CREATE_STATE(s21_entry, s21_run, s21_exit, &demo_states[STATE_S2], + &demo_states[STATE_S211]), + [STATE_S211] = + SMF_CREATE_STATE(s211_entry, s211_run, s211_exit, &demo_states[STATE_S21], NULL), +}; + +K_THREAD_STACK_DEFINE(hsm_psicc2_thread_stack, HSM_PSICC2_THREAD_STACK_SIZE); +K_MSGQ_DEFINE(hsm_psicc2_msgq, sizeof(struct hsm_psicc2_event), HSM_PSICC2_THREAD_EVENT_QUEUE_SIZE, + 1); + +static struct k_thread hsm_psicc2_thread_data; +static k_tid_t hsm_psicc2_thread_tid; + +static void hsm_psicc2_thread(void *arg1, void *arg2, void *arg3) +{ + smf_set_initial(SMF_CTX(&s_obj), &demo_states[STATE_INITIAL]); + while (1) { + int rc = k_msgq_get(&hsm_psicc2_msgq, &s_obj.event, K_FOREVER); + + if (rc == 0) { + /* Run state machine with given message */ + rc = smf_run_state(SMF_CTX(&s_obj)); + + if (rc) { + /* State machine terminates if a non-zero value is returned */ + LOG_INF("%s terminating state machine thread", __func__); + break; + } + } else { + LOG_ERR("Waiting for event failed, code %d", rc); + } + } +} + +void hsm_psicc2_thread_run(void) +{ + hsm_psicc2_thread_tid = + k_thread_create(&hsm_psicc2_thread_data, hsm_psicc2_thread_stack, + K_THREAD_STACK_SIZEOF(hsm_psicc2_thread_stack), hsm_psicc2_thread, + NULL, NULL, NULL, HSM_PSICC2_THREAD_PRIORITY, 0, K_NO_WAIT); + + k_thread_name_set(hsm_psicc2_thread_tid, "psicc2_thread"); +} diff --git a/samples/subsys/smf/hsm_psicc2/src/hsm_psicc2_thread.h b/samples/subsys/smf/hsm_psicc2/src/hsm_psicc2_thread.h new file mode 100644 index 00000000000..e22588dbd67 --- /dev/null +++ b/samples/subsys/smf/hsm_psicc2/src/hsm_psicc2_thread.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2024 Glenn Andrews + * State Machine example copyright (c) Miro Samek + * + * Implementation of the statechart in Figure 2.11 of + * Practical UML Statecharts in C/C++, 2nd Edition by Miro Samek + * https://www.state-machine.com/psicc2 + * Used with permission of the author. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _HSM_PSICC2_THREAD_H +#define _HSM_PSICC2_THREAD_H + +#define HSM_PSICC2_THREAD_STACK_SIZE 1024 +#define HSM_PSICC2_THREAD_PRIORITY 7 +#define HSM_PSICC2_THREAD_EVENT_QUEUE_SIZE 10 + +/** + * @brief Event to be sent to an event queue + */ +struct hsm_psicc2_event { + uint32_t event_id; +}; + +/** + * @brief List of events that can be sent to the state machine + */ +enum demo_events { + EVENT_A, + EVENT_B, + EVENT_C, + EVENT_D, + EVENT_E, + EVENT_F, + EVENT_G, + EVENT_H, + EVENT_I, + EVENT_TERMINATE, +}; + +/* event queue to post messages to */ +extern struct k_msgq hsm_psicc2_msgq; + +/** + * @brief Initializes and starts the PSICC2 demo thread + * @param None + */ +void hsm_psicc2_thread_run(void); + +#endif /* _HSM_PSICC2_THREAD_H */ diff --git a/samples/subsys/smf/hsm_psicc2/src/main.c b/samples/subsys/smf/hsm_psicc2/src/main.c new file mode 100644 index 00000000000..0612e180342 --- /dev/null +++ b/samples/subsys/smf/hsm_psicc2/src/main.c @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2024 Glenn Andrews + * State Machine example copyright (c) Miro Samek + * + * Implementation of the statechart in Figure 2.11 of + * Practical UML Statecharts in C/C++, 2nd Edition by Miro Samek + * https://www.state-machine.com/psicc2 + * Used with permission of the author. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "hsm_psicc2_thread.h" + +int main(void) +{ + printk("State Machine Framework Demo\n"); + printk("See PSiCC2 Fig 2.11 for the statechart\n"); + printk("https://www.state-machine.com/psicc2\n\n"); + hsm_psicc2_thread_run(); + return 0; +} diff --git a/samples/subsys/smf/smf.rst b/samples/subsys/smf/smf.rst new file mode 100644 index 00000000000..bc48258b99f --- /dev/null +++ b/samples/subsys/smf/smf.rst @@ -0,0 +1,10 @@ +.. _smf-samples: + +State Machine Framework Samples +############################### + +.. toctree:: + :maxdepth: 1 + :glob: + + **/* diff --git a/samples/subsys/usb/cdc_acm/nucleo_f413zh_dwc2.overlay b/samples/subsys/usb/cdc_acm/nucleo_f413zh_dwc2.overlay index 8cd2525699c..d1e6b29edbd 100644 --- a/samples/subsys/usb/cdc_acm/nucleo_f413zh_dwc2.overlay +++ b/samples/subsys/usb/cdc_acm/nucleo_f413zh_dwc2.overlay @@ -15,6 +15,11 @@ interrupt-names = "fsotg"; clocks = <&rcc STM32_CLOCK_BUS_AHB2 0x00000080>, <&rcc STM32_SRC_PLL_Q NO_SEL>; + num-out-eps = <6>; + num-in-eps = <6>; + ghwcfg1 = <0x00000000>; + ghwcfg2 = <0x229ed520>; + ghwcfg4 = <0x17f08030>; status = "disabled"; }; }; diff --git a/samples/subsys/usb/cdc_acm/sample.yaml b/samples/subsys/usb/cdc_acm/sample.yaml index 85dc6b7af27..82365c1f245 100644 --- a/samples/subsys/usb/cdc_acm/sample.yaml +++ b/samples/subsys/usb/cdc_acm/sample.yaml @@ -16,6 +16,7 @@ tests: extra_args: CONF_FILE="usbd_next_prj.conf" platform_allow: - nrf52840dk/nrf52840 + - nrf54h20dk/nrf54h20/cpuapp - frdm_k64f - 96b_carbon/stm32f401xe harness: console diff --git a/samples/subsys/usb/cdc_acm/src/main.c b/samples/subsys/usb/cdc_acm/src/main.c index 41cc248aa6b..91f7a8db7f7 100644 --- a/samples/subsys/usb/cdc_acm/src/main.c +++ b/samples/subsys/usb/cdc_acm/src/main.c @@ -52,10 +52,24 @@ static inline void print_baudrate(const struct device *dev) static struct usbd_contex *sample_usbd; K_SEM_DEFINE(dtr_sem, 0, 1); -static void sample_msg_cb(const struct usbd_msg *msg) +static void sample_msg_cb(struct usbd_contex *const ctx, const struct usbd_msg *msg) { LOG_INF("USBD message: %s", usbd_msg_type_string(msg->type)); + if (usbd_can_detect_vbus(ctx)) { + if (msg->type == USBD_MSG_VBUS_READY) { + if (usbd_enable(ctx)) { + LOG_ERR("Failed to enable device support"); + } + } + + if (msg->type == USBD_MSG_VBUS_REMOVED) { + if (usbd_disable(ctx)) { + LOG_ERR("Failed to disable device support"); + } + } + } + if (msg->type == USBD_MSG_CDC_ACM_CONTROL_LINE_STATE) { uint32_t dtr = 0U; @@ -80,13 +94,15 @@ static int enable_usb_device_next(void) return -ENODEV; } - err = usbd_enable(sample_usbd); - if (err) { - LOG_ERR("Failed to enable device support"); - return err; + if (!usbd_can_detect_vbus(sample_usbd)) { + err = usbd_enable(sample_usbd); + if (err) { + LOG_ERR("Failed to enable device support"); + return err; + } } - LOG_DBG("USB device support enabled"); + LOG_INF("USB device support enabled"); return 0; } diff --git a/samples/subsys/usb/cdc_acm/usbd_next_prj.conf b/samples/subsys/usb/cdc_acm/usbd_next_prj.conf index c5147519f87..f08928438b7 100644 --- a/samples/subsys/usb/cdc_acm/usbd_next_prj.conf +++ b/samples/subsys/usb/cdc_acm/usbd_next_prj.conf @@ -8,6 +8,7 @@ CONFIG_USBD_CDC_ACM_CLASS=y CONFIG_LOG=y CONFIG_USBD_LOG_LEVEL_WRN=y CONFIG_UDC_DRIVER_LOG_LEVEL_WRN=y +CONFIG_USBD_CDC_ACM_LOG_LEVEL_ERR=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 index 1d330c2ad08..765fc69bf21 100644 --- a/samples/subsys/usb/common/Kconfig.sample_usbd +++ b/samples/subsys/usb/common/Kconfig.sample_usbd @@ -45,4 +45,9 @@ config SAMPLE_USBD_MAX_POWER help bMaxPower value in the sample configuration in 2 mA units. +config SAMPLE_USBD_20_EXTENSION_DESC + bool "Use default USB 2.0 Extension Descriptor" + help + Set bcdUSB value to 0201 and use default USB 2.0 Extension Descriptor. + endmenu diff --git a/samples/subsys/usb/common/sample_usbd_init.c b/samples/subsys/usb/common/sample_usbd_init.c index 8343ccaae3b..1a712819c57 100644 --- a/samples/subsys/usb/common/sample_usbd_init.c +++ b/samples/subsys/usb/common/sample_usbd_init.c @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -22,17 +23,114 @@ USBD_DEVICE_DEFINE(sample_usbd, 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"); +USBD_DESC_SERIAL_NUMBER_DEFINE(sample_sn); 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, +USBD_CONFIGURATION_DEFINE(sample_fs_config, attributes, CONFIG_SAMPLE_USBD_MAX_POWER); +USBD_CONFIGURATION_DEFINE(sample_hs_config, + attributes, + CONFIG_SAMPLE_USBD_MAX_POWER); + +/* + * This does not yet provide valuable information, but rather serves as an + * example, and will be improved in the future. + */ +static const struct usb_bos_capability_lpm bos_cap_lpm = { + .bLength = sizeof(struct usb_bos_capability_lpm), + .bDescriptorType = USB_DESC_DEVICE_CAPABILITY, + .bDevCapabilityType = USB_BOS_CAPABILITY_EXTENSION, + .bmAttributes = 0UL, +}; + +USBD_DESC_BOS_DEFINE(sample_usbext, sizeof(bos_cap_lpm), &bos_cap_lpm); + +static int register_fs_classes(struct usbd_contex *uds_ctx) +{ + int err = 0; + + STRUCT_SECTION_FOREACH_ALTERNATE(usbd_class_fs, usbd_class_node, c_nd) { + /* Pull everything that is enabled in our configuration. */ + err = usbd_register_class(uds_ctx, c_nd->c_data->name, + USBD_SPEED_FS, 1); + if (err) { + LOG_ERR("Failed to register FS %s (%d)", + c_nd->c_data->name, err); + return err; + } + + LOG_DBG("Register FS %s", c_nd->c_data->name); + } + + return err; +} + +static int register_hs_classes(struct usbd_contex *uds_ctx) +{ + int err = 0; + + STRUCT_SECTION_FOREACH_ALTERNATE(usbd_class_hs, usbd_class_node, c_nd) { + /* Pull everything that is enabled in our configuration. */ + err = usbd_register_class(uds_ctx, c_nd->c_data->name, + USBD_SPEED_HS, 1); + if (err) { + LOG_ERR("Failed to register HS %s (%d)", + c_nd->c_data->name, err); + return err; + } + + LOG_DBG("Register HS %s", c_nd->c_data->name); + } + + return err; +} + +static int sample_add_configuration(struct usbd_contex *uds_ctx, + const enum usbd_speed speed, + struct usbd_config_node *config) +{ + int err; + + err = usbd_add_configuration(uds_ctx, speed, config); + if (err) { + LOG_ERR("Failed to add configuration (%d)", err); + return err; + } + + if (speed == USBD_SPEED_FS) { + err = register_fs_classes(uds_ctx); + } else if (speed == USBD_SPEED_HS) { + err = register_hs_classes(uds_ctx); + } + + if (err) { + return err; + } + + /* Always use class code information from Interface Descriptors */ + if (IS_ENABLED(CONFIG_USBD_CDC_ACM_CLASS) || + IS_ENABLED(CONFIG_USBD_CDC_ECM_CLASS) || + IS_ENABLED(CONFIG_USBD_AUDIO2_CLASS)) { + /* + * Class with multiple interfaces have an Interface + * Association Descriptor available, use an appropriate triple + * to indicate it. + */ + usbd_device_set_code_triple(uds_ctx, speed, + USB_BCC_MISCELLANEOUS, 0x02, 0x01); + } else { + usbd_device_set_code_triple(uds_ctx, speed, 0, 0, 0); + } + + return 0; +} + struct usbd_contex *sample_usbd_init_device(usbd_msg_cb_t msg_cb) { int err; @@ -61,36 +159,20 @@ struct usbd_contex *sample_usbd_init_device(usbd_msg_cb_t msg_cb) 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 (usbd_caps_speed(&sample_usbd) == USBD_SPEED_HS) { + err = sample_add_configuration(&sample_usbd, USBD_SPEED_HS, + &sample_hs_config); if (err) { - LOG_ERR("Failed to register %s (%d)", node->name, err); + LOG_ERR("Failed to add High-Speed configuration"); return NULL; } - - LOG_DBG("Register %s", node->name); } - /* Always use class code information from Interface Descriptors */ - if (IS_ENABLED(CONFIG_USBD_CDC_ACM_CLASS) || - IS_ENABLED(CONFIG_USBD_CDC_ECM_CLASS) || - IS_ENABLED(CONFIG_USBD_AUDIO2_CLASS)) { - /* - * Class with multiple interfaces have an Interface - * Association Descriptor available, use an appropriate triple - * to indicate it. - */ - usbd_device_set_code_triple(&sample_usbd, - USB_BCC_MISCELLANEOUS, 0x02, 0x01); - } else { - usbd_device_set_code_triple(&sample_usbd, 0, 0, 0); + err = sample_add_configuration(&sample_usbd, USBD_SPEED_FS, + &sample_fs_config); + if (err) { + LOG_ERR("Failed to add Full-Speed configuration"); + return NULL; } if (msg_cb != NULL) { @@ -101,6 +183,17 @@ struct usbd_contex *sample_usbd_init_device(usbd_msg_cb_t msg_cb) } } + if (IS_ENABLED(CONFIG_SAMPLE_USBD_20_EXTENSION_DESC)) { + (void)usbd_device_set_bcd(&sample_usbd, USBD_SPEED_FS, 0x0201); + (void)usbd_device_set_bcd(&sample_usbd, USBD_SPEED_HS, 0x0201); + + err = usbd_add_descriptor(&sample_usbd, &sample_usbext); + if (err) { + LOG_ERR("Failed to add USB 2.0 Extension Descriptor"); + return NULL; + } + } + err = usbd_init(&sample_usbd); if (err) { LOG_ERR("Failed to initialize device support"); diff --git a/samples/subsys/usb/hid-keyboard/CMakeLists.txt b/samples/subsys/usb/hid-keyboard/CMakeLists.txt new file mode 100644 index 00000000000..76d18842cff --- /dev/null +++ b/samples/subsys/usb/hid-keyboard/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(hid-keyboard) + +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/hid-keyboard/Kconfig b/samples/subsys/usb/hid-keyboard/Kconfig new file mode 100644 index 00000000000..96c54558948 --- /dev/null +++ b/samples/subsys/usb/hid-keyboard/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/hid-keyboard/README.rst b/samples/subsys/usb/hid-keyboard/README.rst new file mode 100644 index 00000000000..b1936b55588 --- /dev/null +++ b/samples/subsys/usb/hid-keyboard/README.rst @@ -0,0 +1,36 @@ +.. zephyr:code-sample:: usb-hid-keyboard + :name: USB HID keyboard + :relevant-api: usbd_api usbd_hid_class input_interface + + Implement a basic HID keyboard device. + +Overview +******** + +This sample application demonstrates the HID keyboard implementation using the +new experimental USB device stack. + +Requirements +************ + +This project requires an experimental USB device driver (UDC API) and uses the +:ref:`input` API. There must be a :dtcompatible:`gpio-keys` group of buttons +or keys defined at the board level that can generate input events. +At least one key is required and up to four can be used. The first three keys +are used for Num Lock, Caps Lock and Scroll Lock. The fourth key is used to +report HID keys 1, 2, 3 and the right Alt modifier at once. + +The example can use up to three LEDs, configured via the devicetree alias such +as ``led0``, to indicate the state of the keyboard LEDs. + +Building and Running +******************** + +This sample can be built for multiple boards, in this example we will build it +for the nRF52840DK board: + +.. zephyr-app-commands:: + :zephyr-app: samples/subsys/usb/hid-keyboard + :board: nrf52840dk/nrf52840 + :goals: build flash + :compact: diff --git a/samples/subsys/usb/hid-keyboard/app.overlay b/samples/subsys/usb/hid-keyboard/app.overlay new file mode 100644 index 00000000000..6433abbe706 --- /dev/null +++ b/samples/subsys/usb/hid-keyboard/app.overlay @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + hid_dev_0: hid_dev_0 { + compatible = "zephyr,hid-device"; + interface-name = "HID0"; + protocol-code = "keyboard"; + in-report-size = <64>; + in-polling-rate = <1000>; + }; +}; diff --git a/samples/subsys/usb/hid-keyboard/large_in_report.overlay b/samples/subsys/usb/hid-keyboard/large_in_report.overlay new file mode 100644 index 00000000000..2eb82c5df61 --- /dev/null +++ b/samples/subsys/usb/hid-keyboard/large_in_report.overlay @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + hid_dev_0: hid_dev_0 { + compatible = "zephyr,hid-device"; + interface-name = "HID0"; + in-report-size = <256>; + in-polling-rate = <1000>; + }; +}; diff --git a/samples/subsys/usb/hid-keyboard/large_out_report.overlay b/samples/subsys/usb/hid-keyboard/large_out_report.overlay new file mode 100644 index 00000000000..16b02a9efb0 --- /dev/null +++ b/samples/subsys/usb/hid-keyboard/large_out_report.overlay @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "large_in_report.overlay" + +/ { + hid_dev_0: hid_dev_0 { + compatible = "zephyr,hid-device"; + out-report-size = <128>; + out-polling-rate = <16000>; + }; +}; diff --git a/samples/subsys/usb/hid-keyboard/out_report.overlay b/samples/subsys/usb/hid-keyboard/out_report.overlay new file mode 100644 index 00000000000..bcd776622e8 --- /dev/null +++ b/samples/subsys/usb/hid-keyboard/out_report.overlay @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "app.overlay" + +/ { + hid_dev_0: hid_dev_0 { + compatible = "zephyr,hid-device"; + out-report-size = <64>; + out-polling-rate = <16000>; + }; +}; diff --git a/samples/subsys/usb/hid-keyboard/prj.conf b/samples/subsys/usb/hid-keyboard/prj.conf new file mode 100644 index 00000000000..04ce14ad588 --- /dev/null +++ b/samples/subsys/usb/hid-keyboard/prj.conf @@ -0,0 +1,12 @@ +CONFIG_USB_DEVICE_STACK_NEXT=y +CONFIG_USBD_HID_SUPPORT=y + +CONFIG_LOG=y +CONFIG_USBD_LOG_LEVEL_WRN=y +CONFIG_USBD_HID_LOG_LEVEL_WRN=y +CONFIG_UDC_DRIVER_LOG_LEVEL_WRN=y +CONFIG_SAMPLE_USBD_PID=0x0007 + +CONFIG_GPIO=y +CONFIG_INPUT=y +CONFIG_INPUT_MODE_SYNCHRONOUS=y diff --git a/samples/subsys/usb/hid-keyboard/sample.yaml b/samples/subsys/usb/hid-keyboard/sample.yaml new file mode 100644 index 00000000000..726608009ba --- /dev/null +++ b/samples/subsys/usb/hid-keyboard/sample.yaml @@ -0,0 +1,27 @@ +sample: + name: USB HID keyboard sample +common: + harness: button + filter: dt_alias_exists("sw0") and dt_alias_exists("led0") + depends_on: + - usb_device + - gpio + platform_allow: + - nrf52840dk/nrf52840 + - nrf54h20dk/nrf54h20/cpuapp + - frdm_k64f +tests: + sample.usbd.hid-keyboard: + tags: usb + sample.usbd.hid-keyboard.out-report: + tags: usb + extra_args: + - EXTRA_DTC_OVERLAY_FILE="out_report.overlay" + sample.usbd.hid-keyboard.large-report: + tags: usb + extra_args: + - EXTRA_DTC_OVERLAY_FILE="large_in_report.overlay" + sample.usbd.hid-keyboard.large-out-report: + tags: usb + extra_args: + - EXTRA_DTC_OVERLAY_FILE="large_out_report.overlay" diff --git a/samples/subsys/usb/hid-keyboard/src/main.c b/samples/subsys/usb/hid-keyboard/src/main.c new file mode 100644 index 00000000000..1a2a146a5a9 --- /dev/null +++ b/samples/subsys/usb/hid-keyboard/src/main.c @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include +#include +#include + +#include +#include + +#include +LOG_MODULE_REGISTER(main, LOG_LEVEL_INF); + +static const uint8_t hid_report_desc[] = HID_KEYBOARD_REPORT_DESC(); + +enum kb_leds_idx { + KB_LED_NUMLOCK = 0, + KB_LED_CAPSLOCK, + KB_LED_SCROLLLOCK, + KB_LED_COUNT, +}; + +static const struct gpio_dt_spec kb_leds[KB_LED_COUNT] = { + GPIO_DT_SPEC_GET_OR(DT_ALIAS(led0), gpios, {0}), + GPIO_DT_SPEC_GET_OR(DT_ALIAS(led1), gpios, {0}), + GPIO_DT_SPEC_GET_OR(DT_ALIAS(led2), gpios, {0}), +}; + +enum kb_report_idx { + KB_MOD_KEY = 0, + KB_RESERVED, + KB_KEY_CODE1, + KB_KEY_CODE2, + KB_KEY_CODE3, + KB_KEY_CODE4, + KB_KEY_CODE5, + KB_KEY_CODE6, + KB_REPORT_COUNT, +}; + +struct kb_event { + uint16_t code; + int32_t value; +}; + +K_MSGQ_DEFINE(kb_msgq, sizeof(struct kb_event), 2, 1); + +static uint8_t __aligned(sizeof(void *)) report[KB_REPORT_COUNT]; +static uint32_t kb_duration; +static bool kb_ready; + +static void input_cb(struct input_event *evt) +{ + struct kb_event kb_evt; + + kb_evt.code = evt->code; + kb_evt.value = evt->value; + if (k_msgq_put(&kb_msgq, &kb_evt, K_NO_WAIT) != 0) { + LOG_ERR("Failed to put new input event"); + } +} + +INPUT_CALLBACK_DEFINE(NULL, input_cb); + +static void kb_iface_ready(const struct device *dev, const bool ready) +{ + LOG_INF("HID device %s interface is %s", + dev->name, ready ? "ready" : "not ready"); + kb_ready = ready; +} + +static int kb_get_report(const struct device *dev, + const uint8_t type, const uint8_t id, const uint16_t len, + uint8_t *const buf) +{ + LOG_WRN("Get Report not implemented, Type %u ID %u", type, id); + + return 0; +} + +static int kb_set_report(const struct device *dev, + const uint8_t type, const uint8_t id, const uint16_t len, + const uint8_t *const buf) +{ + if (type != HID_REPORT_TYPE_OUTPUT) { + LOG_WRN("Unsupported report type"); + return -ENOTSUP; + } + + for (unsigned int i = 0; i < ARRAY_SIZE(kb_leds); i++) { + if (kb_leds[i].port == NULL) { + continue; + } + + (void)gpio_pin_set_dt(&kb_leds[i], buf[0] & BIT(i)); + } + + return 0; +} + +/* Idle duration is stored but not used to calculate idle reports. */ +static void kb_set_idle(const struct device *dev, + const uint8_t id, const uint32_t duration) +{ + LOG_INF("Set Idle %u to %u", id, duration); + kb_duration = duration; +} + +static uint32_t kb_get_idle(const struct device *dev, const uint8_t id) +{ + LOG_INF("Get Idle %u to %u", id, kb_duration); + return kb_duration; +} + +static void kb_set_protocol(const struct device *dev, const uint8_t proto) +{ + LOG_INF("Protocol changed to %s", + proto == 0U ? "Boot Protocol" : "Report Protocol"); +} + +static void kb_output_report(const struct device *dev, const uint16_t len, + const uint8_t *const buf) +{ + LOG_HEXDUMP_DBG(buf, len, "o.r."); + kb_set_report(dev, HID_REPORT_TYPE_OUTPUT, 0U, len, buf); +} + +struct hid_device_ops kb_ops = { + .iface_ready = kb_iface_ready, + .get_report = kb_get_report, + .set_report = kb_set_report, + .set_idle = kb_set_idle, + .get_idle = kb_get_idle, + .set_protocol = kb_set_protocol, + .output_report = kb_output_report, +}; + +int main(void) +{ + struct usbd_contex *sample_usbd; + const struct device *hid_dev; + int ret; + + for (unsigned int i = 0; i < ARRAY_SIZE(kb_leds); i++) { + if (kb_leds[i].port == NULL) { + continue; + } + + if (!gpio_is_ready_dt(&kb_leds[i])) { + LOG_ERR("LED device %s is not ready", kb_leds[i].port->name); + return -EIO; + } + + ret = gpio_pin_configure_dt(&kb_leds[i], GPIO_OUTPUT_INACTIVE); + if (ret != 0) { + LOG_ERR("Failed to configure the LED pin, %d", ret); + return -EIO; + } + } + + hid_dev = DEVICE_DT_GET_ONE(zephyr_hid_device); + if (!device_is_ready(hid_dev)) { + LOG_ERR("HID Device is not ready"); + return -EIO; + } + + ret = hid_device_register(hid_dev, + hid_report_desc, sizeof(hid_report_desc), + &kb_ops); + if (ret != 0) { + LOG_ERR("Failed to register HID Device, %d", ret); + return ret; + } + + sample_usbd = sample_usbd_init_device(NULL); + if (sample_usbd == NULL) { + LOG_ERR("Failed to initialize USB device"); + return -ENODEV; + } + + ret = usbd_enable(sample_usbd); + if (ret) { + LOG_ERR("Failed to enable device support"); + return ret; + } + + LOG_INF("HID keyboard sample is initialized"); + + while (true) { + struct kb_event kb_evt; + + k_msgq_get(&kb_msgq, &kb_evt, K_FOREVER); + + switch (kb_evt.code) { + case INPUT_KEY_0: + if (kb_evt.value) { + report[KB_KEY_CODE1] = HID_KEY_NUMLOCK; + } else { + report[KB_KEY_CODE1] = 0; + } + + break; + case INPUT_KEY_1: + if (kb_evt.value) { + report[KB_KEY_CODE2] = HID_KEY_CAPSLOCK; + } else { + report[KB_KEY_CODE2] = 0; + } + + break; + case INPUT_KEY_2: + if (kb_evt.value) { + report[KB_KEY_CODE3] = HID_KEY_SCROLLLOCK; + } else { + report[KB_KEY_CODE3] = 0; + } + + break; + case INPUT_KEY_3: + if (kb_evt.value) { + report[KB_MOD_KEY] = HID_KBD_MODIFIER_RIGHT_ALT; + report[KB_KEY_CODE4] = HID_KEY_1; + report[KB_KEY_CODE5] = HID_KEY_2; + report[KB_KEY_CODE6] = HID_KEY_3; + } else { + report[KB_MOD_KEY] = HID_KBD_MODIFIER_NONE; + report[KB_KEY_CODE4] = 0; + report[KB_KEY_CODE5] = 0; + report[KB_KEY_CODE6] = 0; + } + + break; + default: + LOG_INF("Unrecognized input code %u value %d", + kb_evt.code, kb_evt.value); + continue; + } + + if (!kb_ready) { + LOG_INF("USB HID device is not ready"); + continue; + } + + ret = hid_device_submit_report(hid_dev, sizeof(report), report); + if (ret) { + LOG_ERR("HID submit report error, %d", ret); + } + } + + return 0; +} diff --git a/samples/subsys/usb/hid-mouse/CMakeLists.txt b/samples/subsys/usb/hid-mouse/CMakeLists.txt index d384859f9fc..d2217c00a47 100644 --- a/samples/subsys/usb/hid-mouse/CMakeLists.txt +++ b/samples/subsys/usb/hid-mouse/CMakeLists.txt @@ -4,5 +4,6 @@ cmake_minimum_required(VERSION 3.20.0) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(hid-mouse) +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/hid-mouse/Kconfig b/samples/subsys/usb/hid-mouse/Kconfig new file mode 100644 index 00000000000..96c54558948 --- /dev/null +++ b/samples/subsys/usb/hid-mouse/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/hid-mouse/sample.yaml b/samples/subsys/usb/hid-mouse/sample.yaml index f638fefc58c..77ede76aeb4 100644 --- a/samples/subsys/usb/hid-mouse/sample.yaml +++ b/samples/subsys/usb/hid-mouse/sample.yaml @@ -1,10 +1,22 @@ sample: name: USB HID mouse sample +common: + harness: button + filter: dt_alias_exists("sw0") and dt_alias_exists("led0") + depends_on: + - usb_device + - gpio tests: sample.usb.hid-mouse: - depends_on: - - usb_device - - gpio - harness: button - filter: dt_alias_exists("sw0") and dt_alias_exists("led0") + platform_exclude: + - frdm_mcxn947/mcxn947/cpu0 + tags: usb + sample.usb_device_next.hid-mouse: + platform_allow: + - nrf52840dk/nrf52840 + - nrf54h20dk/nrf54h20/cpuapp + - frdm_k64f + extra_args: + - CONF_FILE="usbd_next_prj.conf" + - EXTRA_DTC_OVERLAY_FILE="usbd_next.overlay" tags: usb diff --git a/samples/subsys/usb/hid-mouse/src/main.c b/samples/subsys/usb/hid-mouse/src/main.c index 6a297418b4c..c42a96ed474 100644 --- a/samples/subsys/usb/hid-mouse/src/main.c +++ b/samples/subsys/usb/hid-mouse/src/main.c @@ -5,6 +5,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include + #include #include @@ -14,6 +16,7 @@ #include #include +#include #include #include @@ -34,10 +37,10 @@ enum mouse_report_idx { MOUSE_REPORT_COUNT = 4, }; -static uint8_t report[MOUSE_REPORT_COUNT]; +static uint8_t __aligned(sizeof(void *)) report[MOUSE_REPORT_COUNT]; static K_SEM_DEFINE(report_sem, 0, 1); -static void status_cb(enum usb_dc_status_code status, const uint8_t *param) +static inline void status_cb(enum usb_dc_status_code status, const uint8_t *param) { usb_status = status; } @@ -93,6 +96,30 @@ static void input_cb(struct input_event *evt) INPUT_CALLBACK_DEFINE(NULL, input_cb); +#if defined(CONFIG_USB_DEVICE_STACK_NEXT) +static int enable_usb_device_next(void) +{ + struct usbd_contex *sample_usbd; + int err; + + sample_usbd = sample_usbd_init_device(NULL); + if (sample_usbd == NULL) { + LOG_ERR("Failed to initialize USB device"); + return -ENODEV; + } + + err = usbd_enable(sample_usbd); + if (err) { + LOG_ERR("Failed to enable device support"); + return err; + } + + LOG_DBG("USB device support enabled"); + + return 0; +} +#endif /* IS_ENABLED(CONFIG_USB_DEVICE_STACK_NEXT) */ + int main(void) { const struct device *hid_dev; @@ -103,7 +130,11 @@ int main(void) return 0; } +#if defined(CONFIG_USB_DEVICE_STACK_NEXT) + hid_dev = DEVICE_DT_GET_ONE(zephyr_hid_device); +#else hid_dev = device_get_binding("HID_0"); +#endif if (hid_dev == NULL) { LOG_ERR("Cannot get USB HID Device"); return 0; @@ -121,7 +152,11 @@ int main(void) usb_hid_init(hid_dev); +#if defined(CONFIG_USB_DEVICE_STACK_NEXT) + ret = enable_usb_device_next(); +#else ret = usb_enable(status_cb); +#endif if (ret != 0) { LOG_ERR("Failed to enable USB"); return 0; diff --git a/samples/subsys/usb/hid-mouse/usbd_next.overlay b/samples/subsys/usb/hid-mouse/usbd_next.overlay new file mode 100644 index 00000000000..8b7b5c51821 --- /dev/null +++ b/samples/subsys/usb/hid-mouse/usbd_next.overlay @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + hid_dev_0: hid_dev_0 { + compatible = "zephyr,hid-device"; + interface-name = "HID0"; + protocol-code = "none"; + in-polling-rate = <1000>; + in-report-size = <64>; + }; +}; diff --git a/samples/subsys/usb/hid-mouse/usbd_next_prj.conf b/samples/subsys/usb/hid-mouse/usbd_next_prj.conf new file mode 100644 index 00000000000..9c8894b2126 --- /dev/null +++ b/samples/subsys/usb/hid-mouse/usbd_next_prj.conf @@ -0,0 +1,11 @@ +CONFIG_USB_DEVICE_STACK_NEXT=y +CONFIG_USBD_HID_SUPPORT=y + +CONFIG_LOG=y +CONFIG_USBD_LOG_LEVEL_WRN=y +CONFIG_USBD_HID_LOG_LEVEL_WRN=y +CONFIG_UDC_DRIVER_LOG_LEVEL_WRN=y +CONFIG_SAMPLE_USBD_PID=0x0007 + +CONFIG_GPIO=y +CONFIG_INPUT=y diff --git a/samples/subsys/usb/mass/sample.yaml b/samples/subsys/usb/mass/sample.yaml index d7c2c32bc59..f2459019ce7 100644 --- a/samples/subsys/usb/mass/sample.yaml +++ b/samples/subsys/usb/mass/sample.yaml @@ -24,6 +24,7 @@ tests: depends_on: usb_device platform_allow: - nrf52840dk/nrf52840 + - nrf54h20dk/nrf54h20/cpuapp - frdm_k64f extra_args: - CONF_FILE="usbd_next_prj.conf" diff --git a/samples/subsys/usb/shell/nucleo_f413zh_dwc2.overlay b/samples/subsys/usb/shell/nucleo_f413zh_dwc2.overlay index ff51b08078e..2e954626ded 100644 --- a/samples/subsys/usb/shell/nucleo_f413zh_dwc2.overlay +++ b/samples/subsys/usb/shell/nucleo_f413zh_dwc2.overlay @@ -15,6 +15,11 @@ interrupt-names = "fsotg"; clocks = <&rcc STM32_CLOCK_BUS_AHB2 0x00000080>, <&rcc STM32_SRC_PLL_Q NO_SEL>; + num-out-eps = <6>; + num-in-eps = <6>; + ghwcfg1 = <0x00000000>; + ghwcfg2 = <0x229ed520>; + ghwcfg4 = <0x17f08030>; }; }; }; diff --git a/samples/subsys/usb/shell/sample.yaml b/samples/subsys/usb/shell/sample.yaml index 834044da3df..246b6133a02 100644 --- a/samples/subsys/usb/shell/sample.yaml +++ b/samples/subsys/usb/shell/sample.yaml @@ -4,6 +4,7 @@ tests: sample.usbd.shell: platform_allow: - nrf52840dk/nrf52840 + - nrf54h20dk/nrf54h20/cpuapp - frdm_k64f depends_on: usb_device harness: keyboard diff --git a/samples/subsys/usb/webusb/src/main.c b/samples/subsys/usb/webusb/src/main.c index 69317465877..77866932e02 100644 --- a/samples/subsys/usb/webusb/src/main.c +++ b/samples/subsys/usb/webusb/src/main.c @@ -164,10 +164,13 @@ USB_DEVICE_BOS_DESC_DEFINE_CAP struct usb_bos_capability_lpm bos_cap_lpm = { .bDescriptorType = USB_DESC_DEVICE_CAPABILITY, .bDevCapabilityType = USB_BOS_CAPABILITY_EXTENSION, /** + * Currently there is not a single device driver in Zephyr that supports + * LPM. Moreover, Zephyr USB stack does not have LPM support, so do not + * falsely claim to support LPM. * BIT(1) - LPM support * BIT(2) - BESL support */ - .bmAttributes = BIT(1) | BIT(2), + .bmAttributes = 0, }; /* WebUSB Device Requests */ diff --git a/samples/subsys/zbus/uart_bridge/boards/native_posix_native_64.conf b/samples/subsys/zbus/uart_bridge/boards/native_posix_native_64.conf new file mode 100644 index 00000000000..b552360756c --- /dev/null +++ b/samples/subsys/zbus/uart_bridge/boards/native_posix_native_64.conf @@ -0,0 +1 @@ +CONFIG_UART_NATIVE_POSIX_PORT_1_ENABLE=y diff --git a/samples/subsys/zbus/uart_bridge/boards/native_sim_native_64.conf b/samples/subsys/zbus/uart_bridge/boards/native_sim_native_64.conf new file mode 100644 index 00000000000..b552360756c --- /dev/null +++ b/samples/subsys/zbus/uart_bridge/boards/native_sim_native_64.conf @@ -0,0 +1 @@ +CONFIG_UART_NATIVE_POSIX_PORT_1_ENABLE=y diff --git a/samples/sysbuild/hello_world/CMakeLists.txt b/samples/sysbuild/hello_world/CMakeLists.txt new file mode 100644 index 00000000000..f58082ab8df --- /dev/null +++ b/samples/sysbuild/hello_world/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) + +project(hello_world) +target_sources(app PRIVATE src/main.c) diff --git a/samples/sysbuild/hello_world/Kconfig.sysbuild b/samples/sysbuild/hello_world/Kconfig.sysbuild new file mode 100644 index 00000000000..edec01b94c9 --- /dev/null +++ b/samples/sysbuild/hello_world/Kconfig.sysbuild @@ -0,0 +1,7 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +source "${ZEPHYR_BASE}/share/sysbuild/Kconfig" + +config REMOTE_BOARD + string "The board used for remote target" diff --git a/samples/sysbuild/hello_world/README.rst b/samples/sysbuild/hello_world/README.rst new file mode 100644 index 00000000000..2cb02082051 --- /dev/null +++ b/samples/sysbuild/hello_world/README.rst @@ -0,0 +1,69 @@ +.. zephyr:code-sample:: sysbuild_hello_world + :name: Hello World for multiple board targets using Sysbuild + + Run a hello world sample on multiple board targets + +Overview +******** + +The sample demonstrates how to build a Hello World application for two board +targets with :ref:`sysbuild`. This sample can be useful to test, for example, +SoCs with multiple cores as each core is exposed as a board target. Other +scenarios could include boards embedding multiple SoCs. When building with +Zephyr Sysbuild, the build system adds additional images based on the options +selected in the project's additional configuration and build files. + +All images use the same :file:`main.c` that prints the board target on which the +application is programmed. + +Building and Running +******************** + +This sample needs to be built with Sysbuild by using the ``--sysbuild`` option. +The remote board needs to be specified using ``SB_CONFIG_REMOTE_BOARD``. Some +additional settings may be required depending on the platform, for example, +to boot a remote core. + +.. note:: + It is recommended to use sample setups from + :zephyr_file:`samples/basic/multitarget_hello_world/sample.yaml` using the + ``-T`` option. + +Here's an example to build and flash the sample for the +:ref:`nrf54h20dk_nrf54h20`, using application and radio cores: + +.. zephyr-app-commands:: + :zephyr-app: samples/basic/multitarget_hello_world + :board: nrf54h20dk/nrf54h20/cpuapp + :west-args: --sysbuild + :gen-args: -DSB_CONFIG_REMOTE_BOARD='"nrf54h20dk/nrf54h20/cpurad"' + :goals: build flash + :compact: + +The same can be achieved by using the +:zephyr_file:`samples/basic/multitarget_hello_world/sample.yaml` setup: + +.. zephyr-app-commands:: + :zephyr-app: samples/basic/multitarget_hello_world + :board: nrf54h20dk/nrf54h20/cpuapp + :west-args: -T sample.basic.multitarget_hello_world.nrf54h20dk_cpuapp_cpurad + :goals: build flash + :compact: + +After programming the sample to your board, you should observe a hello world +message in the Zephyr console configured on each target. For example, for the +sample above: + +Application core + + .. code-block:: console + + *** Booting Zephyr OS build v3.6.0-274-g466084bd8c5d *** + Hello world from nrf54h20dk/nrf54h20/cpuapp + +Radio core + + .. code-block:: console + + *** Booting Zephyr OS build v3.6.0-274-g466084bd8c5d *** + Hello world from nrf54h20dk/nrf54h20/cpurad diff --git a/samples/sysbuild/hello_world/boards/nrf5340dk_nrf5340_cpuapp.conf b/samples/sysbuild/hello_world/boards/nrf5340dk_nrf5340_cpuapp.conf new file mode 100644 index 00000000000..046b18c7559 --- /dev/null +++ b/samples/sysbuild/hello_world/boards/nrf5340dk_nrf5340_cpuapp.conf @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_BOARD_ENABLE_CPUNET=y diff --git a/samples/sysbuild/hello_world/prj.conf b/samples/sysbuild/hello_world/prj.conf new file mode 100644 index 00000000000..becd6a54819 --- /dev/null +++ b/samples/sysbuild/hello_world/prj.conf @@ -0,0 +1 @@ +# no additional configuration is required diff --git a/samples/sysbuild/hello_world/remote/CMakeLists.txt b/samples/sysbuild/hello_world/remote/CMakeLists.txt new file mode 100644 index 00000000000..62961aff184 --- /dev/null +++ b/samples/sysbuild/hello_world/remote/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) + +project(remote) +target_sources(app PRIVATE ../src/main.c) diff --git a/samples/sysbuild/hello_world/remote/prj.conf b/samples/sysbuild/hello_world/remote/prj.conf new file mode 100644 index 00000000000..becd6a54819 --- /dev/null +++ b/samples/sysbuild/hello_world/remote/prj.conf @@ -0,0 +1 @@ +# no additional configuration is required diff --git a/samples/sysbuild/hello_world/sample.yaml b/samples/sysbuild/hello_world/sample.yaml new file mode 100644 index 00000000000..5add79c52ba --- /dev/null +++ b/samples/sysbuild/hello_world/sample.yaml @@ -0,0 +1,44 @@ +sample: + name: Hello World for multiple board targets using Sysbuild + description: | + Hello World application that builds for multiple targets. Both images print + the board target they were run on. + +common: + build_only: true + sysbuild: true + +tests: + sample.sysbuild.hello_world.nrf5340dk_cpuapp_cpunet: + platform_allow: + - nrf5340dk/nrf5340/cpuapp + integration_platforms: + - nrf5340dk/nrf5340/cpuapp + extra_args: + SB_CONF_FILE=sysbuild/nrf5340dk_nrf5340_cpunet.conf + + sample.sysbuild.hello_world.nrf54h20dk_cpuapp_cpurad: + platform_allow: + - nrf54h20dk/nrf54h20/cpuapp + integration_platforms: + - nrf54h20dk/nrf54h20/cpuapp + extra_args: + SB_CONF_FILE=sysbuild/nrf54h20dk_nrf54h20_cpurad.conf + + sample.sysbuild.hello_world.nrf54h20dk_cpuapp_cpuppr: + platform_allow: + - nrf54h20dk/nrf54h20/cpuapp + integration_platforms: + - nrf54h20dk/nrf54h20/cpuapp + extra_args: + SB_CONF_FILE=sysbuild/nrf54h20dk_nrf54h20_cpuppr.conf + hello_world_SNIPPET=nordic-ppr + + sample.sysbuild.hello_world.nrf54h20dk_cpuapp_cpuppr_xip: + platform_allow: + - nrf54h20dk/nrf54h20/cpuapp + integration_platforms: + - nrf54h20dk/nrf54h20/cpuapp + extra_args: + SB_CONF_FILE=sysbuild/nrf54h20dk_nrf54h20_cpuppr_xip.conf + hello_world_SNIPPET=nordic-ppr-xip diff --git a/samples/sysbuild/hello_world/src/main.c b/samples/sysbuild/hello_world/src/main.c new file mode 100644 index 00000000000..af5b6fd3dbe --- /dev/null +++ b/samples/sysbuild/hello_world/src/main.c @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +int main(void) +{ + printk("Hello world from %s\n", CONFIG_BOARD_TARGET); + + return 0; +} diff --git a/samples/sysbuild/hello_world/sysbuild.cmake b/samples/sysbuild/hello_world/sysbuild.cmake new file mode 100644 index 00000000000..b59062d881f --- /dev/null +++ b/samples/sysbuild/hello_world/sysbuild.cmake @@ -0,0 +1,15 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if("${SB_CONFIG_REMOTE_BOARD}" STREQUAL "") + message(FATAL_ERROR "REMOTE_BOARD must be set to a valid board name") +endif() + +ExternalZephyrProject_Add( + APPLICATION remote + SOURCE_DIR ${APP_DIR}/remote + BOARD ${SB_CONFIG_REMOTE_BOARD} +) + +add_dependencies(hello_world remote) +sysbuild_add_dependencies(FLASH hello_world remote) diff --git a/samples/sysbuild/hello_world/sysbuild/nrf5340dk_nrf5340_cpunet.conf b/samples/sysbuild/hello_world/sysbuild/nrf5340dk_nrf5340_cpunet.conf new file mode 100644 index 00000000000..b8ae05d4ef6 --- /dev/null +++ b/samples/sysbuild/hello_world/sysbuild/nrf5340dk_nrf5340_cpunet.conf @@ -0,0 +1 @@ +SB_CONFIG_REMOTE_BOARD="nrf5340dk/nrf5340/cpunet" diff --git a/samples/sysbuild/hello_world/sysbuild/nrf54h20dk_nrf54h20_cpuppr.conf b/samples/sysbuild/hello_world/sysbuild/nrf54h20dk_nrf54h20_cpuppr.conf new file mode 100644 index 00000000000..f50bc8553a0 --- /dev/null +++ b/samples/sysbuild/hello_world/sysbuild/nrf54h20dk_nrf54h20_cpuppr.conf @@ -0,0 +1 @@ +SB_CONFIG_REMOTE_BOARD="nrf54h20dk/nrf54h20/cpuppr" diff --git a/samples/sysbuild/hello_world/sysbuild/nrf54h20dk_nrf54h20_cpuppr_xip.conf b/samples/sysbuild/hello_world/sysbuild/nrf54h20dk_nrf54h20_cpuppr_xip.conf new file mode 100644 index 00000000000..270c92c09a4 --- /dev/null +++ b/samples/sysbuild/hello_world/sysbuild/nrf54h20dk_nrf54h20_cpuppr_xip.conf @@ -0,0 +1 @@ +SB_CONFIG_REMOTE_BOARD="nrf54h20dk/nrf54h20/cpuppr/xip" diff --git a/samples/sysbuild/hello_world/sysbuild/nrf54h20dk_nrf54h20_cpurad.conf b/samples/sysbuild/hello_world/sysbuild/nrf54h20dk_nrf54h20_cpurad.conf new file mode 100644 index 00000000000..dd863e78d99 --- /dev/null +++ b/samples/sysbuild/hello_world/sysbuild/nrf54h20dk_nrf54h20_cpurad.conf @@ -0,0 +1 @@ +SB_CONFIG_REMOTE_BOARD="nrf54h20dk/nrf54h20/cpurad" diff --git a/samples/sysbuild/sysbuild.rst b/samples/sysbuild/sysbuild.rst new file mode 100644 index 00000000000..c959e82a3a3 --- /dev/null +++ b/samples/sysbuild/sysbuild.rst @@ -0,0 +1,10 @@ +.. _sysbuild-samples: + +Sysbuild samples +################ + +.. toctree:: + :maxdepth: 1 + :glob: + + **/* diff --git a/samples/application_development/sysbuild/with_mcuboot/CMakeLists.txt b/samples/sysbuild/with_mcuboot/CMakeLists.txt similarity index 100% rename from samples/application_development/sysbuild/with_mcuboot/CMakeLists.txt rename to samples/sysbuild/with_mcuboot/CMakeLists.txt diff --git a/samples/application_development/sysbuild/with_mcuboot/README.rst b/samples/sysbuild/with_mcuboot/README.rst similarity index 100% rename from samples/application_development/sysbuild/with_mcuboot/README.rst rename to samples/sysbuild/with_mcuboot/README.rst diff --git a/samples/application_development/sysbuild/with_mcuboot/prj.conf b/samples/sysbuild/with_mcuboot/prj.conf similarity index 100% rename from samples/application_development/sysbuild/with_mcuboot/prj.conf rename to samples/sysbuild/with_mcuboot/prj.conf diff --git a/samples/sysbuild/with_mcuboot/sample.yaml b/samples/sysbuild/with_mcuboot/sample.yaml new file mode 100644 index 00000000000..e1f456405a7 --- /dev/null +++ b/samples/sysbuild/with_mcuboot/sample.yaml @@ -0,0 +1,20 @@ +sample: + description: Sample with MCUboot built through sysbuild + name: with mcuboot +tests: + sample.sysbuild.with_mcuboot: + sysbuild: true + # Platform allowed is used as twister using sysbuild still lacks proper + # filtering support, see discussion in #49552. + platform_allow: + - reel_board + - nrf52840dk/nrf52840 + integration_platforms: + - nrf52840dk/nrf52840 + tags: mcuboot + harness: console + harness_config: + type: multi_line + regex: + - "Address of sample(.*)" + - "Hello sysbuild with mcuboot!(.*)" diff --git a/samples/application_development/sysbuild/with_mcuboot/src/main.c b/samples/sysbuild/with_mcuboot/src/main.c similarity index 100% rename from samples/application_development/sysbuild/with_mcuboot/src/main.c rename to samples/sysbuild/with_mcuboot/src/main.c diff --git a/samples/sysbuild/with_mcuboot/sysbuild.conf b/samples/sysbuild/with_mcuboot/sysbuild.conf new file mode 100644 index 00000000000..92042e44734 --- /dev/null +++ b/samples/sysbuild/with_mcuboot/sysbuild.conf @@ -0,0 +1,4 @@ +# Sysbuild configuration file. + +# Enable MCUboot per default for this sample. +SB_CONFIG_BOOTLOADER_MCUBOOT=y diff --git a/samples/application_development/sysbuild/with_mcuboot/sysbuild/mcuboot.conf b/samples/sysbuild/with_mcuboot/sysbuild/mcuboot.conf similarity index 100% rename from samples/application_development/sysbuild/with_mcuboot/sysbuild/mcuboot.conf rename to samples/sysbuild/with_mcuboot/sysbuild/mcuboot.conf diff --git a/samples/tfm_integration/psa_crypto/prj.conf b/samples/tfm_integration/psa_crypto/prj.conf index 97df0796411..f308a5aefaf 100644 --- a/samples/tfm_integration/psa_crypto/prj.conf +++ b/samples/tfm_integration/psa_crypto/prj.conf @@ -28,6 +28,13 @@ CONFIG_MBEDTLS_HEAP_SIZE=32768 CONFIG_MBEDTLS_USER_CONFIG_ENABLE=y CONFIG_MBEDTLS_USER_CONFIG_FILE="user-tls-conf.h" +CONFIG_MBEDTLS_PSA_CRYPTO_C=y +CONFIG_MBEDTLS_USE_PSA_CRYPTO=y +CONFIG_MBEDTLS_ENTROPY_ENABLED=y +CONFIG_MBEDTLS_ECP_C=y +CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED=y +CONFIG_MBEDTLS_ECDSA_C=y + # JSON CONFIG_JSON_LIBRARY=y diff --git a/samples/tfm_integration/psa_crypto/src/tls_config/user-tls-conf.h b/samples/tfm_integration/psa_crypto/src/tls_config/user-tls-conf.h index 26b64903319..fa6d4cc6756 100644 --- a/samples/tfm_integration/psa_crypto/src/tls_config/user-tls-conf.h +++ b/samples/tfm_integration/psa_crypto/src/tls_config/user-tls-conf.h @@ -4,21 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -#define MBEDTLS_USE_PSA_CRYPTO -#define MBEDTLS_PSA_CRYPTO_C - -#define MBEDTLS_ENTROPY_C -#define MBEDTLS_TEST_NULL_ENTROPY - -#define MBEDTLS_ECP_C -#define MBEDTLS_ECP_DP_SECP256R1_ENABLED -#define MBEDTLS_ECDSA_C - #define MBEDTLS_X509_CSR_WRITE_C #define MBEDTLS_X509_CREATE_C #define MBEDTLS_PEM_WRITE_C #define MBEDTLS_BASE64_C -#define MBEDTLS_OID_C -#define MBEDTLS_ASN1_WRITE_C -#define MBEDTLS_PK_WRITE_C -#define MBEDTLS_PK_C 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 013332ccb1a..fdb08e81ddb 100644 --- a/samples/tfm_integration/tfm_secure_partition/dummy_partition/CMakeLists.txt +++ b/samples/tfm_integration/tfm_secure_partition/dummy_partition/CMakeLists.txt @@ -36,6 +36,7 @@ target_link_libraries(tfm_app_rot_partition_dp PRIVATE platform_s tfm_sprt + psa_crypto_config ) target_link_libraries(tfm_spm diff --git a/samples/userspace/shared_mem/boards/nucleo_f756zg.overlay b/samples/userspace/shared_mem/boards/nucleo_f756zg.overlay new file mode 100644 index 00000000000..6277cda5bc1 --- /dev/null +++ b/samples/userspace/shared_mem/boards/nucleo_f756zg.overlay @@ -0,0 +1,13 @@ +/* + * Copyright 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * Disable quadspi MPU region for testing + * on this stm32f7 target. + * Otherwise one region will be missing from the 8 MPU regions + */ + +/delete-node/ &quadspi_memory; diff --git a/scripts/build/check_init_priorities.py b/scripts/build/check_init_priorities.py index ba6f476fba5..f126f2097c3 100755 --- a/scripts/build/check_init_priorities.py +++ b/scripts/build/check_init_priorities.py @@ -172,7 +172,7 @@ def _initlevel_pointer(self, addr, idx, shidx): elif elfclass == 64: ptrsize = 8 else: - ValueError(f"Unknown pointer size for ELF class f{elfclass}") + raise ValueError(f"Unknown pointer size for ELF class f{elfclass}") section = self._elf.get_section(shidx) start = section.header.sh_addr diff --git a/scripts/build/gen_kobject_list.py b/scripts/build/gen_kobject_list.py index 6e07fd00957..1d60c0df0fc 100755 --- a/scripts/build/gen_kobject_list.py +++ b/scripts/build/gen_kobject_list.py @@ -138,6 +138,9 @@ def kobject_to_enum(kobj): net_sockets = [ ] def subsystem_to_enum(subsys): + if not subsys.endswith("_driver_api"): + raise Exception("__subsystem is missing _driver_api suffix: (%s)" % subsys) + return "K_OBJ_DRIVER_" + subsys[:-11].upper() # --- debug stuff --- @@ -171,6 +174,7 @@ def debug_die(die, text): # -- ELF processing DW_OP_addr = 0x3 +DW_OP_plus_uconst = 0x23 DW_OP_fbreg = 0x91 STACK_TYPE = "z_thread_stack_element" thread_counter = 0 @@ -622,6 +626,11 @@ def find_kobjects(elf, syms): addr = ((loc.value[1] << 0 ) | (loc.value[2] << 8) | (loc.value[3] << 16) | (loc.value[4] << 24)) + # Handle a DW_FORM_exprloc that contains a DW_OP_addr, followed immediately by + # a DW_OP_plus_uconst. + if len(loc.value) >= 7 and loc.value[5] == DW_OP_plus_uconst: + addr += (loc.value[6]) + if addr == 0: # Never linked; gc-sections deleted it continue diff --git a/scripts/build/gen_syscalls.py b/scripts/build/gen_syscalls.py index 8755f3c649a..b6e332d45ca 100755 --- a/scripts/build/gen_syscalls.py +++ b/scripts/build/gen_syscalls.py @@ -205,21 +205,27 @@ def union_decl(type, split): middle = "struct { uintptr_t lo, hi; } split" if split else "uintptr_t x" return "union { %s; %s val; }" % (middle, type) -def wrapper_defs(func_name, func_type, args, fn): +def wrapper_defs(func_name, func_type, args, fn, userspace_only): ret64 = need_split(func_type) mrsh_args = [] # List of rvalue expressions for the marshalled invocation decl_arglist = ", ".join([" ".join(argrec) for argrec in args]) or "void" syscall_id = "K_SYSCALL_" + func_name.upper() - wrap = "extern %s z_impl_%s(%s);\n" % (func_type, func_name, decl_arglist) - wrap += "\n" + wrap = '' + if not userspace_only: + wrap += "extern %s z_impl_%s(%s);\n" % (func_type, func_name, decl_arglist) + wrap += "\n" + wrap += "__pinned_func\n" wrap += "static inline %s %s(%s)\n" % (func_type, func_name, decl_arglist) wrap += "{\n" - wrap += "#ifdef CONFIG_USERSPACE\n" + if not userspace_only: + wrap += "#ifdef CONFIG_USERSPACE\n" + wrap += ("\t" + "uint64_t ret64;\n") if ret64 else "" - wrap += "\t" + "if (z_syscall_trap()) {\n" + if not userspace_only: + wrap += "\t" + "if (z_syscall_trap()) {\n" valist_args = [] for argnum, (argtype, argname) in enumerate(args): @@ -267,18 +273,19 @@ def wrapper_defs(func_name, func_type, args, fn): for argname in valist_args: wrap += "\t\t" + "va_end(%s);\n" % argname wrap += retcode - wrap += "\t" + "}\n" - wrap += "#endif\n" - - # Otherwise fall through to direct invocation of the impl func. - # Note the compiler barrier: that is required to prevent code from - # the impl call from being hoisted above the check for user - # context. - impl_arglist = ", ".join([argrec[1] for argrec in args]) - impl_call = "z_impl_%s(%s)" % (func_name, impl_arglist) - wrap += "\t" + "compiler_barrier();\n" - wrap += "\t" + "%s%s;\n" % ("return " if func_type != "void" else "", - impl_call) + if not userspace_only: + wrap += "\t" + "}\n" + wrap += "#endif\n" + + # Otherwise fall through to direct invocation of the impl func. + # Note the compiler barrier: that is required to prevent code from + # the impl call from being hoisted above the check for user + # context. + impl_arglist = ", ".join([argrec[1] for argrec in args]) + impl_call = "z_impl_%s(%s)" % (func_name, impl_arglist) + wrap += "\t" + "compiler_barrier();\n" + wrap += "\t" + "%s%s;\n" % ("return " if func_type != "void" else "", + impl_call) wrap += "}\n" @@ -377,7 +384,7 @@ def marshall_defs(func_name, func_type, args): return mrsh, mrsh_name -def analyze_fn(match_group, fn): +def analyze_fn(match_group, fn, userspace_only): func, args = match_group try: @@ -395,7 +402,7 @@ def analyze_fn(match_group, fn): marshaller = None marshaller, handler = marshall_defs(func_name, func_type, args) - invocation = wrapper_defs(func_name, func_type, args, fn) + invocation = wrapper_defs(func_name, func_type, args, fn, userspace_only) # Entry in _k_syscall_table table_entry = "[%s] = %s" % (sys_id, handler) @@ -424,6 +431,8 @@ def parse_args(): help="Generate marshalling files (*_mrsh.c)") parser.add_argument("-e", "--syscall-export-llext", help="output C system call export for extensions") + parser.add_argument("-u", "--userspace-only", action="store_true", + help="Only generate the userpace path of wrappers") args = parser.parse_args() @@ -448,7 +457,7 @@ def main(): exported = [] for match_group, fn, to_emit in syscalls: - handler, inv, mrsh, sys_id, entry = analyze_fn(match_group, fn) + handler, inv, mrsh, sys_id, entry = analyze_fn(match_group, fn, args.userspace_only) if fn not in invocations: invocations[fn] = [] diff --git a/scripts/build/uf2conv.py b/scripts/build/uf2conv.py index 5da08efd5b9..fd70895bc80 100755 --- a/scripts/build/uf2conv.py +++ b/scripts/build/uf2conv.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # Copyright (c) Microsoft Corporation # SPDX-License-Identifier: MIT -# Copied from 7a9e1f4 of https://github.com/microsoft/uf2/blob/master/utils/uf2conv.py +# Copied from 27e322f of https://github.com/microsoft/uf2/blob/master/utils/uf2conv.py # pylint: skip-file import sys import struct @@ -10,40 +10,14 @@ import os import os.path import argparse +import json +from time import sleep UF2_MAGIC_START0 = 0x0A324655 # "UF2\n" UF2_MAGIC_START1 = 0x9E5D5157 # Randomly selected UF2_MAGIC_END = 0x0AB16F30 # Ditto -families = { - 'SAMD21': 0x68ed2b88, - 'SAML21': 0x1851780a, - 'SAMD51': 0x55114460, - 'NRF52': 0x1b57745f, - 'STM32F0': 0x647824b6, - 'STM32F1': 0x5ee21072, - 'STM32F2': 0x5d1a0a2e, - 'STM32F3': 0x6b846188, - 'STM32F4': 0x57755a57, - 'STM32F7': 0x53b80f00, - 'STM32G0': 0x300f5633, - 'STM32G4': 0x4c71240a, - 'STM32H7': 0x6db66082, - 'STM32L0': 0x202e3a91, - 'STM32L1': 0x1e1f432d, - 'STM32L4': 0x00ff6919, - 'STM32L5': 0x04240bdf, - 'STM32WB': 0x70d16653, - 'STM32WL': 0x21460ff0, - 'ATMEGA32': 0x16573617, - 'MIMXRT10XX': 0x4FB2D5BD, - 'LPC55': 0x2abc77ec, - 'GD32F350': 0x31D228C6, - 'ESP32S2': 0xbfdd4eee, - 'RP2040': 0xe48bff56 -} - INFO_FILE = "/INFO_UF2.TXT" appstartaddr = 0x2000 @@ -59,14 +33,19 @@ def is_hex(buf): w = buf[0:30].decode("utf-8") except UnicodeDecodeError: return False - if w[0] == ':' and re.match(b"^[:0-9a-fA-F\r\n]+$", buf): + if w[0] == ':' and re.match(rb"^[:0-9a-fA-F\r\n]+$", buf): return True return False def convert_from_uf2(buf): global appstartaddr + global familyid numblocks = len(buf) // 512 curraddr = None + currfamilyid = None + families_found = {} + prev_flag = None + all_flags_same = True outp = [] for blockno in range(numblocks): ptr = blockno * 512 @@ -82,9 +61,13 @@ def convert_from_uf2(buf): if datalen > 476: assert False, "Invalid UF2 data size at " + ptr newaddr = hd[3] - if curraddr == None: - appstartaddr = newaddr + if (hd[2] & 0x2000) and (currfamilyid == None): + currfamilyid = hd[7] + if curraddr == None or ((hd[2] & 0x2000) and hd[7] != currfamilyid): + currfamilyid = hd[7] curraddr = newaddr + if familyid == 0x0 or familyid == hd[7]: + appstartaddr = newaddr padding = newaddr - curraddr if padding < 0: assert False, "Block out of order at " + ptr @@ -94,9 +77,38 @@ def convert_from_uf2(buf): assert False, "Non-word padding size at " + ptr while padding > 0: padding -= 4 - outp += b"\x00\x00\x00\x00" - outp.append(block[32 : 32 + datalen]) + outp.append(b"\x00\x00\x00\x00") + if familyid == 0x0 or ((hd[2] & 0x2000) and familyid == hd[7]): + outp.append(block[32 : 32 + datalen]) curraddr = newaddr + datalen + if hd[2] & 0x2000: + if hd[7] in families_found.keys(): + if families_found[hd[7]] > newaddr: + families_found[hd[7]] = newaddr + else: + families_found[hd[7]] = newaddr + if prev_flag == None: + prev_flag = hd[2] + if prev_flag != hd[2]: + all_flags_same = False + if blockno == (numblocks - 1): + print("--- UF2 File Header Info ---") + families = load_families() + for family_hex in families_found.keys(): + family_short_name = "" + for name, value in families.items(): + if value == family_hex: + family_short_name = name + print("Family ID is {:s}, hex value is 0x{:08x}".format(family_short_name,family_hex)) + print("Target Address is 0x{:08x}".format(families_found[family_hex])) + if all_flags_same: + print("All block flag values consistent, 0x{:04x}".format(hd[2])) + else: + print("Flags were not all the same") + print("----------------------------") + if len(families_found) > 1 and familyid == 0x0: + outp = [] + appstartaddr = 0x0 return b"".join(outp) def convert_to_carray(file_content): @@ -170,11 +182,10 @@ def convert_from_hex_to_uf2(buf): upper = ((rec[4] << 8) | rec[5]) << 16 elif tp == 2: upper = ((rec[4] << 8) | rec[5]) << 4 - assert (upper & 0xffff) == 0 elif tp == 1: break elif tp == 0: - addr = upper | (rec[1] << 8) | rec[2] + addr = upper + ((rec[1] << 8) | rec[2]) if appstartaddr == None: appstartaddr = addr i = 4 @@ -201,19 +212,21 @@ def get_drives(): "get", "DeviceID,", "VolumeName,", "FileSystem,", "DriveType"]) for line in to_str(r).split('\n'): - words = re.split('\s+', line) + words = re.split(r'\s+', line) if len(words) >= 3 and words[1] == "2" and words[2] == "FAT": drives.append(words[0]) else: - rootpath = "/media" + searchpaths = ["/media"] if sys.platform == "darwin": - rootpath = "/Volumes" + searchpaths = ["/Volumes"] elif sys.platform == "linux": - tmp = rootpath + "/" + os.environ["USER"] - if os.path.isdir(tmp): - rootpath = tmp - for d in os.listdir(rootpath): - drives.append(os.path.join(rootpath, d)) + searchpaths += ["/media/" + os.environ["USER"], '/run/media/' + os.environ["USER"]] + + for rootpath in searchpaths: + if os.path.isdir(rootpath): + for d in os.listdir(rootpath): + if os.path.isdir(rootpath): + drives.append(os.path.join(rootpath, d)) def has_info(d): @@ -228,7 +241,7 @@ def has_info(d): def board_id(path): with open(path + INFO_FILE, mode='r') as file: file_content = file.read() - return re.search("Board-ID: ([^\r\n]*)", file_content).group(1) + return re.search(r"Board-ID: ([^\r\n]*)", file_content).group(1) def list_drives(): @@ -242,36 +255,57 @@ def write_file(name, buf): print("Wrote %d bytes to %s" % (len(buf), name)) +def load_families(): + # The expectation is that the `uf2families.json` file is in the same + # directory as this script. Make a path that works using `__file__` + # which contains the full path to this script. + filename = "uf2families.json" + pathname = os.path.join(os.path.dirname(os.path.abspath(__file__)), filename) + with open(pathname) as f: + raw_families = json.load(f) + + families = {} + for family in raw_families: + families[family["short_name"]] = int(family["id"], 0) + + return families + + def main(): global appstartaddr, familyid def error(msg): - print(msg) + print(msg, file=sys.stderr) sys.exit(1) - parser = argparse.ArgumentParser(description='Convert to UF2 or flash directly.', - allow_abbrev=False) + parser = argparse.ArgumentParser(description='Convert to UF2 or flash directly.') parser.add_argument('input', metavar='INPUT', type=str, nargs='?', help='input file (HEX, BIN or UF2)') - parser.add_argument('-b' , '--base', dest='base', type=str, + parser.add_argument('-b', '--base', dest='base', type=str, default="0x2000", help='set base address of application for BIN format (default: 0x2000)') - parser.add_argument('-o' , '--output', metavar="FILE", dest='output', type=str, + parser.add_argument('-f', '--family', dest='family', type=str, + default="0x0", + help='specify familyID - number or name (default: 0x0)') + parser.add_argument('-o', '--output', metavar="FILE", dest='output', type=str, help='write output to named file; defaults to "flash.uf2" or "flash.bin" where sensible') - parser.add_argument('-d' , '--device', dest="device_path", + parser.add_argument('-d', '--device', dest="device_path", help='select a device path to flash') - parser.add_argument('-l' , '--list', action='store_true', + parser.add_argument('-l', '--list', action='store_true', help='list connected devices') - parser.add_argument('-c' , '--convert', action='store_true', + parser.add_argument('-c', '--convert', action='store_true', help='do not flash, just convert') - parser.add_argument('-D' , '--deploy', action='store_true', + parser.add_argument('-D', '--deploy', action='store_true', help='just flash, do not convert') - parser.add_argument('-f' , '--family', dest='family', type=str, - default="0x0", - help='specify familyID - number or name (default: 0x0)') - parser.add_argument('-C' , '--carray', action='store_true', + parser.add_argument('-w', '--wait', action='store_true', + help='wait for device to flash') + parser.add_argument('-C', '--carray', action='store_true', help='convert binary file to a C array, not UF2') + parser.add_argument('-i', '--info', action='store_true', + help='display header information from UF2, do not convert') args = parser.parse_args() appstartaddr = int(args.base, 0) + families = load_families() + if args.family.upper() in families: familyid = families[args.family.upper()] else: @@ -291,9 +325,12 @@ def error(msg): ext = "uf2" if args.deploy: outbuf = inpbuf - elif from_uf2: + elif from_uf2 and not args.info: outbuf = convert_from_uf2(inpbuf) ext = "bin" + elif from_uf2 and args.info: + outbuf = "" + convert_from_uf2(inpbuf) elif is_hex(inpbuf): outbuf = convert_from_hex_to_uf2(inpbuf.decode("utf-8")) elif args.carray: @@ -301,23 +338,27 @@ def error(msg): ext = "h" else: outbuf = convert_to_uf2(inpbuf) - print("Converting to %s, output size: %d, start address: 0x%x" % - (ext, len(outbuf), appstartaddr)) + if not args.deploy and not args.info: + print("Converted to %s, output size: %d, start address: 0x%x" % + (ext, len(outbuf), appstartaddr)) if args.convert or ext != "uf2": - drives = [] if args.output == None: args.output = "flash." + ext - else: - drives = get_drives() - if args.output: write_file(args.output, outbuf) - else: + if ext == "uf2" and not args.convert and not args.info: + drives = get_drives() if len(drives) == 0: - error("No drive to deploy.") - for d in drives: - print("Flashing %s (%s)" % (d, board_id(d))) - write_file(d + "/NEW.UF2", outbuf) + if args.wait: + print("Waiting for drive to deploy...") + while len(drives) == 0: + sleep(0.1) + drives = get_drives() + elif not args.output: + error("No drive to deploy.") + for d in drives: + print("Flashing %s (%s)" % (d, board_id(d))) + write_file(d + "/NEW.UF2", outbuf) if __name__ == "__main__": diff --git a/scripts/build/uf2families.json b/scripts/build/uf2families.json new file mode 100644 index 00000000000..14c8e5d043c --- /dev/null +++ b/scripts/build/uf2families.json @@ -0,0 +1,247 @@ +[ + { + "id": "0x16573617", + "short_name": "ATMEGA32", + "description": "Microchip (Atmel) ATmega32" + }, + { + "id": "0x1851780a", + "short_name": "SAML21", + "description": "Microchip (Atmel) SAML21" + }, + { + "id": "0x1b57745f", + "short_name": "NRF52", + "description": "Nordic NRF52" + }, + { + "id": "0x1c5f21b0", + "short_name": "ESP32", + "description": "ESP32" + }, + { + "id": "0x1e1f432d", + "short_name": "STM32L1", + "description": "ST STM32L1xx" + }, + { + "id": "0x202e3a91", + "short_name": "STM32L0", + "description": "ST STM32L0xx" + }, + { + "id": "0x21460ff0", + "short_name": "STM32WL", + "description": "ST STM32WLxx" + }, + { + "id": "0x2abc77ec", + "short_name": "LPC55", + "description": "NXP LPC55xx" + }, + { + "id": "0x300f5633", + "short_name": "STM32G0", + "description": "ST STM32G0xx" + }, + { + "id": "0x31d228c6", + "short_name": "GD32F350", + "description": "GD32F350" + }, + { + "id": "0x04240bdf", + "short_name": "STM32L5", + "description": "ST STM32L5xx" + }, + { + "id": "0x4c71240a", + "short_name": "STM32G4", + "description": "ST STM32G4xx" + }, + { + "id": "0x4fb2d5bd", + "short_name": "MIMXRT10XX", + "description": "NXP i.MX RT10XX" + }, + { + "id": "0x53b80f00", + "short_name": "STM32F7", + "description": "ST STM32F7xx" + }, + { + "id": "0x55114460", + "short_name": "SAMD51", + "description": "Microchip (Atmel) SAMD51" + }, + { + "id": "0x57755a57", + "short_name": "STM32F4", + "description": "ST STM32F4xx" + }, + { + "id": "0x5a18069b", + "short_name": "FX2", + "description": "Cypress FX2" + }, + { + "id": "0x5d1a0a2e", + "short_name": "STM32F2", + "description": "ST STM32F2xx" + }, + { + "id": "0x5ee21072", + "short_name": "STM32F1", + "description": "ST STM32F103" + }, + { + "id": "0x621e937a", + "short_name": "NRF52833", + "description": "Nordic NRF52833" + }, + { + "id": "0x647824b6", + "short_name": "STM32F0", + "description": "ST STM32F0xx" + }, + { + "id": "0x68ed2b88", + "short_name": "SAMD21", + "description": "Microchip (Atmel) SAMD21" + }, + { + "id": "0x6b846188", + "short_name": "STM32F3", + "description": "ST STM32F3xx" + }, + { + "id": "0x6d0922fa", + "short_name": "STM32F407", + "description": "ST STM32F407" + }, + { + "id": "0x6db66082", + "short_name": "STM32H7", + "description": "ST STM32H7xx" + }, + { + "id": "0x70d16653", + "short_name": "STM32WB", + "description": "ST STM32WBxx" + }, + { + "id": "0x7eab61ed", + "short_name": "ESP8266", + "description": "ESP8266" + }, + { + "id": "0x7f83e793", + "short_name": "KL32L2", + "description": "NXP KL32L2x" + }, + { + "id": "0x8fb060fe", + "short_name": "STM32F407VG", + "description": "ST STM32F407VG" + }, + { + "id": "0xada52840", + "short_name": "NRF52840", + "description": "Nordic NRF52840" + }, + { + "id": "0xbfdd4eee", + "short_name": "ESP32S2", + "description": "ESP32-S2" + }, + { + "id": "0xc47e5767", + "short_name": "ESP32S3", + "description": "ESP32-S3" + }, + { + "id": "0xd42ba06c", + "short_name": "ESP32C3", + "description": "ESP32-C3" + }, + { + "id": "0x2b88d29c", + "short_name": "ESP32C2", + "description": "ESP32-C2" + }, + { + "id": "0x332726f6", + "short_name": "ESP32H2", + "description": "ESP32-H2" + }, + { + "id": "0x540ddf62", + "short_name": "ESP32C6", + "description": "ESP32-C6" + }, + { + "id": "0x3d308e94", + "short_name": "ESP32P4", + "description": "ESP32-P4" + }, + { + "id": "0xe48bff56", + "short_name": "RP2040", + "description": "Raspberry Pi RP2040" + }, + { + "id": "0x00ff6919", + "short_name": "STM32L4", + "description": "ST STM32L4xx" + }, + { + "id": "0x9af03e33", + "short_name": "GD32VF103", + "description": "GigaDevice GD32VF103" + }, + { + "id": "0x4f6ace52", + "short_name": "CSK4", + "description": "LISTENAI CSK300x/400x" + }, + { + "id": "0x6e7348a8", + "short_name": "CSK6", + "description": "LISTENAI CSK60xx" + }, + { + "id": "0x11de784a", + "short_name": "M0SENSE", + "description": "M0SENSE BL702" + }, + { + "id": "0x4b684d71", + "short_name": "MaixPlay-U4", + "description": "Sipeed MaixPlay-U4(BL618)" + }, + { + "id": "0x9517422f", + "short_name": "RZA1LU", + "description": "Renesas RZ/A1LU (R7S7210xx)" + }, + { + "id": "0x2dc309c5", + "short_name": "STM32F411xE", + "description": "ST STM32F411xE" + }, + { + "id": "0x06d1097b", + "short_name": "STM32F411xC", + "description": "ST STM32F411xC" + }, + { + "id": "0x72721d4e", + "short_name": "NRF52832xxAA", + "description": "Nordic NRF52832xxAA" + }, + { + "id": "0x6f752678", + "short_name": "NRF52832xxAB", + "description": "Nordic NRF52832xxAB" + } +] diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 833b11886fa..27fbd880ef6 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -3544,7 +3544,7 @@ sub process { # known declaration macros $sline =~ /^\+\s+$declaration_macros/ || # start of struct or union or enum - $sline =~ /^\+\s+(?:static\s+)?(?:const\s+)?(?:union|struct|enum|typedef)\b/ || + $sline =~ /^\+\s+(?:volatile\s+)?(?:static\s+)?(?:const\s+)?(?:union|struct|enum|typedef)\b/ || # start or end of block or continuation of declaration $sline =~ /^\+\s+(?:$|[\{\}\.\#\"\?\:\(\[])/ || # bitfield continuation diff --git a/scripts/ci/check_compliance.py b/scripts/ci/check_compliance.py index ba44e084e6d..f726dca2e19 100755 --- a/scripts/ci/check_compliance.py +++ b/scripts/ci/check_compliance.py @@ -7,6 +7,7 @@ import argparse import collections from email.utils import parseaddr +import json import logging import os from pathlib import Path @@ -178,7 +179,6 @@ def fmtd_failure(self, severity, title, file, line=None, col=None, desc=""): self._result(fail, fail.text) self.fmtd_failures.append(fail) - class EndTest(Exception): """ Raised by ComplianceTest.error()/skip() to end the test. @@ -598,6 +598,39 @@ def parse_kconfig(self, filename="Kconfig", hwm=None): # Clean up the temporary directory shutil.rmtree(kconfiglib_dir) + def get_logging_syms(self, kconf): + # Returns a set() with the names of the Kconfig symbols generated with + # logging template in samples/tests folders. The Kconfig symbols doesn't + # include `CONFIG_` and for each module declared there is one symbol + # per suffix created. + + suffixes = [ + "_LOG_LEVEL", + "_LOG_LEVEL_DBG", + "_LOG_LEVEL_ERR", + "_LOG_LEVEL_INF", + "_LOG_LEVEL_WRN", + "_LOG_LEVEL_OFF", + "_LOG_LEVEL_INHERIT", + "_LOG_LEVEL_DEFAULT", + ] + + # Warning: Needs to work with both --perl-regexp and the 're' module. + regex = r"^\s*(?:module\s*=\s*)([A-Z0-9_]+)\s*(?:#|$)" + + # Grep samples/ and tests/ for symbol definitions + grep_stdout = git("grep", "-I", "-h", "--perl-regexp", regex, "--", + ":samples", ":tests", cwd=ZEPHYR_BASE) + + names = re.findall(regex, grep_stdout, re.MULTILINE) + + kconf_syms = [] + for name in names: + for suffix in suffixes: + kconf_syms.append(f"{name}{suffix}") + + return set(kconf_syms) + def get_defined_syms(self, kconf): # Returns a set() with the names of all defined Kconfig symbols (with no # 'CONFIG_' prefix). This is complicated by samples and tests defining @@ -619,8 +652,10 @@ def get_defined_syms(self, kconf): # Symbols from the main Kconfig tree + grepped definitions from samples # and tests - return set([sym.name for sym in kconf_syms] - + re.findall(regex, grep_stdout, re.MULTILINE)) + return set( + [sym.name for sym in kconf_syms] + + re.findall(regex, grep_stdout, re.MULTILINE) + ).union(self.get_logging_syms(kconf)) def check_top_menu_not_too_long(self, kconf): """ @@ -803,7 +838,7 @@ def check_no_undef_outside_kconfig(self, kconf): for sym_name in re.findall(regex, line): sym_name = sym_name[7:] # Strip CONFIG_ if sym_name not in defined_syms and \ - sym_name not in self.UNDEF_KCONFIG_WHITELIST: + sym_name not in self.UNDEF_KCONFIG_ALLOWLIST: undef_to_locs[sym_name].append(f"{path}:{lineno}") @@ -821,7 +856,7 @@ def check_no_undef_outside_kconfig(self, kconf): self.failure(f""" Found references to undefined Kconfig symbols. If any of these are false -positives, then add them to UNDEF_KCONFIG_WHITELIST in {__file__}. +positives, then add them to UNDEF_KCONFIG_ALLOWLIST in {__file__}. If the reference is for a comment like /* CONFIG_FOO_* */ (or /* CONFIG_FOO_*_... */), then please use exactly that form (with the '*'). The @@ -834,7 +869,7 @@ def check_no_undef_outside_kconfig(self, kconf): # Many of these are symbols used as examples. Note that the list is sorted # alphabetically, and skips the CONFIG_ prefix. - UNDEF_KCONFIG_WHITELIST = { + UNDEF_KCONFIG_ALLOWLIST = { "ALSO_MISSING", "APP_LINK_WITH_", "APP_LOG_LEVEL", # Application log level is not detected correctly as @@ -866,8 +901,6 @@ def check_no_undef_outside_kconfig(self, kconf): "BOOT_SIGNATURE_TYPE_RSA", # MCUboot setting used by sysbuild "BOOT_VALIDATE_SLOT0", # Used in (sysbuild-based) test "BOOT_WATCHDOG_FEED", # Used in (sysbuild-based) test - "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 @@ -905,8 +938,6 @@ def check_no_undef_outside_kconfig(self, kconf): "MCUBOOT_CLEANUP_ARM_CORE", # Used in (sysbuild-based) test "MCUBOOT_SERIAL", # Used in (sysbuild-based) test/ # documentation - "MCUMGR_GRP_EXAMPLE", # Used in documentation - "MCUMGR_GRP_EXAMPLE_LOG_LEVEL", # Used in documentation "MCUMGR_GRP_EXAMPLE_OTHER_HOOK", # Used in documentation "MISSING", "MODULES", @@ -919,8 +950,6 @@ def check_no_undef_outside_kconfig(self, kconf): "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 "LOG_BACKEND_MOCK_OUTPUT_SYST", #Referenced in testcase.yaml of log_syst test "SEL", @@ -934,7 +963,6 @@ def check_no_undef_outside_kconfig(self, kconf): "SRAM2", # Referenced in a comment in samples/application_development "STACK_SIZE", # Used as an example in the Kconfig docs "STD_CPP", # Referenced in CMake comment - "TAGOIO_HTTP_POST_LOG_LEVEL", # Used as in samples/net/cloud/tagoio "TEST1", "TOOLCHAIN_ARCMWDT_SUPPORTS_THREAD_LOCAL_STORAGE", # The symbol is defined in the toolchain # Kconfig which is sourced based on Zephyr @@ -1178,7 +1206,7 @@ def run(self): else: python_environment["PYTHONPATH"] = check_script_dir - pylintcmd = ["pylint", "--rcfile=" + pylintrc, + pylintcmd = ["pylint", "--output-format=json2", "--rcfile=" + pylintrc, "--load-plugins=argparse-checker"] + py_files logger.info(cmd2str(pylintcmd)) try: @@ -1190,21 +1218,19 @@ def run(self): env=python_environment) except subprocess.CalledProcessError as ex: output = ex.output.decode("utf-8") - regex = r'^\s*(\S+):(\d+):(\d+):\s*([A-Z]\d{4}):\s*(.*)$' - - matches = re.findall(regex, output, re.MULTILINE) - for m in matches: - # https://pylint.pycqa.org/en/latest/user_guide/messages/messages_overview.html# + messages = json.loads(output)['messages'] + for m in messages: severity = 'unknown' - if m[3][0] in ('F', 'E'): + if m['messageId'][0] in ('F', 'E'): severity = 'error' - elif m[3][0] in ('W','C', 'R', 'I'): + elif m['messageId'][0] in ('W','C', 'R', 'I'): severity = 'warning' - self.fmtd_failure(severity, m[3], m[0], m[1], col=m[2], - desc=m[4]) + self.fmtd_failure(severity, m['messageId'], m['path'], + m['line'], col=str(m['column']), desc=m['message'] + + f" ({m['symbol']})") - # If the regex has not matched add the whole output as a failure - if len(matches) == 0: + if len(messages) == 0: + # If there are no specific messages add the whole output as a failure self.failure(output) diff --git a/scripts/ci/coverage/coverage_analysis.py b/scripts/ci/coverage/coverage_analysis.py index afa4c5fbe63..1d446aded78 100644 --- a/scripts/ci/coverage/coverage_analysis.py +++ b/scripts/ci/coverage/coverage_analysis.py @@ -13,6 +13,13 @@ class Json_report: "components":[] } + simulators = [ + 'unit_testing', + 'native', + 'qemu', + 'mps2/an385' + ] + report_json = {} def __init__(self): @@ -62,7 +69,8 @@ def parse_testplan(self, testplan_path): break sub_component_name = testcase_name[testcase_name.find('.'):] sub_component_name = sub_component_name[1:] - sub_component_name = sub_component_name[:sub_component_name.find(".")] + if sub_component_name.find(".") > 0: + sub_component_name = sub_component_name[:sub_component_name.find(".")] if known_component_flag is False: sub_component = { @@ -80,7 +88,7 @@ def parse_testplan(self, testplan_path): test_case = { "name":testcase_name } - if 'qemu' in testsuite['platform'] or 'native' in testsuite['platform']: + if any(platform in testsuite['platform'] for platform in self.simulators): if test_suite['status'] == "": test_suite['status'] = 'sim_only' @@ -122,7 +130,7 @@ def parse_testplan(self, testplan_path): test_case = { "name": testcase_name } - if 'qemu' in testsuite['platform'] or 'native' in testsuite['platform']: + if any(platform in testsuite['platform'] for platform in self.simulators): if test_suite['status'] == "": test_suite['status'] = 'sim_only' @@ -159,7 +167,7 @@ def parse_testplan(self, testplan_path): test_case = { "name": testcase_name } - if 'qemu' in testsuite['platform'] or 'native' in testsuite['platform']: + if any(platform in testsuite['platform'] for platform in self.simulators): if test_suite['status'] == "": test_suite['status'] = 'sim_only' @@ -175,7 +183,7 @@ def parse_testplan(self, testplan_path): test_suite['platforms'].append(testsuite['platform']) sub_component["test_suites"].append(test_suite) else: - if 'qemu' in testsuite['platform'] or 'native' in testsuite['platform']: + if any(platform in testsuite['platform'] for platform in self.simulators): if test_suite['status'] == "": test_suite['status'] = 'sim_only' diff --git a/scripts/ci/test_plan.py b/scripts/ci/test_plan.py index 9fc3c2b000c..edbbbf2d923 100755 --- a/scripts/ci/test_plan.py +++ b/scripts/ci/test_plan.py @@ -452,7 +452,8 @@ def parse_args(): print("=========") f = Filters(files, args.ignore_path, args.alt_tags, args.testsuite_root, - args.pull_request, args.platform, args.detailed_test_id, args.quarantine_list, args.testcase_roots_threshold) + args.pull_request, args.platform, args.detailed_test_id, args.quarantine_list, + args.testcase_roots_threshold) f.process() # remove dupes and filtered cases diff --git a/scripts/coredump/gdbstubs/arch/risc_v.py b/scripts/coredump/gdbstubs/arch/risc_v.py index 7eb4b924316..60c5fcdf63a 100644 --- a/scripts/coredump/gdbstubs/arch/risc_v.py +++ b/scripts/coredump/gdbstubs/arch/risc_v.py @@ -13,7 +13,6 @@ logger = logging.getLogger("gdbstub") - class RegNum(): ZERO = 0 RA = 1 @@ -52,6 +51,7 @@ class RegNum(): class GdbStub_RISC_V(GdbStub): ARCH_DATA_BLK_STRUCT = " unknown value # Send in "xxxxxxxx" - pkt += b'x' * 8 + length = 8 if self.arch_data_ver == 1 else 16 + pkt += b'x' * length idx += 1 @@ -111,4 +117,5 @@ def handle_register_group_read_packet(self): def handle_register_single_read_packet(self, pkt): # Mark registers as "". 'p' packets are not sent for the registers # currently handled in this file so we can safely reply "xxxxxxxx" here. - self.put_gdb_packet(b'x' * 8) + length = 8 if self.arch_data_ver == 1 else 16 + self.put_gdb_packet(b'x' * length) diff --git a/scripts/dts/gen_defines.py b/scripts/dts/gen_defines.py index b23a4cb76fe..eb350b0483b 100755 --- a/scripts/dts/gen_defines.py +++ b/scripts/dts/gen_defines.py @@ -524,6 +524,15 @@ def write_children(node): out_comment("Helper macros for child nodes of this node.") + out_dt_define(f"{node.z_path_id}_CHILD_NUM", len(node.children)) + + ok_nodes_num = 0 + for child in node.children.values(): + if child.status == "okay": + ok_nodes_num = ok_nodes_num + 1 + + out_dt_define(f"{node.z_path_id}_CHILD_NUM_STATUS_OKAY", ok_nodes_num) + out_dt_define(f"{node.z_path_id}_FOREACH_CHILD(fn)", " ".join(f"fn(DT_{child.z_path_id})" for child in node.children.values())) diff --git a/scripts/dts/python-devicetree/src/devicetree/edtlib.py b/scripts/dts/python-devicetree/src/devicetree/edtlib.py index 851706790b9..088ef6e0996 100644 --- a/scripts/dts/python-devicetree/src/devicetree/edtlib.py +++ b/scripts/dts/python-devicetree/src/devicetree/edtlib.py @@ -163,7 +163,9 @@ class Binding: def __init__(self, path: Optional[str], fname2path: Dict[str, str], raw: Any = None, require_compatible: bool = True, - require_description: bool = True): + require_description: bool = True, + inc_allowlist: Optional[List[str]] = None, + inc_blocklist: Optional[List[str]] = None): """ Binding constructor. @@ -191,16 +193,36 @@ def __init__(self, path: Optional[str], fname2path: Dict[str, str], "description:" line. If False, a missing "description:" is not an error. Either way, "description:" must be a string if it is present in the binding. + + inc_allowlist: + The property-allowlist filter set by including bindings. + + inc_blocklist: + The property-blocklist filter set by including bindings. """ self.path: Optional[str] = path self._fname2path: Dict[str, str] = fname2path + self._inc_allowlist: Optional[List[str]] = inc_allowlist + self._inc_blocklist: Optional[List[str]] = inc_blocklist + if raw is None: if path is None: _err("you must provide either a 'path' or a 'raw' argument") with open(path, encoding="utf-8") as f: raw = yaml.load(f, Loader=_BindingLoader) + # Get the properties this binding modifies + # before we merge the included ones. + last_modified_props = list(raw.get("properties", {}).keys()) + + # Map property names to their specifications: + # - first, _merge_includes() will recursively populate prop2specs with + # the properties specified by the included bindings + # - eventually, we'll update prop2specs with the properties + # this binding itself defines or modifies + self.prop2specs: Dict[str, 'PropertySpec'] = {} + # Merge any included files into self.raw. This also pulls in # inherited child binding definitions, so it has to be done # before initializing those. @@ -224,10 +246,11 @@ def __init__(self, path: Optional[str], fname2path: Dict[str, str], # Make sure this is a well defined object. self._check(require_compatible, require_description) - # Initialize look up tables. - self.prop2specs: Dict[str, 'PropertySpec'] = {} - for prop_name in self.raw.get("properties", {}).keys(): + # Update specs with the properties this binding defines or modifies. + for prop_name in last_modified_props: self.prop2specs[prop_name] = PropertySpec(prop_name, self) + + # Initialize look up tables. self.specifier2cells: Dict[str, List[str]] = {} for key, val in self.raw.items(): if key.endswith("-cells"): @@ -291,18 +314,41 @@ def _merge_includes(self, raw: dict, binding_path: Optional[str]) -> dict: if isinstance(include, str): # Simple scalar string case - _merge_props(merged, self._load_raw(include), None, binding_path, - False) + # Load YAML file and register property specs into prop2specs. + inc_raw = self._load_raw(include, self._inc_allowlist, + self._inc_blocklist) + + _merge_props(merged, inc_raw, None, binding_path, False) elif isinstance(include, list): # List of strings and maps. These types may be intermixed. for elem in include: if isinstance(elem, str): - _merge_props(merged, self._load_raw(elem), None, - binding_path, False) + # Load YAML file and register property specs into prop2specs. + inc_raw = self._load_raw(elem, self._inc_allowlist, + self._inc_blocklist) + + _merge_props(merged, inc_raw, None, binding_path, False) elif isinstance(elem, dict): name = elem.pop('name', None) + + # Merge this include property-allowlist filter + # with filters from including bindings. allowlist = elem.pop('property-allowlist', None) + if allowlist is not None: + if self._inc_allowlist: + allowlist.extend(self._inc_allowlist) + else: + allowlist = self._inc_allowlist + + # Merge this include property-blocklist filter + # with filters from including bindings. blocklist = elem.pop('property-blocklist', None) + if blocklist is not None: + if self._inc_blocklist: + blocklist.extend(self._inc_blocklist) + else: + blocklist = self._inc_blocklist + child_filter = elem.pop('child-binding', None) if elem: @@ -313,10 +359,12 @@ def _merge_includes(self, raw: dict, binding_path: Optional[str]) -> dict: _check_include_dict(name, allowlist, blocklist, child_filter, binding_path) - contents = self._load_raw(name) + # Load YAML file, and register (filtered) property specs + # into prop2specs. + contents = self._load_raw(name, + allowlist, blocklist, + child_filter) - _filter_properties(contents, allowlist, blocklist, - child_filter, binding_path) _merge_props(merged, contents, None, binding_path, False) else: _err(f"all elements in 'include:' in {binding_path} " @@ -336,11 +384,17 @@ def _merge_includes(self, raw: dict, binding_path: Optional[str]) -> dict: return raw - def _load_raw(self, fname: str) -> dict: + + def _load_raw(self, fname: str, + allowlist: Optional[List[str]] = None, + blocklist: Optional[List[str]] = None, + child_filter: Optional[dict] = None) -> dict: # Returns the contents of the binding given by 'fname' after merging - # any bindings it lists in 'include:' into it. 'fname' is just the - # basename of the file, so we check that there aren't multiple - # candidates. + # any bindings it lists in 'include:' into it, according to the given + # property filters. + # + # Will also register the (filtered) included property specs + # into prop2specs. path = self._fname2path.get(fname) @@ -352,8 +406,55 @@ def _load_raw(self, fname: str) -> dict: if not isinstance(contents, dict): _err(f'{path}: invalid contents, expected a mapping') + # Apply constraints to included YAML contents. + _filter_properties(contents, + allowlist, blocklist, + child_filter, self.path) + + # Register included property specs. + self._add_included_prop2specs(fname, contents, allowlist, blocklist) + return self._merge_includes(contents, path) + def _add_included_prop2specs(self, fname: str, contents: dict, + allowlist: Optional[List[str]] = None, + blocklist: Optional[List[str]] = None) -> None: + # Registers the properties specified by an included binding file + # into the properties this binding supports/requires (aka prop2specs). + # + # Consider "this" binding B includes I1 which itself includes I2. + # + # We assume to be called in that order: + # 1) _add_included_prop2spec(B, I1) + # 2) _add_included_prop2spec(B, I2) + # + # Where we don't want I2 "taking ownership" for properties + # modified by I1. + # + # So we: + # - first create a binding that represents the included file + # - then add the property specs defined by this binding to prop2specs, + # without overriding the specs modified by an including binding + # + # Note: Unfortunately, we can't cache these base bindings, + # as a same YAML file may be included with different filters + # (property-allowlist and such), leading to different contents. + + inc_binding = Binding( + self._fname2path[fname], + self._fname2path, + contents, + require_compatible=False, + require_description=False, + # Recursively pass filters to included bindings. + inc_allowlist=allowlist, + inc_blocklist=blocklist, + ) + + for prop, spec in inc_binding.prop2specs.items(): + if prop not in self.prop2specs: + self.prop2specs[prop] = spec + def _check(self, require_compatible: bool, require_description: bool): # Does sanity checking on the binding. diff --git a/scripts/dts/python-devicetree/tests/test-bindings-include/base.yaml b/scripts/dts/python-devicetree/tests/test-bindings-include/base.yaml new file mode 100644 index 00000000000..f564578b48d --- /dev/null +++ b/scripts/dts/python-devicetree/tests/test-bindings-include/base.yaml @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: BSD-3-Clause + +properties: + x: + type: int + y: + type: int diff --git a/scripts/dts/python-devicetree/tests/test-bindings-include/inc-base.yaml b/scripts/dts/python-devicetree/tests/test-bindings-include/inc-base.yaml new file mode 100644 index 00000000000..59dc45eab0d --- /dev/null +++ b/scripts/dts/python-devicetree/tests/test-bindings-include/inc-base.yaml @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: BSD-3-Clause + +include: base.yaml diff --git a/scripts/dts/python-devicetree/tests/test-bindings-include/modified.yaml b/scripts/dts/python-devicetree/tests/test-bindings-include/modified.yaml new file mode 100644 index 00000000000..3d8130c1aed --- /dev/null +++ b/scripts/dts/python-devicetree/tests/test-bindings-include/modified.yaml @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: BSD-3-Clause + +include: base.yaml + +properties: + x: + required: true diff --git a/scripts/dts/python-devicetree/tests/test-bindings-include/top-allows.yaml b/scripts/dts/python-devicetree/tests/test-bindings-include/top-allows.yaml new file mode 100644 index 00000000000..a4938eb0d67 --- /dev/null +++ b/scripts/dts/python-devicetree/tests/test-bindings-include/top-allows.yaml @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: BSD-3-Clause + +description: Test property-allowlist filters set by including bindings + +compatible: "top-allowlist" + +include: + - name: inc-base.yaml + property-allowlist: + - x diff --git a/scripts/dts/python-devicetree/tests/test-bindings-include/top-blocks.yaml b/scripts/dts/python-devicetree/tests/test-bindings-include/top-blocks.yaml new file mode 100644 index 00000000000..787db223a93 --- /dev/null +++ b/scripts/dts/python-devicetree/tests/test-bindings-include/top-blocks.yaml @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: BSD-3-Clause + +description: Test property-blocklist filters set by including bindings. + +compatible: "top-blocklist" + +include: + - name: inc-base.yaml + property-blocklist: + - x diff --git a/scripts/dts/python-devicetree/tests/test-bindings-include/top.yaml b/scripts/dts/python-devicetree/tests/test-bindings-include/top.yaml new file mode 100644 index 00000000000..8fb9320676d --- /dev/null +++ b/scripts/dts/python-devicetree/tests/test-bindings-include/top.yaml @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: BSD-3-Clause + +description: | + Top-level binding file for testing included property spec paths. + + base.yaml: specifies properties "x" and "y" + modified.yaml: includes base.yaml, modifies property "x" + top.yaml (this file): includes modified.yaml, specifies property "p" + + From the top-level binding, we expect: + - "x" was last modified in modified.yaml + - "y" was last modified in base.yaml + - "p" was last modified in top.yaml + +compatible: top-level + +include: modified.yaml + +properties: + p: + type: int diff --git a/scripts/dts/python-devicetree/tests/test_edtlib.py b/scripts/dts/python-devicetree/tests/test_edtlib.py index ca97fbcb9c2..a81aa929370 100644 --- a/scripts/dts/python-devicetree/tests/test_edtlib.py +++ b/scripts/dts/python-devicetree/tests/test_edtlib.py @@ -365,6 +365,35 @@ def test_include_filters(): assert set(child.prop2specs.keys()) == {'child-prop-1', 'child-prop-2', 'x', 'z'} # root level 'y' is blocked +def test_include_paths(): + '''Test "last modified" semantic for included bindings paths.''' + + fname2path = {'base.yaml': 'test-bindings-include/base.yaml', + 'modified.yaml': 'test-bindings-include/modified.yaml'} + + with from_here(): + top = edtlib.Binding('test-bindings-include/top.yaml', fname2path) + + assert 'modified.yaml' == os.path.basename(top.prop2specs["x"].path) + assert 'base.yaml' == os.path.basename(top.prop2specs["y"].path) + assert 'top.yaml' == os.path.basename(top.prop2specs["p"].path) + +def test_include_filters_included_bindings(): + '''Test filters set by including bindings.''' + fname2path = {'base.yaml': 'test-bindings-include/base.yaml', + 'inc-base.yaml': 'test-bindings-include/inc-base.yaml'} + + with from_here(): + top_allows = edtlib.Binding('test-bindings-include/top-allows.yaml', fname2path) + assert top_allows.prop2specs.get("x") + assert not top_allows.prop2specs.get("y") + + with from_here(): + top_blocks = edtlib.Binding('test-bindings-include/top-blocks.yaml', fname2path) + assert not top_blocks.prop2specs.get("x") + assert top_blocks.prop2specs.get("y") + + def test_bus(): '''Test 'bus:' and 'on-bus:' in bindings''' diff --git a/scripts/footprint/size_report b/scripts/footprint/size_report index becabeb25a9..414665c7641 100755 --- a/scripts/footprint/size_report +++ b/scripts/footprint/size_report @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (c) 2016, 2020 Intel Corporation +# Copyright (c) 2016, 2020-2024 Intel Corporation # # SPDX-License-Identifier: Apache-2.0 @@ -28,7 +28,6 @@ from anytree.exporter import DictExporter import elftools from elftools.elf.elffile import ELFFile -from elftools.elf.relocation import RelocationSection from elftools.elf.sections import SymbolTableSection from elftools.dwarf.descriptions import describe_form_class from elftools.dwarf.descriptions import ( @@ -69,9 +68,9 @@ def is_symbol_in_ranges(sym, ranges): """ for bound in ranges: if bound['start'] <= sym['st_value'] <= bound['end']: - return True + return bound - return False + return None def get_die_mapped_address(die, parser, dwarfinfo): @@ -128,7 +127,7 @@ def match_symbol_address(symlist, die, parser, dwarfinfo): def get_symbols(elf, addr_ranges): """ Fetch the symbols from the symbol table and put them - into ROM, RAM buckets. + into ROM, RAM, unassigned buckets. """ rom_syms = dict() ram_syms = dict() @@ -136,6 +135,7 @@ def get_symbols(elf, addr_ranges): rom_addr_ranges = addr_ranges['rom'] ram_addr_ranges = addr_ranges['ram'] + unassigned_addr_ranges = addr_ranges['unassigned'] for section in elf.iter_sections(): if isinstance(section, SymbolTableSection): @@ -147,24 +147,34 @@ def get_symbols(elf, addr_ranges): found_sec = False entry = {'name': sym.name, 'symbol': sym, - 'mapped_files': set()} + 'mapped_files': set(), + 'section': None} # If symbol is in ROM area? - if is_symbol_in_ranges(sym, rom_addr_ranges): + bound = is_symbol_in_ranges(sym, rom_addr_ranges) + if bound: if sym.name not in rom_syms: rom_syms[sym.name] = list() + entry['section'] = bound['name'] rom_syms[sym.name].append(entry) found_sec = True # If symbol is in RAM area? - if is_symbol_in_ranges(sym, ram_addr_ranges): + bound = is_symbol_in_ranges(sym, ram_addr_ranges) + if bound: if sym.name not in ram_syms: ram_syms[sym.name] = list() + entry['section'] = bound['name'] ram_syms[sym.name].append(entry) found_sec = True if not found_sec: - unassigned_syms['sym_name'] = entry + bound = is_symbol_in_ranges(sym, unassigned_addr_ranges) + if bound: + entry['section'] = bound['name'] + if sym.name not in unassigned_syms: + unassigned_syms[sym.name] = list() + unassigned_syms[sym.name].append(entry) ret = {'rom': rom_syms, 'ram': ram_syms, @@ -172,6 +182,18 @@ def get_symbols(elf, addr_ranges): return ret +def print_section_info(section, descr=""): + if args.verbose: + sec_size = section['sh_size'] + sec_start = section['sh_addr'] + sec_end = sec_start + (sec_size - 1 if sec_size else 0) + print(f"DEBUG: " + f"0x{sec_start:08x}-0x{sec_end:08x} " + f"{descr} '{section.name}': size={sec_size}, " + f"{section['sh_type']}, 0x{section['sh_flags']:08x}") +# + + def get_section_ranges(elf): """ Parse ELF header to find out the address ranges of ROM or RAM sections @@ -179,19 +201,26 @@ def get_section_ranges(elf): """ rom_addr_ranges = list() ram_addr_ranges = list() + unassigned_addr_ranges = list() + rom_size = 0 ram_size = 0 + unassigned_size = 0 for section in elf.iter_sections(): size = section['sh_size'] sec_start = section['sh_addr'] - sec_end = sec_start + size - 1 - bound = {'start': sec_start, 'end': sec_end} + sec_end = sec_start + (size - 1 if size else 0) + bound = {'start': sec_start, 'end': sec_end, 'name': section.name} + is_assigned = False if section['sh_type'] == 'SHT_NOBITS': # BSS and noinit sections ram_addr_ranges.append(bound) ram_size += size + is_assigned = True + print_section_info(section, "RAM bss section") + elif section['sh_type'] == 'SHT_PROGBITS': # Sections to be in flash or memory flags = section['sh_flags'] @@ -199,23 +228,37 @@ def get_section_ranges(elf): # Text section rom_addr_ranges.append(bound) rom_size += size + is_assigned = True + print_section_info(section, "ROM txt section") + elif (flags & SHF_WRITE_ALLOC) == SHF_WRITE_ALLOC: # Data occupies both ROM and RAM # since at boot, content is copied from ROM to RAM rom_addr_ranges.append(bound) rom_size += size - ram_addr_ranges.append(bound) ram_size += size + is_assigned = True + print_section_info(section, "ROM,RAM section") + elif (flags & SHF_ALLOC) == SHF_ALLOC: # Read only data rom_addr_ranges.append(bound) rom_size += size + is_assigned = True + print_section_info(section, "ROM r/o section") + + if not is_assigned: + print_section_info(section, "unassigned section") + unassigned_addr_ranges.append(bound) + unassigned_size += size ret = {'rom': rom_addr_ranges, 'rom_total_size': rom_size, 'ram': ram_addr_ranges, - 'ram_total_size': ram_size} + 'ram_total_size': ram_size, + 'unassigned': unassigned_addr_ranges, + 'unassigned_total_size': unassigned_size} return ret @@ -249,7 +292,7 @@ def get_die_filename(die, lineprog): return path -def do_simple_name_matching(elf, symbol_dict, processed): +def do_simple_name_matching(dwarfinfo, symbol_dict, processed): """ Sequentially process DIEs in compiler units with direct file mappings within the DIEs themselves, and do simply matching between DIE names @@ -260,7 +303,6 @@ def do_simple_name_matching(elf, symbol_dict, processed): unmapped_symbols = processed['unmapped_symbols'] newly_mapped_syms = set() - dwarfinfo = elf.get_dwarf_info() location_lists = dwarfinfo.location_lists() location_parser = LocationParser(location_lists) @@ -370,7 +412,7 @@ def mark_address_aliases(symbol_dict, processed): processed['unmapped_symbols'] = unmapped_symbols -def do_address_range_matching(elf, symbol_dict, processed): +def do_address_range_matching(dwarfinfo, symbol_dict, processed): """ Match symbols indirectly using address ranges. @@ -391,7 +433,6 @@ def do_address_range_matching(elf, symbol_dict, processed): unmapped_symbols = processed['unmapped_symbols'] newly_mapped_syms = set() - dwarfinfo = elf.get_dwarf_info() location_lists = dwarfinfo.location_lists() location_parser = LocationParser(location_lists) @@ -532,13 +573,16 @@ class TreeNode(NodeMixin): A symbol node. """ - def __init__(self, name, identifier, size=0, parent=None, children=None, address=0): + def __init__(self, name, identifier, size=0, parent=None, children=None, address=None, section=None): super().__init__() self._name = name self._size = size self.parent = parent self._identifier = identifier - self.address = address + if address is not None: + self.address = address + if section is not None: + self.section = section if children: self.children = children @@ -584,7 +628,7 @@ def generate_any_tree(symbol_dict, total_size, path_prefix): # A set of helper function for building a simple tree with a path-like # hierarchy. - def _insert_one_elem(root, path, size, addr): + def _insert_one_elem(root, path, size, addr, section): cur = None node = None parent = root @@ -597,12 +641,28 @@ def generate_any_tree(symbol_dict, total_size, path_prefix): results = findall_by_attr(root, cur, name="_identifier") if results: item = results[0] - item._size += size - parent = item + if not hasattr(item, 'address'): + # Passing down through a non-terminal parent node. + parent = item + parent._size += size + else: + # Another symbol node here with the same name; stick to its parent as well. + parent = item.parent + node = TreeNode(name=str(part), identifier=cur, size=size, parent=parent) else: + # There is no such terminal symbol in the tree yet; let's add it. if node: parent = node - node = TreeNode(name=str(part), identifier=cur, size=size, parent=parent, address=addr) + node = TreeNode(name=str(part), identifier=cur, size=size, parent=parent) + if node: + # Set memory block address and section name properties only for terminal symbol nodes. + # Don't do it on file- and directory- level parent nodes. + node.address = addr + node.section = section + else: + # normally this shouldn't happen; just to detect data or logic errors. + print(f"ERROR: no end node created for {root}, {path}, 0x{addr:08x}+{size}@{section}") + # # Mapping paths to tree nodes path_node_map = [ @@ -619,6 +679,7 @@ def generate_any_tree(symbol_dict, total_size, path_prefix): for symbol in sym: size = get_symbol_size(symbol['symbol']) addr = get_symbol_addr(symbol['symbol']) + section = symbol['section'] for file in symbol['mapped_files']: path = Path(file, name) if path.is_absolute(): @@ -636,7 +697,7 @@ def generate_any_tree(symbol_dict, total_size, path_prefix): else: dest_node = node_no_paths - _insert_one_elem(dest_node, path, size, addr) + _insert_one_elem(dest_node, path, size, addr, section) if node_zephyr_base is not root: @@ -683,18 +744,21 @@ def print_any_tree(root, total_size, depth): """ Print the symbol tree. """ - print('{:101s} {:7s} {:8s} {:10s}'.format( - Fore.YELLOW + "Path", "Size", "%", "Address" + Fore.RESET)) - print('=' * 126) + print('{:98s} {:>7s} {:>7s} {:11s} {:16s}'.format( + Fore.YELLOW + "Path", "Size", "%", " Address", "Section" + Fore.RESET)) + print('=' * 138) for row in RenderTree(root, childiter=node_sort, maxlevel=depth): f = len(row.pre) + len(row.node._name) s = str(row.node._size).rjust(100-f) percent = 100 * float(row.node._size) / float(total_size) hex_addr = "-" + section_name = "" cc = cr = "" if not row.node.children: - if row.node._name != "(hidden)": + if hasattr(row.node, 'section'): + section_name = row.node.section + if hasattr(row.node, 'address'): hex_addr = "0x{:08x}".format(row.node.address) cc = Fore.CYAN cr = Fore.RESET @@ -702,8 +766,8 @@ def print_any_tree(root, total_size, depth): cc = Fore.GREEN cr = Fore.RESET - print(f"{row.pre}{cc}{row.node._name} {s} {cr}{Fore.BLUE}{percent:6.2f}%{Fore.RESET} {hex_addr}") - print('=' * 126) + print(f"{row.pre}{cc}{row.node._name} {s} {cr}{Fore.BLUE}{percent:6.2f}%{Fore.RESET} {hex_addr} {section_name}") + print('=' * 138) print(f'{total_size:>101}') @@ -755,22 +819,21 @@ def main(): elif args.target == 'all': targets = ['rom', 'ram'] - for t in targets: - - elf = ELFFile(open(args.kernel, "rb")) - - assert elf.has_dwarf_info(), "ELF file has no DWARF information" + elf = ELFFile(open(args.kernel, "rb")) + assert elf.has_dwarf_info(), "ELF file has no DWARF information" - set_global_machine_arch(elf.get_machine_arch()) + set_global_machine_arch(elf.get_machine_arch()) + addr_ranges = get_section_ranges(elf) + dwarfinfo = elf.get_dwarf_info() - addr_ranges = get_section_ranges(elf) + for t in targets: symbols = get_symbols(elf, addr_ranges) for sym in symbols['unassigned'].values(): - print("WARN: Symbol '{0}' is not in RAM or ROM".format(sym['name'])) - - symbol_dict = None + for sym_entry in sym: + print(f"WARN: Symbol '{sym_entry['name']}' section '{sym_entry['section']}' " + "is not in RAM or ROM.") if args.json: jsonout = args.json @@ -786,9 +849,9 @@ def main(): "mapped_addr": set(), "unmapped_symbols": set(symbol_dict.keys())} - do_simple_name_matching(elf, symbol_dict, processed) + do_simple_name_matching(dwarfinfo, symbol_dict, processed) mark_address_aliases(symbol_dict, processed) - do_address_range_matching(elf, symbol_dict, processed) + do_address_range_matching(dwarfinfo, symbol_dict, processed) mark_address_aliases(symbol_dict, processed) common_path_prefix = find_common_path_prefix(symbol_dict) set_root_path_for_unmapped_symbols(symbol_dict, ranges, processed) diff --git a/scripts/kconfig/hardened.csv b/scripts/kconfig/hardened.csv index a8caf3a87cc..f55899569e4 100644 --- a/scripts/kconfig/hardened.csv +++ b/scripts/kconfig/hardened.csv @@ -2,8 +2,8 @@ BOOT_BANNER,n BOOT_DELAY,0 BOUNDS_CHECK_BYPASS_MITIGATION,y BT_CONN_DISABLE_SECURITY,n -BT_DEBUG_KEYS,n -BT_DEBUG_SMP,n +BT_KEYS_LOG_LEVEL_DBG,n +BT_SMP_LOG_LEVEL_DBG,n BT_FIXED_PASSKEY,n BT_LOG_SNIFFER_INFO,n BT_OOB_DATA_FIXED,n diff --git a/scripts/list_boards.py b/scripts/list_boards.py index 597ecf91809..6b810d0e286 100755 --- a/scripts/list_boards.py +++ b/scripts/list_boards.py @@ -15,9 +15,14 @@ import list_hardware from list_hardware import unique_paths +try: + from yaml import CSafeLoader as SafeLoader +except ImportError: + from yaml import SafeLoader + BOARD_SCHEMA_PATH = str(Path(__file__).parent / 'schemas' / 'board-schema.yml') with open(BOARD_SCHEMA_PATH, 'r') as f: - board_schema = yaml.safe_load(f.read()) + board_schema = yaml.load(f.read(), Loader=SafeLoader) BOARD_YML = 'board.yml' @@ -178,7 +183,7 @@ def load_v2_boards(board_name, board_yml, systems): boards = [] if board_yml.is_file(): with board_yml.open('r') as f: - b = yaml.safe_load(f.read()) + b = yaml.load(f.read(), Loader=SafeLoader) try: pykwalify.core.Core(source_data=b, schema_data=board_schema).validate() @@ -231,6 +236,17 @@ def load_v2_boards(board_name, board_yml, systems): return boards +# Note that this does not share the args.board functionality of find_v2_boards +def find_v2_board_dirs(args): + dirs = [] + board_files = [] + for root in unique_paths(args.board_roots): + board_files.extend((root / 'boards').rglob(BOARD_YML)) + + dirs = [board_yml.parent for board_yml in board_files if board_yml.is_file()] + return dirs + + def find_v2_boards(args): root_args = argparse.Namespace(**{'soc_roots': args.soc_roots}) systems = list_hardware.find_v2_systems(root_args) diff --git a/scripts/list_hardware.py b/scripts/list_hardware.py index d1f31a4712e..cdb0e059cc9 100755 --- a/scripts/list_hardware.py +++ b/scripts/list_hardware.py @@ -12,14 +12,19 @@ import yaml import re +try: + from yaml import CSafeLoader as SafeLoader +except ImportError: + from yaml import SafeLoader + SOC_SCHEMA_PATH = str(Path(__file__).parent / 'schemas' / 'soc-schema.yml') with open(SOC_SCHEMA_PATH, 'r') as f: - soc_schema = yaml.safe_load(f.read()) + soc_schema = yaml.load(f.read(), Loader=SafeLoader) ARCH_SCHEMA_PATH = str(Path(__file__).parent / 'schemas' / 'arch-schema.yml') with open(ARCH_SCHEMA_PATH, 'r') as f: - arch_schema = yaml.safe_load(f.read()) + arch_schema = yaml.load(f.read(), Loader=SafeLoader) SOC_YML = 'soc.yml' ARCHS_YML_PATH = PurePath('arch/archs.yml') @@ -35,7 +40,7 @@ def __init__(self, folder='', soc_yaml=None): return try: - data = yaml.safe_load(soc_yaml) + data = yaml.load(soc_yaml, Loader=SafeLoader) pykwalify.core.Core(source_data=data, schema_data=soc_schema).validate() except (yaml.YAMLError, pykwalify.errors.SchemaError) as e: @@ -188,7 +193,7 @@ def find_v2_archs(args): if Path(archs_yml).is_file(): with Path(archs_yml).open('r') as f: - archs = yaml.safe_load(f.read()) + archs = yaml.load(f.read(), Loader=SafeLoader) try: pykwalify.core.Core(source_data=archs, schema_data=arch_schema).validate() diff --git a/scripts/list_shields.py b/scripts/list_shields.py new file mode 100755 index 00000000000..dfbf2580eb4 --- /dev/null +++ b/scripts/list_shields.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python3 + +# Copyright (c) 2024 Vestas Wind Systems A/S +# Copyright (c) 2020 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +import argparse +from dataclasses import dataclass +from pathlib import Path + +# +# This is shared code between the build system's 'shields' target +# and the 'west shields' extension command. If you change it, make +# sure to test both ways it can be used. +# +# (It's done this way to keep west optional, making it possible to run +# 'ninja shields' in a build directory without west installed.) +# + +@dataclass(frozen=True) +class Shield: + name: str + dir: Path + +def shield_key(shield): + return shield.name + +def find_shields(args): + ret = [] + + for root in args.board_roots: + for shields in find_shields_in(root): + ret.append(shields) + + return sorted(ret, key=shield_key) + +def find_shields_in(root): + shields = root / 'boards' / 'shields' + ret = [] + + for maybe_shield in (shields).iterdir(): + if not maybe_shield.is_dir(): + continue + for maybe_kconfig in maybe_shield.iterdir(): + if maybe_kconfig.name == 'Kconfig.shield': + for maybe_overlay in maybe_shield.iterdir(): + file_name = maybe_overlay.name + if file_name.endswith('.overlay'): + shield_name = file_name[:-len('.overlay')] + ret.append(Shield(shield_name, maybe_shield)) + + return sorted(ret, key=shield_key) + +def parse_args(): + parser = argparse.ArgumentParser(allow_abbrev=False) + add_args(parser) + return parser.parse_args() + +def add_args(parser): + # Remember to update west-completion.bash if you add or remove + # flags + parser.add_argument("--board-root", dest='board_roots', default=[], + type=Path, action='append', + help='add a board root, may be given more than once') + +def dump_shields(shields): + for shield in shields: + print(f' {shield.name}') + +if __name__ == '__main__': + dump_shields(find_shields(parse_args())) diff --git a/scripts/logging/dictionary/database_gen.py b/scripts/logging/dictionary/database_gen.py index 663adb3a365..5060ef3b928 100755 --- a/scripts/logging/dictionary/database_gen.py +++ b/scripts/logging/dictionary/database_gen.py @@ -143,7 +143,7 @@ def find_elf_sections(elf, sh_name): def get_kconfig_symbols(elf): """Get kconfig symbols from the ELF file""" for section in elf.iter_sections(): - if isinstance(section, SymbolTableSection): + if isinstance(section, SymbolTableSection) and section['sh_type'] != 'SHT_DYNSYM': return {sym.name: sym.entry.st_value for sym in section.iter_symbols() if sym.name.startswith("CONFIG_")} @@ -254,6 +254,9 @@ def process_kconfigs(elf, database): if arch['kconfig'] in kconfigs: database.set_arch(name) break + else: + logger.error("Did not found architecture") + sys.exit(1) # Put some kconfigs into the database # diff --git a/scripts/logging/dictionary/dictionary_parser/log_database.py b/scripts/logging/dictionary/dictionary_parser/log_database.py index 1baccfe3b69..3e7b37e396f 100644 --- a/scripts/logging/dictionary/dictionary_parser/log_database.py +++ b/scripts/logging/dictionary/dictionary_parser/log_database.py @@ -46,6 +46,9 @@ # for explanation. "extra_string_section": ['datas'], }, + "posix" : { + "kconfig": "CONFIG_ARCH_POSIX", + }, "riscv" : { "kconfig": "CONFIG_RISCV", }, diff --git a/scripts/native_simulator/common/src/include/nsi_hws_models_if.h b/scripts/native_simulator/common/src/include/nsi_hws_models_if.h index f7af34e5c5d..77f28f42e67 100644 --- a/scripts/native_simulator/common/src/include/nsi_hws_models_if.h +++ b/scripts/native_simulator/common/src/include/nsi_hws_models_if.h @@ -35,7 +35,7 @@ struct nsi_hw_event_st { */ #define NSI_HW_EVENT(t, fn, prio) \ static const struct nsi_hw_event_st NSI_CONCAT(NSI_CONCAT(__nsi_hw_event_, fn), t) \ - __attribute__((__used__)) \ + __attribute__((__used__)) NSI_NOASAN \ __attribute__((__section__(".nsi_hw_event_" NSI_STRINGIFY(prio)))) \ = { \ .callback = fn, \ diff --git a/scripts/native_simulator/common/src/include/nsi_main_semipublic.h b/scripts/native_simulator/common/src/include/nsi_main_semipublic.h new file mode 100644 index 00000000000..12486e392be --- /dev/null +++ b/scripts/native_simulator/common/src/include/nsi_main_semipublic.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef NSI_COMMON_SRC_INCL_NSI_MAIN_SEMIPUBLIC_H +#define NSI_COMMON_SRC_INCL_NSI_MAIN_SEMIPUBLIC_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * These APIs are exposed for special use cases in which a developer needs to + * replace the native simulator main loop. + * An example of such a case is LLVMs fuzzing support. For this one sets + * NSI_NO_MAIN, and provides an specialized main() or hooks into the tooling + * provided main(). + * + * These APIs should be used with care, and not be used when the native + * simulator main() is built in. + * + * Check nsi_main.c for more information. + */ + +void nsi_init(int argc, char *argv[]); +void nsi_exec_for(uint64_t us); + +#ifdef __cplusplus +} +#endif + +#endif /* NSI_COMMON_SRC_INCL_NSI_MAIN_SEMIPUBLIC_H */ diff --git a/scripts/native_simulator/common/src/include/nsi_utils.h b/scripts/native_simulator/common/src/include/nsi_utils.h index 996ad635409..997eac30005 100644 --- a/scripts/native_simulator/common/src/include/nsi_utils.h +++ b/scripts/native_simulator/common/src/include/nsi_utils.h @@ -29,4 +29,14 @@ #define NSI_FUNC_NORETURN __attribute__((__noreturn__)) +#if defined(__clang__) + /* The address sanitizer in llvm adds padding (redzones) after data + * But for those we are re-grouping using the linker script + * we cannot have that extra padding as we intend to iterate over them + */ +#define NSI_NOASAN __attribute__((no_sanitize("address"))) +#else +#define NSI_NOASAN +#endif + #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 9b5c566fae0..34b4876a7e8 100644 --- a/scripts/native_simulator/common/src/main.c +++ b/scripts/native_simulator/common/src/main.c @@ -52,9 +52,11 @@ NSI_FUNC_NORETURN void nsi_exit(int exit_code) /** * 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() + * run via nsi_hws_one_event() + * + * Note: This API should normally only be called by the native simulator main() */ -static void nsi_init(int argc, char *argv[]) +void nsi_init(int argc, char *argv[]) { /* * Let's ensure that even if we are redirecting to a file, we get stdout @@ -92,6 +94,8 @@ static void nsi_init(int argc, char *argv[]) * return. Note that this does not affect event timing, so the "next * event" may be significantly after the request if the hardware has * not been configured to e.g. send an interrupt when expected. + * + * Note: This API should normally only be called by the native simulator main() */ void nsi_exec_for(uint64_t us) { @@ -102,7 +106,7 @@ void nsi_exec_for(uint64_t us) } while (nsi_hws_get_time() < (start + us)); } -#ifndef NSI_LIBFUZZER +#ifndef NSI_NO_MAIN /** * @@ -121,39 +125,4 @@ int main(int argc, char *argv[]) return 1; /* LCOV_EXCL_LINE */ } -#else /* NSI_LIBFUZZER */ - -/** - * Entry point for fuzzing (when enabled). Works by placing the data - * into two known symbols, triggering an app-visible interrupt, and - * then letting the simulator run for a fixed amount of time (intended to be - * "long enough" to handle the event and reach a quiescent state - * again) - */ -uint8_t *nsi_fuzz_buf, nsi_fuzz_sz; - -int LLVMFuzzerTestOneInput(const uint8_t *data, size_t sz) -{ - static bool nsi_initialized; - - if (!nsi_initialized) { - nsi_init(0, NULL); - nsi_initialized = true; - } - - /* Provide the fuzz data to the embedded OS as an interrupt, with - * "DMA-like" data placed into nsi_fuzz_buf/sz - */ - nsi_fuzz_buf = (void *)data; - nsi_fuzz_sz = sz; - hw_irq_ctrl_set_irq(NSI_FUZZ_IRQ); - - /* Give the OS time to process whatever happened in that - * interrupt and reach an idle state. - */ - nsi_exec_for(NSI_FUZZ_TIME); - - return 0; -} - -#endif /* NSI_LIBFUZZER */ +#endif /* NSI_NO_MAIN */ diff --git a/scripts/native_simulator/common/src/nsi_tasks.h b/scripts/native_simulator/common/src/nsi_tasks.h index 5223ab08c03..584898bc5ee 100644 --- a/scripts/native_simulator/common/src/nsi_tasks.h +++ b/scripts/native_simulator/common/src/nsi_tasks.h @@ -51,7 +51,7 @@ extern "C" { */ #define NSI_TASK(fn, level, prio) \ static void (* const NSI_CONCAT(__nsi_task_, fn))(void) \ - __attribute__((__used__)) \ + __attribute__((__used__)) NSI_NOASAN \ __attribute__((__section__(".nsi_" #level NSI_STRINGIFY(prio) "_task")))\ = fn; \ /* Let's cross-check the macro level is a valid one, so we don't silently drop it */ \ 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 b5560650c1b..3f73045f899 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 @@ -14,6 +14,7 @@ import time from datetime import datetime from pathlib import Path +from serial import SerialException from twister_harness.exceptions import ( TwisterHarnessException, @@ -69,14 +70,23 @@ def launch(self) -> None: if self.device_config.type != 'hardware': self._flash_and_run() + self._device_run.set() + self._start_reader_thread() + self.connect() + return self._device_run.set() self._start_reader_thread() - self.connect() - if self.device_config.type == 'hardware': + if self.device_config.flash_before: + # For hardware devices with shared USB or software USB, connect after flashing. + # Retry for up to 10 seconds for USB-CDC based devices to enumerate. + self._flash_and_run() + self.connect(retry_s = 10) + else: # On hardware, flash after connecting to COM port, otherwise some messages # from target can be lost. + self.connect() self._flash_and_run() def close(self) -> None: @@ -89,7 +99,7 @@ def close(self) -> None: self._device_run.clear() self._join_reader_thread() - def connect(self) -> None: + def connect(self, retry_s: int = 0) -> None: """Connect to device - allow for output gathering.""" if self.is_device_connected(): logger.debug('Device already connected') @@ -98,7 +108,20 @@ def connect(self) -> None: msg = 'Cannot connect to not working device' logger.error(msg) raise TwisterHarnessException(msg) - self._connect_device() + + if retry_s > 0: + retry_cycles = retry_s * 10 + for i in range(retry_cycles): + try: + self._connect_device() + break + except SerialException: + if i == retry_cycles - 1: + raise + time.sleep(0.1) + else: + self._connect_device() + self._device_connected.set() def disconnect(self) -> None: 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 5a5a845c3a1..98375873eb9 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 @@ -66,6 +66,9 @@ def _prepare_runner_args(self) -> tuple[list[str], list[str]]: extra_args: list[str] = [] runner = self.device_config.runner base_args.extend(['--runner', runner]) + if self.device_config.runner_params: + for param in self.device_config.runner_params: + extra_args.append(param) if board_id := self.device_config.id: if runner == 'pyocd': extra_args.append('--board-id') @@ -79,6 +82,9 @@ def _prepare_runner_args(self) -> tuple[list[str], list[str]]: elif runner == 'openocd' and self.device_config.product == 'EDBG CMSIS-DAP': extra_args.append('--cmd-pre-init') extra_args.append(f'cmsis_dap_serial {board_id}') + elif runner == "openocd" and self.device_config.product == "LPC-LINK2 CMSIS-DAP": + extra_args.append("--cmd-pre-init") + extra_args.append(f'adapter serial {board_id}') elif runner == 'jlink': base_args.append(f'--tool-opt=-SelectEmuBySN {board_id}') elif runner == 'stm32cubeprogrammer': 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 0c5cf2ab839..60537608357 100644 --- a/scripts/pylib/pytest-twister-harness/src/twister_harness/plugin.py +++ b/scripts/pylib/pytest-twister-harness/src/twister_harness/plugin.py @@ -67,6 +67,11 @@ def pytest_addoption(parser: pytest.Parser): '--runner', help='Use the specified west runner (pyocd, nrfjprog, etc.).' ) + twister_harness_group.addoption( + '--runner-params', + action='append', + help='Use the specified west runner params.' + ) twister_harness_group.addoption( '--device-id', help='ID of connected hardware device (for example 000682459367).' @@ -79,6 +84,13 @@ def pytest_addoption(parser: pytest.Parser): '--device-serial-pty', help='Script for controlling pseudoterminal.' ) + twister_harness_group.addoption( + '--flash-before', + type=bool, + help='Flash device before attaching to serial port' + 'This is useful for devices that share the same port for programming' + 'and serial console, or use soft-USB, where flash must come first.' + ) twister_harness_group.addoption( '--west-flash-extra-args', help='Extend parameters for west flash. ' diff --git a/scripts/pylib/pytest-twister-harness/src/twister_harness/twister_harness_config.py b/scripts/pylib/pytest-twister-harness/src/twister_harness/twister_harness_config.py index bcb88715d59..6ab26c3e8f4 100644 --- a/scripts/pylib/pytest-twister-harness/src/twister_harness/twister_harness_config.py +++ b/scripts/pylib/pytest-twister-harness/src/twister_harness/twister_harness_config.py @@ -22,9 +22,11 @@ class DeviceConfig: serial: str = '' baud: int = 115200 runner: str = '' + runner_params: list[str] = field(default_factory=list, repr=False) id: str = '' product: str = '' serial_pty: str = '' + flash_before: bool = False west_flash_extra_args: list[str] = field(default_factory=list, repr=False) name: str = '' pre_script: Path | None = None @@ -46,6 +48,9 @@ def create(cls, config: pytest.Config) -> TwisterHarnessConfig: west_flash_extra_args: list[str] = [] if config.option.west_flash_extra_args: west_flash_extra_args = [w.strip() for w in config.option.west_flash_extra_args.split(',')] + runner_params: list[str] = [] + if config.option.runner_params: + runner_params = [w.strip() for w in config.option.runner_params] device_from_cli = DeviceConfig( type=config.option.device_type, build_dir=_cast_to_path(config.option.build_dir), @@ -54,9 +59,11 @@ def create(cls, config: pytest.Config) -> TwisterHarnessConfig: serial=config.option.device_serial, baud=config.option.device_serial_baud, runner=config.option.runner, + runner_params=runner_params, id=config.option.device_id, product=config.option.device_product, serial_pty=config.option.device_serial_pty, + flash_before=bool(config.option.flash_before), west_flash_extra_args=west_flash_extra_args, pre_script=_cast_to_path(config.option.pre_script), post_script=_cast_to_path(config.option.post_script), diff --git a/scripts/pylib/pytest-twister-harness/tests/device/hardware_adapter_test.py b/scripts/pylib/pytest-twister-harness/tests/device/hardware_adapter_test.py index 5655c4f3f72..214a6080877 100644 --- a/scripts/pylib/pytest-twister-harness/tests/device/hardware_adapter_test.py +++ b/scripts/pylib/pytest-twister-harness/tests/device/hardware_adapter_test.py @@ -128,6 +128,43 @@ def test_if_get_command_returns_proper_string_8(patched_which, device: HardwareA ] +@mock.patch('shutil.which', return_value='west') +def test_if_get_command_returns_proper_string_with_runner_params_1(patched_which, device: HardwareAdapter) -> None: + device.device_config.build_dir = Path('build') + device.device_config.runner_params = ['--runner-param1', 'runner-param2'] + device.generate_command() + assert isinstance(device.command, list) + assert device.command == [ + 'west', 'flash', '--skip-rebuild', '--build-dir', 'build', + '--runner', 'runner', '--', '--runner-param1', 'runner-param2' + ] + + +@mock.patch('shutil.which', return_value='west') +def test_if_get_command_returns_proper_string_with_runner_params_2(patched_which, device: HardwareAdapter) -> None: + device.device_config.build_dir = Path('build') + device.device_config.runner = 'openocd' + device.device_config.runner_params = [ + '--cmd-pre-init', 'adapter serial FT1LRSRD', + '--cmd-pre-init', 'source [find interface/ftdi/jtag-lock-pick_tiny_2.cfg]', + '--cmd-pre-init', 'transport select swd', + '--cmd-pre-init', 'source [find target/nrf52.cfg]', + '--cmd-pre-init', 'adapter speed 10000', + ] + device.device_config.product = 'JTAG-lock-pick Tiny 2' + device.generate_command() + assert isinstance(device.command, list) + assert device.command == [ + 'west', 'flash', '--skip-rebuild', '--build-dir', 'build', + '--runner', 'openocd', '--', + '--cmd-pre-init', 'adapter serial FT1LRSRD', + '--cmd-pre-init', 'source [find interface/ftdi/jtag-lock-pick_tiny_2.cfg]', + '--cmd-pre-init', 'transport select swd', + '--cmd-pre-init', 'source [find target/nrf52.cfg]', + '--cmd-pre-init', 'adapter speed 10000', + ] + + @mock.patch('shutil.which', return_value='west') def test_if_get_command_returns_proper_string_with_west_flash_extra_args( patched_which, device: HardwareAdapter diff --git a/scripts/pylib/twister/twisterlib/coverage.py b/scripts/pylib/twister/twisterlib/coverage.py index 90d523e793a..1cc870f652e 100644 --- a/scripts/pylib/twister/twisterlib/coverage.py +++ b/scripts/pylib/twister/twisterlib/coverage.py @@ -145,6 +145,7 @@ class Lcov(CoverageTool): def __init__(self, jobs=None): super().__init__() self.ignores = [] + self.ignore_branch_patterns = [] self.output_formats = "lcov,html" self.version = self.get_version() self.jobs = jobs @@ -170,6 +171,9 @@ def add_ignore_file(self, pattern): def add_ignore_directory(self, pattern): self.ignores.append('*/' + pattern + '/*') + def add_ignore_branch_pattern(self, pattern): + self.ignore_branch_patterns.append(pattern) + @property def is_lcov_v2(self): return self.version.startswith("2") @@ -253,6 +257,7 @@ class Gcovr(CoverageTool): def __init__(self): super().__init__() self.ignores = [] + self.ignore_branch_patterns = [] self.output_formats = "html" self.version = self.get_version() @@ -279,6 +284,9 @@ def add_ignore_file(self, pattern): def add_ignore_directory(self, pattern): self.ignores.append(".*/" + pattern + '/.*') + def add_ignore_branch_pattern(self, pattern): + self.ignore_branch_patterns.append(pattern) + @staticmethod def _interleave_list(prefix, list): tuple_list = [(prefix, item) for item in list] @@ -293,6 +301,7 @@ def _generate(self, outdir, coveragelog): ztestfile = os.path.join(outdir, "ztest.json") excludes = Gcovr._interleave_list("-e", self.ignores) + excludes += Gcovr._interleave_list("--exclude-branches-by-pattern", self.ignore_branch_patterns) # Different ifdef-ed implementations of the same function should not be # in conflict treated by GCOVR as separate objects for coverage statistics. @@ -384,5 +393,8 @@ def run_coverage(testplan, options): coverage_tool.add_ignore_file('generated') coverage_tool.add_ignore_directory('tests') coverage_tool.add_ignore_directory('samples') + # Ignore branch coverage on LOG_* and LOG_HEXDUMP_* macros + # Branch misses are due to the implementation of Z_LOG2 and cannot be avoided + coverage_tool.add_ignore_branch_pattern(r"^\s*LOG_(?:HEXDUMP_)?(?:DBG|INF|WRN|ERR)\(.*") 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 43c05750bf8..85b7cdb371e 100644 --- a/scripts/pylib/twister/twisterlib/environment.py +++ b/scripts/pylib/twister/twisterlib/environment.py @@ -72,7 +72,7 @@ def add_parse_arguments(parser = None): run_group_option = parser.add_mutually_exclusive_group() - device = parser.add_mutually_exclusive_group(required="--device-testing" in sys.argv) + device = parser.add_mutually_exclusive_group() test_or_build = parser.add_mutually_exclusive_group() @@ -178,7 +178,7 @@ def add_parse_arguments(parser = None): parser.add_argument("--flash-before", action="store_true", default=False, help="""Flash device before attaching to serial port. This is useful for devices that share the same port for programming - and serial console, where flash must come first. + and serial console, or use soft-USB, where flash must come first. """) test_or_build.add_argument( @@ -602,12 +602,24 @@ def add_parse_arguments(parser = None): help="""Create a report with a custom name. """) + parser.add_argument( + "--report-summary", action="store", nargs='?', type=int, const=0, + help="Show failed/error report from latest run. Default shows all items found. " + "However, you can specify the number of items (e.g. --report-summary 15). " + "It also works well with the --outdir switch.") + parser.add_argument( "--report-suffix", help="""Add a suffix to all generated file names, for example to add a version or a commit ID. """) + parser.add_argument( + "--report-all-options", action="store_true", + help="""Show all command line options applied, including defaults, as + environment.options object in twister.json. Default: show only non-default settings. + """) + parser.add_argument( "--retry-failed", type=int, default=0, help="Retry failing tests again, up to the number of times specified.") @@ -738,7 +750,7 @@ def add_parse_arguments(parser = None): return parser -def parse_arguments(parser, args, options = None): +def parse_arguments(parser, args, options = None, on_init=True): if options is None: options = parser.parse_args(args) @@ -782,7 +794,7 @@ def parse_arguments(parser, args, options = None): if options.coverage: options.enable_coverage = True - if not options.coverage_platform: + if options.enable_coverage and not options.coverage_platform: options.coverage_platform = options.platform if options.coverage_formats: @@ -796,6 +808,10 @@ def parse_arguments(parser, args, options = None): logger.error("valgrind enabled but valgrind executable not found") sys.exit(1) + if (not options.device_testing) and (options.device_serial or options.device_serial_pty or options.hardware_map): + logger.error("Use --device-testing with --device-serial, or --device-serial-pty, or --hardware-map.") + sys.exit(1) + if options.device_testing and (options.device_serial or options.device_serial_pty) and len(options.platform) != 1: logger.error("When --device-testing is used with --device-serial " "or --device-serial-pty, exactly one platform must " @@ -856,13 +872,13 @@ def parse_arguments(parser, args, options = None): # Strip off the initial "--" following validation. options.extra_test_args = options.extra_test_args[1:] - if not options.allow_installed_plugin and PYTEST_PLUGIN_INSTALLED: + if on_init and not options.allow_installed_plugin and PYTEST_PLUGIN_INSTALLED: logger.error("By default Twister should work without pytest-twister-harness " "plugin being installed, so please, uninstall it by " "`pip uninstall pytest-twister-harness` and `git clean " "-dxf scripts/pylib/pytest-twister-harness`.") sys.exit(1) - elif options.allow_installed_plugin and PYTEST_PLUGIN_INSTALLED: + elif on_init and options.allow_installed_plugin and PYTEST_PLUGIN_INSTALLED: logger.warning("You work with installed version of " "pytest-twister-harness plugin.") @@ -874,12 +890,13 @@ def strip_ansi_sequences(s: str) -> str: class TwisterEnv: - def __init__(self, options=None) -> None: + def __init__(self, options=None, default_options=None) -> None: self.version = "Unknown" self.toolchain = None self.commit_date = "Unknown" self.run_date = None self.options = options + self.default_options = default_options if options and options.ninja: self.generator_cmd = "ninja" @@ -914,6 +931,18 @@ def __init__(self, options=None) -> None: self.alt_config_root = options.alt_config_root if options else None + def non_default_options(self) -> dict: + """Returns current command line options which are set to non-default values.""" + diff = {} + if not self.options or not self.default_options: + return diff + dict_options = vars(self.options) + dict_default = vars(self.default_options) + for k in dict_options.keys(): + if k not in dict_default or dict_options[k] != dict_default[k]: + diff[k] = dict_options[k] + return diff + def discover(self): self.check_zephyr_version() self.get_toolchain() diff --git a/scripts/pylib/twister/twisterlib/handlers.py b/scripts/pylib/twister/twisterlib/handlers.py index c8399a59ce5..414f89f207a 100755 --- a/scripts/pylib/twister/twisterlib/handlers.py +++ b/scripts/pylib/twister/twisterlib/handlers.py @@ -5,7 +5,6 @@ # Copyright 2022 NXP # SPDX-License-Identifier: Apache-2.0 -import csv import logging import math import os @@ -96,22 +95,6 @@ def get_test_timeout(self): self.instance.platform.timeout_multiplier * self.options.timeout_multiplier) - 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.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) self.terminated = True @@ -130,10 +113,12 @@ def _verify_ztest_suite_name(self, harness_state, detected_suite_names, handler_ return if not detected_suite_names: self._missing_suite_name(expected_suite_names, handler_time) - for detected_suite_name in detected_suite_names: - if detected_suite_name not in expected_suite_names: + return + # compare the expect and detect from end one by one without order + _d_suite = detected_suite_names[-len(expected_suite_names):] + if set(_d_suite) != set(expected_suite_names): + if not set(_d_suite).issubset(set(expected_suite_names)): self._missing_suite_name(expected_suite_names, handler_time) - break def _missing_suite_name(self, expected_suite_names, handler_time): """ @@ -164,7 +149,7 @@ def _final_handle_actions(self, harness, handler_time): for tc in self.instance.testcases: tc.status = "failed" - self.record(harness) + self.instance.record(harness.recording) def get_default_domain_build_dir(self): if self.instance.testsuite.sysbuild: @@ -322,8 +307,9 @@ def handle(self, harness): harness.run_robot_test(command, self) return - with subprocess.Popen(command, stdout=subprocess.PIPE, - stderr=subprocess.PIPE, cwd=self.build_dir, env=env) as proc: + stderr_log = "{}/handler_stderr.log".format(self.instance.build_dir) + with open(stderr_log, "w+") as stderr_log_fp, subprocess.Popen(command, stdout=subprocess.PIPE, + stderr=stderr_log_fp, cwd=self.build_dir, env=env) as proc: logger.debug("Spawning BinaryHandler Thread for %s" % self.name) t = threading.Thread(target=self._output_handler, args=(proc, harness,), daemon=True) t.start() @@ -333,6 +319,9 @@ def handle(self, harness): t.join() proc.wait() self.returncode = proc.returncode + if proc.returncode != 0: + self.instance.status = "error" + self.instance.reason = "BinaryHandler returned {}".format(proc.returncode) self.try_kill_process_by_pid() handler_time = time.time() - start_time @@ -525,6 +514,9 @@ def _create_command(self, runner, hardware): elif runner == "openocd" and product == "EDBG CMSIS-DAP": command_extra_args.append("--cmd-pre-init") command_extra_args.append("cmsis_dap_serial %s" % board_id) + elif runner == "openocd" and product == "LPC-LINK2 CMSIS-DAP": + command_extra_args.append("--cmd-pre-init") + command_extra_args.append("adapter serial %s" % board_id) elif runner == "jlink": command.append("--tool-opt=-SelectEmuBySN %s" % board_id) elif runner == "linkserver": @@ -890,6 +882,9 @@ def _thread(handler, timeout, outdir, logfile, fifo_fn, pid_fn, while True: this_timeout = int((timeout_time - time.time()) * 1000) + if timeout_extended: + # Quit early after timeout extension if no more data is being received + this_timeout = min(this_timeout, 1000) if this_timeout < 0 or not p.poll(this_timeout): try: if pid and this_timeout > 0: diff --git a/scripts/pylib/twister/twisterlib/hardwaremap.py b/scripts/pylib/twister/twisterlib/hardwaremap.py index 12f3c97ac0d..aa2594db38c 100644 --- a/scripts/pylib/twister/twisterlib/hardwaremap.py +++ b/scripts/pylib/twister/twisterlib/hardwaremap.py @@ -119,6 +119,7 @@ class HardwareMap: 'Atmel Corp.', 'Texas Instruments', 'Silicon Labs', + 'NXP', 'NXP Semiconductors', 'Microchip Technology Inc.', 'FTDI', diff --git a/scripts/pylib/twister/twisterlib/harness.py b/scripts/pylib/twister/twisterlib/harness.py index efba14c67b5..b0925c0fce0 100644 --- a/scripts/pylib/twister/twisterlib/harness.py +++ b/scripts/pylib/twister/twisterlib/harness.py @@ -49,7 +49,6 @@ def __init__(self): self.regex = [] self.matches = OrderedDict() self.ordered = True - self.repeat = 1 self.id = None self.fail_on_fault = True self.fault = False @@ -78,7 +77,6 @@ def configure(self, instance): if config: self.type = config.get('type', None) self.regex = config.get('regex', []) - self.repeat = config.get('repeat', 1) self.ordered = config.get('ordered', True) self.record = config.get('record', {}) if self.record: @@ -93,9 +91,19 @@ def get_testcase_name(self): """ return self.id + def parse_record(self, line) -> re.Match: + match = None + if self.record_pattern: + match = self.record_pattern.search(line) + if match: + self.recording.append({ k:v.strip() for k,v in match.groupdict(default="").items() }) + return match + # def process_test(self, line): + self.parse_record(line) + runid_match = re.search(self.run_id_pattern, line) if runid_match: run_id = runid_match.group("run_id") @@ -253,11 +261,6 @@ def handle(self, line): elif self.GCOV_END in line: self.capture_coverage = False - if self.record_pattern: - match = self.record_pattern.search(line) - if match: - self.recording.append({ k:v.strip() for k,v in match.groupdict(default="").items() }) - self.process_test(line) # Reset the resulting test state to 'failed' when not all of the patterns were # found in the output, but just ztest's 'PROJECT EXECUTION SUCCESSFUL'. @@ -309,6 +312,7 @@ def pytest_run(self, timeout): finally: if self.reserved_serial: self.instance.handler.make_device_available(self.reserved_serial) + self.instance.record(self.recording) self._update_test_status() def generate_command(self): @@ -382,6 +386,10 @@ def _generate_parameters_for_hardware(self, handler: Handler): if runner := hardware.runner or options.west_runner: command.append(f'--runner={runner}') + if hardware.runner_params: + for param in hardware.runner_params: + command.append(f'--runner-params={param}') + if options.west_flash and options.west_flash != []: command.append(f'--west-flash-extra-args={options.west_flash}') @@ -400,6 +408,9 @@ def _generate_parameters_for_hardware(self, handler: Handler): if hardware.post_script: command.append(f'--post-script={hardware.post_script}') + if hardware.flash_before: + command.append(f'--flash-before={hardware.flash_before}') + return command def run_command(self, cmd, timeout): @@ -411,7 +422,7 @@ def run_command(self, cmd, timeout): env=env ) as proc: try: - reader_t = threading.Thread(target=self._output_reader, args=(proc,), daemon=True) + reader_t = threading.Thread(target=self._output_reader, args=(proc, self), daemon=True) reader_t.start() reader_t.join(timeout) if reader_t.is_alive(): @@ -448,12 +459,13 @@ def _update_command_with_env_dependencies(cmd): return cmd, env @staticmethod - def _output_reader(proc): + def _output_reader(proc, harness): while proc.stdout.readable() and proc.poll() is None: line = proc.stdout.readline().decode().strip() if not line: continue logger.debug('PYTEST: %s', line) + harness.parse_record(line) proc.communicate() def _update_test_status(self): diff --git a/scripts/pylib/twister/twisterlib/quarantine.py b/scripts/pylib/twister/twisterlib/quarantine.py index e4baa52781e..cc6ae430022 100644 --- a/scripts/pylib/twister/twisterlib/quarantine.py +++ b/scripts/pylib/twister/twisterlib/quarantine.py @@ -5,11 +5,16 @@ import logging import re +import yaml from pathlib import Path -from yaml import safe_load from dataclasses import dataclass, field +try: + from yaml import CSafeLoader as SafeLoader +except ImportError: + from yaml import SafeLoader + logger = logging.getLogger(__name__) @@ -88,7 +93,7 @@ def __post_init__(self): def load_data_from_yaml(cls, filename: str | Path) -> QuarantineData: """Load quarantine from yaml file.""" with open(filename, 'r', encoding='UTF-8') as yaml_fd: - qlist_raw_data: list[dict] = safe_load(yaml_fd) + qlist_raw_data: list[dict] = yaml.load(yaml_fd, Loader=SafeLoader) try: if not qlist_raw_data: # in case of loading empty quarantine file diff --git a/scripts/pylib/twister/twisterlib/reports.py b/scripts/pylib/twister/twisterlib/reports.py index e03d754ee8c..48c9df082c4 100644 --- a/scripts/pylib/twister/twisterlib/reports.py +++ b/scripts/pylib/twister/twisterlib/reports.py @@ -11,6 +11,7 @@ import xml.etree.ElementTree as ET import string from datetime import datetime +from pathlib import PosixPath logger = logging.getLogger('twister') logger.setLevel(logging.DEBUG) @@ -26,6 +27,7 @@ def __init__(self, plan, env) -> None: self.env = env self.timestamp = datetime.now().isoformat() self.outdir = os.path.abspath(env.options.outdir) + self.instance_fail_count = plan.instance_fail_count @staticmethod def process_log(log_file): @@ -234,12 +236,23 @@ def xunit_report(self, json_file, filename, selected_platform=None, full_report= def json_report(self, filename, version="NA", platform=None): logger.info(f"Writing JSON report {filename}") + + if self.env.options.report_all_options: + report_options = vars(self.env.options) + else: + report_options = self.env.non_default_options() + + # Resolve known JSON serialization problems. + for k,v in report_options.items(): + report_options[k] = str(v) if type(v) in [PosixPath] else v + report = {} report["environment"] = {"os": os.name, "zephyr_version": version, "toolchain": self.env.toolchain, "commit_date": self.env.commit_date, - "run_date": self.env.run_date + "run_date": self.env.run_date, + "options": report_options } suites = [] @@ -432,20 +445,36 @@ def footprint_reports(self, report, show_footprint, all_deltas, (report if not last_metrics else "the last twister run."))) def synopsis(self): + if self.env.options.report_summary == 0: + count = self.instance_fail_count + log_txt = f"The following issues were found (showing the all {count} items):" + elif self.env.options.report_summary: + count = self.env.options.report_summary + log_txt = f"The following issues were found " + if count > self.instance_fail_count: + log_txt += f"(presenting {self.instance_fail_count} out of the {count} items requested):" + else: + log_txt += f"(showing the {count} of {self.instance_fail_count} items):" + else: + count = 10 + log_txt = f"The following issues were found (showing the top {count} items):" cnt = 0 example_instance = None detailed_test_id = self.env.options.detailed_test_id for instance in self.instances.values(): if instance.status not in ["passed", "filtered", "skipped"]: - cnt = cnt + 1 + cnt += 1 if cnt == 1: logger.info("-+" * 40) - logger.info("The following issues were found (showing the top 10 items):") + logger.info(log_txt) logger.info(f"{cnt}) {instance.testsuite.name} on {instance.platform.name} {instance.status} ({instance.reason})") example_instance = instance - if cnt == 10: + if cnt == count: break + if cnt == 0 and self.env.options.report_summary is not None: + logger.info("-+" * 40) + logger.info(f"No errors/fails found") if cnt and example_instance: logger.info("") @@ -549,8 +578,8 @@ def save_reports(self, name, suffix, report_dir, no_update, platform_reports): def target_report(self, json_file, outdir, suffix): - platforms = {inst.platform for _, inst in self.instances.items()} - for platform in platforms: + platforms = {repr(inst.platform):inst.platform for _, inst in self.instances.items()} + for platform in platforms.values(): if suffix: filename = os.path.join(outdir,"{}_{}.xml".format(platform.normalized_name, suffix)) json_platform_file = os.path.join(outdir,"{}_{}.json".format(platform.normalized_name, suffix)) diff --git a/scripts/pylib/twister/twisterlib/runner.py b/scripts/pylib/twister/twisterlib/runner.py index 1e8dc3b1a68..7251f3f733c 100644 --- a/scripts/pylib/twister/twisterlib/runner.py +++ b/scripts/pylib/twister/twisterlib/runner.py @@ -46,6 +46,11 @@ from twisterlib.testplan import change_skip_to_error_if_integration from twisterlib.harness import HarnessImporter, Pytest +try: + from yaml import CSafeLoader as SafeLoader +except ImportError: + from yaml import SafeLoader + logger = logging.getLogger('twister') logger.setLevel(logging.DEBUG) import expr_parser @@ -268,7 +273,7 @@ def run_build(self, args=[]): p = self.jobserver.popen(cmd, **kwargs) else: p = subprocess.Popen(cmd, **kwargs) - logger.debug(f'Running {"".join(cmd)}') + logger.debug(f'Running {" ".join(cmd)}') out, _ = p.communicate() @@ -299,7 +304,7 @@ def run_build(self, args=[]): log.write(log_msg) if log_msg: - overflow_found = re.findall("region `(FLASH|ROM|RAM|ICCM|DCCM|SRAM|dram0_1_seg)' overflowed by", log_msg) + overflow_found = re.findall("region `(FLASH|ROM|RAM|ICCM|DCCM|SRAM|dram\\d_\\d_seg)' overflowed by", log_msg) imgtool_overflow_found = re.findall(r"Error: Image size \(.*\) \+ trailer \(.*\) exceeds requested size", log_msg) if overflow_found and not self.options.overflow_as_errors: logger.debug("Test skipped due to {} Overflow".format(overflow_found[0])) @@ -568,6 +573,7 @@ def log_info(self, filename, inline_logs, log_testcases=False): def log_info_file(self, inline_logs): build_dir = self.instance.build_dir h_log = "{}/handler.log".format(build_dir) + he_log = "{}/handler_stderr.log".format(build_dir) b_log = "{}/build.log".format(build_dir) v_log = "{}/valgrind.log".format(build_dir) d_log = "{}/device.log".format(build_dir) @@ -579,6 +585,8 @@ def log_info_file(self, inline_logs): 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(he_log) and os.path.getsize(he_log) > 0: + self.log_info("{}".format(he_log), inline_logs) elif os.path.exists(d_log) and os.path.getsize(d_log) > 0: self.log_info("{}".format(d_log), inline_logs) else: @@ -656,8 +664,12 @@ def process(self, pipeline, done, message, lock, results): pipeline.put({"op": "report", "test": self.instance}) elif op == "gather_metrics": - self.gather_metrics(self.instance) - if self.instance.run and self.instance.handler.ready: + ret = self.gather_metrics(self.instance) + if not ret or ret.get('returncode', 1) > 0: + self.instance.status = "error" + self.instance.reason = "Build Failure at gather_metrics." + pipeline.put({"op": "report", "test": self.instance}) + elif self.instance.run and self.instance.handler.ready: pipeline.put({"op": "run", "test": self.instance}) else: pipeline.put({"op": "report", "test": self.instance}) @@ -725,7 +737,7 @@ def determine_testcases(self, results): if matches: for m in matches: # new_ztest_suite = m[0] # not used for now - test_func_name = m[1].replace("test_", "") + test_func_name = m[1].replace("test_", "", 1) testcase_id = f"{yaml_testsuite_name}.{test_func_name}" detected_cases.append(testcase_id) @@ -748,6 +760,7 @@ def cleanup_artifacts(self, additional_keep: List[str] = []): allow = [ os.path.join('zephyr', '.config'), 'handler.log', + 'handler_stderr.log', 'build.log', 'device.log', 'recording.csv', @@ -851,7 +864,7 @@ def _get_binaries_from_runners(self, domain='') -> List[str]: return [] with open(runners_file_path, 'r') as file: - runners_content: dict = yaml.safe_load(file) + runners_content: dict = yaml.load(file, Loader=SafeLoader) if 'config' not in runners_content: return [] @@ -891,7 +904,7 @@ def _sanitize_runners_file(self): with open(runners_file_path, 'rt') as file: runners_content_text = file.read() - runners_content_yaml: dict = yaml.safe_load(runners_content_text) + runners_content_yaml: dict = yaml.load(runners_content_text, Loader=SafeLoader) if 'config' not in runners_content_yaml: return @@ -1127,8 +1140,9 @@ def run(self): sys.stdout.flush() def gather_metrics(self, instance: TestInstance): + build_result = {"returncode": 0} if self.options.create_rom_ram_report: - self.run_build(['--build', self.build_dir, "--target", "footprint"]) + build_result = 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: @@ -1137,6 +1151,7 @@ def gather_metrics(self, instance: TestInstance): instance.metrics["available_rom"] = 0 instance.metrics["available_ram"] = 0 instance.metrics["unrecognized"] = [] + return build_result @staticmethod def calc_size(instance: TestInstance, from_buildlog: bool): diff --git a/scripts/pylib/twister/twisterlib/testinstance.py b/scripts/pylib/twister/twisterlib/testinstance.py index 5be57e1deb6..fb0fc1d909b 100644 --- a/scripts/pylib/twister/twisterlib/testinstance.py +++ b/scripts/pylib/twister/twisterlib/testinstance.py @@ -10,6 +10,7 @@ import logging import shutil import glob +import csv from twisterlib.testsuite import TestCase, TestSuite from twisterlib.platform import Platform @@ -73,6 +74,22 @@ def __init__(self, testsuite, platform, outdir): self.filters = [] self.filter_type = None + def record(self, recording, fname_csv="recording.csv"): + if recording: + if self.recording is None: + self.recording = recording.copy() + else: + self.recording.extend(recording) + + filename = os.path.join(self.build_dir, fname_csv) + with open(filename, "wt") as csvfile: + cw = csv.DictWriter(csvfile, + fieldnames = self.recording[0].keys(), + lineterminator = os.linesep, + quoting = csv.QUOTE_NONNUMERIC) + cw.writeheader() + cw.writerows(self.recording) + def add_filter(self, reason, filter_type): self.filters.append({'type': filter_type, 'reason': reason }) self.status = "filtered" diff --git a/scripts/pylib/twister/twisterlib/testplan.py b/scripts/pylib/twister/twisterlib/testplan.py index 2d24ca93300..83c5d6b06fd 100755 --- a/scripts/pylib/twister/twisterlib/testplan.py +++ b/scripts/pylib/twister/twisterlib/testplan.py @@ -17,6 +17,7 @@ import shutil import random import snippets +from colorama import Fore from pathlib import Path from argparse import Namespace @@ -107,6 +108,7 @@ def __init__(self, env=None): self.default_platforms = [] self.load_errors = 0 self.instances = dict() + self.instance_fail_count = 0 self.warnings = 0 self.scenarios = [] @@ -217,7 +219,7 @@ def load(self): else: last_run = os.path.join(self.options.outdir, "twister.json") - if self.options.only_failed: + if self.options.only_failed or self.options.report_summary is not None: self.load_from_file(last_run) self.selected_platforms = set(p.platform.name for p in self.instances.values()) elif self.options.load_tests: @@ -349,13 +351,13 @@ def report_tag_list(self): print("- {}".format(t)) def report_test_tree(self): - all_tests = self.get_all_tests() + tests_list = self.get_tests_list() testsuite = Node("Testsuite") samples = Node("Samples", parent=testsuite) tests = Node("Tests", parent=testsuite) - for test in sorted(all_tests): + for test in sorted(tests_list): if test.startswith("sample."): sec = test.split(".") area = find(samples, lambda node: node.name == sec[1] and node.parent == samples) @@ -379,17 +381,14 @@ def report_test_tree(self): print("%s%s" % (pre, node.name)) def report_test_list(self): - cnt = 0 - all_tests = self.get_all_tests() + tests_list = self.get_tests_list() - for test in sorted(all_tests): + cnt = 0 + for test in sorted(tests_list): cnt = cnt + 1 print(" - {}".format(test)) - print("{} total.".format(cnt)) - def config(self): - logger.info("coverage platform: {}".format(self.coverage_platform)) # Debug Functions @staticmethod @@ -397,7 +396,6 @@ def info(what): sys.stdout.write(what + "\n") sys.stdout.flush() - def add_configurations(self): board_dirs = set() # Create a list of board roots as defined by the build system in general @@ -408,16 +406,27 @@ def add_configurations(self): Path(ZEPHYR_BASE) / 'subsys' / 'testsuite'], board_roots=board_roots, board=None, board_dir=None) v1_boards = list_boards.find_boards(lb_args) - v2_boards = list_boards.find_v2_boards(lb_args) + v2_dirs = list_boards.find_v2_board_dirs(lb_args) for b in v1_boards: board_dirs.add(b.dir) - for b in v2_boards: - board_dirs.add(b.dir) + board_dirs.update(v2_dirs) logger.debug("Reading platform configuration files under %s..." % self.env.board_roots) platform_config = self.test_config.get('platforms', {}) for folder in board_dirs: for file in glob.glob(os.path.join(folder, "*.yaml")): + # If the user set a platform filter, we can, if no other option would increase + # the allowed platform pool, save on time by not loading YAMLs of any boards + # that do not start with the required names. + if self.options.platform and \ + not self.options.all and \ + not self.options.integration and \ + not any([ + os.path.basename(file).startswith( + re.split('[/@]', p)[0] + ) for p in self.options.platform + ]): + continue try: platform = Platform() platform.load(file) @@ -449,7 +458,7 @@ def add_configurations(self): # cmake/modules/extensions.cmake. revision_patterns = ["[A-Z]", "[0-9]+", - "(0|[1-9][0-9]*)(_[0-9]+)*(_[0-9]+)*"] + "(0|[1-9][0-9]*)(_[0-9]+){0,2}"] for pattern in revision_patterns: result = re.match(f"{platform.name}_(?P{pattern})\\.conf", item) @@ -481,6 +490,26 @@ def get_all_tests(self): return testcases + def get_tests_list(self): + testcases = [] + if tag_filter := self.options.tag: + for _, ts in self.testsuites.items(): + if ts.tags.intersection(tag_filter): + for case in ts.testcases: + testcases.append(case.name) + else: + for _, ts in self.testsuites.items(): + for case in ts.testcases: + testcases.append(case.name) + + if exclude_tag := self.options.exclude_tag: + for _, ts in self.testsuites.items(): + if ts.tags.intersection(exclude_tag): + for case in ts.testcases: + if case.name in testcases: + testcases.remove(case.name) + return testcases + def add_testsuites(self, testsuite_filter=[]): for root in self.env.test_roots: root = os.path.abspath(root) @@ -542,71 +571,95 @@ def get_platform(self, name): break return selected_platform - def load_from_file(self, file, filter_platform=[]): - with open(file, "r") as json_test_plan: - jtp = json.load(json_test_plan) - instance_list = [] - for ts in jtp.get("testsuites", []): - logger.debug(f"loading {ts['name']}...") - testsuite = ts["name"] + def handle_quarantined_tests(self, instance: TestInstance, plat: Platform): + 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) + return + if not matched_quarantine and self.options.quarantine_verify: + instance.add_filter("Not under quarantine", Filters.QUARANTINE) - platform = self.get_platform(ts["platform"]) - if filter_platform and platform.name not in filter_platform: - continue - instance = TestInstance(self.testsuites[testsuite], platform, self.env.outdir) - if ts.get("run_id"): - instance.run_id = ts.get("run_id") + def load_from_file(self, file, filter_platform=[]): + try: + with open(file, "r") as json_test_plan: + jtp = json.load(json_test_plan) + instance_list = [] + for ts in jtp.get("testsuites", []): + logger.debug(f"loading {ts['name']}...") + testsuite = ts["name"] + + platform = self.get_platform(ts["platform"]) + if filter_platform and platform.name not in filter_platform: + continue + instance = TestInstance(self.testsuites[testsuite], platform, self.env.outdir) + if ts.get("run_id"): + instance.run_id = ts.get("run_id") - if self.options.device_testing: - tfilter = 'runnable' - else: - tfilter = 'buildable' - instance.run = instance.check_runnable( - self.options.enable_slow, - tfilter, - self.options.fixture, - self.hwm - ) + if self.options.device_testing: + tfilter = 'runnable' + else: + tfilter = 'buildable' + instance.run = instance.check_runnable( + self.options.enable_slow, + tfilter, + self.options.fixture, + self.hwm + ) - instance.metrics['handler_time'] = ts.get('execution_time', 0) - instance.metrics['used_ram'] = ts.get("used_ram", 0) - instance.metrics['used_rom'] = ts.get("used_rom",0) - instance.metrics['available_ram'] = ts.get('available_ram', 0) - instance.metrics['available_rom'] = ts.get('available_rom', 0) - - status = ts.get('status', None) - reason = ts.get("reason", "Unknown") - if status in ["error", "failed"]: - instance.status = None - instance.reason = None - instance.retries += 1 - # test marked as passed (built only) but can run when - # --test-only is used. Reset status to capture new results. - elif status == 'passed' and instance.run and self.options.test_only: - instance.status = None - instance.reason = None - else: - instance.status = status - instance.reason = reason - - for tc in ts.get('testcases', []): - identifier = tc['identifier'] - tc_status = tc.get('status', None) - tc_reason = None - # we set reason only if status is valid, it might have been - # reset above... - if instance.status: - tc_reason = tc.get('reason') - if tc_status: - case = instance.set_case_status_by_name(identifier, tc_status, tc_reason) - case.duration = tc.get('execution_time', 0) - if tc.get('log'): - case.output = tc.get('log') - - - instance.create_overlay(platform, self.options.enable_asan, self.options.enable_ubsan, self.options.enable_coverage, self.options.coverage_platform) - instance_list.append(instance) - self.add_instances(instance_list) + instance.metrics['handler_time'] = ts.get('execution_time', 0) + instance.metrics['used_ram'] = ts.get("used_ram", 0) + instance.metrics['used_rom'] = ts.get("used_rom",0) + instance.metrics['available_ram'] = ts.get('available_ram', 0) + instance.metrics['available_rom'] = ts.get('available_rom', 0) + + status = ts.get('status', None) + reason = ts.get("reason", "Unknown") + if status in ["error", "failed"]: + if self.options.report_summary is not None: + if status == "error": status = "ERROR" + elif status == "failed": status = "FAILED" + instance.status = Fore.RED + status + Fore.RESET + instance.reason = reason + self.instance_fail_count += 1 + else: + instance.status = None + instance.reason = None + instance.retries += 1 + # test marked as passed (built only) but can run when + # --test-only is used. Reset status to capture new results. + elif status == 'passed' and instance.run and self.options.test_only: + instance.status = None + instance.reason = None + else: + instance.status = status + instance.reason = reason + + self.handle_quarantined_tests(instance, platform) + + for tc in ts.get('testcases', []): + identifier = tc['identifier'] + tc_status = tc.get('status', None) + tc_reason = None + # we set reason only if status is valid, it might have been + # reset above... + if instance.status: + tc_reason = tc.get('reason') + if tc_status: + case = instance.set_case_status_by_name(identifier, tc_status, tc_reason) + case.duration = tc.get('execution_time', 0) + if tc.get('log'): + case.output = tc.get('log') + + + instance.create_overlay(platform, self.options.enable_asan, self.options.enable_ubsan, self.options.enable_coverage, self.options.coverage_platform) + instance_list.append(instance) + self.add_instances(instance_list) + except FileNotFoundError as e: + logger.error(f"{e}") + return 1 def apply_filters(self, **kwargs): @@ -683,15 +736,17 @@ def apply_filters(self, **kwargs): if ts.build_on_all and not platform_filter and platform_config.get('increased_platform_scope', True): platform_scope = self.platforms elif ts.integration_platforms: - self.verify_platforms_existence( - ts.integration_platforms, f"{ts_name} - integration_platforms") integration_platforms = list(filter(lambda item: item.name in ts.integration_platforms, self.platforms)) if self.options.integration: + self.verify_platforms_existence( + ts.integration_platforms, f"{ts_name} - integration_platforms") platform_scope = integration_platforms else: # if not in integration mode, still add integration platforms to the list if not platform_filter: + self.verify_platforms_existence( + ts.integration_platforms, f"{ts_name} - integration_platforms") platform_scope = platforms + integration_platforms else: platform_scope = platforms @@ -740,9 +795,12 @@ def apply_filters(self, **kwargs): if self.options.level: 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.TESTPLAN) + if tl is None: + instance.add_filter(f"Unknown test level '{self.options.level}'", Filters.TESTPLAN) + else: + 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.TESTPLAN) if runnable and not instance.run: instance.add_filter("Not runnable on device", Filters.CMD_LINE) @@ -869,15 +927,7 @@ def apply_filters(self, **kwargs): 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) - + self.handle_quarantined_tests(instance, plat) # 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 diff --git a/scripts/pylib/twister/twisterlib/testsuite.py b/scripts/pylib/twister/twisterlib/testsuite.py index c3c9daed72b..e967ec1df86 100644 --- a/scripts/pylib/twister/twisterlib/testsuite.py +++ b/scripts/pylib/twister/twisterlib/testsuite.py @@ -82,10 +82,10 @@ def scan_file(inf_name): re.MULTILINE) # Checks if the file contains a definition of "void test_main(void)" # Since ztest provides a plain test_main implementation it is OK to: - # 1. register test suites and not call the run function iff the test - # doesn't have a custom test_main. - # 2. register test suites and a custom test_main definition iff the test - # also calls ztest_run_registered_test_suites. + # 1. register test suites and not call the run function if and only if + # the test doesn't have a custom test_main. + # 2. register test suites and a custom test_main definition if and only if + # the test also calls ztest_run_registered_test_suites. test_main_regex = re.compile( br"^\s*void\s+test_main\(void\)", re.MULTILINE) @@ -310,7 +310,13 @@ def scan_testsuite_path(testsuite_path): except ValueError as e: logger.error("%s: error parsing source file: %s" % (filename, e)) + src_dir_pathlib_path = Path(src_dir_path) for filename in find_c_files_in(testsuite_path): + # If we have already scanned those files in the src_dir step, skip them. + filename_path = Path(filename) + if src_dir_pathlib_path in filename_path.parents: + continue + try: result: ScanPathResult = scan_file(filename) if result.warnings: diff --git a/scripts/pylib/twister/twisterlib/twister_main.py b/scripts/pylib/twister/twisterlib/twister_main.py index 30656544b94..33b0569f330 100644 --- a/scripts/pylib/twister/twisterlib/twister_main.py +++ b/scripts/pylib/twister/twisterlib/twister_main.py @@ -62,7 +62,7 @@ def init_color(colorama_strip): colorama.init(strip=colorama_strip) -def main(options): +def main(options, default_options): start_time = time.time() # Configure color output @@ -73,7 +73,7 @@ def main(options): previous_results = None # Cleanup - if options.no_clean or options.only_failed or options.test_only: + if options.no_clean or options.only_failed or options.test_only or options.report_summary is not None: if os.path.exists(options.outdir): print("Keeping artifacts untouched") elif options.last_metrics: @@ -105,7 +105,7 @@ def main(options): VERBOSE = options.verbose setup_logging(options.outdir, options.log_file, VERBOSE, options.timestamps) - env = TwisterEnv(options) + env = TwisterEnv(options, default_options) env.discover() hwm = HardwareMap(env) @@ -160,6 +160,13 @@ def main(options): report.json_report(options.save_tests) return 0 + if options.report_summary is not None: + if options.report_summary < 0: + logger.error("The report summary value cannot be less than 0") + return 1 + report.synopsis() + return 0 + if options.device_testing and not options.build_only: print("\nDevice testing on:") hwm.dump(filtered=tplan.selected_platforms) diff --git a/scripts/requirements-compliance.txt b/scripts/requirements-compliance.txt index 31c395ac4f0..68469fc80ea 100644 --- a/scripts/requirements-compliance.txt +++ b/scripts/requirements-compliance.txt @@ -5,5 +5,5 @@ python-magic python-magic-bin; sys_platform == "win32" lxml junitparser>=2 -pylint +pylint>=3 yamllint diff --git a/scripts/schemas/twister/testsuite-schema.yaml b/scripts/schemas/twister/testsuite-schema.yaml index 454959fc608..1eae7dcef1b 100644 --- a/scripts/schemas/twister/testsuite-schema.yaml +++ b/scripts/schemas/twister/testsuite-schema.yaml @@ -101,9 +101,6 @@ schema;scenario-schema: "ordered": type: bool required: false - "repeat": - type: int - required: false "pytest_root": type: seq required: false diff --git a/scripts/spelling.txt b/scripts/spelling.txt index c06453a7aee..2fe2d7cdea7 100644 --- a/scripts/spelling.txt +++ b/scripts/spelling.txt @@ -773,6 +773,7 @@ hypervior||hypervisor hypter||hyper idel||idle identidier||identifier +iff||if and only if iligal||illegal illigal||illegal illgal||illegal diff --git a/scripts/tests/twister/test_environment.py b/scripts/tests/twister/test_environment.py index d30f7fdad00..13db3ed2527 100644 --- a/scripts/tests/twister/test_environment.py +++ b/scripts/tests/twister/test_environment.py @@ -274,7 +274,8 @@ def test_parse_arguments(zephyr_base, additional_args): testsuite_root=[ os.path.join('dummy', 'path', "tests"), os.path.join('dummy', 'path', "samples") - ] + ], + outdir='dummy_abspath', ), mock.Mock( generator_cmd='ninja', @@ -294,7 +295,8 @@ def test_parse_arguments(zephyr_base, additional_args): testsuite_root=[ os.path.join('dummy', 'path', "tests"), os.path.join('dummy', 'path', "samples") - ] + ], + outdir='dummy_abspath', ), mock.Mock( generator_cmd='make', @@ -320,9 +322,17 @@ def test_parse_arguments(zephyr_base, additional_args): ] ) def test_twisterenv_init(options, expected_env): - with mock.patch( - 'os.path.abspath', - mock.Mock(return_value='dummy_abspath')): + original_abspath = os.path.abspath + + def mocked_abspath(path): + if path == 'dummy_abspath': + return 'dummy_abspath' + elif isinstance(path, mock.Mock): + return None + else: + return original_abspath(path) + + with mock.patch('os.path.abspath', side_effect=mocked_abspath): twister_env = twisterlib.environment.TwisterEnv(options=options) assert twister_env.generator_cmd == expected_env.generator_cmd @@ -339,9 +349,17 @@ def test_twisterenv_discover(): ninja=True ) - abspath_mock = mock.Mock(return_value='dummy_abspath') + original_abspath = os.path.abspath - with mock.patch('os.path.abspath', abspath_mock): + def mocked_abspath(path): + if path == 'dummy_abspath': + return 'dummy_abspath' + elif isinstance(path, mock.Mock): + return None + else: + return original_abspath(path) + + with mock.patch('os.path.abspath', side_effect=mocked_abspath): twister_env = twisterlib.environment.TwisterEnv(options=options) mock_datetime = mock.Mock( @@ -435,9 +453,17 @@ def mock_run(command, *args, **kwargs): ninja=True ) - abspath_mock = mock.Mock(return_value='dummy_abspath') + original_abspath = os.path.abspath + + def mocked_abspath(path): + if path == 'dummy_abspath': + return 'dummy_abspath' + elif isinstance(path, mock.Mock): + return None + else: + return original_abspath(path) - with mock.patch('os.path.abspath', abspath_mock): + with mock.patch('os.path.abspath', side_effect=mocked_abspath): twister_env = twisterlib.environment.TwisterEnv(options=options) with mock.patch('subprocess.run', mock.Mock(side_effect=mock_run)): @@ -555,9 +581,17 @@ def test_get_toolchain(caplog, script_result, exit_value, expected_log): ninja=True ) - abspath_mock = mock.Mock(return_value='dummy_abspath') + original_abspath = os.path.abspath + + def mocked_abspath(path): + if path == 'dummy_abspath': + return 'dummy_abspath' + elif isinstance(path, mock.Mock): + return None + else: + return original_abspath(path) - with mock.patch('os.path.abspath', abspath_mock): + with mock.patch('os.path.abspath', side_effect=mocked_abspath): twister_env = twisterlib.environment.TwisterEnv(options=options) with mock.patch.object( diff --git a/scripts/tests/twister/test_handlers.py b/scripts/tests/twister/test_handlers.py index dd0686906db..b5012646eb9 100644 --- a/scripts/tests/twister/test_handlers.py +++ b/scripts/tests/twister/test_handlers.py @@ -129,6 +129,7 @@ def test_handler_final_handle_actions(mocked_instance): harness.detected_suite_names = mock.Mock() harness.matched_run_id = False harness.run_id_exists = True + harness.recording = mock.Mock() handler_time = mock.Mock() @@ -143,6 +144,8 @@ def test_handler_final_handle_actions(mocked_instance): handler.instance.reason = 'This reason shan\'t be changed.' handler._final_handle_actions(harness, handler_time) + instance.assert_has_calls([mock.call.record(harness.recording)]) + assert handler.instance.reason == 'This reason shan\'t be changed.' @@ -204,42 +207,6 @@ def test_handler_missing_suite_name(mocked_instance): ) -def test_handler_record(mocked_instance): - instance = mocked_instance - instance.testcases = [mock.Mock()] - - handler = Handler(instance) - - 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.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_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): def mock_kill_function(pid, sig): if pid < 0: diff --git a/scripts/tests/twister/test_harness.py b/scripts/tests/twister/test_harness.py index f9898700af4..a01d313cb28 100644 --- a/scripts/tests/twister/test_harness.py +++ b/scripts/tests/twister/test_harness.py @@ -44,6 +44,32 @@ def process_logs(harness, logs): harness.handle(line) +TEST_DATA_RECORDING = [ + ([''], "^START:(?P.*):END", []), + (['START:bar:STOP'], "^START:(?P.*):END", []), + (['START:bar:END'], "^START:(?P.*):END", [{'foo':'bar'}]), + (['START:bar:baz:END'], "^START:(?P.*):(?P.*):END", [{'foo':'bar', 'boo':'baz'}]), + (['START:bar:baz:END','START:may:jun:END'], "^START:(?P.*):(?P.*):END", + [{'foo':'bar', 'boo':'baz'}, {'foo':'may', 'boo':'jun'}]), + ] +@pytest.mark.parametrize( + "lines, pattern, expected_records", + TEST_DATA_RECORDING, + ids=["empty", "no match", "match 1 field", "match 2 fields", "match 2 records"] +) +def test_harness_parse_record(lines, pattern, expected_records): + harness = Harness() + harness.record = { 'regex': pattern } + harness.record_pattern = re.compile(pattern) + + assert not harness.recording + + for line in lines: + harness.parse_record(line) + + assert harness.recording == expected_records + + 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), @@ -63,6 +89,7 @@ def test_harness_process_test(line, fault, fail_on_fault, cap_cov, exp_stat, exp harness.state = None harness.fault = fault harness.fail_on_fault = fail_on_fault + mock.patch.object(Harness, 'parse_record', return_value=None) #Act harness.process_test(line) @@ -71,6 +98,7 @@ def test_harness_process_test(line, fault, fail_on_fault, cap_cov, exp_stat, exp assert harness.matched_run_id == exp_id assert harness.state == exp_stat assert harness.capture_coverage == cap_cov + assert harness.recording == [] def test_robot_configure(tmp_path): @@ -316,6 +344,7 @@ def test_pytest__generate_parameters_for_hardware(tmp_path, pty_value, hardware_ hardware.serial = 'serial' hardware.baud = 115200 hardware.runner = "runner" + hardware.runner_params = ["--runner-param1", "runner-param2"] options = handler.options options.west_flash = "args" @@ -349,6 +378,8 @@ def test_pytest__generate_parameters_for_hardware(tmp_path, pty_value, hardware_ assert '--device-serial=serial' in command assert '--device-serial-baud=115200' in command assert '--runner=runner' in command + assert '--runner-params=--runner-param1' in command + assert '--runner-params=runner-param2' in command assert '--west-flash-extra-args=args' in command assert '--device-id=123' in command assert '--device-product=product' in command diff --git a/scripts/tests/twister/test_jobserver.py b/scripts/tests/twister/test_jobserver.py index c97e9320447..554df8545fb 100644 --- a/scripts/tests/twister/test_jobserver.py +++ b/scripts/tests/twister/test_jobserver.py @@ -14,15 +14,13 @@ 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 -) +# Job server only works on Linux for now. +pytestmark = pytest.mark.skipif(sys.platform != 'linux', reason='JobServer only works on Linux.') +if sys.platform == 'linux': + from twisterlib.jobserver import GNUMakeJobClient, GNUMakeJobServer, JobClient, JobHandle + from fcntl import F_GETFL def test_jobhandle(capfd): @@ -96,7 +94,6 @@ def test_jobclient_popen(kwargs, expected_kwargs): (True, 16), ] - @pytest.mark.parametrize( 'inheritable, internal_jobs', TESTDATA_2, @@ -283,6 +280,7 @@ def mock_fcntl(fd, flag): **expected_kwargs) + def test_gnumakejobclient_get_job(): inherit_read_fd = mock.Mock() inherit_write_fd = mock.Mock() diff --git a/scripts/tests/twister/test_runner.py b/scripts/tests/twister/test_runner.py index df034b8c00c..592d2c63042 100644 --- a/scripts/tests/twister/test_runner.py +++ b/scripts/tests/twister/test_runner.py @@ -870,6 +870,7 @@ def mock_getsize(filename, *args, **kwargs): mock.ANY, mock.ANY, mock.ANY, + mock.ANY, [], {'op': 'report', 'test': mock.ANY}, 'failed', @@ -891,6 +892,7 @@ def mock_getsize(filename, *args, **kwargs): mock.ANY, mock.ANY, mock.ANY, + mock.ANY, ['filtering dummy instance name'], {'op': 'report', 'test': mock.ANY}, 'filtered', @@ -912,6 +914,7 @@ def mock_getsize(filename, *args, **kwargs): mock.ANY, mock.ANY, mock.ANY, + mock.ANY, [], {'op': 'cmake', 'test': mock.ANY}, 'passed', @@ -933,6 +936,7 @@ def mock_getsize(filename, *args, **kwargs): mock.ANY, mock.ANY, mock.ANY, + mock.ANY, [], {'op': 'report', 'test': mock.ANY}, 'error', @@ -954,6 +958,7 @@ def mock_getsize(filename, *args, **kwargs): mock.ANY, mock.ANY, mock.ANY, + mock.ANY, [], {'op': 'report', 'test': mock.ANY}, 'passed', @@ -975,6 +980,7 @@ def mock_getsize(filename, *args, **kwargs): mock.ANY, mock.ANY, mock.ANY, + mock.ANY, [], {'op': 'report', 'test': mock.ANY}, 'success', @@ -996,6 +1002,7 @@ def mock_getsize(filename, *args, **kwargs): mock.ANY, mock.ANY, mock.ANY, + mock.ANY, ['filtering dummy instance name'], {'op': 'report', 'test': mock.ANY}, 'filtered', @@ -1017,6 +1024,7 @@ def mock_getsize(filename, *args, **kwargs): mock.ANY, mock.ANY, mock.ANY, + mock.ANY, [], {'op': 'build', 'test': mock.ANY}, 'success', @@ -1038,6 +1046,7 @@ def mock_getsize(filename, *args, **kwargs): None, mock.ANY, mock.ANY, + mock.ANY, ['build test: dummy instance name'], {'op': 'report', 'test': mock.ANY}, 'error', @@ -1059,6 +1068,7 @@ def mock_getsize(filename, *args, **kwargs): {'returncode': 0}, mock.ANY, mock.ANY, + mock.ANY, ['build test: dummy instance name', 'Determine test cases for test instance: dummy instance name'], {'op': 'gather_metrics', 'test': mock.ANY}, @@ -1081,6 +1091,7 @@ def mock_getsize(filename, *args, **kwargs): {'dummy': 'dummy'}, mock.ANY, mock.ANY, + mock.ANY, ['build test: dummy instance name'], {'op': 'report', 'test': mock.ANY}, 'passed', @@ -1102,6 +1113,7 @@ def mock_getsize(filename, *args, **kwargs): {'returncode': 0}, mock.ANY, mock.ANY, + mock.ANY, ['build test: dummy instance name', 'Determine test cases for test instance: dummy instance name'], {'op': 'gather_metrics', 'test': mock.ANY}, @@ -1123,6 +1135,7 @@ def mock_getsize(filename, *args, **kwargs): mock.ANY, {'returncode': 0}, mock.ANY, + mock.ANY, BuildError, ['build test: dummy instance name', 'Determine test cases for test instance: dummy instance name'], @@ -1144,6 +1157,7 @@ def mock_getsize(filename, *args, **kwargs): mock.ANY, mock.ANY, mock.ANY, + {'returncode': 0}, # metrics_res mock.ANY, mock.ANY, [], @@ -1152,7 +1166,7 @@ def mock_getsize(filename, *args, **kwargs): mock.ANY, 0, None - ), + ), # 'gather metrics, run and ready handler' ( {'op': 'gather_metrics'}, mock.ANY, @@ -1165,6 +1179,7 @@ def mock_getsize(filename, *args, **kwargs): mock.ANY, mock.ANY, mock.ANY, + {'returncode': 0}, # metrics_res mock.ANY, mock.ANY, [], @@ -1173,7 +1188,29 @@ def mock_getsize(filename, *args, **kwargs): mock.ANY, 0, None - ), + ), # 'gather metrics' + ( + {'op': 'gather_metrics'}, + mock.ANY, + mock.ANY, + False, + True, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + {'returncode': 0}, # build_res + {'returncode': 1}, # metrics_res + mock.ANY, + mock.ANY, + [], + {'op': 'report', 'test': mock.ANY}, + 'error', + 'Build Failure at gather_metrics.', + 0, + None + ), # 'build ok, gather metrics fail', ( {'op': 'run'}, 'success', @@ -1186,6 +1223,7 @@ def mock_getsize(filename, *args, **kwargs): mock.ANY, mock.ANY, mock.ANY, + mock.ANY, None, mock.ANY, ['run test: dummy instance name', @@ -1208,6 +1246,7 @@ def mock_getsize(filename, *args, **kwargs): mock.ANY, mock.ANY, mock.ANY, + mock.ANY, RuntimeError, mock.ANY, ['run test: dummy instance name', @@ -1233,6 +1272,7 @@ def mock_getsize(filename, *args, **kwargs): mock.ANY, mock.ANY, mock.ANY, + mock.ANY, [], {'op': 'cleanup', 'mode': 'device', 'test': mock.ANY}, mock.ANY, @@ -1254,6 +1294,7 @@ def mock_getsize(filename, *args, **kwargs): mock.ANY, mock.ANY, mock.ANY, + mock.ANY, [], {'op': 'cleanup', 'mode': 'passed', 'test': mock.ANY}, mock.ANY, @@ -1275,6 +1316,7 @@ def mock_getsize(filename, *args, **kwargs): mock.ANY, mock.ANY, mock.ANY, + mock.ANY, [], {'op': 'cleanup', 'mode': 'all', 'test': mock.ANY}, mock.ANY, @@ -1296,6 +1338,7 @@ def mock_getsize(filename, *args, **kwargs): mock.ANY, mock.ANY, mock.ANY, + mock.ANY, [], None, mock.ANY, @@ -1317,6 +1360,7 @@ def mock_getsize(filename, *args, **kwargs): mock.ANY, mock.ANY, mock.ANY, + mock.ANY, [], None, mock.ANY, @@ -1338,6 +1382,7 @@ def mock_getsize(filename, *args, **kwargs): mock.ANY, mock.ANY, mock.ANY, + mock.ANY, [], None, mock.ANY, @@ -1359,6 +1404,7 @@ def mock_getsize(filename, *args, **kwargs): mock.ANY, mock.ANY, mock.ANY, + mock.ANY, [], None, mock.ANY, @@ -1380,6 +1426,7 @@ def mock_getsize(filename, *args, **kwargs): mock.ANY, mock.ANY, mock.ANY, + mock.ANY, [], None, mock.ANY, @@ -1394,7 +1441,7 @@ def mock_getsize(filename, *args, **kwargs): ' instance_status, instance_reason, instance_run, instance_handler_ready,' \ ' options_cmake_only,' \ ' options_coverage, options_prep_artifacts, options_runtime_artifacts,' \ - ' cmake_res, build_res,' \ + ' cmake_res, build_res, metrics_res,' \ ' pipeline_runtime_error, determine_testcases_build_error,' \ ' expected_logs, resulting_message,' \ ' expected_status, expected_reason, expected_skipped, expected_missing', @@ -1406,6 +1453,7 @@ def mock_getsize(filename, *args, **kwargs): 'build, no build res', 'build, skipped', 'build, blocked', 'build, determine testcases', 'build, determine testcases Error', 'gather metrics, run and ready handler', 'gather metrics', + 'build ok, gather metrics fail', 'run', 'run, Pipeline Runtime Error', 'report, prep artifacts for testing', 'report, runtime artifact cleanup pass, status passed', @@ -1428,6 +1476,7 @@ def test_projectbuilder_process( options_runtime_artifacts, cmake_res, build_res, + metrics_res, pipeline_runtime_error, determine_testcases_build_error, expected_logs, @@ -1471,7 +1520,7 @@ def mock_determine_testcases(res): pb.cleanup_artifacts = mock.Mock() pb.cleanup_device_testing_artifacts = mock.Mock() pb.run = mock.Mock() - pb.gather_metrics = mock.Mock() + pb.gather_metrics = mock.Mock(return_value=metrics_res) pipeline_mock = mock.Mock(put=mock.Mock(side_effect=mock_pipeline_put)) done_mock = mock.Mock() @@ -1742,7 +1791,7 @@ def mock_exists(fname): with mock.patch('os.path.exists', mock_exists), \ mock.patch('builtins.open', mock.mock_open()), \ - mock.patch('yaml.safe_load', return_value=runners_content): + mock.patch('yaml.load', return_value=runners_content): if domain: bins = pb._get_binaries_from_runners(domain) else: diff --git a/scripts/tests/twister/test_testinstance.py b/scripts/tests/twister/test_testinstance.py index 1b1c99a2143..4f820532aea 100644 --- a/scripts/tests/twister/test_testinstance.py +++ b/scripts/tests/twister/test_testinstance.py @@ -226,6 +226,37 @@ def test_testinstance_init(all_testsuites_dict, class_testplan, platforms_list, 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_record(testinstance): + testinstance.testcases = [mock.Mock()] + 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.DictWriter.writerow', + mock.Mock() + ) as mock_writeheader, \ + mock.patch( + 'csv.DictWriter.writerows', + mock.Mock() + ) as mock_writerows: + testinstance.record(recording) + + print(mock_file.mock_calls) + + mock_file.assert_called_with( + os.path.join(testinstance.build_dir, 'recording.csv'), + 'wt' + ) + + mock_writeheader.assert_has_calls([mock.call({ k:k for k in recording[0]})]) + mock_writerows.assert_has_calls([mock.call(recording)]) + + @pytest.mark.parametrize('testinstance', [{'testsuite_kind': 'sample'}], indirect=True) def test_testinstance_add_filter(testinstance): reason = 'dummy reason' diff --git a/scripts/tests/twister/test_testplan.py b/scripts/tests/twister/test_testplan.py index 02eae84494c..daa732db522 100644 --- a/scripts/tests/twister/test_testplan.py +++ b/scripts/tests/twister/test_testplan.py @@ -109,6 +109,7 @@ def test_get_platforms_short(class_testplan, platforms_list): ("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."), + ("build_on_all", True, "level", "foobar", "Unknown test level 'foobar'"), (None, None, "supported_toolchains", ['gcc'], "Not supported by the toolchain"), ] @@ -162,6 +163,9 @@ def test_apply_filters_part1(class_testplan, all_testsuites_dict, platforms_list if tc_attribute == "min_ram": testcase.min_ram = tc_value + if plat_attribute == "level": + plan.options.level = plat_value + if tc_attribute == "build_on_all": for _, testcase in plan.testsuites.items(): testcase.build_on_all = tc_value @@ -417,6 +421,11 @@ def test_testplan_get_level(): res = testplan.get_level(name) assert res == lvl1 + lvl_missed = mock.Mock() + lvl_missed.name = 'missed lvl' + res = testplan.get_level('missed_lvl') + assert res is None + testplan.levels.remove(lvl1) testplan.levels.remove(lvl2) @@ -700,6 +709,7 @@ def test_testplan_load( testplan.testsuites['ts1'].name = 'ts1' testplan.testsuites['ts2'].name = 'ts2' testplan.options = mock.Mock( + report_summary=None, outdir=tmp_path, report_suffix=report_suffix, only_failed=only_failed, @@ -964,7 +974,7 @@ def test_testplan_report_tag_list(capfd): def test_testplan_report_test_tree(capfd): testplan = TestPlan(env=mock.Mock()) - testplan.get_all_tests = mock.Mock( + testplan.get_tests_list = 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', @@ -1022,7 +1032,7 @@ def test_testplan_report_test_tree(capfd): def test_testplan_report_test_list(capfd): testplan = TestPlan(env=mock.Mock()) - testplan.get_all_tests = mock.Mock( + testplan.get_tests_list = 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', @@ -1049,15 +1059,6 @@ def test_testplan_report_test_list(capfd): '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') @@ -1451,7 +1452,7 @@ def get_platform(name): 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.options = mock.Mock(device_testing=device_testing, test_only=True, report_summary=None) testplan.testsuites = { 'TestSuite 1': ts1, 'TestSuite 2': ts2, diff --git a/scripts/tests/twister/test_testsuite.py b/scripts/tests/twister/test_testsuite.py index 74402561fc1..565fa9dadd8 100644 --- a/scripts/tests/twister/test_testsuite.py +++ b/scripts/tests/twister/test_testsuite.py @@ -213,26 +213,41 @@ def test_scan_file(test_data, test_file, class_env, expected: ScanPathResult): assert result == expected -TESTDATA_3 = [ - ( - 'nt', - {'access': mmap.ACCESS_READ} - ), - ( - 'posix', - { - 'flags': mmap.MAP_PRIVATE, - 'prot': mmap.PROT_READ, - 'offset': 0 - } +# Generate testcases depending on available mmap attributes +TESTIDS_3 = [] +TESTDATA_3 = [] + +try: + TESTDATA_3.append( + ( + 'nt', + {'access': mmap.ACCESS_READ} + ) ) -] + TESTIDS_3.append('windows') +except AttributeError: + pass + +try: + TESTDATA_3.append( + ( + 'posix', + { + 'flags': mmap.MAP_PRIVATE, + 'prot': mmap.PROT_READ, + 'offset': 0 + } + ) + ) + TESTIDS_3.append('linux') +except AttributeError: + pass @pytest.mark.parametrize( 'os_name, expected', TESTDATA_3, - ids=['windows', 'linux'] + ids=TESTIDS_3 ) def test_scan_file_mmap(os_name, expected): class TestException(Exception): diff --git a/scripts/tests/twister_blackbox/test_data/boards/others/dummy_board/dummy.yaml b/scripts/tests/twister_blackbox/test_data/boards/others/dummy_board/dummy_board.yaml similarity index 100% rename from scripts/tests/twister_blackbox/test_data/boards/others/dummy_board/dummy.yaml rename to scripts/tests/twister_blackbox/test_data/boards/others/dummy_board/dummy_board.yaml diff --git a/scripts/tests/twister_blackbox/test_data/tests/one_fail_two_error_one_pass/agnostic/group1/subgroup1/CMakeLists.txt b/scripts/tests/twister_blackbox/test_data/tests/one_fail_two_error_one_pass/agnostic/group1/subgroup1/CMakeLists.txt new file mode 100644 index 00000000000..635c696edf9 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/one_fail_two_error_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_two_error_one_pass/agnostic/group1/subgroup1/prj.conf b/scripts/tests/twister_blackbox/test_data/tests/one_fail_two_error_one_pass/agnostic/group1/subgroup1/prj.conf new file mode 100644 index 00000000000..9467c292689 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/one_fail_two_error_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_two_error_one_pass/agnostic/group1/subgroup1/src/main.c b/scripts/tests/twister_blackbox/test_data/tests/one_fail_two_error_one_pass/agnostic/group1/subgroup1/src/main.c new file mode 100644 index 00000000000..3c250486af6 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/one_fail_two_error_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_two_error_one_pass/agnostic/group1/subgroup1/test_data.yaml b/scripts/tests/twister_blackbox/test_data/tests/one_fail_two_error_one_pass/agnostic/group1/subgroup1/test_data.yaml new file mode 100644 index 00000000000..e42250e6b24 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/one_fail_two_error_one_pass/agnostic/group1/subgroup1/test_data.yaml @@ -0,0 +1,11 @@ +tests: + one_fail_two_error_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_two_error_one_pass/agnostic/group1/subgroup2/CMakeLists.txt b/scripts/tests/twister_blackbox/test_data/tests/one_fail_two_error_one_pass/agnostic/group1/subgroup2/CMakeLists.txt new file mode 100644 index 00000000000..635c696edf9 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/one_fail_two_error_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_two_error_one_pass/agnostic/group1/subgroup2/prj.conf b/scripts/tests/twister_blackbox/test_data/tests/one_fail_two_error_one_pass/agnostic/group1/subgroup2/prj.conf new file mode 100644 index 00000000000..9467c292689 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/one_fail_two_error_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_two_error_one_pass/agnostic/group1/subgroup2/src/main.c b/scripts/tests/twister_blackbox/test_data/tests/one_fail_two_error_one_pass/agnostic/group1/subgroup2/src/main.c new file mode 100644 index 00000000000..d896f500c9e --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/one_fail_two_error_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_two_error_one_pass/agnostic/group1/subgroup2/test_data.yaml b/scripts/tests/twister_blackbox/test_data/tests/one_fail_two_error_one_pass/agnostic/group1/subgroup2/test_data.yaml new file mode 100644 index 00000000000..b2813ad46e1 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/one_fail_two_error_one_pass/agnostic/group1/subgroup2/test_data.yaml @@ -0,0 +1,11 @@ +tests: + one_fail_two_error_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/tests/one_fail_two_error_one_pass/agnostic/group1/subgroup3/CMakeLists.txt b/scripts/tests/twister_blackbox/test_data/tests/one_fail_two_error_one_pass/agnostic/group1/subgroup3/CMakeLists.txt new file mode 100644 index 00000000000..635c696edf9 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/one_fail_two_error_one_pass/agnostic/group1/subgroup3/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_two_error_one_pass/agnostic/group1/subgroup3/prj.conf b/scripts/tests/twister_blackbox/test_data/tests/one_fail_two_error_one_pass/agnostic/group1/subgroup3/prj.conf new file mode 100644 index 00000000000..9467c292689 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/one_fail_two_error_one_pass/agnostic/group1/subgroup3/prj.conf @@ -0,0 +1 @@ +CONFIG_ZTEST=y diff --git a/scripts/tests/twister_blackbox/test_data/tests/one_fail_two_error_one_pass/agnostic/group1/subgroup3/src/main.c b/scripts/tests/twister_blackbox/test_data/tests/one_fail_two_error_one_pass/agnostic/group1/subgroup3/src/main.c new file mode 100644 index 00000000000..04b4de0e086 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/one_fail_two_error_one_pass/agnostic/group1/subgroup3/src/main.c @@ -0,0 +1,23 @@ +/* + * 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) +{ + dummy + zassert_true(0, "1 was false"); + zassert_false(1, "0 was true"); +} diff --git a/scripts/tests/twister_blackbox/test_data/tests/one_fail_two_error_one_pass/agnostic/group1/subgroup3/test_data.yaml b/scripts/tests/twister_blackbox/test_data/tests/one_fail_two_error_one_pass/agnostic/group1/subgroup3/test_data.yaml new file mode 100644 index 00000000000..c5c9486c735 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/one_fail_two_error_one_pass/agnostic/group1/subgroup3/test_data.yaml @@ -0,0 +1,11 @@ +tests: + one_fail_two_error_one_pass.agnostic.group1.subgroup3: + 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_two_error_one_pass/agnostic/group1/subgroup4/CMakeLists.txt b/scripts/tests/twister_blackbox/test_data/tests/one_fail_two_error_one_pass/agnostic/group1/subgroup4/CMakeLists.txt new file mode 100644 index 00000000000..635c696edf9 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/one_fail_two_error_one_pass/agnostic/group1/subgroup4/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_two_error_one_pass/agnostic/group1/subgroup4/prj.conf b/scripts/tests/twister_blackbox/test_data/tests/one_fail_two_error_one_pass/agnostic/group1/subgroup4/prj.conf new file mode 100644 index 00000000000..9467c292689 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/one_fail_two_error_one_pass/agnostic/group1/subgroup4/prj.conf @@ -0,0 +1 @@ +CONFIG_ZTEST=y diff --git a/scripts/tests/twister_blackbox/test_data/tests/one_fail_two_error_one_pass/agnostic/group1/subgroup4/src/main.c b/scripts/tests/twister_blackbox/test_data/tests/one_fail_two_error_one_pass/agnostic/group1/subgroup4/src/main.c new file mode 100644 index 00000000000..04b4de0e086 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/one_fail_two_error_one_pass/agnostic/group1/subgroup4/src/main.c @@ -0,0 +1,23 @@ +/* + * 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) +{ + dummy + zassert_true(0, "1 was false"); + zassert_false(1, "0 was true"); +} diff --git a/scripts/tests/twister_blackbox/test_data/tests/one_fail_two_error_one_pass/agnostic/group1/subgroup4/test_data.yaml b/scripts/tests/twister_blackbox/test_data/tests/one_fail_two_error_one_pass/agnostic/group1/subgroup4/test_data.yaml new file mode 100644 index 00000000000..a4957e6f5eb --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/one_fail_two_error_one_pass/agnostic/group1/subgroup4/test_data.yaml @@ -0,0 +1,11 @@ +tests: + one_fail_two_error_one_pass.agnostic.group1.subgroup4: + platform_allow: + - native_posix + - qemu_x86 + - qemu_x86_64 + integration_platforms: + - native_posix + tags: + - agnostic + - subgrouped diff --git a/scripts/tests/twister_blackbox/test_report.py b/scripts/tests/twister_blackbox/test_report.py index 80f8f722a3e..e116bea3da1 100644 --- a/scripts/tests/twister_blackbox/test_report.py +++ b/scripts/tests/twister_blackbox/test_report.py @@ -13,10 +13,12 @@ import pytest import shutil import sys +import re from lxml import etree -from conftest import TEST_DATA, ZEPHYR_BASE, testsuite_filename_mock +# pylint: disable=no-name-in-module +from conftest import TEST_DATA, ZEPHYR_BASE, testsuite_filename_mock, clear_log_in_test from twisterlib.testplan import TestPlan @@ -106,6 +108,15 @@ class TestReport: "TEST_LOG_FILE.log" ), ] + TESTDATA_7 = [ + ( + os.path.join(TEST_DATA, 'tests', 'one_fail_two_error_one_pass'), + ['qemu_x86'], + [r'one_fail_two_error_one_pass.agnostic.group1.subgroup2 on qemu_x86 FAILED \(Failed\)', + r'one_fail_two_error_one_pass.agnostic.group1.subgroup3 on qemu_x86 ERROR \(Build failure\)', + r'one_fail_two_error_one_pass.agnostic.group1.subgroup4 on qemu_x86 ERROR \(Build failure\)'], + ) + ] @classmethod def setup_class(cls): @@ -397,3 +408,65 @@ def test_enable_size_report(self, out_path): if ts['name'] == expected_rel_path and not 'reason' in ts ] ) + + @pytest.mark.parametrize( + 'test_path, test_platforms, expected_content', + TESTDATA_7, + ids=[ + 'Report summary test' + ] + ) + + def test_report_summary(self, out_path, capfd, test_path, test_platforms, expected_content): + args = ['-i', '--outdir', out_path, '-T', test_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) + + assert str(sys_exit.value) == '1' + + capfd.readouterr() + + clear_log_in_test() + + args += ['--report-summary'] + + 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_content: + result = re.search(line, err) + assert result, f'missing information in log: {line}' + + capfd.readouterr() + + clear_log_in_test() + + args = ['-i', '--outdir', out_path, '-T', test_path] + \ + ['--report-summary', '2'] + \ + [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) + + lines=0 + for line in expected_content: + result = re.search(line, err) + if result: lines += 1 + assert lines == 2, f'too many or too few lines' diff --git a/scripts/twister b/scripts/twister index aa075beb7a1..c6382f9a9e3 100755 --- a/scripts/twister +++ b/scripts/twister @@ -211,7 +211,8 @@ if __name__ == "__main__": try: parser = add_parse_arguments() options = parse_arguments(parser, sys.argv[1:]) - ret = main(options) + default_options = parse_arguments(parser, [], on_init=False) + ret = main(options, default_options) finally: if (os.name != "nt") and os.isatty(1): # (OS is not Windows) and (stdout is interactive) diff --git a/scripts/west-commands.yml b/scripts/west-commands.yml index 803d2b7b2d1..6cd0c511fb3 100644 --- a/scripts/west-commands.yml +++ b/scripts/west-commands.yml @@ -10,6 +10,11 @@ west-commands: - name: boards class: Boards help: display information about supported boards + - file: scripts/west_commands/shields.py + commands: + - name: shields + class: Shields + help: display list of supported shields - file: scripts/west_commands/build.py commands: - name: build diff --git a/scripts/west_commands/build.py b/scripts/west_commands/build.py index 832b4058a04..2e675a72293 100644 --- a/scripts/west_commands/build.py +++ b/scripts/west_commands/build.py @@ -29,6 +29,7 @@ BUILD_USAGE = '''\ west build [-h] [-b BOARD[@REV]]] [-d BUILD_DIR] + [-S SNIPPET] [--shield SHIELD] [-t TARGET] [-p {auto, always, never}] [-c] [--cmake-only] [-n] [-o BUILD_OPT] [-f] [--sysbuild | --no-sysbuild] [--domain DOMAIN] @@ -140,13 +141,20 @@ def do_add_parser(self, parser_adder): group.add_argument('-n', '--just-print', '--dry-run', '--recon', dest='dry_run', action='store_true', help="just print build commands; don't run them") - group.add_argument('-S', '--snippet', dest='snippets', + group.add_argument('-S', '--snippet', dest='snippets', metavar='SNIPPET', action='append', default=[], help='''add the argument to SNIPPET; may be given multiple times. Forces CMake to run again if given. Do not use this option with manually specified -DSNIPPET... cmake arguments: the results are undefined''') + group.add_argument('--shield', dest='shields', metavar='SHIELD', + action='append', default=[], + help='''add the argument to SHIELD; may be given + multiple times. Forces CMake to run again if given. + Do not use this option with manually specified + -DSHIELD... cmake arguments: the results are + undefined''') group = parser.add_mutually_exclusive_group() group.add_argument('--sysbuild', action='store_true', @@ -219,7 +227,8 @@ def do_run(self, args, remainder): else: self._update_cache() if (self.args.cmake or self.args.cmake_opts or - self.args.cmake_only or self.args.snippets): + self.args.cmake_only or self.args.snippets or + self.args.shields): self.run_cmake = True else: self.run_cmake = True @@ -272,7 +281,7 @@ def _parse_remainder(self, remainder): if remainder: self.args.cmake_opts = remainder except IndexError: - return + pass def _parse_test_item(self, test_item): found_test_metadata = False @@ -557,6 +566,8 @@ def _run_cmake(self, board, origin, cmake_opts): cmake_opts.extend(self.args.cmake_opts) if self.args.snippets: cmake_opts.append(f'-DSNIPPET={";".join(self.args.snippets)}') + if self.args.shields: + cmake_opts.append(f'-DSHIELD={";".join(self.args.shields)}') user_args = config_get('cmake-args', None) if user_args: diff --git a/scripts/west_commands/completion/west-completion.bash b/scripts/west_commands/completion/west-completion.bash index d812e8933b1..3a528cded68 100644 --- a/scripts/west_commands/completion/west-completion.bash +++ b/scripts/west_commands/completion/west-completion.bash @@ -401,6 +401,11 @@ __set_comp_west_boards() __set_comp ${boards[@]} } +__set_comp_west_shields() +{ + __set_comp "$(__west_x shields "$@")" +} + __comp_west_west() { case "$prev" in @@ -689,6 +694,37 @@ __comp_west_boards() esac } +__comp_west_shields() +{ + local other_opts=" + --format -f + --name -n + " + + local dir_opts=" + --board-root + " + + all_opts="$dir_opts $other_opts" + + case "$prev" in + $(__west_to_extglob "$other_opts") ) + # We don't know how to autocomplete these. + return + ;; + $(__west_to_extglob "$dir_opts") ) + __set_comp_dirs + return + ;; + esac + + case "$cur" in + -*) + __set_comp $all_opts + ;; + esac +} + __comp_west_build() { local bool_opts=" @@ -702,6 +738,8 @@ __comp_west_build() local special_opts=" --board -b + --snippet -S + --shield --pristine -p " @@ -722,6 +760,10 @@ __comp_west_build() __set_comp_west_boards return ;; + --shield) + __set_comp_west_shields + return + ;; --pristine|-p) __set_comp "auto always never" return @@ -930,6 +972,175 @@ __comp_west_blobs() esac } +__comp_west_twister() +{ + local bool_opts=" + --aggressive-no-clean + --all -l + --all-deltas -D + --allow-installed-plugin + --build-only -b + --clobber-output -c + --cmake-only + --coverage -C + --create-rom-ram-report + --detailed-skipped-report + --detailed-test-id + --device-flash-with-test + --device-testing + --disable-suite-name-check + --disable-unrecognized-section-test + --disable-warnings-as-errors -W + --dry-run -y + --emulation-only + --enable-asan + --enable-coverage + --enable-lsan + --enable-size-report + --enable-slow -S + --enable-slow-only + --enable-ubsan + --enable-valgrind + --flash-before + --footprint-from-buildlog + --force-color + --force-platform -K + --force-toolchain + --ignore-platform-key + --inline-logs -i + --integration -G + --last-metrics -m + --list-tags + --list-tests + --make -k + --ninja -N + --no-clean -n + --no-detailed-test-id + --no-update -u + --only-failed -f + --overflow-as-errors + --persistent-hardware-map + --platform-reports + --prep-artifacts-for-testing + --quarantine-verify + --retry-build-errors + --short-build-path + --show-footprint + --shuffle-tests + --test-only + --test-tree + --timestamps + --verbose -v + " + + local dir_opts=" + --alt-config-root + --board-root -A + --coverage-basedir + --outdir -O + --report-dir -o + --testsuite-root -T + " + + local file_opts=" + --compare-report + --device-serial + --device-serial-pty + --gcov-tool + --generate-hardware-map + --hardware-map + --load-tests -F + --log-file + --package-artifacts + --pre-script + --quarantine-list + --save-tests -E + --size -z + --test-config + " + + local special_opts=" + --coverage-platform + --coverage-tool + --exclude-platform -P + --filter + --platform -p + --runtime-artifact-cleanup -M + " + + local other_opts=" + --arch -a + --coverage-formats + --device-flash-timeout + --device-serial-baud + --exclude-tag -e + --extra-args -x + --fixture -X + --footprint-threshold -H + --jobs -j + --level + --pytest-args + --report-name + --report-suffix + --retry-failed + --retry-interval + --scenario --test -s + --seed + --shuffle-tests-seed + --sub-test + --subset -B + --tag -t + --timeout-multiplier + --vendor + --west-flash + --west-runner + " + + all_opts="$bool_opts $dir_opts $file_opts $special_opts $other_opts" + + case "$prev" in + --platform|-p|--exclude-platform|-P|--coverage-platform) + __set_comp_west_boards + return + ;; + + --coverage-tool) + __set_comp "gcovr lcov" + return + ;; + + --filter) + __set_comp "buildable runnable" + return + ;; + + --runtime-artifact-cleanup|-M) + __set_comp "all pass" + return + ;; + + $(__west_to_extglob "$dir_opts") ) + __set_comp_dirs + return + ;; + + $(__west_to_extglob "$file_opts") ) + __set_comp_files + return + ;; + + # We don't know how to autocomplete those + $(__west_to_extglob "$other_opts") ) + return + ;; + esac + + case "$cur" in + -*) + __set_comp $all_opts + ;; + esac +} __comp_west() { @@ -954,6 +1165,7 @@ __comp_west() local zephyr_ext_cmds=( completion boards + shields build sign flash @@ -963,6 +1175,7 @@ __comp_west() zephyr-export spdx blobs + twister ) local cmds=(${builtin_cmds[*]} ${zephyr_ext_cmds[*]}) diff --git a/scripts/west_commands/runners/linkserver.py b/scripts/west_commands/runners/linkserver.py index b87c594c4ae..9f15dac3135 100644 --- a/scripts/west_commands/runners/linkserver.py +++ b/scripts/west_commands/runners/linkserver.py @@ -1,4 +1,4 @@ -# Copyright 2023 NXP +# Copyright 2023-2024 NXP # Copyright (c) 2017 Linaro Limited. # # SPDX-License-Identifier: Apache-2.0 @@ -164,13 +164,8 @@ def do_run(self, command, **kwargs): def do_erase(self, **kwargs): - if self.core is not None: - _cmd_core = ":"+self.core - else: - _cmd_core = "" - linkserver_cmd = ([self.linkserver, "flash"] + ["--probe", str(self.probe)] + - [self.device+_cmd_core] + ["erase"]) + [self.device] + ["erase"]) self.logger.debug("flash erase command = " + str(linkserver_cmd)) self.check_call(linkserver_cmd) @@ -186,18 +181,16 @@ def _build_override_cli(self): def flash(self, **kwargs): - if self.core is not None: - _cmd_core = ":"+self.core - else: - _cmd_core = "" - - linkserver_cmd = ([self.linkserver, "flash"] + ["--probe", str(self.probe)] + self.override_cli + [self.device+_cmd_core]) + linkserver_cmd = ([self.linkserver, "flash"] + ["--probe", str(self.probe)] + self.override_cli + [self.device]) self.logger.debug(f'LinkServer cmd: + {linkserver_cmd}') if self.erase: self.do_erase() - if self.bin_name is not None and os.path.isfile(self.bin_name): + # Use .hex or .bin, preferring .hex over .bin + if self.supports_hex and self.hex_name is not None and os.path.isfile(self.hex_name): + flash_cmd = (["load", self.hex_name]) + elif self.bin_name is not None and os.path.isfile(self.bin_name): if self.dt_flash: load_addr = self.flash_address_from_build_conf(self.build_conf) else: @@ -206,10 +199,10 @@ def flash(self, **kwargs): flash_cmd = (["load", "--addr", str(load_addr), self.bin_name]) else: - err = 'Cannot flash; no bin ({}) file found.' - raise ValueError(err.format(self.bin_name)) + err = 'Cannot flash; no hex ({}) or bin ({}) file found.' + raise ValueError(err.format(self.hex_name, self.bin_name)) - # Flash the selected elf file + # Flash the selected file linkserver_cmd = linkserver_cmd + flash_cmd self.logger.debug("flash command = " + str(linkserver_cmd)) kwargs = {} @@ -220,3 +213,7 @@ def flash(self, **kwargs): kwargs['stdout'] = subprocess.DEVNULL self.check_call(linkserver_cmd, **kwargs) + + def supports_hex(self): + # v1.5.30 has added flash support for Intel Hex files. + return self.linkserver_version_str >= "v1.5.30" diff --git a/scripts/west_commands/runners/mdb.py b/scripts/west_commands/runners/mdb.py index 656d41618a6..cc44390e279 100644 --- a/scripts/west_commands/runners/mdb.py +++ b/scripts/west_commands/runners/mdb.py @@ -34,6 +34,16 @@ def is_flash_cmd_need_exit_immediately(mdb_runner): else: return True +def smp_core_order(mdb_runner, id): + if is_simulation_run(mdb_runner): + # for simulation targets we start cores in direct order (core 0 first, core 1 second, etc...) + # otherwise we face mismatch arcnum (code ID) with ARConnect ID and core ID in instruction traces + return id + else: + # for HW targets we want to start the primary core last, to avoid ARConnect initialization interfere + # with secondary cores startup - so we reverse start order + return mdb_runner.cores - 1 - id + def mdb_do_run(mdb_runner, command): commander = "mdb64" @@ -81,7 +91,7 @@ def mdb_do_run(mdb_runner, command): if i > 0: mdb_sub_cmd += ['-prop=download=2'] mdb_sub_cmd += mdb_basic_options + mdb_target + [mdb_runner.elf_name] mdb_runner.check_call(mdb_sub_cmd, cwd=mdb_runner.build_dir) - mdb_multifiles += ('core{}'.format(mdb_runner.cores-1-i) if i == 0 else ',core{}'.format(mdb_runner.cores-1-i)) + mdb_multifiles += ('core{}' if i == 0 else ',core{}').format(smp_core_order(mdb_runner, i)) # to enable multi-core aware mode for use with the MetaWare debugger, # need to set the NSIM_MULTICORE environment variable to a non-zero value diff --git a/scripts/west_commands/runners/openocd.py b/scripts/west_commands/runners/openocd.py index dd7c6882a36..33777056879 100644 --- a/scripts/west_commands/runners/openocd.py +++ b/scripts/west_commands/runners/openocd.py @@ -11,6 +11,7 @@ from os import path from pathlib import Path +from zephyr_ext_common import ZEPHYR_BASE try: from elftools.elf.elffile import ELFFile @@ -40,7 +41,14 @@ def __init__(self, cfg, pre_init=None, reset_halt_cmd=DEFAULT_OPENOCD_RESET_HALT target_handle=DEFAULT_OPENOCD_TARGET_HANDLE): super().__init__(cfg) - support = path.join(cfg.board_dir, 'support') + if not path.exists(cfg.board_dir): + # try to find the board support in-tree + cfg_board_path = path.normpath(cfg.board_dir) + _temp_path = cfg_board_path.split("boards/")[1] + support = path.join(ZEPHYR_BASE, "boards", _temp_path, 'support') + else: + support = path.join(cfg.board_dir, 'support') + if not config: default = path.join(support, 'openocd.cfg') diff --git a/scripts/west_commands/shields.py b/scripts/west_commands/shields.py new file mode 100644 index 00000000000..c0916460395 --- /dev/null +++ b/scripts/west_commands/shields.py @@ -0,0 +1,86 @@ +# Copyright (c) 2024 Vestas Wind Systems A/S +# Copyright (c) 2019 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +import argparse +import os +from pathlib import Path +import re +import sys +import textwrap + +from west import log +from west.commands import WestCommand + +from zephyr_ext_common import ZEPHYR_BASE + +sys.path.append(os.fspath(Path(__file__).parent.parent)) +import list_shields +import zephyr_module + +class Shields(WestCommand): + + def __init__(self): + super().__init__( + 'shields', + # Keep this in sync with the string in west-commands.yml. + 'display list of supported shield', + 'Display supported shields', + accepts_unknown_args=False) + + def do_add_parser(self, parser_adder): + default_fmt = '{name}' + parser = parser_adder.add_parser( + self.name, + help=self.help, + formatter_class=argparse.RawDescriptionHelpFormatter, + description=self.description, + epilog=textwrap.dedent(f'''\ + FORMAT STRINGS + -------------- + + Shields are listed using a Python 3 format string. Arguments + to the format string are accessed by name. + + The default format string is: + + "{default_fmt}" + + The following arguments are available: + + - name: shield name + - dir: directory that contains the shield definition + ''')) + + # Remember to update west-completion.bash if you add or remove + # flags + parser.add_argument('-f', '--format', default=default_fmt, + help='''Format string to use to list each shield; + see FORMAT STRINGS below.''') + parser.add_argument('-n', '--name', dest='name_re', + help='''a regular expression; only shields whose + names match NAME_RE will be listed''') + list_shields.add_args(parser) + + return parser + + def do_run(self, args, _): + if args.name_re is not None: + name_re = re.compile(args.name_re) + else: + name_re = None + + modules_board_roots = [ZEPHYR_BASE] + + for module in zephyr_module.parse_modules(ZEPHYR_BASE, self.manifest): + board_root = module.meta.get('build', {}).get('settings', {}).get('board_root') + if board_root is not None: + modules_board_roots.append(Path(module.project) / board_root) + + args.board_roots += modules_board_roots + + for shield in list_shields.find_shields(args): + if name_re is not None and not name_re.search(shield.name): + continue + log.inf(args.format.format(name=shield.name, dir=shield.dir)) diff --git a/scripts/west_commands/sign.py b/scripts/west_commands/sign.py index 8e9321e46cf..71ad5c815bb 100644 --- a/scripts/west_commands/sign.py +++ b/scripts/west_commands/sign.py @@ -406,7 +406,7 @@ def edt_flash_params(flash): # The partitions node, and its subnode, must provide # the size of slot1_partition or slot0_partition partition via the regs property. - slot_key = 'slot0_partition' if 'slot1_partition' in slots else 'slot0_partition' + slot_key = 'slot1_partition' if 'slot1_partition' in slots else 'slot0_partition' if not slots[slot_key].regs: log.die(f'{slot_key} flash partition has no regs property;', "can't determine size of slot") diff --git a/scripts/west_commands/tests/test_mdb.py b/scripts/west_commands/tests/test_mdb.py index ca07b5d1640..27567490282 100644 --- a/scripts/west_commands/tests/test_mdb.py +++ b/scripts/west_commands/tests/test_mdb.py @@ -55,7 +55,7 @@ '-prop=download=2', '-nooptions', '-nogoifmain', '-toggle=include_local_symbols=1', '-nsim', TEST_BOARD_NSIM_ARGS, RC_KERNEL_ELF] -TEST_NSIM_CORES_LAUNCH = [TEST_DRIVER_CMD, '-multifiles=core1,core0', +TEST_NSIM_CORES_LAUNCH = [TEST_DRIVER_CMD, '-multifiles=core0,core1', '-run', '-cl'] # mdb-hw diff --git a/scripts/west_commands/twister_cmd.py b/scripts/west_commands/twister_cmd.py index b10aae71d43..266b60d2bf2 100644 --- a/scripts/west_commands/twister_cmd.py +++ b/scripts/west_commands/twister_cmd.py @@ -56,8 +56,9 @@ def do_run(self, args, remainder): "args: {} remainder: {}".format(args, remainder), level=log.VERBOSE_EXTREME ) - options = self._parse_arguments(args=remainder, options=args) - ret = main(options) + options = parse_arguments(self.parser, args=remainder, options=args) + default_options = parse_arguments(self.parser, args=[], on_init=False) + ret = main(options, default_options) sys.exit(ret) def _parse_arguments(self, args, options): diff --git a/scripts/west_commands/zspdx/datatypes.py b/scripts/west_commands/zspdx/datatypes.py index 1e65d96e995..ca7b92d1cbf 100644 --- a/scripts/west_commands/zspdx/datatypes.py +++ b/scripts/west_commands/zspdx/datatypes.py @@ -68,6 +68,9 @@ def __init__(self): # SPDX ID, including "SPDXRef-" self.spdxID = "" + # primary package purpose (ex. "LIBRARY", "APPLICATION", etc.) + self.primaryPurpose = "" + # the Package's declared license self.declaredLicense = "NOASSERTION" @@ -95,7 +98,7 @@ def __init__(self, cfg, doc): # Document that owns this Package self.doc = doc - # verification code, calculated per section 3.9 of SPDX spec v2.2 + # verification code, calculated per section 7.9 of SPDX spec v2.3 self.verificationCode = "" # concluded license for this Package, if @@ -161,7 +164,7 @@ def __init__(self): self.otherPackageID = "" # text string with Relationship type - # from table in section 7.1 of SPDX spec v2.2 + # from table 68 in section 11.1 of SPDX spec v2.3 self.rlnType = "" # Relationship contains the post-analysis, processed data about a relationship @@ -180,7 +183,7 @@ def __init__(self): self.refB = "" # text string with Relationship type - # from table in section 7.1 of SPDX spec v2.2 + # from table 68 in section 11.1 of SPDX spec v2.3 self.rlnType = "" # File contains the data needed to create a File element in the context of a diff --git a/scripts/west_commands/zspdx/scanner.py b/scripts/west_commands/zspdx/scanner.py index 02987c0cd8e..a259325b189 100644 --- a/scripts/west_commands/zspdx/scanner.py +++ b/scripts/west_commands/zspdx/scanner.py @@ -30,7 +30,7 @@ def __init__(self): self.numLinesScanned = 20 # should we calculate SHA256 hashes for each Package's Files? - # note that SHA1 hashes are mandatory, per SPDX 2.2 + # note that SHA1 hashes are mandatory, per SPDX 2.3 self.doSHA256 = True # should we calculate MD5 hashes for each Package's Files? @@ -159,7 +159,7 @@ def normalizeExpression(licsConcluded): return licsConcluded[0] # more than one, so we'll need to combine them - # iff an expression has spaces, it needs parens + # if and only if an expression has spaces, it needs parens revised = [] for lic in licsConcluded: if lic in ["NONE", "NOASSERTION"]: diff --git a/scripts/west_commands/zspdx/walker.py b/scripts/west_commands/zspdx/walker.py index 0c6469444ed..45e63b29543 100644 --- a/scripts/west_commands/zspdx/walker.py +++ b/scripts/west_commands/zspdx/walker.py @@ -157,6 +157,7 @@ def setupAppDocument(self): cfgPackageApp = PackageConfig() cfgPackageApp.name = "app-sources" cfgPackageApp.spdxID = "SPDXRef-app-sources" + cfgPackageApp.primaryPurpose = "SOURCE" # relativeBaseDir is app sources dir cfgPackageApp.relativeBaseDir = self.cm.paths_source pkgApp = Package(cfgPackageApp, self.docApp) @@ -235,6 +236,7 @@ def setupZephyrDocument(self, modules): cfgPackageZephyrModule.name = module_name cfgPackageZephyrModule.spdxID = "SPDXRef-" + module_name + "-sources" cfgPackageZephyrModule.relativeBaseDir = module_path + cfgPackageZephyrModule.primaryPurpose = "SOURCE" pkgZephyrModule = Package(cfgPackageZephyrModule, self.docZephyr) self.docZephyr.pkgs[pkgZephyrModule.cfg.spdxID] = pkgZephyrModule @@ -313,6 +315,10 @@ def walkTargets(self): if len(cfgTarget.target.artifacts) > 0: # add its build file bf = self.addBuildFile(cfgTarget, pkg) + if pkg.cfg.name == "zephyr_final": + pkg.cfg.primaryPurpose = "APPLICATION" + else: + pkg.cfg.primaryPurpose = "LIBRARY" # get its source files if build file is found if bf: diff --git a/scripts/west_commands/zspdx/writer.py b/scripts/west_commands/zspdx/writer.py index b8afaa47953..a6bdddae52d 100644 --- a/scripts/west_commands/zspdx/writer.py +++ b/scripts/west_commands/zspdx/writer.py @@ -8,14 +8,14 @@ from zspdx.util import getHashes -# Output tag-value SPDX 2.2 content for the given Relationship object. +# Output tag-value SPDX 2.3 content for the given Relationship object. # Arguments: # 1) f: file handle for SPDX document # 2) rln: Relationship object being described def writeRelationshipSPDX(f, rln): f.write(f"Relationship: {rln.refA} {rln.rlnType} {rln.refB}\n") -# Output tag-value SPDX 2.2 content for the given File object. +# Output tag-value SPDX 2.3 content for the given File object. # Arguments: # 1) f: file handle for SPDX document # 2) bf: File object being described @@ -42,7 +42,7 @@ def writeFileSPDX(f, bf): writeRelationshipSPDX(f, rln) f.write("\n") -# Output tag-value SPDX 2.2 content for the given Package object. +# Output tag-value SPDX 2.3 content for the given Package object. # Arguments: # 1) f: file handle for SPDX document # 2) pkg: Package object being described @@ -58,6 +58,9 @@ def writePackageSPDX(f, pkg): PackageCopyrightText: {pkg.cfg.copyrightText} """) + if pkg.cfg.primaryPurpose != "": + f.write(f"PrimaryPackagePurpose: {pkg.cfg.primaryPurpose}\n") + # flag whether files analyzed / any files present if len(pkg.files) > 0: if len(pkg.licenseInfoFromFiles) > 0: @@ -82,7 +85,7 @@ def writePackageSPDX(f, pkg): for bf in bfs: writeFileSPDX(f, bf) -# Output tag-value SPDX 2.2 content for a custom license. +# Output tag-value SPDX 2.3 content for a custom license. # Arguments: # 1) f: file handle for SPDX document # 2) lic: custom license ID being described @@ -93,12 +96,12 @@ def writeOtherLicenseSPDX(f, lic): LicenseComment: Corresponds to the license ID `{lic}` detected in an SPDX-License-Identifier: tag. """) -# Output tag-value SPDX 2.2 content for the given Document object. +# Output tag-value SPDX 2.3 content for the given Document object. # Arguments: # 1) f: file handle for SPDX document # 2) doc: Document object being described def writeDocumentSPDX(f, doc): - f.write(f"""SPDXVersion: SPDX-2.2 + f.write(f"""SPDXVersion: SPDX-2.3 DataLicense: CC0-1.0 SPDXID: SPDXRef-DOCUMENT DocumentName: {doc.cfg.name} diff --git a/scripts/zephyr_module.py b/scripts/zephyr_module.py index b5b257ed712..2bb72e810f4 100755 --- a/scripts/zephyr_module.py +++ b/scripts/zephyr_module.py @@ -28,6 +28,11 @@ from pathlib import Path, PurePath from collections import namedtuple +try: + from yaml import CSafeLoader as SafeLoader +except ImportError: + from yaml import SafeLoader + METADATA_SCHEMA = ''' ## A pykwalify schema for basic validation of the structure of a ## metadata YAML file. @@ -156,7 +161,7 @@ BLOB_NOT_PRESENT = 'D' BLOB_OUTDATED = 'M' -schema = yaml.safe_load(METADATA_SCHEMA) +schema = yaml.load(METADATA_SCHEMA, Loader=SafeLoader) def validate_setting(setting, module_path, filename=None): @@ -180,7 +185,7 @@ def process_module(module): module_path / MODULE_YML_PATH.with_suffix('.yaml')]: if Path(module_yml).is_file(): with Path(module_yml).open('r') as f: - meta = yaml.safe_load(f.read()) + meta = yaml.load(f.read(), Loader=SafeLoader) try: pykwalify.core.Core(source_data=meta, schema_data=schema)\ diff --git a/share/sysbuild/cmake/modules/sysbuild_extensions.cmake b/share/sysbuild/cmake/modules/sysbuild_extensions.cmake index 1a9dbedf412..ce0af2fe7b3 100644 --- a/share/sysbuild/cmake/modules/sysbuild_extensions.cmake +++ b/share/sysbuild/cmake/modules/sysbuild_extensions.cmake @@ -597,7 +597,7 @@ function(sysbuild_cache_set) return() elseif(VARS_REMOVE_DUPLICATES AND NOT VARS_APPEND) message(FATAL_ERROR - "sysbuild_set(VAR APPEND REMOVE_DUPLICATES ...) missing required APPEND option") + "sysbuild_cache_set(VAR APPEND REMOVE_DUPLICATES ...) missing required APPEND option") endif() get_property(var_type CACHE ${VARS_VAR} PROPERTY TYPE) @@ -615,9 +615,7 @@ function(sysbuild_cache_set) # Search for these exact items in the existing value and prevent adding # them if they are already present which avoids issues with double addition # when cmake is reran. - string(FIND "$CACHE{${VARS_VAR}}" "${VARS_UNPARSED_ARGUMENTS}" index) - - if(NOT ${index} EQUAL -1) + if("${VARS_UNPARSED_ARGUMENTS}" IN_LIST var_new) return() endif() diff --git a/snippets/nordic-flpr-xip/README.rst b/snippets/nordic-flpr-xip/README.rst new file mode 100644 index 00000000000..1f7061e85df --- /dev/null +++ b/snippets/nordic-flpr-xip/README.rst @@ -0,0 +1,12 @@ +.. _nordic-flpr-xip: + +Nordic FLPR snippet with execution in place (nordic-flpr-xip) +############################################################# + +Overview +******** + +This snippet allows users to build Zephyr with the capability to boot Nordic FLPR +(Fast Lightweight Peripheral Processor) from application core. +FLPR code is to be executed from RRAM, so the FLPR image must be built +for the ``xip`` board variant, or with :kconfig:option:`CONFIG_XIP` enabled. diff --git a/snippets/nordic-flpr-xip/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay b/snippets/nordic-flpr-xip/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay new file mode 100644 index 00000000000..c473c27c319 --- /dev/null +++ b/snippets/nordic-flpr-xip/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + soc { + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + cpuflpr_code_partition: image@165000 { + /* FLPR core code partition */ + reg = <0x165000 DT_SIZE_K(96)>; + }; + }; + }; +}; + +&uart30 { + status = "reserved"; +}; + +&cpuflpr_vpr { + execution-memory = <&cpuflpr_code_partition>; +}; diff --git a/snippets/nordic-flpr-xip/nordic-flpr-xip.overlay b/snippets/nordic-flpr-xip/nordic-flpr-xip.overlay new file mode 100644 index 00000000000..fc5e048ad5d --- /dev/null +++ b/snippets/nordic-flpr-xip/nordic-flpr-xip.overlay @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor + * SPDX-License-Identifier: Apache-2.0 + */ + +&cpuflpr_vpr { + status = "okay"; +}; + +&cpuflpr_vevif_remote { + status = "okay"; +}; diff --git a/snippets/nordic-flpr-xip/snippet.yml b/snippets/nordic-flpr-xip/snippet.yml new file mode 100644 index 00000000000..d7ca9c25a23 --- /dev/null +++ b/snippets/nordic-flpr-xip/snippet.yml @@ -0,0 +1,8 @@ +name: nordic-flpr-xip +append: + EXTRA_DTC_OVERLAY_FILE: nordic-flpr-xip.overlay + +boards: + nrf54l15pdk/nrf54l15/cpuapp: + append: + EXTRA_DTC_OVERLAY_FILE: boards/nrf54l15pdk_nrf54l15_cpuapp.overlay diff --git a/snippets/nordic-flpr/README.rst b/snippets/nordic-flpr/README.rst new file mode 100644 index 00000000000..eb519856124 --- /dev/null +++ b/snippets/nordic-flpr/README.rst @@ -0,0 +1,12 @@ +.. _nordic-flpr: + +Nordic FLPR snippet with execution from SRAM (nordic-flpr) +########################################################## + +Overview +******** + +This snippet allows users to build Zephyr with the capability to boot Nordic FLPR +(Fast Lightweight Peripheral Processor) from application core. +FLPR code is to be executed from SRAM, so the FLPR image must be built +without the ``xip`` board variant, or with :kconfig:option:`CONFIG_XIP` disabled. diff --git a/snippets/nordic-flpr/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay b/snippets/nordic-flpr/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay new file mode 100644 index 00000000000..84d6b71b047 --- /dev/null +++ b/snippets/nordic-flpr/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + soc { + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + cpuflpr_code_partition: image@165000 { + /* FLPR core code partition */ + reg = <0x165000 DT_SIZE_K(96)>; + }; + }; + + cpuflpr_sram_code_data: memory@20028000 { + compatible = "mmio-sram"; + reg = <0x20028000 DT_SIZE_K(96)>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x20028000 0x18000>; + }; + }; +}; + +&uart30 { + status = "reserved"; +}; + +&cpuapp_sram { + reg = <0x20000000 DT_SIZE_K(160)>; + ranges = <0x0 0x20000000 0x28000>; +}; + +&cpuflpr_vpr { + execution-memory = <&cpuflpr_sram_code_data>; + source-memory = <&cpuflpr_code_partition>; +}; diff --git a/snippets/nordic-flpr/nordic-flpr.overlay b/snippets/nordic-flpr/nordic-flpr.overlay new file mode 100644 index 00000000000..fc5e048ad5d --- /dev/null +++ b/snippets/nordic-flpr/nordic-flpr.overlay @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor + * SPDX-License-Identifier: Apache-2.0 + */ + +&cpuflpr_vpr { + status = "okay"; +}; + +&cpuflpr_vevif_remote { + status = "okay"; +}; diff --git a/snippets/nordic-flpr/snippet.yml b/snippets/nordic-flpr/snippet.yml new file mode 100644 index 00000000000..e214067145f --- /dev/null +++ b/snippets/nordic-flpr/snippet.yml @@ -0,0 +1,8 @@ +name: nordic-flpr +append: + EXTRA_DTC_OVERLAY_FILE: nordic-flpr.overlay + +boards: + nrf54l15pdk/nrf54l15/cpuapp: + append: + EXTRA_DTC_OVERLAY_FILE: boards/nrf54l15pdk_nrf54l15_cpuapp.overlay diff --git a/snippets/nus-console/nus-console.overlay b/snippets/nus-console/nus-console.overlay index 71b1b32079a..b6b0dfbe381 100644 --- a/snippets/nus-console/nus-console.overlay +++ b/snippets/nus-console/nus-console.overlay @@ -7,6 +7,7 @@ / { chosen { zephyr,console = &bt_nus_console_uart; + zephyr,shell-uart = &bt_nus_console_uart; }; bt_nus_console_uart: bt_nus_console_uart { diff --git a/snippets/rtt-console/README.rst b/snippets/rtt-console/README.rst new file mode 100644 index 00000000000..68a1f1baf5a --- /dev/null +++ b/snippets/rtt-console/README.rst @@ -0,0 +1,21 @@ +.. _snippet-rtt-console: + +RTT Console Snippet (rtt-console) +######################################### + +.. code-block:: console + + west build -S rtt-console [...] + +Overview +******** + +This snippet redirects serial console output to SEGGER RTT. + +Requirements +************ + +Hardware support for: + +- :kconfig:option:`CONFIG_HAS_SEGGER_RTT` +- :kconfig:option:`CONFIG_CONSOLE` diff --git a/snippets/rtt-console/rtt-console.conf b/snippets/rtt-console/rtt-console.conf new file mode 100644 index 00000000000..3453f62ca38 --- /dev/null +++ b/snippets/rtt-console/rtt-console.conf @@ -0,0 +1,3 @@ +CONFIG_USE_SEGGER_RTT=y +CONFIG_RTT_CONSOLE=y +CONFIG_UART_CONSOLE=n diff --git a/snippets/rtt-console/snippet.yml b/snippets/rtt-console/snippet.yml new file mode 100644 index 00000000000..c773063490c --- /dev/null +++ b/snippets/rtt-console/snippet.yml @@ -0,0 +1,3 @@ +name: rtt-console +append: + EXTRA_CONF_FILE: rtt-console.conf diff --git a/snippets/xen_dom0/boards/rcar_spider_s4_r8a779f0_a55.overlay b/snippets/xen_dom0/boards/rcar_spider_s4_r8a779f0_a55.overlay new file mode 100644 index 00000000000..5be53e872b7 --- /dev/null +++ b/snippets/xen_dom0/boards/rcar_spider_s4_r8a779f0_a55.overlay @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2024 EPAM Systems. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/delete-node/ &ram; +/delete-node/ &hscif0; + +/ { + /* + * This node may differs on different setups, please check + * following line in Xen boot log to set it right: + * (XEN) Grant table range: 0x00000078080000-0x000000780c0000 + * Also, add extended region 1: + * (XEN) Extended region 1: 0x40000000->0x47e00000 + * + * Xen passes actual values for setup in domain device tree, but Zephyr + * is not capable to parse and handle it in runtime. + */ + hypervisor: hypervisor@78080000 { + compatible = "xen,xen"; + reg = <0x0 0x78080000 0x0 0x40000 0x0 0x40000000 0x0 0x7e00000>; + interrupts = ; + interrupt-parent = <&gic>; + status = "okay"; + }; + + /* + * This node may differs on different setups, because Xen picks + * region for Domain-0 for every specific configuration. You can + * start Xen for your platform and check following log: + * (XEN) Allocating 1:1 mappings for dom0: + * (XEN) BANK[0] 0x00000080000000-0x00000090000000 (256MB) + * + * Xen passes actual values for setup in domain device tree, but Zephyr + * is not capable to parse and handle it in runtime. + */ + ram: memory@80000000 { + device_type = "mmio-sram"; + reg = <0x00 0x80000000 0x00 DT_SIZE_M(256)>; + }; +}; diff --git a/snippets/xen_dom0/snippet.yml b/snippets/xen_dom0/snippet.yml index 84d13bf77c1..501f24d2c0e 100644 --- a/snippets/xen_dom0/snippet.yml +++ b/snippets/xen_dom0/snippet.yml @@ -13,3 +13,6 @@ boards: rcar_salvator_xs/r8a77961: append: EXTRA_DTC_OVERLAY_FILE: boards/rcar_salvator_xs.overlay + rcar_spider_s4/r8a779f0/a55: + append: + EXTRA_DTC_OVERLAY_FILE: boards/rcar_spider_s4_r8a779f0_a55.overlay diff --git a/snippets/xen_dom0/xen_dom0.conf b/snippets/xen_dom0/xen_dom0.conf index c5cb5d24aa3..38e7ef1863e 100644 --- a/snippets/xen_dom0/xen_dom0.conf +++ b/snippets/xen_dom0/xen_dom0.conf @@ -1 +1,2 @@ CONFIG_XEN_DOM0=y +CONFIG_UART_INTERRUPT_DRIVEN=n diff --git a/soc/Kconfig b/soc/Kconfig index 0063021c3e3..cd3b17f28af 100644 --- a/soc/Kconfig +++ b/soc/Kconfig @@ -36,6 +36,9 @@ config SOC_COMPATIBLE_NRF52X config SOC_COMPATIBLE_NRF53X bool +config SOC_COMPATIBLE_NRF54LX + bool + config SOC_COMPATIBLE_NRF52833 bool @@ -45,6 +48,12 @@ config SOC_COMPATIBLE_NRF5340_CPUNET config SOC_COMPATIBLE_NRF5340_CPUAPP bool +config SOC_COMPATIBLE_NRF54L15 + bool + +config SOC_COMPATIBLE_NRF54L15_CPUAPP + bool + config SOC_DEPRECATED_RELEASE string help diff --git a/soc/ambiq/Kconfig.defconfig b/soc/ambiq/Kconfig.defconfig index 2d0efbe5424..70a7507a4c1 100644 --- a/soc/ambiq/Kconfig.defconfig +++ b/soc/ambiq/Kconfig.defconfig @@ -12,4 +12,7 @@ config CORTEX_M_SYSTICK config SYS_CLOCK_HW_CYCLES_PER_SEC default 32768 if AMBIQ_STIMER_TIMER +config SYS_CLOCK_TICKS_PER_SEC + default 1024 + endif # SOC_FAMILY_AMBIQ diff --git a/soc/ambiq/apollo3x/CMakeLists.txt b/soc/ambiq/apollo3x/CMakeLists.txt new file mode 100644 index 00000000000..2003b1a8df5 --- /dev/null +++ b/soc/ambiq/apollo3x/CMakeLists.txt @@ -0,0 +1,9 @@ +# Copyright (c) 2023 Ambiq Micro Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +zephyr_sources(soc.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/ambiq/apollo3x/Kconfig b/soc/ambiq/apollo3x/Kconfig new file mode 100644 index 00000000000..de93bd91e90 --- /dev/null +++ b/soc/ambiq/apollo3x/Kconfig @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright (c) 2023 Ambiq Micro Inc. + +config SOC_SERIES_APOLLO3X + select ARM + select CPU_CORTEX_M4 + select CPU_CORTEX_M_HAS_DWT + select CPU_HAS_FPU + select CPU_HAS_ARM_MPU + select HAS_SWO + select AMBIQ_HAL diff --git a/soc/ambiq/apollo3x/Kconfig.defconfig b/soc/ambiq/apollo3x/Kconfig.defconfig new file mode 100644 index 00000000000..abac3c9c75d --- /dev/null +++ b/soc/ambiq/apollo3x/Kconfig.defconfig @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright (c) 2023 Ambiq Micro Inc. + +if SOC_SERIES_APOLLO3X + +rsource "Kconfig.defconfig.apollo3*" + +endif # SOC_SERIES_APOLLO3X diff --git a/soc/ambiq/apollo3x/Kconfig.defconfig.apollo3_blue b/soc/ambiq/apollo3x/Kconfig.defconfig.apollo3_blue new file mode 100644 index 00000000000..c6c07932856 --- /dev/null +++ b/soc/ambiq/apollo3x/Kconfig.defconfig.apollo3_blue @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright (c) 2023 Ambiq Micro Inc. + +if SOC_APOLLO3_BLUE + +config NUM_IRQS + default 31 + +endif # SOC_APOLLO3_BLUE diff --git a/soc/ambiq/apollo3x/Kconfig.defconfig.apollo3p_blue b/soc/ambiq/apollo3x/Kconfig.defconfig.apollo3p_blue new file mode 100644 index 00000000000..8484dfad347 --- /dev/null +++ b/soc/ambiq/apollo3x/Kconfig.defconfig.apollo3p_blue @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright (c) 2023 Ambiq Micro Inc. + +if SOC_APOLLO3P_BLUE + +config NUM_IRQS + default 33 + +endif # SOC_APOLLO3P_BLUE diff --git a/soc/ambiq/apollo3x/Kconfig.soc b/soc/ambiq/apollo3x/Kconfig.soc new file mode 100644 index 00000000000..6a681417993 --- /dev/null +++ b/soc/ambiq/apollo3x/Kconfig.soc @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright (c) 2023 Ambiq Micro Inc. + +config SOC_SERIES_APOLLO3X + bool + select SOC_FAMILY_AMBIQ + help + Apollo3 Series MCU + +config SOC_APOLLO3P_BLUE + bool + select SOC_SERIES_APOLLO3X + help + Apollo3P Blue + +config SOC_APOLLO3_BLUE + bool + select SOC_SERIES_APOLLO3X + help + Apollo3 Blue + +config SOC_SERIES + default "apollo3x" if SOC_SERIES_APOLLO3X + +config SOC + default "apollo3_blue" if SOC_APOLLO3_BLUE + default "apollo3p_blue" if SOC_APOLLO3P_BLUE diff --git a/soc/ambiq/apollo3x/pinctrl_soc.h b/soc/ambiq/apollo3x/pinctrl_soc.h new file mode 100644 index 00000000000..1aa6a32d81f --- /dev/null +++ b/soc/ambiq/apollo3x/pinctrl_soc.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2023 Ambiq Micro Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_SOC_ARM_AMBIQ_APOLLO3_PINCTRL_SOC_H_ +#define ZEPHYR_SOC_ARM_AMBIQ_APOLLO3_PINCTRL_SOC_H_ + +#include + +/** + * @brief Type to hold a pin's pinctrl configuration. + */ +struct apollo3_pinctrl_soc_pin { + /** Pin number 0..74 */ + uint32_t pin_num: 7; + /** Alternative function (UART, SPI, etc.) */ + uint32_t alt_func: 3; + /** Enable the pin as an input */ + uint32_t input_enable: 1; + /** Drive strength, relative to full-driver strength */ + uint32_t drive_strength: 2; + /** Drive actively high or low */ + uint32_t push_pull: 1; + /** Drive with open drain */ + uint32_t open_drain: 1; + /** High impedance mode */ + uint32_t tristate: 1; + /** Enable the internal pull up resistor */ + uint32_t bias_pull_up: 1; + /** Enable the internal pull down resistor */ + uint32_t bias_pull_down: 1; + /** pullup resistor value */ + uint32_t ambiq_pull_up_ohms: 3; + /** IOM nCE module select */ + uint32_t iom_nce: 2; + /** IOM or MSPI */ + uint32_t iom_mspi: 1; + /** IOM/MSPI instance number */ + uint32_t iom_num: 3; +}; + +typedef struct apollo3_pinctrl_soc_pin pinctrl_soc_pin_t; + +/** + * @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) \ + { \ + APOLLO3_GET_PIN_NUM(DT_PROP_BY_IDX(node_id, prop, idx)), \ + APOLLO3_GET_PIN_ALT_FUNC(DT_PROP_BY_IDX(node_id, prop, idx)), \ + DT_PROP(node_id, input_enable), \ + DT_ENUM_IDX(node_id, drive_strength), \ + DT_PROP(node_id, drive_push_pull), \ + DT_PROP(node_id, drive_open_drain), \ + DT_PROP(node_id, bias_high_impedance), \ + DT_PROP(node_id, bias_pull_up), \ + DT_PROP(node_id, bias_pull_down), \ + DT_ENUM_IDX(node_id, ambiq_pull_up_ohms), \ + DT_PROP(node_id, ambiq_iom_nce_module), \ + DT_PROP(node_id, ambiq_iom_mspi), \ + DT_PROP(node_id, ambiq_iom_num), \ + }, + +/** + * @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) \ + } + +#define APOLLO3_GET_PIN_NUM(pinctrl) (((pinctrl) >> APOLLO3_PIN_NUM_POS) & APOLLO3_PIN_NUM_MASK) +#define APOLLO3_GET_PIN_ALT_FUNC(pinctrl) \ + (((pinctrl) >> APOLLO3_ALT_FUNC_POS) & APOLLO3_ALT_FUNC_MASK) + +#endif /* ZEPHYR_SOC_ARM_AMBIQ_APOLLO3_PINCTRL_SOC_H_ */ diff --git a/soc/ambiq/apollo3x/soc.c b/soc/ambiq/apollo3x/soc.c new file mode 100644 index 00000000000..d10b4a5dcfb --- /dev/null +++ b/soc/ambiq/apollo3x/soc.c @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023 Ambiq Micro Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include + +static int arm_apollo3_init(void) +{ + + /* Initialize for low power in the power control block */ + am_hal_pwrctrl_low_power_init(); + + /* Disable the RTC. */ + am_hal_rtc_osc_disable(); + + return 0; +} + +SYS_INIT(arm_apollo3_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); diff --git a/soc/ambiq/apollo3x/soc.h b/soc/ambiq/apollo3x/soc.h new file mode 100644 index 00000000000..ae9b7e597df --- /dev/null +++ b/soc/ambiq/apollo3x/soc.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2023 Ambiq Micro Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __SOC_H__ +#define __SOC_H__ + +#if defined(CONFIG_SOC_APOLLO3P_BLUE) +#include +#elif defined(CONFIG_SOC_APOLLO3_BLUE) +#include +#endif + +#endif /* __SOC_H__ */ diff --git a/soc/ambiq/apollo4x/CMakeLists.txt b/soc/ambiq/apollo4x/CMakeLists.txt index 19f7fa032af..5ff65e2ba35 100644 --- a/soc/ambiq/apollo4x/CMakeLists.txt +++ b/soc/ambiq/apollo4x/CMakeLists.txt @@ -5,5 +5,6 @@ zephyr_sources(soc.c) zephyr_include_directories(.) +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/ambiq/apollo4x/Kconfig b/soc/ambiq/apollo4x/Kconfig index a224512cd08..dc1cdda6a9b 100644 --- a/soc/ambiq/apollo4x/Kconfig +++ b/soc/ambiq/apollo4x/Kconfig @@ -11,3 +11,6 @@ config SOC_SERIES_APOLLO4X select CPU_HAS_ARM_MPU select HAS_SWO select AMBIQ_HAL + select CPU_HAS_DCACHE + select CPU_HAS_ICACHE + select HAS_PM diff --git a/soc/ambiq/apollo4x/Kconfig.defconfig b/soc/ambiq/apollo4x/Kconfig.defconfig index 182adf42cd5..c8b0d5cbaf0 100644 --- a/soc/ambiq/apollo4x/Kconfig.defconfig +++ b/soc/ambiq/apollo4x/Kconfig.defconfig @@ -6,4 +6,9 @@ if SOC_SERIES_APOLLO4X rsource "Kconfig.defconfig.apollo4*" +# Need to enlarge the IDLE stack size because the power +# management operations are executed in the idle task +config IDLE_STACK_SIZE + default 2048 if PM + endif # SOC_SERIES_APOLLO4X diff --git a/soc/ambiq/apollo4x/power.c b/soc/ambiq/apollo4x/power.c new file mode 100644 index 00000000000..8fe8557ba7e --- /dev/null +++ b/soc/ambiq/apollo4x/power.c @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2024 Ambiq LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include +#include +#include +#include + +/* ambiq-sdk includes */ +#include + +LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL); + +void pm_state_set(enum pm_state state, uint8_t substate_id) +{ + ARG_UNUSED(substate_id); + + __disable_irq(); + __set_BASEPRI(0); + + switch (state) { + case PM_STATE_SUSPEND_TO_IDLE: + /* Put ARM core to normal sleep. */ + am_hal_sysctrl_sleep(AM_HAL_SYSCTRL_SLEEP_NORMAL); + break; + case PM_STATE_SUSPEND_TO_RAM: + /* Put ARM core to deep sleep. */ + /* Cotex-m: power down, register value preserve.*/ + /* Cache: power down*/ + /* Flash: power down*/ + /* Sram: retention*/ + am_hal_sysctrl_sleep(AM_HAL_SYSCTRL_SLEEP_DEEP); + break; + default: + LOG_DBG("Unsupported power state %u", state); + break; + } +} + +/** + * @brief PM State Exit Post Operations + * + * For PM_STATE_SUSPEND_TO_IDLE: + * Nothing is needed after soc woken up. + * + * For PM_STATE_SUSPEND_TO_RAM: + * Flash, cache, sram automatically switch + * to active state on wake up + * + * @param state PM State + * @param substate_id Unused + * + */ +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +{ + ARG_UNUSED(substate_id); + + __enable_irq(); + irq_unlock(0); +} + +static int ambiq_power_init(void) +{ + am_hal_pwrctrl_mcu_memory_config_t sMcuMemCfg = { + .eCacheCfg = AM_HAL_PWRCTRL_CACHE_NONE, + .bRetainCache = true, + .eDTCMCfg = AM_HAL_PWRCTRL_DTCM_384K, + .eRetainDTCM = AM_HAL_PWRCTRL_DTCM_384K, + .bEnableNVM0 = true, + .bRetainNVM0 = false + }; + + am_hal_pwrctrl_sram_memcfg_t sSRAMCfg = { + .eSRAMCfg = AM_HAL_PWRCTRL_SRAM_ALL, + .eActiveWithMCU = AM_HAL_PWRCTRL_SRAM_NONE, + .eActiveWithGFX = AM_HAL_PWRCTRL_SRAM_NONE, + .eActiveWithDISP = AM_HAL_PWRCTRL_SRAM_NONE, + .eActiveWithDSP = AM_HAL_PWRCTRL_SRAM_NONE, + .eSRAMRetain = AM_HAL_PWRCTRL_SRAM_ALL + }; + + am_hal_pwrctrl_dsp_memory_config_t sDSPMemCfg = { + .bEnableICache = false, + .bRetainCache = false, + .bEnableRAM = false, + .bActiveRAM = false, + .bRetainRAM = false + }; + + am_hal_pwrctrl_mcu_memory_config(&sMcuMemCfg); + am_hal_pwrctrl_sram_config(&sSRAMCfg); + am_hal_pwrctrl_dsp_memory_config(AM_HAL_DSP0, &sDSPMemCfg); + + am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_CRYPTO); + + return 0; +} + +SYS_INIT(ambiq_power_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); diff --git a/soc/ambiq/soc.yml b/soc/ambiq/soc.yml index 2fd2f06529f..b0a471d1fd5 100644 --- a/soc/ambiq/soc.yml +++ b/soc/ambiq/soc.yml @@ -5,3 +5,7 @@ family: socs: - name: apollo4p - name: apollo4p_blue + - name: apollo3x + socs: + - name: apollo3_blue + - name: apollo3p_blue diff --git a/soc/andestech/ae350/CMakeLists.txt b/soc/andestech/ae350/CMakeLists.txt index b8eac026dfb..583134a91ce 100644 --- a/soc/andestech/ae350/CMakeLists.txt +++ b/soc/andestech/ae350/CMakeLists.txt @@ -8,7 +8,6 @@ zephyr_sources( ) 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) diff --git a/soc/andestech/ae350/Kconfig b/soc/andestech/ae350/Kconfig index 1a0a2443492..d184845c2d2 100644 --- a/soc/andestech/ae350/Kconfig +++ b/soc/andestech/ae350/Kconfig @@ -14,6 +14,7 @@ config SOC_ANDES_AE350 select RISCV_ISA_EXT_C select CPU_HAS_DCACHE select CPU_HAS_ICACHE + select CACHE_MANAGEMENT if DCACHE select RISCV_PMP if SOC_SERIES_ANDES_AE350 @@ -103,16 +104,12 @@ config SOC_ANDES_V5_PMA_REGION_MIN_ALIGN_AND_SIZE 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)) + select DEPRECATED 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 diff --git a/soc/andestech/ae350/Kconfig.defconfig b/soc/andestech/ae350/Kconfig.defconfig index ba36eddc354..b760c38d64d 100644 --- a/soc/andestech/ae350/Kconfig.defconfig +++ b/soc/andestech/ae350/Kconfig.defconfig @@ -36,4 +36,8 @@ config MAX_IRQ_PER_AGGREGATOR config NUM_IRQS default 64 +choice CACHE_TYPE + default EXTERNAL_CACHE +endchoice + endif # SOC_SERIES_ANDES_AE350 diff --git a/soc/andestech/ae350/l2_cache.c b/soc/andestech/ae350/l2_cache.c deleted file mode 100644 index 83a048ca896..00000000000 --- a/soc/andestech/ae350/l2_cache.c +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2021 Andes Technology Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#define DT_DRV_COMPAT andestech_l2c - -/** - * @brief Andes V5 L2 Cache Controller driver - */ - -#include "soc_v5.h" - -#include -#include -#include -#include -#include -#include - -LOG_MODULE_REGISTER(andes_v5_l2_cache, CONFIG_SOC_LOG_LEVEL); - -/* L2C Register Base Address */ -#define ANDES_V5_L2C_BASE DT_INST_REG_ADDR(0) - -/* L2C Register Offset */ -#define L2C_CONFIG (ANDES_V5_L2C_BASE + 0x00) -#define L2C_CTRL (ANDES_V5_L2C_BASE + 0x08) - -/* L2C Helper Constant */ -#define L2C_CONFIG_VER GENMASK64(31, 24) -#define L2C_CTRL_CEN BIT(0) - -/* Instruction prefetch depth */ -#define IPFDPT_FIELD(x) (x << 3) -#define L2C_CTRL_IPFDPT_0 IPFDPT_FIELD(0) -#define L2C_CTRL_IPFDPT_1 IPFDPT_FIELD(1) -#define L2C_CTRL_IPFDPT_2 IPFDPT_FIELD(2) -#define L2C_CTRL_IPFDPT_3 IPFDPT_FIELD(3) - -/* Data prefetch depth */ -#define DPFDPT_FIELD(x) (x << 5) -#define L2C_CTRL_DPFDPT_0 DPFDPT_FIELD(0) -#define L2C_CTRL_DPFDPT_2 DPFDPT_FIELD(1) -#define L2C_CTRL_DPFDPT_4 DPFDPT_FIELD(2) -#define L2C_CTRL_DPFDPT_8 DPFDPT_FIELD(3) - -#if DT_HAS_COMPAT_STATUS_OKAY(andestech_atcsmu100) -/* SMU Register offset */ -#define SMU_SYSTEMCFG 0x08 - -/* SMU Helper Constant */ -#define SMU_SYSTEMCFG_L2C BIT(8) -#endif - -static void andes_v5_l2c_enable(void) -{ - uint32_t l2c_ctrl = sys_read32(L2C_CTRL); - - /* Enable L2C if I-cache or D-cache is enabled */ - if (csr_read(NDS_MCACHE_CTL) & BIT_MASK(2)) { - uint32_t l2c_config = sys_read32(L2C_CONFIG); - - /* Memory barrier, flush all I/D-Cache before setting L2C */ - __asm__ volatile ("fence.i"); - - l2c_ctrl |= (L2C_CTRL_IPFDPT_3 | L2C_CTRL_DPFDPT_8); - sys_write32(l2c_ctrl, L2C_CTRL); - - /* Enable L2C for Gen1 L2C, Gen2 L2C defaults to enable */ - if ((l2c_config & L2C_CONFIG_VER) < (16 << 24)) { - l2c_ctrl = sys_read32(L2C_CTRL); - l2c_ctrl |= L2C_CTRL_CEN; - sys_write32(l2c_ctrl, L2C_CTRL); - } - } else { - /* Disable L2C */ - l2c_ctrl &= ~L2C_CTRL_CEN; - sys_write32(l2c_ctrl, L2C_CTRL); - } -} - -static int andes_v5_l2c_init(void) -{ -#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(syscon), andestech_atcsmu100, okay) - const struct device *const syscon_dev = DEVICE_DT_GET(DT_NODELABEL(syscon)); - - if (device_is_ready(syscon_dev)) { - uint32_t system_cfg; - - syscon_read_reg(syscon_dev, SMU_SYSTEMCFG, &system_cfg); - - /* Platform doesn't have L2C */ - if (!(system_cfg & SMU_SYSTEMCFG_L2C)) { - return -ENODEV; - } - } else { - LOG_ERR("Syscon driver should be initialized before L2 Cache " - "initialization."); - } -#endif - - andes_v5_l2c_enable(); - - return 0; -} - -SYS_INIT(andes_v5_l2c_init, PRE_KERNEL_2, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); diff --git a/soc/andestech/ae350/soc_v5.h b/soc/andestech/ae350/soc_v5.h index 09d7ddca903..111a021a4f8 100644 --- a/soc/andestech/ae350/soc_v5.h +++ b/soc/andestech/ae350/soc_v5.h @@ -10,10 +10,19 @@ /* Control and Status Registers (CSRs) available for Andes V5 SoCs */ #define NDS_MMISC_CTL 0x7D0 #define NDS_MCACHE_CTL 0x7CA -#define NDS_MMSC_CFG 0xFC2 #define NDS_MXSTATUS 0x7C4 +#define NDS_MCCTLBEGINADDR 0x7CB +#define NDS_MCCTLCOMMAND 0x7CC +#define NDS_MCCTLDATA 0x7CD #define NDS_UITB 0x800 #define NDS_UCODE 0x801 +#define NDS_UCCTLBEGINADDR 0x80B +#define NDS_UCCTLCOMMAND 0x80C +#define NDS_MICM_CFG 0xFC0 +#define NDS_MDCM_CFG 0xFC1 +#define NDS_MMSC_CFG 0xFC2 +#define NDS_MMSC_CFG2 0xFC3 +#define NDS_MRVARCH_CFG 0xFCA /* Control and Status Registers (CSRs) available for Andes V5 PMA */ #define NDS_PMACFG0 0xBC0 diff --git a/soc/brcm/bcm2712/CMakeLists.txt b/soc/brcm/bcm2712/CMakeLists.txt new file mode 100644 index 00000000000..733abbebd91 --- /dev/null +++ b/soc/brcm/bcm2712/CMakeLists.txt @@ -0,0 +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/brcm/bcm2712/Kconfig b/soc/brcm/bcm2712/Kconfig new file mode 100644 index 00000000000..af683756c40 --- /dev/null +++ b/soc/brcm/bcm2712/Kconfig @@ -0,0 +1,7 @@ +# Copyright 2024 Junho Lee +# SPDX-License-Identifier: Apache-2.0 + +config SOC_BCM2712 + select ARM64 + select CPU_CORTEX_A76 + select ARM_ARCH_TIMER if SYS_CLOCK_EXISTS diff --git a/soc/brcm/bcm2712/Kconfig.defconfig b/soc/brcm/bcm2712/Kconfig.defconfig new file mode 100644 index 00000000000..e408b20271a --- /dev/null +++ b/soc/brcm/bcm2712/Kconfig.defconfig @@ -0,0 +1,14 @@ +# Copyright 2024 Junho Lee +# SPDX-License-Identifier: Apache-2.0 + +if SOC_BCM2712 + +config NUM_IRQS + int + default 280 + +config SYS_CLOCK_HW_CYCLES_PER_SEC + int + default 54000000 + +endif diff --git a/soc/brcm/bcm2712/Kconfig.soc b/soc/brcm/bcm2712/Kconfig.soc new file mode 100644 index 00000000000..3d55282e5db --- /dev/null +++ b/soc/brcm/bcm2712/Kconfig.soc @@ -0,0 +1,8 @@ +# Copyright 2024 Junho Lee +# SPDX-License-Identifier: Apache-2.0 + +config SOC_BCM2712 + bool + +config SOC + default "bcm2712" if SOC_BCM2712 diff --git a/soc/brcm/bcm2712/mmu_regions.c b/soc/brcm/bcm2712/mmu_regions.c new file mode 100644 index 00000000000..ea3314ffc2e --- /dev/null +++ b/soc/brcm/bcm2712/mmu_regions.c @@ -0,0 +1,26 @@ +/* + * Copyright 2024 Junho Lee + * + * 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_INST(0, arm_gic), 0), + DT_REG_SIZE_BY_IDX(DT_INST(0, arm_gic), 0), + MT_DEVICE_nGnRnE | MT_P_RW_U_NA | MT_DEFAULT_SECURE_STATE), + + MMU_REGION_FLAT_ENTRY("GIC", + DT_REG_ADDR_BY_IDX(DT_INST(0, arm_gic), 1), + DT_REG_SIZE_BY_IDX(DT_INST(0, arm_gic), 1), + MT_DEVICE_nGnRnE | MT_P_RW_U_NA | MT_DEFAULT_SECURE_STATE), +}; + +const struct arm_mmu_config mmu_config = { + .num_regions = ARRAY_SIZE(mmu_regions), + .mmu_regions = mmu_regions, +}; diff --git a/soc/brcm/bcm2712/soc.yml b/soc/brcm/bcm2712/soc.yml new file mode 100644 index 00000000000..ce95e07ac68 --- /dev/null +++ b/soc/brcm/bcm2712/soc.yml @@ -0,0 +1,4 @@ +series: +- name: bcm2712 + socs: + - name: bcm2712 diff --git a/soc/cdns/dc233c/Kconfig.defconfig b/soc/cdns/dc233c/Kconfig.defconfig index c872936a044..ff74226cce1 100644 --- a/soc/cdns/dc233c/Kconfig.defconfig +++ b/soc/cdns/dc233c/Kconfig.defconfig @@ -6,6 +6,9 @@ if SOC_XTENSA_DC233C +config SOC_XTENSA_DC233C + select XTENSA_GEN_HANDLERS + config XTENSA_MMU_NUM_L2_TABLES int default 48 if XTENSA_MMU diff --git a/soc/cdns/dc233c/include/_soc_inthandlers.h b/soc/cdns/dc233c/include/_soc_inthandlers.h deleted file mode 100644 index 96bdf2146f8..00000000000 --- a/soc/cdns/dc233c/include/_soc_inthandlers.h +++ /dev/null @@ -1,279 +0,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 != 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_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 != 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_INT19_LEVEL) || XCHAL_INT19_LEVEL != 1 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT20_LEVEL) || XCHAL_INT20_LEVEL != 1 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT8_LEVEL) || XCHAL_INT8_LEVEL != 2 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT9_LEVEL) || XCHAL_INT9_LEVEL != 3 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT10_LEVEL) || XCHAL_INT10_LEVEL != 3 -#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_INT21_LEVEL) || XCHAL_INT21_LEVEL != 3 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT12_LEVEL) || XCHAL_INT12_LEVEL != 4 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT13_LEVEL) || XCHAL_INT13_LEVEL != 5 -#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 - -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 & 0x18080) { - if (mask & BIT(7)) { - mask = BIT(7); - irq = 7; - goto handle_irq; - } - if (mask & BIT(15)) { - mask = BIT(15); - irq = 15; - goto handle_irq; - } - if (mask & BIT(16)) { - mask = BIT(16); - irq = 16; - goto handle_irq; - } - } else { - if (mask & 0x60000) { - 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 & BIT(19)) { - mask = BIT(19); - irq = 19; - goto handle_irq; - } - if (mask & BIT(20)) { - mask = BIT(20); - irq = 20; - 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(8)) { - mask = BIT(8); - irq = 8; - 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 & 0x600) { - 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 & BIT(11)) { - mask = BIT(11); - irq = 11; - 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 & BIT(12)) { - mask = BIT(12); - irq = 12; - 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(13)) { - mask = BIT(13); - irq = 13; - 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_int0(unsigned int mask) -{ - return 0; -} -static inline int _xtensa_handle_one_int6(unsigned int mask) -{ - return 0; -} diff --git a/soc/cdns/dc233c/include/xtensa-dc233c.ld b/soc/cdns/dc233c/include/xtensa-dc233c.ld index b77effc032b..87ad18b5424 100644 --- a/soc/cdns/dc233c/include/xtensa-dc233c.ld +++ b/soc/cdns/dc233c/include/xtensa-dc233c.ld @@ -45,25 +45,7 @@ MEMORY { - sram0_0_seg : org = 0x00002000, len = 0x178 - sram0_1_seg : org = 0x00002178, len = 0x8 - sram0_2_seg : org = 0x00002180, len = 0x38 - sram0_3_seg : org = 0x000021B8, len = 0x8 - sram0_4_seg : org = 0x000021C0, len = 0x38 - sram0_5_seg : org = 0x000021F8, len = 0x8 - sram0_6_seg : org = 0x00002200, len = 0x38 - sram0_7_seg : org = 0x00002238, len = 0x8 - sram0_8_seg : org = 0x00002240, len = 0x38 - sram0_9_seg : org = 0x00002278, len = 0x8 - sram0_10_seg : org = 0x00002280, len = 0x38 - sram0_11_seg : org = 0x000022B8, len = 0x8 - sram0_12_seg : org = 0x000022C0, len = 0x38 - sram0_13_seg : org = 0x000022F8, len = 0x8 - sram0_14_seg : org = 0x00002300, len = 0x38 - sram0_15_seg : org = 0x00002338, len = 0x8 - sram0_16_seg : org = 0x00002340, len = 0x38 - sram0_17_seg : org = 0x00002378, len = 0x48 - sram0_18_seg : org = 0x000023C0, len = 0x40 + vectors : org = 0x00002000, len = 0x2400 #ifdef CONFIG_XTENSA_MMU vec_helpers : org = 0x00002400, len = (PHYS_RAM_ADDR - 0x00002400) #endif @@ -87,26 +69,7 @@ MEMORY PHDRS { - sram0_0_phdr PT_LOAD; - sram0_1_phdr PT_LOAD; - sram0_2_phdr PT_LOAD; - sram0_3_phdr PT_LOAD; - sram0_4_phdr PT_LOAD; - sram0_5_phdr PT_LOAD; - sram0_6_phdr PT_LOAD; - sram0_7_phdr PT_LOAD; - sram0_8_phdr PT_LOAD; - sram0_9_phdr PT_LOAD; - sram0_10_phdr PT_LOAD; - sram0_11_phdr PT_LOAD; - sram0_12_phdr PT_LOAD; - sram0_13_phdr PT_LOAD; - sram0_14_phdr PT_LOAD; - sram0_15_phdr PT_LOAD; - sram0_16_phdr PT_LOAD; - sram0_17_phdr PT_LOAD; - sram0_18_phdr PT_LOAD; - + vectors_phdr PT_LOAD; #ifdef CONFIG_XTENSA_MMU vec_helpers_phdr PT_LOAD; #endif @@ -154,138 +117,9 @@ SECTIONS #include #endif - .WindowVectors.text : ALIGN(4) - { - _WindowVectors_text_start = ABSOLUTE(.); - KEEP (*(.WindowVectors.text)) - _WindowVectors_text_end = ABSOLUTE(.); - } >sram0_0_seg :sram0_0_phdr - - .Level2InterruptVector.literal : ALIGN(4) - { - _Level2InterruptVector_literal_start = ABSOLUTE(.); - *(.Level2InterruptVector.literal) - _Level2InterruptVector_literal_end = ABSOLUTE(.); - } >sram0_1_seg :sram0_1_phdr - - .Level2InterruptVector.text : ALIGN(4) - { - _Level2InterruptVector_text_start = ABSOLUTE(.); - KEEP (*(.Level2InterruptVector.text)) - _Level2InterruptVector_text_end = ABSOLUTE(.); - } >sram0_2_seg :sram0_2_phdr - - .Level3InterruptVector.literal : ALIGN(4) - { - _Level3InterruptVector_literal_start = ABSOLUTE(.); - *(.Level3InterruptVector.literal) - _Level3InterruptVector_literal_end = ABSOLUTE(.); - } >sram0_3_seg :sram0_3_phdr - - .Level3InterruptVector.text : ALIGN(4) - { - _Level3InterruptVector_text_start = ABSOLUTE(.); - KEEP (*(.Level3InterruptVector.text)) - _Level3InterruptVector_text_end = ABSOLUTE(.); - } >sram0_4_seg :sram0_4_phdr - - .Level4InterruptVector.literal : ALIGN(4) - { - _Level4InterruptVector_literal_start = ABSOLUTE(.); - *(.Level4InterruptVector.literal) - _Level4InterruptVector_literal_end = ABSOLUTE(.); - } >sram0_5_seg :sram0_5_phdr - - .Level4InterruptVector.text : ALIGN(4) - { - _Level4InterruptVector_text_start = ABSOLUTE(.); - KEEP (*(.Level4InterruptVector.text)) - _Level4InterruptVector_text_end = ABSOLUTE(.); - } >sram0_6_seg :sram0_6_phdr - - .Level5InterruptVector.literal : ALIGN(4) - { - _Level5InterruptVector_literal_start = ABSOLUTE(.); - *(.Level5InterruptVector.literal) - _Level5InterruptVector_literal_end = ABSOLUTE(.); - } >sram0_7_seg :sram0_7_phdr - - .Level5InterruptVector.text : ALIGN(4) - { - _Level5InterruptVector_text_start = ABSOLUTE(.); - KEEP (*(.Level5InterruptVector.text)) - _Level5InterruptVector_text_end = ABSOLUTE(.); - } >sram0_8_seg :sram0_8_phdr - - .DebugExceptionVector.literal : ALIGN(4) - { - _DebugExceptionVector_literal_start = ABSOLUTE(.); - *(.DebugExceptionVector.literal) - _DebugExceptionVector_literal_end = ABSOLUTE(.); - } >sram0_9_seg :sram0_9_phdr - - .DebugExceptionVector.text : ALIGN(4) - { - _DebugExceptionVector_text_start = ABSOLUTE(.); - KEEP (*(.DebugExceptionVector.text)) - _DebugExceptionVector_text_end = ABSOLUTE(.); - } >sram0_10_seg :sram0_10_phdr - - .NMIExceptionVector.literal : ALIGN(4) - { - _NMIExceptionVector_literal_start = ABSOLUTE(.); - *(.NMIExceptionVector.literal) - _NMIExceptionVector_literal_end = ABSOLUTE(.); - } >sram0_11_seg :sram0_11_phdr - - .NMIExceptionVector.text : ALIGN(4) - { - _NMIExceptionVector_text_start = ABSOLUTE(.); - KEEP (*(.NMIExceptionVector.text)) - _NMIExceptionVector_text_end = ABSOLUTE(.); - } >sram0_12_seg :sram0_12_phdr - - .KernelExceptionVector.literal : ALIGN(4) - { - _KernelExceptionVector_literal_start = ABSOLUTE(.); - *(.KernelExceptionVector.literal) - _KernelExceptionVector_literal_end = ABSOLUTE(.); - } >sram0_13_seg :sram0_13_phdr - - .KernelExceptionVector.text : ALIGN(4) - { - _KernelExceptionVector_text_start = ABSOLUTE(.); - KEEP (*(.KernelExceptionVector.text)) - _KernelExceptionVector_text_end = ABSOLUTE(.); - } >sram0_14_seg :sram0_14_phdr - - .UserExceptionVector.literal : ALIGN(4) - { - _UserExceptionVector_literal_start = ABSOLUTE(.); - *(.UserExceptionVector.literal) - _UserExceptionVector_literal_end = ABSOLUTE(.); - } >sram0_15_seg :sram0_15_phdr - - .UserExceptionVector.text : ALIGN(4) - { - _UserExceptionVector_text_start = ABSOLUTE(.); - KEEP (*(.UserExceptionVector.text)) - _UserExceptionVector_text_end = ABSOLUTE(.); - } >sram0_16_seg :sram0_16_phdr - - .DoubleExceptionVector.literal : ALIGN(4) - { - _DoubleExceptionVector_literal_start = ABSOLUTE(.); - *(.DoubleExceptionVector.literal) - _DoubleExceptionVector_literal_end = ABSOLUTE(.); - } >sram0_17_seg :sram0_17_phdr - - .DoubleExceptionVector.text : ALIGN(4) - { - _DoubleExceptionVector_text_start = ABSOLUTE(.); - KEEP (*(.DoubleExceptionVector.text)) - _DoubleExceptionVector_text_end = ABSOLUTE(.); - } >sram0_18_seg :sram0_18_phdr +/* Auto-generated vector linkage, to "vectors" memory region */ +#include + >vectors :vectors_phdr #define LIB_OBJ_FUNC_IN_SECT(library, obj_file, func) \ *##library##:##obj_file##(.literal.##func .text.##func) \ diff --git a/soc/common/riscv-privileged/vector.S b/soc/common/riscv-privileged/vector.S index bb113457874..4822fa55333 100644 --- a/soc/common/riscv-privileged/vector.S +++ b/soc/common/riscv-privileged/vector.S @@ -97,5 +97,10 @@ SECTION_FUNC(vectors, __start) #endif /* CONFIG_RISCV_VECTORED_MODE */ +#if CONFIG_INCLUDE_RESET_VECTOR /* Jump to __reset */ tail __reset +#else + /* Jump to __initialize */ + tail __initialize +#endif diff --git a/soc/cypress/CMakeLists.txt b/soc/cypress/CMakeLists.txt deleted file mode 100644 index e55e3139740..00000000000 --- a/soc/cypress/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -# -# Copyright (c) 2018, Cypress -# Copyright (c) 2021, ATL Electronics -# -# SPDX-License-Identifier: Apache-2.0 -# - -add_subdirectory(psoc6) diff --git a/soc/cypress/Kconfig b/soc/cypress/Kconfig deleted file mode 100644 index 8c645cb1d7b..00000000000 --- a/soc/cypress/Kconfig +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2018, Cypress -# Copyright (c) 2020, ATL Electronics -# SPDX-License-Identifier: Apache-2.0 - -if SOC_FAMILY_PSOC6 || SOC_FAMILY_INFINEON_CAT1 - -rsource "*/Kconfig" - -endif # SOC_FAMILY_PSOC6 || SOC_FAMILY_INFINEON_CAT1 diff --git a/soc/cypress/Kconfig.defconfig b/soc/cypress/Kconfig.defconfig deleted file mode 100644 index 1e382579c5f..00000000000 --- a/soc/cypress/Kconfig.defconfig +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright (c) 2018, Cypress -# SPDX-License-Identifier: Apache-2.0 - -if SOC_FAMILY_PSOC6 || SOC_FAMILY_INFINEON_CAT1 - -rsource "*/Kconfig.defconfig" - -endif # SOC_FAMILY_PSOC6 || SOC_FAMILY_INFINEON_CAT1 diff --git a/soc/cypress/Kconfig.soc b/soc/cypress/Kconfig.soc deleted file mode 100644 index 140274c4e26..00000000000 --- a/soc/cypress/Kconfig.soc +++ /dev/null @@ -1,17 +0,0 @@ -# Copyright (c) 2018, Cypress -# SPDX-License-Identifier: Apache-2.0 - -config SOC_FAMILY_PSOC6 - bool - -config SOC_FAMILY_INFINEON_CAT1 - bool - -config SOC_FAMILY_INFINEON_CAT1A - bool - -config SOC_FAMILY - default "psoc6" if SOC_FAMILY_PSOC6 - default "infineon_cat1" if SOC_FAMILY_INFINEON_CAT1 - -rsource "*/Kconfig.soc" diff --git a/soc/cypress/psoc6/CMakeLists.txt b/soc/cypress/psoc6/CMakeLists.txt deleted file mode 100644 index f7a4bd016ad..00000000000 --- a/soc/cypress/psoc6/CMakeLists.txt +++ /dev/null @@ -1,32 +0,0 @@ -# -# Copyright (c) 2018, Cypress -# Copyright (c) 2020, ATL Electronics -# -# SPDX-License-Identifier: Apache-2.0 -# - -if(CONFIG_SOC_SERIES_PSOC62 OR CONFIG_SOC_SERIES_PSOC63) - add_subdirectory(old/common) - zephyr_include_directories(old) - zephyr_sources(old/soc.c) - - zephyr_linker_sources_ifdef(CONFIG_SOC_FAMILY_PSOC6 NOINIT old/noinit.ld) - zephyr_linker_sources_ifdef(CONFIG_SOC_FAMILY_PSOC6 RWDATA old/rwdata.ld) -else() - zephyr_include_directories(new) - zephyr_include_directories(new/common) - zephyr_sources(new/soc.c) - - # Add sections - zephyr_linker_sources_ifdef(CONFIG_SOC_FAMILY_INFINEON_CAT1 NOINIT new/noinit.ld) - - # Add section for cm0p image ROM - zephyr_linker_sources_ifdef(CONFIG_SOC_FAMILY_INFINEON_CAT1A ROM_START SORT_KEY 0x0cm0p new/rom_cm0image.ld) - - # Add section for cm0p image RAM - zephyr_linker_sources_ifdef(CONFIG_SOC_FAMILY_INFINEON_CAT1A RAM_SECTIONS SORT_KEY 0 new/ram_cm0image.ld) - zephyr_linker_sources_ifdef(CONFIG_SOC_FAMILY_INFINEON_CAT1A RAMFUNC_SECTION SORT_KEY 0 new/ram_func.ld) - zephyr_linker_sources_ifdef(CONFIG_SOC_FAMILY_INFINEON_CAT1 RODATA SORT_KEY 0 new/rom.ld) -endif() - -set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/cypress/psoc6/Kconfig b/soc/cypress/psoc6/Kconfig deleted file mode 100644 index 78c412cc3ef..00000000000 --- a/soc/cypress/psoc6/Kconfig +++ /dev/null @@ -1,58 +0,0 @@ -# Cypress Semiconductor PSoC6 series configuration options -# Copyright (c) 2018, Cypress -# Copyright (c) 2020, ATL Electronics -# SPDX-License-Identifier: Apache-2.0 - -config SOC_SERIES_PSOC62_PSOC63 - bool - select ARM - select HAS_CYPRESS_DRIVERS - select CPU_CORTEX_M0PLUS if SOC_CY8C6247_M0 || SOC_CY8C6347_M0 - select CPU_CORTEX_M_HAS_SYSTICK if SOC_CY8C6247_M0 || SOC_CY8C6347_M0 - select CPU_CORTEX_M_HAS_VTOR if SOC_CY8C6247_M0 || SOC_CY8C6347_M0 - select CPU_HAS_ARM_MPU if SOC_CY8C6247_M0 || SOC_CY8C6347_M0 - select CPU_CORTEX_M4 if SOC_CY8C6247_M4 || SOC_CY8C6347_M4 - select CPU_CORTEX_M_HAS_DWT if SOC_CY8C6247_M4 || SOC_CY8C6347_M4 - select CPU_CORTEX_M_HAS_SYSTICK if SOC_CY8C6247_M4 || SOC_CY8C6347_M4 - select CPU_HAS_ARM_MPU if SOC_CY8C6247_M4 || SOC_CY8C6347_M4 - select CPU_HAS_FPU if SOC_CY8C6247_M4 || SOC_CY8C6347_M4 - -config SOC_SERIES_PSOC62 - select SOC_SERIES_PSOC62_PSOC63 - -config SOC_SERIES_PSOC63 - select SOC_SERIES_PSOC62_PSOC63 - -config SOC_PSOC6_M0_ENABLES_M4 - bool "Dual-core support [activate Cortex-M4]" - depends on SOC_CY8C6247_M0 || SOC_CY8C6347_M0 - help - Cortex-M0 CPU should boot Cortex-M4 - -config SOC_DIE_PSOC6 - select ARM - select CPU_CORTEX_M4 - select CPU_HAS_ARM_MPU - select DYNAMIC_INTERRUPTS - select CPU_HAS_FPU - -if SOC_FAMILY_INFINEON_CAT1A - -## PSoCā„¢ 6 Cortex M0+ prebuilt images -choice - prompt "PSoCā„¢ 6 Cortex M0+ prebuilt images" - help - Choose the prebuilt application image to be executed on the Cortex-M0+ core of the PSoCā„¢ 6 - dual-core MCU. The image is responsible for booting the Cortex-M4 on the device. - -config SOC_PSOC6_CM0P_IMAGE_SLEEP - bool "DeepSleep" - help - DeepSleep prebuilt application image is executed on the Cortex-M0+ core of the PSoCā„¢ 6 BLE - dual-core MCU.The image is provided as C array ready to be compiled as part of the Cortex-M4 - application. The Cortex-M0+ application code is placed to internal flash by the Cortex-M4 - linker script. - -endchoice - -endif # SOC_FAMILY_INFINEON_CAT1A diff --git a/soc/cypress/psoc6/Kconfig.defconfig b/soc/cypress/psoc6/Kconfig.defconfig deleted file mode 100644 index a5995c61a0c..00000000000 --- a/soc/cypress/psoc6/Kconfig.defconfig +++ /dev/null @@ -1,30 +0,0 @@ -# Cypress Semiconductor PSoC6 series configuration options -# Copyright (c) 2018, Cypress -# Copyright (c) 2020, ATL Electronics -# SPDX-License-Identifier: Apache-2.0 - -if SOC_SERIES_PSOC62 || SOC_SERIES_PSOC63 - -config SYS_CLOCK_HW_CYCLES_PER_SEC - default 50000000 - -rsource "old/Kconfig.defconfig.psoc*" - -endif # SOC_SERIES_PSOC62 || SOC_SERIES_PSOC63 - -if SOC_FAMILY_INFINEON_CAT1 - -config SYS_CLOCK_HW_CYCLES_PER_SEC - default 100000000 - -config SOC_PSOC6_CM0P_IMAGE_ROM_SIZE - hex - default 0x2000 if SOC_PSOC6_CM0P_IMAGE_SLEEP - -config SOC_PSOC6_CM0P_IMAGE_RAM_SIZE - hex - default 0x2000 if SOC_PSOC6_CM0P_IMAGE_SLEEP - -rsource "new/Kconfig.defconfig.psoc6*" - -endif # SOC_FAMILY_INFINEON_CAT1 diff --git a/soc/cypress/psoc6/Kconfig.soc b/soc/cypress/psoc6/Kconfig.soc deleted file mode 100644 index b644b123a07..00000000000 --- a/soc/cypress/psoc6/Kconfig.soc +++ /dev/null @@ -1,1074 +0,0 @@ -# Cypress Semiconductor PSoC6 series configuration options -# Copyright (c) 2018, Cypress -# Copyright (c) 2020, ATL Electronics -# SPDX-License-Identifier: Apache-2.0 - -config SOC_SERIES_PSOC6 - bool - select SOC_FAMILY_INFINEON_CAT1 - -config SOC_SERIES_PSOC62 - bool - select SOC_FAMILY_PSOC6 - help - Enable support for Cypress PSoC6 MCU series - -config SOC_SERIES_PSOC63 - bool - select SOC_FAMILY_PSOC6 - help - Enable support for Cypress PSoC6-BLE MCU series - -# Cypress PSoCā„¢ 6 MCU lines -config SOC_SERIES_PSOC_60 - bool - select SOC_SERIES_PSOC6 - help - Enable support for Infineon PSoCā„¢ 60 MCU series - -config SOC_SERIES_PSOC_61 - bool - select SOC_SERIES_PSOC6 - help - Enable support for Infineon PSoCā„¢ 61 MCU series - -config SOC_SERIES_PSOC_62 - bool - select SOC_SERIES_PSOC6 - help - Enable support for Infineon PSoCā„¢ 62 MCU series - -config SOC_SERIES_PSOC_63 - bool - select SOC_SERIES_PSOC6 - help - Enable support for Infineon PSoCā„¢ 63 MCU series - -config SOC_SERIES_PSOC_64 - bool - select SOC_SERIES_PSOC6 - help - Enable support for Infineon PSoCā„¢ 64 MCU series - -config SOC_CY8C6247_M0 - bool - select SOC_SERIES_PSOC62 - -config SOC_CY8C6247_M4 - bool - select SOC_SERIES_PSOC62 - -config SOC_CY8C6347_M0 - bool - select SOC_SERIES_PSOC63 - -config SOC_CY8C6347_M4 - bool - select SOC_SERIES_PSOC63 - -config SOC_PART_NUMBER_CY8C6247BZI_D54 - bool - depends on SOC_SERIES_PSOC62 - help - CY8C6247BZI_D54 - -config SOC_PART_NUMBER_CY8C6347BZI_BLD53 - bool - depends on SOC_SERIES_PSOC63 - help - CY8C6347BZI_BLD53 - -# Infineon PSoC6 die -config SOC_DIE_PSOC6 - bool - select SOC_FAMILY_INFINEON_CAT1A - -# Infineon PSoC6_01 die -config SOC_DIE_PSOC6_01 - bool - select SOC_DIE_PSOC6 - -# Infineon PSoC6_02 die -config SOC_DIE_PSOC6_02 - bool - select SOC_DIE_PSOC6 - -# Infineon PSoC6_03 die -config SOC_DIE_PSOC6_03 - bool - select SOC_DIE_PSOC6 - -# Infineon PSoC6_04 die -config SOC_DIE_PSOC6_04 - bool - select SOC_DIE_PSOC6 - -# Infineon soc packages -config SOC_PACKAGE_PSOC6_01_124_BGA - bool - -config SOC_PACKAGE_PSOC6_01_116_BGA_BLE - bool - -config SOC_PACKAGE_PSOC6_01_104_M_CSP_BLE - bool - -config SOC_PACKAGE_PSOC6_01_80_WLCSP - bool - -config SOC_PACKAGE_PSOC6_01_116_BGA_USB - bool - -config SOC_PACKAGE_PSOC6_01_124_BGA_SIP - bool - -config SOC_PACKAGE_PSOC6_01_43_SMT - bool - -config SOC_PACKAGE_PSOC6_01_104_M_CSP_BLE_USB - bool - -config SOC_PACKAGE_PSOC6_01_68_QFN_BLE - bool - -config SOC_PACKAGE_PSOC6_02_124_BGA - bool - -config SOC_PACKAGE_PSOC6_02_128_TQFP - bool - -config SOC_PACKAGE_PSOC6_02_100_WLCSP - bool - -config SOC_PACKAGE_PSOC6_02_68_QFN - bool - -config SOC_PACKAGE_PSOC6_03_100_TQFP - bool - -config SOC_PACKAGE_PSOC6_03_68_QFN - bool - -config SOC_PACKAGE_PSOC6_03_49_WLCSP - bool - -config SOC_PACKAGE_PSOC6_04_64_TQFP - bool - -config SOC_PACKAGE_PSOC6_04_68_QFN - bool - -config SOC_PACKAGE_PSOC6_04_80_TQFP - bool - -# Infineon PSoC6_01 series MCUs -config SOC_CY8C6036BZI_F04 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_124_BGA - select SOC_SERIES_PSOC_60 - -config SOC_CY8C6016BZI_F04 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_124_BGA - select SOC_SERIES_PSOC_60 - -config SOC_CY8C6116BZI_F54 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_124_BGA - select SOC_SERIES_PSOC_61 - -config SOC_CY8C6136BZI_F14 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_124_BGA - select SOC_SERIES_PSOC_61 - -config SOC_CY8C6136BZI_F34 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_124_BGA - select SOC_SERIES_PSOC_61 - -config SOC_CY8C6137BZI_F14 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_124_BGA - select SOC_SERIES_PSOC_61 - -config SOC_CY8C6137BZI_F34 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_124_BGA - select SOC_SERIES_PSOC_61 - -config SOC_CY8C6137BZI_F54 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_124_BGA - select SOC_SERIES_PSOC_61 - -config SOC_CY8C6117BZI_F34 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_124_BGA - select SOC_SERIES_PSOC_61 - -config SOC_CY8C6246BZI_D04 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_124_BGA - select SOC_SERIES_PSOC_62 - -config SOC_CY8C6247BZI_D44 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_124_BGA - select SOC_SERIES_PSOC_62 - -config SOC_CY8C6247BZI_D34 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_124_BGA - select SOC_SERIES_PSOC_62 - -config SOC_CY8C6247BZI_D54 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_124_BGA - select SOC_SERIES_PSOC_62 - -config SOC_CY8C6336BZI_BLF03 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_116_BGA_BLE - select SOC_SERIES_PSOC_63 - -config SOC_CY8C6316BZI_BLF03 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_116_BGA_BLE - select SOC_SERIES_PSOC_63 - -config SOC_CY8C6316BZI_BLF53 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_116_BGA_BLE - select SOC_SERIES_PSOC_63 - -config SOC_CY8C6336BZI_BLD13 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_116_BGA_BLE - select SOC_SERIES_PSOC_63 - -config SOC_CY8C6347BZI_BLD43 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_116_BGA_BLE - select SOC_SERIES_PSOC_63 - -config SOC_CY8C6347BZI_BLD33 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_116_BGA_BLE - select SOC_SERIES_PSOC_63 - -config SOC_CY8C6347BZI_BLD53 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_116_BGA_BLE - select SOC_SERIES_PSOC_63 - -config SOC_CY8C6347FMI_BLD13 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_104_M_CSP_BLE - select SOC_SERIES_PSOC_63 - -config SOC_CY8C6347FMI_BLD43 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_104_M_CSP_BLE - select SOC_SERIES_PSOC_63 - -config SOC_CY8C6347FMI_BLD33 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_104_M_CSP_BLE - select SOC_SERIES_PSOC_63 - -config SOC_CY8C6347FMI_BLD53 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_104_M_CSP_BLE - select SOC_SERIES_PSOC_63 - -config SOC_CY8C6137FDI_F02 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_80_WLCSP - select SOC_SERIES_PSOC_61 - -config SOC_CY8C6117FDI_F02 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_80_WLCSP - select SOC_SERIES_PSOC_61 - -config SOC_CY8C6247FDI_D02 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_80_WLCSP - select SOC_SERIES_PSOC_62 - -config SOC_CY8C6247FDI_D32 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_80_WLCSP - select SOC_SERIES_PSOC_62 - -config SOC_CY8C6336BZI_BUD13 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_116_BGA_USB - select SOC_SERIES_PSOC_63 - -config SOC_CY8C6347BZI_BUD43 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_116_BGA_USB - select SOC_SERIES_PSOC_63 - -config SOC_CY8C6347BZI_BUD33 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_116_BGA_USB - select SOC_SERIES_PSOC_63 - -config SOC_CY8C6347BZI_BUD53 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_116_BGA_USB - select SOC_SERIES_PSOC_63 - -config SOC_CY8C6337BZI_BLF13 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_116_BGA_BLE - select SOC_SERIES_PSOC_63 - -config SOC_CY8C6136FDI_F42 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_80_WLCSP - select SOC_SERIES_PSOC_61 - -config SOC_CY8C6247FDI_D52 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_80_WLCSP - select SOC_SERIES_PSOC_62 - -config SOC_CY8C6136FTI_F42 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_80_WLCSP - select SOC_SERIES_PSOC_61 - -config SOC_CY8C6247FTI_D52 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_80_WLCSP - select SOC_SERIES_PSOC_62 - -config SOC_CY8C6247BZI_AUD54 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_124_BGA - select SOC_SERIES_PSOC_62 - -config SOC_CY8C6336BZI_BLF04 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_124_BGA_SIP - select SOC_SERIES_PSOC_63 - -config SOC_CY8C6316BZI_BLF04 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_124_BGA_SIP - select SOC_SERIES_PSOC_63 - -config SOC_CY8C6316BZI_BLF54 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_124_BGA_SIP - select SOC_SERIES_PSOC_63 - -config SOC_CY8C6336BZI_BLD14 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_124_BGA_SIP - select SOC_SERIES_PSOC_63 - -config SOC_CY8C6347BZI_BLD44 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_124_BGA_SIP - select SOC_SERIES_PSOC_63 - -config SOC_CY8C6347BZI_BLD34 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_124_BGA_SIP - select SOC_SERIES_PSOC_63 - -config SOC_CY8C6347BZI_BLD54 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_124_BGA_SIP - select SOC_SERIES_PSOC_63 - -config SOC_CY8C6247BFI_D54 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_124_BGA - select SOC_SERIES_PSOC_62 - -config SOC_CYBLE_416045_02 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_116_BGA_BLE - select SOC_SERIES_PSOC_63 - -config SOC_CY8C6347FMI_BUD53 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_104_M_CSP_BLE_USB - select SOC_SERIES_PSOC_63 - -config SOC_CY8C6347FMI_BUD13 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_104_M_CSP_BLE_USB - select SOC_SERIES_PSOC_63 - -config SOC_CY8C6347FMI_BUD43 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_104_M_CSP_BLE_USB - select SOC_SERIES_PSOC_63 - -config SOC_CY8C6347FMI_BUD33 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_104_M_CSP_BLE_USB - select SOC_SERIES_PSOC_63 - -config SOC_CY8C6137WI_F54 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_124_BGA - select SOC_SERIES_PSOC_61 - -config SOC_CY8C6117WI_F34 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_124_BGA - select SOC_SERIES_PSOC_61 - -config SOC_CY8C6247WI_D54 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_124_BGA - select SOC_SERIES_PSOC_62 - -config SOC_CY8C6336LQI_BLF02 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_68_QFN_BLE - select SOC_SERIES_PSOC_63 - -config SOC_CY8C6336LQI_BLF42 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_68_QFN_BLE - select SOC_SERIES_PSOC_63 - -config SOC_CY8C6347LQI_BLD52 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_68_QFN_BLE - select SOC_SERIES_PSOC_63 - -config SOC_CYB06447BZI_BLD54 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_124_BGA_SIP - select SOC_SERIES_PSOC_64 - -config SOC_CYB06447BZI_BLD53 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_116_BGA_BLE - select SOC_SERIES_PSOC_64 - -config SOC_CYB06447BZI_D54 - bool - select SOC_DIE_PSOC6_01 - select SOC_PACKAGE_PSOC6_01_124_BGA - select SOC_SERIES_PSOC_64 - -# Infineon PSoC6_02 series MCUs -config SOC_CYB0644ABZI_S2D44 - bool - select SOC_DIE_PSOC6_02 - select SOC_PACKAGE_PSOC6_02_124_BGA - select SOC_SERIES_PSOC_64 - -config SOC_CYS0644ABZI_S2D44 - bool - select SOC_DIE_PSOC6_02 - select SOC_PACKAGE_PSOC6_02_124_BGA - select SOC_SERIES_PSOC_64 - -config SOC_CY8C624ABZI_S2D44A0 - bool - select SOC_DIE_PSOC6_02 - select SOC_PACKAGE_PSOC6_02_124_BGA - select SOC_SERIES_PSOC_62 - -config SOC_CY8C624ABZI_S2D44 - bool - select SOC_DIE_PSOC6_02 - select SOC_PACKAGE_PSOC6_02_124_BGA - select SOC_SERIES_PSOC_62 - -config SOC_CY8C624AAZI_S2D44 - bool - select SOC_DIE_PSOC6_02 - select SOC_PACKAGE_PSOC6_02_128_TQFP - select SOC_SERIES_PSOC_62 - -config SOC_CY8C624AFNI_S2D43 - bool - select SOC_DIE_PSOC6_02 - select SOC_PACKAGE_PSOC6_02_100_WLCSP - select SOC_SERIES_PSOC_62 - -config SOC_CY8C624ABZI_S2D04 - bool - select SOC_DIE_PSOC6_02 - select SOC_PACKAGE_PSOC6_02_124_BGA - select SOC_SERIES_PSOC_62 - -config SOC_CY8C624ABZI_S2D14 - bool - select SOC_DIE_PSOC6_02 - select SOC_PACKAGE_PSOC6_02_124_BGA - select SOC_SERIES_PSOC_62 - -config SOC_CY8C624AAZI_S2D14 - bool - select SOC_DIE_PSOC6_02 - select SOC_PACKAGE_PSOC6_02_128_TQFP - select SOC_SERIES_PSOC_62 - -config SOC_CY8C6248AZI_S2D14 - bool - select SOC_DIE_PSOC6_02 - select SOC_PACKAGE_PSOC6_02_128_TQFP - select SOC_SERIES_PSOC_62 - -config SOC_CY8C6248BZI_S2D44 - bool - select SOC_DIE_PSOC6_02 - select SOC_PACKAGE_PSOC6_02_124_BGA - select SOC_SERIES_PSOC_62 - -config SOC_CY8C6248AZI_S2D44 - bool - select SOC_DIE_PSOC6_02 - select SOC_PACKAGE_PSOC6_02_128_TQFP - select SOC_SERIES_PSOC_62 - -config SOC_CY8C6248FNI_S2D43 - bool - select SOC_DIE_PSOC6_02 - select SOC_PACKAGE_PSOC6_02_100_WLCSP - select SOC_SERIES_PSOC_62 - -config SOC_CY8C614ABZI_S2F04 - bool - select SOC_DIE_PSOC6_02 - select SOC_PACKAGE_PSOC6_02_124_BGA - select SOC_SERIES_PSOC_61 - -config SOC_CY8C614AAZI_S2F04 - bool - select SOC_DIE_PSOC6_02 - select SOC_PACKAGE_PSOC6_02_128_TQFP - select SOC_SERIES_PSOC_61 - -config SOC_CY8C614AFNI_S2F03 - bool - select SOC_DIE_PSOC6_02 - select SOC_PACKAGE_PSOC6_02_100_WLCSP - select SOC_SERIES_PSOC_61 - -config SOC_CY8C614AAZI_S2F14 - bool - select SOC_DIE_PSOC6_02 - select SOC_PACKAGE_PSOC6_02_128_TQFP - select SOC_SERIES_PSOC_61 - -config SOC_CY8C614ABZI_S2F44 - bool - select SOC_DIE_PSOC6_02 - select SOC_PACKAGE_PSOC6_02_124_BGA - select SOC_SERIES_PSOC_61 - -config SOC_CY8C614AAZI_S2F44 - bool - select SOC_DIE_PSOC6_02 - select SOC_PACKAGE_PSOC6_02_128_TQFP - select SOC_SERIES_PSOC_61 - -config SOC_CY8C614AFNI_S2F43 - bool - select SOC_DIE_PSOC6_02 - select SOC_PACKAGE_PSOC6_02_100_WLCSP - select SOC_SERIES_PSOC_61 - -config SOC_CY8C6148BZI_S2F44 - bool - select SOC_DIE_PSOC6_02 - select SOC_PACKAGE_PSOC6_02_124_BGA - select SOC_SERIES_PSOC_61 - -config SOC_CY8C6148AZI_S2F44 - bool - select SOC_DIE_PSOC6_02 - select SOC_PACKAGE_PSOC6_02_128_TQFP - select SOC_SERIES_PSOC_61 - -config SOC_CY8C6148FNI_S2F43 - bool - select SOC_DIE_PSOC6_02 - select SOC_PACKAGE_PSOC6_02_100_WLCSP - select SOC_SERIES_PSOC_61 - -config SOC_CY8C624ABZI_D44 - bool - select SOC_DIE_PSOC6_02 - select SOC_PACKAGE_PSOC6_02_124_BGA - select SOC_SERIES_PSOC_62 - -config SOC_CY8C624ALQI_S2D42 - bool - select SOC_DIE_PSOC6_02 - select SOC_PACKAGE_PSOC6_02_68_QFN - select SOC_SERIES_PSOC_62 - -config SOC_CY8C624ALQI_S2D02 - bool - select SOC_DIE_PSOC6_02 - select SOC_PACKAGE_PSOC6_02_68_QFN - select SOC_SERIES_PSOC_62 - -config SOC_CY8C6248LQI_S2D42 - bool - select SOC_DIE_PSOC6_02 - select SOC_PACKAGE_PSOC6_02_68_QFN - select SOC_SERIES_PSOC_62 - -config SOC_CY8C6248LQI_S2D02 - bool - select SOC_DIE_PSOC6_02 - select SOC_PACKAGE_PSOC6_02_68_QFN - select SOC_SERIES_PSOC_62 - -config SOC_CY8C614ALQI_S2F42 - bool - select SOC_DIE_PSOC6_02 - select SOC_PACKAGE_PSOC6_02_68_QFN - select SOC_SERIES_PSOC_61 - -config SOC_CY8C614ALQI_S2F02 - bool - select SOC_DIE_PSOC6_02 - select SOC_PACKAGE_PSOC6_02_68_QFN - select SOC_SERIES_PSOC_61 - -config SOC_CY8C6148LQI_S2F42 - bool - select SOC_DIE_PSOC6_02 - select SOC_PACKAGE_PSOC6_02_68_QFN - select SOC_SERIES_PSOC_61 - -config SOC_CY8C6148LQI_S2F02 - bool - select SOC_DIE_PSOC6_02 - select SOC_PACKAGE_PSOC6_02_68_QFN - select SOC_SERIES_PSOC_61 - -# Infineon PSoC6_04 series MCUs -config SOC_CY8C6244AZI_S4D92 - bool - select SOC_DIE_PSOC6_04 - select SOC_PACKAGE_PSOC6_04_64_TQFP - select SOC_SERIES_PSOC_62 - -config SOC_CY8C6244LQI_S4D92 - bool - select SOC_DIE_PSOC6_04 - select SOC_PACKAGE_PSOC6_04_68_QFN - select SOC_SERIES_PSOC_62 - -config SOC_CY8C6244AZI_S4D93 - bool - select SOC_DIE_PSOC6_04 - select SOC_PACKAGE_PSOC6_04_80_TQFP - select SOC_SERIES_PSOC_62 - -config SOC_CY8C6244AZI_S4D82 - bool - select SOC_DIE_PSOC6_04 - select SOC_PACKAGE_PSOC6_04_64_TQFP - select SOC_SERIES_PSOC_62 - -config SOC_CY8C6244LQI_S4D82 - bool - select SOC_DIE_PSOC6_04 - select SOC_PACKAGE_PSOC6_04_68_QFN - select SOC_SERIES_PSOC_62 - -config SOC_CY8C6244AZI_S4D83 - bool - select SOC_DIE_PSOC6_04 - select SOC_PACKAGE_PSOC6_04_80_TQFP - select SOC_SERIES_PSOC_62 - -config SOC_CY8C6244AZI_S4D62 - bool - select SOC_DIE_PSOC6_04 - select SOC_PACKAGE_PSOC6_04_64_TQFP - select SOC_SERIES_PSOC_62 - -config SOC_CY8C6244LQI_S4D62 - bool - select SOC_DIE_PSOC6_04 - select SOC_PACKAGE_PSOC6_04_68_QFN - select SOC_SERIES_PSOC_62 - -config SOC_CY8C6244AZI_S4D12 - bool - select SOC_DIE_PSOC6_04 - select SOC_PACKAGE_PSOC6_04_64_TQFP - select SOC_SERIES_PSOC_62 - -config SOC_CY8C6244LQI_S4D12 - bool - select SOC_DIE_PSOC6_04 - select SOC_PACKAGE_PSOC6_04_68_QFN - select SOC_SERIES_PSOC_62 - -config SOC_CY8C6144AZI_S4F92 - bool - select SOC_DIE_PSOC6_04 - select SOC_PACKAGE_PSOC6_04_64_TQFP - select SOC_SERIES_PSOC_61 - -config SOC_CY8C6144LQI_S4F92 - bool - select SOC_DIE_PSOC6_04 - select SOC_PACKAGE_PSOC6_04_68_QFN - select SOC_SERIES_PSOC_61 - -config SOC_CY8C6144AZI_S4F93 - bool - select SOC_DIE_PSOC6_04 - select SOC_PACKAGE_PSOC6_04_80_TQFP - select SOC_SERIES_PSOC_61 - -config SOC_CY8C6144AZI_S4F82 - bool - select SOC_DIE_PSOC6_04 - select SOC_PACKAGE_PSOC6_04_64_TQFP - select SOC_SERIES_PSOC_61 - -config SOC_CY8C6144LQI_S4F82 - bool - select SOC_DIE_PSOC6_04 - select SOC_PACKAGE_PSOC6_04_68_QFN - select SOC_SERIES_PSOC_61 - -config SOC_CY8C6144AZI_S4F83 - bool - select SOC_DIE_PSOC6_04 - select SOC_PACKAGE_PSOC6_04_80_TQFP - select SOC_SERIES_PSOC_61 - -config SOC_CY8C6144AZI_S4F62 - bool - select SOC_DIE_PSOC6_04 - select SOC_PACKAGE_PSOC6_04_64_TQFP - select SOC_SERIES_PSOC_61 - -config SOC_CY8C6144LQI_S4F62 - bool - select SOC_DIE_PSOC6_04 - select SOC_PACKAGE_PSOC6_04_68_QFN - select SOC_SERIES_PSOC_61 - -config SOC_CY8C6144AZI_S4F12 - bool - select SOC_DIE_PSOC6_04 - select SOC_PACKAGE_PSOC6_04_64_TQFP - select SOC_SERIES_PSOC_61 - -config SOC_CY8C6144LQI_S4F12 - bool - select SOC_DIE_PSOC6_04 - select SOC_PACKAGE_PSOC6_04_68_QFN - select SOC_SERIES_PSOC_61 - -config SOC_SERIES - default "psoc62" if SOC_SERIES_PSOC62 - default "psoc63" if SOC_SERIES_PSOC63 - default "psoc6" if SOC_SERIES_PSOC6 - -config SOC - default "cy8c6247" if SOC_CY8C6247_M0 || SOC_CY8C6247_M4 - default "cy8c6347" if SOC_CY8C6247_M4 || SOC_CY8C6347_M4 - default "cy8c6036bzi_f04" if SOC_CY8C6036BZI_F04 - default "cy8c6016bzi_f04" if SOC_CY8C6016BZI_F04 - default "cy8c6116bzi_f54" if SOC_CY8C6116BZI_F54 - default "cy8c6136bzi_f14" if SOC_CY8C6136BZI_F14 - default "cy8c6136bzi_f34" if SOC_CY8C6136BZI_F34 - default "cy8c6137bzi_f14" if SOC_CY8C6137BZI_F14 - default "cy8c6137bzi_f34" if SOC_CY8C6137BZI_F34 - default "cy8c6137bzi_f54" if SOC_CY8C6137BZI_F54 - default "cy8c6117bzi_f34" if SOC_CY8C6117BZI_F34 - default "cy8c6246bzi_d04" if SOC_CY8C6246BZI_D04 - default "cy8c6247bzi_d44" if SOC_CY8C6247BZI_D44 - default "cy8c6247bzi_d34" if SOC_CY8C6247BZI_D34 - default "cy8c6247bzi_d54" if SOC_CY8C6247BZI_D54 - default "cy8c6336bzi_blf03" if SOC_CY8C6336BZI_BLF03 - default "cy8c6316bzi_blf03" if SOC_CY8C6316BZI_BLF03 - default "cy8c6316bzi_blf53" if SOC_CY8C6316BZI_BLF53 - default "cy8c6336bzi_bld13" if SOC_CY8C6336BZI_BLD13 - default "cy8c6347bzi_bld43" if SOC_CY8C6347BZI_BLD43 - default "cy8c6347bzi_bld33" if SOC_CY8C6347BZI_BLD33 - default "cy8c6347bzi_bld53" if SOC_CY8C6347BZI_BLD53 - default "cy8c6347fmi_bld13" if SOC_CY8C6347FMI_BLD13 - default "cy8c6347fmi_bld43" if SOC_CY8C6347FMI_BLD43 - default "cy8c6347fmi_bld33" if SOC_CY8C6347FMI_BLD33 - default "cy8c6347fmi_bld53" if SOC_CY8C6347FMI_BLD53 - default "cy8c6137fdi_f02" if SOC_CY8C6137FDI_F02 - default "cy8c6117fdi_f02" if SOC_CY8C6117FDI_F02 - default "cy8c6247fdi_d02" if SOC_CY8C6247FDI_D02 - default "cy8c6247fdi_d32" if SOC_CY8C6247FDI_D32 - default "cy8c6336bzi_bud13" if SOC_CY8C6336BZI_BUD13 - default "cy8c6347bzi_bud43" if SOC_CY8C6347BZI_BUD43 - default "cy8c6347bzi_bud33" if SOC_CY8C6347BZI_BUD33 - default "cy8c6347bzi_bud53" if SOC_CY8C6347BZI_BUD53 - default "cy8c6337bzi_blf13" if SOC_CY8C6337BZI_BLF13 - default "cy8c6136fdi_f42" if SOC_CY8C6136FDI_F42 - default "cy8c6247fdi_d52" if SOC_CY8C6247FDI_D52 - default "cy8c6136fti_f42" if SOC_CY8C6136FTI_F42 - default "cy8c6247fti_d52" if SOC_CY8C6247FTI_D52 - default "cy8c6247bzi_aud54" if SOC_CY8C6247BZI_AUD54 - default "cy8c6336bzi_blf04" if SOC_CY8C6336BZI_BLF04 - default "cy8c6316bzi_blf04" if SOC_CY8C6316BZI_BLF04 - default "cy8c6316bzi_blf54" if SOC_CY8C6316BZI_BLF54 - default "cy8c6336bzi_bld14" if SOC_CY8C6336BZI_BLD14 - default "cy8c6347bzi_bld44" if SOC_CY8C6347BZI_BLD44 - default "cy8c6347bzi_bld34" if SOC_CY8C6347BZI_BLD34 - default "cy8c6347bzi_bld54" if SOC_CY8C6347BZI_BLD54 - default "cy8c6247bfi_d54" if SOC_CY8C6247BFI_D54 - default "cyble_416045_02" if SOC_CYBLE_416045_02 - default "cy8c6347fmi_bud53" if SOC_CY8C6347FMI_BUD53 - default "cy8c6347fmi_bud13" if SOC_CY8C6347FMI_BUD13 - default "cy8c6347fmi_bud43" if SOC_CY8C6347FMI_BUD43 - default "cy8c6347fmi_bud33" if SOC_CY8C6347FMI_BUD33 - default "cy8c6137wi_f54" if SOC_CY8C6137WI_F54 - default "cy8c6117wi_f34" if SOC_CY8C6117WI_F34 - default "cy8c6247wi_d54" if SOC_CY8C6247WI_D54 - default "cy8c6336lqi_blf02" if SOC_CY8C6336LQI_BLF02 - default "cy8c6336lqi_blf42" if SOC_CY8C6336LQI_BLF42 - default "cy8c6347lqi_bld52" if SOC_CY8C6347LQI_BLD52 - default "cyb06447bzi_bld54" if SOC_CYB06447BZI_BLD54 - default "cyb06447bzi_bld53" if SOC_CYB06447BZI_BLD53 - default "cyb06447bzi_d54" if SOC_CYB06447BZI_D54 - default "cyb0644abzi_s2d44" if SOC_CYB0644ABZI_S2D44 - default "cys0644abzi_s2d44" if SOC_CYS0644ABZI_S2D44 - default "cy8c624abzi_s2d44a0" if SOC_CY8C624ABZI_S2D44A0 - default "cy8c624abzi_s2d44" if SOC_CY8C624ABZI_S2D44 - default "cy8c624aazi_s2d44" if SOC_CY8C624AAZI_S2D44 - default "cy8c624afni_s2d43" if SOC_CY8C624AFNI_S2D43 - default "cy8c624abzi_s2d04" if SOC_CY8C624ABZI_S2D04 - default "cy8c624abzi_s2d14" if SOC_CY8C624ABZI_S2D14 - default "cy8c624aazi_s2d14" if SOC_CY8C624AAZI_S2D14 - default "cy8c6248azi_s2d14" if SOC_CY8C6248AZI_S2D14 - default "cy8c6248bzi_s2d44" if SOC_CY8C6248BZI_S2D44 - default "cy8c6248azi_s2d44" if SOC_CY8C6248AZI_S2D44 - default "cy8c6248fni_s2d43" if SOC_CY8C6248FNI_S2D43 - default "cy8c614abzi_s2f04" if SOC_CY8C614ABZI_S2F04 - default "cy8c614aazi_s2f04" if SOC_CY8C614AAZI_S2F04 - default "cy8c614afni_s2f03" if SOC_CY8C614AFNI_S2F03 - default "cy8c614aazi_s2f14" if SOC_CY8C614AAZI_S2F14 - default "cy8c614abzi_s2f44" if SOC_CY8C614ABZI_S2F44 - default "cy8c614aazi_s2f44" if SOC_CY8C614AAZI_S2F44 - default "cy8c614afni_s2f43" if SOC_CY8C614AFNI_S2F43 - default "cy8c6148bzi_s2f44" if SOC_CY8C6148BZI_S2F44 - default "cy8c6148azi_s2f44" if SOC_CY8C6148AZI_S2F44 - default "cy8c6148fni_s2f43" if SOC_CY8C6148FNI_S2F43 - default "cy8c624abzi_d44" if SOC_CY8C624ABZI_D44 - default "cy8c624alqi_s2d42" if SOC_CY8C624ALQI_S2D42 - default "cy8c624alqi_s2d02" if SOC_CY8C624ALQI_S2D02 - default "cy8c6248lqi_s2d42" if SOC_CY8C6248LQI_S2D42 - default "cy8c6248lqi_s2d02" if SOC_CY8C6248LQI_S2D02 - default "cy8c614alqi_s2f42" if SOC_CY8C614ALQI_S2F42 - default "cy8c614alqi_s2f02" if SOC_CY8C614ALQI_S2F02 - default "cy8c6148lqi_s2f42" if SOC_CY8C6148LQI_S2F42 - default "cy8c6148lqi_s2f02" if SOC_CY8C6148LQI_S2F02 - default "cy8c6244azi_s4d92" if SOC_CY8C6244AZI_S4D92 - default "cy8c6244lqi_s4d92" if SOC_CY8C6244LQI_S4D92 - default "cy8c6244azi_s4d93" if SOC_CY8C6244AZI_S4D93 - default "cy8c6244azi_s4d82" if SOC_CY8C6244AZI_S4D82 - default "cy8c6244lqi_s4d82" if SOC_CY8C6244LQI_S4D82 - default "cy8c6244azi_s4d83" if SOC_CY8C6244AZI_S4D83 - default "cy8c6244azi_s4d62" if SOC_CY8C6244AZI_S4D62 - default "cy8c6244lqi_s4d62" if SOC_CY8C6244LQI_S4D62 - default "cy8c6244azi_s4d12" if SOC_CY8C6244AZI_S4D12 - default "cy8c6244lqi_s4d12" if SOC_CY8C6244LQI_S4D12 - default "cy8c6144azi_s4f92" if SOC_CY8C6144AZI_S4F92 - default "cy8c6144lqi_s4f92" if SOC_CY8C6144LQI_S4F92 - default "cy8c6144azi_s4f93" if SOC_CY8C6144AZI_S4F93 - default "cy8c6144azi_s4f82" if SOC_CY8C6144AZI_S4F82 - default "cy8c6144lqi_s4f82" if SOC_CY8C6144LQI_S4F82 - default "cy8c6144azi_s4f83" if SOC_CY8C6144AZI_S4F83 - default "cy8c6144azi_s4f62" if SOC_CY8C6144AZI_S4F62 - default "cy8c6144lqi_s4f62" if SOC_CY8C6144LQI_S4F62 - default "cy8c6144azi_s4f12" if SOC_CY8C6144AZI_S4F12 - default "cy8c6144lqi_s4f12" if SOC_CY8C6144LQI_S4F12 - -config SOC_PART_NUMBER - default "CY8C6247BZI_D54" if SOC_PART_NUMBER_CY8C6247BZI_D54 - default "CY8C6347BZI_BLD53" if SOC_PART_NUMBER_CY8C6347BZI_BLD53 - default "CY8C6036BZI_F04" if SOC_CY8C6036BZI_F04 - default "CY8C6016BZI_F04" if SOC_CY8C6016BZI_F04 - default "CY8C6116BZI_F54" if SOC_CY8C6116BZI_F54 - default "CY8C6136BZI_F14" if SOC_CY8C6136BZI_F14 - default "CY8C6136BZI_F34" if SOC_CY8C6136BZI_F34 - default "CY8C6137BZI_F14" if SOC_CY8C6137BZI_F14 - default "CY8C6137BZI_F34" if SOC_CY8C6137BZI_F34 - default "CY8C6137BZI_F54" if SOC_CY8C6137BZI_F54 - default "CY8C6117BZI_F34" if SOC_CY8C6117BZI_F34 - default "CY8C6246BZI_D04" if SOC_CY8C6246BZI_D04 - default "CY8C6247BZI_D44" if SOC_CY8C6247BZI_D44 - default "CY8C6247BZI_D34" if SOC_CY8C6247BZI_D34 - default "CY8C6247BZI_D54" if SOC_CY8C6247BZI_D54 - default "CY8C6336BZI_BLF03" if SOC_CY8C6336BZI_BLF03 - default "CY8C6316BZI_BLF03" if SOC_CY8C6316BZI_BLF03 - default "CY8C6316BZI_BLF53" if SOC_CY8C6316BZI_BLF53 - default "CY8C6336BZI_BLD13" if SOC_CY8C6336BZI_BLD13 - default "CY8C6347BZI_BLD43" if SOC_CY8C6347BZI_BLD43 - default "CY8C6347BZI_BLD33" if SOC_CY8C6347BZI_BLD33 - default "CY8C6347BZI_BLD53" if SOC_CY8C6347BZI_BLD53 - default "CY8C6347FMI_BLD13" if SOC_CY8C6347FMI_BLD13 - default "CY8C6347FMI_BLD43" if SOC_CY8C6347FMI_BLD43 - default "CY8C6347FMI_BLD33" if SOC_CY8C6347FMI_BLD33 - default "CY8C6347FMI_BLD53" if SOC_CY8C6347FMI_BLD53 - default "CY8C6137FDI_F02" if SOC_CY8C6137FDI_F02 - default "CY8C6117FDI_F02" if SOC_CY8C6117FDI_F02 - default "CY8C6247FDI_D02" if SOC_CY8C6247FDI_D02 - default "CY8C6247FDI_D32" if SOC_CY8C6247FDI_D32 - default "CY8C6336BZI_BUD13" if SOC_CY8C6336BZI_BUD13 - default "CY8C6347BZI_BUD43" if SOC_CY8C6347BZI_BUD43 - default "CY8C6347BZI_BUD33" if SOC_CY8C6347BZI_BUD33 - default "CY8C6347BZI_BUD53" if SOC_CY8C6347BZI_BUD53 - default "CY8C6337BZI_BLF13" if SOC_CY8C6337BZI_BLF13 - default "CY8C6136FDI_F42" if SOC_CY8C6136FDI_F42 - default "CY8C6247FDI_D52" if SOC_CY8C6247FDI_D52 - default "CY8C6136FTI_F42" if SOC_CY8C6136FTI_F42 - default "CY8C6247FTI_D52" if SOC_CY8C6247FTI_D52 - default "CY8C6247BZI_AUD54" if SOC_CY8C6247BZI_AUD54 - default "CY8C6336BZI_BLF04" if SOC_CY8C6336BZI_BLF04 - default "CY8C6316BZI_BLF04" if SOC_CY8C6316BZI_BLF04 - default "CY8C6316BZI_BLF54" if SOC_CY8C6316BZI_BLF54 - default "CY8C6336BZI_BLD14" if SOC_CY8C6336BZI_BLD14 - default "CY8C6347BZI_BLD44" if SOC_CY8C6347BZI_BLD44 - default "CY8C6347BZI_BLD34" if SOC_CY8C6347BZI_BLD34 - default "CY8C6347BZI_BLD54" if SOC_CY8C6347BZI_BLD54 - default "CY8C6247BFI_D54" if SOC_CY8C6247BFI_D54 - default "CYBLE_416045_02_device" if SOC_CYBLE_416045_02 - default "CY8C6347FMI_BUD53" if SOC_CY8C6347FMI_BUD53 - default "CY8C6347FMI_BUD13" if SOC_CY8C6347FMI_BUD13 - default "CY8C6347FMI_BUD43" if SOC_CY8C6347FMI_BUD43 - default "CY8C6347FMI_BUD33" if SOC_CY8C6347FMI_BUD33 - default "CY8C6137WI_F54" if SOC_CY8C6137WI_F54 - default "CY8C6117WI_F34" if SOC_CY8C6117WI_F34 - default "CY8C6247WI_D54" if SOC_CY8C6247WI_D54 - default "CY8C6336LQI_BLF02" if SOC_CY8C6336LQI_BLF02 - default "CY8C6336LQI_BLF42" if SOC_CY8C6336LQI_BLF42 - default "CY8C6347LQI_BLD52" if SOC_CY8C6347LQI_BLD52 - default "CYB06447BZI_BLD54" if SOC_CYB06447BZI_BLD54 - default "CYB06447BZI_BLD53" if SOC_CYB06447BZI_BLD53 - default "CYB06447BZI_D54" if SOC_CYB06447BZI_D54 - default "CYB0644ABZI_S2D44" if SOC_CYB0644ABZI_S2D44 - default "CYS0644ABZI_S2D44" if SOC_CYS0644ABZI_S2D44 - default "CY8C624ABZI_S2D44A0" if SOC_CY8C624ABZI_S2D44A0 - default "CY8C624ABZI_S2D44" if SOC_CY8C624ABZI_S2D44 - default "CY8C624AAZI_S2D44" if SOC_CY8C624AAZI_S2D44 - default "CY8C624AFNI_S2D43" if SOC_CY8C624AFNI_S2D43 - default "CY8C624ABZI_S2D04" if SOC_CY8C624ABZI_S2D04 - default "CY8C624ABZI_S2D14" if SOC_CY8C624ABZI_S2D14 - default "CY8C624AAZI_S2D14" if SOC_CY8C624AAZI_S2D14 - default "CY8C6248AZI_S2D14" if SOC_CY8C6248AZI_S2D14 - default "CY8C6248BZI_S2D44" if SOC_CY8C6248BZI_S2D44 - default "CY8C6248AZI_S2D44" if SOC_CY8C6248AZI_S2D44 - default "CY8C6248FNI_S2D43" if SOC_CY8C6248FNI_S2D43 - default "CY8C614ABZI_S2F04" if SOC_CY8C614ABZI_S2F04 - default "CY8C614AAZI_S2F04" if SOC_CY8C614AAZI_S2F04 - default "CY8C614AFNI_S2F03" if SOC_CY8C614AFNI_S2F03 - default "CY8C614AAZI_S2F14" if SOC_CY8C614AAZI_S2F14 - default "CY8C614ABZI_S2F44" if SOC_CY8C614ABZI_S2F44 - default "CY8C614AAZI_S2F44" if SOC_CY8C614AAZI_S2F44 - default "CY8C614AFNI_S2F43" if SOC_CY8C614AFNI_S2F43 - default "CY8C6148BZI_S2F44" if SOC_CY8C6148BZI_S2F44 - default "CY8C6148AZI_S2F44" if SOC_CY8C6148AZI_S2F44 - default "CY8C6148FNI_S2F43" if SOC_CY8C6148FNI_S2F43 - default "CY8C624ABZI_D44" if SOC_CY8C624ABZI_D44 - default "CY8C624ALQI_S2D42" if SOC_CY8C624ALQI_S2D42 - default "CY8C624ALQI_S2D02" if SOC_CY8C624ALQI_S2D02 - default "CY8C6248LQI_S2D42" if SOC_CY8C6248LQI_S2D42 - default "CY8C6248LQI_S2D02" if SOC_CY8C6248LQI_S2D02 - default "CY8C614ALQI_S2F42" if SOC_CY8C614ALQI_S2F42 - default "CY8C614ALQI_S2F02" if SOC_CY8C614ALQI_S2F02 - default "CY8C6148LQI_S2F42" if SOC_CY8C6148LQI_S2F42 - default "CY8C6148LQI_S2F02" if SOC_CY8C6148LQI_S2F02 - default "CY8C6244AZI_S4D92" if SOC_CY8C6244AZI_S4D92 - default "CY8C6244LQI_S4D92" if SOC_CY8C6244LQI_S4D92 - default "CY8C6244AZI_S4D93" if SOC_CY8C6244AZI_S4D93 - default "CY8C6244AZI_S4D82" if SOC_CY8C6244AZI_S4D82 - default "CY8C6244LQI_S4D82" if SOC_CY8C6244LQI_S4D82 - default "CY8C6244AZI_S4D83" if SOC_CY8C6244AZI_S4D83 - default "CY8C6244AZI_S4D62" if SOC_CY8C6244AZI_S4D62 - default "CY8C6244LQI_S4D62" if SOC_CY8C6244LQI_S4D62 - default "CY8C6244AZI_S4D12" if SOC_CY8C6244AZI_S4D12 - default "CY8C6244LQI_S4D12" if SOC_CY8C6244LQI_S4D12 - default "CY8C6144AZI_S4F92" if SOC_CY8C6144AZI_S4F92 - default "CY8C6144LQI_S4F92" if SOC_CY8C6144LQI_S4F92 - default "CY8C6144AZI_S4F93" if SOC_CY8C6144AZI_S4F93 - default "CY8C6144AZI_S4F82" if SOC_CY8C6144AZI_S4F82 - default "CY8C6144LQI_S4F82" if SOC_CY8C6144LQI_S4F82 - default "CY8C6144AZI_S4F83" if SOC_CY8C6144AZI_S4F83 - default "CY8C6144AZI_S4F62" if SOC_CY8C6144AZI_S4F62 - default "CY8C6144LQI_S4F62" if SOC_CY8C6144LQI_S4F62 - default "CY8C6144AZI_S4F12" if SOC_CY8C6144AZI_S4F12 - default "CY8C6144LQI_S4F12" if SOC_CY8C6144LQI_S4F12 diff --git a/soc/cypress/psoc6/new/Kconfig.defconfig.psoc6_01 b/soc/cypress/psoc6/new/Kconfig.defconfig.psoc6_01 deleted file mode 100644 index 3120bfdded2..00000000000 --- a/soc/cypress/psoc6/new/Kconfig.defconfig.psoc6_01 +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright (c) 2022 Cypress Semiconductor Corporation (an Infineon company) or -# an affiliate of Cypress Semiconductor Corporation -# SPDX-License-Identifier: Apache-2.0 - -# Infineon PSoC6_01 based MCU default configuration - -if SOC_DIE_PSOC6_01 - -config NUM_IRQS - default 32 if CPU_CORTEX_M0PLUS - default 147 if CPU_CORTEX_M4 - -# add additional die specific params - -endif # SOC_DIE_PSOC6_01 diff --git a/soc/cypress/psoc6/new/Kconfig.defconfig.psoc6_02 b/soc/cypress/psoc6/new/Kconfig.defconfig.psoc6_02 deleted file mode 100644 index b50a91cff1e..00000000000 --- a/soc/cypress/psoc6/new/Kconfig.defconfig.psoc6_02 +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright (c) 2022 Cypress Semiconductor Corporation (an Infineon company) or -# an affiliate of Cypress Semiconductor Corporation -# SPDX-License-Identifier: Apache-2.0 - -# Infineon PSoC6_02 based MCU default configuration - -if SOC_DIE_PSOC6_02 - -config NUM_IRQS - default 32 if CPU_CORTEX_M0PLUS - default 168 if CPU_CORTEX_M4 - -# add additional die specific params - -endif # SOC_DIE_PSOC6_02 diff --git a/soc/cypress/psoc6/new/Kconfig.defconfig.psoc6_04 b/soc/cypress/psoc6/new/Kconfig.defconfig.psoc6_04 deleted file mode 100644 index 30908b188a7..00000000000 --- a/soc/cypress/psoc6/new/Kconfig.defconfig.psoc6_04 +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright (c) 2022 Cypress Semiconductor Corporation (an Infineon company) or -# an affiliate of Cypress Semiconductor Corporation -# Copyright (c) David Ullmann -# SPDX-License-Identifier: Apache-2.0 - -# Infineon PSoC6_04 based MCU default configuration - -if SOC_DIE_PSOC6_04 - -config NUM_IRQS - default 16 if CPU_CORTEX_M0PLUS - default 175 if CPU_CORTEX_M4 - -endif # SOC_DIE_PSOC6_04 diff --git a/soc/cypress/psoc6/old/Kconfig.defconfig.psoc6_m0 b/soc/cypress/psoc6/old/Kconfig.defconfig.psoc6_m0 deleted file mode 100644 index df5e232dc0f..00000000000 --- a/soc/cypress/psoc6/old/Kconfig.defconfig.psoc6_m0 +++ /dev/null @@ -1,10 +0,0 @@ -# Cypress PSoC6 CM0 platform configuration options -# Copyright (c) 2018, Cypress -# SPDX-License-Identifier: Apache-2.0 - -if SOC_CY8C6247_M0 || SOC_CY8C6347_M0 - -config NUM_IRQS - default 32 - -endif # SOC_CY8C6247_M0 || SOC_CY8C6347_M0 diff --git a/soc/cypress/psoc6/old/Kconfig.defconfig.psoc6_m4 b/soc/cypress/psoc6/old/Kconfig.defconfig.psoc6_m4 deleted file mode 100644 index 975ea4fa7fb..00000000000 --- a/soc/cypress/psoc6/old/Kconfig.defconfig.psoc6_m4 +++ /dev/null @@ -1,10 +0,0 @@ -# Cypress PSoC6 CM4 platform configuration options -# Copyright (c) 2018, Cypress -# SPDX-License-Identifier: Apache-2.0 - -if SOC_CY8C6247_M4 || SOC_CY8C6347_M4 - -config NUM_IRQS - default 147 - -endif # SOC_CY8C6247_M4 || SOC_CY8C6347_M4 diff --git a/soc/cypress/psoc6/old/common/CMakeLists.txt b/soc/cypress/psoc6/old/common/CMakeLists.txt deleted file mode 100644 index aad2f32b666..00000000000 --- a/soc/cypress/psoc6/old/common/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -# Copyright (c) 2021 ATL Electronics -# SPDX-License-Identifier: Apache-2.0 - -zephyr_include_directories(.) - -zephyr_library_sources_ifdef(CONFIG_SOC_FAMILY_PSOC6 soc_gpio.c) diff --git a/soc/cypress/psoc6/old/soc.h b/soc/cypress/psoc6/old/soc.h deleted file mode 100644 index fe5e982cde1..00000000000 --- a/soc/cypress/psoc6/old/soc.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2018, Cypress - * Copyright (c) 2020-2021, ATL Electronics - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief Board configuration macros - * - * This header file is used to specify and describe board-level aspects - */ - -#ifndef _SOC__H_ -#define _SOC__H_ - -#include - -#ifndef _ASMLANGUAGE - -#include -#include "../common/soc_gpio.h" -#include "../common/cypress_psoc6_dt.h" - -#endif /* !_ASMLANGUAGE */ - -#endif /* _SOC__H_ */ diff --git a/soc/cypress/soc.yml b/soc/cypress/soc.yml deleted file mode 100644 index c973ed24b94..00000000000 --- a/soc/cypress/soc.yml +++ /dev/null @@ -1,131 +0,0 @@ -family: -- name: psoc6 - series: - - name: psoc62 - socs: - - name: cy8c6247 - cpuclusters: - - name: m0 - - name: m4 - - name: psoc63 - socs: - - name: cy8c6347 - cpuclusters: - - name: m0 - - name: m4 -- name: infineon_cat1 - series: - - name: psoc6 - socs: - - name: cy8c6036bzi_f04 - - name: cy8c6016bzi_f04 - - name: cy8c6116bzi_f54 - - name: cy8c6136bzi_f14 - - name: cy8c6136bzi_f34 - - name: cy8c6137bzi_f14 - - name: cy8c6137bzi_f34 - - name: cy8c6137bzi_f54 - - name: cy8c6117bzi_f34 - - name: cy8c6246bzi_d04 - - name: cy8c6247bzi_d44 - - name: cy8c6247bzi_d34 - - name: cy8c6247bzi_d54 - - name: cy8c6336bzi_blf03 - - name: cy8c6316bzi_blf03 - - name: cy8c6316bzi_blf53 - - name: cy8c6336bzi_bld13 - - name: cy8c6347bzi_bld43 - - name: cy8c6347bzi_bld33 - - name: cy8c6347bzi_bld53 - - name: cy8c6347fmi_bld13 - - name: cy8c6347fmi_bld43 - - name: cy8c6347fmi_bld33 - - name: cy8c6347fmi_bld53 - - name: cy8c6137fdi_f02 - - name: cy8c6117fdi_f02 - - name: cy8c6247fdi_d02 - - name: cy8c6247fdi_d32 - - name: cy8c6336bzi_bud13 - - name: cy8c6347bzi_bud43 - - name: cy8c6347bzi_bud33 - - name: cy8c6347bzi_bud53 - - name: cy8c6337bzi_blf13 - - name: cy8c6136fdi_f42 - - name: cy8c6247fdi_d52 - - name: cy8c6136fti_f42 - - name: cy8c6247fti_d52 - - name: cy8c6247bzi_aud54 - - name: cy8c6336bzi_blf04 - - name: cy8c6316bzi_blf04 - - name: cy8c6316bzi_blf54 - - name: cy8c6336bzi_bld14 - - name: cy8c6347bzi_bld44 - - name: cy8c6347bzi_bld34 - - name: cy8c6347bzi_bld54 - - name: cy8c6247bfi_d54 - - name: cyble_416045_02 - - name: cy8c6347fmi_bud53 - - name: cy8c6347fmi_bud13 - - name: cy8c6347fmi_bud43 - - name: cy8c6347fmi_bud33 - - name: cy8c6137wi_f54 - - name: cy8c6117wi_f34 - - name: cy8c6247wi_d54 - - name: cy8c6336lqi_blf02 - - name: cy8c6336lqi_blf42 - - name: cy8c6347lqi_bld52 - - name: cyb06447bzi_bld54 - - name: cyb06447bzi_bld53 - - name: cyb06447bzi_d54 - - name: cyb0644abzi_s2d44 - - name: cys0644abzi_s2d44 - - name: cy8c624abzi_s2d44a0 - - name: cy8c624abzi_s2d44 - - name: cy8c624aazi_s2d44 - - name: cy8c624afni_s2d43 - - name: cy8c624abzi_s2d04 - - name: cy8c624abzi_s2d14 - - name: cy8c624aazi_s2d14 - - name: cy8c6248azi_s2d14 - - name: cy8c6248bzi_s2d44 - - name: cy8c6248azi_s2d44 - - name: cy8c6248fni_s2d43 - - name: cy8c614abzi_s2f04 - - name: cy8c614aazi_s2f04 - - name: cy8c614afni_s2f03 - - name: cy8c614aazi_s2f14 - - name: cy8c614abzi_s2f44 - - name: cy8c614aazi_s2f44 - - name: cy8c614afni_s2f43 - - name: cy8c6148bzi_s2f44 - - name: cy8c6148azi_s2f44 - - name: cy8c6148fni_s2f43 - - name: cy8c624abzi_d44 - - name: cy8c624alqi_s2d42 - - name: cy8c624alqi_s2d02 - - name: cy8c6248lqi_s2d42 - - name: cy8c6248lqi_s2d02 - - name: cy8c614alqi_s2f42 - - name: cy8c614alqi_s2f02 - - name: cy8c6148lqi_s2f42 - - name: cy8c6148lqi_s2f02 - - name: cy8c6244azi_s4d92 - - name: cy8c6244lqi_s4d92 - - name: cy8c6244azi_s4d93 - - name: cy8c6244azi_s4d82 - - name: cy8c6244lqi_s4d82 - - name: cy8c6244azi_s4d83 - - name: cy8c6244azi_s4d62 - - name: cy8c6244lqi_s4d62 - - name: cy8c6244azi_s4d12 - - name: cy8c6244lqi_s4d12 - - name: cy8c6144azi_s4f92 - - name: cy8c6144lqi_s4f92 - - name: cy8c6144azi_s4f93 - - name: cy8c6144azi_s4f82 - - name: cy8c6144lqi_s4f82 - - name: cy8c6144azi_s4f83 - - name: cy8c6144azi_s4f62 - - name: cy8c6144lqi_s4f62 - - name: cy8c6144azi_s4f12 - - name: cy8c6144lqi_s4f12 diff --git a/soc/espressif/common/Kconfig.spiram b/soc/espressif/common/Kconfig.spiram index 0daad784aa9..7ee95172a1f 100644 --- a/soc/espressif/common/Kconfig.spiram +++ b/soc/espressif/common/Kconfig.spiram @@ -141,6 +141,14 @@ config SPIRAM_RODATA can forgo being placed in IRAM, thus optimizing RAM usage (see External RAM documentation for more details). +config SPIRAM_ECC_ENABLE + bool "Allow enabling SPI RAM ECC" + default n + depends on SPIRAM_MODE_OCT && SOC_SERIES_ESP32S3 + help + Enable MSPI Error-Correcting Code function when accessing SPIRAM. + If enabled, 1/16 of the SPI RAM total size will be reserved for error-correcting code. + if SOC_SERIES_ESP32 menu "PSRAM clock and cs IO for ESP32-DOWD" diff --git a/soc/espressif/common/loader.c b/soc/espressif/common/loader.c index e563f6757ec..5377f6bb312 100644 --- a/soc/espressif/common/loader.c +++ b/soc/espressif/common/loader.c @@ -204,6 +204,15 @@ void map_rom_segments(uint32_t app_drom_start, uint32_t app_drom_vaddr, cache_hal_enable(CACHE_TYPE_ALL); #endif /* CONFIG_SOC_SERIES_ESP32 */ +#if !defined(CONFIG_SOC_SERIES_ESP32) && !defined(CONFIG_SOC_SERIES_ESP32S2) + /* Configure the Cache MMU size for instruction and rodata in flash. */ + uint32_t cache_mmu_irom_size = ((app_irom_size + CONFIG_MMU_PAGE_SIZE - 1) / + CONFIG_MMU_PAGE_SIZE) * sizeof(uint32_t); + + /* Split the cache usage by the segment sizes */ + Cache_Set_IDROM_MMU_Size(cache_mmu_irom_size, + CACHE_DROM_MMU_MAX_END - cache_mmu_irom_size); +#endif /* Show map segments continue using same log format as during MCUboot phase */ BOOT_LOG_INF("DROM segment: paddr=%08xh, vaddr=%08xh, size=%05Xh (%6d) map", app_drom_start_aligned, app_drom_vaddr_aligned, diff --git a/soc/espressif/esp32/Kconfig.rtc b/soc/espressif/esp32/Kconfig.rtc index bfbddc28ebb..ea14eeaf098 100644 --- a/soc/espressif/esp32/Kconfig.rtc +++ b/soc/espressif/esp32/Kconfig.rtc @@ -74,4 +74,21 @@ config RTC_XTAL_CAL_RETRY Increase this option if the 32k crystal oscillator does not start and switches to internal RC. +config ESP_SYSTEM_RTC_EXT_XTAL_BOOTSTRAP_CYCLES + int "Bootstrap cycles for external 32kHz crystal" + depends on ESP_SYSTEM_RTC_EXT_XTAL + default 5 + range 0 32768 + help + To reduce the startup time of an external RTC crystal, + we bootstrap it with a 32kHz square wave for a fixed number of cycles. + Setting 0 will disable bootstrapping (if disabled, the crystal may take + longer to start up or fail to oscillate under some conditions). + + If this value is too high, a faulty crystal may initially start and then fail. + If this value is too low, an otherwise good crystal may not start. + + To accurately determine if the crystal has started, + set a larger "Number of cycles for RTC_SLOW_CLK calibration" (about 3000). + endif # SOC_SERIES_ESP32 diff --git a/soc/espressif/esp32/default.ld b/soc/espressif/esp32/default.ld index 4f0ac082896..338a90b9964 100644 --- a/soc/espressif/esp32/default.ld +++ b/soc/espressif/esp32/default.ld @@ -789,7 +789,6 @@ SECTIONS *(.dynamic) *(.gnu.version_d) . = ALIGN(4); - _rodata_end = ABSOLUTE(.); __rodata_region_end = ABSOLUTE(.); /* Literals are also RO data. */ _lit4_start = ABSOLUTE(.); @@ -846,6 +845,7 @@ SECTIONS _stext = .; _instruction_reserved_start = ABSOLUTE(.); /* This is a symbol marking the flash.text start, this can be used for mmu driver to maintain virtual address */ _text_start = ABSOLUTE(.); + __text_region_start = ABSOLUTE(.); #ifndef CONFIG_ESP32_WIFI_IRAM_OPT *libnet80211.a:( .wifi0iram .wifi0iram.* .wifislpiram .wifislpiram.*) @@ -864,6 +864,7 @@ SECTIONS . = ALIGN(4); _text_end = ABSOLUTE(.); _instruction_reserved_end = ABSOLUTE(.); /* This is a symbol marking the flash.text end, this can be used for mmu driver to maintain virtual address */ + __text_region_end = ABSOLUTE(.); _etext = .; } GROUP_DATA_LINK_IN(FLASH_CODE_REGION, ROMABLE_REGION) diff --git a/soc/espressif/esp32/soc.c b/soc/espressif/esp32/soc.c index 42b5e7bb399..1c6e0eaa7db 100644 --- a/soc/espressif/esp32/soc.c +++ b/soc/espressif/esp32/soc.c @@ -40,9 +40,6 @@ #include "esp_clk_internal.h" #endif /* CONFIG_SOC_ENABLE_APPCPU */ -#ifdef CONFIG_MCUBOOT -#include "bootloader_init.h" -#endif /* CONFIG_MCUBOOT */ #include #if CONFIG_ESP_SPIRAM diff --git a/soc/espressif/esp32c3/Kconfig.rtc b/soc/espressif/esp32c3/Kconfig.rtc index fcd91f9ff5c..b0f2e47f565 100644 --- a/soc/espressif/esp32c3/Kconfig.rtc +++ b/soc/espressif/esp32c3/Kconfig.rtc @@ -47,4 +47,21 @@ config RTC_CLK_CAL_CYCLES In case more value will help improve the definition of the launch of the crystal. If the crystal could not start, it will be switched to internal RC. +config ESP_SYSTEM_RTC_EXT_XTAL_BOOTSTRAP_CYCLES + int "Bootstrap cycles for external 32kHz crystal" + depends on ESP_SYSTEM_RTC_EXT_XTAL + default 0 + range 0 32768 + help + To reduce the startup time of an external RTC crystal, + we bootstrap it with a 32kHz square wave for a fixed number of cycles. + Setting 0 will disable bootstrapping (if disabled, the crystal may take + longer to start up or fail to oscillate under some conditions). + + If this value is too high, a faulty crystal may initially start and then fail. + If this value is too low, an otherwise good crystal may not start. + + To accurately determine if the crystal has started, + set a larger "Number of cycles for RTC_SLOW_CLK calibration" (about 3000). + endif # SOC_SERIES_ESP32C3 diff --git a/soc/espressif/esp32c3/default.ld b/soc/espressif/esp32c3/default.ld index 120f66d852d..17e88337355 100644 --- a/soc/espressif/esp32c3/default.ld +++ b/soc/espressif/esp32c3/default.ld @@ -658,7 +658,7 @@ SECTIONS *(.rodata_desc .rodata_desc.*) *(.rodata_custom_desc .rodata_custom_desc.*) - __rodata_region_start = .; + __rodata_region_start = ABSOLUTE(.); . = ALIGN(4); #include @@ -684,7 +684,7 @@ SECTIONS *(.xt_except_desc_end) *(.dynamic) *(.gnu.version_d) - __rodata_region_end = .; + __rodata_region_end = ABSOLUTE(.); _rodata_end = ABSOLUTE(.); /* Literals are also RO data. */ _lit4_start = ABSOLUTE(.); @@ -745,6 +745,7 @@ SECTIONS _instruction_reserved_start = ABSOLUTE(.); _text_start = ABSOLUTE(.); _instruction_reserved_start = ABSOLUTE(.); + __text_region_start = ABSOLUTE(.); #if !defined(CONFIG_ESP32_WIFI_IRAM_OPT) *libnet80211.a:( .wifi0iram .wifi0iram.* .wifislpiram .wifislpiram.*) @@ -765,24 +766,19 @@ SECTIONS *(.gnu.version) - /** CPU will try to prefetch up to 16 bytes of - * of instructions. This means that any configuration (e.g. MMU, PMS) must allow - * safe access to up to 16 bytes after the last real instruction, add - * dummy bytes to ensure this - */ + /* CPU will try to prefetch up to 16 bytes of + * of instructions. This means that any configuration (e.g. MMU, PMS) must allow + * safe access to up to 16 bytes after the last real instruction, add + * dummy bytes to ensure this + */ . += 16; _instruction_reserved_end = ABSOLUTE(.); _text_end = ABSOLUTE(.); _instruction_reserved_end = ABSOLUTE(.); + __text_region_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) /* --- END OF .flash.text --- */ diff --git a/soc/espressif/esp32c3/soc.c b/soc/espressif/esp32c3/soc.c index cb13c6205af..2e39e108705 100644 --- a/soc/espressif/esp32c3/soc.c +++ b/soc/espressif/esp32c3/soc.c @@ -30,10 +30,6 @@ #include #include -#ifdef CONFIG_MCUBOOT -#include "bootloader_init.h" -#endif /* CONFIG_MCUBOOT */ - extern void esp_reset_reason_init(void); /* @@ -64,20 +60,6 @@ void __attribute__((section(".iram1"))) __esp_platform_start(void) wdt_hal_disable(&rtc_wdt_ctx); wdt_hal_write_protect_enable(&rtc_wdt_ctx); - /* Configure the Cache MMU size for instruction and rodata in flash. */ - extern uint32_t esp_rom_cache_set_idrom_mmu_size(uint32_t irom_size, - uint32_t drom_size); - - extern int _rodata_reserved_start; - uint32_t rodata_reserved_start_align = - (uint32_t)&_rodata_reserved_start & ~(CONFIG_MMU_PAGE_SIZE - 1); - uint32_t cache_mmu_irom_size = - ((rodata_reserved_start_align - SOC_DROM_LOW) / CONFIG_MMU_PAGE_SIZE) * - sizeof(uint32_t); - - esp_rom_cache_set_idrom_mmu_size(cache_mmu_irom_size, - CACHE_DROM_MMU_MAX_END - cache_mmu_irom_size); - /* Enable wireless phy subsystem clock, * This needs to be done before the kernel starts */ diff --git a/soc/espressif/esp32s2/Kconfig.rtc b/soc/espressif/esp32s2/Kconfig.rtc index 837ab8623e5..61ca8d3a9df 100644 --- a/soc/espressif/esp32s2/Kconfig.rtc +++ b/soc/espressif/esp32s2/Kconfig.rtc @@ -73,4 +73,21 @@ config RTC_XTAL_CAL_RETRY Increase this option if the 32k crystal oscillator does not start and switches to internal RC. +config ESP_SYSTEM_RTC_EXT_XTAL_BOOTSTRAP_CYCLES + int "Bootstrap cycles for external 32kHz crystal" + depends on ESP_SYSTEM_RTC_EXT_XTAL + default 0 + range 0 32768 + help + To reduce the startup time of an external RTC crystal, + we bootstrap it with a 32kHz square wave for a fixed number of cycles. + Setting 0 will disable bootstrapping (if disabled, the crystal may take + longer to start up or fail to oscillate under some conditions). + + If this value is too high, a faulty crystal may initially start and then fail. + If this value is too low, an otherwise good crystal may not start. + + To accurately determine if the crystal has started, + set a larger "Number of cycles for RTC_SLOW_CLK calibration" (about 3000). + endif # SOC_SERIES_ESP32S2 diff --git a/soc/espressif/esp32s2/default.ld b/soc/espressif/esp32s2/default.ld index 89fb139f19c..0799af2ea4a 100644 --- a/soc/espressif/esp32s2/default.ld +++ b/soc/espressif/esp32s2/default.ld @@ -839,7 +839,7 @@ SECTIONS *(.dynamic) *(.gnu.version_d) . = ALIGN(4); - __rodata_region_end = ABSOLUTE(.); + _rodata_end = ABSOLUTE(.); /* Literals are also RO data. */ _lit4_start = ABSOLUTE(.); *(*.lit4) @@ -868,8 +868,8 @@ SECTIONS { . = ALIGN(CACHE_ALIGN); _image_rodata_end = ABSOLUTE(.); - _rodata_region_end = ABSOLUTE(.); _rodata_reserved_end = ABSOLUTE(.); + __rodata_region_end = ABSOLUTE(.); } GROUP_DATA_LINK_IN(RODATA_REGION, ROMABLE_REGION) @@ -891,6 +891,7 @@ SECTIONS _stext = .; _instruction_reserved_start = ABSOLUTE(.); _text_start = ABSOLUTE(.); + __text_region_start = ABSOLUTE(.); #if !defined(CONFIG_ESP32_WIFI_IRAM_OPT) *libnet80211.a:( .wifi0iram .wifi0iram.* .wifislpiram .wifislpiram.*) @@ -919,13 +920,9 @@ SECTIONS _text_end = ABSOLUTE(.); _instruction_reserved_end = ABSOLUTE(.); /* This is a symbol marking the flash.text end, this can be used for mmu driver to maintain virtual address */ + __text_region_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(ROTEXT_REGION, ROMABLE_REGION) /* --- END OF .flash.text --- */ diff --git a/soc/espressif/esp32s2/soc.c b/soc/espressif/esp32s2/soc.c index 2df9f7f288f..a0558bd8ea3 100644 --- a/soc/espressif/esp32s2/soc.c +++ b/soc/espressif/esp32s2/soc.c @@ -37,10 +37,6 @@ #include #include -#ifdef CONFIG_MCUBOOT -#include "bootloader_init.h" -#endif /* CONFIG_MCUBOOT */ - extern void rtc_clk_cpu_freq_set_xtal(void); extern void esp_reset_reason_init(void); diff --git a/soc/espressif/esp32s3/Kconfig.rtc b/soc/espressif/esp32s3/Kconfig.rtc index 526d4b909c9..9c5d7d834ba 100644 --- a/soc/espressif/esp32s3/Kconfig.rtc +++ b/soc/espressif/esp32s3/Kconfig.rtc @@ -43,4 +43,21 @@ config RTC_CLK_CAL_CYCLES In case more value will help improve the definition of the launch of the crystal. If the crystal could not start, it will be switched to internal RC. +config ESP_SYSTEM_RTC_EXT_XTAL_BOOTSTRAP_CYCLES + int "Bootstrap cycles for external 32kHz crystal" + depends on ESP_SYSTEM_RTC_EXT_XTAL + default 0 + range 0 32768 + help + To reduce the startup time of an external RTC crystal, + we bootstrap it with a 32kHz square wave for a fixed number of cycles. + Setting 0 will disable bootstrapping (if disabled, the crystal may take + longer to start up or fail to oscillate under some conditions). + + If this value is too high, a faulty crystal may initially start and then fail. + If this value is too low, an otherwise good crystal may not start. + + To accurately determine if the crystal has started, + set a larger "Number of cycles for RTC_SLOW_CLK calibration" (about 3000). + endif # SOC_SERIES_ESP32S3 diff --git a/soc/espressif/esp32s3/default.ld b/soc/espressif/esp32s3/default.ld index 120fb083d38..93c9c3044b9 100644 --- a/soc/espressif/esp32s3/default.ld +++ b/soc/espressif/esp32s3/default.ld @@ -744,6 +744,7 @@ SECTIONS _stext = .; _instruction_reserved_start = ABSOLUTE(.); _text_start = ABSOLUTE(.); + __text_region_start = ABSOLUTE(.); #if !defined(CONFIG_ESP32_WIFI_IRAM_OPT) *libnet80211.a:( .wifi0iram .wifi0iram.* .wifislpiram .wifislpiram.*) @@ -771,13 +772,9 @@ SECTIONS _text_end = ABSOLUTE(.); _instruction_reserved_end = ABSOLUTE(.); /* This is a symbol marking the flash.text end, this can be used for mmu driver to maintain virtual address */ + __text_region_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) /* This dummy section represents the .flash.text section but in default_rodata_seg. diff --git a/soc/espressif/esp32s3/soc.c b/soc/espressif/esp32s3/soc.c index c63d61474dd..d8791cf6cc8 100644 --- a/soc/espressif/esp32s3/soc.c +++ b/soc/espressif/esp32s3/soc.c @@ -45,9 +45,6 @@ #include #include -#ifdef CONFIG_MCUBOOT -#include "bootloader_init.h" -#endif /* CONFIG_MCUBOOT */ #include #if CONFIG_ESP_SPIRAM diff --git a/soc/infineon/cat1a/CMakeLists.txt b/soc/infineon/cat1a/CMakeLists.txt new file mode 100644 index 00000000000..c08c13ac0cc --- /dev/null +++ b/soc/infineon/cat1a/CMakeLists.txt @@ -0,0 +1,30 @@ +# Copyright (c) 2024 Cypress Semiconductor Corporation. +# SPDX-License-Identifier: Apache-2.0 + +if(CONFIG_SOC_FAMILY_PSOC6) + zephyr_include_directories(common) + zephyr_sources(common/soc.c) + + # Add sections + zephyr_linker_sources(NOINIT common/noinit.ld) + + # Add section for cm0p image ROM + zephyr_linker_sources(ROM_START SORT_KEY 0x0cm0p common/rom_cm0image.ld) + + # Add section for cm0p image RAM + zephyr_linker_sources(RAM_SECTIONS SORT_KEY 0 common/ram_cm0image.ld) + zephyr_linker_sources(RAMFUNC_SECTION SORT_KEY 0 common/ram_func.ld) + zephyr_linker_sources(RODATA SORT_KEY 0 common/rom.ld) + +endif() + +if(CONFIG_SOC_FAMILY_PSOC6_LEGACY) + zephyr_include_directories(psoc6_legacy) + zephyr_sources(psoc6_legacy/soc.c) + zephyr_sources(psoc6_legacy/soc_gpio.c) + + zephyr_linker_sources(NOINIT psoc6_legacy/noinit.ld) + zephyr_linker_sources(RWDATA psoc6_legacy/rwdata.ld) +endif() + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/infineon/cat1a/Kconfig b/soc/infineon/cat1a/Kconfig new file mode 100644 index 00000000000..f7e3e0b49b4 --- /dev/null +++ b/soc/infineon/cat1a/Kconfig @@ -0,0 +1,62 @@ +# Copyright (c) 2024 Cypress Semiconductor Corporation (an Infineon company) or +# an affiliate of Cypress Semiconductor Corporation +# SPDX-License-Identifier: Apache-2.0 + +# Infineon CAT1A devices + +# Family definitions +config SOC_FAMILY_PSOC6 + select ARM + select CPU_CORTEX_M4 + select CPU_HAS_ARM_MPU + select DYNAMIC_INTERRUPTS + select CPU_HAS_FPU + select SOC_FAMILY_INFINEON_CAT1 + +config SOC_FAMILY_PSOC6_LEGACY + select ARM + select HAS_CYPRESS_DRIVERS + select CPU_CORTEX_M_HAS_SYSTICK + select CPU_HAS_ARM_MPU + +config SOC_FAMILY_PSOC6_LEGACY_M4 + select CPU_CORTEX_M4 + select CPU_CORTEX_M_HAS_DWT + select CPU_HAS_FPU + +config SOC_FAMILY_PSOC6_LEGACY_M0 + select CPU_CORTEX_M0PLUS + select CPU_CORTEX_M_HAS_VTOR + +config SOC_PSOC6_M0_ENABLES_M4 + bool "Dual-core support [activate Cortex-M4]" + depends on SOC_FAMILY_PSOC6_LEGACY_M0 + help + Cortex-M0 CPU should boot Cortex-M4 + +if SOC_FAMILY_PSOC6 +## PSoCā„¢ 6 Cortex M0+ prebuilt images +choice + prompt "PSoCā„¢ 6 Cortex M0+ prebuilt images" + help + Choose the prebuilt application image to be executed on the Cortex-M0+ core of the PSoCā„¢ 6 + dual-core MCU. The image is responsible for booting the Cortex-M4 on the device. + +config SOC_PSOC6_CM0P_IMAGE_SLEEP + bool "DeepSleep" + help + DeepSleep prebuilt application image is executed on the Cortex-M0+ core of the PSoCā„¢ 6 BLE + dual-core MCU.The image is provided as C array ready to be compiled as part of the Cortex-M4 + application. The Cortex-M0+ application code is placed to internal flash by the Cortex-M4 + linker script. +endchoice + +config SOC_PSOC6_CM0P_IMAGE_ROM_SIZE + hex + default 0x2000 if SOC_PSOC6_CM0P_IMAGE_SLEEP + +config SOC_PSOC6_CM0P_IMAGE_RAM_SIZE + hex + default 0x2000 if SOC_PSOC6_CM0P_IMAGE_SLEEP + +endif # SOC_FAMILY_PSOC6 diff --git a/soc/infineon/cat1a/Kconfig.defconfig b/soc/infineon/cat1a/Kconfig.defconfig new file mode 100644 index 00000000000..57e358eff8b --- /dev/null +++ b/soc/infineon/cat1a/Kconfig.defconfig @@ -0,0 +1,10 @@ +# PSOC CAT1A Configuration + +# Copyright (c) 2024 Cypress Semiconductor Corporation. +# SPDX-License-Identifier: Apache-2.0 + +if SOC_FAMILY_INFINEON_CAT1A + +rsource "*/Kconfig.defconfig" + +endif # SOC_FAMILY_INFINEON_CAT1A diff --git a/soc/infineon/cat1a/Kconfig.soc b/soc/infineon/cat1a/Kconfig.soc new file mode 100644 index 00000000000..a70e341dd41 --- /dev/null +++ b/soc/infineon/cat1a/Kconfig.soc @@ -0,0 +1,61 @@ +# Copyright (c) 2024 Cypress Semiconductor Corporation (an Infineon company) or +# an affiliate of Cypress Semiconductor Corporation +# SPDX-License-Identifier: Apache-2.0 + +# MPNs definitions +rsource "*/Kconfig.soc" + +# Infineon CAT1A devices + +# Category definitions +config SOC_FAMILY_INFINEON_CAT1 + bool + +config SOC_FAMILY_INFINEON_CAT1A + bool + +# Family definitions +config SOC_FAMILY_PSOC6 + bool + +config SOC_FAMILY_PSOC6_LEGACY + bool + +config SOC_FAMILY_PSOC6_LEGACY_M4 + bool + +config SOC_FAMILY_PSOC6_LEGACY_M0 + bool + +# Cypress PSoCā„¢ 6 MCU lines +config SOC_SERIES_PSOC6_60 + bool + select SOC_FAMILY_PSOC6 if !SOC_FAMILY_PSOC6_LEGACY + select SOC_FAMILY_INFINEON_CAT1A + +config SOC_SERIES_PSOC6_61 + bool + select SOC_FAMILY_PSOC6 if !SOC_FAMILY_PSOC6_LEGACY + select SOC_FAMILY_INFINEON_CAT1A + +config SOC_SERIES_PSOC6_62 + bool + select SOC_FAMILY_PSOC6 if !SOC_FAMILY_PSOC6_LEGACY + select SOC_FAMILY_INFINEON_CAT1A + +config SOC_SERIES_PSOC6_63 + bool + select SOC_FAMILY_PSOC6 if !SOC_FAMILY_PSOC6_LEGACY + select SOC_FAMILY_INFINEON_CAT1A + +config SOC_SERIES_PSOC6_64 + bool + select SOC_FAMILY_PSOC6 if !SOC_FAMILY_PSOC6_LEGACY + select SOC_FAMILY_INFINEON_CAT1A + +config SOC_SERIES + default "psoc6_60" if SOC_SERIES_PSOC6_60 + default "psoc6_61" if SOC_SERIES_PSOC6_61 + default "psoc6_62" if SOC_SERIES_PSOC6_62 + default "psoc6_63" if SOC_SERIES_PSOC6_63 + default "psoc6_64" if SOC_SERIES_PSOC6_64 diff --git a/soc/cypress/psoc6/new/noinit.ld b/soc/infineon/cat1a/common/noinit.ld similarity index 100% rename from soc/cypress/psoc6/new/noinit.ld rename to soc/infineon/cat1a/common/noinit.ld diff --git a/soc/cypress/psoc6/new/common/pinctrl_soc.h b/soc/infineon/cat1a/common/pinctrl_soc.h similarity index 100% rename from soc/cypress/psoc6/new/common/pinctrl_soc.h rename to soc/infineon/cat1a/common/pinctrl_soc.h diff --git a/soc/cypress/psoc6/new/ram_cm0image.ld b/soc/infineon/cat1a/common/ram_cm0image.ld similarity index 100% rename from soc/cypress/psoc6/new/ram_cm0image.ld rename to soc/infineon/cat1a/common/ram_cm0image.ld diff --git a/soc/cypress/psoc6/new/ram_func.ld b/soc/infineon/cat1a/common/ram_func.ld similarity index 100% rename from soc/cypress/psoc6/new/ram_func.ld rename to soc/infineon/cat1a/common/ram_func.ld diff --git a/soc/cypress/psoc6/new/rom.ld b/soc/infineon/cat1a/common/rom.ld similarity index 100% rename from soc/cypress/psoc6/new/rom.ld rename to soc/infineon/cat1a/common/rom.ld diff --git a/soc/cypress/psoc6/new/rom_cm0image.ld b/soc/infineon/cat1a/common/rom_cm0image.ld similarity index 100% rename from soc/cypress/psoc6/new/rom_cm0image.ld rename to soc/infineon/cat1a/common/rom_cm0image.ld diff --git a/soc/cypress/psoc6/new/soc.c b/soc/infineon/cat1a/common/soc.c similarity index 100% rename from soc/cypress/psoc6/new/soc.c rename to soc/infineon/cat1a/common/soc.c diff --git a/soc/cypress/psoc6/new/soc.h b/soc/infineon/cat1a/common/soc.h similarity index 100% rename from soc/cypress/psoc6/new/soc.h rename to soc/infineon/cat1a/common/soc.h diff --git a/soc/infineon/cat1a/psoc6_01/Kconfig.defconfig b/soc/infineon/cat1a/psoc6_01/Kconfig.defconfig new file mode 100644 index 00000000000..aec3e32650c --- /dev/null +++ b/soc/infineon/cat1a/psoc6_01/Kconfig.defconfig @@ -0,0 +1,18 @@ +# Copyright (c) 2023 Cypress Semiconductor Corporation (an Infineon company) or +# an affiliate of Cypress Semiconductor Corporation +# SPDX-License-Identifier: Apache-2.0 + +# Infineon PSoC6_01 based MCU default configuration + +if SOC_DIE_PSOC6_01 + +config NUM_IRQS + default 32 if CPU_CORTEX_M0PLUS + default 147 if CPU_CORTEX_M4 + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default 100000000 + +# add additional die specific params + +endif # SOC_DIE_PSOC6_01 diff --git a/soc/infineon/cat1a/psoc6_01/Kconfig.soc b/soc/infineon/cat1a/psoc6_01/Kconfig.soc new file mode 100644 index 00000000000..3380db75d79 --- /dev/null +++ b/soc/infineon/cat1a/psoc6_01/Kconfig.soc @@ -0,0 +1,483 @@ +# Copyright (c) 2023 Cypress Semiconductor Corporation (an Infineon company) or +# an affiliate of Cypress Semiconductor Corporation +# SPDX-License-Identifier: Apache-2.0 + +# SOC die +config SOC_DIE_PSOC6_01 + bool + +# SOC packages +config SOC_PACKAGE_PSOC6_01_124_BGA + bool + +config SOC_PACKAGE_PSOC6_01_116_BGA_BLE + bool + +config SOC_PACKAGE_PSOC6_01_104_M_CSP_BLE + bool + +config SOC_PACKAGE_PSOC6_01_80_WLCSP + bool + +config SOC_PACKAGE_PSOC6_01_116_BGA_USB + bool + +config SOC_PACKAGE_PSOC6_01_124_BGA_SIP + bool + +config SOC_PACKAGE_PSOC6_01_104_M_CSP_BLE_USB + bool + +config SOC_PACKAGE_PSOC6_01_68_QFN_BLE + bool + +# Infineon PSoC6_01 series MCUs +config SOC_CY8C6036BZI_F04 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_124_BGA + select SOC_SERIES_PSOC6_60 + +config SOC_CY8C6016BZI_F04 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_124_BGA + select SOC_SERIES_PSOC6_60 + +config SOC_CY8C6116BZI_F54 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_124_BGA + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C6136BZI_F14 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_124_BGA + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C6136BZI_F34 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_124_BGA + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C6137BZI_F14 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_124_BGA + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C6137BZI_F34 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_124_BGA + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C6137BZI_F54 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_124_BGA + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C6117BZI_F34 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_124_BGA + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C6246BZI_D04 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_124_BGA + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C6247BZI_D44 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_124_BGA + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C6247BZI_D34 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_124_BGA + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C6247BZI_D54 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_124_BGA + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C6336BZI_BLF03 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_116_BGA_BLE + select SOC_SERIES_PSOC6_63 + +config SOC_CY8C6316BZI_BLF03 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_116_BGA_BLE + select SOC_SERIES_PSOC6_63 + +config SOC_CY8C6316BZI_BLF53 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_116_BGA_BLE + select SOC_SERIES_PSOC6_63 + +config SOC_CY8C6336BZI_BLD13 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_116_BGA_BLE + select SOC_SERIES_PSOC6_63 + +config SOC_CY8C6347BZI_BLD43 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_116_BGA_BLE + select SOC_SERIES_PSOC6_63 + +config SOC_CY8C6347BZI_BLD33 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_116_BGA_BLE + select SOC_SERIES_PSOC6_63 + +config SOC_CY8C6347BZI_BLD53 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_116_BGA_BLE + select SOC_SERIES_PSOC6_63 + +config SOC_CY8C6347FMI_BLD13 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_104_M_CSP_BLE + select SOC_SERIES_PSOC6_63 + +config SOC_CY8C6347FMI_BLD43 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_104_M_CSP_BLE + select SOC_SERIES_PSOC6_63 + +config SOC_CY8C6347FMI_BLD33 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_104_M_CSP_BLE + select SOC_SERIES_PSOC6_63 + +config SOC_CY8C6347FMI_BLD53 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_104_M_CSP_BLE + select SOC_SERIES_PSOC6_63 + +config SOC_CY8C6137FDI_F02 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_80_WLCSP + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C6117FDI_F02 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_80_WLCSP + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C6247FDI_D02 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_80_WLCSP + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C6247FDI_D32 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_80_WLCSP + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C6336BZI_BUD13 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_116_BGA_USB + select SOC_SERIES_PSOC6_63 + +config SOC_CY8C6347BZI_BUD43 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_116_BGA_USB + select SOC_SERIES_PSOC6_63 + +config SOC_CY8C6347BZI_BUD33 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_116_BGA_USB + select SOC_SERIES_PSOC6_63 + +config SOC_CY8C6347BZI_BUD53 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_116_BGA_USB + select SOC_SERIES_PSOC6_63 + +config SOC_CY8C6337BZI_BLF13 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_116_BGA_BLE + select SOC_SERIES_PSOC6_63 + +config SOC_CY8C6136FDI_F42 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_80_WLCSP + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C6247FDI_D52 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_80_WLCSP + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C6136FTI_F42 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_80_WLCSP + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C6247FTI_D52 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_80_WLCSP + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C6247BZI_AUD54 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_124_BGA + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C6336BZI_BLF04 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_124_BGA_SIP + select SOC_SERIES_PSOC6_63 + +config SOC_CY8C6316BZI_BLF04 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_124_BGA_SIP + select SOC_SERIES_PSOC6_63 + +config SOC_CY8C6316BZI_BLF54 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_124_BGA_SIP + select SOC_SERIES_PSOC6_63 + +config SOC_CY8C6336BZI_BLD14 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_124_BGA_SIP + select SOC_SERIES_PSOC6_63 + +config SOC_CY8C6347BZI_BLD44 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_124_BGA_SIP + select SOC_SERIES_PSOC6_63 + +config SOC_CY8C6347BZI_BLD34 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_124_BGA_SIP + select SOC_SERIES_PSOC6_63 + +config SOC_CY8C6347BZI_BLD54 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_124_BGA_SIP + select SOC_SERIES_PSOC6_63 + +config SOC_CY8C6247BFI_D54 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_124_BGA + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C6347FMI_BUD53 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_104_M_CSP_BLE_USB + select SOC_SERIES_PSOC6_63 + +config SOC_CY8C6347FMI_BUD13 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_104_M_CSP_BLE_USB + select SOC_SERIES_PSOC6_63 + +config SOC_CY8C6347FMI_BUD43 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_104_M_CSP_BLE_USB + select SOC_SERIES_PSOC6_63 + +config SOC_CY8C6347FMI_BUD33 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_104_M_CSP_BLE_USB + select SOC_SERIES_PSOC6_63 + +config SOC_CY8C6137WI_F54 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_124_BGA + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C6117WI_F34 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_124_BGA + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C6247WI_D54 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_124_BGA + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C6336LQI_BLF02 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_68_QFN_BLE + select SOC_SERIES_PSOC6_63 + +config SOC_CY8C6336LQI_BLF42 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_68_QFN_BLE + select SOC_SERIES_PSOC6_63 + +config SOC_CY8C6347LQI_BLD52 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_68_QFN_BLE + select SOC_SERIES_PSOC6_63 + +config SOC_CY8C6247BTI_D54 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_124_BGA + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C6246BTI_D54 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_124_BGA + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C6147BTI_F54 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_124_BGA + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C6146BTI_F54 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_124_BGA + select SOC_SERIES_PSOC6_61 + +config SOC_CYB06447BZI_BLD54 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_124_BGA_SIP + select SOC_SERIES_PSOC6_64 + +config SOC_CYB06447BZI_BLD53 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_116_BGA_BLE + select SOC_SERIES_PSOC6_64 + +config SOC_CYB06447BZI_D54 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_124_BGA + select SOC_SERIES_PSOC6_64 + +config SOC_CYBLE_416045_02 + bool + select SOC_DIE_PSOC6_01 + select SOC_PACKAGE_PSOC6_01_116_BGA_BLE + select SOC_SERIES_PSOC6_63 + +config SOC + default "cy8c6036bzi_f04" if SOC_CY8C6036BZI_F04 + default "cy8c6016bzi_f04" if SOC_CY8C6016BZI_F04 + default "cy8c6116bzi_f54" if SOC_CY8C6116BZI_F54 + default "cy8c6136bzi_f14" if SOC_CY8C6136BZI_F14 + default "cy8c6136bzi_f34" if SOC_CY8C6136BZI_F34 + default "cy8c6137bzi_f14" if SOC_CY8C6137BZI_F14 + default "cy8c6137bzi_f34" if SOC_CY8C6137BZI_F34 + default "cy8c6137bzi_f54" if SOC_CY8C6137BZI_F54 + default "cy8c6117bzi_f34" if SOC_CY8C6117BZI_F34 + default "cy8c6246bzi_d04" if SOC_CY8C6246BZI_D04 + default "cy8c6247bzi_d44" if SOC_CY8C6247BZI_D44 + default "cy8c6247bzi_d34" if SOC_CY8C6247BZI_D34 + default "cy8c6247bzi_d54" if SOC_CY8C6247BZI_D54 + default "cy8c6336bzi_blf03" if SOC_CY8C6336BZI_BLF03 + default "cy8c6316bzi_blf03" if SOC_CY8C6316BZI_BLF03 + default "cy8c6316bzi_blf53" if SOC_CY8C6316BZI_BLF53 + default "cy8c6336bzi_bld13" if SOC_CY8C6336BZI_BLD13 + default "cy8c6347bzi_bld43" if SOC_CY8C6347BZI_BLD43 + default "cy8c6347bzi_bld33" if SOC_CY8C6347BZI_BLD33 + default "cy8c6347bzi_bld53" if SOC_CY8C6347BZI_BLD53 + default "cy8c6347fmi_bld13" if SOC_CY8C6347FMI_BLD13 + default "cy8c6347fmi_bld43" if SOC_CY8C6347FMI_BLD43 + default "cy8c6347fmi_bld33" if SOC_CY8C6347FMI_BLD33 + default "cy8c6347fmi_bld53" if SOC_CY8C6347FMI_BLD53 + default "cy8c6137fdi_f02" if SOC_CY8C6137FDI_F02 + default "cy8c6117fdi_f02" if SOC_CY8C6117FDI_F02 + default "cy8c6247fdi_d02" if SOC_CY8C6247FDI_D02 + default "cy8c6247fdi_d32" if SOC_CY8C6247FDI_D32 + default "cy8c6336bzi_bud13" if SOC_CY8C6336BZI_BUD13 + default "cy8c6347bzi_bud43" if SOC_CY8C6347BZI_BUD43 + default "cy8c6347bzi_bud33" if SOC_CY8C6347BZI_BUD33 + default "cy8c6347bzi_bud53" if SOC_CY8C6347BZI_BUD53 + default "cy8c6337bzi_blf13" if SOC_CY8C6337BZI_BLF13 + default "cy8c6136fdi_f42" if SOC_CY8C6136FDI_F42 + default "cy8c6247fdi_d52" if SOC_CY8C6247FDI_D52 + default "cy8c6136fti_f42" if SOC_CY8C6136FTI_F42 + default "cy8c6247fti_d52" if SOC_CY8C6247FTI_D52 + default "cy8c6247bzi_aud54" if SOC_CY8C6247BZI_AUD54 + default "cy8c6336bzi_blf04" if SOC_CY8C6336BZI_BLF04 + default "cy8c6316bzi_blf04" if SOC_CY8C6316BZI_BLF04 + default "cy8c6316bzi_blf54" if SOC_CY8C6316BZI_BLF54 + default "cy8c6336bzi_bld14" if SOC_CY8C6336BZI_BLD14 + default "cy8c6347bzi_bld44" if SOC_CY8C6347BZI_BLD44 + default "cy8c6347bzi_bld34" if SOC_CY8C6347BZI_BLD34 + default "cy8c6347bzi_bld54" if SOC_CY8C6347BZI_BLD54 + default "cy8c6247bfi_d54" if SOC_CY8C6247BFI_D54 + default "cy8c6347fmi_bud53" if SOC_CY8C6347FMI_BUD53 + default "cy8c6347fmi_bud13" if SOC_CY8C6347FMI_BUD13 + default "cy8c6347fmi_bud43" if SOC_CY8C6347FMI_BUD43 + default "cy8c6347fmi_bud33" if SOC_CY8C6347FMI_BUD33 + default "cy8c6137wi_f54" if SOC_CY8C6137WI_F54 + default "cy8c6117wi_f34" if SOC_CY8C6117WI_F34 + default "cy8c6247wi_d54" if SOC_CY8C6247WI_D54 + default "cy8c6336lqi_blf02" if SOC_CY8C6336LQI_BLF02 + default "cy8c6336lqi_blf42" if SOC_CY8C6336LQI_BLF42 + default "cy8c6347lqi_bld52" if SOC_CY8C6347LQI_BLD52 + default "cy8c6247bti_d54" if SOC_CY8C6247BTI_D54 + default "cy8c6246bti_d54" if SOC_CY8C6246BTI_D54 + default "cy8c6147bti_f54" if SOC_CY8C6147BTI_F54 + default "cy8c6146bti_f54" if SOC_CY8C6146BTI_F54 + default "cyb06447bzi_bld54" if SOC_CYB06447BZI_BLD54 + default "cyb06447bzi_bld53" if SOC_CYB06447BZI_BLD53 + default "cyb06447bzi_d54" if SOC_CYB06447BZI_D54 + default "cyble_416045_02" if SOC_CYBLE_416045_02 diff --git a/soc/infineon/cat1a/psoc6_02/Kconfig.defconfig b/soc/infineon/cat1a/psoc6_02/Kconfig.defconfig new file mode 100644 index 00000000000..65c86f0b831 --- /dev/null +++ b/soc/infineon/cat1a/psoc6_02/Kconfig.defconfig @@ -0,0 +1,18 @@ +# Copyright (c) 2023 Cypress Semiconductor Corporation (an Infineon company) or +# an affiliate of Cypress Semiconductor Corporation +# SPDX-License-Identifier: Apache-2.0 + +# Infineon PSoC6_02 based MCU default configuration + +if SOC_DIE_PSOC6_02 + +config NUM_IRQS + default 16 if CPU_CORTEX_M0PLUS + default 168 if CPU_CORTEX_M4 + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default 100000000 + +# add additional die specific params + +endif # SOC_DIE_PSOC6_02 diff --git a/soc/infineon/cat1a/psoc6_02/Kconfig.soc b/soc/infineon/cat1a/psoc6_02/Kconfig.soc new file mode 100644 index 00000000000..1a3d7e05467 --- /dev/null +++ b/soc/infineon/cat1a/psoc6_02/Kconfig.soc @@ -0,0 +1,254 @@ +# Copyright (c) 2023 Cypress Semiconductor Corporation (an Infineon company) or +# an affiliate of Cypress Semiconductor Corporation +# SPDX-License-Identifier: Apache-2.0 + +# SOC die +config SOC_DIE_PSOC6_02 + bool + +# SOC packages +config SOC_PACKAGE_PSOC6_02_124_BGA + bool + +config SOC_PACKAGE_PSOC6_02_100_WLCSP + bool + +config SOC_PACKAGE_PSOC6_02_128_TQFP + bool + +config SOC_PACKAGE_PSOC6_02_68_QFN + bool + +# Infineon PSoC6_02 series MCUs +config SOC_CYB0644ABZI_S2D44 + bool + select SOC_DIE_PSOC6_02 + select SOC_PACKAGE_PSOC6_02_124_BGA + select SOC_SERIES_PSOC6_64 + +config SOC_CYS0644ABZI_S2D44 + bool + select SOC_DIE_PSOC6_02 + select SOC_PACKAGE_PSOC6_02_124_BGA + select SOC_SERIES_PSOC6_64 + +config SOC_CYS0644AFNI_S2D43 + bool + select SOC_DIE_PSOC6_02 + select SOC_PACKAGE_PSOC6_02_100_WLCSP + select SOC_SERIES_PSOC6_64 + +config SOC_CY8C624ABZI_S2D44A0 + bool + select SOC_DIE_PSOC6_02 + select SOC_PACKAGE_PSOC6_02_124_BGA + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C624ABZI_S2D44 + bool + select SOC_DIE_PSOC6_02 + select SOC_PACKAGE_PSOC6_02_124_BGA + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C624AAZI_S2D44 + bool + select SOC_DIE_PSOC6_02 + select SOC_PACKAGE_PSOC6_02_128_TQFP + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C624AFNI_S2D43 + bool + select SOC_DIE_PSOC6_02 + select SOC_PACKAGE_PSOC6_02_100_WLCSP + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C624ABZI_S2D04 + bool + select SOC_DIE_PSOC6_02 + select SOC_PACKAGE_PSOC6_02_124_BGA + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C624ABZI_S2D14 + bool + select SOC_DIE_PSOC6_02 + select SOC_PACKAGE_PSOC6_02_124_BGA + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C624AAZI_S2D14 + bool + select SOC_DIE_PSOC6_02 + select SOC_PACKAGE_PSOC6_02_128_TQFP + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C6248AZI_S2D14 + bool + select SOC_DIE_PSOC6_02 + select SOC_PACKAGE_PSOC6_02_128_TQFP + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C6248BZI_S2D44 + bool + select SOC_DIE_PSOC6_02 + select SOC_PACKAGE_PSOC6_02_124_BGA + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C6248AZI_S2D44 + bool + select SOC_DIE_PSOC6_02 + select SOC_PACKAGE_PSOC6_02_128_TQFP + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C6248FNI_S2D43 + bool + select SOC_DIE_PSOC6_02 + select SOC_PACKAGE_PSOC6_02_100_WLCSP + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C614ABZI_S2F04 + bool + select SOC_DIE_PSOC6_02 + select SOC_PACKAGE_PSOC6_02_124_BGA + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C614AAZI_S2F04 + bool + select SOC_DIE_PSOC6_02 + select SOC_PACKAGE_PSOC6_02_128_TQFP + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C614AFNI_S2F03 + bool + select SOC_DIE_PSOC6_02 + select SOC_PACKAGE_PSOC6_02_100_WLCSP + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C614AAZI_S2F14 + bool + select SOC_DIE_PSOC6_02 + select SOC_PACKAGE_PSOC6_02_128_TQFP + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C614ABZI_S2F44 + bool + select SOC_DIE_PSOC6_02 + select SOC_PACKAGE_PSOC6_02_124_BGA + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C614AAZI_S2F44 + bool + select SOC_DIE_PSOC6_02 + select SOC_PACKAGE_PSOC6_02_128_TQFP + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C614AFNI_S2F43 + bool + select SOC_DIE_PSOC6_02 + select SOC_PACKAGE_PSOC6_02_100_WLCSP + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C6148BZI_S2F44 + bool + select SOC_DIE_PSOC6_02 + select SOC_PACKAGE_PSOC6_02_124_BGA + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C6148AZI_S2F44 + bool + select SOC_DIE_PSOC6_02 + select SOC_PACKAGE_PSOC6_02_128_TQFP + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C6148FNI_S2F43 + bool + select SOC_DIE_PSOC6_02 + select SOC_PACKAGE_PSOC6_02_100_WLCSP + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C624ABZI_D44 + bool + select SOC_DIE_PSOC6_02 + select SOC_PACKAGE_PSOC6_02_124_BGA + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C624ALQI_S2D42 + bool + select SOC_DIE_PSOC6_02 + select SOC_PACKAGE_PSOC6_02_68_QFN + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C624ALQI_S2D02 + bool + select SOC_DIE_PSOC6_02 + select SOC_PACKAGE_PSOC6_02_68_QFN + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C6248LQI_S2D42 + bool + select SOC_DIE_PSOC6_02 + select SOC_PACKAGE_PSOC6_02_68_QFN + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C6248LQI_S2D02 + bool + select SOC_DIE_PSOC6_02 + select SOC_PACKAGE_PSOC6_02_68_QFN + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C614ALQI_S2F42 + bool + select SOC_DIE_PSOC6_02 + select SOC_PACKAGE_PSOC6_02_68_QFN + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C614ALQI_S2F02 + bool + select SOC_DIE_PSOC6_02 + select SOC_PACKAGE_PSOC6_02_68_QFN + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C6148LQI_S2F42 + bool + select SOC_DIE_PSOC6_02 + select SOC_PACKAGE_PSOC6_02_68_QFN + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C6148LQI_S2F02 + bool + select SOC_DIE_PSOC6_02 + select SOC_PACKAGE_PSOC6_02_68_QFN + select SOC_SERIES_PSOC6_61 + +config SOC + default "cyb0644abzi_s2d44" if SOC_CYB0644ABZI_S2D44 + default "cys0644abzi_s2d44" if SOC_CYS0644ABZI_S2D44 + default "cys0644afni_s2d43" if SOC_CYS0644AFNI_S2D43 + default "cy8c624abzi_s2d44a0" if SOC_CY8C624ABZI_S2D44A0 + default "cy8c624abzi_s2d44" if SOC_CY8C624ABZI_S2D44 + default "cy8c624aazi_s2d44" if SOC_CY8C624AAZI_S2D44 + default "cy8c624afni_s2d43" if SOC_CY8C624AFNI_S2D43 + default "cy8c624abzi_s2d04" if SOC_CY8C624ABZI_S2D04 + default "cy8c624abzi_s2d14" if SOC_CY8C624ABZI_S2D14 + default "cy8c624aazi_s2d14" if SOC_CY8C624AAZI_S2D14 + default "cy8c6248azi_s2d14" if SOC_CY8C6248AZI_S2D14 + default "cy8c6248bzi_s2d44" if SOC_CY8C6248BZI_S2D44 + default "cy8c6248azi_s2d44" if SOC_CY8C6248AZI_S2D44 + default "cy8c6248fni_s2d43" if SOC_CY8C6248FNI_S2D43 + default "cy8c614abzi_s2f04" if SOC_CY8C614ABZI_S2F04 + default "cy8c614aazi_s2f04" if SOC_CY8C614AAZI_S2F04 + default "cy8c614afni_s2f03" if SOC_CY8C614AFNI_S2F03 + default "cy8c614aazi_s2f14" if SOC_CY8C614AAZI_S2F14 + default "cy8c614abzi_s2f44" if SOC_CY8C614ABZI_S2F44 + default "cy8c614aazi_s2f44" if SOC_CY8C614AAZI_S2F44 + default "cy8c614afni_s2f43" if SOC_CY8C614AFNI_S2F43 + default "cy8c6148bzi_s2f44" if SOC_CY8C6148BZI_S2F44 + default "cy8c6148azi_s2f44" if SOC_CY8C6148AZI_S2F44 + default "cy8c6148fni_s2f43" if SOC_CY8C6148FNI_S2F43 + default "cy8c624abzi_d44" if SOC_CY8C624ABZI_D44 + default "cy8c624alqi_s2d42" if SOC_CY8C624ALQI_S2D42 + default "cy8c624alqi_s2d02" if SOC_CY8C624ALQI_S2D02 + default "cy8c6248lqi_s2d42" if SOC_CY8C6248LQI_S2D42 + default "cy8c6248lqi_s2d02" if SOC_CY8C6248LQI_S2D02 + default "cy8c614alqi_s2f42" if SOC_CY8C614ALQI_S2F42 + default "cy8c614alqi_s2f02" if SOC_CY8C614ALQI_S2F02 + default "cy8c6148lqi_s2f42" if SOC_CY8C6148LQI_S2F42 + default "cy8c6148lqi_s2f02" if SOC_CY8C6148LQI_S2F02 diff --git a/soc/infineon/cat1a/psoc6_03/Kconfig.defconfig b/soc/infineon/cat1a/psoc6_03/Kconfig.defconfig new file mode 100644 index 00000000000..9986f512d3e --- /dev/null +++ b/soc/infineon/cat1a/psoc6_03/Kconfig.defconfig @@ -0,0 +1,18 @@ +# Copyright (c) 2023 Cypress Semiconductor Corporation (an Infineon company) or +# an affiliate of Cypress Semiconductor Corporation +# SPDX-License-Identifier: Apache-2.0 + +# Infineon PSoC6_03 based MCU default configuration + +if SOC_DIE_PSOC6_03 + +config NUM_IRQS + default 16 if CPU_CORTEX_M0PLUS + default 174 if CPU_CORTEX_M4 + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default 100000000 + +# add additional die specific params + +endif # SOC_DIE_PSOC6_03 diff --git a/soc/infineon/cat1a/psoc6_03/Kconfig.soc b/soc/infineon/cat1a/psoc6_03/Kconfig.soc new file mode 100644 index 00000000000..1863a4fd229 --- /dev/null +++ b/soc/infineon/cat1a/psoc6_03/Kconfig.soc @@ -0,0 +1,209 @@ +# Copyright (c) 2023 Cypress Semiconductor Corporation (an Infineon company) or +# an affiliate of Cypress Semiconductor Corporation +# SPDX-License-Identifier: Apache-2.0 + +# SOC die +config SOC_DIE_PSOC6_03 + bool + +# SOC packages +config SOC_PACKAGE_PSOC6_03_100_TQFP + bool + +config SOC_PACKAGE_PSOC6_03_68_QFN + bool + +config SOC_PACKAGE_PSOC6_03_49_WLCSP + bool + +# Infineon PSoC6_03 series MCUs +config SOC_CY8C6245AZI_S3D72 + bool + select SOC_DIE_PSOC6_03 + select SOC_PACKAGE_PSOC6_03_100_TQFP + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C6245LQI_S3D72 + bool + select SOC_DIE_PSOC6_03 + select SOC_PACKAGE_PSOC6_03_68_QFN + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C6245FNI_S3D71 + bool + select SOC_DIE_PSOC6_03 + select SOC_PACKAGE_PSOC6_03_49_WLCSP + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C6245AZI_S3D62 + bool + select SOC_DIE_PSOC6_03 + select SOC_PACKAGE_PSOC6_03_100_TQFP + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C6245LQI_S3D62 + bool + select SOC_DIE_PSOC6_03 + select SOC_PACKAGE_PSOC6_03_68_QFN + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C6245AZI_S3D42 + bool + select SOC_DIE_PSOC6_03 + select SOC_PACKAGE_PSOC6_03_100_TQFP + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C6245LQI_S3D42 + bool + select SOC_DIE_PSOC6_03 + select SOC_PACKAGE_PSOC6_03_68_QFN + select SOC_SERIES_PSOC6_62 + +config SOC_CYB06445LQI_S3D42 + bool + select SOC_DIE_PSOC6_03 + select SOC_PACKAGE_PSOC6_03_68_QFN + select SOC_SERIES_PSOC6_64 + +config SOC_CY8C6245FNI_S3D41 + bool + select SOC_DIE_PSOC6_03 + select SOC_PACKAGE_PSOC6_03_49_WLCSP + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C6245AZI_S3D12 + bool + select SOC_DIE_PSOC6_03 + select SOC_PACKAGE_PSOC6_03_100_TQFP + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C6245LQI_S3D12 + bool + select SOC_DIE_PSOC6_03 + select SOC_PACKAGE_PSOC6_03_68_QFN + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C6245FNI_S3D11 + bool + select SOC_DIE_PSOC6_03 + select SOC_PACKAGE_PSOC6_03_49_WLCSP + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C6245AZI_S3D02 + bool + select SOC_DIE_PSOC6_03 + select SOC_PACKAGE_PSOC6_03_100_TQFP + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C6245LQI_S3D02 + bool + select SOC_DIE_PSOC6_03 + select SOC_PACKAGE_PSOC6_03_68_QFN + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C6145AZI_S3F72 + bool + select SOC_DIE_PSOC6_03 + select SOC_PACKAGE_PSOC6_03_100_TQFP + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C6145LQI_S3F72 + bool + select SOC_DIE_PSOC6_03 + select SOC_PACKAGE_PSOC6_03_68_QFN + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C6145FNI_S3F71 + bool + select SOC_DIE_PSOC6_03 + select SOC_PACKAGE_PSOC6_03_49_WLCSP + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C6145AZI_S3F62 + bool + select SOC_DIE_PSOC6_03 + select SOC_PACKAGE_PSOC6_03_100_TQFP + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C6145LQI_S3F62 + bool + select SOC_DIE_PSOC6_03 + select SOC_PACKAGE_PSOC6_03_68_QFN + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C6145AZI_S3F42 + bool + select SOC_DIE_PSOC6_03 + select SOC_PACKAGE_PSOC6_03_100_TQFP + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C6145LQI_S3F42 + bool + select SOC_DIE_PSOC6_03 + select SOC_PACKAGE_PSOC6_03_68_QFN + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C6145FNI_S3F41 + bool + select SOC_DIE_PSOC6_03 + select SOC_PACKAGE_PSOC6_03_49_WLCSP + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C6145AZI_S3F12 + bool + select SOC_DIE_PSOC6_03 + select SOC_PACKAGE_PSOC6_03_100_TQFP + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C6145LQI_S3F12 + bool + select SOC_DIE_PSOC6_03 + select SOC_PACKAGE_PSOC6_03_68_QFN + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C6145FNI_S3F11 + bool + select SOC_DIE_PSOC6_03 + select SOC_PACKAGE_PSOC6_03_49_WLCSP + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C6145AZI_S3F02 + bool + select SOC_DIE_PSOC6_03 + select SOC_PACKAGE_PSOC6_03_100_TQFP + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C6145LQI_S3F02 + bool + select SOC_DIE_PSOC6_03 + select SOC_PACKAGE_PSOC6_03_68_QFN + select SOC_SERIES_PSOC6_61 + +config SOC + default "cy8c6245azi_s3d72" if SOC_CY8C6245AZI_S3D72 + default "cy8c6245lqi_s3d72" if SOC_CY8C6245LQI_S3D72 + default "cy8c6245fni_s3d71" if SOC_CY8C6245FNI_S3D71 + default "cy8c6245azi_s3d62" if SOC_CY8C6245AZI_S3D62 + default "cy8c6245lqi_s3d62" if SOC_CY8C6245LQI_S3D62 + default "cy8c6245azi_s3d42" if SOC_CY8C6245AZI_S3D42 + default "cy8c6245lqi_s3d42" if SOC_CY8C6245LQI_S3D42 + default "cyb06445lqi_s3d42" if SOC_CYB06445LQI_S3D42 + default "cy8c6245fni_s3d41" if SOC_CY8C6245FNI_S3D41 + default "cy8c6245azi_s3d12" if SOC_CY8C6245AZI_S3D12 + default "cy8c6245lqi_s3d12" if SOC_CY8C6245LQI_S3D12 + default "cy8c6245fni_s3d11" if SOC_CY8C6245FNI_S3D11 + default "cy8c6245azi_s3d02" if SOC_CY8C6245AZI_S3D02 + default "cy8c6245lqi_s3d02" if SOC_CY8C6245LQI_S3D02 + default "cy8c6145azi_s3f72" if SOC_CY8C6145AZI_S3F72 + default "cy8c6145lqi_s3f72" if SOC_CY8C6145LQI_S3F72 + default "cy8c6145fni_s3f71" if SOC_CY8C6145FNI_S3F71 + default "cy8c6145azi_s3f62" if SOC_CY8C6145AZI_S3F62 + default "cy8c6145lqi_s3f62" if SOC_CY8C6145LQI_S3F62 + default "cy8c6145azi_s3f42" if SOC_CY8C6145AZI_S3F42 + default "cy8c6145lqi_s3f42" if SOC_CY8C6145LQI_S3F42 + default "cy8c6145fni_s3f41" if SOC_CY8C6145FNI_S3F41 + default "cy8c6145azi_s3f12" if SOC_CY8C6145AZI_S3F12 + default "cy8c6145lqi_s3f12" if SOC_CY8C6145LQI_S3F12 + default "cy8c6145fni_s3f11" if SOC_CY8C6145FNI_S3F11 + default "cy8c6145azi_s3f02" if SOC_CY8C6145AZI_S3F02 + default "cy8c6145lqi_s3f02" if SOC_CY8C6145LQI_S3F02 diff --git a/soc/infineon/cat1a/psoc6_04/Kconfig.defconfig b/soc/infineon/cat1a/psoc6_04/Kconfig.defconfig new file mode 100644 index 00000000000..77de960a053 --- /dev/null +++ b/soc/infineon/cat1a/psoc6_04/Kconfig.defconfig @@ -0,0 +1,18 @@ +# Copyright (c) 2023 Cypress Semiconductor Corporation (an Infineon company) or +# an affiliate of Cypress Semiconductor Corporation +# SPDX-License-Identifier: Apache-2.0 + +# Infineon PSoC6_04 based MCU default configuration + +if SOC_DIE_PSOC6_04 + +config NUM_IRQS + default 16 if CPU_CORTEX_M0PLUS + default 175 if CPU_CORTEX_M4 + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default 100000000 + +# add additional die specific params + +endif # SOC_DIE_PSOC6_04 diff --git a/soc/infineon/cat1a/psoc6_04/Kconfig.soc b/soc/infineon/cat1a/psoc6_04/Kconfig.soc new file mode 100644 index 00000000000..b70ed63313c --- /dev/null +++ b/soc/infineon/cat1a/psoc6_04/Kconfig.soc @@ -0,0 +1,275 @@ +# Copyright (c) 2023 Cypress Semiconductor Corporation (an Infineon company) or +# an affiliate of Cypress Semiconductor Corporation +# SPDX-License-Identifier: Apache-2.0 + +# SOC die +config SOC_DIE_PSOC6_04 + bool + +# SOC packages +config SOC_PACKAGE_PSOC6_04_64_TQFP + bool + +config SOC_PACKAGE_PSOC6_04_68_QFN + bool + +config SOC_PACKAGE_PSOC6_04_80_TQFP + bool + +config SOC_PACKAGE_PSOC6_04_80_M_CSP + bool + +# Infineon PSoC6_04 series MCUs +config SOC_CY8C6244AZI_S4D92 + bool + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_64_TQFP + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C6244LQI_S4D92 + bool + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_68_QFN + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C6244AZI_S4D93 + bool + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_80_TQFP + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C6244AZI_S4D82 + bool + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_64_TQFP + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C6244LQI_S4D82 + bool + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_68_QFN + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C6244AZI_S4D83 + bool + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_80_TQFP + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C6244AZI_S4D62 + bool + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_64_TQFP + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C6244LQI_S4D62 + bool + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_68_QFN + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C6244AZI_S4D12 + bool + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_64_TQFP + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C6244LQI_S4D12 + bool + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_68_QFN + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C6144AZI_S4F92 + bool + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_64_TQFP + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C6144LQI_S4F92 + bool + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_68_QFN + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C6144AZI_S4F93 + bool + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_80_TQFP + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C6144AZI_S4F82 + bool + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_64_TQFP + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C6144LQI_S4F82 + bool + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_68_QFN + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C6144AZI_S4F83 + bool + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_80_TQFP + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C6144AZI_S4F62 + bool + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_64_TQFP + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C6144LQI_S4F62 + bool + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_68_QFN + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C6144AZI_S4F12 + bool + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_64_TQFP + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C6144LQI_S4F12 + bool + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_68_QFN + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C6244AZQ_S4D92 + bool + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_64_TQFP + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C6244LQQ_S4D92 + bool + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_68_QFN + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C6244AZQ_S4D93 + bool + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_80_TQFP + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C6144AZQ_S4F92 + bool + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_64_TQFP + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C6144LQQ_S4F92 + bool + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_68_QFN + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C6144AZQ_S4F93 + bool + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_80_TQFP + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C6244FMI_S4D93 + bool + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_80_M_CSP + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C6244FMI_S4D73 + bool + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_80_M_CSP + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C6244FMI_S4D53 + bool + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_80_M_CSP + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C6244FMI_S4D03 + bool + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_80_M_CSP + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C6244FMQ_S4D93 + bool + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_80_M_CSP + select SOC_SERIES_PSOC6_62 + +config SOC_CY8C6144FMI_S4F93 + bool + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_80_M_CSP + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C6144FMI_S4F73 + bool + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_80_M_CSP + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C6144FMI_S4F53 + bool + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_80_M_CSP + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C6144FMI_S4F03 + bool + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_80_M_CSP + select SOC_SERIES_PSOC6_61 + +config SOC_CY8C6144FMQ_S4F93 + bool + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_80_M_CSP + select SOC_SERIES_PSOC6_61 + +config SOC + default "cy8c6244azi_s4d92" if SOC_CY8C6244AZI_S4D92 + default "cy8c6244lqi_s4d92" if SOC_CY8C6244LQI_S4D92 + default "cy8c6244azi_s4d93" if SOC_CY8C6244AZI_S4D93 + default "cy8c6244azi_s4d82" if SOC_CY8C6244AZI_S4D82 + default "cy8c6244lqi_s4d82" if SOC_CY8C6244LQI_S4D82 + default "cy8c6244azi_s4d83" if SOC_CY8C6244AZI_S4D83 + default "cy8c6244azi_s4d62" if SOC_CY8C6244AZI_S4D62 + default "cy8c6244lqi_s4d62" if SOC_CY8C6244LQI_S4D62 + default "cy8c6244azi_s4d12" if SOC_CY8C6244AZI_S4D12 + default "cy8c6244lqi_s4d12" if SOC_CY8C6244LQI_S4D12 + default "cy8c6144azi_s4f92" if SOC_CY8C6144AZI_S4F92 + default "cy8c6144lqi_s4f92" if SOC_CY8C6144LQI_S4F92 + default "cy8c6144azi_s4f93" if SOC_CY8C6144AZI_S4F93 + default "cy8c6144azi_s4f82" if SOC_CY8C6144AZI_S4F82 + default "cy8c6144lqi_s4f82" if SOC_CY8C6144LQI_S4F82 + default "cy8c6144azi_s4f83" if SOC_CY8C6144AZI_S4F83 + default "cy8c6144azi_s4f62" if SOC_CY8C6144AZI_S4F62 + default "cy8c6144lqi_s4f62" if SOC_CY8C6144LQI_S4F62 + default "cy8c6144azi_s4f12" if SOC_CY8C6144AZI_S4F12 + default "cy8c6144lqi_s4f12" if SOC_CY8C6144LQI_S4F12 + default "cy8c6244azq_s4d92" if SOC_CY8C6244AZQ_S4D92 + default "cy8c6244lqq_s4d92" if SOC_CY8C6244LQQ_S4D92 + default "cy8c6244azq_s4d93" if SOC_CY8C6244AZQ_S4D93 + default "cy8c6144azq_s4f92" if SOC_CY8C6144AZQ_S4F92 + default "cy8c6144lqq_s4f92" if SOC_CY8C6144LQQ_S4F92 + default "cy8c6144azq_s4f93" if SOC_CY8C6144AZQ_S4F93 + default "cy8c6244fmi_s4d93" if SOC_CY8C6244FMI_S4D93 + default "cy8c6244fmi_s4d73" if SOC_CY8C6244FMI_S4D73 + default "cy8c6244fmi_s4d53" if SOC_CY8C6244FMI_S4D53 + default "cy8c6244fmi_s4d03" if SOC_CY8C6244FMI_S4D03 + default "cy8c6244fmq_s4d93" if SOC_CY8C6244FMQ_S4D93 + default "cy8c6144fmi_s4f93" if SOC_CY8C6144FMI_S4F93 + default "cy8c6144fmi_s4f73" if SOC_CY8C6144FMI_S4F73 + default "cy8c6144fmi_s4f53" if SOC_CY8C6144FMI_S4F53 + default "cy8c6144fmi_s4f03" if SOC_CY8C6144FMI_S4F03 + default "cy8c6144fmq_s4f93" if SOC_CY8C6144FMQ_S4F93 diff --git a/soc/infineon/cat1a/psoc6_legacy/Kconfig.defconfig b/soc/infineon/cat1a/psoc6_legacy/Kconfig.defconfig new file mode 100644 index 00000000000..c6da791fa96 --- /dev/null +++ b/soc/infineon/cat1a/psoc6_legacy/Kconfig.defconfig @@ -0,0 +1,18 @@ +# Copyright (c) 2023 Cypress Semiconductor Corporation (an Infineon company) or +# an affiliate of Cypress Semiconductor Corporation +# SPDX-License-Identifier: Apache-2.0 + +# Infineon PSoC6 (Legacy) based MCU default configuration + +if SOC_FAMILY_PSOC6_LEGACY + +config NUM_IRQS + default 32 if CPU_CORTEX_M0PLUS + default 147 if CPU_CORTEX_M4 + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default 50000000 + +# add additional die specific params + +endif # SOC_FAMILY_PSOC6_LEGACY diff --git a/soc/infineon/cat1a/psoc6_legacy/Kconfig.soc b/soc/infineon/cat1a/psoc6_legacy/Kconfig.soc new file mode 100644 index 00000000000..7cb8f8acde9 --- /dev/null +++ b/soc/infineon/cat1a/psoc6_legacy/Kconfig.soc @@ -0,0 +1,42 @@ +# Copyright (c) 2023 Cypress Semiconductor Corporation (an Infineon company) or +# an affiliate of Cypress Semiconductor Corporation +# SPDX-License-Identifier: Apache-2.0 + +# Infineon PSoC6 (legacy) series MCUs +config SOC_CY8C6247_M0 + bool + select SOC_SERIES_PSOC6_62 + select SOC_FAMILY_PSOC6_LEGACY + select SOC_FAMILY_PSOC6_LEGACY_M0 + +config SOC_CY8C6247_M4 + bool + select SOC_SERIES_PSOC6_62 + select SOC_FAMILY_PSOC6_LEGACY + select SOC_FAMILY_PSOC6_LEGACY_M4 + +config SOC_CY8C6347_M0 + bool + select SOC_SERIES_PSOC6_63 + select SOC_FAMILY_PSOC6_LEGACY + select SOC_FAMILY_PSOC6_LEGACY_M0 + +config SOC_CY8C6347_M4 + bool + select SOC_SERIES_PSOC6_63 + select SOC_FAMILY_PSOC6_LEGACY + select SOC_FAMILY_PSOC6_LEGACY_M4 + +config SOC_PART_NUMBER_CY8C6247BZI_D54 + bool + +config SOC_PART_NUMBER_CY8C6347BZI_BLD53 + bool + +config SOC + default "cy8c6247" if SOC_CY8C6247_M0 || SOC_CY8C6247_M4 + default "cy8c6347" if SOC_CY8C6347_M0 || SOC_CY8C6347_M4 + +config SOC_PART_NUMBER + default "CY8C6247BZI_D54" if SOC_PART_NUMBER_CY8C6247BZI_D54 + default "CY8C6347BZI_BLD53" if SOC_PART_NUMBER_CY8C6347BZI_BLD53 diff --git a/soc/cypress/psoc6/old/common/cypress_psoc6_dt.h b/soc/infineon/cat1a/psoc6_legacy/cypress_psoc6_dt.h similarity index 100% rename from soc/cypress/psoc6/old/common/cypress_psoc6_dt.h rename to soc/infineon/cat1a/psoc6_legacy/cypress_psoc6_dt.h diff --git a/soc/cypress/psoc6/old/noinit.ld b/soc/infineon/cat1a/psoc6_legacy/noinit.ld similarity index 100% rename from soc/cypress/psoc6/old/noinit.ld rename to soc/infineon/cat1a/psoc6_legacy/noinit.ld diff --git a/soc/cypress/psoc6/old/rwdata.ld b/soc/infineon/cat1a/psoc6_legacy/rwdata.ld similarity index 100% rename from soc/cypress/psoc6/old/rwdata.ld rename to soc/infineon/cat1a/psoc6_legacy/rwdata.ld diff --git a/soc/cypress/psoc6/old/soc.c b/soc/infineon/cat1a/psoc6_legacy/soc.c similarity index 100% rename from soc/cypress/psoc6/old/soc.c rename to soc/infineon/cat1a/psoc6_legacy/soc.c diff --git a/soc/infineon/cat1a/psoc6_legacy/soc.h b/soc/infineon/cat1a/psoc6_legacy/soc.h new file mode 100644 index 00000000000..8bd23b04ec2 --- /dev/null +++ b/soc/infineon/cat1a/psoc6_legacy/soc.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2018, Cypress + * Copyright (c) 2020-2021, ATL Electronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Board configuration macros + * + * This header file is used to specify and describe board-level aspects + */ + +#ifndef _SOC__H_ +#define _SOC__H_ + +#include + +#ifndef _ASMLANGUAGE + +#include +#include "soc_gpio.h" +#include "cypress_psoc6_dt.h" + +#endif /* !_ASMLANGUAGE */ + +#endif /* _SOC__H_ */ diff --git a/soc/cypress/psoc6/old/common/soc_gpio.c b/soc/infineon/cat1a/psoc6_legacy/soc_gpio.c similarity index 100% rename from soc/cypress/psoc6/old/common/soc_gpio.c rename to soc/infineon/cat1a/psoc6_legacy/soc_gpio.c diff --git a/soc/cypress/psoc6/old/common/soc_gpio.h b/soc/infineon/cat1a/psoc6_legacy/soc_gpio.h similarity index 100% rename from soc/cypress/psoc6/old/common/soc_gpio.h rename to soc/infineon/cat1a/psoc6_legacy/soc_gpio.h diff --git a/soc/infineon/cat1a/soc.yml b/soc/infineon/cat1a/soc.yml new file mode 100644 index 00000000000..a7d58a4a992 --- /dev/null +++ b/soc/infineon/cat1a/soc.yml @@ -0,0 +1,125 @@ +family: +- name: cat1a + series: + - name: psoc6 + socs: + - name: cy8c6036bzi_f04 + - name: cy8c6016bzi_f04 + - name: cy8c6116bzi_f54 + - name: cy8c6136bzi_f14 + - name: cy8c6136bzi_f34 + - name: cy8c6137bzi_f14 + - name: cy8c6137bzi_f34 + - name: cy8c6137bzi_f54 + - name: cy8c6117bzi_f34 + - name: cy8c6246bzi_d04 + - name: cy8c6247bzi_d44 + - name: cy8c6247bzi_d34 + - name: cy8c6247bzi_d54 + - name: cy8c6336bzi_blf03 + - name: cy8c6316bzi_blf03 + - name: cy8c6316bzi_blf53 + - name: cy8c6336bzi_bld13 + - name: cy8c6347bzi_bld43 + - name: cy8c6347bzi_bld33 + - name: cy8c6347bzi_bld53 + - name: cy8c6347fmi_bld13 + - name: cy8c6347fmi_bld43 + - name: cy8c6347fmi_bld33 + - name: cy8c6347fmi_bld53 + - name: cy8c6137fdi_f02 + - name: cy8c6117fdi_f02 + - name: cy8c6247fdi_d02 + - name: cy8c6247fdi_d32 + - name: cy8c6336bzi_bud13 + - name: cy8c6347bzi_bud43 + - name: cy8c6347bzi_bud33 + - name: cy8c6347bzi_bud53 + - name: cy8c6337bzi_blf13 + - name: cy8c6136fdi_f42 + - name: cy8c6247fdi_d52 + - name: cy8c6136fti_f42 + - name: cy8c6247fti_d52 + - name: cy8c6247bzi_aud54 + - name: cy8c6336bzi_blf04 + - name: cy8c6316bzi_blf04 + - name: cy8c6316bzi_blf54 + - name: cy8c6336bzi_bld14 + - name: cy8c6347bzi_bld44 + - name: cy8c6347bzi_bld34 + - name: cy8c6347bzi_bld54 + - name: cy8c6247bfi_d54 + - name: cy8c6347fmi_bud53 + - name: cy8c6347fmi_bud13 + - name: cy8c6347fmi_bud43 + - name: cy8c6347fmi_bud33 + - name: cy8c6137wi_f54 + - name: cy8c6117wi_f34 + - name: cy8c6247wi_d54 + - name: cy8c6336lqi_blf02 + - name: cy8c6336lqi_blf42 + - name: cy8c6347lqi_bld52 + - name: cyb06447bzi_bld54 + - name: cyb06447bzi_bld53 + - name: cyb06447bzi_d54 + - name: cyb0644abzi_s2d44 + - name: cys0644abzi_s2d44 + - name: cy8c624abzi_s2d44a0 + - name: cy8c624abzi_s2d44 + - name: cy8c624aazi_s2d44 + - name: cy8c624afni_s2d43 + - name: cy8c624abzi_s2d04 + - name: cy8c624abzi_s2d14 + - name: cy8c624aazi_s2d14 + - name: cy8c6248azi_s2d14 + - name: cy8c6248bzi_s2d44 + - name: cy8c6248azi_s2d44 + - name: cy8c6248fni_s2d43 + - name: cy8c614abzi_s2f04 + - name: cy8c614aazi_s2f04 + - name: cy8c614afni_s2f03 + - name: cy8c614aazi_s2f14 + - name: cy8c614abzi_s2f44 + - name: cy8c614aazi_s2f44 + - name: cy8c614afni_s2f43 + - name: cy8c6148bzi_s2f44 + - name: cy8c6148azi_s2f44 + - name: cy8c6148fni_s2f43 + - name: cy8c624abzi_d44 + - name: cy8c624alqi_s2d42 + - name: cy8c624alqi_s2d02 + - name: cy8c6248lqi_s2d42 + - name: cy8c6248lqi_s2d02 + - name: cy8c614alqi_s2f42 + - name: cy8c614alqi_s2f02 + - name: cy8c6148lqi_s2f42 + - name: cy8c6148lqi_s2f02 + - name: cy8c6244azi_s4d92 + - name: cy8c6244lqi_s4d92 + - name: cy8c6244azi_s4d93 + - name: cy8c6244azi_s4d82 + - name: cy8c6244lqi_s4d82 + - name: cy8c6244azi_s4d83 + - name: cy8c6244azi_s4d62 + - name: cy8c6244lqi_s4d62 + - name: cy8c6244azi_s4d12 + - name: cy8c6244lqi_s4d12 + - name: cy8c6144azi_s4f92 + - name: cy8c6144lqi_s4f92 + - name: cy8c6144azi_s4f93 + - name: cy8c6144azi_s4f82 + - name: cy8c6144lqi_s4f82 + - name: cy8c6144azi_s4f83 + - name: cy8c6144azi_s4f62 + - name: cy8c6144lqi_s4f62 + - name: cy8c6144azi_s4f12 + - name: cy8c6144lqi_s4f12 + - name: cyble_416045_02 + - name: cy8c6247 + cpuclusters: + - name: m0 + - name: m4 + - name: cy8c6347 + cpuclusters: + - name: m0 + - name: m4 diff --git a/soc/infineon/cat3/CMakeLists.txt b/soc/infineon/cat3/CMakeLists.txt new file mode 100644 index 00000000000..6c98bdb9880 --- /dev/null +++ b/soc/infineon/cat3/CMakeLists.txt @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright (c) 2020 Linumiz +# Author: Parthiban Nallathambi + +add_subdirectory(${SOC_SERIES}) + +zephyr_compile_definitions($_${CONFIG_SOC_PART_NUMBER}) diff --git a/soc/infineon/xmc/Kconfig b/soc/infineon/cat3/Kconfig similarity index 100% rename from soc/infineon/xmc/Kconfig rename to soc/infineon/cat3/Kconfig diff --git a/soc/infineon/xmc/Kconfig.defconfig b/soc/infineon/cat3/Kconfig.defconfig similarity index 100% rename from soc/infineon/xmc/Kconfig.defconfig rename to soc/infineon/cat3/Kconfig.defconfig diff --git a/soc/infineon/xmc/Kconfig.soc b/soc/infineon/cat3/Kconfig.soc similarity index 100% rename from soc/infineon/xmc/Kconfig.soc rename to soc/infineon/cat3/Kconfig.soc diff --git a/soc/infineon/xmc/soc.yml b/soc/infineon/cat3/soc.yml similarity index 100% rename from soc/infineon/xmc/soc.yml rename to soc/infineon/cat3/soc.yml diff --git a/soc/infineon/xmc/xmc4xxx/CMakeLists.txt b/soc/infineon/cat3/xmc4xxx/CMakeLists.txt similarity index 100% rename from soc/infineon/xmc/xmc4xxx/CMakeLists.txt rename to soc/infineon/cat3/xmc4xxx/CMakeLists.txt diff --git a/soc/infineon/xmc/xmc4xxx/Kconfig b/soc/infineon/cat3/xmc4xxx/Kconfig similarity index 100% rename from soc/infineon/xmc/xmc4xxx/Kconfig rename to soc/infineon/cat3/xmc4xxx/Kconfig diff --git a/soc/infineon/xmc/xmc4xxx/Kconfig.defconfig b/soc/infineon/cat3/xmc4xxx/Kconfig.defconfig similarity index 100% rename from soc/infineon/xmc/xmc4xxx/Kconfig.defconfig rename to soc/infineon/cat3/xmc4xxx/Kconfig.defconfig diff --git a/soc/infineon/xmc/xmc4xxx/Kconfig.defconfig.xmc4500 b/soc/infineon/cat3/xmc4xxx/Kconfig.defconfig.xmc4500 similarity index 100% rename from soc/infineon/xmc/xmc4xxx/Kconfig.defconfig.xmc4500 rename to soc/infineon/cat3/xmc4xxx/Kconfig.defconfig.xmc4500 diff --git a/soc/infineon/xmc/xmc4xxx/Kconfig.defconfig.xmc4700 b/soc/infineon/cat3/xmc4xxx/Kconfig.defconfig.xmc4700 similarity index 100% rename from soc/infineon/xmc/xmc4xxx/Kconfig.defconfig.xmc4700 rename to soc/infineon/cat3/xmc4xxx/Kconfig.defconfig.xmc4700 diff --git a/soc/infineon/xmc/xmc4xxx/Kconfig.soc b/soc/infineon/cat3/xmc4xxx/Kconfig.soc similarity index 100% rename from soc/infineon/xmc/xmc4xxx/Kconfig.soc rename to soc/infineon/cat3/xmc4xxx/Kconfig.soc diff --git a/soc/infineon/xmc/xmc4xxx/noinit.ld b/soc/infineon/cat3/xmc4xxx/noinit.ld similarity index 100% rename from soc/infineon/xmc/xmc4xxx/noinit.ld rename to soc/infineon/cat3/xmc4xxx/noinit.ld diff --git a/soc/infineon/xmc/xmc4xxx/pinctrl_soc.h b/soc/infineon/cat3/xmc4xxx/pinctrl_soc.h similarity index 100% rename from soc/infineon/xmc/xmc4xxx/pinctrl_soc.h rename to soc/infineon/cat3/xmc4xxx/pinctrl_soc.h diff --git a/soc/infineon/xmc/xmc4xxx/soc.c b/soc/infineon/cat3/xmc4xxx/soc.c similarity index 100% rename from soc/infineon/xmc/xmc4xxx/soc.c rename to soc/infineon/cat3/xmc4xxx/soc.c diff --git a/soc/infineon/xmc/xmc4xxx/soc.h b/soc/infineon/cat3/xmc4xxx/soc.h similarity index 100% rename from soc/infineon/xmc/xmc4xxx/soc.h rename to soc/infineon/cat3/xmc4xxx/soc.h diff --git a/soc/infineon/xmc/CMakeLists.txt b/soc/infineon/xmc/CMakeLists.txt deleted file mode 100644 index 9aed50a0fd8..00000000000 --- a/soc/infineon/xmc/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 -# -# Copyright (c) 2020 Linumiz -# Author: Parthiban Nallathambi - -add_subdirectory(${SOC_SERIES}) diff --git a/soc/intel/alder_lake/CMakeLists.txt b/soc/intel/alder_lake/CMakeLists.txt index 7db5fbabfc0..918ee2f3e91 100644 --- a/soc/intel/alder_lake/CMakeLists.txt +++ b/soc/intel/alder_lake/CMakeLists.txt @@ -8,5 +8,6 @@ zephyr_library_include_directories(${ZEPHYR_BASE}/drivers) zephyr_cc_option(-march=goldmont) zephyr_library_sources(cpu.c) +zephyr_library_sources(../common/soc_gpio.c) set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld CACHE INTERNAL "") diff --git a/soc/intel/alder_lake/soc.h b/soc/intel/alder_lake/soc.h index e1c6a04e834..b725bd44a25 100644 --- a/soc/intel/alder_lake/soc.h +++ b/soc/intel/alder_lake/soc.h @@ -23,6 +23,10 @@ #include #endif +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(acpi_hid) +#include "../common/soc_gpio.h" +#endif + #ifdef CONFIG_GPIO_INTEL #include "soc_gpio.h" #endif diff --git a/soc/intel/common/soc_gpio.c b/soc/intel/common/soc_gpio.c new file mode 100644 index 00000000000..26954156ccc --- /dev/null +++ b/soc/intel/common/soc_gpio.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2023 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "soc.h" +#include "soc_gpio.h" + +#define GET_GPIO_BASE_NUM ("\\_SB.GINF") + +static int gpio_info_acpi_get(uint32_t bank_idx, uint32_t field_idx, uint32_t *ret_val) +{ + int status; + ACPI_OBJECT args[2]; + ACPI_OBJECT_LIST arg_list; + ACPI_OBJECT gpio_obj; + + arg_list.Count = ARRAY_SIZE(args); + arg_list.Pointer = args; + + args[0].Type = ACPI_TYPE_INTEGER; + args[0].Integer.Value = bank_idx; + + args[1].Type = ACPI_TYPE_INTEGER; + args[1].Integer.Value = field_idx; + + status = acpi_invoke_method(GET_GPIO_BASE_NUM, &arg_list, &gpio_obj); + if (status) { + return status; + } + + if (gpio_obj.Type == ACPI_TYPE_INTEGER) { + *ret_val = gpio_obj.Integer.Value; + } + + return status; +} + +int soc_acpi_gpio_resource_get(int bank_idx, char *hid, char *uid, struct gpio_acpi_res *res) +{ + int ret; + struct acpi_dev *acpi_child; + struct acpi_irq_resource irq_res; + struct acpi_mmio_resource mmio_res; + uint32_t field_val[7]; + uint16_t irqs[CONFIG_ACPI_IRQ_VECTOR_MAX]; + struct acpi_reg_base reg_base[CONFIG_ACPI_MMIO_ENTRIES_MAX]; + + acpi_child = acpi_device_get(hid, uid); + if (!acpi_child) { + printk("acpi_device_get failed\n"); + return -EIO; + } + + mmio_res.mmio_max = ARRAY_SIZE(reg_base); + mmio_res.reg_base = reg_base; + ret = acpi_device_mmio_get(acpi_child, &mmio_res); + if (ret) { + printk("acpi_device_mmio_get failed\n"); + return ret; + } + + irq_res.irq_vector_max = ARRAY_SIZE(irqs); + irq_res.irqs = irqs; + ret = acpi_device_irq_get(acpi_child, &irq_res); + if (ret) { + printk("acpi_device_irq_get failed\n"); + return ret; + } + + res->irq = irq_res.irqs[0]; + res->irq_flags = irq_res.flags; + + if (ACPI_RESOURCE_TYPE_GET(&mmio_res) == ACPI_RES_TYPE_MEM) { + for (int i = 0; i < ARRAY_SIZE(field_val); i++) { + ret = gpio_info_acpi_get(bank_idx, i, &field_val[i]); + if (ret) { + printk("gpio_info_acpi_get failed\n"); + return ret; + } + } + + res->reg_base = ACPI_MMIO_GET(&mmio_res) & (~0x0FFFFFF); + res->reg_base += field_val[0]; + res->len = ACPI_RESOURCE_SIZE_GET(&mmio_res); + res->num_pins = field_val[1]; + res->pad_base = field_val[2]; + res->host_owner_reg = field_val[3]; + res->pad_owner_reg = field_val[4]; + res->intr_stat_reg = field_val[5] - 0x40; + res->base_num = field_val[6]; + } else { + printk("ACPI_RES_TYPE_MEM failed\n"); + return -ENODEV; + } + + return 0; +} diff --git a/soc/intel/common/soc_gpio.h b/soc/intel/common/soc_gpio.h new file mode 100644 index 00000000000..f7c28963abb --- /dev/null +++ b/soc/intel/common/soc_gpio.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2023 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +struct gpio_acpi_res { + uintptr_t reg_base; + uint32_t len; + uint32_t pad_base; + uint8_t num_pins; + uint32_t host_owner_reg; + uint32_t pad_owner_reg; + uint32_t intr_stat_reg; + uint16_t base_num; + uint16_t irq; + uint32_t irq_flags; +}; + +/** + * @brief Retrieve current resource settings of a gpio device from acpi. + * + * @param bank_idx band index of the gpio group (eg: gpp_a, gpp_b etc.) + * @param hid the hardware id of the acpi device + * @param uid the unique id of the acpi device + * @param res the pointer to resource struct on which data return + * @return return 0 on success or error code + */ +int soc_acpi_gpio_resource_get(int bank_idx, char *hid, char *uid, struct gpio_acpi_res *res); diff --git a/soc/intel/intel_adsp/ace/Kconfig b/soc/intel/intel_adsp/ace/Kconfig index 17de11a36ff..ff86472466e 100644 --- a/soc/intel/intel_adsp/ace/Kconfig +++ b/soc/intel/intel_adsp/ace/Kconfig @@ -8,6 +8,7 @@ config SOC_SERIES_INTEL_ADSP_ACE select ATOMIC_OPERATIONS_BUILTIN if "$(ZEPHYR_TOOLCHAIN_VARIANT)" != "xcc" select ARCH_HAS_COHERENCE select SCHED_IPI_SUPPORTED + select ARCH_CPU_IDLE_CUSTOM select DW_ICTL_ACE select SOC_HAS_RUNTIME_NUM_CPUS select HAS_PM diff --git a/soc/intel/intel_adsp/ace/Kconfig.defconfig.series b/soc/intel/intel_adsp/ace/Kconfig.defconfig.series index b9a548d77c1..a860d744226 100644 --- a/soc/intel/intel_adsp/ace/Kconfig.defconfig.series +++ b/soc/intel/intel_adsp/ace/Kconfig.defconfig.series @@ -74,6 +74,13 @@ config XTENSA_NUM_SPIN_RELAX_NOPS endif # XTENSA_MORE_SPIN_RELAX_NOPS +if KERNEL_VM_SUPPORT + +config KERNEL_VM_SIZE + default 0xfe0000 + +endif + rsource "Kconfig.defconfig.ace*" endif # SOC_SERIES_INTEL_ADSP_ACE diff --git a/soc/intel/intel_adsp/ace/include/ace15_mtpm/adsp_memory.h b/soc/intel/intel_adsp/ace/include/ace15_mtpm/adsp_memory.h index 56e78cdca5f..e0a7175aad0 100644 --- a/soc/intel/intel_adsp/ace/include/ace15_mtpm/adsp_memory.h +++ b/soc/intel/intel_adsp/ace/include/ace15_mtpm/adsp_memory.h @@ -161,17 +161,17 @@ struct ace_lpsram_regs { #endif /* These registers are for the L2 HP SRAM bank power management control and status.*/ -#define L2HSBPM_REG 0x17A800 -#define L2HSBPM_REG_SIZE 0x0008 +#define L2_HSBPM_BASE (DT_REG_ADDR(DT_NODELABEL(hsbpm))) +#define L2_HSBPM_SIZE (DT_REG_SIZE(DT_NODELABEL(hsbpm))) #define HPSRAM_REGS(block_idx) ((volatile struct ace_hpsram_regs *const) \ - (L2HSBPM_REG + L2HSBPM_REG_SIZE * (block_idx))) + (L2_HSBPM_BASE + L2_HSBPM_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 L2_LSBPM_BASE (DT_REG_ADDR(DT_NODELABEL(lsbpm))) +#define L2_LSBPM_SIZE (DT_REG_SIZE(DT_NODELABEL(lsbpm))) #define LPSRAM_REGS(block_idx) ((volatile struct ace_lpsram_regs *const) \ - (L2LSBPM_REG + L2LSBPM_REG_SIZE * (block_idx))) + (L2_LSBPM_BASE + L2_LSBPM_SIZE * (block_idx))) #endif /* ZEPHYR_SOC_INTEL_ADSP_MEMORY_H_ */ diff --git a/soc/intel/intel_adsp/ace/include/ace20_lnl/adsp_memory.h b/soc/intel/intel_adsp/ace/include/ace20_lnl/adsp_memory.h index a45a8ae590d..d8d23f2cefc 100644 --- a/soc/intel/intel_adsp/ace/include/ace20_lnl/adsp_memory.h +++ b/soc/intel/intel_adsp/ace/include/ace20_lnl/adsp_memory.h @@ -159,17 +159,17 @@ struct ace_lpsram_regs { #endif /* These registers are for the L2 HP SRAM bank power management control and status.*/ -#define L2HSBPM_REG 0x17A800 -#define L2HSBPM_REG_SIZE 0x0008 +#define L2_HSBPM_BASE (DT_REG_ADDR(DT_NODELABEL(hsbpm))) +#define L2_HSBPM_SIZE (DT_REG_SIZE(DT_NODELABEL(hsbpm))) #define HPSRAM_REGS(block_idx) ((volatile struct ace_hpsram_regs *const) \ - (L2HSBPM_REG + L2HSBPM_REG_SIZE * (block_idx))) + (L2_HSBPM_BASE + L2_HSBPM_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 L2_LSBPM_BASE (DT_REG_ADDR(DT_NODELABEL(lsbpm))) +#define L2_LSBPM_SIZE (DT_REG_SIZE(DT_NODELABEL(lsbpm))) #define LPSRAM_REGS(block_idx) ((volatile struct ace_lpsram_regs *const) \ - (L2LSBPM_REG + L2LSBPM_REG_SIZE * (block_idx))) + (L2_LSBPM_BASE + L2_LSBPM_SIZE * (block_idx))) #endif /* ZEPHYR_SOC_INTEL_ADSP_MEMORY_H_ */ diff --git a/soc/intel/intel_adsp/ace/power.c b/soc/intel/intel_adsp/ace/power.c index ef11a66c6ea..2e260eb2f9c 100644 --- a/soc/intel/intel_adsp/ace/power.c +++ b/soc/intel/intel_adsp/ace/power.c @@ -437,3 +437,25 @@ void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) } #endif /* CONFIG_PM */ + +#ifdef CONFIG_ARCH_CPU_IDLE_CUSTOM + +__no_optimization +void arch_cpu_idle(void) +{ + uint32_t cpu = arch_proc_id(); + + sys_trace_idle(); + + /* + * unlock and invalidate icache if clock gating is allowed + */ + if (!(DSPCS.bootctl[cpu].bctl & DSPBR_BCTL_WAITIPCG)) { + xthal_icache_all_unlock(); + xthal_icache_all_invalidate(); + } + + __asm__ volatile ("waiti 0"); +} + +#endif /* CONFIG_ARCH_CPU_IDLE_CUSTOM */ diff --git a/soc/intel/intel_adsp/cavs/Kconfig.defconfig.cavs_v25 b/soc/intel/intel_adsp/cavs/Kconfig.defconfig.cavs_v25 index ad6fa8baac6..d0e7662195e 100644 --- a/soc/intel/intel_adsp/cavs/Kconfig.defconfig.cavs_v25 +++ b/soc/intel/intel_adsp/cavs/Kconfig.defconfig.cavs_v25 @@ -46,7 +46,7 @@ config CAVS_ISR_TBL_OFFSET if KERNEL_VM_SUPPORT config KERNEL_VM_SIZE - default 0x800000 + default 0xfe0000 endif diff --git a/soc/intel/intel_adsp/cavs/include/cavs25/adsp_memory.h b/soc/intel/intel_adsp/cavs/include/cavs25/adsp_memory.h index ed10a5d1367..231c254e7c8 100644 --- a/soc/intel/intel_adsp/cavs/include/cavs25/adsp_memory.h +++ b/soc/intel/intel_adsp/cavs/include/cavs25/adsp_memory.h @@ -65,5 +65,40 @@ /* The number of set associative cache way supported on L1 Instruction Cache */ #define ADSP_CxL1CCAP_ICMWC ((ADSP_CxL1CCAP_REG >> 20) & 7) +#ifndef _ASMLANGUAGE +/* L2 Local Memory Management */ + +struct cavs_hpsram_regs { + /** @brief power gating control */ + uint32_t HSxPGCTL; + /** @brief retention mode control */ + uint32_t HSxRMCTL; + /** @brief power gating status */ + uint32_t HSxPGISTS; +}; + +struct cavs_lpsram_regs { + /** @brief power gating control */ + uint32_t USxPGCTL; + /** @brief retention mode control */ + uint32_t USxRMCTL; + /** @brief power gating status */ + uint32_t USxPGISTS; +}; +#endif /* _ASMLANGUAGE */ + +/* These registers are for the L2 HP SRAM bank power management control and status.*/ +#define L2_HSBPM_BASE (DT_REG_ADDR(DT_NODELABEL(hsbpm))) +#define L2_HSBPM_SIZE (DT_REG_SIZE(DT_NODELABEL(hsbpm))) + +#define HPSRAM_REGS(block_idx) ((volatile struct cavs_hpsram_regs *const) \ + (L2_HSBPM_BASE + L2_HSBPM_SIZE * (block_idx))) + +/* These registers are for the L2 LP SRAM bank power management control and status.*/ +#define L2_LSBPM_BASE (DT_REG_ADDR(DT_NODELABEL(lsbpm))) +#define L2_LSBPM_SIZE (DT_REG_SIZE(DT_NODELABEL(lsbpm))) + +#define LPSRAM_REGS(block_idx) ((volatile struct cavs_lpsram_regs *const) \ + (L2_LSBPM_BASE + L2_LSBPM_SIZE * (block_idx))) #endif /* ZEPHYR_SOC_INTEL_ADSP_MEMORY_H_ */ diff --git a/soc/intel/intel_adsp/common/ipc.c b/soc/intel/intel_adsp/common/ipc.c index a33c03ebfde..04503ca35e8 100644 --- a/soc/intel/intel_adsp/common/ipc.c +++ b/soc/intel/intel_adsp/common/ipc.c @@ -100,6 +100,8 @@ int intel_adsp_ipc_init(const struct device *dev) memset(devdata, 0, sizeof(*devdata)); + k_sem_init(&devdata->sem, 0, 1); + /* ACK any latched interrupts (including TDA to clear IDA on * the other side!), then enable. */ diff --git a/soc/intel/intel_adsp/tools/acetool.py b/soc/intel/intel_adsp/tools/acetool.py index 9dd184b9685..5424e2a68ae 100755 --- a/soc/intel/intel_adsp/tools/acetool.py +++ b/soc/intel/intel_adsp/tools/acetool.py @@ -2,728 +2,11 @@ # 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 - -# pylint: disable=duplicate-code - -# 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) +import cavstool if __name__ == "__main__": try: - asyncio.get_event_loop().run_until_complete(main()) + asyncio.run(cavstool.main()) except KeyboardInterrupt: start_output = False diff --git a/soc/intel/intel_adsp/tools/cavstool.py b/soc/intel/intel_adsp/tools/cavstool.py index 97ce9134379..3b82d5bf336 100755 --- a/soc/intel/intel_adsp/tools/cavstool.py +++ b/soc/intel/intel_adsp/tools/cavstool.py @@ -21,15 +21,18 @@ HUGEPAGESZ = 2 * 1024 * 1024 HUGEPAGE_FILE = "/dev/hugepages/cavs-fw-dma.tmp." -# SRAM windows. Each appears in a 128k region starting at 512k. +# SRAM windows. Base and stride varies depending on ADSP version # # 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 2 is debug, divided into multiple slots, unused by this script # Window 3 is winstream-formatted log output -OUTBOX_OFFSET = (512 + (0 * 128)) * 1024 + 4096 -INBOX_OFFSET = (512 + (1 * 128)) * 1024 -WINSTREAM_OFFSET = (512 + (3 * 128)) * 1024 + +WINDOW_BASE = 0x80000 +WINDOW_STRIDE = 0x20000 + +WINDOW_BASE_ACE = 0x180000 +WINDOW_STRIDE_ACE = 0x8000 # pylint: disable=duplicate-code @@ -188,17 +191,34 @@ def reset(self): self.debug() log.info(f"Reset stream {self.stream_id}") +def adsp_is_cavs(): + return cavs15 or cavs18 or cavs15 + +def adsp_is_ace(): + return ace15 or ace20 + +def adsp_mem_window_config(): + if adsp_is_ace(): + base = WINDOW_BASE_ACE + stride = WINDOW_STRIDE_ACE + else: + base = WINDOW_BASE + stride = WINDOW_STRIDE + + return (base, stride) 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 - global cavs15, cavs18, cavs25 + global cavs15, cavs18, cavs25, ace15, ace20 did = int(open(f"{pcidir}/device").read().rstrip(), 16) cavs15 = did in [ 0x5a98, 0x1a98, 0x3198 ] cavs18 = did in [ 0x9dc8, 0xa348, 0x02c8, 0x06c8, 0xa3f0 ] cavs25 = did in [ 0xa0c8, 0x43c8, 0x4b55, 0x4b58, 0x7ad0, 0x51c8 ] + ace15 = did in [ 0x7e28 ] + ace20 = did in [ 0xa828 ] # Check sysfs for a loaded driver and remove it if os.path.exists(f"{pcidir}/driver"): @@ -249,14 +269,28 @@ def map_regs(): global bar4_mmap (bar4_mem, bar4_mmap) = bar_map(pcidir, 4) dsp = Regs(bar4_mem) - dsp.ADSPCS = 0x00004 - dsp.HIPCTDR = 0x00040 if cavs15 else 0x000c0 - dsp.HIPCTDA = 0x000c4 # 1.8+ only - dsp.HIPCTDD = 0x00044 if cavs15 else 0x000c8 - dsp.HIPCIDR = 0x00048 if cavs15 else 0x000d0 - dsp.HIPCIDA = 0x000d4 # 1.8+ only - dsp.HIPCIDD = 0x0004c if cavs15 else 0x000d8 - dsp.SRAM_FW_STATUS = 0x80000 # Start of first SRAM window + if adsp_is_ace(): + 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_ACE + else: + dsp.ADSPCS = 0x00004 + dsp.HIPCTDR = 0x00040 if cavs15 else 0x000c0 + dsp.HIPCTDA = 0x000c4 # 1.8+ only + dsp.HIPCTDD = 0x00044 if cavs15 else 0x000c8 + dsp.HIPCIDR = 0x00048 if cavs15 else 0x000d0 + dsp.HIPCIDA = 0x000d4 # 1.8+ only + dsp.HIPCIDD = 0x0004c if cavs15 else 0x000d8 + dsp.SRAM_FW_STATUS = WINDOW_BASE # Start of first SRAM window dsp.freeze() return (hda, sd, dsp, hda_ostream_id) @@ -461,6 +495,128 @@ def load_firmware(fw_file): sd.CTL |= 1 log.info(f"cAVS firmware load complete") +def load_firmware_ace(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"ACE firmware load complete") + def fw_is_alive(): return dsp.SRAM_FW_STATUS & ((1 << 28) - 1) == 5 # "FW_ENTERED" @@ -485,17 +641,20 @@ def wait_fw_entered(timeout_s=2): else: log.info("FW alive, FW_STATUS = 0x%x", dsp.SRAM_FW_STATUS) +def winstream_offset(): + ( base, stride ) = adsp_mem_window_config() + return base + stride * 3 # 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') + 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("IndexError in bar4_mmap[%d + %d]", winstream_offset(), start) log.error("bar4_mmap.size()=%d", bar4_mmap.size()) raise ie @@ -528,7 +687,18 @@ def winstream_read(last_seq): async def ipc_delay_done(): await asyncio.sleep(0.1) - dsp.HIPCTDA = 1<<31 + if adsp_is_ace(): + dsp.HFIPCXTDA = ~(1<<31) & dsp.HFIPCXTDA # Signal done + else: + dsp.HIPCTDA = 1<<31 + +def inbox_offset(): + ( base, stride ) = adsp_mem_window_config() + return base + stride + +def outbox_offset(): + ( base, _ ) = adsp_mem_window_config() + return base + 4096 ipc_timestamp = 0 @@ -554,8 +724,8 @@ def ipc_command(data, ext_data): 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) + 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) @@ -634,15 +804,37 @@ def ipc_command(data, ext_data): return - dsp.HIPCTDR = 1<<31 # Ack local interrupt, also signals DONE on v1.5 - if cavs18: - time.sleep(0.01) # Needed on 1.8, or the command below won't send! - - if done and not cavs15: - dsp.HIPCTDA = 1<<31 # Signal done - if send_msg: - dsp.HIPCIDD = ext_data - dsp.HIPCIDR = (1<<31) | ext_data + if adsp_is_ace(): + 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 + else: + dsp.HIPCTDR = 1<<31 # Ack local interrupt, also signals DONE on v1.5 + if cavs18: + time.sleep(0.01) # Needed on 1.8, or the command below won't send! + if done and not cavs15: + dsp.HIPCTDA = 1<<31 # Signal done + if send_msg: + dsp.HIPCIDD = ext_data + dsp.HIPCIDR = (1<<31) | ext_data + +def handle_ipc(): + if adsp_is_ace(): + 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) + return + + if dsp.HIPCIDA & 0x80000000: + dsp.HIPCIDA = 1<<31 # must ACK any DONE interrupts that arrive! + if dsp.HIPCTDR & 0x80000000: + ipc_command(dsp.HIPCTDR & ~0x80000000, dsp.HIPCTDD) async def main(): #TODO this bit me, remove the globals, write a little FirmwareLoader class or something to contain. @@ -664,8 +856,12 @@ async def main(): log.error("Firmware file argument missing") sys.exit(1) - load_firmware(args.fw_file) + if adsp_is_ace(): + load_firmware_ace(args.fw_file) + else: + load_firmware(args.fw_file) time.sleep(0.1) + if not args.quiet: sys.stdout.write("--\n") @@ -679,10 +875,7 @@ async def main(): sys.stdout.write(output) sys.stdout.flush() if not args.log_only: - if dsp.HIPCIDA & 0x80000000: - dsp.HIPCIDA = 1<<31 # must ACK any DONE interrupts that arrive! - if dsp.HIPCTDR & 0x80000000: - ipc_command(dsp.HIPCTDR & ~0x80000000, dsp.HIPCTDD) + handle_ipc() ap = argparse.ArgumentParser(description="DSP loader/logger tool", allow_abbrev=False) diff --git a/soc/intel/intel_socfpga_std/cyclonev/soc.c b/soc/intel/intel_socfpga_std/cyclonev/soc.c index 73f7617d792..3adcfbab33a 100644 --- a/soc/intel/intel_socfpga_std/cyclonev/soc.c +++ b/soc/intel/intel_socfpga_std/cyclonev/soc.c @@ -31,7 +31,7 @@ void arch_reserved_pages_update(void) } struct z_page_frame *pf = z_phys_to_page_frame(pos); - pf->flags |= Z_PAGE_FRAME_RESERVED; + z_page_frame_set(pf, Z_PAGE_FRAME_RESERVED); } } diff --git a/soc/intel/raptor_lake/CMakeLists.txt b/soc/intel/raptor_lake/CMakeLists.txt index b3d7da79222..ff999b93f68 100644 --- a/soc/intel/raptor_lake/CMakeLists.txt +++ b/soc/intel/raptor_lake/CMakeLists.txt @@ -3,5 +3,6 @@ zephyr_include_directories(.) zephyr_cc_option(-march=goldmont) +zephyr_library_sources(../common/soc_gpio.c) set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld CACHE INTERNAL "") diff --git a/soc/intel/raptor_lake/soc.h b/soc/intel/raptor_lake/soc.h index bb4adb62fa0..af5220f891d 100644 --- a/soc/intel/raptor_lake/soc.h +++ b/soc/intel/raptor_lake/soc.h @@ -21,6 +21,10 @@ #include #endif +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(acpi_hid) +#include "../common/soc_gpio.h" +#endif + #ifdef CONFIG_GPIO_INTEL #include "soc_gpio.h" #endif diff --git a/soc/ite/ec/common/chip_chipregs.h b/soc/ite/ec/common/chip_chipregs.h index b42ceb0fd89..c585271542e 100644 --- a/soc/ite/ec/common/chip_chipregs.h +++ b/soc/ite/ec/common/chip_chipregs.h @@ -55,10 +55,6 @@ #define IT8XXX2_GCTRL_JTAGSEL BIT(0) #define IT8XXX2_GCTRL_JTAG (IT8XXX2_GCTRL_JTAGEN | IT8XXX2_GCTRL_JTAGSEL) -/* --- External GPIO Control (EGPIO) --- */ -#define IT8XXX2_EGPIO_BASE 0x00F02100 -#define IT8XXX2_EGPIO_EGCR ECREG(IT8XXX2_EGPIO_BASE + 0x04) - #ifdef CONFIG_SOC_IT8XXX2_REG_SET_V2 #define IT8XXX2_JTAG_PINS_BASE ECREG(0xF01660) #define IT8XXX2_JTAG_VOLT_SET ECREG(0xF01648) @@ -67,18 +63,25 @@ #define IT8XXX2_JTAG_VOLT_SET ECREG(0xF016e9) #endif +#ifdef CONFIG_SOC_IT8XXX2_REG_SET_V2 +/* --- 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) +#endif /** * * (11xxh) Interrupt controller (INTC) * */ +#ifdef CONFIG_SOC_IT8XXX2_REG_SET_V1 #define ISR0 ECREG(EC_REG_BASE_ADDR + 0x3F00) #define ISR1 ECREG(EC_REG_BASE_ADDR + 0x3F01) #define ISR2 ECREG(EC_REG_BASE_ADDR + 0x3F02) @@ -178,7 +181,7 @@ #define IPOLR21 ECREG(EC_REG_BASE_ADDR + 0x3F5B) #define IPOLR22 ECREG(EC_REG_BASE_ADDR + 0x3F5F) #define IPOLR23 ECREG(EC_REG_BASE_ADDR + 0x3F93) - +#endif #define IVECT ECREG(EC_REG_BASE_ADDR + 0x3F10) @@ -187,10 +190,17 @@ * to fix in tcpm\it83xx_pd.h. */ /* GPIO control register */ +#ifdef CONFIG_SOC_IT8XXX2_REG_SET_V1 #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) +#elif CONFIG_SOC_IT8XXX2_REG_SET_V2 +#define GPCRF4 ECREG(EC_REG_BASE_ADDR + 0x168C) +#define GPCRF5 ECREG(EC_REG_BASE_ADDR + 0x168D) +#define GPCRH1 ECREG(EC_REG_BASE_ADDR + 0x1699) +#define GPCRH2 ECREG(EC_REG_BASE_ADDR + 0x169A) +#endif /* * IT8XXX2 register structure size/offset checking macro function to mitigate @@ -268,6 +278,7 @@ struct pwm_it8xxx2_regs { /* --- Wake-Up Control (WUC) --- */ +#ifdef CONFIG_SOC_IT8XXX2_REG_SET_V1 #define IT8XXX2_WUC_BASE 0x00F01B00 /* TODO: should a defined interface for configuring wake-up interrupts */ @@ -277,6 +288,7 @@ struct pwm_it8xxx2_regs { #define IT8XXX2_WUC_WUESR5 (IT8XXX2_WUC_BASE + 0x0d) #define IT8XXX2_WUC_WUBEMR1 (IT8XXX2_WUC_BASE + 0x3c) #define IT8XXX2_WUC_WUBEMR5 (IT8XXX2_WUC_BASE + 0x0f) +#endif /** * @@ -1117,8 +1129,8 @@ struct gpio_it8xxx2_regs { GPCR_PORT_PIN_MODE_PULLDOWN) /* --- GPIO --- */ +#ifdef CONFIG_SOC_IT8XXX2_REG_SET_V1 #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 @@ -1136,11 +1148,14 @@ struct gpio_it8xxx2_regs { #define IT8XXX2_GPIO_GCR24_OFFSET 0xe9 #define IT8XXX2_GPIO_GCR30_OFFSET 0xed #define IT8XXX2_GPIO_GCR29_OFFSET 0xee +#endif /* * TODO: use pinctrl node instead of following register declarations * to fix in tcpm\it83xx_pd.h. */ +#define IT8XXX2_GPIO2_BASE 0x00F03E00 + #define IT8XXX2_GPIO_GPCRP0 ECREG(IT8XXX2_GPIO2_BASE + 0x18) #define IT8XXX2_GPIO_GPCRP1 ECREG(IT8XXX2_GPIO2_BASE + 0x19) @@ -1494,11 +1509,7 @@ enum chip_pll_mode { #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) @@ -1622,6 +1633,8 @@ struct gctrl_it8xxx2_regs { /* 0x06: Reset Status */ #define IT8XXX2_GCTRL_LRS (BIT(1) | BIT(0)) #define IT8XXX2_GCTRL_IWDTR BIT(1) +/* 0x0B: Wait Next 65K Rising */ +#define IT8XXX2_GCTRL_WN65K 0x00 /* 0x10: Reset Control DMM */ #define IT8XXX2_GCTRL_UART1SD BIT(3) #define IT8XXX2_GCTRL_UART2SD BIT(2) @@ -1641,12 +1654,15 @@ struct gctrl_it8xxx2_regs { #define IT8XXX2_GCTRL_EPLR_ENABLE BIT(0) /* 0x46: Pin Multi-function Enable 3 */ #define IT8XXX2_GCTRL_SMB3PSEL BIT(6) +#define IT8XXX2_GCTRL_SRAM_CRYPTO_USED BIT(5) /* 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) +/* Accept Port 81h Cycle */ +#define IT8XXX2_GCTRL_ACP81 BIT(3) /* USB Debug Enable */ #define IT8XXX2_GCTRL_MCCR_USB_EN BIT(7) /* USB Pad Power-On Enable */ diff --git a/soc/ite/ec/it8xxx2/Kconfig b/soc/ite/ec/it8xxx2/Kconfig index 7ba9d832534..38b92c9c6b8 100644 --- a/soc/ite/ec/it8xxx2/Kconfig +++ b/soc/ite/ec/it8xxx2/Kconfig @@ -1,11 +1,11 @@ # Copyright (c) 2020 ITE Corporation. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 -config SOC_SERIES_ITE_IT8XXX2 +config SOC_SERIES_IT8XXX2 select CPU_HAS_FPU if "$(ZEPHYR_TOOLCHAIN_VARIANT)" != "zephyr" || RISCV_ISA_EXT_M select HAS_PM -if SOC_SERIES_ITE_IT8XXX2 +if SOC_SERIES_IT8XXX2 config SOC_IT8XXX2 select RISCV @@ -15,7 +15,7 @@ config SOC_IT8XXX2 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_M if !(SOC_IT81302BX || SOC_IT81202BX) select RISCV_ISA_EXT_A select RISCV_ISA_EXT_C @@ -31,29 +31,71 @@ config SOC_IT8XXX2_REG_SET_V2 This option is selected by a variable of which soc, and will determine the register for the IT82xx2 specification. -config SOC_IT81302_BX +config SOC_IT8XXX2_USBPD_PHY_V1 + bool + help + This option is automatically selected by variant soc and sets + the USBPD PHY version. + +config SOC_IT8XXX2_USBPD_PHY_V2 + bool + help + This option is automatically selected by variant soc and sets + the USBPD PHY version. + +config SOC_IT81302BX select SOC_IT8XXX2_REG_SET_V1 + select SOC_IT8XXX2_USBPD_PHY_V1 -config SOC_IT81202_BX +config SOC_IT81202BX select SOC_IT8XXX2_REG_SET_V1 + select SOC_IT8XXX2_USBPD_PHY_V1 -config SOC_IT81302_CX +config SOC_IT81302CX select SOC_IT8XXX2_REG_SET_V1 + select SOC_IT8XXX2_USBPD_PHY_V2 -config SOC_IT81202_CX +config SOC_IT81202CX select SOC_IT8XXX2_REG_SET_V1 + select SOC_IT8XXX2_USBPD_PHY_V2 -config SOC_IT82202_AX +config SOC_IT81302DX + select SOC_IT8XXX2_REG_SET_V1 + select SOC_IT8XXX2_USBPD_PHY_V2 + +config SOC_IT81202DX + select SOC_IT8XXX2_REG_SET_V1 + select SOC_IT8XXX2_USBPD_PHY_V2 + +config SOC_IT82202AX select SOC_IT8XXX2_REG_SET_V2 select SOC_IT8XXX2_EC_BUS_24MHZ if !DT_HAS_ITE_IT82XX2_USB_ENABLED + select SOC_IT8XXX2_USBPD_PHY_V2 -config SOC_IT82302_AX +config SOC_IT82302AX select SOC_IT8XXX2_REG_SET_V2 select SOC_IT8XXX2_EC_BUS_24MHZ if !DT_HAS_ITE_IT82XX2_USB_ENABLED + select SOC_IT8XXX2_USBPD_PHY_V2 -config SOC_IT82002_AW +config SOC_IT82002AW select SOC_IT8XXX2_REG_SET_V2 select SOC_IT8XXX2_EC_BUS_24MHZ if !DT_HAS_ITE_IT82XX2_USB_ENABLED + select SOC_IT8XXX2_USBPD_PHY_V2 + +config SOC_IT82002BW + select SOC_IT8XXX2_REG_SET_V2 + select SOC_IT8XXX2_EC_BUS_24MHZ if !DT_HAS_ITE_IT82XX2_USB_ENABLED + select SOC_IT8XXX2_USBPD_PHY_V2 + +config SOC_IT82202BW + select SOC_IT8XXX2_REG_SET_V2 + select SOC_IT8XXX2_EC_BUS_24MHZ if !DT_HAS_ITE_IT82XX2_USB_ENABLED + select SOC_IT8XXX2_USBPD_PHY_V2 + +config SOC_IT82302BW + select SOC_IT8XXX2_REG_SET_V2 + select SOC_IT8XXX2_EC_BUS_24MHZ if !DT_HAS_ITE_IT82XX2_USB_ENABLED + select SOC_IT8XXX2_USBPD_PHY_V2 config SOC_IT8XXX2_PLL_FLASH_48M bool "Flash frequency is 48MHz" @@ -149,6 +191,11 @@ config SOC_IT8XXX2_SHA256_HW_ACCELERATE If we enable this config, because HW limits, the sha256 data must place in first 4KB of RAM. +config SOC_IT8XXX2_SHA256_BLOCK_SIZE + hex + default 0x500 if SOC_IT8XXX2_REG_SET_V2 + default 0x200 + DT_CHOSEN_ZEPHYR_FLASH := zephyr,flash config SOC_IT8XXX2_FLASH_SIZE_BYTES @@ -159,7 +206,6 @@ config SOC_IT8XXX2_FLASH_SIZE_BYTES config ILM_MAX_SIZE int "ILM Size in kB" - default 60 if SOC_IT81202_CX || SOC_IT81302_CX default SRAM_SIZE -endif # SOC_SERIES_ITE_IT8XXX2 +endif # SOC_SERIES_IT8XXX2 diff --git a/soc/ite/ec/it8xxx2/Kconfig.defconfig.it81202bx b/soc/ite/ec/it8xxx2/Kconfig.defconfig.it81202bx index a643011e6b4..5471961fa8d 100644 --- a/soc/ite/ec/it8xxx2/Kconfig.defconfig.it81202bx +++ b/soc/ite/ec/it8xxx2/Kconfig.defconfig.it81202bx @@ -1,7 +1,7 @@ # Copyright (c) 2022 ITE Corporation. # SPDX-License-Identifier: Apache-2.0 -if SOC_IT81202_BX +if SOC_IT81202BX config SOC_IT8XXX2_GPIO_GROUP_K_L_DEFAULT_PULL_DOWN default y diff --git a/soc/ite/ec/it8xxx2/Kconfig.defconfig.it81202cx b/soc/ite/ec/it8xxx2/Kconfig.defconfig.it81202cx index e9b5d1d5eb6..abbeecd53d6 100644 --- a/soc/ite/ec/it8xxx2/Kconfig.defconfig.it81202cx +++ b/soc/ite/ec/it8xxx2/Kconfig.defconfig.it81202cx @@ -1,7 +1,10 @@ # Copyright (c) 2022 ITE Corporation. # SPDX-License-Identifier: Apache-2.0 -if SOC_IT81202_CX +if SOC_IT81202CX + +config ILM_MAX_SIZE + default 60 config SOC_IT8XXX2_GPIO_GROUP_K_L_DEFAULT_PULL_DOWN default y diff --git a/soc/ite/ec/it8xxx2/Kconfig.defconfig.it81202dx b/soc/ite/ec/it8xxx2/Kconfig.defconfig.it81202dx new file mode 100644 index 00000000000..48fed80f1c2 --- /dev/null +++ b/soc/ite/ec/it8xxx2/Kconfig.defconfig.it81202dx @@ -0,0 +1,12 @@ +# Copyright (c) 2024 ITE Corporation. +# SPDX-License-Identifier: Apache-2.0 + +if SOC_IT81202DX + +config ILM_MAX_SIZE + default 60 + +config SOC_IT8XXX2_GPIO_GROUP_K_L_DEFAULT_PULL_DOWN + default y + +endif diff --git a/soc/ite/ec/it8xxx2/Kconfig.defconfig.it81302bx b/soc/ite/ec/it8xxx2/Kconfig.defconfig.it81302bx index 051d40f1e4b..c8f08310803 100644 --- a/soc/ite/ec/it8xxx2/Kconfig.defconfig.it81302bx +++ b/soc/ite/ec/it8xxx2/Kconfig.defconfig.it81302bx @@ -1,7 +1,7 @@ # Copyright (c) 2022 ITE Corporation. # SPDX-License-Identifier: Apache-2.0 -if SOC_IT81302_BX +if SOC_IT81302BX config SOC_IT8XXX2_GPIO_GROUP_K_L_DEFAULT_PULL_DOWN default n diff --git a/soc/ite/ec/it8xxx2/Kconfig.defconfig.it81302cx b/soc/ite/ec/it8xxx2/Kconfig.defconfig.it81302cx index 06fb93d78df..c6d9608490d 100644 --- a/soc/ite/ec/it8xxx2/Kconfig.defconfig.it81302cx +++ b/soc/ite/ec/it8xxx2/Kconfig.defconfig.it81302cx @@ -1,7 +1,10 @@ # Copyright (c) 2022 ITE Corporation. # SPDX-License-Identifier: Apache-2.0 -if SOC_IT81302_CX +if SOC_IT81302CX + +config ILM_MAX_SIZE + default 60 config SOC_IT8XXX2_GPIO_GROUP_K_L_DEFAULT_PULL_DOWN default n diff --git a/soc/ite/ec/it8xxx2/Kconfig.defconfig.it81302dx b/soc/ite/ec/it8xxx2/Kconfig.defconfig.it81302dx new file mode 100644 index 00000000000..d774e6a455b --- /dev/null +++ b/soc/ite/ec/it8xxx2/Kconfig.defconfig.it81302dx @@ -0,0 +1,12 @@ +# Copyright (c) 2024 ITE Corporation. +# SPDX-License-Identifier: Apache-2.0 + +if SOC_IT81302DX + +config ILM_MAX_SIZE + default 60 + +config SOC_IT8XXX2_GPIO_GROUP_K_L_DEFAULT_PULL_DOWN + default n + +endif diff --git a/soc/ite/ec/it8xxx2/Kconfig.defconfig.it82002aw b/soc/ite/ec/it8xxx2/Kconfig.defconfig.it82002aw index 30e2db747b3..9ac533f35e6 100644 --- a/soc/ite/ec/it8xxx2/Kconfig.defconfig.it82002aw +++ b/soc/ite/ec/it8xxx2/Kconfig.defconfig.it82002aw @@ -1,7 +1,7 @@ # Copyright (c) 2023 ITE Corporation. # SPDX-License-Identifier: Apache-2.0 -if SOC_IT82002_AW +if SOC_IT82002AW config SOC_IT8XXX2_GPIO_GROUP_K_L_DEFAULT_PULL_DOWN default y diff --git a/soc/ite/ec/it8xxx2/Kconfig.defconfig.it82002bw b/soc/ite/ec/it8xxx2/Kconfig.defconfig.it82002bw new file mode 100644 index 00000000000..6bd70e438f9 --- /dev/null +++ b/soc/ite/ec/it8xxx2/Kconfig.defconfig.it82002bw @@ -0,0 +1,9 @@ +# Copyright (c) 2024 ITE Corporation. +# SPDX-License-Identifier: Apache-2.0 + +if SOC_IT82002BW + +config SOC_IT8XXX2_GPIO_GROUP_K_L_DEFAULT_PULL_DOWN + default y + +endif diff --git a/soc/ite/ec/it8xxx2/Kconfig.defconfig.it82202ax b/soc/ite/ec/it8xxx2/Kconfig.defconfig.it82202ax index 99343db0b37..d00acc8c4d0 100644 --- a/soc/ite/ec/it8xxx2/Kconfig.defconfig.it82202ax +++ b/soc/ite/ec/it8xxx2/Kconfig.defconfig.it82202ax @@ -1,7 +1,7 @@ # Copyright (c) 2023 ITE Corporation. # SPDX-License-Identifier: Apache-2.0 -if SOC_IT82202_AX +if SOC_IT82202AX config SOC_IT8XXX2_GPIO_GROUP_K_L_DEFAULT_PULL_DOWN default y diff --git a/soc/ite/ec/it8xxx2/Kconfig.defconfig.it82202bw b/soc/ite/ec/it8xxx2/Kconfig.defconfig.it82202bw new file mode 100644 index 00000000000..b9f53bd6c86 --- /dev/null +++ b/soc/ite/ec/it8xxx2/Kconfig.defconfig.it82202bw @@ -0,0 +1,9 @@ +# Copyright (c) 2024 ITE Corporation. +# SPDX-License-Identifier: Apache-2.0 + +if SOC_IT82202BW + +config SOC_IT8XXX2_GPIO_GROUP_K_L_DEFAULT_PULL_DOWN + default y + +endif diff --git a/soc/ite/ec/it8xxx2/Kconfig.defconfig.it82302ax b/soc/ite/ec/it8xxx2/Kconfig.defconfig.it82302ax index e1cff23886e..5481408c325 100644 --- a/soc/ite/ec/it8xxx2/Kconfig.defconfig.it82302ax +++ b/soc/ite/ec/it8xxx2/Kconfig.defconfig.it82302ax @@ -1,7 +1,7 @@ # Copyright (c) 2024 ITE Corporation. # SPDX-License-Identifier: Apache-2.0 -if SOC_IT82302_AX +if SOC_IT82302AX config SOC_IT8XXX2_GPIO_GROUP_K_L_DEFAULT_PULL_DOWN default n diff --git a/soc/ite/ec/it8xxx2/Kconfig.defconfig.it82302bw b/soc/ite/ec/it8xxx2/Kconfig.defconfig.it82302bw new file mode 100644 index 00000000000..e5339f0734f --- /dev/null +++ b/soc/ite/ec/it8xxx2/Kconfig.defconfig.it82302bw @@ -0,0 +1,9 @@ +# Copyright (c) 2024 ITE Corporation. +# SPDX-License-Identifier: Apache-2.0 + +if SOC_IT82302BW + +config SOC_IT8XXX2_GPIO_GROUP_K_L_DEFAULT_PULL_DOWN + default n + +endif diff --git a/soc/ite/ec/it8xxx2/Kconfig.defconfig.series b/soc/ite/ec/it8xxx2/Kconfig.defconfig.series index 98fbee6c0c1..2b0f8549efc 100644 --- a/soc/ite/ec/it8xxx2/Kconfig.defconfig.series +++ b/soc/ite/ec/it8xxx2/Kconfig.defconfig.series @@ -1,7 +1,7 @@ # Copyright (c) 2020 ITE Corporation. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 -if SOC_SERIES_ITE_IT8XXX2 +if SOC_SERIES_IT8XXX2 config RISCV_GP default y @@ -53,4 +53,4 @@ config RISCV_SOC_INTERRUPT_INIT rsource "Kconfig.defconfig.it8*" -endif # SOC_SERIES_ITE_IT8XXX2 +endif # SOC_SERIES_IT8XXX2 diff --git a/soc/ite/ec/it8xxx2/Kconfig.soc b/soc/ite/ec/it8xxx2/Kconfig.soc index aba69c55346..96504021f23 100644 --- a/soc/ite/ec/it8xxx2/Kconfig.soc +++ b/soc/ite/ec/it8xxx2/Kconfig.soc @@ -1,7 +1,7 @@ # Copyright (c) 2020 ITE Corporation. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 -config SOC_SERIES_ITE_IT8XXX2 +config SOC_SERIES_IT8XXX2 bool select SOC_FAMILY_ITE_EC help @@ -9,44 +9,69 @@ config SOC_SERIES_ITE_IT8XXX2 config SOC_IT8XXX2 bool - select SOC_SERIES_ITE_IT8XXX2 + select SOC_SERIES_IT8XXX2 -config SOC_IT81302_BX +config SOC_IT81302BX bool select SOC_IT8XXX2 -config SOC_IT81202_BX +config SOC_IT81202BX bool select SOC_IT8XXX2 -config SOC_IT81302_CX +config SOC_IT81302CX bool select SOC_IT8XXX2 -config SOC_IT81202_CX +config SOC_IT81202CX bool select SOC_IT8XXX2 -config SOC_IT82202_AX +config SOC_IT81302DX bool select SOC_IT8XXX2 -config SOC_IT82302_AX +config SOC_IT81202DX bool select SOC_IT8XXX2 -config SOC_IT82002_AW +config SOC_IT82202AX + bool + select SOC_IT8XXX2 + +config SOC_IT82302AX + bool + select SOC_IT8XXX2 + +config SOC_IT82002AW + bool + select SOC_IT8XXX2 + +config SOC_IT82002BW + bool + select SOC_IT8XXX2 + +config SOC_IT82202BW + bool + select SOC_IT8XXX2 + +config SOC_IT82302BW bool select SOC_IT8XXX2 config SOC_SERIES - default "it8xxx2" if SOC_SERIES_ITE_IT8XXX2 + default "it8xxx2" if SOC_SERIES_IT8XXX2 config SOC - default "it81202bx" if SOC_IT81202_BX - default "it81202cx" if SOC_IT81202_CX - default "it81302bx" if SOC_IT81302_BX - default "it81302cx" if SOC_IT81302_CX - default "it82002aw" if SOC_IT82002_AW - default "it82202ax" if SOC_IT82202_AX - default "it82302ax" if SOC_IT82302_AX + default "it81202bx" if SOC_IT81202BX + default "it81202cx" if SOC_IT81202CX + default "it81202dx" if SOC_IT81202DX + default "it81302bx" if SOC_IT81302BX + default "it81302cx" if SOC_IT81302CX + default "it81302dx" if SOC_IT81302DX + default "it82002aw" if SOC_IT82002AW + default "it82002bw" if SOC_IT82002BW + default "it82202ax" if SOC_IT82202AX + default "it82302ax" if SOC_IT82302AX + default "it82202bw" if SOC_IT82202BW + default "it82302bw" if SOC_IT82302BW diff --git a/soc/ite/ec/it8xxx2/ilm.c b/soc/ite/ec/it8xxx2/ilm.c index 85738f54c4c..f586e38dd45 100644 --- a/soc/ite/ec/it8xxx2/ilm.c +++ b/soc/ite/ec/it8xxx2/ilm.c @@ -176,7 +176,7 @@ static const struct ilm_config ilm_config = { SCAR_REG(13), SCAR_REG(14), /* - * Except for CONFIG_SOC_IT81202_CX and CONFIG_SOC_IT81302_CX + * Except for CONFIG_SOC_IT81202CX and CONFIG_SOC_IT81302CX * maximum ILM size are 60KB, the ILM size of other varients * are equal to the SRAM size. */ diff --git a/soc/ite/ec/it8xxx2/linker.ld b/soc/ite/ec/it8xxx2/linker.ld index 5c13ee2ecce..3ad9bd21df3 100644 --- a/soc/ite/ec/it8xxx2/linker.ld +++ b/soc/ite/ec/it8xxx2/linker.ld @@ -65,10 +65,6 @@ #define MPU_ALIGN(region_size) . = ALIGN(4) #endif -#ifdef CONFIG_SOC_IT8XXX2_SHA256_HW_ACCELERATE -#define SHA256_BLOCK_SIZE 0x200 -#endif - #include MEMORY @@ -130,6 +126,26 @@ SECTIONS KEEP(*(.reset.*)) } GROUP_LINK_IN(ROMABLE_REGION) +#ifdef CONFIG_SOC_IT8XXX2_JTAG_DEBUG_INTERFACE +#define JTAG_DEBUG_RESERVED_ADDR_START 0x80000800 +#define JTAG_DEBUG_RESERVED_ADDR_END 0x800008FF + /* The CPU address from 0x80000800 to 0x800008FF is reserved for JTAG + * debug usage. */ + SECTION_PROLOGUE(jtag_dbg,,) + { + __jtag_dbg_pad_start = ABSOLUTE(.); + ASSERT((__jtag_dbg_pad_start < JTAG_DEBUG_RESERVED_ADDR_START), + "The start address of jtag debug section is incorrect."); + + __jtag_dbg_pad_size = JTAG_DEBUG_RESERVED_ADDR_END - __jtag_dbg_pad_start; + . = . + __jtag_dbg_pad_size; + + __jtag_dbg_pad_end = ABSOLUTE(.); + ASSERT((__jtag_dbg_pad_end == JTAG_DEBUG_RESERVED_ADDR_END), + "The end address of jtag debug section is incorrect."); + } GROUP_LINK_IN(ROMABLE_REGION) +#endif + #ifndef CONFIG_SOC_IT8XXX2_EXCEPTIONS_IN_RAM SECTION_PROLOGUE(_EXCEPTION_SECTION_NAME,,) { @@ -161,7 +177,7 @@ SECTIONS /* Pad to match allocation of block in RAM, * maintaining code alignment against ILM */ __sha256_pad_block_start = .; - . = . + SHA256_BLOCK_SIZE; + . = . + CONFIG_SOC_IT8XXX2_SHA256_BLOCK_SIZE; #endif /* Specially-tagged functions in SoC sources */ KEEP(*(.__ram_code)) @@ -249,15 +265,18 @@ SECTIONS __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_size == CONFIG_SOC_IT8XXX2_SHA256_BLOCK_SIZE), \ + "Not compatible ram size for HW sha256 module"); ASSERT((__sha256_ram_block_end < (RAM_BASE + 0x1000)), \ - "512bytes must in SRAM first 4kbytes"); + "sha256 ram block 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"); +#else + __sha256_ram_block_size = 0; #endif - . += __ilm_flash_end - __ilm_flash_start; + . += __ilm_flash_end - __ilm_flash_start - __sha256_ram_block_size; __ilm_ram_end = .; } GROUP_LINK_IN(RAMABLE_REGION) diff --git a/soc/ite/ec/it8xxx2/soc.c b/soc/ite/ec/it8xxx2/soc.c index c1ab2e13562..865391f222c 100644 --- a/soc/ite/ec/it8xxx2/soc.c +++ b/soc/ite/ec/it8xxx2/soc.c @@ -239,8 +239,10 @@ void riscv_idle(enum chip_pll_mode mode, unsigned int key) chip_pll_ctrl(mode); do { +#ifndef CONFIG_SOC_IT8XXX2_JTAG_DEBUG_INTERFACE /* Wait for interrupt */ __asm__ volatile ("wfi"); +#endif /* * Sometimes wfi instruction may fail due to CPU's MTIP@mip * register is non-zero. diff --git a/soc/ite/ec/soc.yml b/soc/ite/ec/soc.yml index c2ffdd222db..b73270535f9 100644 --- a/soc/ite/ec/soc.yml +++ b/soc/ite/ec/soc.yml @@ -5,8 +5,13 @@ family: socs: - name: it81202bx - name: it81202cx + - name: it81202dx - name: it81302bx - name: it81302cx + - name: it81302dx - name: it82002aw + - name: it82002bw - name: it82202ax - name: it82302ax + - name: it82202bw + - name: it82302bw diff --git a/soc/microchip/mec/Kconfig b/soc/microchip/mec/Kconfig index 1b5ccda45e0..8f0b84b4b4a 100644 --- a/soc/microchip/mec/Kconfig +++ b/soc/microchip/mec/Kconfig @@ -8,6 +8,7 @@ if SOC_FAMILY_MICROCHIP_MEC menuconfig MCHP_MEC_UNSIGNED_HEADER bool "Create an unsigned output binary with MCHP MEC binary header" + depends on SOC_SERIES_MEC172X help On Microchip MEC series chip, the ROM code loads firmware image from flash to RAM using a TAG to locate a Header which specifies the location and @@ -210,6 +211,54 @@ config MCHP_HEADER_VERBOSE_OUTPUT endif # MCHP_MEC_UNSIGNED_HEADER +# Common debug configuration +choice + prompt "MEC debug interface general configuration" + default SOC_MEC_DEBUG_AND_TRACING + depends on SOC_SERIES_MEC174X || SOC_SERIES_MEC175X || SOC_SERIES_MECH172X + help + Select Debug SoC interface support for MEC SoC family + + config SOC_MEC_DEBUG_DISABLED + bool "Disable debug support" + help + Debug port is disabled, JTAG/SWD cannot be enabled. JTAG_RST# + pin is ignored. All other JTAG pins can be used as GPIOs + or other non-JTAG alternate functions. + + config SOC_MEC_DEBUG_WITHOUT_TRACING + bool "Debug support via Serial wire debug" + help + JTAG port in SWD mode. + + config SOC_MEC_DEBUG_AND_TRACING + bool "Debug support via Serial wire debug with tracing enabled" + help + JTAG port is enabled in SWD mode. +endchoice + +choice + prompt "MEC debug interface trace configuration" + default SOC_MEC_DEBUG_AND_SWV_TRACING + depends on SOC_MEC_DEBUG_AND_TRACING + help + Select tracing mode for debug interface + + config SOC_MEC_DEBUG_AND_ETM_TRACING + bool "Debug support via Serial wire debug" + help + JTAG port in SWD mode and ETM as tracing method. + ETM re-assigns 5 pins for clock and 4-bit data bus. + Check data sheet for functions shared with ETM. + + config SOC_MEC_DEBUG_AND_SWV_TRACING + bool "debug support via Serial Wire Debug and Viewer" + help + JTAG port in SWD mode and SWV as tracing method. + Check data sheet for functions shared with SWD and SWV pins. +endchoice + +# common processor clock divider configuration config SOC_MEC_PROC_CLK_DIV int "PROC_CLK_DIV" default 1 diff --git a/soc/microchip/mec/common/CMakeLists.txt b/soc/microchip/mec/common/CMakeLists.txt index 0fe0c9f3d8b..0669a09cbe2 100644 --- a/soc/microchip/mec/common/CMakeLists.txt +++ b/soc/microchip/mec/common/CMakeLists.txt @@ -4,6 +4,9 @@ zephyr_include_directories(.) zephyr_library_sources_ifdef(CONFIG_SOC_SERIES_MEC172X soc_i2c.c ) +zephyr_library_sources_ifdef(CONFIG_HAS_MEC5_HAL + soc_cmn_init.c +) if (DEFINED CONFIG_MCHP_HEADER_VERBOSE_OUTPUT) set(MCHP_HEADER_VERBOSE_OPTION "-v") diff --git a/soc/microchip/mec/common/soc_cmn_init.c b/soc/microchip/mec/common/soc_cmn_init.c new file mode 100644 index 00000000000..62cd150861f --- /dev/null +++ b/soc/microchip/mec/common/soc_cmn_init.c @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2024 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +static void mec5_soc_init_debug_interface(void) +{ +#if defined(CONFIG_SOC_MEC_DEBUG_DISABLED) + mec_ecs_etm_pins(ECS_ETM_PINS_DISABLE); + mec_ecs_debug_port(MEC_DEBUG_MODE_DISABLE); +#else +#if defined(SOC_MEC_DEBUG_WITHOUT_TRACING) + mec_ecs_etm_pins(ECS_ETM_PINS_DISABLE); + mec_ecs_debug_port(MEC_DEBUG_MODE_SWD); +#elif defined(SOC_MEC_DEBUG_AND_TRACING) +#if defined(SOC_MEC_DEBUG_AND_ETM_TRACING) + mec_ecs_etm_pins(ECS_ETM_PINS_DISABLE); + mec_ecs_debug_port(MEC_DEBUG_MODE_SWD_SWV); +#elif defined(CONFIG_SOC_MEC_DEBUG_AND_ETM_TRACING) + mec_ecs_debug_port(MEC_DEBUG_MODE_SWD); + mec_ecs_etm_pins(ECS_ETM_PINS_ENABLE); +#endif +#endif +#endif +} + +int mec5_soc_common_init(void) +{ + mec5_soc_init_debug_interface(); + mec_ecia_init(MEC5_ECIA_DIRECT_BITMAP, 1, 0); + + return 0; +} diff --git a/soc/microchip/mec/common/soc_cmn_init.h b/soc/microchip/mec/common/soc_cmn_init.h new file mode 100644 index 00000000000..807d8f67b09 --- /dev/null +++ b/soc/microchip/mec/common/soc_cmn_init.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2024 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __MEC5_SOC_CMN_INIT_H +#define __MEC5_SOC_CMN_INIT_H + +#ifndef _ASMLANGUAGE + +int mec5_soc_common_init(void); + +#endif + +#endif diff --git a/soc/microchip/mec/mec174x/CMakeLists.txt b/soc/microchip/mec/mec174x/CMakeLists.txt new file mode 100644 index 00000000000..6d2a447f729 --- /dev/null +++ b/soc/microchip/mec/mec174x/CMakeLists.txt @@ -0,0 +1,11 @@ +# +# Copyright (c) 2024, Microchip Technology Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +zephyr_include_directories(${ZEPHYR_BASE}/drivers) +zephyr_sources(soc.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/microchip/mec/mec174x/Kconfig b/soc/microchip/mec/mec174x/Kconfig new file mode 100644 index 00000000000..52eb412941a --- /dev/null +++ b/soc/microchip/mec/mec174x/Kconfig @@ -0,0 +1,21 @@ +# Microchip MEC174X MCU core series + +# Copyright (c) 2024 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_MEC174X + select ARM + select CPU_CORTEX_M4 + select CPU_CORTEX_M_HAS_DWT + select CPU_HAS_FPU + select CPU_HAS_ARM_MPU + select HAS_SWO + select HAS_MEC5_HAL + select HAS_PM + +if SOC_SERIES_MEC174X + +config RTOS_TIMER + bool "MEC174x RTOS Timer(32KHz) as kernel timer" + +endif # SOC_SERIES_MEC174X diff --git a/soc/microchip/mec/mec174x/Kconfig.defconfig.mec1743qlj b/soc/microchip/mec/mec174x/Kconfig.defconfig.mec1743qlj new file mode 100644 index 00000000000..9f52e8bad9a --- /dev/null +++ b/soc/microchip/mec/mec174x/Kconfig.defconfig.mec1743qlj @@ -0,0 +1,16 @@ +# Copyright (c) 2024 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +# Microchip MEC1743QLJ MCU using MEC5 HAL +# Q = 480KB total SRAM +# LJ = 176 pin package + +if SOC_MEC1743_QLJ + +config GPIO + default y + +config PINCTRL + default y + +endif # SOC_MEC1743_QLJ diff --git a/soc/microchip/mec/mec174x/Kconfig.defconfig.mec1743qsz b/soc/microchip/mec/mec174x/Kconfig.defconfig.mec1743qsz new file mode 100644 index 00000000000..b75177ea757 --- /dev/null +++ b/soc/microchip/mec/mec174x/Kconfig.defconfig.mec1743qsz @@ -0,0 +1,16 @@ +# Copyright (c) 2024 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +# Microchip MEC1743QSZ MCU using MEC5 HAL +# Q = 480KB total SRAM +# SZ = 144 pin package + +if SOC_MEC1743_QSZ + +config GPIO + default y + +config PINCTRL + default y + +endif # SOC_MEC1743_QSZ diff --git a/soc/microchip/mec/mec174x/Kconfig.defconfig.series b/soc/microchip/mec/mec174x/Kconfig.defconfig.series new file mode 100644 index 00000000000..75a55c39356 --- /dev/null +++ b/soc/microchip/mec/mec174x/Kconfig.defconfig.series @@ -0,0 +1,19 @@ +# Copyright (c) 2024 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +# Microchip MEC174x MCU series configuration options + +if SOC_SERIES_MEC174X + +config NUM_IRQS + # must be >= the highest interrupt number used + # - include the UART interrupts + # All NVIC external sources. + default 194 + +rsource "Kconfig.defconfig.mec174*" + +config CORTEX_M_SYSTICK + depends on !RTOS_TIMER + +endif # SOC_SERIES_MEC174X diff --git a/soc/microchip/mec/mec174x/Kconfig.soc b/soc/microchip/mec/mec174x/Kconfig.soc new file mode 100644 index 00000000000..e815797d8f4 --- /dev/null +++ b/soc/microchip/mec/mec174x/Kconfig.soc @@ -0,0 +1,25 @@ +# Copyright (c) 2024 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +# Microchip MEC174x MCU core series + +config SOC_SERIES_MEC174X + bool + select SOC_FAMILY_MICROCHIP_MEC + help + Enable support for Microchip MEC Cortex-M4F MCU series + +config SOC_SERIES + default "mec174x" if SOC_SERIES_MEC174X + +config SOC_MEC1743_QLJ + bool + select SOC_SERIES_MEC174X + +config SOC_MEC1743_QSZ + bool + select SOC_SERIES_MEC174X + +config SOC + default "mec1743_qlj" if SOC_MEC1743_QLJ + default "mec1743_qsz" if SOC_MEC1743_QSZ diff --git a/soc/microchip/mec/mec174x/soc.c b/soc/microchip/mec/mec174x/soc.c new file mode 100644 index 00000000000..6d7a502b082 --- /dev/null +++ b/soc/microchip/mec/mec174x/soc.c @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2024 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +static int soc_init(void) +{ + mec5_soc_common_init(); + return 0; +} + +/* Enabling HW debug and initializing the MEC interrupt aggregator should be done + * before driver are loaded to not overwrite driver interrupt configuration. + * Use early initialization category called soon after Zephyr z_cstart and before + * Zephyr starts making driver initialization calls. + */ +SYS_INIT(soc_init, EARLY, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); diff --git a/soc/microchip/mec/mec174x/soc.h b/soc/microchip/mec/mec174x/soc.h new file mode 100644 index 00000000000..b0a2a46eef8 --- /dev/null +++ b/soc/microchip/mec/mec174x/soc.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2024 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __MEC5_SOC_H +#define __MEC5_SOC_H + +#define SYSCLK_DEFAULT_IOSC_HZ MHZ(96) + +#ifndef _ASMLANGUAGE + +#include "device_mec5.h" + +/* common SoC API */ +#include "soc_dt.h" +#include "soc_espi_channels.h" +#include "soc_gpio.h" +#include "soc_pcr.h" +#include "soc_pins.h" + +#endif + +#endif diff --git a/soc/microchip/mec/mec175x/CMakeLists.txt b/soc/microchip/mec/mec175x/CMakeLists.txt new file mode 100644 index 00000000000..6d2a447f729 --- /dev/null +++ b/soc/microchip/mec/mec175x/CMakeLists.txt @@ -0,0 +1,11 @@ +# +# Copyright (c) 2024, Microchip Technology Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +zephyr_include_directories(${ZEPHYR_BASE}/drivers) +zephyr_sources(soc.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/microchip/mec/mec175x/Kconfig b/soc/microchip/mec/mec175x/Kconfig new file mode 100644 index 00000000000..1cce7ce0e2b --- /dev/null +++ b/soc/microchip/mec/mec175x/Kconfig @@ -0,0 +1,21 @@ +# Microchip MEC175X MCU core series + +# Copyright (c) 2024 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_MEC175X + select ARM + select CPU_CORTEX_M4 + select CPU_CORTEX_M_HAS_DWT + select CPU_HAS_FPU + select CPU_HAS_ARM_MPU + select HAS_SWO + select HAS_MEC5_HAL + select HAS_PM + +if SOC_SERIES_MEC175X + +config RTOS_TIMER + bool "MEC175x RTOS Timer(32KHz) as kernel timer" + +endif # SOC_SERIES_MEC175X diff --git a/soc/microchip/mec/mec175x/Kconfig.defconfig.mec1753qlj b/soc/microchip/mec/mec175x/Kconfig.defconfig.mec1753qlj new file mode 100644 index 00000000000..268b482b3c0 --- /dev/null +++ b/soc/microchip/mec/mec175x/Kconfig.defconfig.mec1753qlj @@ -0,0 +1,16 @@ +# Copyright (c) 2024 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +# Microchip MEC1753QLJ MCU using MEC5 HAL +# Q = 480KB total SRAM +# LJ = 176 pin package + +if SOC_MEC1753_QLJ + +config GPIO + default y + +config PINCTRL + default y + +endif # SOC_MEC1753_QLJ diff --git a/soc/microchip/mec/mec175x/Kconfig.defconfig.mec1753qsz b/soc/microchip/mec/mec175x/Kconfig.defconfig.mec1753qsz new file mode 100644 index 00000000000..b75177ea757 --- /dev/null +++ b/soc/microchip/mec/mec175x/Kconfig.defconfig.mec1753qsz @@ -0,0 +1,16 @@ +# Copyright (c) 2024 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +# Microchip MEC1743QSZ MCU using MEC5 HAL +# Q = 480KB total SRAM +# SZ = 144 pin package + +if SOC_MEC1743_QSZ + +config GPIO + default y + +config PINCTRL + default y + +endif # SOC_MEC1743_QSZ diff --git a/soc/microchip/mec/mec175x/Kconfig.defconfig.series b/soc/microchip/mec/mec175x/Kconfig.defconfig.series new file mode 100644 index 00000000000..9d8cdf99040 --- /dev/null +++ b/soc/microchip/mec/mec175x/Kconfig.defconfig.series @@ -0,0 +1,19 @@ +# Copyright (c) 2024 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +# Microchip MEC175x MCU series configuration options + +if SOC_SERIES_MEC175X + +config NUM_IRQS + # must be >= the highest interrupt number used + # - include the UART interrupts + # All NVIC external sources. + default 198 + +rsource "Kconfig.defconfig.mec175*" + +config CORTEX_M_SYSTICK + depends on !RTOS_TIMER + +endif # SOC_SERIES_MEC175X diff --git a/soc/microchip/mec/mec175x/Kconfig.soc b/soc/microchip/mec/mec175x/Kconfig.soc new file mode 100644 index 00000000000..39fe541636f --- /dev/null +++ b/soc/microchip/mec/mec175x/Kconfig.soc @@ -0,0 +1,25 @@ +# Copyright (c) 2024 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +# Microchip MEC175x MCU core series + +config SOC_SERIES_MEC175X + bool + select SOC_FAMILY_MICROCHIP_MEC + help + Enable support for Microchip MEC Cortex-M4F MCU series + +config SOC_SERIES + default "mec175x" if SOC_SERIES_MEC175X + +config SOC_MEC1753_QLJ + bool + select SOC_SERIES_MEC175X + +config SOC_MEC1753_QSZ + bool + select SOC_SERIES_MEC175X + +config SOC + default "mec1753_qlj" if SOC_MEC1753_QLJ + default "mec1753_qsz" if SOC_MEC1753_QSZ diff --git a/soc/microchip/mec/mec175x/soc.c b/soc/microchip/mec/mec175x/soc.c new file mode 100644 index 00000000000..6d7a502b082 --- /dev/null +++ b/soc/microchip/mec/mec175x/soc.c @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2024 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +static int soc_init(void) +{ + mec5_soc_common_init(); + return 0; +} + +/* Enabling HW debug and initializing the MEC interrupt aggregator should be done + * before driver are loaded to not overwrite driver interrupt configuration. + * Use early initialization category called soon after Zephyr z_cstart and before + * Zephyr starts making driver initialization calls. + */ +SYS_INIT(soc_init, EARLY, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); diff --git a/soc/microchip/mec/mec175x/soc.h b/soc/microchip/mec/mec175x/soc.h new file mode 100644 index 00000000000..b0a2a46eef8 --- /dev/null +++ b/soc/microchip/mec/mec175x/soc.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2024 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __MEC5_SOC_H +#define __MEC5_SOC_H + +#define SYSCLK_DEFAULT_IOSC_HZ MHZ(96) + +#ifndef _ASMLANGUAGE + +#include "device_mec5.h" + +/* common SoC API */ +#include "soc_dt.h" +#include "soc_espi_channels.h" +#include "soc_gpio.h" +#include "soc_pcr.h" +#include "soc_pins.h" + +#endif + +#endif diff --git a/soc/microchip/mec/mech172x/CMakeLists.txt b/soc/microchip/mec/mech172x/CMakeLists.txt new file mode 100644 index 00000000000..6d2a447f729 --- /dev/null +++ b/soc/microchip/mec/mech172x/CMakeLists.txt @@ -0,0 +1,11 @@ +# +# Copyright (c) 2024, Microchip Technology Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +zephyr_include_directories(${ZEPHYR_BASE}/drivers) +zephyr_sources(soc.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/microchip/mec/mech172x/Kconfig b/soc/microchip/mec/mech172x/Kconfig new file mode 100644 index 00000000000..0bc04fbed20 --- /dev/null +++ b/soc/microchip/mec/mech172x/Kconfig @@ -0,0 +1,21 @@ +# Microchip MECH172X MCU core series using MEC5 HAL and DTSI + +# Copyright (c) 2024 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_MECH172X + select ARM + select CPU_CORTEX_M4 + select CPU_CORTEX_M_HAS_DWT + select CPU_HAS_FPU + select CPU_HAS_ARM_MPU + select HAS_SWO + select HAS_MEC5_HAL + select HAS_PM + +if SOC_SERIES_MECH172X + +config RTOS_TIMER + bool "MECH172x RTOS Timer(32KHz) as kernel timer" + +endif # SOC_SERIES_MECH172X diff --git a/soc/microchip/mec/mech172x/Kconfig.defconfig.mech1723nlj b/soc/microchip/mec/mech172x/Kconfig.defconfig.mech1723nlj new file mode 100644 index 00000000000..fe25daf3a93 --- /dev/null +++ b/soc/microchip/mec/mech172x/Kconfig.defconfig.mech1723nlj @@ -0,0 +1,16 @@ +# Copyright (c) 2024 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +# Microchip MECH1723N-LJ MCU using MEC5 HAL +# N = 416KB total SRAM +# LJ = 176 pin package + +if SOC_MECH1723_NLJ + +config GPIO + default y + +config PINCTRL + default y + +endif # SOC_MECH1723_NLJ diff --git a/soc/microchip/mec/mech172x/Kconfig.defconfig.mech1723nsz b/soc/microchip/mec/mech172x/Kconfig.defconfig.mech1723nsz new file mode 100644 index 00000000000..b13f40a231f --- /dev/null +++ b/soc/microchip/mec/mech172x/Kconfig.defconfig.mech1723nsz @@ -0,0 +1,16 @@ +# Copyright (c) 2024 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +# Microchip MECH1723N-SZ MCU using MEC5 HAL +# N = 416KB total SRAM +# SZ = 144 pin package + +if SOC_MECH1723_NSZ + +config GPIO + default y + +config PINCTRL + default y + +endif # SOC_MECH1723_NSZ diff --git a/soc/microchip/mec/mech172x/Kconfig.defconfig.series b/soc/microchip/mec/mech172x/Kconfig.defconfig.series new file mode 100644 index 00000000000..5bbc8bb5df1 --- /dev/null +++ b/soc/microchip/mec/mech172x/Kconfig.defconfig.series @@ -0,0 +1,19 @@ +# Copyright (c) 2024 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +# Microchip MECH172x MCU series configuration options + +if SOC_SERIES_MECH172X + +config NUM_IRQS + # must be >= the highest interrupt number used + # - include the UART interrupts + # All NVIC external sources. + default 181 + +rsource "Kconfig.defconfig.mech172*" + +config CORTEX_M_SYSTICK + depends on !RTOS_TIMER + +endif # SOC_SERIES_MECH172X diff --git a/soc/microchip/mec/mech172x/Kconfig.soc b/soc/microchip/mec/mech172x/Kconfig.soc new file mode 100644 index 00000000000..3e3a210cf6c --- /dev/null +++ b/soc/microchip/mec/mech172x/Kconfig.soc @@ -0,0 +1,25 @@ +# Copyright (c) 2024 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +# Microchip MECH172x MCU core series + +config SOC_SERIES_MECH172X + bool + select SOC_FAMILY_MICROCHIP_MEC + help + Enable support for Microchip MEC Cortex-M4F MCU series + +config SOC_SERIES + default "mech172x" if SOC_SERIES_MECH172X + +config SOC_MECH1723_NLJ + bool + select SOC_SERIES_MECH172X + +config SOC_MECH1723_NSZ + bool + select SOC_SERIES_MECH172X + +config SOC + default "mech1723_nlj" if SOC_MECH1723_NLJ + default "mech1723_nsz" if SOC_MECH1723_NSZ diff --git a/soc/microchip/mec/mech172x/soc.c b/soc/microchip/mec/mech172x/soc.c new file mode 100644 index 00000000000..6d7a502b082 --- /dev/null +++ b/soc/microchip/mec/mech172x/soc.c @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2024 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +static int soc_init(void) +{ + mec5_soc_common_init(); + return 0; +} + +/* Enabling HW debug and initializing the MEC interrupt aggregator should be done + * before driver are loaded to not overwrite driver interrupt configuration. + * Use early initialization category called soon after Zephyr z_cstart and before + * Zephyr starts making driver initialization calls. + */ +SYS_INIT(soc_init, EARLY, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); diff --git a/soc/microchip/mec/mech172x/soc.h b/soc/microchip/mec/mech172x/soc.h new file mode 100644 index 00000000000..b0a2a46eef8 --- /dev/null +++ b/soc/microchip/mec/mech172x/soc.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2024 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __MEC5_SOC_H +#define __MEC5_SOC_H + +#define SYSCLK_DEFAULT_IOSC_HZ MHZ(96) + +#ifndef _ASMLANGUAGE + +#include "device_mec5.h" + +/* common SoC API */ +#include "soc_dt.h" +#include "soc_espi_channels.h" +#include "soc_gpio.h" +#include "soc_pcr.h" +#include "soc_pins.h" + +#endif + +#endif diff --git a/soc/microchip/mec/soc.yml b/soc/microchip/mec/soc.yml index 6c20b24ff9f..b3c68a80ed0 100644 --- a/soc/microchip/mec/soc.yml +++ b/soc/microchip/mec/soc.yml @@ -8,3 +8,15 @@ family: socs: - name: mec172x_nsz - name: mec172x_nlj + - name: mec174x + socs: + - name: mec1743_qlj + - name: mec1743_qsz + - name: mec175x + socs: + - name: mec1753_qlj + - name: mec1753_qsz + - name: mech172x + socs: + - name: mech1723_nlj + - name: mech1723_nsz diff --git a/soc/nordic/CMakeLists.txt b/soc/nordic/CMakeLists.txt index 9797d2e717a..f1ad19476f0 100644 --- a/soc/nordic/CMakeLists.txt +++ b/soc/nordic/CMakeLists.txt @@ -8,9 +8,22 @@ endif() zephyr_library_sources( validate_base_addresses.c + validate_binding_headers.c validate_enabled_instances.c ) +# Include dt-bindings headers into the build. This lets us validate all required +# DT values against the MDK, without having to conditionally include different +# headers for different SoCs. +set(dt_binding_includes ${DTS_INCLUDE_FILES}) +list(FILTER dt_binding_includes INCLUDE REGEX "/dt-bindings/.*\.h$") +list(TRANSFORM dt_binding_includes PREPEND "-include;") +set_source_files_properties( + validate_binding_headers.c + DIRECTORY ${CMAKE_CURRENT_LIST_DIR} + PROPERTIES COMPILE_OPTIONS "${dt_binding_includes}" +) + if(CONFIG_SOC_HAS_TIMING_FUNCTIONS AND NOT CONFIG_BOARD_HAS_TIMING_FUNCTIONS) if(CONFIG_TIMING_FUNCTIONS) # Use nRF-specific timing calculations only if DWT is not present diff --git a/soc/nordic/Kconfig.sysbuild b/soc/nordic/Kconfig.sysbuild new file mode 100644 index 00000000000..f146dac821e --- /dev/null +++ b/soc/nordic/Kconfig.sysbuild @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +rsource "common/vpr/Kconfig.sysbuild" diff --git a/soc/nordic/common/vpr/CMakeLists.txt b/soc/nordic/common/vpr/CMakeLists.txt index d418954eebc..cf14c817a1b 100644 --- a/soc/nordic/common/vpr/CMakeLists.txt +++ b/soc/nordic/common/vpr/CMakeLists.txt @@ -3,6 +3,6 @@ zephyr_include_directories(.) -zephyr_library_sources(soc_idle.c soc_irq.S soc_irq.c vector.S) +zephyr_library_sources(soc_context.S soc_idle.c soc_init.c) set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/riscv/common/linker.ld CACHE INTERNAL "") diff --git a/soc/nordic/common/vpr/Kconfig b/soc/nordic/common/vpr/Kconfig index 35d203c42dc..d3a8b7f5261 100644 --- a/soc/nordic/common/vpr/Kconfig +++ b/soc/nordic/common/vpr/Kconfig @@ -5,14 +5,17 @@ config RISCV_CORE_NORDIC_VPR bool "RISC-V Nordic VPR core" default y depends on DT_HAS_NORDIC_VPR_ENABLED - select RISCV select ATOMIC_OPERATIONS_C + select RISCV + select RISCV_PRIVILEGED + select RISCV_VECTORED_MODE select RISCV_ISA_RV32E select RISCV_ISA_EXT_M select RISCV_ISA_EXT_C select RISCV_ISA_EXT_ZICSR select RISCV_ISA_EXT_ZIFENCEI select RISCV_SOC_HAS_ISR_STACKING + select RISCV_HAS_CLIC select RISCV_SOC_CONTEXT_SAVE select HAS_FLASH_LOAD_OFFSET select ARCH_CPU_IDLE_CUSTOM diff --git a/soc/nordic/common/vpr/Kconfig.sysbuild b/soc/nordic/common/vpr/Kconfig.sysbuild new file mode 100644 index 00000000000..84fbad22f26 --- /dev/null +++ b/soc/nordic/common/vpr/Kconfig.sysbuild @@ -0,0 +1,11 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config VPR_LAUNCHER + bool "VPR launcher" + default y + depends on (SOC_NRF54H20_CPUPPR || SOC_NRF54L15_ENGA_CPUFLPR) + help + Include VPR launcher in build. + VPR launcher is a minimal sample built for an ARM core that starts given VPR core. + It is based on samples/basic/minimal with an appropriate snippet. diff --git a/soc/nordic/common/vpr/soc_context.S b/soc/nordic/common/vpr/soc_context.S new file mode 100644 index 00000000000..82c8ecfe598 --- /dev/null +++ b/soc/nordic/common/vpr/soc_context.S @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2024 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +GTEXT(__soc_save_context) +GTEXT(__soc_restore_context) + +SECTION_FUNC(exception.other, __soc_save_context) + csrr t0, 0x347 + sw t0, __soc_esf_t_minttresh_OFFSET(a0) + + ret + +SECTION_FUNC(exception.other, __soc_restore_context) + lw t0, __soc_esf_t_minttresh_OFFSET(a0) + csrw 0x347, t0 + + ret diff --git a/soc/nordic/common/vpr/soc_init.c b/soc/nordic/common/vpr/soc_init.c new file mode 100644 index 00000000000..c224feebac4 --- /dev/null +++ b/soc/nordic/common/vpr/soc_init.c @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2024 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +static int vpr_init(void) +{ + /* RT peripherals for VPR all share one enable. + * To prevent redundant calls, do it here once. + */ + nrf_vpr_csr_rtperiph_enable_set(true); + + return 0; +} + +SYS_INIT(vpr_init, PRE_KERNEL_1, 0); diff --git a/soc/nordic/common/vpr/soc_irq.S b/soc/nordic/common/vpr/soc_irq.S deleted file mode 100644 index 0e9db48d9b4..00000000000 --- a/soc/nordic/common/vpr/soc_irq.S +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2024 Nordic Semiconductor ASA - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include - -/* Exports */ -GTEXT(__soc_handle_irq) -GTEXT(__soc_save_context) -GTEXT(__soc_restore_context) - -/* - * No need to clear anything, pending bit is cleared by HW. - */ -SECTION_FUNC(exception.other, __soc_handle_irq) - ret - -SECTION_FUNC(exception.other, __soc_save_context) - csrr t0, 0x347 - sw t0, __soc_esf_t_minttresh_OFFSET(a0) - - ret - -SECTION_FUNC(exception.other, __soc_restore_context) - lw t0, __soc_esf_t_minttresh_OFFSET(a0) - csrw 0x347, t0 - - ret diff --git a/soc/nordic/common/vpr/soc_irq.c b/soc/nordic/common/vpr/soc_irq.c deleted file mode 100644 index 88655f6efa0..00000000000 --- a/soc/nordic/common/vpr/soc_irq.c +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (C) 2024 Nordic Semiconductor ASA - * SPDX-License-Identifier: Apache-2.0 - */ - -#include - -void arch_irq_enable(unsigned int irq) -{ - nrf_vpr_clic_int_enable_set(NRF_VPRCLIC, irq, true); -} - -void arch_irq_disable(unsigned int irq) -{ - nrf_vpr_clic_int_enable_set(NRF_VPRCLIC, irq, false); -} - -void arch_irq_priority_set(unsigned int irq, unsigned int prio) -{ - nrf_vpr_clic_int_priority_set(NRF_VPRCLIC, irq, prio); -} - -int arch_irq_is_enabled(unsigned int irq) -{ - return nrf_vpr_clic_int_enable_check(NRF_VPRCLIC, irq); -} diff --git a/soc/nordic/common/vpr/vector.S b/soc/nordic/common/vpr/vector.S deleted file mode 100644 index 84feb3e56b3..00000000000 --- a/soc/nordic/common/vpr/vector.S +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (C) 2024 Nordic Semiconductor ASA - * SPDX-License-Identifier: Apache-2.0 - */ - -#include - -/* Imports */ -GTEXT(__initialize) - -/* Exports */ -GTEXT(__start) - -SECTION_FUNC(vectors, __start) - /* Set mtvec.base (mtvec.mode is RO, no need to mask it). */ - la t0, _isr_wrapper - csrw mtvec, t0 - - /* Set mtvt. */ - la t0, _irq_vector_table - csrw 0x307, t0 - - /* Call into Zephyr initialization. */ - tail __initialize diff --git a/soc/nordic/nrf53/soc_cpu_idle.h b/soc/nordic/nrf53/soc_cpu_idle.h index c02c9451419..d17b0e15445 100644 --- a/soc/nordic/nrf53/soc_cpu_idle.h +++ b/soc/nordic/nrf53/soc_cpu_idle.h @@ -8,19 +8,22 @@ * @file SoC extensions of cpu_idle.S for the Nordic Semiconductor nRF53 processors family. */ - -#if defined(_ASMLANGUAGE) +#define SOC_ON_EXIT_CPU_IDLE_4 \ + __NOP(); \ + __NOP(); \ + __NOP(); \ + __NOP(); +#define SOC_ON_EXIT_CPU_IDLE_8 \ + SOC_ON_EXIT_CPU_IDLE_4 \ + SOC_ON_EXIT_CPU_IDLE_4 #if defined(CONFIG_SOC_NRF53_ANOMALY_168_WORKAROUND_FOR_EXECUTION_FROM_RAM) #define SOC_ON_EXIT_CPU_IDLE \ - .rept 26; \ - nop; \ - .endr + SOC_ON_EXIT_CPU_IDLE_8; \ + SOC_ON_EXIT_CPU_IDLE_8; \ + SOC_ON_EXIT_CPU_IDLE_8; \ + __NOP(); \ + __NOP(); #elif defined(CONFIG_SOC_NRF53_ANOMALY_168_WORKAROUND) -#define SOC_ON_EXIT_CPU_IDLE \ - .rept 8; \ - nop; \ - .endr +#define SOC_ON_EXIT_CPU_IDLE SOC_ON_EXIT_CPU_IDLE_8 #endif - -#endif /* _ASMLANGUAGE */ diff --git a/soc/nordic/nrf54h/CMakeLists.txt b/soc/nordic/nrf54h/CMakeLists.txt index 77290a332da..88e45de0046 100644 --- a/soc/nordic/nrf54h/CMakeLists.txt +++ b/soc/nordic/nrf54h/CMakeLists.txt @@ -2,10 +2,13 @@ # SPDX-License-Identifier: Apache-2.0 if(CONFIG_ARM) - zephyr_include_directories(.) zephyr_library_sources(soc.c) endif() +zephyr_library_sources_ifdef(CONFIG_CPU_HAS_CUSTOM_FIXED_SOC_MPU_REGIONS mpu_regions.c) + +zephyr_include_directories(.) + # Ensure that image size aligns with 16 bytes so that MRAMC finalizes all writes # for the image correctly zephyr_linker_sources(SECTIONS SORT_KEY zzz_place_align_at_end align.ld) diff --git a/soc/nordic/nrf54h/Kconfig b/soc/nordic/nrf54h/Kconfig index 8925669ae0d..a7eb08d9c9f 100644 --- a/soc/nordic/nrf54h/Kconfig +++ b/soc/nordic/nrf54h/Kconfig @@ -4,6 +4,7 @@ # SPDX-License-Identifier: Apache-2.0 config SOC_SERIES_NRF54HX + select HAS_NRFS select HAS_NRFX select HAS_NORDIC_DRIVERS @@ -16,7 +17,13 @@ config SOC_NRF54H20_CPUAPP select CPU_HAS_DCACHE select CPU_HAS_ICACHE select CPU_HAS_FPU + select CPU_HAS_CUSTOM_FIXED_SOC_MPU_REGIONS select HAS_SEGGER_RTT if ZEPHYR_SEGGER_MODULE + select NRFS_HAS_CLOCK_SERVICE + select NRFS_HAS_DVFS_SERVICE + select NRFS_HAS_MRAM_SERVICE + select NRFS_HAS_TEMP_SERVICE + select NRFS_HAS_VBUS_DETECTOR_SERVICE config SOC_NRF54H20_CPURAD select ARM @@ -27,7 +34,11 @@ config SOC_NRF54H20_CPURAD select CPU_HAS_DCACHE select CPU_HAS_ICACHE select CPU_HAS_FPU + select CPU_HAS_CUSTOM_FIXED_SOC_MPU_REGIONS select HAS_SEGGER_RTT if ZEPHYR_SEGGER_MODULE + select NRFS_HAS_CLOCK_SERVICE + select NRFS_HAS_MRAM_SERVICE + select NRFS_HAS_TEMP_SERVICE config SOC_NRF54H20_CPUPPR depends on RISCV_CORE_NORDIC_VPR diff --git a/soc/nordic/nrf54h/mpu_regions.c b/soc/nordic/nrf54h/mpu_regions.c new file mode 100644 index 00000000000..a19d2d33f10 --- /dev/null +++ b/soc/nordic/nrf54h/mpu_regions.c @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#define USBHS_BASE DT_REG_ADDR_BY_NAME(DT_NODELABEL(usbhs), core) +#define USBHS_SIZE DT_REG_SIZE_BY_NAME(DT_NODELABEL(usbhs), core) + +static struct arm_mpu_region mpu_regions[] = { + MPU_REGION_ENTRY("FLASH_0", + CONFIG_FLASH_BASE_ADDRESS, + REGION_FLASH_ATTR(CONFIG_FLASH_BASE_ADDRESS, + CONFIG_FLASH_SIZE * 1024)), + MPU_REGION_ENTRY("SRAM_0", + CONFIG_SRAM_BASE_ADDRESS, + REGION_RAM_ATTR(CONFIG_SRAM_BASE_ADDRESS, + CONFIG_SRAM_SIZE * 1024)), + +#if DT_NODE_HAS_STATUS(DT_NODELABEL(usbhs), okay) + MPU_REGION_ENTRY("USBHS_CORE", USBHS_BASE, + REGION_RAM_NOCACHE_ATTR(USBHS_BASE, USBHS_SIZE)), +#endif +}; + +const struct arm_mpu_config mpu_config = { + .num_regions = ARRAY_SIZE(mpu_regions), + .mpu_regions = mpu_regions, +}; diff --git a/soc/nordic/nrf54l/Kconfig b/soc/nordic/nrf54l/Kconfig index 640e090005d..f5e62021e1e 100644 --- a/soc/nordic/nrf54l/Kconfig +++ b/soc/nordic/nrf54l/Kconfig @@ -19,6 +19,9 @@ config SOC_NRF54L15_ENGA_CPUAPP select HAS_HW_NRF_RADIO_IEEE802154 select HAS_POWEROFF +config SOC_NRF54L15_ENGA_CPUFLPR + depends on RISCV_CORE_NORDIC_VPR + if SOC_SERIES_NRF54LX config SOC_NRF54LX_SKIP_CLOCK_CONFIG diff --git a/soc/nordic/nrf54l/Kconfig.defconfig b/soc/nordic/nrf54l/Kconfig.defconfig index 39ed9025ea0..b6ba2a07a87 100644 --- a/soc/nordic/nrf54l/Kconfig.defconfig +++ b/soc/nordic/nrf54l/Kconfig.defconfig @@ -7,10 +7,26 @@ if SOC_SERIES_NRF54LX rsource "Kconfig.defconfig.nrf54l*" +if ARM + config CORTEX_M_SYSTICK default !NRF_GRTC_TIMER config CACHE_NRF_CACHE default y if EXTERNAL_CACHE +endif # ARM + +if RISCV + +DT_CHOSEN_Z_SRAM = zephyr,sram +DT_CHOSEN_Z_CODE = zephyr,code-partition + +config BUILD_OUTPUT_ADJUST_LMA + depends on !XIP + default "$(dt_chosen_partition_addr_hex,$(DT_CHOSEN_Z_CODE)) - \ + $(dt_chosen_reg_addr_hex,$(DT_CHOSEN_Z_SRAM))" + +endif # RISCV + endif # SOC_SERIES_NRF54LX diff --git a/soc/nordic/nrf54l/Kconfig.defconfig.nrf54l15_enga_cpuflpr b/soc/nordic/nrf54l/Kconfig.defconfig.nrf54l15_enga_cpuflpr new file mode 100644 index 00000000000..de1a8519225 --- /dev/null +++ b/soc/nordic/nrf54l/Kconfig.defconfig.nrf54l15_enga_cpuflpr @@ -0,0 +1,15 @@ +# Nordic Semiconductor nRF54L15 MCU + +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if SOC_NRF54L15_ENGA_CPUFLPR + +config RISCV_HAS_CPU_IDLE + bool + +config NUM_IRQS + int + default 287 + +endif # SOC_NRF54L15_ENGA_CPUFLPR diff --git a/soc/nordic/nrf54l/Kconfig.soc b/soc/nordic/nrf54l/Kconfig.soc index 05ce9db0a3e..506db433b2b 100644 --- a/soc/nordic/nrf54l/Kconfig.soc +++ b/soc/nordic/nrf54l/Kconfig.soc @@ -21,5 +21,11 @@ config SOC_NRF54L15_ENGA_CPUAPP help NRF54L15 ENGA CPUAPP +config SOC_NRF54L15_ENGA_CPUFLPR + bool + select SOC_NRF54L15_ENGA + help + NRF54L15 ENGA CPUFLPR + config SOC default "nrf54l15" if SOC_NRF54L15 diff --git a/soc/nordic/nrf54l/soc.c b/soc/nordic/nrf54l/soc.c index 6af0ff4ebcd..94f48c14233 100644 --- a/soc/nordic/nrf54l/soc.c +++ b/soc/nordic/nrf54l/soc.c @@ -18,19 +18,23 @@ #include #include +#if defined(NRF_APPLICATION) #include #include #include #include #include +#endif #include #include LOG_MODULE_REGISTER(soc, CONFIG_SOC_LOG_LEVEL); +#if defined(NRF_APPLICATION) #define LFXO_NODE DT_NODELABEL(lfxo) #define HFXO_NODE DT_NODELABEL(hfxo) +#endif static int nordicsemi_nrf54l_init(void) { @@ -39,6 +43,7 @@ static int nordicsemi_nrf54l_init(void) */ SystemCoreClockUpdate(); +#if defined(NRF_APPLICATION) /* Enable ICACHE */ sys_cache_instr_enable(); @@ -120,6 +125,7 @@ static int nordicsemi_nrf54l_init(void) #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 */ +#endif /* NRF_APPLICATION */ return 0; } diff --git a/soc/nordic/soc.yml b/soc/nordic/soc.yml index f7fb6bfec71..d3400f78468 100644 --- a/soc/nordic/soc.yml +++ b/soc/nordic/soc.yml @@ -24,6 +24,7 @@ family: - name: nrf54l15 cpuclusters: - name: cpuapp + - name: cpuflpr - name: nrf54h socs: - name: nrf54h20 diff --git a/soc/nordic/sysbuild.cmake b/soc/nordic/sysbuild.cmake new file mode 100644 index 00000000000..03db1a5ad18 --- /dev/null +++ b/soc/nordic/sysbuild.cmake @@ -0,0 +1,31 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if(SB_CONFIG_VPR_LAUNCHER) + set(launcher_core "cpuapp") + string(REPLACE "/" ";" launcher_quals ${BOARD_QUALIFIERS}) + list(LENGTH launcher_quals launcher_quals_len) + list(GET launcher_quals 1 launcher_soc) + list(GET launcher_quals 2 launcher_vpr) + + string(REPLACE "cpu" "" launcher_vpr ${launcher_vpr}) + + if(launcher_quals_len EQUAL 4) + list(GET launcher_quals 3 launcher_variant) + set(launcher_vpr ${launcher_vpr}-${launcher_variant}) + endif() + + string(CONCAT launcher_board ${BOARD} "/" ${launcher_soc} "/" ${launcher_core}) + + set(image "vpr_launcher") + + ExternalZephyrProject_Add( + APPLICATION ${image} + SOURCE_DIR ${ZEPHYR_BASE}/samples/basic/minimal + BOARD ${launcher_board} + ) + + string(CONCAT launcher_snippet "nordic-" ${launcher_vpr}) + + sysbuild_cache_set(VAR ${image}_SNIPPET APPEND REMOVE_DUPLICATES ${launcher_snippet}) +endif() diff --git a/soc/nordic/validate_base_addresses.c b/soc/nordic/validate_base_addresses.c index 6874fe9c62e..4fca3501e27 100644 --- a/soc/nordic/validate_base_addresses.c +++ b/soc/nordic/validate_base_addresses.c @@ -331,7 +331,13 @@ CHECK_DT_REG(usbhs, NRF_USBHS); CHECK_DT_REG(usbhs_core, NRF_USBHSCORE0); CHECK_DT_REG(usbreg, NRF_USBREGULATOR); CHECK_DT_REG(vmc, NRF_VMC); +CHECK_DT_REG(cpuflpr_clic, NRF_FLPR_VPRCLIC); +#if defined(CONFIG_SOC_NRF54L15) +CHECK_DT_REG(cpuflpr_vpr, NRF_VPR00); +#elif defined(CONFIG_SOC_NRF54H20) +CHECK_DT_REG(cpuflpr_vpr, NRF_VPR121); CHECK_DT_REG(cpuppr_vpr, NRF_VPR130); +#endif 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); diff --git a/soc/nordic/validate_binding_headers.c b/soc/nordic/validate_binding_headers.c new file mode 100644 index 00000000000..98ffffe8670 --- /dev/null +++ b/soc/nordic/validate_binding_headers.c @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * This file validates definitions found in dt-bindings headers against their + * expected values from MDK, which may be provided in the form of C types. + * + * Note: all dt-bindings headers which have been included by DTS in this build + * are automagically included in this file as well. See CMakeLists.txt. + */ + +#include +#include + +#include + +/** + * Domain IDs. See: + * - dt-bindings/misc/nordic-domain-id-nrf54h20.h + */ +#if defined(NRF_DOMAIN_ID_APPLICATION) +BUILD_ASSERT(NRF_DOMAIN_ID_APPLICATION == NRF_DOMAIN_APPLICATION); +#endif +#if defined(NRF_DOMAIN_ID_RADIOCORE) +BUILD_ASSERT(NRF_DOMAIN_ID_RADIOCORE == NRF_DOMAIN_RADIOCORE); +#endif +#if defined(NRF_DOMAIN_ID_GLOBALFAST) +BUILD_ASSERT(NRF_DOMAIN_ID_GLOBALFAST == NRF_DOMAIN_GLOBALFAST); +#endif +#if defined(NRF_DOMAIN_ID_GLOBALSLOW) +BUILD_ASSERT(NRF_DOMAIN_ID_GLOBALSLOW == NRF_DOMAIN_GLOBALSLOW); +#endif + +/** + * Owner IDs. See: + * - dt-bindings/misc/nordic-owner-id-nrf54h20.h + */ +#if defined(NRF_OWNER_ID_NONE) +BUILD_ASSERT(NRF_OWNER_ID_NONE == NRF_OWNER_NONE); +#endif +#if defined(NRF_OWNER_ID_APPLICATION) +BUILD_ASSERT(NRF_OWNER_ID_APPLICATION == NRF_OWNER_APPLICATION); +#endif +#if defined(NRF_OWNER_ID_RADIOCORE) +BUILD_ASSERT(NRF_OWNER_ID_RADIOCORE == NRF_OWNER_RADIOCORE); +#endif diff --git a/soc/nordic/validate_rram_partitions.c b/soc/nordic/validate_rram_partitions.c index f35d9cf73f3..99f75f291af 100644 --- a/soc/nordic/validate_rram_partitions.c +++ b/soc/nordic/validate_rram_partitions.c @@ -43,7 +43,7 @@ /* clang-format off */ -#define RRAM_BASE REG_ADDR_NS(DT_NODELABEL(rram0)) +#define RRAM_BASE REG_ADDR_NS(DT_CHOSEN(zephyr_flash)) #define RRAM_CONTROLLER DT_NODELABEL(rram_controller) #if !DT_NODE_EXISTS(RRAM_CONTROLLER) diff --git a/soc/nuvoton/npcx/common/reg/reg_def.h b/soc/nuvoton/npcx/common/reg/reg_def.h index f13dfd507f8..ae02a6e506d 100644 --- a/soc/nuvoton/npcx/common/reg/reg_def.h +++ b/soc/nuvoton/npcx/common/reg/reg_def.h @@ -78,7 +78,10 @@ struct cdcg_reg { volatile uint8_t reserved7; /* 0x014: HFCG Bus Clock Dividers */ volatile uint8_t HFCBCD2; - volatile uint8_t reserved8[235]; + volatile uint8_t reserved12[8]; + /* 0x01d: HFCG Bus Clock Dividers */ + volatile uint8_t HFCBCD3; + volatile uint8_t reserved8[226]; /* Low Frequency Clock Generator (LFCG) registers */ /* 0x100: LFCG Control */ @@ -373,6 +376,9 @@ struct uart_reg { #define NPCX_UFRS_PSEL_FIELD FIELD(4, 2) #define NPCX_UFRS_PEN 6 #define NPCX_UMDSL_FIFO_MD 0 +#define NPCX_UMDSL_ETD 4 +#define NPCX_UMDSL_ERD 5 + #define NPCX_UFTSTS_TEMPTY_LVL FIELD(0, 5) #define NPCX_UFTSTS_TEMPTY_LVL_STS 5 #define NPCX_UFTSTS_TFIFO_EMPTY_STS 6 @@ -1756,4 +1762,231 @@ struct spip_reg { #define NPCX_SPIP_STAT_BSY 0 #define NPCX_SPIP_STAT_RBF 1 +/* Software-triggered Pheripheral Reset Controller Register */ +struct swrst_reg { + /* 0x000: Software Reset Trigger */ + volatile uint16_t SWRST_TRG; + volatile uint8_t reserved1[2]; + volatile uint32_t SWRST_CTL[4]; +}; + +/* Improved Inter Integrated Circuit (I3C) device registers */ +struct i3c_reg { + /* 0x000: Controller Configuration */ + volatile uint32_t MCONFIG; + /* 0x004: Target Configuration */ + volatile uint32_t CONFIG; + volatile uint32_t reserved1[31]; + /* 0x084: Controller Control */ + volatile uint32_t MCTRL; + /* 0x088: Controller Status */ + volatile uint32_t MSTATUS; + /* 0x08C: IBI Registry and Rules */ + volatile uint32_t IBIRULES; + /* 0x090: Controller Interrupt Enable Set */ + volatile uint32_t MINTSET; + /* 0x094: Controller Interrupt Enable Clear */ + volatile uint32_t MINTCLR; + /* 0x098: Controller Interrupt Masked */ + volatile uint32_t MINTMASKED; + /* 0x09C: Controller Error and Warning */ + volatile uint32_t MERRWARN; + /* 0x0A0: Controller DMA Control */ + volatile uint32_t MDMACTRL; + volatile uint32_t reserved2[2]; + /* 0x0AC: Controller Data Control */ + volatile uint32_t MDATACTRL; + /* 0x0B0: Controller Write Byte Data */ + volatile uint32_t MWDATAB; + /* 0x0B4: Controller Write Byte Data as End */ + volatile uint32_t MWDATABE; + /* 0x0B8: Controller Write Half-Word Data */ + volatile uint32_t MWDATAH; + /* 0x0BC: Controller Write Half-Word Data as End */ + volatile uint32_t MWDATAHE; + /* 0x0C0: Controller Read Byte Data */ + volatile uint32_t MRDATAB; + volatile uint32_t reserved3; + /* 0x0C8: Controller Read Half-Word Data */ + volatile uint32_t MRDATAH; + volatile uint32_t reserved4[3]; + /* 0x0D8: Start or Continue DDR Message */ + volatile uint32_t MWMSG_DDR; + /* 0x0DC: Read DDR Message Data */ + volatile uint32_t MRMSG_DDR; + volatile uint32_t reserved5; + /* 0x0E4: Controller Dynamic Address */ + volatile uint32_t MDYNADDR; +}; + +/* I3C register fields */ +#define NPCX_I3C_CONFIG_BAMATCH FIELD(16, 7) +#define NPCX_I3C_MCONFIG_CTRENA FIELD(0, 2) +#define NPCX_I3C_MCONFIG_DISTO 3 +#define NPCX_I3C_MCONFIG_HKEEP FIELD(4, 2) /* Must be '11' */ +#define NPCX_I3C_MCONFIG_ODSTOP 6 +#define NPCX_I3C_MCONFIG_PPBAUD FIELD(8, 4) +#define NPCX_I3C_MCONFIG_PPLOW FIELD(12, 4) +#define NPCX_I3C_MCONFIG_ODBAUD FIELD(16, 8) +#define NPCX_I3C_MCONFIG_ODHPP 24 +#define NPCX_I3C_MCONFIG_SKEW FIELD(25, 3) +#define NPCX_I3C_MCONFIG_I2CBAUD FIELD(28, 4) +#define NPCX_I3C_MCTRL_REQUEST FIELD(0, 3) +#define NPCX_I3C_MCTRL_TYPE FIELD(4, 2) +#define NPCX_I3C_MCTRL_IBIRESP FIELD(6, 2) +#define NPCX_I3C_MCTRL_DIR 8 +#define NPCX_I3C_MCTRL_ADDR FIELD(9, 7) +#define NPCX_I3C_MCTRL_RDTERM FIELD(16, 8) +#define NPCX_I3C_MSTATUS_STATE FIELD(0, 3) +#define NPCX_I3C_MSTATUS_BETWEEN 4 +#define NPCX_I3C_MSTATUS_NACKED 5 +#define NPCX_I3C_MSTATUS_IBITYPE FIELD(6, 2) +#define NPCX_I3C_MSTATUS_TGTSTART 8 +#define NPCX_I3C_MSTATUS_MCTRLDONE 9 +#define NPCX_I3C_MSTATUS_COMPLETE 10 +#define NPCX_I3C_MSTATUS_RXPEND 11 +#define NPCX_I3C_MSTATUS_TXNOTFULL 12 +#define NPCX_I3C_MSTATUS_IBIWON 13 +#define NPCX_I3C_MSTATUS_ERRWARN 15 +#define NPCX_I3C_MSTATUS_NOWCNTLR 19 +#define NPCX_I3C_MSTATUS_IBIADDR FIELD(24, 7) +#define NPCX_I3C_IBIRULES_MSB0 30 +#define NPCX_I3C_IBIRULES_NOBYTE 31 +#define NPCX_I3C_MINTSET_TGTSTART 8 +#define NPCX_I3C_MINTSET_MCTRLDONE 9 +#define NPCX_I3C_MINTSET_COMPLETE 10 +#define NPCX_I3C_MINTSET_RXPEND 11 +#define NPCX_I3C_MINTSET_TXNOTFULL 12 +#define NPCX_I3C_MINTSET_IBIWON 13 +#define NPCX_I3C_MINTSET_ERRWARN 15 +#define NPCX_I3C_MINTSET_NOWCNTLR 19 +#define NPCX_I3C_MINTCLR_TGTSTART 8 +#define NPCX_I3C_MINTCLR_MCTRLDONE 9 +#define NPCX_I3C_MINTCLR_COMPLETE 10 +#define NPCX_I3C_MINTCLR_RXPEND 11 +#define NPCX_I3C_MINTCLR_TXNOTFULL 12 +#define NPCX_I3C_MINTCLR_IBIWON 13 +#define NPCX_I3C_MINTCLR_ERRWARN 15 +#define NPCX_I3C_MINTCLR_NOWCNTLR 19 +#define NPCX_I3C_MDATACTRL_FLUSHTB 0 +#define NPCX_I3C_MDATACTRL_FLUSHFB 1 +#define NPCX_I3C_MDATACTRL_UNLOCK 3 +#define NPCX_I3C_MDATACTRL_TXTRIG FIELD(4, 2) +#define NPCX_I3C_MDATACTRL_RXTRIG FIELD(6, 2) +#define NPCX_I3C_MDATACTRL_TXCOUNT FIELD(16, 5) +#define NPCX_I3C_MDATACTRL_RXCOUNT FIELD(24, 5) +#define NPCX_I3C_MDATACTRL_TXFULL 30 +#define NPCX_I3C_MDATACTRL_RXEMPTY 31 +#define NPCX_I3C_MERRWARN_NACK 2 +#define NPCX_I3C_MERRWARN_WRABT 3 +#define NPCX_I3C_MERRWARN_TERM 4 +#define NPCX_I3C_MERRWARN_HPAR 9 +#define NPCX_I3C_MERRWARN_HCRC 10 +#define NPCX_I3C_MERRWARN_OREAD 16 +#define NPCX_I3C_MERRWARN_OWRITE 17 +#define NPCX_I3C_MERRWARN_MSGERR 18 +#define NPCX_I3C_MERRWARN_INVERQ 19 +#define NPCX_I3C_MERRWARN_TIMEOUT 20 +#define NPCX_I3C_MDMACTRL_DMAFB FIELD(0, 2) +#define NPCX_I3C_MDMACTRL_DMATB FIELD(2, 2) + + +/* MCONFIG options */ +#define MCONFIG_CTRENA_OFF 0x0 +#define MCONFIG_CTRENA_ON 0x1 +#define MCONFIG_CTRENA_CAPABLE 0x2 +#define MCONFIG_HKEEP_EXT_SDA_SCL 0x3 + +/* MCTRL options */ +#define MCTRL_REQUEST_NONE 0 /* None */ +#define MCTRL_REQUEST_EMITSTARTADDR 1 /* Emit a START */ +#define MCTRL_REQUEST_EMITSTOP 2 /* Emit a STOP */ +#define MCTRL_REQUEST_IBIACKNACK 3 /* Manually ACK or NACK an IBI */ +#define MCTRL_REQUEST_PROCESSDAA 4 /* Starts the DAA process */ +#define MCTRL_REQUEST_FORCEEXIT 6 /* Emit HDR Exit Pattern */ +/* Emits a START with address 7Eh when a slave pulls I3C_SDA low to request an IBI */ +#define MCTRL_REQUEST_AUTOIBI 7 + +/* ACK with mandatory byte determined by IBIRULES or ACK with no mandatory byte */ +#define MCTRL_IBIRESP_ACK 0 +#define MCTRL_IBIRESP_NACK 1 /* NACK */ +#define MCTRL_IBIRESP_ACK_MANDATORY 2 /* ACK with mandatory byte */ +#define MCTRL_IBIRESP_MANUAL 3 + +enum npcx_i3c_mctrl_type { + NPCX_I3C_MCTRL_TYPE_I3C, + NPCX_I3C_MCTRL_TYPE_I2C, + NPCX_I3C_MCTRL_TYPE_I3C_HDR_DDR, +}; + +/* MSTATUS options */ +#define MSTATUS_STATE_IDLE 0x0 +#define MSTATUS_STATE_TGTREQ 0x1 +#define MSTATUS_STATE_NORMACT 0x3 /* SDR message mode */ +#define MSTATUS_STATE_MSGDDR 0x4 +#define MSTATUS_STATE_DAA 0x5 +#define MSTATUS_STATE_IBIACK 0x6 +#define MSTATUS_STATE_IBIRCV 0x7 +#define MSTATUS_IBITYPE_NONE 0x0 +#define MSTATUS_IBITYPE_IBI 0x1 +#define MSTATUS_IBITYPE_CR 0x2 +#define MSTATUS_IBITYPE_HJ 0x3 + +/* IBIRULES */ +#define IBIRULES_ADDR_MSK 0x3F +#define IBIRULES_ADDR_SHIFT 0x6 + +/* MDMACTRL options */ +#define MDMA_DMAFB_DISABLE 0x0 +#define MDMA_DMAFB_EN_ONE_FRAME 0x1 +#define MDMA_DMAFB_EN_MANUAL 0x2 +#define MDMA_DMATB_DISABLE 0x0 +#define MDMA_DMATB_EN_ONE_FRAME 0x1 +#define MDMA_DMATB_EN_MANUAL 0x2 + +/* MDMA Controller registers */ +struct mdma_reg { + /* Channel 0 */ + /* 0x000: Channel 0 Control */ + volatile uint32_t MDMA_CTL0; + /* 0x004: Channel 0 Source Base Address */ + volatile uint32_t MDMA_SRCB0; + /* 0x008: Channel 0 Destination Base Address */ + volatile uint32_t MDMA_DSTB0; + /* 0x00C: Channel 0 Transfer Count */ + volatile uint32_t MDMA_TCNT0; + /* 0x010: reserved1 */ + volatile uint32_t reserved1; + /* 0x014: Channel 0 Current Destination */ + volatile uint32_t MDMA_CDST0; + /* 0x018: Channel 0 Current Transfer Count */ + volatile uint32_t MDMA_CTCNT0; + /* 0x01C: reserved2 */ + volatile uint32_t reserved2; + + /* Channel 1 */ + /* 0x020: Channel 1 Control */ + volatile uint32_t MDMA_CTL1; + /* 0x024: Channel 1 Source Base Address */ + volatile uint32_t MDMA_SRCB1; + /* 0x028: Channel 1 Destination Base Address */ + volatile uint32_t MDMA_DSTB1; + /* 0x02C: Channel 1 Transfer Count */ + volatile uint32_t MDMA_TCNT1; + /* 0x030: Channel 1 Current Source */ + volatile uint32_t MDMA_CSRC1; + /* 0x034: reserved3 */ + volatile uint32_t reserved3; + /* 0x038: Channel 1 Current Transfer Count */ + volatile uint32_t MDMA_CTCNT1; +}; + +/* MDMA register fields */ +#define NPCX_MDMA_CTL_MDMAEN 0 +#define NPCX_MDMA_CTL_MPD 1 +#define NPCX_MDMA_CTL_SIEN 8 +#define NPCX_MDMA_CTL_MPS 14 +#define NPCX_MDMA_CTL_TC 18 +#define NPCX_MDMA_TCNT_TFR_CNT FIELD(0, 12) + #endif /* _NUVOTON_NPCX_REG_DEF_H */ diff --git a/soc/nuvoton/npcx/common/registers.c b/soc/nuvoton/npcx/common/registers.c index 8c4ed132b46..00ee142b1a5 100644 --- a/soc/nuvoton/npcx/common/registers.c +++ b/soc/nuvoton/npcx/common/registers.c @@ -189,3 +189,38 @@ 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); + +/* SWRST register structure check */ +NPCX_REG_SIZE_CHECK(swrst_reg, 0x014); +NPCX_REG_OFFSET_CHECK(swrst_reg, SWRST_TRG, 0x000); +NPCX_REG_OFFSET_CHECK(swrst_reg, SWRST_CTL[0], 0x004); +NPCX_REG_OFFSET_CHECK(swrst_reg, SWRST_CTL[1], 0x008); +NPCX_REG_OFFSET_CHECK(swrst_reg, SWRST_CTL[2], 0x00c); +NPCX_REG_OFFSET_CHECK(swrst_reg, SWRST_CTL[3], 0x010); + +/* I3C register structure check */ +NPCX_REG_SIZE_CHECK(i3c_reg, 0x0E8); +NPCX_REG_OFFSET_CHECK(i3c_reg, MCONFIG, 0x000); +NPCX_REG_OFFSET_CHECK(i3c_reg, MCTRL, 0x084); +NPCX_REG_OFFSET_CHECK(i3c_reg, IBIRULES, 0x08C); +NPCX_REG_OFFSET_CHECK(i3c_reg, MINTSET, 0x090); +NPCX_REG_OFFSET_CHECK(i3c_reg, MINTCLR, 0x094); +NPCX_REG_OFFSET_CHECK(i3c_reg, MINTMASKED, 0x098); +NPCX_REG_OFFSET_CHECK(i3c_reg, MERRWARN, 0x09C); +NPCX_REG_OFFSET_CHECK(i3c_reg, MDATACTRL, 0x0AC); +NPCX_REG_OFFSET_CHECK(i3c_reg, MWDATAB, 0x0B0); +NPCX_REG_OFFSET_CHECK(i3c_reg, MWDATABE, 0x0B4); +NPCX_REG_OFFSET_CHECK(i3c_reg, MWDATAH, 0x0B8); +NPCX_REG_OFFSET_CHECK(i3c_reg, MWDATAHE, 0x0BC); +NPCX_REG_OFFSET_CHECK(i3c_reg, MRDATAB, 0x0C0); +NPCX_REG_OFFSET_CHECK(i3c_reg, MRDATAH, 0x0C8); +NPCX_REG_OFFSET_CHECK(i3c_reg, MWMSG_DDR, 0x0D8); +NPCX_REG_OFFSET_CHECK(i3c_reg, MRMSG_DDR, 0x0DC); +NPCX_REG_OFFSET_CHECK(i3c_reg, MDYNADDR, 0x0E4); + +/* MDMA register structure check */ +NPCX_REG_SIZE_CHECK(mdma_reg, 0x03C); +NPCX_REG_OFFSET_CHECK(mdma_reg, MDMA_SRCB0, 0x004); +NPCX_REG_OFFSET_CHECK(mdma_reg, MDMA_CTCNT0, 0x018); +NPCX_REG_OFFSET_CHECK(mdma_reg, MDMA_CTL1, 0x020); +NPCX_REG_OFFSET_CHECK(mdma_reg, MDMA_CTCNT1, 0x038); diff --git a/soc/nuvoton/npcx/common/soc_clock.h b/soc/nuvoton/npcx/common/soc_clock.h index d43a70d4529..4ec4c591b04 100644 --- a/soc/nuvoton/npcx/common/soc_clock.h +++ b/soc/nuvoton/npcx/common/soc_clock.h @@ -105,6 +105,16 @@ struct npcx_clk_cfg { #endif #endif /* CONFIG_CLOCK_CONTROL_NPCX_SUPP_FIU1 */ +/* I3C clock divider */ +#if (OFMCLK == MHZ(120)) /* MCLkD must between 40 mhz to 50 mhz*/ +#define MCLKD_SL 2 /* I3C_CLK = (MCLK / 3) */ +#elif (OFMCLK <= MHZ(100) && OFMCLK >= MHZ(80)) +#define MCLKD_SL 1 /* I3C_CLK = (MCLK / 2) */ +#else +#define MCLKD_SL 0 /* I3C_CLK = MCLK */ +#endif + + /* Get APB clock freq */ #define NPCX_APB_CLOCK(no) (APBSRC_CLK / (APB##no##DIV_VAL + 1)) @@ -158,6 +168,8 @@ struct npcx_clk_cfg { #else #define VAL_HFCBCD2 APB3DIV_VAL #endif /* APB4DIV_VAL */ +/* I3C1~I3C3 share the same configuration */ +#define VAL_HFCBCD3 MCLKD_SL /** * @brief Function to notify clock driver that backup the counter value of diff --git a/soc/nuvoton/npcx/common/soc_dt.h b/soc/nuvoton/npcx/common/soc_dt.h index 6bcf2e416b6..64ddcf5f1a4 100644 --- a/soc/nuvoton/npcx/common/soc_dt.h +++ b/soc/nuvoton/npcx/common/soc_dt.h @@ -80,6 +80,20 @@ .bit = DT_CLOCKS_CELL_BY_IDX(DT_DRV_INST(inst), i, bit), \ } +/** + * @brief Construct a npcx_clk_cfg structure from 'clocks' with the same clock 'name'. + * + * @param inst instance number for compatible defined in DT_DRV_COMPAT. + * @param name name of the clock + * @return npcx_clk_cfg item from 'clocks' property with the same clock 'name' + */ +#define NPCX_DT_CLK_CFG_ITEM_BY_NAME(inst, name) \ + { \ + .bus = DT_CLOCKS_CELL_BY_NAME(DT_DRV_INST(inst), name, bus), \ + .ctrl = DT_CLOCKS_CELL_BY_NAME(DT_DRV_INST(inst), name, ctl), \ + .bit = DT_CLOCKS_CELL_BY_NAME(DT_DRV_INST(inst), name, bit), \ + } + /** * @brief Length of 'clocks' property which type is 'phandle-array' * diff --git a/soc/nuvoton/npcx/common/soc_espi_taf.h b/soc/nuvoton/npcx/common/soc_espi_taf.h index a8755e080f7..90b98cbb62d 100644 --- a/soc/nuvoton/npcx/common/soc_espi_taf.h +++ b/soc/nuvoton/npcx/common/soc_espi_taf.h @@ -144,6 +144,8 @@ struct npcx_taf_head { uint8_t llen; }; +int npcx_init_taf(const struct device *dev, sys_slist_t *callbacks); + #ifdef __cplusplus } #endif diff --git a/soc/nuvoton/npcx/npcx9/Kconfig b/soc/nuvoton/npcx/npcx9/Kconfig index 25cee4381b7..dd93a355e93 100644 --- a/soc/nuvoton/npcx/npcx9/Kconfig +++ b/soc/nuvoton/npcx/npcx9/Kconfig @@ -11,3 +11,11 @@ config SOC_SERIES_NPCX9 select CPU_HAS_ARM_MPU select SOC_FAMILY_NPCX select HAS_PM + +config NPCX_VCC1_RST_HANG_WORKAROUND + bool + depends on SOC_NPCX9M7FB + default y + help + Workaround the issue "Possible Hang-Up After VCC1_RST Reset" + in the npcx9m7fb SoC errata. diff --git a/soc/nuvoton/npcx/npcx9/Kconfig.soc b/soc/nuvoton/npcx/npcx9/Kconfig.soc index 274aaddf1ec..c7abe79ffd4 100644 --- a/soc/nuvoton/npcx/npcx9/Kconfig.soc +++ b/soc/nuvoton/npcx/npcx9/Kconfig.soc @@ -48,11 +48,3 @@ config SOC default "npcx9m7f" if SOC_NPCX9M7F default "npcx9m7fb" if SOC_NPCX9M7FB default "npcx9mfp" if SOC_NPCX9MFP - -config NPCX_VCC1_RST_HANG_WORKAROUND - bool - depends on SOC_NPCX9M7FB - default y - help - Workaround the issue "Possible Hang-Up After VCC1_RST Reset" - in the npcx9m7fb SoC errata. diff --git a/soc/nuvoton/numaker/common/pinctrl_soc.h b/soc/nuvoton/numaker/common/pinctrl_soc.h index 4c12b81c94b..53f07b526ed 100644 --- a/soc/nuvoton/numaker/common/pinctrl_soc.h +++ b/soc/nuvoton/numaker/common/pinctrl_soc.h @@ -25,6 +25,7 @@ typedef struct pinctrl_soc_pin_t { uint32_t open_drain: 1; uint32_t schmitt_enable: 1; uint32_t slew_rate: 2; + uint32_t digital_disable: 1; } pinctrl_soc_pin_t; #define Z_PINCTRL_STATE_PIN_INIT(node_id, prop, idx) \ @@ -33,6 +34,7 @@ typedef struct pinctrl_soc_pin_t { .open_drain = DT_PROP(node_id, drive_open_drain), \ .schmitt_enable = DT_PROP(node_id, input_schmitt_enable), \ .slew_rate = DT_ENUM_IDX(node_id, slew_rate), \ + .digital_disable = DT_PROP(node_id, digital_path_disable), \ }, #define Z_PINCTRL_STATE_PINS_INIT(node_id, prop) \ diff --git a/soc/nxp/imx/imx6sx/Kconfig.defconfig.mcimx6x_m4 b/soc/nxp/imx/imx6sx/Kconfig.defconfig.mcimx6x_m4 index 9a925ade2f6..73f11971d6c 100644 --- a/soc/nxp/imx/imx6sx/Kconfig.defconfig.mcimx6x_m4 +++ b/soc/nxp/imx/imx6sx/Kconfig.defconfig.mcimx6x_m4 @@ -8,4 +8,18 @@ if SOC_MCIMX6X_M4 config FPU default y + +#-By default ROM_START is relocated to address 0 in a 1K region, allowing imx_rproc +# to translate it to TCM_L address +#-Select the relocation if the chosen flash is not the TCML +#-Disable this option if you use the bin format as this choice will enlarge it. +# This is due to relocation of the irq-vectors in a different memory region than +# the chosen zephyr,flash and all the address span in between +# will be filled in the bin file. +config ROMSTART_RELOCATION_ROM + default n + +config ROMSTART_REGION_ADDRESS + default $(dt_nodelabel_reg_addr_hex,tcml) + endif # SOC_MCIMX6X_M4 diff --git a/soc/nxp/imx/imx7d/Kconfig.defconfig.mcimx7d_m4 b/soc/nxp/imx/imx7d/Kconfig.defconfig.mcimx7d_m4 index 2e9d5e71d9d..041da088770 100644 --- a/soc/nxp/imx/imx7d/Kconfig.defconfig.mcimx7d_m4 +++ b/soc/nxp/imx/imx7d/Kconfig.defconfig.mcimx7d_m4 @@ -11,4 +11,17 @@ config SYS_CLOCK_HW_CYCLES_PER_SEC config GPIO default y +#-By default ROM_START is relocated to address 0 in a 1K region, allowing imx_rproc +# to translate it to OCRAM_S address +#-Select the relocation if the chosen flash is not the OCRAM_S +#-Disable this option if you use the bin format as this choice will enlarge it. +# This is due to relocation of the irq-vectors in a different memory region than +# the chosen zephyr,flash and all the address span in between +# will be filled in the bin file. +config ROMSTART_RELOCATION_ROM + default n + +config ROMSTART_REGION_ADDRESS + default $(dt_nodelabel_reg_addr_hex,ocram_s_code) + endif # SOC_MCIMX7D_M4 diff --git a/soc/nxp/imx/imx7d/soc.h b/soc/nxp/imx/imx7d/soc.h index 5f9540084b6..8998d11ee05 100644 --- a/soc/nxp/imx/imx7d/soc.h +++ b/soc/nxp/imx/imx7d/soc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, NXP + * Copyright 2017,2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -9,12 +9,18 @@ #ifndef _ASMLANGUAGE +#include + +#ifndef __cplusplus + #include "rdc.h" #include "rdc_defs_imx7d.h" #include "ccm_imx7d.h" #include "clock_freq.h" #include "soc_clk_freq.h" +#endif /* !__cplusplus */ + #endif /* !_ASMLANGUAGE */ #endif /* _SOC__H_ */ diff --git a/soc/nxp/imxrt/CMakeLists.txt b/soc/nxp/imxrt/CMakeLists.txt index 25cd1b81554..b42829869e4 100644 --- a/soc/nxp/imxrt/CMakeLists.txt +++ b/soc/nxp/imxrt/CMakeLists.txt @@ -13,6 +13,9 @@ if(CONFIG_SOC_SERIES_IMXRT10XX OR CONFIG_SOC_SERIES_IMXRT11XX) if(CONFIG_DEVICE_CONFIGURATION_DATA) set(boot_hdr_dcd_data_section ".boot_hdr.dcd_data") endif() + if(CONFIG_EXTERNAL_MEM_CONFIG_DATA) + set(boot_hdr_xmcd_data_section ".boot_hdr.xmcd_data") + endif() zephyr_sources(mpu_regions.c) zephyr_linker_section_configure( SECTION .rom_start @@ -26,6 +29,7 @@ if(CONFIG_SOC_SERIES_IMXRT10XX OR CONFIG_SOC_SERIES_IMXRT11XX) INPUT ".boot_hdr.ivt" ".boot_hdr.data" ${boot_hdr_dcd_data_section} + ${boot_hdr_xmcd_data_section} OFFSET ${CONFIG_IMAGE_VECTOR_TABLE_OFFSET} KEEP PRIO 11 diff --git a/soc/nxp/imxrt/Kconfig b/soc/nxp/imxrt/Kconfig index b249dbb312b..2ab29a50ce6 100644 --- a/soc/nxp/imxrt/Kconfig +++ b/soc/nxp/imxrt/Kconfig @@ -114,6 +114,25 @@ config DEVICE_CONFIGURATION_DATA initialized at boot time. +config EXTERNAL_MEM_CONFIG_DATA + bool "External Memory Configuration Data" + depends on !DEVICE_CONFIGURATION_DATA + help + External memory configuration data (XMDC) provides an alternative + configuration sequences which allows to intilialize the external memory + at the boot time. This sequence allows to configure + external memories (such as SDRAM) with more advanced option. + This is a new alternative boot header compared to DCD, and DCD must be disabled + in order to select this option. + +config EXTERNAL_MEM_CONFIG_OFFSET + hex "External memory configuration offset" + depends on EXTERNAL_MEM_CONFIG_DATA + default 0x1040 if BOOT_FLEXSPI_NOR || BOOT_SEMC_NOR + help + As specified by the boot ROM, the External Memory configuration data must be + placed in a specific address location to be pointed by the boot ROM. + endif # NXP_IMXRT_BOOT_HEADER config NXP_IMX_EXTERNAL_SDRAM @@ -184,6 +203,9 @@ config INIT_ENET_PLL MIMXRT1021 - see commit 17f4d6bec7 ("soc: nxp_imx: fix ENET_PLL selection for MIMXRT1021"). +config INIT_SYS_PLL + bool "Initialize System PLL" + endif # SOC_SERIES_IMXRT10XX || SOC_SERIES_IMXRT11XX endif # SOC_FAMILY_NXP_IMXRT diff --git a/soc/nxp/imxrt/boot_header.ld b/soc/nxp/imxrt/boot_header.ld index e46fa5789e3..b96e5e58b3f 100644 --- a/soc/nxp/imxrt/boot_header.ld +++ b/soc/nxp/imxrt/boot_header.ld @@ -18,4 +18,8 @@ KEEP(*(.boot_hdr.data)) #ifdef CONFIG_DEVICE_CONFIGURATION_DATA KEEP(*(.boot_hdr.dcd_data)) #endif /* CONFIG_DEVICE_CONFIGURATION_DATA */ +#ifdef CONFIG_EXTERNAL_MEM_CONFIG_DATA + . = CONFIG_EXTERNAL_MEM_CONFIG_OFFSET; + KEEP(*(.boot_hdr.xmcd_data)) +#endif #endif /* CONFIG_SOC_SERIES_IMXRT10XX || CONFIG_SOC_SERIES_IMXRT11XX */ diff --git a/soc/nxp/imxrt/imxrt10xx/Kconfig b/soc/nxp/imxrt/imxrt10xx/Kconfig index 51b894ae304..aa5e5e70501 100644 --- a/soc/nxp/imxrt/imxrt10xx/Kconfig +++ b/soc/nxp/imxrt/imxrt10xx/Kconfig @@ -70,6 +70,7 @@ config SOC_MIMXRT1042 select CPU_HAS_FPU_DOUBLE_PRECISION select CPU_HAS_ARM_MPU select INIT_ARM_PLL + select INIT_SYS_PLL config SOC_MIMXRT1051 select HAS_MCUX_ENET @@ -79,7 +80,6 @@ config SOC_MIMXRT1051 select INIT_ARM_PLL select HAS_MCUX_USDHC1 select HAS_MCUX_USDHC2 - select HAS_MCUX_CSI select HAS_MCUX_FLEXCAN config SOC_MIMXRT1052 @@ -93,7 +93,6 @@ config SOC_MIMXRT1052 select INIT_ENET_PLL if NET_L2_ETHERNET && ETH_DRIVER select HAS_MCUX_USDHC1 select HAS_MCUX_USDHC2 - select HAS_MCUX_CSI select HAS_MCUX_FLEXCAN select HAS_MCUX_PWM select HAS_MCUX_SRC @@ -107,7 +106,6 @@ config SOC_MIMXRT1061 select INIT_ARM_PLL select HAS_MCUX_USDHC1 select HAS_MCUX_USDHC2 - select HAS_MCUX_CSI select HAS_MCUX_FLEXCAN config SOC_MIMXRT1062 @@ -124,7 +122,6 @@ config SOC_MIMXRT1062 select INIT_ENET_PLL if NET_L2_ETHERNET && ETH_DRIVER select HAS_MCUX_USDHC1 select HAS_MCUX_USDHC2 - select HAS_MCUX_CSI select HAS_MCUX_FLEXCAN select HAS_MCUX_I2S select HAS_MCUX_ADC_ETC @@ -146,6 +143,5 @@ config SOC_MIMXRT1064 select INIT_ENET_PLL if NET_L2_ETHERNET && ETH_DRIVER select HAS_MCUX_USDHC1 select HAS_MCUX_USDHC2 - select HAS_MCUX_CSI select HAS_MCUX_FLEXCAN select HAS_SWO diff --git a/soc/nxp/imxrt/imxrt10xx/lpm_rt1064.c b/soc/nxp/imxrt/imxrt10xx/lpm_rt1064.c index 9020b9bf809..c7cc46d0307 100644 --- a/soc/nxp/imxrt/imxrt10xx/lpm_rt1064.c +++ b/soc/nxp/imxrt/imxrt10xx/lpm_rt1064.c @@ -117,7 +117,7 @@ static void clock_init_usb1_pll(const clock_usb_pll_config_t *config) static void flexspi_enter_critical(void) { -#if DT_SAME_NODE(DT_NODELABEL(flexspi2), DT_PARENT(DT_CHOSEN(flash))) +#if DT_SAME_NODE(DT_NODELABEL(flexspi2), DT_PARENT(DT_CHOSEN(zephyr_flash))) /* Wait for flexspi to be inactive, and gate the clock */ while (!((FLEXSPI2->STS0 & FLEXSPI_STS0_ARBIDLE_MASK) && (FLEXSPI2->STS0 & FLEXSPI_STS0_SEQIDLE_MASK))) { @@ -128,7 +128,7 @@ static void flexspi_enter_critical(void) CCM->CCGR7 &= (~CCM_CCGR7_CG1_MASK); #endif -#if DT_SAME_NODE(DT_NODELABEL(flexspi), DT_PARENT(DT_CHOSEN(flash))) +#if DT_SAME_NODE(DT_NODELABEL(flexspi), DT_PARENT(DT_CHOSEN(zephyr_flash))) /* Wait for flexspi to be inactive, and gate the clock */ while (!((FLEXSPI->STS0 & FLEXSPI_STS0_ARBIDLE_MASK) && (FLEXSPI->STS0 & FLEXSPI_STS0_SEQIDLE_MASK))) { @@ -142,7 +142,7 @@ static void flexspi_enter_critical(void) static void flexspi_exit_critical(void) { -#if DT_SAME_NODE(DT_NODELABEL(flexspi2), DT_PARENT(DT_CHOSEN(flash))) +#if DT_SAME_NODE(DT_NODELABEL(flexspi2), DT_PARENT(DT_CHOSEN(zephyr_flash))) /* Enable clock gate of flexspi2. */ CCM->CCGR7 |= (CCM_CCGR7_CG1_MASK); @@ -153,7 +153,7 @@ static void flexspi_exit_critical(void) while (!((FLEXSPI2->STS0 & FLEXSPI_STS0_ARBIDLE_MASK) && (FLEXSPI2->STS0 & FLEXSPI_STS0_SEQIDLE_MASK))) { } -#elif DT_SAME_NODE(DT_NODELABEL(flexspi), DT_PARENT(DT_CHOSEN(flash))) +#elif DT_SAME_NODE(DT_NODELABEL(flexspi), DT_PARENT(DT_CHOSEN(zephyr_flash))) /* Enable clock of flexspi. */ CCM->CCGR6 |= CCM_CCGR6_CG5_MASK; @@ -211,11 +211,11 @@ void clock_full_power(void) #endif /* Set Flexspi divider before increasing frequency of PLL3 PDF0. */ -#if DT_SAME_NODE(DT_NODELABEL(flexspi), DT_PARENT(DT_CHOSEN(flash))) +#if DT_SAME_NODE(DT_NODELABEL(flexspi), DT_PARENT(DT_CHOSEN(zephyr_flash))) clock_set_div(kCLOCK_FlexspiDiv, flexspi_div); clock_set_mux(kCLOCK_FlexspiMux, 3); #endif -#if DT_SAME_NODE(DT_NODELABEL(flexspi2), DT_PARENT(DT_CHOSEN(flash))) +#if DT_SAME_NODE(DT_NODELABEL(flexspi2), DT_PARENT(DT_CHOSEN(zephyr_flash))) clock_set_div(kCLOCK_Flexspi2Div, flexspi_div); clock_set_mux(kCLOCK_Flexspi2Mux, 1); #endif @@ -258,12 +258,12 @@ void clock_low_power(void) CCM_ANALOG->PLL_USB1_SET = CCM_ANALOG_PLL_USB1_ENABLE_MASK; CCM_ANALOG->PFD_480_CLR = CCM_ANALOG_PFD_480_PFD0_CLKGATE_MASK; /* Change flexspi to use PLL3 PFD0 with no divisor (24M flexspi clock) */ -#if DT_SAME_NODE(DT_NODELABEL(flexspi), DT_PARENT(DT_CHOSEN(flash))) +#if DT_SAME_NODE(DT_NODELABEL(flexspi), DT_PARENT(DT_CHOSEN(zephyr_flash))) clock_set_div(kCLOCK_FlexspiDiv, 0); /* FLEXSPI1 mux to PLL3 PFD0 BYPASS */ clock_set_mux(kCLOCK_FlexspiMux, 3); #endif -#if DT_SAME_NODE(DT_NODELABEL(flexspi2), DT_PARENT(DT_CHOSEN(flash))) +#if DT_SAME_NODE(DT_NODELABEL(flexspi2), DT_PARENT(DT_CHOSEN(zephyr_flash))) clock_set_div(kCLOCK_Flexspi2Div, 0); /* FLEXSPI2 mux to PLL3 PFD0 BYPASS */ clock_set_mux(kCLOCK_Flexspi2Mux, 1); diff --git a/soc/nxp/imxrt/imxrt10xx/soc.c b/soc/nxp/imxrt/imxrt10xx/soc.c index 0e4bae616a6..789f02099be 100644 --- a/soc/nxp/imxrt/imxrt10xx/soc.c +++ b/soc/nxp/imxrt/imxrt10xx/soc.c @@ -40,6 +40,16 @@ const clock_arm_pll_config_t armPllConfig = { }; #endif +#if CONFIG_INIT_SYS_PLL +/* Configure System PLL */ +const clock_sys_pll_config_t sysPllConfig = { + .loopDivider = (DT_PROP(DT_CHILD(CCM_NODE, sys_pll), loop_div) - 20) / 2, + .numerator = DT_PROP(DT_CHILD(CCM_NODE, sys_pll), numerator), + .denominator = DT_PROP(DT_CHILD(CCM_NODE, sys_pll), denominator), + .src = DT_PROP(DT_CHILD(CCM_NODE, sys_pll), src), +}; +#endif + #if CONFIG_USB_DC_NXP_EHCI /* USB PHY condfiguration */ #define BOARD_USB_PHY_D_CAL (0x0CU) @@ -64,7 +74,7 @@ const clock_enet_pll_config_t ethPllConfig = { .enableClkOutput1 = true, #endif #endif -#if defined(CONFIG_PTP_CLOCK_MCUX) +#if defined(CONFIG_PTP_CLOCK_MCUX) || defined(CONFIG_PTP_CLOCK_NXP_ENET) .enableClkOutput25M = true, #else .enableClkOutput25M = false, @@ -160,6 +170,10 @@ static ALWAYS_INLINE void clock_init(void) CLOCK_InitVideoPll(&videoPllConfig); #endif +#if CONFIG_INIT_SYS_PLL + CLOCK_InitSysPll(&sysPllConfig); +#endif + #if DT_NODE_EXISTS(DT_CHILD(CCM_NODE, arm_podf)) /* Set ARM PODF */ BUILD_ASSERT_PODF_IN_RANGE(arm_podf, 1, 8); @@ -172,8 +186,13 @@ static ALWAYS_INLINE void clock_init(void) BUILD_ASSERT_PODF_IN_RANGE(ipg_podf, 1, 4); CLOCK_SetDiv(kCLOCK_IpgDiv, DT_PROP(DT_CHILD(CCM_NODE, ipg_podf), clock_div) - 1); +#ifdef CONFIG_SOC_MIMXRT1042 + /* Set PRE_PERIPH_CLK to SYS_PLL */ + CLOCK_SetMux(kCLOCK_PrePeriphMux, 0x0); +#else /* Set PRE_PERIPH_CLK to PLL1, 1200M */ CLOCK_SetMux(kCLOCK_PrePeriphMux, 0x3); +#endif /* Set PERIPH_CLK MUX to PRE_PERIPH_CLK */ CLOCK_SetMux(kCLOCK_PeriphMux, 0x0); diff --git a/soc/nxp/imxrt/imxrt11xx/soc.c b/soc/nxp/imxrt/imxrt11xx/soc.c index 9eee69ad66a..642708af987 100644 --- a/soc/nxp/imxrt/imxrt11xx/soc.c +++ b/soc/nxp/imxrt/imxrt11xx/soc.c @@ -398,6 +398,11 @@ static ALWAYS_INLINE void clock_init(void) rootCfg.mux = kCLOCK_LPI2C5_ClockRoot_MuxOscRc48MDiv2; rootCfg.div = 1; CLOCK_SetRootClock(kCLOCK_Root_Lpi2c5, &rootCfg); + + /* Configure Lpi2c6 using Osc24M */ + rootCfg.mux = kCLOCK_LPI2C6_ClockRoot_MuxOsc24MOut; + rootCfg.div = 12; + CLOCK_SetRootClock(kCLOCK_Root_Lpi2c6, &rootCfg); #endif @@ -437,7 +442,7 @@ static ALWAYS_INLINE void clock_init(void) #endif #endif -#ifdef CONFIG_PTP_CLOCK_MCUX +#if defined(CONFIG_PTP_CLOCK_MCUX) || defined(CONFIG_PTP_CLOCK_NXP_ENET) /* 24MHz PTP clock */ rootCfg.mux = kCLOCK_ENET_TIMER1_ClockRoot_MuxOscRc48MDiv2; rootCfg.div = 1; @@ -451,6 +456,27 @@ static ALWAYS_INLINE void clock_init(void) CLOCK_SetRootClock(kCLOCK_Root_Lpspi1, &rootCfg); #endif +#ifdef CONFIG_VIDEO_MCUX_MIPI_CSI2RX + /* MIPI CSI-2 Rx connects to CSI via Video Mux */ + CLOCK_EnableClock(kCLOCK_Video_Mux); + VIDEO_MUX->VID_MUX_CTRL.SET = VIDEO_MUX_VID_MUX_CTRL_CSI_SEL_MASK; + + /* Configure MIPI CSI-2 Rx clocks */ + rootCfg.div = 8; + rootCfg.mux = kCLOCK_CSI2_ClockRoot_MuxSysPll3Out; + CLOCK_SetRootClock(kCLOCK_Root_Csi2, &rootCfg); + + rootCfg.mux = kCLOCK_CSI2_ESC_ClockRoot_MuxSysPll3Out; + CLOCK_SetRootClock(kCLOCK_Root_Csi2_Esc, &rootCfg); + + rootCfg.mux = kCLOCK_CSI2_UI_ClockRoot_MuxSysPll3Out; + CLOCK_SetRootClock(kCLOCK_Root_Csi2_Ui, &rootCfg); + + /* Enable power domain for MIPI CSI-2 */ + PGMC_BPC4->BPC_POWER_CTRL |= (PGMC_BPC_BPC_POWER_CTRL_PSW_ON_SOFT_MASK | + PGMC_BPC_BPC_POWER_CTRL_ISO_OFF_SOFT_MASK); +#endif + #ifdef CONFIG_CAN_MCUX_FLEXCAN #if DT_NODE_HAS_STATUS(DT_NODELABEL(flexcan1), okay) /* Configure CAN1 using Osc48MDiv2 */ @@ -527,7 +553,7 @@ static ALWAYS_INLINE void clock_init(void) #endif #endif -#if !(DT_NODE_HAS_COMPAT(DT_CHOSEN(flash), nxp_imx_flexspi)) && \ +#if !(DT_NODE_HAS_COMPAT(DT_CHOSEN(zephyr_flash), nxp_imx_flexspi)) && \ defined(CONFIG_MEMC_MCUX_FLEXSPI) && \ DT_NODE_HAS_STATUS(DT_NODELABEL(flexspi), okay) /* Configure FLEXSPI1 using OSC_RC_48M_DIV2 */ diff --git a/soc/nxp/imxrt/imxrt5xx/cm33/soc.c b/soc/nxp/imxrt/imxrt5xx/cm33/soc.c index 4b420ea46d4..9f29550b576 100644 --- a/soc/nxp/imxrt/imxrt5xx/cm33/soc.c +++ b/soc/nxp/imxrt/imxrt5xx/cm33/soc.c @@ -423,10 +423,6 @@ void __weak rt5xx_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. diff --git a/soc/nxp/imxrt/imxrt6xx/cm33/soc.c b/soc/nxp/imxrt/imxrt6xx/cm33/soc.c index de658a285be..bb6ea26ac45 100644 --- a/soc/nxp/imxrt/imxrt6xx/cm33/soc.c +++ b/soc/nxp/imxrt/imxrt6xx/cm33/soc.c @@ -321,10 +321,6 @@ 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/nxp/kinetis/common/pinctrl_soc.h b/soc/nxp/kinetis/common/pinctrl_soc.h index d3a2ee0c02d..9caa7610b72 100644 --- a/soc/nxp/kinetis/common/pinctrl_soc.h +++ b/soc/nxp/kinetis/common/pinctrl_soc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 NXP + * Copyright (c) 2022, 2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -29,14 +29,16 @@ typedef uint32_t pinctrl_soc_pin_t; #if (defined(CONFIG_SOC_SERIES_KINETIS_KWX) && \ !(defined(CONFIG_SOC_MKW24D5) || \ defined(CONFIG_SOC_MKW22D5))) || \ - defined(CONFIG_SOC_SERIES_KINETIS_KL2X) || \ - defined(CONFIG_SOC_SERIES_KINETIS_KE1XF) + defined(CONFIG_SOC_SERIES_KINETIS_KL2X) || \ + defined(CONFIG_SOC_SERIES_KINETIS_KE1XF) || \ + defined(CONFIG_SOC_SERIES_KE1XZ) #define PORT_PCR_ODE(x) 0x0 #define PORT_PCR_ODE_MASK 0x0 #endif /* Kinetis KE series does not support slew rate. Define macros to have no effect */ -#if defined(CONFIG_SOC_SERIES_KINETIS_KE1XF) +#if defined(CONFIG_SOC_SERIES_KINETIS_KE1XF) || \ + defined(CONFIG_SOC_SERIES_KE1XZ) #define PORT_PCR_SRE(x) 0x0 #define PORT_PCR_SRE_MASK 0x0 #endif diff --git a/soc/nxp/kinetis/ke1xz/CMakeLists.txt b/soc/nxp/kinetis/ke1xz/CMakeLists.txt new file mode 100644 index 00000000000..116e67f6751 --- /dev/null +++ b/soc/nxp/kinetis/ke1xz/CMakeLists.txt @@ -0,0 +1,13 @@ +# +# Copyright 2024 NXP +# +# SPDX-License-Identifier: Apache-2.0 +# + +zephyr_sources( + soc.c +) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") + +zephyr_include_directories(.) diff --git a/soc/nxp/kinetis/ke1xz/Kconfig b/soc/nxp/kinetis/ke1xz/Kconfig new file mode 100644 index 00000000000..9e01b9ec4eb --- /dev/null +++ b/soc/nxp/kinetis/ke1xz/Kconfig @@ -0,0 +1,14 @@ +# Kinetis KE1xZ series MCU + +# Copyright (c) 2019 Vestas Wind Systems A/S +# Copyright 2024 NXP +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_KE1XZ + select ARM + select CPU_CORTEX_M0PLUS + select CPU_CORTEX_M_HAS_SYSTICK + select CPU_CORTEX_M_HAS_VTOR + select CLOCK_CONTROL + select HAS_MCUX + select PLATFORM_SPECIFIC_INIT diff --git a/soc/nxp/kinetis/ke1xz/Kconfig.defconfig b/soc/nxp/kinetis/ke1xz/Kconfig.defconfig new file mode 100644 index 00000000000..3077b6e8731 --- /dev/null +++ b/soc/nxp/kinetis/ke1xz/Kconfig.defconfig @@ -0,0 +1,28 @@ +# Kinetis KE1xZ series configuration options + +# Copyright (c) 2019-2021 Vestas Wind Systems A/S +# Copyright 2024 NXP +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_KE1XZ + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default $(dt_node_int_prop_int,/cpus/cpu@0,clock-frequency) if CORTEX_M_SYSTICK + +config NUM_IRQS + default 32 + +config CPU_HAS_CUSTOM_FIXED_SOC_MPU_REGIONS + default y + +# This Kconfig is SOC Specific and configures the MCU at boot time +# This SOC is configured via the following bits +# 0000 0001 - Normal Boot +# 0000 0100 - Enable Interrupts +# 0000 1000 - Allow Reset detection from RESET_Pin +# 0111 0000 - Reserved for Future Expansion +config KINETIS_FLASH_CONFIG_FOPT + default 0x7d + depends on KINETIS_FLASH_CONFIG + +endif # SOC_SERIES_KE1XZ diff --git a/soc/nxp/kinetis/ke1xz/Kconfig.soc b/soc/nxp/kinetis/ke1xz/Kconfig.soc new file mode 100644 index 00000000000..e0059ac98b1 --- /dev/null +++ b/soc/nxp/kinetis/ke1xz/Kconfig.soc @@ -0,0 +1,37 @@ +# Kinetis KE1xZ MCU line + +# Copyright (c) 2019 Vestas Wind Systems A/S +# Copyright 2024 NXP +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_KE1XZ + bool + select SOC_FAMILY_KINETIS + +config SOC_SERIES + default "ke1xz" if SOC_SERIES_KE1XZ + +config SOC_MKE15Z7 + bool + select SOC_SERIES_KE1XZ + +config SOC + default "mke15z7" if SOC_MKE15Z7 + +config SOC_PART_NUMBER_MKE15Z128VLL7 + bool + +config SOC_PART_NUMBER_MKE15Z128VLH7 + bool + +config SOC_PART_NUMBER_MKE15Z256VLL7 + bool + +config SOC_PART_NUMBER_MKE15Z256VLH7 + bool + +config SOC_PART_NUMBER + default "MKE15Z128VLL7" if SOC_PART_NUMBER_MKE15Z128VLL7 + default "MKE15Z128VLH7" if SOC_PART_NUMBER_MKE15Z128VLH7 + default "MKE15Z256VLL7" if SOC_PART_NUMBER_MKE15Z256VLL7 + default "MKE15Z256VLH7" if SOC_PART_NUMBER_MKE15Z256VLH7 diff --git a/soc/nxp/kinetis/ke1xz/soc.c b/soc/nxp/kinetis/ke1xz/soc.c new file mode 100644 index 00000000000..3aeb5db419e --- /dev/null +++ b/soc/nxp/kinetis/ke1xz/soc.c @@ -0,0 +1,142 @@ +/* + * Copyright 2024 NXP + * Copyright (c) 2019-2021 Vestas Wind Systems A/S + * + * Based on NXP k6x soc.c, which is: + * Copyright (c) 2014-2015 Wind River Systems, Inc. + * Copyright (c) 2016, Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#define ASSERT_WITHIN_RANGE(val, min, max, str) \ + BUILD_ASSERT(val >= min && val <= max, str) + +#define ASSERT_ASYNC_CLK_DIV_VALID(val, str) \ + BUILD_ASSERT(val == 0 || val == 1 || val == 2 || val == 4 || \ + val == 8 || val == 16 || val == 2 || val == 64, str) + +#define TO_SYS_CLK_DIV(val) _DO_CONCAT(kSCG_SysClkDivBy, val) + +#define kSCG_AsyncClkDivBy0 kSCG_AsyncClkDisable +#define TO_ASYNC_CLK_DIV(val) _DO_CONCAT(kSCG_AsyncClkDivBy, val) + +#define SCG_CLOCK_NODE(name) DT_CHILD(DT_INST(0, nxp_kinetis_scg), name) +#define SCG_CLOCK_DIV(name) DT_PROP(SCG_CLOCK_NODE(name), clock_div) + +/* System Clock configuration */ +ASSERT_WITHIN_RANGE(SCG_CLOCK_DIV(bus_clk), 2, 8, + "Invalid SCG bus clock divider value"); +ASSERT_WITHIN_RANGE(SCG_CLOCK_DIV(core_clk), 1, 16, + "Invalid SCG core clock divider value"); + +static const scg_sys_clk_config_t scg_sys_clk_config = { + .divSlow = TO_SYS_CLK_DIV(SCG_CLOCK_DIV(bus_clk)), + .divCore = TO_SYS_CLK_DIV(SCG_CLOCK_DIV(core_clk)), +#if DT_SAME_NODE(DT_CLOCKS_CTLR(SCG_CLOCK_NODE(core_clk)), SCG_CLOCK_NODE(sirc_clk)) + .src = kSCG_SysClkSrcSirc, +#elif DT_SAME_NODE(DT_CLOCKS_CTLR(SCG_CLOCK_NODE(core_clk)), SCG_CLOCK_NODE(firc_clk)) + .src = kSCG_SysClkSrcFirc, +#endif +}; + +/* Slow Internal Reference Clock (SIRC) configuration */ +ASSERT_ASYNC_CLK_DIV_VALID(SCG_CLOCK_DIV(sircdiv2_clk), + "Invalid SCG SIRC divider 2 value"); +static const scg_sirc_config_t scg_sirc_config = { + .enableMode = kSCG_SircEnable, + .div2 = TO_ASYNC_CLK_DIV(SCG_CLOCK_DIV(sircdiv2_clk)), +#if MHZ(2) == DT_PROP(SCG_CLOCK_NODE(sirc_clk), clock_frequency) + .range = kSCG_SircRangeLow +#elif MHZ(8) == DT_PROP(SCG_CLOCK_NODE(sirc_clk), clock_frequency) + .range = kSCG_SircRangeHigh +#else +#error Invalid SCG SIRC clock frequency +#endif +}; + +/* Fast Internal Reference Clock (FIRC) configuration */ +ASSERT_ASYNC_CLK_DIV_VALID(SCG_CLOCK_DIV(fircdiv2_clk), + "Invalid SCG FIRC divider 2 value"); +static const scg_firc_config_t scg_firc_config = { + .enableMode = kSCG_FircEnable, + .div2 = TO_ASYNC_CLK_DIV(SCG_CLOCK_DIV(fircdiv2_clk)), /* b20253 */ +#if MHZ(48) == DT_PROP(SCG_CLOCK_NODE(firc_clk), clock_frequency) + .range = kSCG_FircRange48M, +#elif MHZ(52) == DT_PROP(SCG_CLOCK_NODE(firc_clk), clock_frequency) + .range = kSCG_FircRange52M, +#elif MHZ(56) == DT_PROP(SCG_CLOCK_NODE(firc_clk), clock_frequency) + .range = kSCG_FircRange56M, +#elif MHZ(60) == DT_PROP(SCG_CLOCK_NODE(firc_clk), clock_frequency) + .range = kSCG_FircRange60M, +#else +#error Invalid SCG FIRC clock frequency +#endif + .trimConfig = NULL +}; + +static ALWAYS_INLINE void clk_init(void) +{ + const scg_sys_clk_config_t scg_sys_clk_config_safe = { + .divSlow = kSCG_SysClkDivBy4, + .divCore = kSCG_SysClkDivBy1, + .src = kSCG_SysClkSrcSirc + }; + scg_sys_clk_config_t current; + + /* Configure SIRC */ + CLOCK_InitSirc(&scg_sirc_config); + + /* Temporary switch to safe SIRC in order to configure FIRC */ + CLOCK_SetRunModeSysClkConfig(&scg_sys_clk_config_safe); + do { + CLOCK_GetCurSysClkConfig(¤t); + } while (current.src != scg_sys_clk_config_safe.src); + CLOCK_InitFirc(&scg_firc_config); + + /* Only RUN mode supported for now */ + CLOCK_SetRunModeSysClkConfig(&scg_sys_clk_config); + do { + CLOCK_GetCurSysClkConfig(¤t); + } while (current.src != scg_sys_clk_config.src); + +#if DT_NODE_HAS_STATUS(DT_NODELABEL(lpuart0), okay) + CLOCK_SetIpSrc(kCLOCK_Lpuart0, + DT_CLOCKS_CELL(DT_NODELABEL(lpuart0), ip_source)); +#endif +#if DT_NODE_HAS_STATUS(DT_NODELABEL(lpuart1), okay) + CLOCK_SetIpSrc(kCLOCK_Lpuart1, + DT_CLOCKS_CELL(DT_NODELABEL(lpuart1), ip_source)); +#endif +#if DT_NODE_HAS_STATUS(DT_NODELABEL(lpuart2), okay) + CLOCK_SetIpSrc(kCLOCK_Lpuart2, + DT_CLOCKS_CELL(DT_NODELABEL(lpuart2), ip_source)); +#endif +} + +static int ke1xz_init(void) + +{ + /* Initialize system clocks and PLL */ + clk_init(); + + return 0; +} + +#ifdef CONFIG_PLATFORM_SPECIFIC_INIT + +void z_arm_platform_init(void) +{ + /* SystemInit is provided by the NXP SDK */ + SystemInit(); +} + +#endif /* CONFIG_PLATFORM_SPECIFIC_INIT */ + +SYS_INIT(ke1xz_init, PRE_KERNEL_1, 0); diff --git a/soc/nxp/kinetis/ke1xz/soc.h b/soc/nxp/kinetis/ke1xz/soc.h new file mode 100644 index 00000000000..ac805348a55 --- /dev/null +++ b/soc/nxp/kinetis/ke1xz/soc.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2019 Vestas Wind Systems A/S + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _SOC__H_ +#define _SOC__H_ + +#include +#include + +#define PORT_MUX_GPIO kPORT_MuxAsGpio /* GPIO setting for the Port Mux Register */ + +#ifndef _ASMLANGUAGE + +#include + + +#endif /* !_ASMLANGUAGE */ + +#endif /* _SOC__H_ */ diff --git a/soc/nxp/kinetis/soc.yml b/soc/nxp/kinetis/soc.yml index c2b27eb9841..887c6d6980b 100644 --- a/soc/nxp/kinetis/soc.yml +++ b/soc/nxp/kinetis/soc.yml @@ -29,3 +29,6 @@ family: socs: - name: mkv56f24 - name: mkv58f24 + - name: ke1xz + socs: + - name: mke15z7 diff --git a/soc/nxp/lpc/lpc51u68/soc.c b/soc/nxp/lpc/lpc51u68/soc.c index e09800ce872..c4b7b58131a 100644 --- a/soc/nxp/lpc/lpc51u68/soc.c +++ b/soc/nxp/lpc/lpc51u68/soc.c @@ -31,17 +31,11 @@ int soc_init(void) #if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(flexcomm4), nxp_lpc_i2c, okay) /* attach 12 MHz clock for flexcomm4 */ CLOCK_AttachClk(kFRO12M_to_FLEXCOMM4); - - /* reset FLEXCOMM for I2C */ - RESET_PeripheralReset(kFC4_RST_SHIFT_RSTn); #endif #if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(flexcomm5), nxp_lpc_spi, okay) /* attach 12MHz clock to flexcomm5 */ CLOCK_AttachClk(kFRO12M_to_FLEXCOMM5); - - /* reset FLEXCOMM for SPI */ - RESET_PeripheralReset(kFC5_RST_SHIFT_RSTn); #endif POWER_DisablePD(kPDRUNCFG_PD_ADC0); diff --git a/soc/nxp/lpc/lpc54xxx/soc.c b/soc/nxp/lpc/lpc54xxx/soc.c index 20f2022cd56..f5a353d2ad3 100644 --- a/soc/nxp/lpc/lpc54xxx/soc.c +++ b/soc/nxp/lpc/lpc54xxx/soc.c @@ -81,17 +81,11 @@ static ALWAYS_INLINE void clock_init(void) #if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(flexcomm4), nxp_lpc_i2c, okay) /* attach 12 MHz clock to FLEXCOMM4 */ CLOCK_AttachClk(kFRO12M_to_FLEXCOMM4); - - /* reset FLEXCOMM for I2C */ - RESET_PeripheralReset(kFC4_RST_SHIFT_RSTn); #endif #if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(flexcomm5), nxp_lpc_spi, okay) /* Attach 12 MHz clock to FLEXCOMM5 */ CLOCK_AttachClk(kFRO_HF_to_FLEXCOMM5); - - /* reset FLEXCOMM for SPI */ - RESET_PeripheralReset(kFC5_RST_SHIFT_RSTn); #endif #endif /* CONFIG_SOC_LPC54114_M4 */ diff --git a/soc/nxp/lpc/lpc55xxx/soc.c b/soc/nxp/lpc/lpc55xxx/soc.c index a26aae34d9b..5072fd8266b 100644 --- a/soc/nxp/lpc/lpc55xxx/soc.c +++ b/soc/nxp/lpc/lpc55xxx/soc.c @@ -191,17 +191,11 @@ static ALWAYS_INLINE void clock_init(void) #endif /* attach 12 MHz clock to FLEXCOMM4 */ CLOCK_AttachClk(kFRO12M_to_FLEXCOMM4); - - /* reset FLEXCOMM for I2C */ - RESET_PeripheralReset(kFC4_RST_SHIFT_RSTn); #endif #if DT_NODE_HAS_STATUS(DT_NODELABEL(hs_lspi), okay) /* Attach 12 MHz clock to HSLSPI */ CLOCK_AttachClk(kFRO_HF_DIV_to_HSLSPI); - - /* reset HSLSPI for SPI */ - RESET_PeripheralReset(kHSLSPI_RST_SHIFT_RSTn); #endif #if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(wwdt0), nxp_lpc_wwdt, okay) @@ -211,8 +205,6 @@ static ALWAYS_INLINE void clock_init(void) #if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(mailbox0), nxp_lpc_mailbox, okay) CLOCK_EnableClock(kCLOCK_Mailbox); - /* Reset the MAILBOX module */ - RESET_PeripheralReset(kMAILBOX_RST_SHIFT_RSTn); #endif #if CONFIG_USB_DC_NXP_LPCIP3511 @@ -296,7 +288,6 @@ DT_FOREACH_STATUS_OKAY(nxp_lpc_ctimer, CTIMER_CLOCK_SETUP) #if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(can0), nxp_lpc_mcan, okay) CLOCK_SetClkDiv(kCLOCK_DivCanClk, 1U, false); CLOCK_AttachClk(kMCAN_DIV_to_MCAN); - RESET_PeripheralReset(kMCAN_RST_SHIFT_RSTn); #endif #if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(sdif), nxp_lpc_sdif, okay) && \ @@ -347,10 +338,6 @@ 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/nxp/mcx/Kconfig b/soc/nxp/mcx/Kconfig index 1f310d9fa56..3bf1d3a881a 100644 --- a/soc/nxp/mcx/Kconfig +++ b/soc/nxp/mcx/Kconfig @@ -39,4 +39,8 @@ config MFD default y depends on DT_HAS_NXP_LP_FLEXCOMM_ENABLED +choice USB_MCUX_CONTROLLER_TYPE + default USB_DC_NXP_EHCI +endchoice + endif # SOC_FAMILY_NXP_MCX diff --git a/soc/nxp/rw/CMakeLists.txt b/soc/nxp/rw/CMakeLists.txt index d4c7cd7af4d..3790d07afd8 100644 --- a/soc/nxp/rw/CMakeLists.txt +++ b/soc/nxp/rw/CMakeLists.txt @@ -7,7 +7,13 @@ zephyr_sources( flexspi_clock_setup.c ) +zephyr_sources_ifdef(CONFIG_PM + power.c + ) + zephyr_linker_sources_ifdef(CONFIG_NXP_RW6XX_BOOT_HEADER ROM_START SORT_KEY 0 boot_header.ld) set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") + +zephyr_include_directories(.) diff --git a/soc/nxp/rw/Kconfig b/soc/nxp/rw/Kconfig index 5951cf59ab2..a072151a05c 100644 --- a/soc/nxp/rw/Kconfig +++ b/soc/nxp/rw/Kconfig @@ -17,6 +17,7 @@ config SOC_SERIES_RW6XX select HAS_MCUX_FLEXCOMM select INIT_SYS_PLL select HAS_MCUX_CACHE + select HAS_PM if SOC_SERIES_RW6XX diff --git a/soc/nxp/rw/Kconfig.defconfig b/soc/nxp/rw/Kconfig.defconfig index 38bb0df74b7..aa62fea1460 100644 --- a/soc/nxp/rw/Kconfig.defconfig +++ b/soc/nxp/rw/Kconfig.defconfig @@ -9,6 +9,13 @@ config ROM_START_OFFSET config NUM_IRQS default 129 +if MCUX_OS_TIMER + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default 1000000 + +endif # MCUX_OS_TIMER + if CORTEX_M_SYSTICK config SYS_CLOCK_HW_CYCLES_PER_SEC diff --git a/soc/nxp/rw/Kconfig.soc b/soc/nxp/rw/Kconfig.soc index 115b7721f9a..32af5b57109 100644 --- a/soc/nxp/rw/Kconfig.soc +++ b/soc/nxp/rw/Kconfig.soc @@ -26,35 +26,35 @@ config SOC default "rw610" if SOC_RW610 default "rw612" if SOC_RW612 -config SOC_PART_NUMBER_RW612ETA1I +config SOC_PART_NUMBER_RW612ETA2I bool select SOC_RW612 -config SOC_PART_NUMBER_RW612HNA1I +config SOC_PART_NUMBER_RW612HNA2I bool select SOC_RW612 -config SOC_PART_NUMBER_RW612UKA1I +config SOC_PART_NUMBER_RW612UKA2I bool select SOC_RW612 -config SOC_PART_NUMBER_RW610ETA1I +config SOC_PART_NUMBER_RW610ETA2I bool select SOC_RW610 -config SOC_PART_NUMBER_RW610HNA1I +config SOC_PART_NUMBER_RW610HNA2I bool select SOC_RW610 -config SOC_PART_NUMBER_RW610UKA1I +config SOC_PART_NUMBER_RW610UKA2I bool select SOC_RW610 config SOC_PART_NUMBER string - default "RW612ETA1I" if SOC_PART_NUMBER_RW612ETA1I - default "RW612HNA1I" if SOC_PART_NUMBER_RW612HNA1I - default "RW612UKA1I" if SOC_PART_NUMBER_RW612UKA1I - default "RW610ETA1I" if SOC_PART_NUMBER_RW610ETA1I - default "RW610HNA1I" if SOC_PART_NUMBER_RW610HNA1I - default "RW610UKA1I" if SOC_PART_NUMBER_RW610UKA1I + default "RW612ETA2I" if SOC_PART_NUMBER_RW612ETA2I + default "RW612HNA2I" if SOC_PART_NUMBER_RW612HNA2I + default "RW612UKA2I" if SOC_PART_NUMBER_RW612UKA2I + default "RW610ETA2I" if SOC_PART_NUMBER_RW610ETA2I + default "RW610HNA2I" if SOC_PART_NUMBER_RW610HNA2I + default "RW610UKA2I" if SOC_PART_NUMBER_RW610UKA2I diff --git a/soc/nxp/rw/flash_config.h b/soc/nxp/rw/flash_config.h new file mode 100644 index 00000000000..b5c7db0da72 --- /dev/null +++ b/soc/nxp/rw/flash_config.h @@ -0,0 +1,191 @@ +/* + * Copyright 2021-2023 NXP + * All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __FLASH_CONFIG__ +#define __FLASH_CONFIG__ + +#include +#include +#include "fsl_common.h" + + +#define FC_BLOCK_TAG (0x42464346) +#define FC_BLOCK_VERSION (0x00000000) + +#define FC_CMD_SDR 0x01 +#define FC_CMD_DDR 0x21 +#define FC_RADDR_SDR 0x02 +#define FC_RADDR_DDR 0x22 +#define FC_CADDR_SDR 0x03 +#define FC_CADDR_DDR 0x23 +#define FC_MODE1_SDR 0x04 +#define FC_MODE1_DDR 0x24 +#define FC_MODE2_SDR 0x05 +#define FC_MODE2_DDR 0x25 +#define FC_MODE4_SDR 0x06 +#define FC_MODE4_DDR 0x26 +#define FC_MODE8_SDR 0x07 +#define FC_MODE8_DDR 0x27 +#define FC_WRITE_SDR 0x08 +#define FC_WRITE_DDR 0x28 +#define FC_READ_SDR 0x09 +#define FC_READ_DDR 0x29 +#define FC_LEARN_SDR 0x0A +#define FC_LEARN_DDR 0x2A +#define FC_DATSZ_SDR 0x0B +#define FC_DATSZ_DDR 0x2B +#define FC_DUMMY_SDR 0x0C +#define FC_DUMMY_DDR 0x2C +#define FC_DUMMY_RWDS_SDR 0x0D +#define FC_DUMMY_RWDS_DDR 0x2D +#define FC_JMP_ON_CS 0x1F +#define FC_STOP_EXE 0 + +#define FC_FLEXSPI_1PAD 0 +#define FC_FLEXSPI_2PAD 1 +#define FC_FLEXSPI_4PAD 2 +#define FC_FLEXSPI_8PAD 3 + +#define FC_FLEXSPI_LUT_SEQ(cmd0, pad0, op0, cmd1, pad1, op1) \ + (FLEXSPI_LUT_OPERAND0(op0) | FLEXSPI_LUT_NUM_PADS0(pad0) | FLEXSPI_LUT_OPCODE0(cmd0) | \ + FLEXSPI_LUT_OPERAND1(op1) | FLEXSPI_LUT_NUM_PADS1(pad1) | FLEXSPI_LUT_OPCODE1(cmd1)) + + +enum { + kSerialFlash_1Pads = 1, + kSerialFlash_2Pads = 2, + kSerialFlash_4Pads = 4, + kSerialFlash_8Pads = 8, +}; + + +enum { + kFlexSpiSerialClk_30MHz = 1, + kFlexSpiSerialClk_50MHz = 2, + kFlexSpiSerialClk_60MHz = 3, + kFlexSpiSerialClk_80MHz = 4, + kFlexSpiSerialClk_100MHz = 5, + kFlexSpiSerialClk_120MHz = 6, + kFlexSpiSerialClk_133MHz = 7, + kFlexSpiSerialClk_166MHz = 8, + kFlexSpiSerialClk_200MHz = 9, +}; + + +enum { + kFlexSpiSerialClk_SDR_24MHz = 1, + kFlexSpiSerialClk_SDR_48MHz = 2, +}; + + +enum { + kFlexSpiSerialClk_DDR_48MHz = 1, +}; + + +enum { + kFlexSpiMiscOffset_DiffClkEnable = 0, + kFlexSpiMiscOffset_WordAddressableEnable = 3, + kFlexSpiMiscOffset_SafeConfigFreqEnable = + 4, + kFlexSpiMiscOffset_DdrModeEnable = 6, +}; + + +enum { + kDeviceConfigCmdType_Generic, + kDeviceConfigCmdType_QuadEnable, + kDeviceConfigCmdType_Spi2Xpi, + kDeviceConfigCmdType_Xpi2Spi, + kDeviceConfigCmdType_Spi2NoCmd, + kDeviceConfigCmdType_Reset, +}; + +typedef struct _fc_flexspi_dll_time { + uint8_t time_100ps; + uint8_t delay_cells; +} fc_flexspi_dll_time_t; + + +typedef struct _fc_flexspi_lut_seq { + uint8_t seqNum; + uint8_t seqId; + uint16_t reserved; +} fc_flexspi_lut_seq_t; + + +typedef struct _fc_flexspi_mem_config { + uint32_t tag; + uint32_t version; + uint32_t reserved0; + uint8_t readSampleClkSrc; + uint8_t csHoldTime; + uint8_t csSetupTime; + uint8_t columnAddressWidth; + uint8_t deviceModeCfgEnable; + uint8_t deviceModeType; + uint16_t waitTimeCfgCommands; + fc_flexspi_lut_seq_t deviceModeSeq; + uint32_t deviceModeArg; + uint8_t configCmdEnable; + uint8_t configModeType[3]; + fc_flexspi_lut_seq_t configCmdSeqs[3]; + uint32_t reserved1; + uint32_t configCmdArgs[3]; + uint32_t reserved2; + uint32_t controllerMiscOption; + uint8_t deviceType; + uint8_t sflashPadType; + uint8_t serialClkFreq; + uint8_t lutCustomSeqEnable; + uint32_t reserved3[2]; + uint32_t sflashA1Size; + uint32_t sflashA2Size; + uint32_t sflashB1Size; + uint32_t sflashB2Size; + uint32_t csPadSettingOverride; + uint32_t sclkPadSettingOverride; + uint32_t dataPadSettingOverride; + uint32_t dqsPadSettingOverride; + uint32_t timeoutInMs; + uint32_t commandInterval; + fc_flexspi_dll_time_t dataValidTime[2]; + uint16_t busyOffset; + uint16_t busyBitPolarity; + uint32_t lookupTable[64]; + fc_flexspi_lut_seq_t lutCustomSeq[12]; + uint32_t reserved4[4]; +} fc_flexspi_mem_config_t; + +typedef struct _fc_flexspi_nor_config { +#if defined(__ARMCC_VERSION) || defined(__ICCARM__) + uint8_t padding[0x400]; +#endif + fc_flexspi_mem_config_t memConfig; + uint32_t pageSize; + uint32_t sectorSize; + uint8_t ipcmdSerialClkFreq; + uint8_t isUniformBlockSize; + uint8_t isDataOrderSwapped; + uint8_t reserved0[1]; + uint8_t serialNorType; + uint8_t needExitNoCmdMode; + uint8_t halfClkForNonReadCmd; + uint8_t needRestoreNoCmdMode; + uint32_t blockSize; + uint32_t flashStateCtx; + uint32_t reserve2[10]; + uint32_t fcb_fill[0x280]; +} fc_flexspi_nor_config_t; +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} +#endif +#endif diff --git a/soc/nxp/rw/flexspi_clock_setup.c b/soc/nxp/rw/flexspi_clock_setup.c index 3876e1adbf4..3eb5640d82d 100644 --- a/soc/nxp/rw/flexspi_clock_setup.c +++ b/soc/nxp/rw/flexspi_clock_setup.c @@ -43,7 +43,7 @@ int __ramfunc flexspi_clock_set_freq(uint32_t clock_name, uint32_t rate) FLEXSPI_Enable(FLEXSPI, false); set_flexspi_clock(FLEXSPI, (CLKCTL0->FLEXSPIFCLKSEL & - CLKCTL0_FLEXSPIFCLKDIV_DIV_MASK), (divider + 1)); + CLKCTL0_FLEXSPIFCLKSEL_SEL_MASK), (divider + 1)); FLEXSPI_Enable(FLEXSPI, true); diff --git a/soc/nxp/rw/power.c b/soc/nxp/rw/power.c new file mode 100644 index 00000000000..69e9901f0d2 --- /dev/null +++ b/soc/nxp/rw/power.c @@ -0,0 +1,77 @@ +/* + * Copyright 2023, NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include + +#include "fsl_power.h" + +#include +LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL); + +/* Active mode */ +#define POWER_MODE0 0 +/* Idle mode */ +#define POWER_MODE1 1 +/* Standby mode */ +#define POWER_MODE2 2 +/* Sleep mode */ +#define POWER_MODE3 3 +/* Deep Sleep mode */ +#define POWER_MODE4 4 + +#define NODE_ID DT_INST(0, nxp_pdcfg_power) + +power_sleep_config_t slp_cfg; + +/* Invoke Low Power/System Off specific Tasks */ +__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +{ + ARG_UNUSED(substate_id); + + /* Set PRIMASK */ + __disable_irq(); + /* Set BASEPRI to 0 */ + irq_unlock(0); + + switch (state) { + case PM_STATE_RUNTIME_IDLE: + POWER_SetSleepMode(POWER_MODE1); + __WFI(); + break; + case PM_STATE_SUSPEND_TO_IDLE: + POWER_EnterPowerMode(POWER_MODE2, &slp_cfg); + break; + default: + LOG_DBG("Unsupported power state %u", state); + break; + } +} + +/* Handle SOC specific activity after Low Power Mode Exit */ +__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +{ + ARG_UNUSED(state); + ARG_UNUSED(substate_id); + + /* Clear PRIMASK */ + __enable_irq(); +} + +static int nxp_rw6xx_power_init(void) +{ + uint32_t suspend_sleepconfig[5] = DT_PROP_OR(NODE_ID, deep_sleep_config, {}); + + slp_cfg.pm2MemPuCfg = suspend_sleepconfig[0]; + slp_cfg.pm2AnaPuCfg = suspend_sleepconfig[1]; + slp_cfg.clkGate = suspend_sleepconfig[2]; + slp_cfg.memPdCfg = suspend_sleepconfig[3]; + slp_cfg.pm3BuckCfg = suspend_sleepconfig[4]; + + return 0; +} + +SYS_INIT(nxp_rw6xx_power_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); diff --git a/soc/nxp/rw/soc.c b/soc/nxp/rw/soc.c index f1571010bdd..a18aff5cf8a 100644 --- a/soc/nxp/rw/soc.c +++ b/soc/nxp/rw/soc.c @@ -138,6 +138,10 @@ __ramfunc void clock_init(void) /* Call function set_flexspi_clock() to set flexspi clock source to aux0_pll_clk in XIP. */ set_flexspi_clock(FLEXSPI, 2U, 2U); +#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(os_timer), nxp_os_timer, okay) + CLOCK_AttachClk(kLPOSC_to_OSTIMER_CLK); +#endif + #if (DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(wwdt), nxp_lpc_wwdt, okay)) CLOCK_AttachClk(kLPOSC_to_WDT0_CLK); #else @@ -147,6 +151,14 @@ __ramfunc void clock_init(void) CLOCK_AttachClk(kNONE_to_WDT0_CLK); #endif +#if defined(CONFIG_ADC_MCUX_GAU) || defined(CONFIG_DAC_MCUX_GAU) + /* Attack clock for GAU and reset */ + CLOCK_AttachClk(kMAIN_CLK_to_GAU_CLK); + CLOCK_SetClkDiv(kCLOCK_DivGauClk, 1U); + CLOCK_EnableClock(kCLOCK_Gau); + RESET_PeripheralReset(kGAU_RST_SHIFT_RSTn); +#endif /* GAU */ + /* Any flexcomm can be USART */ #if (DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(flexcomm0), nxp_lpc_usart, okay)) && CONFIG_SERIAL CLOCK_SetFRGClock(&(const clock_frg_clk_config_t){0, kCLOCK_FrgPllDiv, 255, 0}); @@ -238,11 +250,6 @@ __ramfunc void clock_init(void) #endif #endif /* CONFIG_COUNTER_MCUX_CTIMER */ -#ifdef CONFIG_COUNTER_NXP_MRT - RESET_PeripheralReset(kMRT_RST_SHIFT_RSTn); - RESET_PeripheralReset(kFREEMRT_RST_SHIFT_RSTn); -#endif - #if DT_NODE_HAS_STATUS(DT_NODELABEL(usb_otg), okay) && CONFIG_USB_DC_NXP_EHCI /* Enable system xtal from Analog */ SYSCTL2->ANA_GRP_CTRL |= SYSCTL2_ANA_GRP_CTRL_PU_AG_MASK; @@ -272,20 +279,28 @@ static int nxp_rw600_init(void) POWER_EnableResetSource(kPOWER_ResetSourceWdt); #endif +#if DT_NODE_HAS_PROP(DT_NODELABEL(pmu), reset_causes_en) #define PMU_RESET_CAUSES_ \ DT_FOREACH_PROP_ELEM_SEP(DT_NODELABEL(pmu), reset_causes_en, DT_PROP_BY_IDX, (|)) #define PMU_RESET_CAUSES \ COND_CODE_0(IS_EMPTY(PMU_RESET_CAUSES_), (PMU_RESET_CAUSES_), (0)) #define WDT_RESET \ - COND_CODE_1(DT_NODE_HAS_STATUS_OKAY(wwdt), (kPOWER_ResetSourceWdt), (0)) + COND_CODE_1(DT_NODE_HAS_STATUS(wwdt, okay), (kPOWER_ResetSourceWdt), (0)) #define RESET_CAUSES \ (PMU_RESET_CAUSES | WDT_RESET) +#else +#define RESET_CAUSES 0 +#endif POWER_EnableResetSource(RESET_CAUSES); /* Initialize clock */ clock_init(); +#if defined(CONFIG_ADC_MCUX_GAU) || defined(CONFIG_DAC_MCUX_GAU) + POWER_PowerOnGau(); +#endif + return 0; } diff --git a/soc/nxp/rw/soc.h b/soc/nxp/rw/soc.h index a9a28b3ab6e..780bd9b66aa 100644 --- a/soc/nxp/rw/soc.h +++ b/soc/nxp/rw/soc.h @@ -9,12 +9,18 @@ #ifndef _ASMLANGUAGE #include #include +#include "fsl_power.h" /* Add include for DTS generated information */ #include #endif /* !_ASMLANGUAGE */ +/* Wrapper Function to deal with SDK differences in power API */ +static inline void EnableDeepSleepIRQ(IRQn_Type irq) +{ + POWER_EnableWakeup(irq); +} #ifdef CONFIG_MEMC int flexspi_clock_set_freq(uint32_t clock_name, uint32_t rate); diff --git a/soc/renesas/ra/ra4m1/CMakeLists.txt b/soc/renesas/ra/ra4m1/CMakeLists.txt index c0d9c7b1baa..00cdd96aa18 100644 --- a/soc/renesas/ra/ra4m1/CMakeLists.txt +++ b/soc/renesas/ra/ra4m1/CMakeLists.txt @@ -3,4 +3,13 @@ zephyr_include_directories(.) +zephyr_library_sources_ifdef(CONFIG_SOC_OPTION_SETTING_MEMORY + soc.c +) + +zephyr_linker_sources_ifdef(CONFIG_SOC_OPTION_SETTING_MEMORY + ROM_START + ${CMAKE_CURRENT_SOURCE_DIR}/opt_set_mem.ld +) + set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/renesas/ra/ra4m1/Kconfig b/soc/renesas/ra/ra4m1/Kconfig index 56153d0732f..c2f9efea3c7 100644 --- a/soc/renesas/ra/ra4m1/Kconfig +++ b/soc/renesas/ra/ra4m1/Kconfig @@ -9,3 +9,7 @@ config SOC_SERIES_RA4M1 select DYNAMIC_INTERRUPTS select TIMER_READS_ITS_FREQUENCY_AT_RUNTIME select XIP + +config SOC_OPTION_SETTING_MEMORY + bool "Option Setting Memory" + default y diff --git a/soc/renesas/ra/ra4m1/opt_set_mem.ld b/soc/renesas/ra/ra4m1/opt_set_mem.ld new file mode 100644 index 00000000000..c05238789af --- /dev/null +++ b/soc/renesas/ra/ra4m1/opt_set_mem.ld @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2024 Ian Morris + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +. = 0x400; +FILL(0xFF) +KEEP(*(.opt_set_mem*)) +. = 0x500; diff --git a/soc/renesas/ra/ra4m1/soc.c b/soc/renesas/ra/ra4m1/soc.c new file mode 100644 index 00000000000..7f021ba17fa --- /dev/null +++ b/soc/renesas/ra/ra4m1/soc.c @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2024 Ian Morris + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include + +#define HOCO_FREQ DT_PROP(DT_PATH(clocks, hoco), clock_frequency) + +#if HOCO_FREQ == MHZ(24) +#define OFS1_HOCO_FREQ 0 +#elif HOCO_FREQ == MHZ(32) +#define OFS1_HOCO_FREQ 2 +#elif HOCO_FREQ == MHZ(48) +#define OFS1_HOCO_FREQ 4 +#elif HOCO_FREQ == MHZ(64) +#define OFS1_HOCO_FREQ 5 +#else +#error "Unsupported HOCO frequency" +#endif + +struct ofs0_reg { + uint32_t RSVD1: 1; + uint32_t IWDTSTRT: 1; + uint32_t IWDTTOPS: 2; + uint32_t IWDTCKS: 4; + uint32_t IWDTRPES: 2; + uint32_t IWDTRPSS: 2; + uint32_t IWDTRSTIRQS: 1; + uint32_t RSVD2: 1; + uint32_t IWDTSTPCTL: 1; + uint32_t RSVD3: 2; + uint32_t WDTSTRT: 1; + uint32_t WDTTOPS: 2; + uint32_t WDTCKS: 4; + uint32_t WDTRPES: 2; + uint32_t WDTRPSS: 2; + uint32_t WDTRSTIRQS: 1; + uint32_t RSVD4: 1; + uint32_t WDTSTPCTL: 1; + uint32_t RSVD5: 1; +}; + +struct ofs1_reg { + uint32_t RSVD1: 2; + uint32_t LVDAS: 1; + uint32_t VDSEL1: 3; + uint32_t RSVD2: 2; + uint32_t HOCOEN: 1; + uint32_t RSVD3: 3; + uint32_t HOCOFRQ1: 3; + uint32_t RSVD4: 17; +}; + +struct mpu_regs { + uint32_t SECMPUPCSO; + uint32_t SECMPUPCEO; + uint32_t SECMPUPCS1; + uint32_t SECMPUPCE1; + uint32_t SECMPUS0; + uint32_t SECMPUE0; + uint32_t SECMPUS1; + uint32_t SECMPUE1; + uint32_t SECMPUS2; + uint32_t SECMPUE2; + uint32_t SECMPUS3; + uint32_t SECMPUE3; + uint32_t SECMPUAC; +}; + +struct opt_set_mem { + struct ofs0_reg ofs0; + struct ofs1_reg ofs1; + struct mpu_regs mpu; +}; + +#ifdef CONFIG_SOC_OPTION_SETTING_MEMORY +const struct opt_set_mem ops __attribute__((section(".opt_set_mem"))) = { + .ofs0 = { + /* + * Initial settings for watchdog timers. Set all fields to 1, + * disabling watchdog functionality as config options have not + * yet been implemented. + */ + .RSVD1 = 0x1, + .IWDTSTRT = 0x1, /* Disable independent watchdog timer */ + .IWDTTOPS = 0x3, + .IWDTCKS = 0xf, + .IWDTRPES = 0x3, + .IWDTRPSS = 0x3, + .IWDTRSTIRQS = 0x1, + .RSVD2 = 0x1, + .IWDTSTPCTL = 0x1, + .RSVD3 = 0x3, + .WDTSTRT = 0x1, /* Stop watchdog timer following reset */ + .WDTTOPS = 0x3, + .WDTCKS = 0xf, + .WDTRPES = 0x3, + .WDTRPSS = 0x3, + .WDTRSTIRQS = 0x1, + .RSVD4 = 0x1, + .WDTSTPCTL = 0x1, + .RSVD5 = 0x1, + }, + .ofs1 = { + .RSVD1 = 0x3, + .LVDAS = 0x1, /* Disable voltage monitor 0 following reset */ + .VDSEL1 = 0x3, + .RSVD2 = 0x3, + .HOCOEN = !DT_NODE_HAS_STATUS(DT_PATH(clocks, hoco), okay), + .RSVD3 = 0x7, + .HOCOFRQ1 = OFS1_HOCO_FREQ, + .RSVD4 = 0x1ffff, + }, + .mpu = { + /* + * Initial settings for MPU. Set all areas to maximum values + * essentially disabling MPU functionality as config options + * have not yet been implemented. + */ + .SECMPUPCSO = 0x00fffffc, + .SECMPUPCEO = 0x00ffffff, + .SECMPUPCS1 = 0x00fffffc, + .SECMPUPCE1 = 0x00ffffff, + .SECMPUS0 = 0x00fffffc, + .SECMPUE0 = 0x00ffffff, + .SECMPUS1 = 0x200ffffc, + .SECMPUE1 = 0x200fffff, + .SECMPUS2 = 0x407ffffc, + .SECMPUE2 = 0x407fffff, + .SECMPUS3 = 0x40dffffc, + .SECMPUE3 = 0x40dfffff, + .SECMPUAC = 0xffffffff, + } +}; +#endif diff --git a/soc/renesas/rcar/rcar_gen4/CMakeLists.txt b/soc/renesas/rcar/rcar_gen4/CMakeLists.txt index 691c155c6e3..17936ad303b 100644 --- a/soc/renesas/rcar/rcar_gen4/CMakeLists.txt +++ b/soc/renesas/rcar/rcar_gen4/CMakeLists.txt @@ -1,5 +1,11 @@ # Copyright (c) 2023 IoT.bzh # SPDX-License-Identifier: Apache-2.0 -zephyr_include_directories(.) -set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_a_r/scripts/linker.ld CACHE INTERNAL "") +if(CONFIG_SOC_R8A779F0_R52) + zephyr_include_directories(r52) + set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_a_r/scripts/linker.ld CACHE INTERNAL "") +elseif(CONFIG_SOC_R8A779F0_A55) + zephyr_include_directories(a55) + zephyr_library_sources_ifdef(CONFIG_ARM_MMU a55/mmu_regions.c) + set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm64/scripts/linker.ld CACHE INTERNAL "") +endif() diff --git a/soc/renesas/rcar/rcar_gen4/Kconfig b/soc/renesas/rcar/rcar_gen4/Kconfig index a084ac558b8..fb05e3c06c8 100644 --- a/soc/renesas/rcar/rcar_gen4/Kconfig +++ b/soc/renesas/rcar/rcar_gen4/Kconfig @@ -1,10 +1,15 @@ # Copyright (c) 2023 IoT.bzh # SPDX-License-Identifier: Apache-2.0 -config SOC_SERIES_RCAR_GEN4 - bool +config SOC_R8A779F0_R52 select ARM select CPU_CORTEX_R52 select GIC_SINGLE_SECURITY_STATE select CLOCK_CONTROL_RCAR_CPG_MSSR if CLOCK_CONTROL select ARM_ARCH_TIMER + +config SOC_R8A779F0_A55 + select ARM64 + select CPU_CORTEX_A55 + select CLOCK_CONTROL_RCAR_CPG_MSSR if CLOCK_CONTROL + select ARM_ARCH_TIMER diff --git a/soc/renesas/rcar/rcar_gen4/Kconfig.defconfig.r8a779f0 b/soc/renesas/rcar/rcar_gen4/Kconfig.defconfig.r8a779f0 index c3c09787e11..3874573bcf7 100644 --- a/soc/renesas/rcar/rcar_gen4/Kconfig.defconfig.r8a779f0 +++ b/soc/renesas/rcar/rcar_gen4/Kconfig.defconfig.r8a779f0 @@ -1,7 +1,7 @@ # Copyright (c) 2023 IoT.bzh # SPDX-License-Identifier: Apache-2.0 -if SOC_R8A779F0 +if SOC_SERIES_RCAR_GEN4 config NUM_IRQS default 1216 #960 SPI + 256 LPI @@ -9,4 +9,4 @@ config NUM_IRQS config PINCTRL default y -endif # SOC_R8A779F0 +endif # SOC_SERIES_RCAR_GEN4 diff --git a/soc/renesas/rcar/rcar_gen4/Kconfig.soc b/soc/renesas/rcar/rcar_gen4/Kconfig.soc index 99193973d59..fa99fed2482 100644 --- a/soc/renesas/rcar/rcar_gen4/Kconfig.soc +++ b/soc/renesas/rcar/rcar_gen4/Kconfig.soc @@ -5,14 +5,20 @@ config SOC_SERIES_RCAR_GEN4 bool select SOC_FAMILY_RENESAS_RCAR -config SOC_R8A779F0 +config SOC_R8A779F0_R52 bool select SOC_SERIES_RCAR_GEN4 help - r8a779f0 + r8a779f0 r52 + +config SOC_R8A779F0_A55 + bool + select SOC_SERIES_RCAR_GEN4 + help + r8a779f0 a55 config SOC_SERIES default "rcar_gen4" if SOC_SERIES_RCAR_GEN4 config SOC - default "r8a779f0" if SOC_R8A779F0 + default "r8a779f0" if SOC_R8A779F0_R52 || SOC_R8A779F0_A55 diff --git a/soc/renesas/rcar/rcar_gen4/a55/mmu_regions.c b/soc/renesas/rcar/rcar_gen4/a55/mmu_regions.c new file mode 100644 index 00000000000..64cfa479785 --- /dev/null +++ b/soc/renesas/rcar/rcar_gen4/a55/mmu_regions.c @@ -0,0 +1,25 @@ +/* + * Copyright 2023 EPAM Systems + * + * 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_INST(0, arm_gic), 0), + DT_REG_SIZE_BY_IDX(DT_INST(0, arm_gic), 0), + MT_DEVICE_nGnRnE | MT_RW | MT_NS), + + MMU_REGION_FLAT_ENTRY("GIC", + DT_REG_ADDR_BY_IDX(DT_INST(0, arm_gic), 1), + DT_REG_SIZE_BY_IDX(DT_INST(0, arm_gic), 1), + MT_DEVICE_nGnRnE | MT_RW | MT_NS), +}; + +const struct arm_mmu_config mmu_config = { + .num_regions = ARRAY_SIZE(mmu_regions), + .mmu_regions = mmu_regions, +}; diff --git a/soc/renesas/rcar/rcar_gen4/pinctrl_soc.h b/soc/renesas/rcar/rcar_gen4/a55/pinctrl_soc.h similarity index 100% rename from soc/renesas/rcar/rcar_gen4/pinctrl_soc.h rename to soc/renesas/rcar/rcar_gen4/a55/pinctrl_soc.h diff --git a/soc/renesas/rcar/rcar_gen4/r52/pinctrl_soc.h b/soc/renesas/rcar/rcar_gen4/r52/pinctrl_soc.h new file mode 100644 index 00000000000..b9c5ae88b6e --- /dev/null +++ b/soc/renesas/rcar/rcar_gen4/r52/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/renesas/rcar/rcar_gen4/soc.h b/soc/renesas/rcar/rcar_gen4/r52/soc.h similarity index 100% rename from soc/renesas/rcar/rcar_gen4/soc.h rename to soc/renesas/rcar/rcar_gen4/r52/soc.h diff --git a/soc/renesas/rcar/soc.yml b/soc/renesas/rcar/soc.yml index 6c936a7b7c9..17d2f870928 100644 --- a/soc/renesas/rcar/soc.yml +++ b/soc/renesas/rcar/soc.yml @@ -11,3 +11,6 @@ family: - name: rcar_gen4 socs: - name: r8a779f0 + cpuclusters: + - name: r52 + - name: a55 diff --git a/soc/renesas/smartbond/da1469x/CMakeLists.txt b/soc/renesas/smartbond/da1469x/CMakeLists.txt index 0c45be52d2d..164e641cc0f 100644 --- a/soc/renesas/smartbond/da1469x/CMakeLists.txt +++ b/soc/renesas/smartbond/da1469x/CMakeLists.txt @@ -8,5 +8,6 @@ zephyr_linker_sources( zephyr_library() zephyr_library_sources(soc.c) zephyr_include_directories(.) +zephyr_library_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/renesas/smartbond/da1469x/Kconfig b/soc/renesas/smartbond/da1469x/Kconfig index 267df2ea79d..b07c4274ad6 100644 --- a/soc/renesas/smartbond/da1469x/Kconfig +++ b/soc/renesas/smartbond/da1469x/Kconfig @@ -9,5 +9,9 @@ config SOC_SERIES_DA1469X select CPU_CORTEX_M_HAS_SYSTICK select ARMV8_M_DSP select HAS_SEGGER_RTT if ZEPHYR_SEGGER_MODULE + select HAS_PM select CLOCK_CONTROL select CLOCK_CONTROL_SMARTBOND + select PLATFORM_SPECIFIC_INIT + select PM_DEVICE if PM + imply TIMER_READS_ITS_FREQUENCY_AT_RUNTIME diff --git a/soc/renesas/smartbond/da1469x/Kconfig.defconfig b/soc/renesas/smartbond/da1469x/Kconfig.defconfig index fedbde9f19e..239c34482b0 100644 --- a/soc/renesas/smartbond/da1469x/Kconfig.defconfig +++ b/soc/renesas/smartbond/da1469x/Kconfig.defconfig @@ -3,11 +3,21 @@ if SOC_SERIES_DA1469X +config SMARTBOND_TIMER + default y if PM + +config CORTEX_M_SYSTICK + default n if SMARTBOND_TIMER + config NUM_IRQS default 40 config SYS_CLOCK_HW_CYCLES_PER_SEC - default $(dt_node_int_prop_int,/cpus/cpu@0,clock-frequency) + default $(dt_node_int_prop_int,/cpus/cpu@0,clock-frequency) if CORTEX_M_SYSTICK + default 32768 if SMARTBOND_TIMER + +config SYS_CLOCK_TICKS_PER_SEC + default 32768 if SMARTBOND_TIMER config SRAM_VECTOR_TABLE default y @@ -21,7 +31,4 @@ config FLASH_BASE_ADDRESS config FLASH_LOAD_OFFSET default 0x2400 if !USE_DT_CODE_PARTITION -config PLATFORM_SPECIFIC_INIT - default y - endif # SOC_SERIES_DA1469X diff --git a/soc/renesas/smartbond/da1469x/power.c b/soc/renesas/smartbond/da1469x/power.c new file mode 100644 index 00000000000..1b325c47eb8 --- /dev/null +++ b/soc/renesas/smartbond/da1469x/power.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2023 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL); + +void pm_state_set(enum pm_state state, uint8_t substate_id) +{ + ARG_UNUSED(substate_id); + + switch (state) { + case PM_STATE_STANDBY: + /* We enter here with interrupts disabled by BASEPRI which prevents wfi from + * waking up on interrupts. Need to disable interrupts by PRIMASK instead and + * reset BASEPRI to 0. + */ + __disable_irq(); + arch_irq_unlock(0); + + da1469x_sleep(); + + 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(state); + ARG_UNUSED(substate_id); +} + +static int renesas_da1469x_pm_init(void) +{ + static const struct da1469x_sleep_config sleep_cfg = { + .enable_xtal_on_wakeup = DT_NODE_HAS_STATUS(DT_NODELABEL(xtal32m), okay), + }; + + da1469x_sleep_config(&sleep_cfg); + + return 0; +} + +SYS_INIT(renesas_da1469x_pm_init, PRE_KERNEL_2, 2); diff --git a/soc/renesas/smartbond/da1469x/soc.c b/soc/renesas/smartbond/da1469x/soc.c index 5fc566748c6..a6626aa9598 100644 --- a/soc/renesas/smartbond/da1469x/soc.c +++ b/soc/renesas/smartbond/da1469x/soc.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -13,7 +14,9 @@ #include #include #include -#include +#include + +LOG_MODULE_REGISTER(soc, CONFIG_SOC_LOG_LEVEL); #define REMAP_ADR0_QSPI 0x2 @@ -108,15 +111,31 @@ static void z_renesas_configure_cache(void) void z_arm_platform_init(void) { +#if defined(CONFIG_PM) + uint32_t *ivt; +#endif + #if defined(CONFIG_BOOTLOADER_MCUBOOT) z_renesas_configure_cache(); #endif + +#if defined(CONFIG_PM) + /* IVT is always placed in reserved space at the start of RAM which + * is then remapped to 0x0 and retained. Generic reset handler is + * changed to custom routine since next time ARM core is reset we + * need to determine whether it was a regular reset or a wakeup from + * extended sleep and ARM core state needs to be restored. + */ + ivt = (uint32_t *)_image_ram_start; + ivt[1] = (uint32_t)da1469x_wakeup_handler; +#endif } static int renesas_da1469x_init(void) { /* Freeze watchdog until configured */ GPREG->SET_FREEZE_REG = GPREG_SET_FREEZE_REG_FRZ_SYS_WDOG_Msk; + SYS_WDOG->WATCHDOG_REG = SYS_WDOG_WATCHDOG_REG_WDOG_VAL_Msk; /* Reset clock dividers to 0 */ CRG_TOP->CLK_AMBA_REG &= ~(CRG_TOP_CLK_AMBA_REG_HCLK_DIV_Msk | @@ -127,8 +146,10 @@ static int renesas_da1469x_init(void) CRG_TOP_PMU_CTRL_REG_COM_SLEEP_Msk | CRG_TOP_PMU_CTRL_REG_RADIO_SLEEP_Msk); - /* PDC should take care of PD_SYS */ - CRG_TOP->PMU_CTRL_REG &= ~CRG_TOP_PMU_CTRL_REG_SYS_SLEEP_Msk; +#if defined(CONFIG_PM) + /* Enable cache retainability */ + CRG_TOP->PMU_CTRL_REG |= CRG_TOP_PMU_CTRL_REG_RETAIN_CACHE_Msk; +#endif /* * Due to crosstalk issues any power rail can potentially @@ -143,15 +164,18 @@ static int renesas_da1469x_init(void) CRG_TOP_BOD_CTRL_REG_BOD_V30_EN_Msk | CRG_TOP_BOD_CTRL_REG_BOD_VBAT_EN_Msk); - da1469x_pdc_reset(); - da1469x_otp_init(); da1469x_trimv_init_from_otp(); da1469x_pd_init(); + + /* + * Take PD_SYS control. + */ da1469x_pd_acquire(MCU_PD_DOMAIN_SYS); da1469x_pd_acquire(MCU_PD_DOMAIN_TIM); - da1469x_pd_acquire(MCU_PD_DOMAIN_COM); + + da1469x_pdc_reset(); return 0; } diff --git a/soc/snps/nsim/Kconfig.defconfig.hs5x_smp b/soc/snps/nsim/Kconfig.defconfig.hs5x_smp index 9d7ac1d7f4c..69b0b578afa 100644 --- a/soc/snps/nsim/Kconfig.defconfig.hs5x_smp +++ b/soc/snps/nsim/Kconfig.defconfig.hs5x_smp @@ -15,7 +15,7 @@ config NUM_IRQS default 30 config SYS_CLOCK_HW_CYCLES_PER_SEC - default 5000000 + default 1000000 config CACHE_MANAGEMENT default y diff --git a/soc/st/stm32/Kconfig b/soc/st/stm32/Kconfig index 773e62a0dc7..5b299239b84 100644 --- a/soc/st/stm32/Kconfig +++ b/soc/st/stm32/Kconfig @@ -47,6 +47,9 @@ config SWJ_ANALOG_PRIORITY This priority must be greater than GPIO_INIT_PRIORITY and lower than UART_INIT_PRIORITY. +config STM32_FLASH_PREFETCH + bool "Flash prefetch buffer" + choice POWER_SUPPLY_CHOICE prompt "STM32 power supply configuration" default POWER_SUPPLY_LDO diff --git a/soc/st/stm32/Kconfig.defconfig b/soc/st/stm32/Kconfig.defconfig index d90ce9b7da8..64f6b817dd0 100644 --- a/soc/st/stm32/Kconfig.defconfig +++ b/soc/st/stm32/Kconfig.defconfig @@ -57,6 +57,10 @@ config CLOCK_CONTROL_INIT_PRIORITY default 1 depends on CLOCK_CONTROL +config PHY_INIT_PRIORITY + default 81 + depends on NET_L2_ETHERNET && ETH_DRIVER + config MEMC_STM32 default y depends on MEMC diff --git a/soc/st/stm32/soc.yml b/soc/st/stm32/soc.yml index 304ab56acfc..2572f6b0f0c 100644 --- a/soc/st/stm32/soc.yml +++ b/soc/st/stm32/soc.yml @@ -3,6 +3,7 @@ family: series: - name: stm32c0x socs: + - name: stm32c011xx - name: stm32c031xx - name: stm32f0x socs: diff --git a/soc/st/stm32/stm32c0x/Kconfig.defconfig.stm32c011xx b/soc/st/stm32/stm32c0x/Kconfig.defconfig.stm32c011xx new file mode 100644 index 00000000000..ace25ef8137 --- /dev/null +++ b/soc/st/stm32/stm32c0x/Kconfig.defconfig.stm32c011xx @@ -0,0 +1,11 @@ +# STMicroelectronics STM32C011xx MCU + +# Copyright (c) 2024 Kickmaker +# SPDX-License-Identifier: Apache-2.0 + +if SOC_STM32C011XX + +config NUM_IRQS + default 29 + +endif # SOC_STM32C011XX diff --git a/soc/st/stm32/stm32c0x/Kconfig.soc b/soc/st/stm32/stm32c0x/Kconfig.soc index c91158abbb1..57a833c82f0 100644 --- a/soc/st/stm32/stm32c0x/Kconfig.soc +++ b/soc/st/stm32/stm32c0x/Kconfig.soc @@ -14,5 +14,10 @@ config SOC_STM32C031XX bool select SOC_SERIES_STM32C0X +config SOC_STM32C011XX + bool + select SOC_SERIES_STM32C0X + config SOC + default "stm32c011xx" if SOC_STM32C011XX default "stm32c031xx" if SOC_STM32C031XX diff --git a/soc/st/stm32/stm32f1x/Kconfig.defconfig.stm32f100xx b/soc/st/stm32/stm32f1x/Kconfig.defconfig.stm32f100xx index 916d2fd3d31..65df1c356e7 100644 --- a/soc/st/stm32/stm32f1x/Kconfig.defconfig.stm32f100xx +++ b/soc/st/stm32/stm32f1x/Kconfig.defconfig.stm32f100xx @@ -1,13 +1,10 @@ -# ST Microelectronics STM32F100XX MCU +# STMicroelectronics STM32F100XX MCU # Copyright (c) 2020, Jonas Eriksson, Up to Code AB # SPDX-License-Identifier: Apache-2.0 if SOC_STM32F100XB -config SOC - default "stm32f100xb" - config NUM_IRQS default 56 @@ -15,9 +12,6 @@ endif # SOC_STM32F100XB if SOC_STM32F100XE -config SOC - default "stm32f100xe" - config NUM_IRQS default 61 diff --git a/soc/st/stm32/stm32g0x/soc.c b/soc/st/stm32/stm32g0x/soc.c index 77c66858a2f..bab4e3dbca2 100644 --- a/soc/st/stm32/stm32g0x/soc.c +++ b/soc/st/stm32/stm32g0x/soc.c @@ -16,8 +16,8 @@ #include #include -#if defined(SYSCFG_CFGR1_UCPD1_STROBE) || defined(SYSCFG_CFGR1_UCPD2_STROBE) #include +#if defined(SYSCFG_CFGR1_UCPD1_STROBE) || defined(SYSCFG_CFGR1_UCPD2_STROBE) #include #endif /* SYSCFG_CFGR1_UCPD1_STROBE || SYSCFG_CFGR1_UCPD2_STROBE */ @@ -81,6 +81,10 @@ static void stm32g0_disable_dead_battery(void) */ static int stm32g0_init(void) { + /* Enable ART Accelerator I-cache and prefetch */ + LL_FLASH_EnableInstCache(); + LL_FLASH_EnablePrefetch(); + /* Update CMSIS SystemCoreClock variable (HCLK) */ /* At reset, system core clock is set to 16 MHz from HSI */ SystemCoreClock = 16000000; diff --git a/soc/st/stm32/stm32l4x/soc.c b/soc/st/stm32/stm32l4x/soc.c index 48cd59b9012..8aaf22f1097 100644 --- a/soc/st/stm32/stm32l4x/soc.c +++ b/soc/st/stm32/stm32l4x/soc.c @@ -15,6 +15,7 @@ #include #include +#include #define LOG_LEVEL CONFIG_SOC_LOG_LEVEL LOG_MODULE_REGISTER(soc); @@ -30,6 +31,11 @@ LOG_MODULE_REGISTER(soc); */ static int stm32l4_init(void) { + /* Enable the ART Accelerator I-cache, D-cache and prefetch */ + LL_FLASH_EnableInstCache(); + LL_FLASH_EnableDataCache(); + LL_FLASH_EnablePrefetch(); + /* Update CMSIS SystemCoreClock variable (HCLK) */ /* At reset, system core clock is set to 4 MHz from MSI */ SystemCoreClock = 4000000; diff --git a/soc/st/stm32/stm32wbax/Kconfig.defconfig b/soc/st/stm32/stm32wbax/Kconfig.defconfig index 8a7e2c0ab04..3efc1e334f3 100644 --- a/soc/st/stm32/stm32wbax/Kconfig.defconfig +++ b/soc/st/stm32/stm32wbax/Kconfig.defconfig @@ -10,6 +10,9 @@ rsource "Kconfig.defconfig.stm32wba*" config STM32_LPTIM_TIMER default y if PM +config STM32_FLASH_PREFETCH + default y + choice BT_HCI_BUS_TYPE default BT_STM32WBA depends on BT diff --git a/soc/st/stm32/stm32wbax/soc.c b/soc/st/stm32/stm32wbax/soc.c index c3f12078e8d..983d8018a8d 100644 --- a/soc/st/stm32/stm32wbax/soc.c +++ b/soc/st/stm32/stm32wbax/soc.c @@ -37,6 +37,9 @@ int stm32wba_init(void) /* Enable instruction cache in 1-way (direct mapped cache) */ LL_ICACHE_SetMode(LL_ICACHE_1WAY); LL_ICACHE_Enable(); +#ifdef CONFIG_STM32_FLASH_PREFETCH + __HAL_FLASH_PREFETCH_BUFFER_ENABLE(); +#endif /* Update CMSIS SystemCoreClock variable (HCLK) */ /* At reset, system core clock is set to 16 MHz from HSI */ diff --git a/soc/ti/k3/am6x/CMakeLists.txt b/soc/ti/k3/am6x/CMakeLists.txt index 9f0cb3dd2f5..993d8d8d95b 100644 --- a/soc/ti/k3/am6x/CMakeLists.txt +++ b/soc/ti/k3/am6x/CMakeLists.txt @@ -7,7 +7,7 @@ if(CONFIG_SOC_AM6234_A53) zephyr_sources_ifdef(CONFIG_ARM_MMU a53/mmu_regions.c) set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm64/scripts/linker.ld CACHE INTERNAL "") -elseif(CONFIG_SOC_AM6234_M4) +elseif(CONFIG_SOC_SERIES_AM6X_M4) zephyr_sources(m4/soc.c) zephyr_include_directories(m4) diff --git a/soc/ti/k3/am6x/Kconfig b/soc/ti/k3/am6x/Kconfig index 8eb993db66f..f5596944bf8 100644 --- a/soc/ti/k3/am6x/Kconfig +++ b/soc/ti/k3/am6x/Kconfig @@ -21,3 +21,4 @@ config SOC_SERIES_AM6X_M4 config SOC_PART_NUMBER default "AM6234" if SOC_AM6234_A53 default "AM6234" if SOC_AM6234_M4 + default "AM6442" if SOC_AM6442_M4 diff --git a/soc/ti/k3/am6x/Kconfig.soc b/soc/ti/k3/am6x/Kconfig.soc index fa9c8e20f7e..df9805f92d4 100644 --- a/soc/ti/k3/am6x/Kconfig.soc +++ b/soc/ti/k3/am6x/Kconfig.soc @@ -25,8 +25,13 @@ config SOC_AM6234_M4 bool select SOC_SERIES_AM6X_M4 +config SOC_AM6442_M4 + bool + select SOC_SERIES_AM6X_M4 + config SOC_SERIES default "am6x" if SOC_SERIES_AM6X config SOC default "am6234" if SOC_AM6234_M4 || SOC_AM6234_A53 + default "am6442" if SOC_AM6442_M4 diff --git a/soc/ti/k3/am6x/m4/soc.c b/soc/ti/k3/am6x/m4/soc.c index 9c86eb09a1d..b2e261a4e9c 100644 --- a/soc/ti/k3/am6x/m4/soc.c +++ b/soc/ti/k3/am6x/m4/soc.c @@ -17,7 +17,7 @@ #define CSL_MCU_PADCONFIG_LOCK0_KICK0_OFFSET (0x1008) #define CSL_MCU_PADCONFIG_LOCK1_KICK0_OFFSET (0x5008) -static struct address_trans_region_config region_config[] = { +static struct address_trans_region_config am6x_region_config[] = { { .system_addr = 0x0u, .local_addr = 0x80000000u, @@ -44,7 +44,7 @@ static struct address_trans_region_config region_config[] = { */ }; -static void mmr_unlock(void) +static void am6x_mmr_unlock(void) { uint32_t baseAddr = PINCTRL_BASE_ADDR; uintptr_t kickAddr; @@ -62,12 +62,12 @@ static void mmr_unlock(void) sys_write32(KICK1_UNLOCK_VAL, kickAddr); /* KICK 1 */ } -static int am62x_m4_init(void) +static int am6x_m4_init(void) { - sys_mm_drv_ti_rat_init( - region_config, ADDR_TRANSLATE_RAT_BASE_ADDR, ARRAY_SIZE(region_config)); - mmr_unlock(); + sys_mm_drv_ti_rat_init(am6x_region_config, ADDR_TRANSLATE_RAT_BASE_ADDR, + ARRAY_SIZE(am6x_region_config)); + am6x_mmr_unlock(); return 0; } -SYS_INIT(am62x_m4_init, EARLY, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +SYS_INIT(am6x_m4_init, EARLY, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); diff --git a/soc/ti/k3/soc.yml b/soc/ti/k3/soc.yml index 92ae28d5a0a..3065ab13d42 100644 --- a/soc/ti/k3/soc.yml +++ b/soc/ti/k3/soc.yml @@ -7,3 +7,6 @@ family: cpuclusters: - name: m4 - name: a53 + - name: am6442 + cpuclusters: + - name: m4 diff --git a/soc/xlnx/zynq7000/xc7zxxx/Kconfig b/soc/xlnx/zynq7000/xc7zxxx/Kconfig index 7a94994fd8d..4e2d138229d 100644 --- a/soc/xlnx/zynq7000/xc7zxxx/Kconfig +++ b/soc/xlnx/zynq7000/xc7zxxx/Kconfig @@ -9,4 +9,5 @@ config SOC_SERIES_XC7ZXXX select ARM select CPU_CORTEX_A9 + select SYSCON select ARM_ARCH_TIMER_ERRATUM_740657 if ARM_ARCH_TIMER diff --git a/soc/xlnx/zynq7000/xc7zxxxs/Kconfig b/soc/xlnx/zynq7000/xc7zxxxs/Kconfig index ecac57425fe..5195a0c248b 100644 --- a/soc/xlnx/zynq7000/xc7zxxxs/Kconfig +++ b/soc/xlnx/zynq7000/xc7zxxxs/Kconfig @@ -9,4 +9,5 @@ config SOC_SERIES_XC7ZXXXS select ARM select CPU_CORTEX_A9 + select SYSCON select ARM_ARCH_TIMER_ERRATUM_740657 if ARM_ARCH_TIMER diff --git a/submanifests/optional.yaml b/submanifests/optional.yaml index 0f314ffd2c3..82007d5ae26 100644 --- a/submanifests/optional.yaml +++ b/submanifests/optional.yaml @@ -22,7 +22,7 @@ manifest: groups: - optional - name: nanopb - revision: 65cbefb4695bc7af1cb733ced99618afb3586b20 + revision: 7f88274070afa5edfaf608f4d8e32f3d3c1de139 path: modules/lib/nanopb remote: upstream groups: @@ -40,7 +40,7 @@ manifest: groups: - optional - name: tf-m-tests - revision: 08a3158f0623a4205608a52d880b17ae394e31d2 + revision: 85f533a4aa5b4fe31247676a923db7453eb4429c path: modules/tee/tf-m/tf-m-tests remote: upstream groups: diff --git a/subsys/bluetooth/Kconfig b/subsys/bluetooth/Kconfig index 2bd29855e55..43b8c654e85 100644 --- a/subsys/bluetooth/Kconfig +++ b/subsys/bluetooth/Kconfig @@ -61,15 +61,6 @@ config BT_HCI_RAW_H4_ENABLE This option enables use of H:4 transport for HCI RAW access at build time. -config BT_HCI_RAW_RESERVE - int "Buffer headroom needed for HCI transport" - depends on BT_HCI_RAW - default 1 if BT_HCI_RAW_H4 - default 0 - help - This option is used by the HCI raw transport implementation to - declare how much headroom it needs for any HCI transport headers. - config BT_HCI_RAW_CMD_EXT bool "RAW HCI Command Extension" help diff --git a/subsys/bluetooth/Kconfig.iso b/subsys/bluetooth/Kconfig.iso index 89955b70614..9fdde1da867 100644 --- a/subsys/bluetooth/Kconfig.iso +++ b/subsys/bluetooth/Kconfig.iso @@ -25,21 +25,19 @@ config BT_ISO_UNICAST Isochronous channels. config BT_ISO_PERIPHERAL - bool "Bluetooth Isochronous Channel Unicast Peripheral Support [EXPERIMENTAL]" + bool "Bluetooth Isochronous Channel Unicast Peripheral Support" depends on !BT_CTLR || BT_CTLR_PERIPHERAL_ISO_SUPPORT select BT_PERIPHERAL select BT_ISO_UNICAST - select EXPERIMENTAL help This option enables support for Bluetooth Unicast Isochronous channels for the peripheral role. config BT_ISO_CENTRAL - bool "Bluetooth Isochronous Channel Unicast Central Support [EXPERIMENTAL]" + bool "Bluetooth Isochronous Channel Unicast Central Support" depends on !BT_CTLR || BT_CTLR_CENTRAL_ISO_SUPPORT select BT_CENTRAL select BT_ISO_UNICAST - select EXPERIMENTAL help This option enables support for Bluetooth Broadcast Isochronous channels for the central role. @@ -50,24 +48,22 @@ config BT_ISO_BROADCAST select BT_EXT_ADV config BT_ISO_BROADCASTER - bool "Bluetooth Isochronous Broadcaster Support [EXPERIMENTAL]" + bool "Bluetooth Isochronous Broadcaster Support" depends on !BT_CTLR || BT_CTLR_ADV_ISO_SUPPORT select BT_ISO_BROADCAST select BT_ISO_TX select BT_BROADCASTER select BT_PER_ADV - select EXPERIMENTAL help This option enables support for the Bluetooth Isochronous Broadcaster. config BT_ISO_SYNC_RECEIVER - bool "Bluetooth Isochronous Synchronized Receiver Support [EXPERIMENTAL]" + bool "Bluetooth Isochronous Synchronized Receiver Support" depends on !BT_CTLR || BT_CTLR_SYNC_ISO_SUPPORT select BT_ISO_BROADCAST select BT_ISO_RX select BT_OBSERVER select BT_PER_ADV_SYNC - select EXPERIMENTAL help This option enables support for the Bluetooth Isochronous Synchronized Receiver. @@ -105,14 +101,15 @@ config BT_ISO_TX_FRAG_COUNT config BT_ISO_TX_MTU int "Maximum supported MTU for Isochronous TX buffers" - default 251 range 1 4095 + default 247 help Maximum MTU for Isochronous channels TX buffers. 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`). + HCI ISO Data packet fields (e.g. `struct bt_hci_iso_sdu_ts_hdr`). Set this value to 247 to fit 247 bytes of data within a single - HCI ISO Data packet with a size of 255, without utilizing timestamps. + HCI ISO Data packet with Data_Total_Length of 255, utilizing + timestamps. config BT_ISO_RX_BUF_COUNT int "Number of Isochronous RX buffers" @@ -128,7 +125,7 @@ config BT_ISO_RX_MTU help Maximum MTU for Isochronous channels RX buffers. 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`) + HCI ISO Data packet fields (e.g. `struct bt_hci_iso_sdu_ts_hdr`) config BT_ISO_TEST_PARAMS bool "ISO test parameters support" diff --git a/subsys/bluetooth/Kconfig.logging b/subsys/bluetooth/Kconfig.logging index 6c6c26f0b77..ab28df1bcec 100644 --- a/subsys/bluetooth/Kconfig.logging +++ b/subsys/bluetooth/Kconfig.logging @@ -7,704 +7,89 @@ config BT_LOG # convenience symbol, _no touchy_ bool default y if LOG && BT - select BT_LOG_LEGACY if BT_LOG menu "Bluetooth logging" -config BT_LOG_LEGACY - bool - -if BT_LOG_LEGACY - -menu "Bluetooth legacy logging options" - -# COMMON - -config BT_DEBUG_HCI_DRIVER - bool "[DEPRECATED] Bluetooth HCI driver debug" - select DEPRECATED - help - This option enables debug support for the active - Bluetooth HCI driver, including the Controller-side HCI layer - when included in the build. - -config BT_DEBUG_RPA - bool "[DEPRECATED] Bluetooth Resolvable Private Address (RPA) debug" - select DEPRECATED - depends on BT_RPA - help - This option enables debug support for the Bluetooth - Resolvable Private Address (RPA) generation and resolution. - -menu "[DEPRECATED] Audio" - -# AICS - -config BT_DEBUG_AICS - bool "[DEPRECATED] Audio Input Control Service debug" - select DEPRECATED - help - Use this option to enable Audio Input Control Service debug logs for - the Bluetooth Audio functionality. - -config BT_DEBUG_AICS_CLIENT - bool "[DEPRECATED] Audio Input Control Service client debug" - select DEPRECATED - help - Use this option to enable Audio Input Control Service client debug - logs for the Bluetooth Audio functionality. - -# BAP - -config BT_BAP_DEBUG_STREAM - bool "[DEPRECATED] Basic Audio Profile Stream debug" - select DEPRECATED - depends on BT_BAP_STREAM - help - Use this option to enable Basic Audio Profile Stream debug logs. - -config BT_DEBUG_ASCS - bool "[DEPRECATED] Audio Stream Control Service debug" - select DEPRECATED - depends on BT_ASCS - help - Use this option to enable Audio Stream Control Service debug logs for - the Bluetooth Audio functionality. - -config BT_DEBUG_BAP_UNICAST_SERVER - bool "[DEPRECATED] Bluetooth Audio Unicast Server debug" - select DEPRECATED - depends on BT_BAP_UNICAST_SERVER - help - Use this option to enable Bluetooth Audio Unicast Server debug logs - for the Bluetooth Audio functionality. - -config BT_DEBUG_BAP_UNICAST_CLIENT - bool "[DEPRECATED] Basic Audio Profile client debug" - select DEPRECATED - depends on BT_BAP_UNICAST_CLIENT - help - Use this option to enable Basic Audio Profile debug logs for the - Bluetooth Audio functionality. - -config BT_DEBUG_BAP_BROADCAST_SOURCE - bool "[DEPRECATED] Bluetooth Audio Broadcast Source debug" - select DEPRECATED - depends on BT_BAP_BROADCAST_SOURCE - help - Use this option to enable Bluetooth Audio Broadcast Source debug logs - for the Bluetooth Audio functionality. - -config BT_DEBUG_BAP_BROADCAST_SINK - bool "[DEPRECATED] Bluetooth Audio Broadcast Sink debug" - select DEPRECATED - depends on BT_BAP_BROADCAST_SINK - help - Use this option to enable Bluetooth Audio Broadcast Sink debug logs - for the Bluetooth Audio functionality. - -config BT_DEBUG_BAP_SCAN_DELEGATOR - bool "[DEPRECATED] Broadcast Audio Scan Service debug" - select DEPRECATED - depends on BT_BAP_SCAN_DELEGATOR - help - Use this option to enable Broadcast Audio Scan Service debug logs for - the Bluetooth Audio functionality. - -config BT_DEBUG_BAP_BROADCAST_ASSISTANT - bool "[DEPRECATED] Broadcast Audio Scan Service client debug" - select DEPRECATED - depends on BT_BAP_BROADCAST_ASSISTANT - help - Use this option to enable Broadcast Audio Scan Service client - debug logs for the Bluetooth Audio functionality. - -# CAP - -config BT_DEBUG_CAP_ACCEPTOR - bool "[DEPRECATED] Common Audio Profile debug" - select DEPRECATED - depends on BT_CAP_ACCEPTOR - help - Use this option to enable CAP debug logs for the - Bluetooth Audio functionality. - -config BT_DEBUG_CAP_INITIATOR - bool "[DEPRECATED] Common Audio Profile Initiator debug" - select DEPRECATED - depends on BT_CAP_INITIATOR - help - Use this option to enable CAP Initiator debug logs for the - Bluetooth Audio functionality. - -# CISP - -config BT_DEBUG_CSIP_SET_MEMBER - bool "[DEPRECATED] Coordinated Set Identification Service debug" - select DEPRECATED - help - Use this option to enable Coordinated Set Identification Service debug - logs for the Bluetooth Audio functionality. - -config BT_DEBUG_CSIP_SET_COORDINATOR - bool "[DEPRECATED] Coordinated Set Identification Profile Set Coordinator debug" - select DEPRECATED - help - Use this option to enable Coordinated Set Identification Profile - Set Coordinator debug logs for the Bluetooth Audio functionality. - -config BT_DEBUG_CSIP_SET_MEMBER_CRYPTO - bool "[DEPRECATED] Coordinated Set Identification Profile crypto functions debug" - select DEPRECATED - depends on BT_CSIP_SET_COORDINATOR || BT_CSIP_SET_MEMBER - help - Use this option to enable Coordinated Set Identification Profile - crypto functions debug logs for the Bluetooth Audio functionality. - -# HAS - -config BT_DEBUG_HAS - bool "[DEPRECATED] Hearing Access Service debug" - select DEPRECATED - help - This option enables enables Hearing Access Service debug logs. - -config BT_DEBUG_HAS_CLIENT - bool "[DEPRECATED] Hearing Access Service Client debug" - select DEPRECATED - depends on BT_HAS_CLIENT - help - This option enables enables Hearing Access Service Client debug logs. - -# MCS - -config BT_DEBUG_MCS - bool "[DEPRECATED] Media Control Service debug" - select DEPRECATED - help - Use this option to enable Media Control Service debug logs for the - Bluetooth Audio functionality. - -config BT_DEBUG_MCC - bool "[DEPRECATED] Media Control Client debug" - select DEPRECATED - help - Use this option to enable Media Control Client debug logs for the - Bluetooth Audio functionality. - -# MCTL - -config MCTL_DEBUG - bool "[DEPRECATED] Media control debug" - select DEPRECATED - help - Use this option to enable Media control debug logs - -# MICP - -config BT_DEBUG_MICP_MIC_DEV - bool "[DEPRECATED] Microphone Control Profile Microphone Device debug" - select DEPRECATED - help - Use this option to enable Microphone Control Profile - Microphone Device debug logs for the Bluetooth Audio functionality. - -config BT_DEBUG_MICP_MIC_CTLR - bool "[DEPRECATED] Microphone Control Profile Microphone Controller debug" - select DEPRECATED - help - Use this option to enable Microphone Control Profile Microphone - Controller debug logs for the Bluetooth Audio functionality. - -# MPL - -config BT_DEBUG_MPL - bool "[DEPRECATED] Media player debug" - select DEPRECATED - help - Enables debug logs for the media player - -# PACS - -config BT_DEBUG_PACS - bool "[DEPRECATED] Published Audio Capabilities Service debug" - select DEPRECATED - depends on BT_PACS - help - Use this option to enable Published Audio Capabilities Service debug - logs for the Bluetooth Audio functionality. - -# TBS - -config BT_DEBUG_TBS - bool "[DEPRECATED] Telephone Bearer Service debug" - select DEPRECATED - help - Use this option to enable Telephone Bearer Service debug logs for the - Bluetooth Audio functionality. - -config BT_DEBUG_TBS_CLIENT - bool "[DEPRECATED] Telephone Bearer Service client debug" - select DEPRECATED - help - Use this option to enable Telephone Bearer Service client debug logs - for the Bluetooth Audio functionality. - -# VCP - -config BT_DEBUG_VCP_VOL_REND - bool "[DEPRECATED] Volume Control Profile Volume Renderer debug" - select DEPRECATED - help - Use this option to enable Volume Control Profile debug logs for the - Bluetooth Audio functionality. - -config BT_DEBUG_VCP_VOL_CTLR - bool "[DEPRECATED] Volume Control Profile Volume Controller debug" - select DEPRECATED - help - Use this option to enable Volume Control Profile Volume Controller - debug logs for the Bluetooth Audio functionality. - -# VOCS - -config BT_DEBUG_VOCS - bool "[DEPRECATED] Volume Offset Control Service debug" - select DEPRECATED - help - Use this option to enable Volume Offset Control Service debug logs for - the Bluetooth Audio functionality. - -config BT_DEBUG_VOCS_CLIENT - bool "[DEPRECATED] Volume Offset Control Service client debug" - select DEPRECATED - help - Use this option to enable Volume Offset Control Service client debug - logs for the Bluetooth Audio functionality. - -endmenu # [DEPRECATED] Audio - -menu "[DEPRECATED] Others" - -# CRYPTO (subsys/bluetooth/crypto/Kconfig) - -config BT_DEBUG_CRYPTO - bool "[DEPRECATED] Bluetooth Cryptographic Toolbox debug" - select DEPRECATED - depends on BT_CRYPTO - help - This option enables debug log output for the Bluetooth - Cryptographic Toolbox. - - WARNING: This option prints out private security keys such as - the Long Term Key. - Use of this feature in production is strongly discouraged. - -# GATT - -config BT_DEBUG_ATT - bool "[DEPRECATED] Bluetooth Attribute Protocol (ATT) debug" - select DEPRECATED - help - This option enables debug support for the Bluetooth - Attribute Protocol (ATT). - -config BT_DEBUG_GATT - bool "[DEPRECATED] Bluetooth Generic Attribute Profile (GATT) debug" - select DEPRECATED - help - This option enables debug support for the Bluetooth - Generic Attribute Profile (GATT). - -# L2CAP - -config BT_DEBUG_L2CAP - bool "[DEPRECATED] Bluetooth L2CAP debug" - select DEPRECATED - help - This option enables debug support for the Bluetooth - L2ACP layer. - -# HOST (subsys/bluetooth/host/Kconfig) - -config BT_DEBUG_DF - bool "[DEPRECATED] Bluetooth Direction Finding debug" - select DEPRECATED - help - This option enables debug support for Bluetooth Direction Finding - -config BT_DEBUG_SETTINGS - bool "[DEPRECATED] Bluetooth storage debug" - select DEPRECATED - depends on BT_SETTINGS - help - This option enables debug support for Bluetooth storage. - -config BT_DEBUG_HCI_CORE - bool "[DEPRECATED] Bluetooth HCI core debug" - select DEPRECATED - help - This option enables debug support for Bluetooth HCI - core. - -config BT_DEBUG_CONN - bool "[DEPRECATED] Bluetooth connection debug" - select DEPRECATED - depends on BT_CONN || BT_ISO - help - This option enables debug support for Bluetooth - connection handling. - -config BT_DEBUG_ISO - bool "[DEPRECATED] ISO channel debug" - select DEPRECATED - help - Use this option to enable ISO channels debug logs for the - Bluetooth Audio functionality. - -config BT_DEBUG_KEYS - bool "[DEPRECATED] Bluetooth security keys debug" - select DEPRECATED - depends on BT_HCI_HOST - depends on BT_SMP - help - This option enables debug support for the handling of - Bluetooth security keys. - - WARNING: This option prints out private security keys such as - the Long Term Key. - Use of this feature in production is strongly discouraged. - -config BT_DEBUG_SMP - bool "[DEPRECATED] Bluetooth Security Manager Protocol (SMP) debug" - select DEPRECATED - depends on BT_HCI_HOST - depends on BT_SMP - help - This option enables debug support for the Bluetooth - Security Manager Protocol (SMP). - - WARNING: This option prints out private security keys such as - the Long Term Key. - Use of this feature in production is strongly discouraged. - -config BT_DEBUG_SERVICE - bool "[DEPRECATED] Bluetooth Services debug" - select DEPRECATED - depends on BT_CONN - help - This option enables debug support for the Bluetooth - Services. - -# CONTROLLER (subsys/bluetooth/controller/Kconfig) - -config BT_CTLR_DEBUG_ISOAL - bool "[DEPRECATED] Bluetooth ISO-AL debug" - select DEPRECATED - depends on BT_CTLR_ISO - help - This option enables debug support for the Bluetooth ISO-AL. - - -endmenu # [DEPRECATED] Others - -menu "[DEPRECATED] BR/EDR" - -config BT_DEBUG_RFCOMM - bool "[DEPRECATED] Bluetooth RFCOMM debug" - select DEPRECATED - depends on BT_RFCOMM - help - This option enables debug support for the Bluetooth - RFCOMM layer. - -config BT_DEBUG_HFP_HF - bool "[DEPRECATED] Bluetooth Hands Free Profile (HFP) debug" - select DEPRECATED - depends on BT_HFP_HF - help - This option enables debug support for the Bluetooth - Hands Free Profile (HFP). - -config BT_DEBUG_AVDTP - bool "[DEPRECATED] Bluetooth AVDTP debug" - select DEPRECATED - depends on BT_AVDTP - help - This option enables debug support for the Bluetooth AVDTP. - -config BT_DEBUG_A2DP - bool "[DEPRECATED] Bluetooth A2DP debug" - select DEPRECATED - depends on BT_A2DP - help - This option enables debug support for the Bluetooth - A2DP profile. - -config BT_DEBUG_SDP - bool "[DEPRECATED] Bluetooth Service Discovery Protocol (SDP) debug" - select DEPRECATED - depends on BT_CLASSIC - help - This option enables debug support for the Bluetooth - Service Discovery Protocol (SDP). - -endmenu # [DEPRECATED] BR/EDR - -# MESH (subsys/bluetooth/mesh/Kconfig) - -menu "[DEPRECATED] Mesh" - -config BT_MESH_DEBUG - bool "[DEPRECATED] Debug logs" - select DEPRECATED - help - Use this option to enable debug logs for the Bluetooth - Mesh functionality. - -config BT_MESH_DEBUG_NET - bool "[DEPRECATED] Network layer debug" - select DEPRECATED - help - Use this option to enable Network layer debug logs for the - 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. - -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. - -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. - -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. - -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. - -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. - -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. - -config BT_MESH_DEBUG_PROV_DEVICE - bool "[DEPRECATED] Provisioning device debug" - select DEPRECATED - help - Use this option to enable Provisioning device debug logs for the - Bluetooth Mesh functionality. - -config BT_MESH_DEBUG_ACCESS - bool "[DEPRECATED] Access layer debug" - select DEPRECATED - help - Use this option to enable Access layer and device composition - related debug logs for Bluetooth Mesh. - -config BT_MESH_DEBUG_MODEL - bool "[DEPRECATED] Foundation model debug" - select DEPRECATED - help - Use this option to enable debug logs for the Foundation - Models. - -config BT_MESH_DEBUG_ADV - bool "[DEPRECATED] Advertising debug" - select DEPRECATED - help - Use this option to enable advertising debug logs for - 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. - -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. - -config BT_MESH_DEBUG_PROXY - bool "[DEPRECATED] Proxy debug" - select DEPRECATED - depends on BT_MESH_GATT - help - Use this option to enable Proxy protocol debug logs. - -config BT_MESH_DEBUG_SETTINGS - bool "[DEPRECATED] Persistent settings debug" - select DEPRECATED - depends on BT_SETTINGS - help - Use this option to enable persistent settings debug logs. - -config BT_MESH_DEBUG_CDB - bool "[DEPRECATED] Configuration database debug" - select DEPRECATED - depends on BT_MESH_CDB - help - Use this option to enable configuration database debug logs. - -config BT_MESH_DEBUG_CFG - bool "[DEPRECATED] Configuration debug" - select DEPRECATED - help - Use this option to enable node configuration debug logs for the - Bluetooth Mesh functionality. - -endmenu # [DEPRECATED] Mesh - -menu "[DEPRECATED] Services" - -# IAS - -config BT_DEBUG_IAS_CLIENT - bool "[DEPRECATED] Immediate Alert Service Client debug" - select DEPRECATED - depends on BT_IAS_CLIENT - help - This option enables enables Immediate Alert Service Client debug logs. - -# OTS - -# TODO: Unify logging for OTS server and client - the client uses -# "BT" debugging, the server does not. - -config BT_DEBUG_OTS_CLIENT - bool "[DEPRECATED] Object Transfer Service Client debug" - select DEPRECATED - help - Use this option to enable Object Transfer Client debug logs - -endmenu # [DEPRECATED] Services - -endmenu # Bluetooth legacy logging options - -endif # BT_LOG_LEGACY - # (subsys/bluetooth/Kconfig) module = BT module-str = "Bluetooth" source "subsys/logging/Kconfig.template.log_config" +# Set BT as the parent module for all the symbols that will use +# `Kconfig.template.log_config_inherit`. This is more convenient to do it here +# instead of setting it for every modules. +# +# The downside of doing that is that people need to be careful when adding a new +# parent module because all the following symbol will use it. +parent-module = BT + # COMMON (subsys/bluetooth/common/Kconfig) module = BT_HCI_DRIVER -legacy-debug-sym = BT_DEBUG_HCI_DRIVER module-str = "Bluetooth HCI driver" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" module = BT_RPA -legacy-debug-sym = BT_DEBUG_RPA module-str = "Bluetooth Resolvable Private Address (RPA)" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" menu "Audio" # AICS module = BT_AICS -legacy-debug-sym = BT_DEBUG_AICS module-str = "Audio Input Control Service" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" module = BT_AICS_CLIENT -legacy-debug-sym = BT_DEBUG_AICS_CLIENT module-str = "Audio Input Control Service client" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" # BAP module = BT_BAP_STREAM -legacy-debug-sym = BT_BAP_DEBUG_STREAM module-str = "Bluetooth Audio Stream" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" -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" source "subsys/logging/Kconfig.template.log_config_inherit" module = BT_ASCS -legacy-debug-sym = BT_DEBUG_ASCS module-str = "Audio Stream Control Service" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" module = BT_BAP_UNICAST_SERVER -legacy-debug-sym = BT_DEBUG_BAP_UNICAST_SERVER module-str = "Bluetooth Audio Unicast Server" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" module = BT_BAP_UNICAST_CLIENT -legacy-debug-sym = BT_DEBUG_BAP_UNICAST_CLIENT module-str = "Basic Audio Profile" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" module = BT_BAP_BROADCAST_SOURCE -legacy-debug-sym = BT_DEBUG_BAP_BROADCAST_SOURCE module-str = "Bluetooth Audio Broadcast Source" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" module = BT_BAP_BROADCAST_SINK -legacy-debug-sym = BT_DEBUG_BAP_BROADCAST_SINK module-str = "Bluetooth Audio Broadcast Sink" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" module = BT_BAP_SCAN_DELEGATOR -legacy-debug-sym = BT_DEBUG_BAP_SCAN_DELEGATOR module-str = "Broadcast Audio Scan Service" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" module = BT_BAP_BROADCAST_ASSISTANT -legacy-debug-sym = BT_DEBUG_BAP_BROADCAST_ASSISTANT module-str = "Broadcast Audio Scan Service client debug" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" -parent-module = BT module = BT_BAP_ISO module-str = "Bluetooth Audio ISO" source "subsys/logging/Kconfig.template.log_config_inherit" @@ -712,26 +97,21 @@ source "subsys/logging/Kconfig.template.log_config_inherit" # CAP module = BT_CAP_ACCEPTOR -legacy-debug-sym = BT_DEBUG_CAP_ACCEPTOR module-str = "Common Audio Profile Acceptor" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" module = BT_CAP_INITIATOR -legacy-debug-sym = BT_DEBUG_CAP_INITIATOR module-str = "Common Audio Profile Initiator" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" -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" source "subsys/logging/Kconfig.template.log_config_inherit" @@ -739,112 +119,94 @@ source "subsys/logging/Kconfig.template.log_config_inherit" # CSIP module = BT_CSIP_SET_MEMBER -legacy-debug-sym = BT_DEBUG_CSIP_SET_MEMBER module-str = "Coordinated Set Identification Service" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" module = BT_CSIP_SET_COORDINATOR -legacy-debug-sym = BT_DEBUG_CSIP_SET_COORDINATOR module-str = "Coordinated Set Identification Profile Set Coordinator" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" module = BT_CSIP_SET_MEMBER_CRYPTO -legacy-debug-sym = BT_DEBUG_CSIP_SET_MEMBER_CRYPTO module-str = "Coordinated Set Identification Profile crypto functions" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" # HAS module = BT_HAS -legacy-debug-sym = BT_DEBUG_HAS module-str = "Hearing Access Service" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" module = BT_HAS_CLIENT -legacy-debug-sym = BT_DEBUG_HAS_CLIENT module-str = "Hearing Access Service Client" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" # MCS module = BT_MCS -legacy-debug-sym = BT_DEBUG_MCS module-str = "Media Control Service" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" module = BT_MCC -legacy-debug-sym = BT_DEBUG_MCC module-str = "Media Control Client" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" # MCTL module = MCTL -legacy-debug-sym = MCTL_DEBUG module-str = "Media control" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" # MICP module = BT_MICP_MIC_DEV -legacy-debug-sym = BT_DEBUG_MICP_MIC_DEV module-str = "Microphone Control Profile Microphone Device" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" module = BT_MICP_MIC_CTLR -legacy-debug-sym = BT_DEBUG_MICP_MIC_CTLR module-str = "Microphone Control Profile Microphone Controller" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" # MPL module = BT_MPL -legacy-debug-sym = BT_DEBUG_MPL module-str = "Media player" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" # PACS module = BT_PACS -legacy-debug-sym = BT_DEBUG_PACS module-str = "Published Audio Capabilities Service" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" # TBS module = BT_TBS -legacy-debug-sym = BT_DEBUG_TBS module-str = "Telephone Bearer Service" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" module = BT_TBS_CLIENT -legacy-debug-sym = BT_DEBUG_TBS_CLIENT module-str = "Telephone Bearer Service client" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" # VCP module = BT_VCP_VOL_REND -legacy-debug-sym = BT_DEBUG_VCP_VOL_REND module-str = "Volume Control Profile Voluem Renderer" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" module = BT_VCP_VOL_CTLR -legacy-debug-sym = BT_DEBUG_VCP_VOL_CTLR module-str = "Volume Control Profile Volume Controller" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" # VOCS module = BT_VOCS -legacy-debug-sym = BT_DEBUG_VOCS module-str = "Volume Offset Control Service" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" module = BT_VOCS_CLIENT -legacy-debug-sym = BT_DEBUG_VOCS_CLIENT module-str = "Volume Offset Control Service client" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" # PBP @@ -859,32 +221,27 @@ menu "Others" # CRYPTO (subsys/bluetooth/crypto/Kconfig) module = BT_CRYPTO -legacy-debug-sym = BT_DEBUG_CRYPTO module-str = "Bluetooth Cryptographic Toolbox" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" # GATT module = BT_ATT -legacy-debug-sym = BT_DEBUG_ATT module-str = "Bluetooth Attribute Protocol (ATT)" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" module = BT_GATT -legacy-debug-sym = BT_DEBUG_GATT module-str = "Bluetooth Generic Attribute Profile (GATT)" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" # L2CAP module = BT_L2CAP -legacy-debug-sym = BT_DEBUG_L2CAP module-str = "Bluetooth L2CAP" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" # LIB (subsys/bluetooth/lib/Kconfig) -parent-module = BT module = BT_EAD module-str = "Bluetooth Encrypted Advertising Data" source "subsys/logging/Kconfig.template.log_config_inherit" @@ -892,80 +249,70 @@ source "subsys/logging/Kconfig.template.log_config_inherit" # HOST (subsys/bluetooth/host/Kconfig) module = BT_DF -legacy-debug-sym = BT_DEBUG_DF module-str = "Bluetooth Direction Finding" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" module = BT_SETTINGS -legacy-debug-sym = BT_DEBUG_SETTINGS module-str = "Bluetooth storage" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" module = BT_HCI_CORE -legacy-debug-sym = BT_DEBUG_HCI_CORE module-str = "Bluetooth HCI core" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" module = BT_CONN -legacy-debug-sym = BT_DEBUG_CONN module-str = "Bluetooth connection" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" module = BT_ISO -legacy-debug-sym = BT_DEBUG_ISO module-str = "ISO channel" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" module = BT_KEYS -legacy-debug-sym = BT_DEBUG_KEYS module-str = "Bluetooth security keys" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" module = BT_SMP -legacy-debug-sym = BT_DEBUG_SMP module-str = "Bluetooth Security Manager Protocol" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" module = BT_SERVICE -legacy-debug-sym = BT_DEBUG_SERVICE module-str = "Bluetooth Services" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" # CONTROLLER (subsys/bluetooth/controller/Kconfig) module = BT_CTLR_ISOAL -legacy-debug-sym = BT_CTLR_DEBUG_ISOAL module-str = "Bluetooth Controller ISO-AL" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" endmenu # Others menu "BR/EDR" module = BT_RFCOMM -legacy-debug-sym = BT_DEBUG_RFCOMM module-str = "Bluetooth RFCOMM" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" module = BT_HFP_HF -legacy-debug-sym = BT_DEBUG_HFP_HF module-str = "Bluetooth Hands Free Profile (HFP)" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" + +module = BT_HFP_AG +module-str = "Bluetooth Hands Free Audio Gateway Profile (HFP AG)" +source "subsys/logging/Kconfig.template.log_config_inherit" module = BT_AVDTP -legacy-debug-sym = BT_DEBUG_AVDTP module-str = "Bluetooth AVDTP debug" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" module = BT_A2DP -legacy-debug-sym = BT_DEBUG_A2DP module-str = "Bluetooth A2DP" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" module = BT_SDP -legacy-debug-sym = BT_DEBUG_SDP module-str = "Bluetooth Service Discovery Protocol (SDP)" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" endmenu # BR/EDR @@ -974,103 +321,84 @@ endmenu # BR/EDR menu "Mesh" module = BT_MESH -legacy-debug-sym = BT_MESH_DEBUG module-str = "Debug logs" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" module = BT_MESH_NET -legacy-debug-sym = BT_MESH_DEBUG_NET module-str = "Network layer" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" module = BT_MESH_RPL -legacy-debug-sym = BT_MESH_DEBUG_RPL module-str = "Replay protection list" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" module = BT_MESH_TRANS -legacy-debug-sym = BT_MESH_DEBUG_TRANS module-str = "Transport layer" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" module = BT_MESH_BEACON -legacy-debug-sym = BT_MESH_DEBUG_BEACON module-str = "Beacon" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" module = BT_MESH_CRYPTO -legacy-debug-sym = BT_MESH_DEBUG_CRYPTO module-str = "Crypto" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" module = BT_MESH_KEYS -legacy-debug-sym = BT_MESH_DEBUG_KEYS module-str = "Key management" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" module = BT_MESH_PROV -legacy-debug-sym = BT_MESH_DEBUG_PROV module-str = "Provisioning" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" module = BT_MESH_PROVISIONER -legacy-debug-sym = BT_MESH_DEBUG_PROVISIONER module-str = "Provisioner" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" 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" +source "subsys/logging/Kconfig.template.log_config_inherit" module = BT_MESH_ACCESS -legacy-debug-sym = BT_MESH_DEBUG_ACCESS module-str = "Access layer" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" module = BT_MESH_MODEL -legacy-debug-sym = BT_MESH_DEBUG_MODEL module-str = "Foundation model" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" module = BT_MESH_DFU module-str = "DFU model" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" module = BT_MESH_ADV -legacy-debug-sym = BT_MESH_DEBUG_ADV module-str = "Advertising" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" module = BT_MESH_LOW_POWER -legacy-debug-sym = BT_MESH_DEBUG_LOW_POWER module-str = "Low Power" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" module = BT_MESH_FRIEND -legacy-debug-sym = BT_MESH_DEBUG_FRIEND module-str = "Friend" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" module = BT_MESH_PROXY -legacy-debug-sym = BT_MESH_DEBUG_PROXY module-str = "Proxy" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" module = BT_MESH_SETTINGS -legacy-debug-sym = BT_MESH_DEBUG_SETTINGS module-str = "Persistent settings" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" module = BT_MESH_CDB -legacy-debug-sym = BT_MESH_DEBUG_CDB module-str = "Configuration database" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" module = BT_MESH_CFG -legacy-debug-sym = BT_MESH_DEBUG_CFG module-str = "Configuration" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" endmenu # Mesh @@ -1097,9 +425,8 @@ source "subsys/logging/Kconfig.template.log_config" # IAS module = BT_IAS_CLIENT -legacy-debug-sym = BT_DEBUG_IAS_CLIENT module-str = "Immediate Alert Service Client" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" module = BT_IAS module-str = IAS @@ -1108,9 +435,8 @@ source "${ZEPHYR_BASE}/subsys/logging/Kconfig.template.log_config" # OTS (subsys/bluetooth/services/ots/Kconfig) module = BT_OTS_CLIENT -legacy-debug-sym = BT_DEBUG_OTS_CLIENT module-str = "Object Transfer Service Client" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" module = BT_OTS module-str = BT_OTS diff --git a/subsys/bluetooth/audio/Kconfig b/subsys/bluetooth/audio/Kconfig index b60475c02e2..f8e7769df34 100644 --- a/subsys/bluetooth/audio/Kconfig +++ b/subsys/bluetooth/audio/Kconfig @@ -8,8 +8,7 @@ # menuconfig BT_AUDIO - bool "Bluetooth Audio support [EXPERIMENTAL]" - select EXPERIMENTAL + bool "Bluetooth Audio support" help This option enables Bluetooth Audio support. The specific features that are available may depend on other features diff --git a/subsys/bluetooth/audio/Kconfig.aics b/subsys/bluetooth/audio/Kconfig.aics index 570fcbf58d4..b39c4027e81 100644 --- a/subsys/bluetooth/audio/Kconfig.aics +++ b/subsys/bluetooth/audio/Kconfig.aics @@ -9,7 +9,7 @@ ##################### Audio Input Control Service ##################### config BT_AICS_MAX_INSTANCE_COUNT - int "Audio Input Control Service max instance count [EXPERIMENTAL]" + int "Audio Input Control Service max instance count" default 0 range 0 15 help @@ -19,7 +19,6 @@ config BT_AICS_MAX_INSTANCE_COUNT config BT_AICS bool # hidden default y if BT_AICS_MAX_INSTANCE_COUNT > 0 - select EXPERIMENTAL select BT_GATT_DYNAMIC_DB help This hidden option enables support for Audio Input Control Service. @@ -38,7 +37,7 @@ endif # BT_AICS ##################### Audio Input Control Service Client ##################### config BT_AICS_CLIENT_MAX_INSTANCE_COUNT - int "Audio Input Control Service client max instance count [EXPERIMENTAL]" + int "Audio Input Control Service client max instance count" default 0 range 0 15 help @@ -48,6 +47,5 @@ config BT_AICS_CLIENT_MAX_INSTANCE_COUNT config BT_AICS_CLIENT bool # hidden default y if BT_AICS_CLIENT_MAX_INSTANCE_COUNT > 0 - select EXPERIMENTAL help This hidden option enables support for Audio Input Control Service. diff --git a/subsys/bluetooth/audio/Kconfig.bap b/subsys/bluetooth/audio/Kconfig.bap index 6e5dc3094b7..93ab96f6279 100644 --- a/subsys/bluetooth/audio/Kconfig.bap +++ b/subsys/bluetooth/audio/Kconfig.bap @@ -13,21 +13,20 @@ config BT_BAP_UNICAST select BT_ISO_UNICAST config BT_BAP_UNICAST_SERVER - bool "Bluetooth Unicast Audio Server Support [EXPERIMENTAL]" - select EXPERIMENTAL - select BT_PERIPHERAL + bool "Bluetooth Unicast Audio Server Support" select BT_BAP_UNICAST - select BT_ISO_PERIPHERAL select BT_GATT_DYNAMIC_DB select BT_GATT_CACHING - select BT_ASCS + depends on BT_PERIPHERAL + depends on BT_ISO_PERIPHERAL + depends on BT_ASCS + depends on BT_PACS help This option enables support for Bluetooth Unicast Audio Server using Isochronous channels. config BT_BAP_UNICAST_CLIENT - bool "Bluetooth Unicast Audio Client Support [EXPERIMENTAL]" - select EXPERIMENTAL + bool "Bluetooth Unicast Audio Client Support" select BT_BAP_UNICAST select BT_ISO_CENTRAL select BT_CENTRAL @@ -126,8 +125,7 @@ config BT_BAP_UNICAST_CLIENT_ASE_SRC endif # BT_BAP_UNICAST_CLIENT config BT_BAP_BROADCAST_SOURCE - bool "Bluetooth Broadcast Source Audio Support [EXPERIMENTAL]" - select EXPERIMENTAL + bool "Bluetooth Broadcast Source Audio Support" select BT_ISO_BROADCASTER select BT_AUDIO_TX help @@ -166,8 +164,7 @@ config BT_BAP_BROADCAST_SRC_STREAM_COUNT endif # BT_BAP_BROADCAST_SOURCE config BT_BAP_BROADCAST_SINK - bool "Bluetooth Broadcast Sink Audio Support [EXPERIMENTAL]" - select EXPERIMENTAL + bool "Bluetooth Broadcast Sink Audio Support" select BT_ISO_SYNC_RECEIVER select BT_AUDIO_RX select BT_PAC_SNK @@ -210,8 +207,7 @@ config BT_BAP_BROADCAST_SNK_STREAM_COUNT endif # BT_BAP_BROADCAST_SINK config BT_BAP_SCAN_DELEGATOR - bool "Basic Audio Profile Scan Delegator role support [EXPERIMENTAL]" - select EXPERIMENTAL + bool "Basic Audio Profile Scan Delegator role support" select BT_OBSERVER select BT_EXT_ADV select BT_PER_ADV_SYNC @@ -243,8 +239,7 @@ config BT_BAP_SCAN_DELEGATOR_BUF_TIMEOUT endif # BT_BAP_SCAN_DELEGATOR config BT_BAP_BROADCAST_ASSISTANT - bool "Basic Audio Profile Broadcast Assistant role support [EXPERIMENTAL]" - select EXPERIMENTAL + bool "Basic Audio Profile Broadcast Assistant role support" select BT_OBSERVER select BT_EXT_ADV select BT_PER_ADV_SYNC diff --git a/subsys/bluetooth/audio/Kconfig.cap b/subsys/bluetooth/audio/Kconfig.cap index 2a130f53d9a..5ba8a9bf2f0 100644 --- a/subsys/bluetooth/audio/Kconfig.cap +++ b/subsys/bluetooth/audio/Kconfig.cap @@ -9,10 +9,9 @@ config BT_CAP def_bool BT_CAP_ACCEPTOR || BT_CAP_INITIATOR config BT_CAP_ACCEPTOR - bool "Common Audio Profile Acceptor Role Support [EXPERIMENTAL]" + bool "Common Audio Profile Acceptor Role Support" depends on BT_BAP_UNICAST_SERVER || (BT_BAP_BROADCAST_SINK && BT_BAP_SCAN_DELEGATOR) depends on BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE >= 4 - select EXPERIMENTAL help Enabling this will enable the CAP Acceptor role. This instantiates the common audio service (CAS). @@ -32,22 +31,20 @@ 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]" + bool "Common Audio Profile Initiator Role Support" depends on (BT_BAP_UNICAST_CLIENT && BT_CSIP_SET_COORDINATOR) || BT_BAP_BROADCAST_SOURCE depends on BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE >= 4 - select EXPERIMENTAL help Enabling this will enable the CAP Initiator role. config BT_CAP_COMMANDER - bool "Common Audio Profile Initiator Role Support [EXPERIMENTAL]" + bool "Common Audio Profile Initiator Role Support" 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.csip b/subsys/bluetooth/audio/Kconfig.csip index 878962feb41..ca72550843a 100644 --- a/subsys/bluetooth/audio/Kconfig.csip +++ b/subsys/bluetooth/audio/Kconfig.csip @@ -9,9 +9,8 @@ #################### Coordinated Set Identification Service #################### config BT_CSIP_SET_MEMBER - bool "Coordinated Set Identification Profile Set Member support [EXPERIMENTAL]" + bool "Coordinated Set Identification Profile Set Member support" imply BT_EXT_ADV if BT_PRIVACY - select EXPERIMENTAL help This option enables support for Coordinated Set Identification Profile Set Member role and the Coordinated Set Identification @@ -57,10 +56,9 @@ endif # BT_CSIP_SET_MEMBER #################### Coordinated Set Identification Client #################### config BT_CSIP_SET_COORDINATOR - bool "Coordinated Set Identification Profile Set Coordinator Support [EXPERIMENTAL]" + bool "Coordinated Set Identification Profile Set Coordinator Support" select BT_GATT_CLIENT select BT_GATT_AUTO_DISCOVER_CCC - select EXPERIMENTAL help This option enables support for Coordinated Set Identification Profile Set Coordinator. diff --git a/subsys/bluetooth/audio/Kconfig.gmap b/subsys/bluetooth/audio/Kconfig.gmap index a9bd3024aa3..bcf72962427 100644 --- a/subsys/bluetooth/audio/Kconfig.gmap +++ b/subsys/bluetooth/audio/Kconfig.gmap @@ -18,9 +18,8 @@ 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]" + bool "Gaming Audio Profile" depends on BT_CAP_ACCEPTOR || BT_CAP_INITIATOR - select EXPERIMENTAL help Enabling this will enable GMAP. diff --git a/subsys/bluetooth/audio/Kconfig.has b/subsys/bluetooth/audio/Kconfig.has index a66831d1eb7..f0d89d7b585 100644 --- a/subsys/bluetooth/audio/Kconfig.has +++ b/subsys/bluetooth/audio/Kconfig.has @@ -5,8 +5,7 @@ # SPDX-License-Identifier: Apache-2.0 menuconfig BT_HAS - bool "Hearing Access Service support [EXPERIMENTAL]" - select EXPERIMENTAL + bool "Hearing Access Service support" select UTF8 select BT_GATT_DYNAMIC_DB depends on BT_BAP_UNICAST_SERVER @@ -56,8 +55,7 @@ endif # BT_HAS_PRESET_SUPPORT endif # BT_HAS config BT_HAS_CLIENT - bool "Hearing Access Service Client support [EXPERIMENTAL]" - select EXPERIMENTAL + bool "Hearing Access Service Client support" select BT_GATT_CLIENT select BT_GATT_AUTO_DISCOVER_CCC select BT_GATT_AUTO_UPDATE_MTU diff --git a/subsys/bluetooth/audio/Kconfig.mcs b/subsys/bluetooth/audio/Kconfig.mcs index d0b139e90b1..ccd3d55cdac 100644 --- a/subsys/bluetooth/audio/Kconfig.mcs +++ b/subsys/bluetooth/audio/Kconfig.mcs @@ -13,7 +13,6 @@ config BT_MCS depends on MCTL_LOCAL_PLAYER_REMOTE_CONTROL depends on UTF8 select BT_CCID - select EXPERIMENTAL select BT_GATT_DYNAMIC_DB help This option enables support for the Media Control Service. @@ -24,7 +23,6 @@ config BT_MCC bool "Media Control Client Support" select BT_GATT_CLIENT select BT_GATT_AUTO_DISCOVER_CCC - select EXPERIMENTAL help This option enables support for the Media Control Client. diff --git a/subsys/bluetooth/audio/Kconfig.mctl b/subsys/bluetooth/audio/Kconfig.mctl index cb14218068c..ed632848d23 100644 --- a/subsys/bluetooth/audio/Kconfig.mctl +++ b/subsys/bluetooth/audio/Kconfig.mctl @@ -11,7 +11,6 @@ config MCTL bool "Support for media player control" - select EXPERIMENTAL help Enables support for control of local and remote media players To enable support for control of a local media player, support for diff --git a/subsys/bluetooth/audio/Kconfig.micp b/subsys/bluetooth/audio/Kconfig.micp index 15b8191d2f8..ef4f8928650 100644 --- a/subsys/bluetooth/audio/Kconfig.micp +++ b/subsys/bluetooth/audio/Kconfig.micp @@ -9,8 +9,7 @@ ########### Microphone Control Profile Microphone Device ########### config BT_MICP_MIC_DEV - bool "Microphone Control Profile Microphone Device Support [EXPERIMENTAL]" - select EXPERIMENTAL + bool "Microphone Control Profile Microphone Device Support" select BT_GATT_DYNAMIC_DB help This option enables support for Microphone Control Profile @@ -39,10 +38,9 @@ endif # BT_MICP_MIC_DEV ########### Microphone Control Profile Microphone Controller ########### config BT_MICP_MIC_CTLR - bool "Microphone Control Profile Microphone Controller Support [EXPERIMENTAL]" + bool "Microphone Control Profile Microphone Controller Support" select BT_GATT_CLIENT select BT_GATT_AUTO_DISCOVER_CCC - select EXPERIMENTAL help This option enables support for the Microphone Control Profile Microphone Controller role diff --git a/subsys/bluetooth/audio/Kconfig.mpl b/subsys/bluetooth/audio/Kconfig.mpl index 2e7fcb38420..69efefe5b91 100644 --- a/subsys/bluetooth/audio/Kconfig.mpl +++ b/subsys/bluetooth/audio/Kconfig.mpl @@ -9,7 +9,6 @@ config BT_MPL bool "Support for media player" select BT_CCID - select EXPERIMENTAL help Enables support for media player Note that the provided media player is a sample that only provides a diff --git a/subsys/bluetooth/audio/Kconfig.pbp b/subsys/bluetooth/audio/Kconfig.pbp index cb24845b202..3a0e7ed2c73 100644 --- a/subsys/bluetooth/audio/Kconfig.pbp +++ b/subsys/bluetooth/audio/Kconfig.pbp @@ -6,7 +6,6 @@ # config BT_PBP - bool "Public Broadcast Profile [EXPERIMENTAL]" - select EXPERIMENTAL + bool "Public Broadcast Profile" help Enabling this will enable PBP. diff --git a/subsys/bluetooth/audio/Kconfig.tmap b/subsys/bluetooth/audio/Kconfig.tmap index 9a9d6c61d26..aa5dd7e727c 100644 --- a/subsys/bluetooth/audio/Kconfig.tmap +++ b/subsys/bluetooth/audio/Kconfig.tmap @@ -6,21 +6,12 @@ # config BT_TMAP - bool "Telephony and Media Audio Profile [EXPERIMENTAL]" + bool "Telephony and Media Audio Profile" depends on BT_CAP_ACCEPTOR || BT_CAP_INITIATOR - select EXPERIMENTAL help Enabling this will enable TMAP. -config BT_DEBUG_TMAP - bool "Telephony and Media Audio Profile debug" - select DEPRECATED - depends on BT_TMAP - help - Use this option to enable Telephony and Media Audio Profile debug - logs for the Bluetooth Audio functionality. - +parent-module = BT module = BT_TMAP -legacy-debug-sym = BT_DEBUG_TMAP module-str = "Telephony and Media Audio Profile" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" diff --git a/subsys/bluetooth/audio/Kconfig.vcp b/subsys/bluetooth/audio/Kconfig.vcp index ed227defc1b..084f1397d0c 100644 --- a/subsys/bluetooth/audio/Kconfig.vcp +++ b/subsys/bluetooth/audio/Kconfig.vcp @@ -9,8 +9,7 @@ ################### Volume Control Profile Volume Renderer ################### config BT_VCP_VOL_REND - bool "Volume Control Profile Volume Renderer Support [EXPERIMENTAL]" - select EXPERIMENTAL + bool "Volume Control Profile Volume Renderer Support" select BT_GATT_DYNAMIC_DB help This option enables support for Volume Control Profile Volume Renderer @@ -58,10 +57,9 @@ endif # BT_VCP_VOL_REND ################### Volume Control Profile Volume Controller ################### config BT_VCP_VOL_CTLR - bool "Volume Control Profile Volume Controller Support [EXPERIMENTAL]" + bool "Volume Control Profile Volume Controller Support" select BT_GATT_CLIENT select BT_GATT_AUTO_DISCOVER_CCC - select EXPERIMENTAL help This option enables support for Volume Control Profile Volume Controller. diff --git a/subsys/bluetooth/audio/Kconfig.vocs b/subsys/bluetooth/audio/Kconfig.vocs index 2b1e4362b13..d582b2aaab4 100644 --- a/subsys/bluetooth/audio/Kconfig.vocs +++ b/subsys/bluetooth/audio/Kconfig.vocs @@ -8,7 +8,7 @@ ##################### Volume Offset Control Service ##################### config BT_VOCS_MAX_INSTANCE_COUNT - int "Volume Offset Control Service max instance count [EXPERIMENTAL]" + int "Volume Offset Control Service max instance count" default 0 range 0 15 help @@ -18,7 +18,6 @@ config BT_VOCS_MAX_INSTANCE_COUNT config BT_VOCS bool # hidden default y if BT_VOCS_MAX_INSTANCE_COUNT > 0 - select EXPERIMENTAL help This hidden option enables support for Volume Control Service. @@ -36,7 +35,7 @@ endif # BT_VOCS ##################### Volume Offset Control Service Client ##################### config BT_VOCS_CLIENT_MAX_INSTANCE_COUNT - int "Volume Offset Control Service client max instance count [EXPERIMENTAL]" + int "Volume Offset Control Service client max instance count" default 0 range 0 15 help @@ -46,6 +45,5 @@ config BT_VOCS_CLIENT_MAX_INSTANCE_COUNT config BT_VOCS_CLIENT bool # hidden default y if BT_VOCS_CLIENT_MAX_INSTANCE_COUNT > 0 - select EXPERIMENTAL help This hidden option enables support for Volume Offset Control Service. diff --git a/subsys/bluetooth/audio/bap_broadcast_assistant.c b/subsys/bluetooth/audio/bap_broadcast_assistant.c index aef75d072e4..6013afbf817 100644 --- a/subsys/bluetooth/audio/bap_broadcast_assistant.c +++ b/subsys/bluetooth/audio/bap_broadcast_assistant.c @@ -118,15 +118,14 @@ static void bap_broadcast_assistant_recv_state_changed( } } -static void bap_broadcast_assistant_recv_state_removed(struct bt_conn *conn, int err, - uint8_t src_id) +static void bap_broadcast_assistant_recv_state_removed(struct bt_conn *conn, uint8_t src_id) { struct bt_bap_broadcast_assistant_cb *listener, *next; SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&broadcast_assistant_cbs, listener, next, _node) { if (listener->recv_state_removed) { - listener->recv_state_removed(conn, err, src_id); + listener->recv_state_removed(conn, src_id); } } } @@ -442,8 +441,8 @@ static uint8_t notify_handler(struct bt_conn *conn, } } else { broadcast_assistant.recv_states[index].past_avail = false; - bap_broadcast_assistant_recv_state_removed(conn, 0, - broadcast_assistant.recv_states[index].src_id); + bap_broadcast_assistant_recv_state_removed( + conn, broadcast_assistant.recv_states[index].src_id); } return BT_GATT_ITER_CONTINUE; diff --git a/subsys/bluetooth/audio/bap_internal.h b/subsys/bluetooth/audio/bap_internal.h index 5eb53f5de58..27f62977a22 100644 --- a/subsys/bluetooth/audio/bap_internal.h +++ b/subsys/bluetooth/audio/bap_internal.h @@ -123,3 +123,16 @@ static inline const char *bt_bap_big_enc_state_str(uint8_t state) return "unknown state"; } } + +static inline bool valid_bis_syncs(uint32_t bis_sync) +{ + if (bis_sync == BT_BAP_BIS_SYNC_NO_PREF) { + return true; + } + + if (bis_sync > BIT_MASK(31)) { /* Max BIS index */ + return false; + } + + return true; +} diff --git a/subsys/bluetooth/audio/bap_scan_delegator.c b/subsys/bluetooth/audio/bap_scan_delegator.c index 09cd2327051..6a55d7da2c3 100644 --- a/subsys/bluetooth/audio/bap_scan_delegator.c +++ b/subsys/bluetooth/audio/bap_scan_delegator.c @@ -88,19 +88,6 @@ static bool bits_subset_of(uint32_t a, uint32_t b) return (((a) & (~(b))) == 0); } -static bool valid_bis_syncs(uint32_t bis_sync) -{ - if (bis_sync == BT_BAP_BIS_SYNC_NO_PREF) { - return true; - } - - if (bis_sync > BIT_MASK(31)) { /* Max BIS index */ - return false; - } - - return true; -} - static bool bis_syncs_unique_or_no_pref(uint32_t requested_bis_syncs, uint32_t aggregated_bis_syncs) { diff --git a/subsys/bluetooth/audio/cap_commander.c b/subsys/bluetooth/audio/cap_commander.c index b65eb453ce9..80fd66c103a 100644 --- a/subsys/bluetooth/audio/cap_commander.c +++ b/subsys/bluetooth/audio/cap_commander.c @@ -11,6 +11,7 @@ #include #include #include +#include "bap_internal.h" #include "cap_internal.h" #include "ccid_internal.h" #include "csip_internal.h" @@ -22,17 +23,21 @@ LOG_MODULE_REGISTER(bt_cap_commander, CONFIG_BT_CAP_COMMANDER_LOG_LEVEL); #include "common/bt_str.h" +static void cap_commander_proc_complete(void); + 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; } @@ -60,10 +65,11 @@ int bt_cap_commander_unregister_cb(const struct bt_cap_commander_cb *cb) static void cap_commander_discover_complete(struct bt_conn *conn, int err, + const struct bt_csip_set_coordinator_set_member *member, 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); + cap_cb->discovery_complete(conn, err, member, csis_inst); } } @@ -77,18 +83,311 @@ int bt_cap_commander_discover(struct bt_conn *conn) return bt_cap_common_discover(conn, cap_commander_discover_complete); } +#if defined(CONFIG_BT_BAP_BROADCAST_ASSISTANT) +static struct bt_bap_broadcast_assistant_cb broadcast_assistant_cb; +static bool ba_cb_registered; + +static void +copy_broadcast_reception_start_param(struct bt_bap_broadcast_assistant_add_src_param *add_src_param, + struct cap_broadcast_reception_start *start_param) +{ + bt_addr_le_copy(&add_src_param->addr, &start_param->addr); + add_src_param->adv_sid = start_param->adv_sid; + add_src_param->broadcast_id = start_param->broadcast_id; + add_src_param->pa_interval = start_param->pa_interval; + add_src_param->num_subgroups = start_param->num_subgroups; + add_src_param->subgroups = start_param->subgroups; +} + +static void cap_commander_ba_add_src_cb(struct bt_conn *conn, int err) +{ + struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc(); + struct bt_bap_broadcast_assistant_add_src_param add_src_param = {0}; + + 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 add source: %d", err); + LOG_DBG("Aborting the proc %d %d", active_proc->proc_done_cnt, + active_proc->proc_initiated_cnt); + + bt_cap_common_abort_proc(conn, err); + } else { + active_proc->proc_done_cnt++; + + LOG_DBG("Conn %p broadcast source added (%zu/%zu streams done)", (void *)conn, + active_proc->proc_done_cnt, active_proc->proc_cnt); + } + + if (bt_cap_common_proc_is_aborted()) { + if (bt_cap_common_proc_all_handled()) { + cap_commander_proc_complete(); + } + + return; + } + + if (!bt_cap_common_proc_is_done()) { + struct bt_cap_commander_proc_param *proc_param; + + proc_param = &active_proc->proc_param.commander[active_proc->proc_done_cnt]; + conn = proc_param->conn; + copy_broadcast_reception_start_param(&add_src_param, + &proc_param->broadcast_reception_start); + + active_proc->proc_initiated_cnt++; + err = bt_bap_broadcast_assistant_add_src(conn, &add_src_param); + if (err != 0) { + LOG_DBG("Failed to perform broadcast reception start for conn %p: %d", + (void *)conn, err); + bt_cap_common_abort_proc(conn, err); + cap_commander_proc_complete(); + } + } else { + cap_commander_proc_complete(); + } +} + +static int cap_commander_register_ba_cb(void) +{ + int err; + + err = bt_bap_broadcast_assistant_register_cb(&broadcast_assistant_cb); + if (err != 0) { + LOG_DBG("Failed to register broadcast assistant callbacks: %d", err); + + return -ENOEXEC; + } + + ba_cb_registered = true; + + return 0; +} + +static bool valid_broadcast_reception_start_param( + const struct bt_cap_commander_broadcast_reception_start_param *param) +{ + uint32_t total_bis_sync = 0U; + + 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->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; + } + + CHECKIF(param->param == NULL) { + LOG_DBG("param->param is NULL"); + return false; + } + + for (size_t i = 0; i < param->count; i++) { + const struct bt_cap_commander_broadcast_reception_start_member_param *start_param = + ¶m->param[i]; + const union bt_cap_set_member *member = ¶m->param[i].member; + const struct bt_cap_common_client *client = + bt_cap_common_get_client(param->type, member); + + if (member == NULL) { + LOG_DBG("param->param[%zu].member is NULL", i); + return false; + } + + if (client == NULL) { + LOG_DBG("Invalid param->param[%zu].member", i); + return false; + } + + CHECKIF(start_param->addr.type > BT_ADDR_LE_RANDOM) { + LOG_DBG("Invalid address type %u", start_param->addr.type); + return false; + } + + CHECKIF(start_param->adv_sid > BT_GAP_SID_MAX) { + LOG_DBG("param->param[%zu]->adv_sid is larger than %d", i, BT_GAP_SID_MAX); + return false; + } + + CHECKIF(!IN_RANGE(start_param->pa_interval, BT_GAP_PER_ADV_MIN_INTERVAL, + BT_GAP_PER_ADV_MAX_INTERVAL)) { + LOG_DBG("param->param[%zu]->pa_interval is out of range", i); + return false; + } + + CHECKIF(start_param->broadcast_id > BT_AUDIO_BROADCAST_ID_MAX) { + LOG_DBG("param->param[%zu]->broadcast_id is larger than %u", i, + BT_AUDIO_BROADCAST_ID_MAX); + return false; + } + + CHECKIF(start_param->num_subgroups == 0) { + LOG_DBG("param->param[%zu]->num_subgroups is 0", i); + return false; + } + + CHECKIF(start_param->num_subgroups > CONFIG_BT_BAP_BASS_MAX_SUBGROUPS) { + LOG_DBG("Too many subgroups %u/%u", start_param->num_subgroups, + CONFIG_BT_BAP_BASS_MAX_SUBGROUPS); + + return false; + } + + CHECKIF(start_param->subgroups == NULL) { + LOG_DBG("param->param[%zu]->subgroup is NULL", i); + return false; + } + + for (size_t j = 0U; j < start_param->num_subgroups; j++) { + const struct bt_bap_bass_subgroup *param_subgroups = + &start_param->subgroups[j]; + + CHECKIF(!valid_bis_syncs(param_subgroups->bis_sync)) { + LOG_DBG("param->param[%zu].subgroup[%zu].bis_sync is invalid %u", i, + j, param_subgroups->bis_sync); + } + + CHECKIF((total_bis_sync & param_subgroups->bis_sync) != 0) { + LOG_DBG("param->param[%zu].subgroup[%zu].bis_sync 0x%08X has " + "duplicate bits (0x%08X) ", + i, j, param_subgroups->bis_sync, total_bis_sync); + } + + total_bis_sync |= param_subgroups->bis_sync; + + CHECKIF(param_subgroups->metadata_len > + CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE) { + LOG_DBG("param->param[%zu].subgroup[%zu].metadata_len too long " + "%u/%u", + i, j, param_subgroups->metadata_len, + CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE); + + return false; + } +#if defined(CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE) + CHECKIF(param_subgroups->metadata_len > 0 && + !bt_audio_valid_ltv(param_subgroups->metadata, + param_subgroups->metadata_len)) { + LOG_DBG("param->param[%zu].subgroup[%zu].metadata not valid LTV", i, + j); + } +#endif + } + + for (size_t j = 0U; j < i; j++) { + const union bt_cap_set_member *other = ¶m->param[j].member; + + if (other == member) { + LOG_DBG("param->members[%zu] (%p) is duplicated by " + "param->members[%zu] (%p)", + j, other, i, member); + return false; + } + } + } + + return true; +} + int bt_cap_commander_broadcast_reception_start( const struct bt_cap_commander_broadcast_reception_start_param *param) { - return -ENOSYS; + struct bt_bap_broadcast_assistant_add_src_param add_src_param = {0}; + struct bt_cap_commander_proc_param *proc_param; + struct bt_cap_common_proc *active_proc; + struct bt_conn *conn; + int err; + + if (bt_cap_common_proc_is_active()) { + LOG_DBG("A CAP procedure is already in progress"); + + return -EBUSY; + } + + if (!valid_broadcast_reception_start_param(param)) { + return -EINVAL; + } + + bt_cap_common_start_proc(BT_CAP_COMMON_PROC_TYPE_BROADCAST_RECEPTION_START, param->count); + + broadcast_assistant_cb.add_src = cap_commander_ba_add_src_cb; + if (!ba_cb_registered && cap_commander_register_ba_cb() != 0) { + LOG_DBG("Failed to register VCP callbacks"); + + return -ENOEXEC; + } + + active_proc = bt_cap_common_get_active_proc(); + + for (size_t i = 0U; i < param->count; i++) { + const struct bt_cap_commander_broadcast_reception_start_member_param *member_param = + ¶m->param[i]; + struct bt_cap_commander_proc_param *stored_param; + struct bt_conn *member_conn = + bt_cap_common_get_member_conn(param->type, &member_param->member); + + 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 + * TODO: consider putting this into a function + */ + stored_param = &active_proc->proc_param.commander[i]; + stored_param->conn = member_conn; + bt_addr_le_copy(&stored_param->broadcast_reception_start.addr, &member_param->addr); + stored_param->broadcast_reception_start.adv_sid = member_param->adv_sid; + stored_param->broadcast_reception_start.broadcast_id = member_param->broadcast_id; + stored_param->broadcast_reception_start.pa_interval = member_param->pa_interval; + stored_param->broadcast_reception_start.num_subgroups = member_param->num_subgroups; + memcpy(stored_param->broadcast_reception_start.subgroups, member_param->subgroups, + sizeof(struct bt_bap_bass_subgroup) * add_src_param.num_subgroups); + } + + active_proc->proc_initiated_cnt++; + + proc_param = &active_proc->proc_param.commander[0]; + + conn = proc_param->conn; + copy_broadcast_reception_start_param(&add_src_param, + &proc_param->broadcast_reception_start); + + /* TODO: what to do if we are adding a source that has already been added? */ + err = bt_bap_broadcast_assistant_add_src(conn, &add_src_param); + if (err != 0) { + LOG_DBG("Failed to start broadcast reception for conn %p: %d", (void *)conn, err); + + return -ENOEXEC; + } + + return 0; } +#endif /* CONFIG_BT_BAP_BROADCAST_ASSISTANT */ 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) + +static void cap_commander_proc_complete(void) { struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc(); enum bt_cap_common_proc_type proc_type; @@ -112,7 +411,7 @@ static void cap_commander_unicast_audio_proc_complete(void) } break; case BT_CAP_COMMON_PROC_TYPE_VOLUME_MUTE_CHANGE: - if (cap_cb->volume_changed != NULL) { + if (cap_cb->volume_mute_changed != NULL) { cap_cb->volume_mute_changed(failed_conn, err); } break; @@ -138,6 +437,13 @@ static void cap_commander_unicast_audio_proc_complete(void) break; #endif /* CONFIG_BT_MICP_MIC_CTLR_AICS */ #endif /* CONFIG_BT_MICP_MIC_CTLR */ +#if defined(CONFIG_BT_BAP_BROADCAST_ASSISTANT) + case BT_CAP_COMMON_PROC_TYPE_BROADCAST_RECEPTION_START: + if (cap_cb->broadcast_reception_start != NULL) { + cap_cb->broadcast_reception_start(failed_conn, err); + } + break; +#endif /* CONFIG_BT_BAP_BROADCAST_ASSISTANT */ case BT_CAP_COMMON_PROC_TYPE_NONE: default: __ASSERT(false, "Invalid proc_type: %u", proc_type); @@ -153,7 +459,7 @@ int bt_cap_commander_cancel(void) } bt_cap_common_abort_proc(NULL, -ECANCELED); - cap_commander_unicast_audio_proc_complete(); + cap_commander_proc_complete(); return 0; } @@ -265,7 +571,7 @@ static void cap_commander_vcp_vol_set_cb(struct bt_vcp_vol_ctlr *vol_ctlr, int e LOG_DBG("Proc is aborted"); if (bt_cap_common_proc_all_handled()) { LOG_DBG("All handled"); - cap_commander_unicast_audio_proc_complete(); + cap_commander_proc_complete(); } return; @@ -282,10 +588,10 @@ static void cap_commander_vcp_vol_set_cb(struct bt_vcp_vol_ctlr *vol_ctlr, int e 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(); + cap_commander_proc_complete(); } } else { - cap_commander_unicast_audio_proc_complete(); + cap_commander_proc_complete(); } } @@ -434,7 +740,7 @@ static void cap_commander_vcp_vol_mute_cb(struct bt_vcp_vol_ctlr *vol_ctlr, int LOG_DBG("Proc is aborted"); if (bt_cap_common_proc_all_handled()) { LOG_DBG("All handled"); - cap_commander_unicast_audio_proc_complete(); + cap_commander_proc_complete(); } return; @@ -455,10 +761,10 @@ static void cap_commander_vcp_vol_mute_cb(struct bt_vcp_vol_ctlr *vol_ctlr, int 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(); + cap_commander_proc_complete(); } } else { - cap_commander_unicast_audio_proc_complete(); + cap_commander_proc_complete(); } } @@ -634,7 +940,7 @@ static void cap_commander_vcp_set_offset_cb(struct bt_vocs *inst, int err) LOG_DBG("Proc is aborted"); if (bt_cap_common_proc_all_handled()) { LOG_DBG("All handled"); - cap_commander_unicast_audio_proc_complete(); + cap_commander_proc_complete(); } return; @@ -652,10 +958,10 @@ static void cap_commander_vcp_set_offset_cb(struct bt_vocs *inst, int err) if (err != 0) { LOG_DBG("Failed to set offset for conn %p: %d", (void *)conn, err); bt_cap_common_abort_proc(conn, err); - cap_commander_unicast_audio_proc_complete(); + cap_commander_proc_complete(); } } else { - cap_commander_unicast_audio_proc_complete(); + cap_commander_proc_complete(); } } @@ -847,7 +1153,7 @@ static void cap_commander_micp_mic_mute_cb(struct bt_micp_mic_ctlr *mic_ctlr, in LOG_DBG("Proc is aborted"); if (bt_cap_common_proc_all_handled()) { LOG_DBG("All handled"); - cap_commander_unicast_audio_proc_complete(); + cap_commander_proc_complete(); } return; @@ -868,10 +1174,10 @@ static void cap_commander_micp_mic_mute_cb(struct bt_micp_mic_ctlr *mic_ctlr, in if (err != 0) { LOG_DBG("Failed to change mute for conn %p: %d", (void *)conn, err); bt_cap_common_abort_proc(conn, err); - cap_commander_unicast_audio_proc_complete(); + cap_commander_proc_complete(); } } else { - cap_commander_unicast_audio_proc_complete(); + cap_commander_proc_complete(); } } @@ -1040,7 +1346,7 @@ static void cap_commander_micp_gain_set_cb(struct bt_aics *inst, int err) LOG_DBG("Proc is aborted"); if (bt_cap_common_proc_all_handled()) { LOG_DBG("All handled"); - cap_commander_unicast_audio_proc_complete(); + cap_commander_proc_complete(); } return; @@ -1056,10 +1362,10 @@ static void cap_commander_micp_gain_set_cb(struct bt_aics *inst, int err) if (err != 0) { LOG_DBG("Failed to set gain for conn %p: %d", (void *)conn, err); bt_cap_common_abort_proc(conn, err); - cap_commander_unicast_audio_proc_complete(); + cap_commander_proc_complete(); } } else { - cap_commander_unicast_audio_proc_complete(); + cap_commander_proc_complete(); } } diff --git a/subsys/bluetooth/audio/cap_common.c b/subsys/bluetooth/audio/cap_common.c index 23de8c19cb7..cd4ee8639f0 100644 --- a/subsys/bluetooth/audio/cap_common.c +++ b/subsys/bluetooth/audio/cap_common.c @@ -124,6 +124,7 @@ static bool active_proc_is_commander(void) case BT_CAP_COMMON_PROC_TYPE_VOLUME_MUTE_CHANGE: case BT_CAP_COMMON_PROC_TYPE_MICROPHONE_GAIN_CHANGE: case BT_CAP_COMMON_PROC_TYPE_MICROPHONE_MUTE_CHANGE: + case BT_CAP_COMMON_PROC_TYPE_BROADCAST_RECEPTION_START: return true; default: return false; @@ -255,6 +256,7 @@ struct bt_cap_common_client *bt_cap_common_get_client(enum bt_cap_set_type type, } static void cap_common_discover_complete(struct bt_conn *conn, int err, + const struct bt_csip_set_coordinator_set_member *member, const struct bt_csip_set_coordinator_csis_inst *csis_inst) { struct bt_cap_common_client *client; @@ -264,7 +266,7 @@ static void cap_common_discover_complete(struct bt_conn *conn, int err, const bt_cap_common_discover_func_t cb_func = client->discover_cb_func; client->discover_cb_func = NULL; - cb_func(conn, err, csis_inst); + cb_func(conn, err, member, csis_inst); } } @@ -277,7 +279,7 @@ static void csis_client_discover_cb(struct bt_conn *conn, if (err != 0) { LOG_DBG("CSIS client discover failed: %d", err); - cap_common_discover_complete(conn, err, NULL); + cap_common_discover_complete(conn, err, NULL, NULL); return; } @@ -289,10 +291,10 @@ static void csis_client_discover_cb(struct bt_conn *conn, 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); + cap_common_discover_complete(conn, -ENODATA, NULL, NULL); } else { LOG_DBG("Found CAS with CSIS"); - cap_common_discover_complete(conn, 0, client->csis_inst); + cap_common_discover_complete(conn, 0, member, client->csis_inst); } } @@ -303,7 +305,7 @@ static uint8_t bt_cap_common_discover_included_cb(struct bt_conn *conn, if (attr == NULL) { LOG_DBG("CAS CSIS include not found"); - cap_common_discover_complete(conn, 0, NULL); + cap_common_discover_complete(conn, 0, NULL, NULL); } else { const struct bt_gatt_include *included_service = attr->user_data; struct bt_cap_common_client *client = @@ -334,11 +336,15 @@ static uint8_t bt_cap_common_discover_included_cb(struct bt_conn *conn, err = bt_csip_set_coordinator_discover(conn); if (err != 0) { LOG_DBG("Discover failed (err %d)", err); - cap_common_discover_complete(conn, err, NULL); + cap_common_discover_complete(conn, err, NULL, NULL); } } else { + const struct bt_csip_set_coordinator_set_member *member = + bt_csip_set_coordinator_csis_member_by_conn(conn); + LOG_DBG("Found CAS with CSIS"); - cap_common_discover_complete(conn, 0, client->csis_inst); + + cap_common_discover_complete(conn, 0, member, client->csis_inst); } } @@ -349,7 +355,7 @@ static uint8_t bt_cap_common_discover_cas_cb(struct bt_conn *conn, const struct struct bt_gatt_discover_params *params) { if (attr == NULL) { - cap_common_discover_complete(conn, -ENODATA, NULL); + cap_common_discover_complete(conn, -ENODATA, NULL, NULL); } else { const struct bt_gatt_service_val *prim_service = attr->user_data; struct bt_cap_common_client *client = @@ -361,7 +367,7 @@ static uint8_t bt_cap_common_discover_cas_cb(struct bt_conn *conn, const struct if (attr->handle == prim_service->end_handle) { LOG_DBG("Found CAS without CSIS"); - cap_common_discover_complete(conn, 0, NULL); + cap_common_discover_complete(conn, 0, NULL, NULL); return BT_GATT_ITER_STOP; } @@ -378,7 +384,7 @@ static uint8_t bt_cap_common_discover_cas_cb(struct bt_conn *conn, const struct if (err != 0) { LOG_DBG("Discover failed (err %d)", err); - cap_common_discover_complete(conn, err, NULL); + cap_common_discover_complete(conn, err, NULL, NULL); } } diff --git a/subsys/bluetooth/audio/cap_initiator.c b/subsys/bluetooth/audio/cap_initiator.c index cd57f97e11c..3f750e9516f 100644 --- a/subsys/bluetooth/audio/cap_initiator.c +++ b/subsys/bluetooth/audio/cap_initiator.c @@ -315,10 +315,11 @@ int bt_cap_initiator_broadcast_get_base(struct bt_cap_broadcast_source *broadcas static void bt_cap_initiator_discover_complete(struct bt_conn *conn, int err, + const struct bt_csip_set_coordinator_set_member *member, const struct bt_csip_set_coordinator_csis_inst *csis_inst) { if (cap_cb && cap_cb->unicast_discovery_complete) { - cap_cb->unicast_discovery_complete(conn, err, csis_inst); + cap_cb->unicast_discovery_complete(conn, err, member, csis_inst); } } diff --git a/subsys/bluetooth/audio/cap_internal.h b/subsys/bluetooth/audio/cap_internal.h index 2210110703f..ad94a97a965 100644 --- a/subsys/bluetooth/audio/cap_internal.h +++ b/subsys/bluetooth/audio/cap_internal.h @@ -36,6 +36,7 @@ enum bt_cap_common_proc_type { BT_CAP_COMMON_PROC_TYPE_START, BT_CAP_COMMON_PROC_TYPE_UPDATE, BT_CAP_COMMON_PROC_TYPE_STOP, + BT_CAP_COMMON_PROC_TYPE_BROADCAST_RECEPTION_START, BT_CAP_COMMON_PROC_TYPE_VOLUME_CHANGE, BT_CAP_COMMON_PROC_TYPE_VOLUME_OFFSET_CHANGE, BT_CAP_COMMON_PROC_TYPE_VOLUME_MUTE_CHANGE, @@ -70,6 +71,18 @@ struct bt_cap_initiator_proc_param { }; }; +#if defined(CONFIG_BT_BAP_BROADCAST_ASSISTANT) +struct cap_broadcast_reception_start { + + bt_addr_le_t addr; + uint8_t adv_sid; + uint32_t broadcast_id; + uint16_t pa_interval; + uint8_t num_subgroups; + struct bt_bap_bass_subgroup subgroups[CONFIG_BT_BAP_BASS_MAX_SUBGROUPS]; +}; +#endif /* CONFIG_BT_BAP_BROADCAST_ASSISTANT */ + struct bt_cap_commander_proc_param { struct bt_conn *conn; union { @@ -87,6 +100,9 @@ struct bt_cap_commander_proc_param { struct bt_vocs *vocs; } change_offset; #endif /* CONFIG_BT_VCP_VOL_CTLR_VOCS */ +#if defined(CONFIG_BT_BAP_BROADCAST_ASSISTANT) + struct cap_broadcast_reception_start broadcast_reception_start; +#endif /* CONFIG_BT_BAP_BROADCAST_ASSISTANT */ #if defined(CONFIG_BT_MICP_MIC_CTLR) struct { bool mute; @@ -102,7 +118,8 @@ struct bt_cap_commander_proc_param { }; typedef void (*bt_cap_common_discover_func_t)( - struct bt_conn *conn, int err, const struct bt_csip_set_coordinator_csis_inst *csis_inst); + struct bt_conn *conn, int err, const struct bt_csip_set_coordinator_set_member *member, + const struct bt_csip_set_coordinator_csis_inst *csis_inst); struct bt_cap_common_proc_param { union { diff --git a/subsys/bluetooth/audio/csip_internal.h b/subsys/bluetooth/audio/csip_internal.h index 082a96d2f1b..86dcdcc0161 100644 --- a/subsys/bluetooth/audio/csip_internal.h +++ b/subsys/bluetooth/audio/csip_internal.h @@ -48,3 +48,5 @@ struct bt_csip_set_coordinator_svc_inst { struct bt_csip_set_coordinator_csis_inst *bt_csip_set_coordinator_csis_inst_by_handle( struct bt_conn *conn, uint16_t start_handle); +struct bt_csip_set_coordinator_set_member * +bt_csip_set_coordinator_csis_member_by_conn(struct bt_conn *conn); diff --git a/subsys/bluetooth/audio/csip_set_coordinator.c b/subsys/bluetooth/audio/csip_set_coordinator.c index b59587ebdfc..fb68aa2ee9e 100644 --- a/subsys/bluetooth/audio/csip_set_coordinator.c +++ b/subsys/bluetooth/audio/csip_set_coordinator.c @@ -1418,6 +1418,22 @@ struct bt_csip_set_coordinator_csis_inst *bt_csip_set_coordinator_csis_inst_by_h return NULL; } +struct bt_csip_set_coordinator_set_member * +bt_csip_set_coordinator_csis_member_by_conn(struct bt_conn *conn) +{ + struct bt_csip_set_coordinator_inst *client; + + CHECKIF(conn == NULL) { + LOG_DBG("conn is NULL"); + + return NULL; + } + + client = &client_insts[bt_conn_index(conn)]; + + return &client->set_member; +} + /*************************** PUBLIC FUNCTIONS ***************************/ int bt_csip_set_coordinator_register_cb(struct bt_csip_set_coordinator_cb *cb) { diff --git a/subsys/bluetooth/audio/shell/CMakeLists.txt b/subsys/bluetooth/audio/shell/CMakeLists.txt index 9913d92994a..d44f4e18417 100644 --- a/subsys/bluetooth/audio/shell/CMakeLists.txt +++ b/subsys/bluetooth/audio/shell/CMakeLists.txt @@ -81,6 +81,9 @@ zephyr_library_sources_ifdef( CONFIG_BT_BAP_STREAM bap.c ) +if (CONFIG_LIBLC3 AND CONFIG_USB_DEVICE_AUDIO) + zephyr_library_sources(bap_usb.c) +endif() zephyr_library_sources_ifdef( CONFIG_BT_BAP_SCAN_DELEGATOR bap_scan_delegator.c diff --git a/subsys/bluetooth/audio/shell/audio.h b/subsys/bluetooth/audio/shell/audio.h index eb32b235871..8d537557dae 100644 --- a/subsys/bluetooth/audio/shell/audio.h +++ b/subsys/bluetooth/audio/shell/audio.h @@ -23,6 +23,7 @@ #include "shell/bt.h" #define SHELL_PRINT_INDENT_LEVEL_SIZE 2 +#define MAX_CODEC_FRAMES_PER_SDU 4U extern struct bt_csip_set_member_svc_inst *svc_inst; @@ -31,6 +32,7 @@ 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 bap_scan_delegator_ad_data_add(struct bt_data data[], size_t data_size); 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); ssize_t cap_initiator_ad_data_add(struct bt_data *data_array, const size_t data_array_size, @@ -46,7 +48,20 @@ ssize_t cap_initiator_pa_data_add(struct bt_data *data_array, const size_t data_ #include #include -#define LOCATION BT_AUDIO_LOCATION_FRONT_LEFT | BT_AUDIO_LOCATION_FRONT_RIGHT +unsigned long bap_get_stats_interval(void); + +#if defined(CONFIG_LIBLC3) +#include "lc3.h" + +#define USB_SAMPLE_RATE 48000U +#define LC3_MAX_SAMPLE_RATE 48000U +#define LC3_MAX_FRAME_DURATION_US 10000U +#define LC3_MAX_NUM_SAMPLES_MONO ((LC3_MAX_FRAME_DURATION_US * LC3_MAX_SAMPLE_RATE) / \ + USEC_PER_SEC) +#define LC3_MAX_NUM_SAMPLES_STEREO (LC3_MAX_NUM_SAMPLES_MONO * 2U) +#endif /* CONFIG_LIBLC3 */ + +#define LOCATION BT_AUDIO_LOCATION_FRONT_LEFT #define CONTEXT \ (BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED | BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL | \ BT_AUDIO_CONTEXT_TYPE_MEDIA | \ @@ -60,40 +75,86 @@ struct named_lc3_preset { struct bt_bap_lc3_preset preset; }; -const struct named_lc3_preset *bap_get_named_preset(bool is_unicast, enum bt_audio_dir dir, - const char *preset_arg); - struct shell_stream { struct bt_cap_stream stream; struct bt_audio_codec_cfg codec_cfg; struct bt_audio_codec_qos qos; + bool is_tx; + bool is_rx; + #if defined(CONFIG_LIBLC3) uint32_t lc3_freq_hz; uint32_t lc3_frame_duration_us; uint16_t lc3_octets_per_frame; - uint8_t lc3_frames_per_sdu; + uint8_t lc3_frame_blocks_per_sdu; + enum bt_audio_location lc3_chan_allocation; + uint8_t lc3_chan_cnt; #endif /* CONFIG_LIBLC3 */ + + union { #if defined(CONFIG_BT_AUDIO_TX) - int64_t connected_at_ticks; /* The uptime tick measured when stream was connected */ - uint16_t seq_num; - struct k_work_delayable audio_send_work; - bool tx_active; + struct { + /* The uptime tick measured when stream was connected */ + int64_t connected_at_ticks; + uint16_t seq_num; #if defined(CONFIG_LIBLC3) - atomic_t lc3_enqueue_cnt; - size_t lc3_sdu_cnt; + atomic_t lc3_enqueue_cnt; + bool active; + size_t encoded_cnt; + size_t lc3_sdu_cnt; + lc3_encoder_mem_48k_t lc3_encoder_mem; + lc3_encoder_t lc3_encoder; +#if defined(CONFIG_USB_DEVICE_AUDIO) + /* Indicates where to read left USB data in the ring buffer */ + size_t left_read_idx; + /* Indicates where to read right USB data in the ring buffer */ + size_t right_read_idx; + size_t right_ring_buf_fail_cnt; +#endif /* CONFIG_USB_DEVICE_AUDIO */ #endif /* CONFIG_LIBLC3 */ + } tx; #endif /* CONFIG_BT_AUDIO_TX */ + #if defined(CONFIG_BT_AUDIO_RX) - struct bt_iso_recv_info last_info; - size_t empty_sdu_pkts; - size_t lost_pkts; - size_t err_pkts; - size_t dup_psn; - size_t rx_cnt; - size_t dup_ts; + struct { + struct bt_iso_recv_info last_info; + size_t empty_sdu_pkts; + size_t valid_sdu_pkts; + size_t lost_pkts; + size_t err_pkts; + size_t dup_psn; + size_t rx_cnt; + size_t dup_ts; +#if defined(CONFIG_LIBLC3) + lc3_decoder_mem_48k_t lc3_decoder_mem; + lc3_decoder_t lc3_decoder; + size_t decoded_cnt; +#endif /* CONFIG_LIBLC3 */ + } rx; #endif /* CONFIG_BT_AUDIO_RX */ + }; }; +const struct named_lc3_preset *bap_get_named_preset(bool is_unicast, enum bt_audio_dir dir, + const char *preset_arg); + +size_t bap_get_rx_streaming_cnt(void); +size_t bap_get_tx_streaming_cnt(void); +void bap_foreach_stream(void (*func)(struct shell_stream *sh_stream, void *data), void *data); + +int bap_usb_init(void); + +int bap_usb_add_frame_to_usb(enum bt_audio_location lc3_chan_allocation, const int16_t *frame, + size_t frame_size, uint32_t ts); +void bap_usb_clear_frames_to_usb(void); +uint16_t get_next_seq_num(struct bt_bap_stream *bap_stream); +struct shell_stream *shell_stream_from_bap_stream(struct bt_bap_stream *bap_stream); +struct bt_bap_stream *bap_stream_from_shell_stream(struct shell_stream *sh_stream); +bool bap_usb_can_get_full_sdu(struct shell_stream *sh_stream); +void bap_usb_get_frame(struct shell_stream *sh_stream, enum bt_audio_location chan_alloc, + int16_t buffer[]); +size_t bap_usb_get_frame_size(const struct shell_stream *sh_stream); + struct broadcast_source { bool is_cap; union { @@ -131,8 +192,8 @@ struct broadcast_sink { CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT), \ (0)) -extern struct shell_stream unicast_streams[CONFIG_BT_MAX_CONN * (UNICAST_SERVER_STREAM_COUNT + - UNICAST_CLIENT_STREAM_COUNT)]; +extern struct shell_stream unicast_streams[CONFIG_BT_MAX_CONN * MAX(UNICAST_SERVER_STREAM_COUNT, + UNICAST_CLIENT_STREAM_COUNT)]; #if defined(CONFIG_BT_BAP_UNICAST_CLIENT) @@ -155,11 +216,26 @@ int bap_ac_create_unicast_group(const struct bap_unicast_ac_param *param, struct shell_stream *snk_uni_streams[], size_t snk_cnt, struct shell_stream *src_uni_streams[], size_t src_cnt); -int cap_ac_unicast(const struct shell *sh, size_t argc, char **argv, - const struct bap_unicast_ac_param *param); +int cap_ac_unicast(const struct shell *sh, const struct bap_unicast_ac_param *param); #endif /* CONFIG_BT_BAP_UNICAST_CLIENT */ #endif /* CONFIG_BT_BAP_UNICAST */ +static inline uint8_t get_chan_cnt(enum bt_audio_location chan_allocation) +{ + uint8_t cnt = 0U; + + if (chan_allocation == BT_AUDIO_LOCATION_MONO_AUDIO) { + return 1; + } + + while (chan_allocation != 0) { + cnt += chan_allocation & 1U; + chan_allocation >>= 1; + } + + return cnt; +} + static inline void print_qos(const struct shell *sh, const struct bt_audio_codec_qos *qos) { #if defined(CONFIG_BT_BAP_BROADCAST_SOURCE) || defined(CONFIG_BT_BAP_UNICAST) @@ -784,13 +860,18 @@ static inline void print_codec_cfg_chan_allocation(const struct shell *sh, size_ shell_print(sh, "%*sChannel allocation:", indent, ""); indent += SHELL_PRINT_INDENT_LEVEL_SIZE; - /* There can be up to 32 bits set in the field */ - for (size_t i = 0; i < 32; i++) { - const uint8_t bit_val = BIT(i); - if (chan_allocation & bit_val) { - shell_print(sh, "%*s%s (0x%08X)", indent, "", - chan_location_bit_to_str(bit_val), bit_val); + if (chan_allocation == BT_AUDIO_LOCATION_MONO_AUDIO) { + shell_print(sh, "%*s Mono", indent, ""); + } else { + /* There can be up to 32 bits set in the field */ + for (size_t i = 0; i < 32; i++) { + const uint8_t bit_val = BIT(i); + + if (chan_allocation & bit_val) { + shell_print(sh, "%*s%s (0x%08X)", indent, "", + chan_location_bit_to_str(bit_val), bit_val); + } } } } @@ -941,6 +1022,7 @@ int cap_ac_broadcast(const struct shell *sh, size_t argc, char **argv, extern struct shell_stream broadcast_source_streams[CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT]; extern struct broadcast_source default_source; +extern struct named_lc3_preset default_broadcast_source_preset; #endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */ static inline bool print_base_subgroup_bis_cb(const struct bt_bap_base_subgroup_bis *bis, diff --git a/subsys/bluetooth/audio/shell/bap.c b/subsys/bluetooth/audio/shell/bap.c index 49cca9941c5..4ffa9539940 100644 --- a/subsys/bluetooth/audio/shell/bap.c +++ b/subsys/bluetooth/audio/shell/bap.c @@ -27,14 +27,6 @@ #include #include -#if defined(CONFIG_LIBLC3) -#include "lc3.h" - -#define LC3_MAX_SAMPLE_RATE 48000 -#define LC3_MAX_FRAME_DURATION_US 10000 -#define LC3_MAX_NUM_SAMPLES ((LC3_MAX_FRAME_DURATION_US * LC3_MAX_SAMPLE_RATE) / USEC_PER_SEC) -#endif /* CONFIG_LIBLC3 */ - #include "shell/bt.h" #include "audio.h" @@ -42,10 +34,12 @@ #define IS_BAP_INITIATOR \ (IS_ENABLED(CONFIG_BT_BAP_BROADCAST_SOURCE) || IS_ENABLED(CONFIG_BT_BAP_UNICAST_CLIENT)) +#define GENERATE_SINE_SUPPORTED (IS_ENABLED(CONFIG_LIBLC3) && !IS_ENABLED(CONFIG_USB_DEVICE_AUDIO)) + #if defined(CONFIG_BT_BAP_UNICAST) struct shell_stream unicast_streams[CONFIG_BT_MAX_CONN * - (UNICAST_SERVER_STREAM_COUNT + UNICAST_CLIENT_STREAM_COUNT)]; + MAX(UNICAST_SERVER_STREAM_COUNT, UNICAST_CLIENT_STREAM_COUNT)]; #if defined(CONFIG_BT_BAP_UNICAST_CLIENT) struct bt_bap_unicast_group *default_unicast_group; @@ -78,7 +72,7 @@ struct named_lc3_preset default_sink_preset = {"16_2_1", BT_BAP_LC3_UNICAST_PRESET_16_2_1(LOCATION, CONTEXT)}; struct named_lc3_preset default_source_preset = { "16_2_1", BT_BAP_LC3_UNICAST_PRESET_16_2_1(LOCATION, CONTEXT)}; -static struct named_lc3_preset default_broadcast_source_preset = { +struct named_lc3_preset default_broadcast_source_preset = { "16_2_1", BT_BAP_LC3_BROADCAST_PRESET_16_2_1(LOCATION, CONTEXT)}; #endif /* IS_BAP_INITIATOR */ @@ -155,8 +149,9 @@ static const struct named_lc3_preset lc3_broadcast_presets[] = { }; static bool initialized; +static unsigned long bap_stats_interval = 1000U; -static struct shell_stream *shell_stream_from_bap_stream(struct bt_bap_stream *bap_stream) +struct shell_stream *shell_stream_from_bap_stream(struct bt_bap_stream *bap_stream) { struct bt_cap_stream *cap_stream = CONTAINER_OF(bap_stream, struct bt_cap_stream, bap_stream); @@ -165,13 +160,75 @@ static struct shell_stream *shell_stream_from_bap_stream(struct bt_bap_stream *b return sh_stream; } -static struct bt_bap_stream *bap_stream_from_shell_stream(struct shell_stream *sh_stream) +struct bt_bap_stream *bap_stream_from_shell_stream(struct shell_stream *sh_stream) { return &sh_stream->stream.bap_stream; } +unsigned long bap_get_stats_interval(void) +{ + return bap_stats_interval; +} + +void bap_foreach_stream(void (*func)(struct shell_stream *sh_stream, void *data), void *data) +{ +#if defined(CONFIG_BT_BAP_UNICAST) + for (size_t i = 0U; i < ARRAY_SIZE(unicast_streams); i++) { + func(&unicast_streams[i], data); + } +#endif /* CONFIG_BT_BAP_UNICAST */ + +#if defined(CONFIG_BT_BAP_BROADCAST_SOURCE) + for (size_t i = 0U; i < ARRAY_SIZE(broadcast_source_streams); i++) { + func(&broadcast_source_streams[i], data); + } +#endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */ + +#if defined(CONFIG_BT_BAP_BROADCAST_SINK) + for (size_t i = 0U; i < ARRAY_SIZE(broadcast_sink_streams); i++) { + func(&broadcast_sink_streams[i], data); + } +#endif /* CONFIG_BT_BAP_BROADCAST_SINK */ +} + +#if defined(CONFIG_LIBLC3) +static int get_lc3_chan_alloc_from_index(const struct shell_stream *sh_stream, uint8_t index, + enum bt_audio_location *chan_alloc) +{ + const bool has_left = (sh_stream->lc3_chan_allocation & BT_AUDIO_LOCATION_FRONT_LEFT) != 0; + const bool has_right = + (sh_stream->lc3_chan_allocation & BT_AUDIO_LOCATION_FRONT_RIGHT) != 0; + const bool is_mono = sh_stream->lc3_chan_allocation == BT_AUDIO_LOCATION_MONO_AUDIO; + const bool is_left = index == 0 && has_left; + const bool is_right = has_right && (index == 0U || (index == 1U && has_left)); + + /* LC3 is always Left before Right, so we can use the index and the stream channel + * allocation to determine if index 0 is left or right. + */ + if (is_left) { + *chan_alloc = BT_AUDIO_LOCATION_FRONT_LEFT; + } else if (is_right) { + *chan_alloc = BT_AUDIO_LOCATION_FRONT_RIGHT; + } else if (is_mono) { + *chan_alloc = BT_AUDIO_LOCATION_MONO_AUDIO; + } else { + /* Not suitable for USB */ + return -EINVAL; + } + + return 0; +} +#endif /* CONFIG_LIBLC3 */ + #if defined(CONFIG_BT_AUDIO_TX) -static uint16_t get_next_seq_num(struct bt_bap_stream *bap_stream) +static size_t tx_streaming_cnt; + +size_t bap_get_tx_streaming_cnt(void) +{ + return tx_streaming_cnt; +} + +uint16_t get_next_seq_num(struct bt_bap_stream *bap_stream) { struct shell_stream *sh_stream = shell_stream_from_bap_stream(bap_stream); const uint32_t interval_us = bap_stream->qos->interval; @@ -180,9 +237,13 @@ static uint16_t get_next_seq_num(struct bt_bap_stream *bap_stream) uint64_t delta_us; uint16_t seq_num; + if (!sh_stream->is_tx) { + return 0; + } + /* Note: This does not handle wrapping of ticks when they go above 2^(62-1) */ uptime_ticks = k_uptime_ticks(); - delta_ticks = uptime_ticks - sh_stream->connected_at_ticks; + delta_ticks = uptime_ticks - sh_stream->tx.connected_at_ticks; delta_us = k_ticks_to_us_near64((uint64_t)delta_ticks); /* Calculate the sequence number by dividing the stream uptime by the SDU interval */ @@ -197,8 +258,8 @@ static uint16_t get_next_seq_num(struct bt_bap_stream *bap_stream) * controller ISO buffer to handle jitter. */ #define PRIME_COUNT 2U -NET_BUF_POOL_FIXED_DEFINE(sine_tx_pool, CONFIG_BT_ISO_TX_BUF_COUNT, - BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU), +#define SINE_TX_POOL_SIZE (BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU)) +NET_BUF_POOL_FIXED_DEFINE(sine_tx_pool, CONFIG_BT_ISO_TX_BUF_COUNT, SINE_TX_POOL_SIZE, CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); #include "math.h" @@ -206,18 +267,59 @@ NET_BUF_POOL_FIXED_DEFINE(sine_tx_pool, CONFIG_BT_ISO_TX_BUF_COUNT, #define AUDIO_VOLUME (INT16_MAX - 3000) /* codec does clipping above INT16_MAX - 3000 */ #define AUDIO_TONE_FREQUENCY_HZ 400 -static int16_t lc3_tx_buf[LC3_MAX_NUM_SAMPLES]; -static lc3_encoder_t lc3_encoder; -static lc3_encoder_mem_48k_t lc3_encoder_mem; -static int lc3_encoder_freq_hz; -static int lc3_encoder_frame_duration_us; +static int16_t lc3_tx_buf[LC3_MAX_NUM_SAMPLES_MONO]; -static void clear_lc3_sine_data(struct bt_bap_stream *bap_stream) +static int init_lc3_encoder(struct shell_stream *sh_stream) { - struct shell_stream *sh_stream = shell_stream_from_bap_stream(bap_stream); + if (sh_stream == NULL) { + shell_error(ctx_shell, "NULL stream to init LC3"); + return -EINVAL; + } + + if (!sh_stream->is_tx) { + shell_error(ctx_shell, "Invalid stream to init LC3 encoder"); + return -EINVAL; + } + + if (sh_stream->tx.lc3_encoder != NULL) { + shell_error(ctx_shell, "Already initialized"); + return -EALREADY; + } + + if (sh_stream->lc3_freq_hz == 0 || sh_stream->lc3_frame_duration_us == 0) { + shell_error(ctx_shell, "Invalid freq (%u) or frame duration (%u)", + sh_stream->lc3_freq_hz, sh_stream->lc3_frame_duration_us); + + return -EINVAL; + } + + if (IS_ENABLED(CONFIG_USB_DEVICE_AUDIO)) { + const size_t frame_size = bap_usb_get_frame_size(sh_stream); + + if (frame_size > sizeof(lc3_tx_buf)) { + shell_error(ctx_shell, "Cannot put %u octets in lc3_tx_buf of size %zu", + frame_size, sizeof(lc3_tx_buf)); + + return -EINVAL; + } + } + + shell_print(ctx_shell, + "Initializing LC3 encoder for BAP stream %p with %u us duration and %u Hz " + "frequency", + bap_stream_from_shell_stream(sh_stream), sh_stream->lc3_frame_duration_us, + sh_stream->lc3_freq_hz); - sh_stream->tx_active = false; - (void)k_work_cancel_delayable(&sh_stream->audio_send_work); + sh_stream->tx.lc3_encoder = + lc3_setup_encoder(sh_stream->lc3_frame_duration_us, sh_stream->lc3_freq_hz, + IS_ENABLED(CONFIG_USB_DEVICE_AUDIO) ? USB_SAMPLE_RATE : 0, + &sh_stream->tx.lc3_encoder_mem); + if (sh_stream->tx.lc3_encoder == NULL) { + shell_error(ctx_shell, "Failed to setup LC3 encoder - wrong parameters?\n"); + return -EINVAL; + } + + return 0; } /** @@ -241,64 +343,97 @@ static void fill_lc3_tx_buf_sin(int16_t *buf, int length_us, int frequency_hz, i } } -static int init_lc3_encoder(const struct shell_stream *sh_stream) +static bool encode_frame(struct shell_stream *sh_stream, uint8_t index, size_t frame_cnt, + struct net_buf *out_buf) { - size_t num_samples; + const size_t total_frames = sh_stream->lc3_chan_cnt * sh_stream->lc3_frame_blocks_per_sdu; + const uint16_t octets_per_frame = sh_stream->lc3_octets_per_frame; + int lc3_ret; - if (sh_stream == NULL) { - shell_error(ctx_shell, "invalid stream to init LC3"); - return -EINVAL; - } + if (IS_ENABLED(CONFIG_USB_DEVICE_AUDIO)) { + enum bt_audio_location chan_alloc; + int err; - if (sh_stream->lc3_freq_hz == 0 || sh_stream->lc3_frame_duration_us == 0) { - shell_error(ctx_shell, "Invalid freq (%u) or frame duration (%u)", - sh_stream->lc3_freq_hz, sh_stream->lc3_frame_duration_us); + err = get_lc3_chan_alloc_from_index(sh_stream, index, &chan_alloc); + if (err != 0) { + /* Not suitable for USB */ + false; + } - return -EINVAL; + /* TODO: Move the following to a function in bap_usb.c*/ + bap_usb_get_frame(sh_stream, chan_alloc, lc3_tx_buf); + } else { + /* Generate sine wave */ + fill_lc3_tx_buf_sin(lc3_tx_buf, sh_stream->lc3_frame_duration_us, + AUDIO_TONE_FREQUENCY_HZ, sh_stream->lc3_freq_hz); } - /* Create the encoder instance. This shall complete before stream_started() is called. */ - lc3_encoder = lc3_setup_encoder(sh_stream->lc3_frame_duration_us, sh_stream->lc3_freq_hz, - 0, /* No resampling */ - &lc3_encoder_mem); + if ((sh_stream->tx.encoded_cnt % bap_stats_interval) == 0) { + shell_print(ctx_shell, "[%zu]: Encoding frame of size %u (%u/%u)", + sh_stream->tx.encoded_cnt, octets_per_frame, frame_cnt + 1, + total_frames); + } - if (lc3_encoder == NULL) { - shell_error(ctx_shell, "Failed to setup LC3 encoder - wrong parameters?\n"); - return -EINVAL; + lc3_ret = lc3_encode(sh_stream->tx.lc3_encoder, LC3_PCM_FORMAT_S16, lc3_tx_buf, 1, + octets_per_frame, net_buf_tail(out_buf)); + if (lc3_ret == -1) { + shell_error(ctx_shell, "LC3 encoder failed - wrong parameters?: %d", lc3_ret); + + return false; } - lc3_encoder_freq_hz = sh_stream->lc3_freq_hz; - lc3_encoder_frame_duration_us = sh_stream->lc3_frame_duration_us; + out_buf->len += octets_per_frame; - /* Fill audio buffer with Sine wave only once and repeat encoding the same tone frame */ - fill_lc3_tx_buf_sin(lc3_tx_buf, lc3_encoder_frame_duration_us, AUDIO_TONE_FREQUENCY_HZ, - lc3_encoder_freq_hz); + return true; +} - num_samples = ((lc3_encoder_frame_duration_us * lc3_encoder_freq_hz) / USEC_PER_SEC); - for (size_t i = 0; i < num_samples; i++) { - printk("%zu: %6i\n", i, lc3_tx_buf[i]); +static size_t encode_frame_block(struct shell_stream *sh_stream, size_t frame_cnt, + struct net_buf *out_buf) +{ + const uint8_t chan_cnt = sh_stream->lc3_chan_cnt; + size_t encoded_frames = 0U; + + for (uint8_t i = 0U; i < chan_cnt; i++) { + /* We provide the total number of decoded frames to `decode_frame` for logging + * purposes + */ + if (encode_frame(sh_stream, i, frame_cnt, out_buf)) { + encoded_frames++; + } } - return 0; + return encoded_frames; +} + +static void do_lc3_encode(struct shell_stream *sh_stream, struct net_buf *out_buf) +{ + if (IS_ENABLED(CONFIG_USB_DEVICE_AUDIO) && !bap_usb_can_get_full_sdu(sh_stream)) { + /* No op - Will just send empty SDU */ + } else { + size_t frame_cnt = 0U; + + for (uint8_t i = 0U; i < sh_stream->lc3_frame_blocks_per_sdu; i++) { + frame_cnt += encode_frame_block(sh_stream, frame_cnt, out_buf); + + sh_stream->tx.encoded_cnt++; + } + } } -static void lc3_audio_send_data(struct k_work *work) +static void lc3_audio_send_data(struct shell_stream *sh_stream) { - struct shell_stream *sh_stream = CONTAINER_OF(k_work_delayable_from_work(work), - struct shell_stream, audio_send_work); struct bt_bap_stream *bap_stream = bap_stream_from_shell_stream(sh_stream); - const uint16_t tx_sdu_len = sh_stream->lc3_frames_per_sdu * sh_stream->lc3_octets_per_frame; + const uint16_t tx_sdu_len = sh_stream->lc3_frame_blocks_per_sdu * sh_stream->lc3_chan_cnt * + sh_stream->lc3_octets_per_frame; struct net_buf *buf; - uint8_t *net_buffer; - off_t offset = 0; int err; - if (!sh_stream->tx_active) { + if (!sh_stream->is_tx || !sh_stream->tx.active) { /* TX has been aborted */ return; } - if (lc3_encoder == NULL) { + if (sh_stream->tx.lc3_encoder == NULL) { shell_error(ctx_shell, "LC3 encoder not setup, cannot encode data"); return; } @@ -308,91 +443,75 @@ static void lc3_audio_send_data(struct k_work *work) return; } - if (tx_sdu_len == 0U) { - shell_error( - ctx_shell, - "Cannot send 0 length SDU (from frames per sdu %u and %u octets per frame)", - sh_stream->lc3_frames_per_sdu, sh_stream->lc3_octets_per_frame); + if (tx_sdu_len == 0U || tx_sdu_len > SINE_TX_POOL_SIZE) { + shell_error(ctx_shell, + "Cannot send %u length SDU (from frame blocks per sdu %u, channel " + "count %u and %u octets per frame) for pool size %d", + tx_sdu_len, sh_stream->lc3_frame_blocks_per_sdu, + sh_stream->lc3_chan_cnt, sh_stream->lc3_octets_per_frame, + SINE_TX_POOL_SIZE); return; } - if (atomic_get(&sh_stream->lc3_enqueue_cnt) == 0U) { - shell_error(ctx_shell, "Stream %p enqueue count was 0", bap_stream); - - /* Reschedule for next interval */ - k_work_reschedule(k_work_delayable_from_work(work), - K_USEC(bap_stream->qos->interval)); + if (atomic_get(&sh_stream->tx.lc3_enqueue_cnt) == 0U) { + /* no op */ return; } buf = net_buf_alloc(&sine_tx_pool, K_FOREVER); net_buf_reserve(buf, BT_ISO_CHAN_SEND_RESERVE); - net_buffer = net_buf_tail(buf); - buf->len += tx_sdu_len; - - for (uint8_t i = 0U; i < sh_stream->lc3_frames_per_sdu; i++) { - int lc3_ret; + do_lc3_encode(sh_stream, buf); - lc3_ret = lc3_encode(lc3_encoder, LC3_PCM_FORMAT_S16, lc3_tx_buf, 1, - sh_stream->lc3_octets_per_frame, net_buffer + offset); - offset += sh_stream->lc3_octets_per_frame; - - if (lc3_ret == -1) { - shell_error(ctx_shell, "LC3 encoder failed - wrong parameters?: %d", - lc3_ret); - net_buf_unref(buf); - - /* Reschedule for next interval */ - k_work_reschedule(k_work_delayable_from_work(work), - K_USEC(bap_stream->qos->interval)); - return; - } - } - - err = bt_bap_stream_send(bap_stream, buf, sh_stream->seq_num); + err = bt_bap_stream_send(bap_stream, buf, sh_stream->tx.seq_num); if (err < 0) { shell_error(ctx_shell, "Failed to send LC3 audio data (%d)", err); net_buf_unref(buf); - /* Reschedule for next interval */ - k_work_reschedule(k_work_delayable_from_work(work), - K_USEC(bap_stream->qos->interval)); return; } - if ((sh_stream->lc3_sdu_cnt % 100) == 0) { + if ((sh_stream->tx.lc3_sdu_cnt % bap_stats_interval) == 0U) { shell_info(ctx_shell, "[%zu]: stream %p : TX LC3: %zu (seq_num %u)", - sh_stream->lc3_sdu_cnt, bap_stream, tx_sdu_len, sh_stream->seq_num); + sh_stream->tx.lc3_sdu_cnt, bap_stream, tx_sdu_len, + sh_stream->tx.seq_num); } - sh_stream->lc3_sdu_cnt++; - sh_stream->seq_num++; - atomic_dec(&sh_stream->lc3_enqueue_cnt); - - if (atomic_get(&sh_stream->lc3_enqueue_cnt) > 0) { - /* If we have more buffers available, we reschedule the workqueue item immediately - * to trigger another encode + TX, but without blocking this call for too long - */ - k_work_reschedule(k_work_delayable_from_work(work), K_NO_WAIT); - } + sh_stream->tx.lc3_sdu_cnt++; + sh_stream->tx.seq_num++; + atomic_dec(&sh_stream->tx.lc3_enqueue_cnt); } static void lc3_sent_cb(struct bt_bap_stream *bap_stream) { struct shell_stream *sh_stream = shell_stream_from_bap_stream(bap_stream); - int err; - atomic_inc(&sh_stream->lc3_enqueue_cnt); - - if (!sh_stream->tx_active) { - /* TX has been aborted */ + if (!sh_stream->is_tx) { return; } - err = k_work_schedule(&sh_stream->audio_send_work, K_NO_WAIT); - if (err < 0) { - shell_error(ctx_shell, "Failed to schedule TX for stream %p: %d", bap_stream, err); + atomic_inc(&sh_stream->tx.lc3_enqueue_cnt); +} + +static void encode_and_send_cb(struct shell_stream *sh_stream, void *user_data) +{ + if (sh_stream->is_tx) { + lc3_audio_send_data(sh_stream); + } +} + +static void lc3_encoder_thread_func(void *arg1, void *arg2, void *arg3) +{ + /* This will attempt to send on all TX streams. + * If there are no buffers available or the stream already have PRIME_COUNT outstanding SDUs + * the stream will not send anything. + * + * If USB is enabled it will attempt to read from buffered USB audio data. + * If there is no data available it will send empty SDUs + */ + while (true) { + bap_foreach_stream(encode_and_send_cb, NULL); + k_sleep(K_MSEC(1)); } } #endif /* CONFIG_LIBLC3 && CONFIG_BT_AUDIO_TX */ @@ -422,9 +541,9 @@ const struct named_lc3_preset *bap_get_named_preset(bool is_unicast, enum bt_aud } #if defined(CONFIG_BT_PACS) -static const struct bt_audio_codec_cap lc3_codec_cap = - BT_AUDIO_CODEC_CAP_LC3(BT_AUDIO_CODEC_CAP_FREQ_ANY, BT_AUDIO_CODEC_CAP_DURATION_ANY, - BT_AUDIO_CODEC_CAP_CHAN_COUNT_SUPPORT(1, 2), 30, 240, 2, CONTEXT); +static const struct bt_audio_codec_cap lc3_codec_cap = BT_AUDIO_CODEC_CAP_LC3( + BT_AUDIO_CODEC_CAP_FREQ_ANY, BT_AUDIO_CODEC_CAP_DURATION_ANY, + BT_AUDIO_CODEC_CAP_CHAN_COUNT_SUPPORT(1, 2), 30, 240, MAX_CODEC_FRAMES_PER_SDU, CONTEXT); #if defined(CONFIG_BT_PAC_SNK) static struct bt_pacs_cap cap_sink = { @@ -2150,6 +2269,7 @@ static int cmd_preset(const struct shell *sh, size_t argc, char *argv[]) static struct broadcast_sink_auto_scan { struct broadcast_sink *broadcast_sink; uint32_t broadcast_id; + struct bt_le_per_adv_sync **out_sync; } auto_scan = { .broadcast_id = INVALID_BROADCAST_ID, }; @@ -2204,8 +2324,10 @@ static bool scan_check_and_sync_broadcast(struct bt_data *data, void *user_data) bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr)); - shell_print(ctx_shell, "Found broadcaster with ID 0x%06X and addr %s and sid 0x%02X", - broadcast_id, le_addr, info->sid); + shell_print(ctx_shell, + "Found broadcaster with ID 0x%06X and addr %s and sid 0x%02X (looking for " + "0x%06X)", + broadcast_id, le_addr, info->sid, auto_scan.broadcast_id); if (auto_scan.broadcast_id == broadcast_id && auto_scan.broadcast_sink != NULL && auto_scan.broadcast_sink->pa_sync == NULL) { @@ -2224,9 +2346,11 @@ static bool scan_check_and_sync_broadcast(struct bt_data *data, void *user_data) create_params.timeout = interval_to_sync_timeout(info->interval); shell_print(ctx_shell, "Attempting to PA sync to the broadcaster"); - err = bt_le_per_adv_sync_create(&create_params, &auto_scan.broadcast_sink->pa_sync); + err = bt_le_per_adv_sync_create(&create_params, auto_scan.out_sync); if (err != 0) { shell_error(ctx_shell, "Could not create Broadcast PA sync: %d", err); + } else { + auto_scan.broadcast_sink->pa_sync = *auto_scan.out_sync; } } @@ -2271,12 +2395,13 @@ static void syncable(struct bt_bap_broadcast_sink *sink, const struct bt_iso_big static void bap_pa_sync_synced_cb(struct bt_le_per_adv_sync *sync, struct bt_le_per_adv_sync_synced_info *info) { - if (auto_scan.broadcast_sink != NULL && sync == auto_scan.broadcast_sink->pa_sync) { + if (auto_scan.broadcast_sink != NULL && auto_scan.out_sync != NULL && + sync == *auto_scan.out_sync) { shell_print(ctx_shell, "PA synced to broadcast with broadcast ID 0x%06x", auto_scan.broadcast_id); if (auto_scan.broadcast_sink->bap_sink == NULL) { - shell_print(ctx_shell, "Attempting to sync to the BIG"); + shell_print(ctx_shell, "Attempting to create the sink"); int err; err = bt_bap_broadcast_sink_create(sync, auto_scan.broadcast_id, @@ -2285,7 +2410,7 @@ static void bap_pa_sync_synced_cb(struct bt_le_per_adv_sync *sync, shell_error(ctx_shell, "Could not create broadcast sink: %d", err); } } else { - shell_print(ctx_shell, "BIG is already synced"); + shell_print(ctx_shell, "Sink is already created"); } } @@ -2328,7 +2453,209 @@ static struct bt_le_scan_cb bap_scan_cb = { #endif /* CONFIG_BT_BAP_BROADCAST_SINK */ #if defined(CONFIG_BT_AUDIO_RX) -static unsigned long recv_stats_interval = 100U; +static size_t rx_streaming_cnt; + +size_t bap_get_rx_streaming_cnt(void) +{ + return rx_streaming_cnt; +} + +#if defined(CONFIG_LIBLC3) +struct lc3_data { + void *fifo_reserved; /* 1st word reserved for use by FIFO */ + struct net_buf *buf; + struct shell_stream *sh_stream; + uint32_t ts; + bool do_plc; +}; + +K_MEM_SLAB_DEFINE(lc3_data_slab, sizeof(struct lc3_data), CONFIG_BT_ISO_RX_BUF_COUNT, + __alignof__(struct lc3_data)); + +static int16_t lc3_rx_buf[LC3_MAX_NUM_SAMPLES_MONO]; +static K_FIFO_DEFINE(lc3_in_fifo); + +/* We only want to send USB to left/right from a single stream. If we have 2 left streams, the + * outgoing audio is going to be terrible. + * Since a stream can contain stereo data, both of these may be the same stream. + */ +static struct shell_stream *usb_left_stream; +static struct shell_stream *usb_right_stream; + +static int init_lc3_decoder(struct shell_stream *sh_stream) +{ + if (sh_stream == NULL) { + shell_error(ctx_shell, "NULL stream to init LC3 decoder"); + return -EINVAL; + } + + if (!sh_stream->is_rx) { + shell_error(ctx_shell, "Invalid stream to init LC3 decoder"); + return -EINVAL; + } + + if (sh_stream->rx.lc3_decoder != NULL) { + shell_error(ctx_shell, "Already initialized"); + return -EALREADY; + } + + if (sh_stream->lc3_freq_hz == 0 || sh_stream->lc3_frame_duration_us == 0) { + shell_error(ctx_shell, "Invalid freq (%u) or frame duration (%u)", + sh_stream->lc3_freq_hz, sh_stream->lc3_frame_duration_us); + + return -EINVAL; + } + + shell_print(ctx_shell, + "Initializing the LC3 decoder with %u us duration and %u Hz frequency", + sh_stream->lc3_frame_duration_us, sh_stream->lc3_freq_hz); + /* Create the decoder instance. This shall complete before stream_started() is called. */ + sh_stream->rx.lc3_decoder = + lc3_setup_decoder(sh_stream->lc3_frame_duration_us, sh_stream->lc3_freq_hz, + IS_ENABLED(CONFIG_USB_DEVICE_AUDIO) ? USB_SAMPLE_RATE : 0, + &sh_stream->rx.lc3_decoder_mem); + if (sh_stream->rx.lc3_decoder == NULL) { + shell_error(ctx_shell, "Failed to setup LC3 decoder - wrong parameters?\n"); + return -EINVAL; + } + + return 0; +} + +static bool decode_frame(struct lc3_data *data, size_t frame_cnt) +{ + const struct shell_stream *sh_stream = data->sh_stream; + const size_t total_frames = sh_stream->lc3_chan_cnt * sh_stream->lc3_frame_blocks_per_sdu; + const uint16_t octets_per_frame = sh_stream->lc3_octets_per_frame; + struct net_buf *buf = data->buf; + void *iso_data; + int err; + + if (data->do_plc) { + iso_data = NULL; /* perform PLC */ + + if ((sh_stream->rx.decoded_cnt % bap_stats_interval) == 0) { + shell_print(ctx_shell, "[%zu]: Performing PLC", sh_stream->rx.decoded_cnt); + } + + data->do_plc = false; /* clear flag */ + } else { + iso_data = net_buf_pull_mem(data->buf, octets_per_frame); + + if ((sh_stream->rx.decoded_cnt % bap_stats_interval) == 0) { + shell_print(ctx_shell, "[%zu]: Decoding frame of size %u (%u/%u)", + sh_stream->rx.decoded_cnt, octets_per_frame, frame_cnt + 1, + total_frames); + } + } + + err = lc3_decode(sh_stream->rx.lc3_decoder, iso_data, octets_per_frame, LC3_PCM_FORMAT_S16, + lc3_rx_buf, 1); + if (err < 0) { + shell_error(ctx_shell, "Failed to decode LC3 data (%u/%u - %u/%u)", frame_cnt + 1, + total_frames, octets_per_frame * frame_cnt, buf->len); + return false; + } + + return true; +} + +static size_t decode_frame_block(struct lc3_data *data, size_t frame_cnt) +{ + const struct shell_stream *sh_stream = data->sh_stream; + const uint8_t chan_cnt = sh_stream->lc3_chan_cnt; + size_t decoded_frames = 0U; + + for (uint8_t i = 0U; i < chan_cnt; i++) { + /* We provide the total number of decoded frames to `decode_frame` for logging + * purposes + */ + if (decode_frame(data, frame_cnt + decoded_frames)) { + decoded_frames++; + + if (IS_ENABLED(CONFIG_USB_DEVICE_AUDIO)) { + enum bt_audio_location chan_alloc; + int err; + + err = get_lc3_chan_alloc_from_index(sh_stream, i, &chan_alloc); + if (err != 0) { + /* Not suitable for USB */ + continue; + } + + /* We only want to left or right from one stream to USB */ + if ((chan_alloc == BT_AUDIO_LOCATION_FRONT_LEFT && + sh_stream != usb_left_stream) || + (chan_alloc == BT_AUDIO_LOCATION_FRONT_RIGHT && + sh_stream != usb_right_stream)) { + continue; + } + + err = bap_usb_add_frame_to_usb(chan_alloc, lc3_rx_buf, + sizeof(lc3_rx_buf), data->ts); + if (err == -EINVAL) { + continue; + } + } + } else { + /* If decoding failed, we clear the data to USB as it would contain + * invalid data + */ + if (IS_ENABLED(CONFIG_USB_DEVICE_AUDIO)) { + bap_usb_clear_frames_to_usb(); + } + + break; + } + } + + return decoded_frames; +} + +static void do_lc3_decode(struct lc3_data *data) +{ + struct shell_stream *sh_stream = data->sh_stream; + + if (sh_stream->is_rx && sh_stream->rx.lc3_decoder != NULL) { + const uint8_t frame_blocks_per_sdu = sh_stream->lc3_frame_blocks_per_sdu; + size_t frame_cnt; + + frame_cnt = 0; + for (uint8_t i = 0U; i < frame_blocks_per_sdu; i++) { + const size_t decoded_frames = decode_frame_block(data, frame_cnt); + + if (decoded_frames == 0) { + break; + } + + frame_cnt += decoded_frames; + } + + sh_stream->rx.decoded_cnt++; + } + + net_buf_unref(data->buf); +} + +static void lc3_decoder_thread_func(void *arg1, void *arg2, void *arg3) +{ + while (true) { + struct lc3_data *data = k_fifo_get(&lc3_in_fifo, K_FOREVER); + struct shell_stream *sh_stream = data->sh_stream; + + if (sh_stream->is_rx && sh_stream->rx.lc3_decoder == NULL) { + shell_warn(ctx_shell, "Decoder is NULL, discarding data from FIFO"); + k_mem_slab_free(&lc3_data_slab, (void *)data); + continue; /* Wait for new data */ + } + + do_lc3_decode(data); + + k_mem_slab_free(&lc3_data_slab, (void *)data); + } +} + +#endif /* CONFIG_LIBLC3*/ static void audio_recv(struct bt_bap_stream *stream, const struct bt_iso_recv_info *info, @@ -2336,43 +2663,91 @@ static void audio_recv(struct bt_bap_stream *stream, { struct shell_stream *sh_stream = shell_stream_from_bap_stream(stream); - sh_stream->rx_cnt++; + if (!sh_stream->is_rx) { + return; + } - if ((info->flags & BT_ISO_FLAGS_VALID) != 0) { - /* For valid ISO packets we check if they are invalid in other ways */ + sh_stream->rx.rx_cnt++; - if (info->ts == sh_stream->last_info.ts) { - sh_stream->dup_ts++; - } + if (info->ts == sh_stream->rx.last_info.ts) { + sh_stream->rx.dup_ts++; + } - if (info->seq_num == sh_stream->last_info.seq_num) { - sh_stream->dup_psn++; - } + if (info->seq_num == sh_stream->rx.last_info.seq_num) { + sh_stream->rx.dup_psn++; + } + if ((info->flags & BT_ISO_FLAGS_VALID) != 0) { if (buf->len == 0U) { - sh_stream->empty_sdu_pkts++; + sh_stream->rx.empty_sdu_pkts++; + } else { + sh_stream->rx.valid_sdu_pkts++; } } if (info->flags & BT_ISO_FLAGS_ERROR) { - sh_stream->err_pkts++; + sh_stream->rx.err_pkts++; } if (info->flags & BT_ISO_FLAGS_LOST) { - sh_stream->lost_pkts++; + sh_stream->rx.lost_pkts++; } - if ((sh_stream->rx_cnt % recv_stats_interval) == 0) { - shell_print( - ctx_shell, - "[%zu]: Incoming audio on stream %p len %u ts %u seq_num %u flags %u " - "(dup ts %zu; dup psn %zu, err_pkts %zu, lost_pkts %zu, empty SDUs %zu)", - sh_stream->rx_cnt, stream, buf->len, info->ts, info->seq_num, info->flags, - sh_stream->dup_ts, sh_stream->dup_psn, sh_stream->err_pkts, - sh_stream->lost_pkts, sh_stream->empty_sdu_pkts); + if ((sh_stream->rx.rx_cnt % bap_stats_interval) == 0) { + shell_print(ctx_shell, + "[%zu]: Incoming audio on stream %p len %u ts %u seq_num %u flags %u " + "(valid %zu, dup ts %zu, dup psn %zu, err_pkts %zu, lost_pkts %zu, " + "empty SDUs %zu)", + sh_stream->rx.rx_cnt, stream, buf->len, info->ts, info->seq_num, + info->flags, sh_stream->rx.valid_sdu_pkts, sh_stream->rx.dup_ts, + sh_stream->rx.dup_psn, sh_stream->rx.err_pkts, sh_stream->rx.lost_pkts, + sh_stream->rx.empty_sdu_pkts); } - (void)memcpy(&sh_stream->last_info, info, sizeof(sh_stream->last_info)); + (void)memcpy(&sh_stream->rx.last_info, info, sizeof(sh_stream->rx.last_info)); + +#if defined(CONFIG_LIBLC3) + if (sh_stream->rx.lc3_decoder != NULL) { + const uint8_t frame_blocks_per_sdu = sh_stream->lc3_frame_blocks_per_sdu; + const uint16_t octets_per_frame = sh_stream->lc3_octets_per_frame; + const uint8_t chan_cnt = sh_stream->lc3_chan_cnt; + struct lc3_data *data; + + /* Allocate a context that holds both the buffer and the stream so that we can + * send both of these values to the LC3 decoder thread as a single struct + * in a FIFO + */ + if (k_mem_slab_alloc(&lc3_data_slab, (void **)&data, K_NO_WAIT)) { + shell_warn(ctx_shell, "Could not allocate LC3 data item"); + + return; + } + + if ((info->flags & BT_ISO_FLAGS_VALID) == 0) { + data->do_plc = true; + } else if (buf->len != (octets_per_frame * chan_cnt * frame_blocks_per_sdu)) { + if (buf->len != 0U) { + shell_error( + ctx_shell, + "Expected %u frame blocks with %u channels of size %u, but " + "length is %u", + frame_blocks_per_sdu, chan_cnt, octets_per_frame, buf->len); + } + + data->do_plc = true; + } + + data->buf = net_buf_ref(buf); + data->sh_stream = sh_stream; + if (info->flags & BT_ISO_FLAGS_TS) { + data->ts = info->ts; + } else { + data->ts = 0U; + } + + k_fifo_put(&lc3_in_fifo, data); + } +#endif /* CONFIG_LIBLC3 */ } #endif /* CONFIG_BT_AUDIO_RX */ @@ -2418,66 +2793,31 @@ static void stream_enabled_cb(struct bt_bap_stream *stream) static void stream_started_cb(struct bt_bap_stream *bap_stream) { struct shell_stream *sh_stream = shell_stream_from_bap_stream(bap_stream); - -#if defined(CONFIG_BT_AUDIO_TX) - sh_stream->connected_at_ticks = k_uptime_ticks(); -#if defined(CONFIG_LIBLC3) - atomic_set(&sh_stream->lc3_enqueue_cnt, PRIME_COUNT); - sh_stream->lc3_sdu_cnt = 0U; -#endif /* CONFIG_LIBLC3 */ -#endif /* CONFIG_BT_AUDIO_TX */ + struct bt_bap_ep_info info = {0}; + int ret; printk("Stream %p started\n", bap_stream); -#if defined(CONFIG_BT_AUDIO_RX) - sh_stream->empty_sdu_pkts = 0U; - sh_stream->lost_pkts = 0U; - sh_stream->err_pkts = 0U; - sh_stream->dup_psn = 0U; - sh_stream->rx_cnt = 0U; - sh_stream->dup_ts = 0U; -#endif -} - -static void stream_stopped_cb(struct bt_bap_stream *stream, uint8_t reason) -{ - printk("Stream %p stopped with reason 0x%02X\n", stream, reason); - -#if defined(CONFIG_LIBLC3) && defined(CONFIG_BT_AUDIO_TX) - clear_lc3_sine_data(stream); -#endif /* CONFIG_LIBLC3 && CONFIG_BT_AUDIO_TX*/ + ret = bt_bap_ep_get_info(bap_stream->ep, &info); + if (ret != 0) { + shell_error(ctx_shell, "Failed to get EP info: %d", ret); + return; + } -#if defined(CONFIG_BT_BAP_BROADCAST_SINK) - struct shell_stream *sh_stream = shell_stream_from_bap_stream(stream); + sh_stream->is_rx = info.can_recv; + sh_stream->is_tx = info.can_send; - if (IS_ARRAY_ELEMENT(broadcast_sink_streams, sh_stream)) { - if (default_broadcast_sink.stream_cnt != 0) { - default_broadcast_sink.stream_cnt--; - } +#if defined(CONFIG_LIBLC3) + const struct bt_audio_codec_cfg *codec_cfg = bap_stream->codec_cfg; - if (default_broadcast_sink.stream_cnt == 0) { - /* All streams in the broadcast sink has been terminated */ - default_broadcast_sink.syncable = true; - memset(&default_broadcast_sink.received_base, 0, - sizeof(default_broadcast_sink.received_base)); - default_broadcast_sink.broadcast_id = 0; - default_broadcast_sink.syncable = false; + if (codec_cfg->id == BT_HCI_CODING_FORMAT_LC3) { + if (sh_stream->is_tx) { + atomic_set(&sh_stream->tx.lc3_enqueue_cnt, PRIME_COUNT); + sh_stream->tx.lc3_sdu_cnt = 0U; } - } -#endif /* CONFIG_BT_BAP_BROADCAST_SINK */ -} -#if defined(CONFIG_BT_BAP_UNICAST) -static void stream_configured_cb(struct bt_bap_stream *stream, - const struct bt_audio_codec_qos_pref *pref) -{ -#if defined(CONFIG_LIBLC3) - if (stream->codec_cfg->id == BT_HCI_CODING_FORMAT_LC3) { - struct shell_stream *sh_stream = shell_stream_from_bap_stream(stream); - int ret; - - ret = bt_audio_codec_cfg_get_freq(stream->codec_cfg); - if (ret > 0) { + ret = bt_audio_codec_cfg_get_freq(codec_cfg); + if (ret >= 0) { ret = bt_audio_codec_cfg_freq_to_freq_hz(ret); if (ret > 0) { @@ -2498,8 +2838,8 @@ static void stream_configured_cb(struct bt_bap_stream *stream, sh_stream->lc3_freq_hz = 0U; } - ret = bt_audio_codec_cfg_get_frame_dur(stream->codec_cfg); - if (ret > 0) { + ret = bt_audio_codec_cfg_get_frame_dur(codec_cfg); + if (ret >= 0) { ret = bt_audio_codec_cfg_frame_dur_to_frame_dur_us(ret); if (ret > 0) { sh_stream->lc3_frame_duration_us = (uint32_t)ret; @@ -2512,29 +2852,213 @@ static void stream_configured_cb(struct bt_bap_stream *stream, sh_stream->lc3_frame_duration_us = 0U; } - ret = bt_audio_codec_cfg_get_frame_blocks_per_sdu(stream->codec_cfg, true); - if (ret > 0) { - sh_stream->lc3_frames_per_sdu = (uint8_t)ret; + ret = bt_audio_codec_cfg_get_chan_allocation(codec_cfg, + &sh_stream->lc3_chan_allocation); + if (ret == 0) { + sh_stream->lc3_chan_cnt = get_chan_cnt(sh_stream->lc3_chan_allocation); + } else { + shell_error(ctx_shell, "Could not get channel allocation: %d", ret); + sh_stream->lc3_chan_allocation = BT_AUDIO_LOCATION_MONO_AUDIO; + sh_stream->lc3_chan_cnt = 1U; + } + + ret = bt_audio_codec_cfg_get_frame_blocks_per_sdu(codec_cfg, true); + if (ret >= 0) { + sh_stream->lc3_frame_blocks_per_sdu = (uint8_t)ret; } else { shell_error(ctx_shell, "Could not get frame blocks per SDU: %d", ret); - sh_stream->lc3_frames_per_sdu = 0U; + sh_stream->lc3_frame_blocks_per_sdu = 0U; } - ret = bt_audio_codec_cfg_get_octets_per_frame(stream->codec_cfg); - if (ret > 0) { + ret = bt_audio_codec_cfg_get_octets_per_frame(codec_cfg); + if (ret >= 0) { sh_stream->lc3_octets_per_frame = (uint16_t)ret; } else { shell_error(ctx_shell, "Could not get octets per frame: %d", ret); sh_stream->lc3_octets_per_frame = 0U; } + +#if defined(CONFIG_BT_AUDIO_TX) + if (sh_stream->is_tx && sh_stream->tx.lc3_encoder == NULL) { + const int err = init_lc3_encoder(sh_stream); + + if (err != 0) { + shell_error(ctx_shell, "Failed to init LC3 encoder: %d", err); + + return; + } + + if (IS_ENABLED(CONFIG_USB_DEVICE_AUDIO)) { + /* Always mark as active when using USB */ + sh_stream->tx.active = true; + } + } +#endif /* CONFIG_BT_AUDIO_TX */ + +#if defined(CONFIG_BT_AUDIO_RX) + if (sh_stream->is_rx) { + if (sh_stream->rx.lc3_decoder == NULL) { + const int err = init_lc3_decoder(sh_stream); + + if (err != 0) { + shell_error(ctx_shell, "Failed to init LC3 decoder: %d", + err); + + return; + } + } + + sh_stream->rx.decoded_cnt = 0U; + + if (IS_ENABLED(CONFIG_USB_DEVICE_AUDIO)) { + if ((sh_stream->lc3_chan_allocation & + BT_AUDIO_LOCATION_FRONT_LEFT) != 0) { + if (usb_left_stream == NULL) { + shell_info(ctx_shell, + "Setting USB left stream to %p", + sh_stream); + usb_left_stream = sh_stream; + } else { + shell_warn(ctx_shell, + "Multiple left streams started"); + } + } + + if ((sh_stream->lc3_chan_allocation & + BT_AUDIO_LOCATION_FRONT_RIGHT) != 0) { + if (usb_right_stream == NULL) { + shell_info(ctx_shell, + "Setting USB right stream to %p", + sh_stream); + usb_right_stream = sh_stream; + } else { + shell_warn(ctx_shell, + "Multiple right streams started"); + } + } + } + } +#endif /* CONFIG_BT_AUDIO_RX */ } #endif /* CONFIG_LIBLC3 */ +#if defined(CONFIG_BT_AUDIO_TX) + if (sh_stream->is_tx) { + sh_stream->tx.connected_at_ticks = k_uptime_ticks(); + } +#endif /* CONFIG_BT_AUDIO_TX */ + +#if defined(CONFIG_BT_AUDIO_RX) + if (sh_stream->is_rx) { + sh_stream->rx.empty_sdu_pkts = 0U; + sh_stream->rx.valid_sdu_pkts = 0U; + sh_stream->rx.lost_pkts = 0U; + sh_stream->rx.err_pkts = 0U; + sh_stream->rx.dup_psn = 0U; + sh_stream->rx.rx_cnt = 0U; + sh_stream->rx.dup_ts = 0U; + + rx_streaming_cnt++; + } +#endif +} + +#if defined(CONFIG_LIBLC3) +static void update_usb_streams_cb(struct shell_stream *sh_stream, void *user_data) +{ + if (sh_stream->is_rx) { + if (usb_left_stream == NULL && + (sh_stream->lc3_chan_allocation & BT_AUDIO_LOCATION_FRONT_LEFT) != 0) { + shell_info(ctx_shell, "Setting new USB left stream to %p", sh_stream); + usb_left_stream = sh_stream; + } + + if (usb_right_stream == NULL && + (sh_stream->lc3_chan_allocation & BT_AUDIO_LOCATION_FRONT_RIGHT) != 0) { + shell_info(ctx_shell, "Setting new USB right stream to %p", sh_stream); + usb_right_stream = sh_stream; + } + } +} + +static void update_usb_streams(struct shell_stream *sh_stream) +{ + if (sh_stream->is_rx) { + if (sh_stream == usb_left_stream) { + shell_info(ctx_shell, "Clearing USB left stream (%p)", usb_left_stream); + usb_left_stream = NULL; + } + + if (sh_stream == usb_right_stream) { + shell_info(ctx_shell, "Clearing USB right stream (%p)", usb_right_stream); + usb_right_stream = NULL; + } + + bap_foreach_stream(update_usb_streams_cb, NULL); + } +} +#endif /* CONFIG_LIBLC3 */ + +static void clear_stream_data(struct shell_stream *sh_stream) +{ +#if defined(CONFIG_BT_BAP_BROADCAST_SINK) + if (IS_ARRAY_ELEMENT(broadcast_sink_streams, sh_stream)) { + if (default_broadcast_sink.stream_cnt != 0) { + default_broadcast_sink.stream_cnt--; + } + + if (default_broadcast_sink.stream_cnt == 0) { + /* All streams in the broadcast sink has been terminated */ + memset(&default_broadcast_sink.received_base, 0, + sizeof(default_broadcast_sink.received_base)); + default_broadcast_sink.broadcast_id = 0; + default_broadcast_sink.syncable = false; + } + } +#endif /* CONFIG_BT_BAP_BROADCAST_SINK */ + +#if defined(CONFIG_BT_AUDIO_RX) + if (sh_stream->is_rx) { + rx_streaming_cnt--; + memset(&sh_stream->rx, 0, sizeof(sh_stream->rx)); + } +#endif + +#if defined(CONFIG_BT_AUDIO_TX) + if (sh_stream->is_tx) { + memset(&sh_stream->tx, 0, sizeof(sh_stream->tx)); + } +#endif + + sh_stream->is_rx = sh_stream->is_tx = false; + +#if defined(CONFIG_LIBLC3) + if (IS_ENABLED(CONFIG_USB_DEVICE_AUDIO)) { + update_usb_streams(sh_stream); + } +#endif /* CONFIG_LIBLC3 */ +} + +static void stream_stopped_cb(struct bt_bap_stream *stream, uint8_t reason) +{ + struct shell_stream *sh_stream = shell_stream_from_bap_stream(stream); + + printk("Stream %p stopped with reason 0x%02X\n", stream, reason); + + clear_stream_data(sh_stream); +} + +#if defined(CONFIG_BT_BAP_UNICAST) +static void stream_configured_cb(struct bt_bap_stream *stream, + const struct bt_audio_codec_qos_pref *pref) +{ shell_print(ctx_shell, "Stream %p configured\n", stream); } static void stream_released_cb(struct bt_bap_stream *stream) { + struct shell_stream *sh_stream = shell_stream_from_bap_stream(stream); + shell_print(ctx_shell, "Stream %p released\n", stream); #if defined(CONFIG_BT_BAP_UNICAST_CLIENT) @@ -2574,10 +3098,7 @@ static void stream_released_cb(struct bt_bap_stream *stream) } #endif /* CONFIG_BT_BAP_UNICAST_CLIENT */ -#if defined(CONFIG_LIBLC3) && defined(CONFIG_BT_AUDIO_TX) - /* stop sending */ - clear_lc3_sine_data(stream); -#endif /* CONFIG_LIBLC3 && defined(CONFIG_BT_AUDIO_TX) */ + clear_stream_data(sh_stream); } #endif /* CONFIG_BT_BAP_UNICAST */ @@ -2822,6 +3343,7 @@ static int cmd_create_broadcast_sink(const struct shell *sh, size_t argc, char * auto_scan.broadcast_sink = &default_broadcast_sink; auto_scan.broadcast_id = broadcast_id; + auto_scan.out_sync = &per_adv_syncs[selected_per_adv_sync]; } else { shell_print(sh, "Creating broadcast sink with broadcast ID 0x%06X", (uint32_t)broadcast_id); @@ -3153,12 +3675,44 @@ static int cmd_init(const struct shell *sh, size_t argc, char *argv[]) } #endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */ +#if defined(CONFIG_LIBLC3) +#if defined(CONFIG_BT_AUDIO_RX) + static K_KERNEL_STACK_DEFINE(lc3_decoder_thread_stack, 4096); + const int lc3_decoder_thread_prio = K_PRIO_PREEMPT(5); + static struct k_thread lc3_decoder_thread; + + k_thread_create(&lc3_decoder_thread, lc3_decoder_thread_stack, + K_KERNEL_STACK_SIZEOF(lc3_decoder_thread_stack), lc3_decoder_thread_func, + NULL, NULL, NULL, lc3_decoder_thread_prio, 0, K_NO_WAIT); + k_thread_name_set(&lc3_decoder_thread, "LC3 Decoder"); +#endif /* CONFIG_BT_AUDIO_RX */ + +#if defined(CONFIG_BT_AUDIO_TX) + static K_KERNEL_STACK_DEFINE(lc3_encoder_thread_stack, 4096); + const int lc3_encoder_thread_prio = K_PRIO_PREEMPT(5); + static struct k_thread lc3_encoder_thread; + + k_thread_create(&lc3_encoder_thread, lc3_encoder_thread_stack, + K_KERNEL_STACK_SIZEOF(lc3_encoder_thread_stack), lc3_encoder_thread_func, + NULL, NULL, NULL, lc3_encoder_thread_prio, 0, K_NO_WAIT); + k_thread_name_set(&lc3_encoder_thread, "LC3 Encoder"); + +#endif /* CONFIG_BT_AUDIO_TX */ + + if (IS_ENABLED(CONFIG_USB_DEVICE_AUDIO) && + (IS_ENABLED(CONFIG_BT_AUDIO_RX) || IS_ENABLED(CONFIG_BT_AUDIO_TX))) { + err = bap_usb_init(); + __ASSERT(err == 0, "Failed to enable USB: %d", err); + } +#endif /* CONFIG_LIBLC3 */ + initialized = true; return 0; } #if defined(CONFIG_BT_AUDIO_TX) + #define DATA_MTU CONFIG_BT_ISO_TX_MTU NET_BUF_POOL_FIXED_DEFINE(tx_pool, 1, DATA_MTU, CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); @@ -3212,60 +3766,31 @@ static int cmd_send(const struct shell *sh, size_t argc, char *argv[]) return 0; } -#if defined(CONFIG_LIBLC3) -static bool stream_start_sine_verify(const struct shell_stream *sh_stream) +#if GENERATE_SINE_SUPPORTED +static void start_sine_stream_cb(struct shell_stream *sh_stream, void *user_data) { - const struct bt_bap_stream *bap_stream; - struct bt_bap_ep_info info; - int err; - - if (sh_stream == NULL) { - return false; - } - - bap_stream = &sh_stream->stream.bap_stream; - - if (bap_stream->qos == NULL) { - return false; - } - - err = bt_bap_ep_get_info(bap_stream->ep, &info); - if (err != 0) { - return false; - } - - if (info.state != BT_BAP_EP_STATE_STREAMING) { - return false; - } + if (sh_stream->is_tx) { + struct bt_bap_stream *bap_stream = bap_stream_from_shell_stream(sh_stream); + const struct shell *sh = user_data; + int err; - if (sh_stream->lc3_freq_hz != lc3_encoder_freq_hz || - sh_stream->lc3_frame_duration_us != lc3_encoder_frame_duration_us) { - return false; - } + err = init_lc3_encoder(sh_stream); + if (err != 0) { + shell_error(sh, "Failed to init LC3 %d for stream %p", err, bap_stream); - return true; -} -static int stream_start_sine(struct shell_stream *sh_stream) -{ - int err; + return; + } - k_work_init_delayable(&sh_stream->audio_send_work, lc3_audio_send_data); + sh_stream->tx.active = true; + sh_stream->tx.seq_num = get_next_seq_num(bap_stream_from_shell_stream(sh_stream)); - err = k_work_schedule(&sh_stream->audio_send_work, K_NO_WAIT); - if (err < 0) { - return -ENOEXEC; + shell_print(sh, "Started transmitting sine on stream %p", bap_stream); } - - sh_stream->tx_active = true; - sh_stream->seq_num = get_next_seq_num(bap_stream_from_shell_stream(sh_stream)); - - return 0; } static int cmd_start_sine(const struct shell *sh, size_t argc, char *argv[]) { bool start_all = false; - int err; if (argc > 1) { if (strcmp(argv[1], "all") == 0) { @@ -3278,91 +3803,26 @@ static int cmd_start_sine(const struct shell *sh, size_t argc, char *argv[]) } if (start_all) { - bool lc3_initialized = false; - - for (size_t i = 0U; i < ARRAY_SIZE(unicast_streams); i++) { - struct shell_stream *sh_stream = &unicast_streams[i]; - struct bt_bap_stream *bap_stream = bap_stream_from_shell_stream(sh_stream); - - if (!lc3_initialized) { - err = init_lc3_encoder(sh_stream); - if (err != 0) { - shell_error(sh, "Failed to init LC3 %d", err); - - return -ENOEXEC; - } - - lc3_initialized = true; - } - - if (!stream_start_sine_verify(sh_stream)) { - continue; - } - - err = stream_start_sine(sh_stream); - if (err != 0) { - shell_error(sh, "Failed to start TX for stream %p: %d", bap_stream, - err); - return err; - } - - shell_print(sh, "Started transmitting on unicast stream %p", bap_stream); - } - - for (size_t i = 0U; i < ARRAY_SIZE(broadcast_source_streams); i++) { - struct shell_stream *sh_stream = &broadcast_source_streams[i]; - struct bt_bap_stream *bap_stream = bap_stream_from_shell_stream(sh_stream); - - if (!lc3_initialized) { - err = init_lc3_encoder(sh_stream); - if (err != 0) { - shell_error(sh, "Failed to init LC3 %d", err); - - return -ENOEXEC; - } - - lc3_initialized = true; - } - - if (!stream_start_sine_verify(sh_stream)) { - continue; - } - - err = stream_start_sine(sh_stream); - if (err != 0) { - shell_error(sh, "Failed to start TX for stream %p: %d", bap_stream, - err); - return err; - } - - shell_print(sh, "Started transmitting on broadcast stream %p", bap_stream); - } + bap_foreach_stream(start_sine_stream_cb, (void *)sh); } else { struct shell_stream *sh_stream = shell_stream_from_bap_stream(default_stream); - err = init_lc3_encoder(sh_stream); - if (err != 0) { - shell_error(sh, "Failed to init LC3 %d", err); + start_sine_stream_cb(sh_stream, (void *)sh); + } - return -ENOEXEC; - } + return 0; +} - if (!stream_start_sine_verify(sh_stream)) { - shell_error(sh, "Invalid stream %p", default_stream); - return -ENOEXEC; - } +static void stop_sine_stream_cb(struct shell_stream *sh_stream, void *user_data) +{ + if (sh_stream->is_tx) { + struct bt_bap_stream *bap_stream = bap_stream_from_shell_stream(sh_stream); + const struct shell *sh = user_data; - err = stream_start_sine(sh_stream); - if (err != 0) { - shell_error(sh, "Failed to start TX for stream %p: %d", default_stream, - err); - return err; - } + shell_print(sh, "Stopped transmitting on stream %p", bap_stream); - shell_print(sh, "Started transmitting on default_stream %p", default_stream); + sh_stream->tx.active = false; } - - return 0; } static int cmd_stop_sine(const struct shell *sh, size_t argc, char *argv[]) @@ -3380,43 +3840,22 @@ static int cmd_stop_sine(const struct shell *sh, size_t argc, char *argv[]) } if (stop_all) { - for (size_t i = 0U; i < ARRAY_SIZE(unicast_streams); i++) { - struct bt_bap_stream *bap_stream = - bap_stream_from_shell_stream(&unicast_streams[i]); - - if (unicast_streams[i].tx_active) { - clear_lc3_sine_data(bap_stream); - shell_print(sh, "Stopped transmitting on stream %p", bap_stream); - } - } - - for (size_t i = 0U; i < ARRAY_SIZE(broadcast_source_streams); i++) { - struct bt_bap_stream *bap_stream = - bap_stream_from_shell_stream(&broadcast_source_streams[i]); - if (unicast_streams[i].tx_active) { - clear_lc3_sine_data(bap_stream); - shell_print(sh, "Stopped transmitting on stream %p", bap_stream); - } - } + bap_foreach_stream(stop_sine_stream_cb, (void *)sh); } else { struct shell_stream *sh_stream = shell_stream_from_bap_stream(default_stream); - if (sh_stream->tx_active) { - clear_lc3_sine_data(default_stream); - shell_print(sh, "Stopped transmitting on stream %p", default_stream); - } + stop_sine_stream_cb(sh_stream, (void *)sh); } return 0; } -#endif /* CONFIG_LIBLC3 */ +#endif /* GENERATE_SINE_SUPPORTED */ #endif /* CONFIG_BT_AUDIO_TX */ -#if defined(CONFIG_BT_AUDIO_RX) -static int cmd_recv_stats(const struct shell *sh, size_t argc, char *argv[]) +static int cmd_bap_stats(const struct shell *sh, size_t argc, char *argv[]) { if (argc == 1) { - shell_info(sh, "Current receive stats interval: %lu", recv_stats_interval); + shell_info(sh, "Current stats interval: %lu", bap_stats_interval); } else { int err = 0; unsigned long interval; @@ -3434,12 +3873,11 @@ static int cmd_recv_stats(const struct shell *sh, size_t argc, char *argv[]) return -ENOEXEC; } - recv_stats_interval = interval; + bap_stats_interval = interval; } return 0; } -#endif /* CONFIG_BT_AUDIO_RX */ #if defined(CONFIG_BT_BAP_UNICAST_SERVER) static void print_ase_info(struct bt_bap_ep *ep, void *user_data) @@ -3532,18 +3970,16 @@ SHELL_STATIC_SUBCMD_SET_CREATE( #endif /* IS_BAP_INITIATOR */ #if defined(CONFIG_BT_AUDIO_TX) SHELL_CMD_ARG(send, NULL, "Send to Audio Stream [data]", cmd_send, 1, 1), -#if defined(CONFIG_LIBLC3) +#if GENERATE_SINE_SUPPORTED SHELL_CMD_ARG(start_sine, NULL, "Start sending a LC3 encoded sine wave [all]", cmd_start_sine, 1, 1), SHELL_CMD_ARG(stop_sine, NULL, "Stop sending a LC3 encoded sine wave [all]", cmd_stop_sine, 1, 1), -#endif /* CONFIG_LIBLC3 */ +#endif /* GENERATE_SINE_SUPPORTED */ #endif /* CONFIG_BT_AUDIO_TX */ -#if defined(CONFIG_BT_AUDIO_RX) - SHELL_CMD_ARG(recv_stats, NULL, - "Sets or gets the receive statistics reporting interval in # of packets", - cmd_recv_stats, 1, 1), -#endif /* CONFIG_BT_AUDIO_RX */ + SHELL_CMD_ARG(bap_stats, NULL, + "Sets or gets the statistics reporting interval in # of packets", + cmd_bap_stats, 1, 1), SHELL_COND_CMD_ARG(CONFIG_BT_PACS, set_location, NULL, " ", cmd_set_loc, 3, 0), SHELL_COND_CMD_ARG(CONFIG_BT_PACS, set_context, NULL, @@ -3604,6 +4040,11 @@ static ssize_t connectable_ad_data_add(struct bt_data *data_array, ad_len++; } + if (IS_ENABLED(CONFIG_BT_BAP_SCAN_DELEGATOR)) { + ad_len += bap_scan_delegator_ad_data_add(&data_array[ad_len], + data_array_size - ad_len); + } + if (IS_ENABLED(CONFIG_BT_CAP_ACCEPTOR)) { ad_len += cap_acceptor_ad_data_add(&data_array[ad_len], data_array_size - ad_len, true); diff --git a/subsys/bluetooth/audio/shell/bap_broadcast_assistant.c b/subsys/bluetooth/audio/shell/bap_broadcast_assistant.c index fe28cdbb853..6f210a4ae5e 100644 --- a/subsys/bluetooth/audio/shell/bap_broadcast_assistant.c +++ b/subsys/bluetooth/audio/shell/bap_broadcast_assistant.c @@ -215,16 +215,9 @@ static void bap_broadcast_assistant_recv_state_cb( } } -static void bap_broadcast_assistant_recv_state_removed_cb(struct bt_conn *conn, - int err, - uint8_t src_id) +static void bap_broadcast_assistant_recv_state_removed_cb(struct bt_conn *conn, uint8_t src_id) { - if (err != 0) { - shell_error(ctx_shell, "BASS recv state removed failed (%d)", - err); - } else { - shell_print(ctx_shell, "BASS recv state %u removed", src_id); - } + shell_print(ctx_shell, "BASS recv state %u removed", src_id); } static void bap_broadcast_assistant_scan_start_cb(struct bt_conn *conn, int err) @@ -810,6 +803,7 @@ static inline bool add_pa_sync_base_subgroup_cb(const struct bt_bap_base_subgrou ret = bt_bap_base_subgroup_foreach_bis(subgroup, add_pa_sync_base_subgroup_bis_cb, subgroup_param); + if (ret < 0) { return false; } @@ -829,6 +823,7 @@ static int cmd_bap_broadcast_assistant_add_pa_sync(const struct shell *sh, struct bt_le_per_adv_sync_info pa_info; unsigned long broadcast_id; uint32_t bis_bitfield_req; + uint32_t subgroups_bis_sync; int err; if (pa_sync == NULL) { @@ -848,6 +843,8 @@ static int cmd_bap_broadcast_assistant_add_pa_sync(const struct shell *sh, param.adv_sid = pa_info.sid; param.pa_interval = pa_info.interval; + memset(&subgroup_params, 0, sizeof(subgroup_params)); + param.pa_sync = shell_strtobool(argv[1], 0, &err); if (err != 0) { shell_error(sh, "Could not parse pa_sync: %d", err); @@ -870,6 +867,7 @@ static int cmd_bap_broadcast_assistant_add_pa_sync(const struct shell *sh, param.broadcast_id = broadcast_id; bis_bitfield_req = 0U; + subgroups_bis_sync = 0U; for (size_t i = 3U; i < argc; i++) { const unsigned long index = shell_strtoul(argv[i], 16, &err); @@ -900,6 +898,27 @@ static int cmd_bap_broadcast_assistant_add_pa_sync(const struct shell *sh, } } + /* use the BASE to verify the BIS indexes set by command */ + for (size_t j = 0U; j < param.num_subgroups; j++) { + if (bis_bitfield_req == 0) { + /* Request a PA sync without BIS sync */ + subgroup_params[j].bis_sync = 0; + } else { + subgroups_bis_sync |= subgroup_params[j].bis_sync; + /* only set the BIS index field as optional parameters */ + /* not to whatever is in the BASE */ + subgroup_params[j].bis_sync &= bis_bitfield_req; + } + } + + if ((subgroups_bis_sync & bis_bitfield_req) != bis_bitfield_req) { + /* bis_sync of all subgroups should contain at least all the bits in request */ + /* Otherwise Command will be rejected */ + shell_error(ctx_shell, "Cannot set BIS index 0x%06X when BASE subgroups only " + "supports %d", bis_bitfield_req, subgroups_bis_sync); + return -ENOEXEC; + } + err = bt_bap_broadcast_assistant_add_src(default_conn, ¶m); if (err != 0) { shell_print(sh, "Fail: %d", err); diff --git a/subsys/bluetooth/audio/shell/bap_scan_delegator.c b/subsys/bluetooth/audio/shell/bap_scan_delegator.c index a2067301c8d..9c0789eabb1 100644 --- a/subsys/bluetooth/audio/shell/bap_scan_delegator.c +++ b/subsys/bluetooth/audio/shell/bap_scan_delegator.c @@ -36,6 +36,20 @@ struct sync_state { static bool past_preference = true; +size_t bap_scan_delegator_ad_data_add(struct bt_data data[], size_t data_size) +{ + static uint8_t ad_bap_scan_delegator[2] = { + BT_UUID_16_ENCODE(BT_UUID_BASS_VAL), + }; + + __ASSERT(data_size > 0, "No space for ad_bap_scan_delegator"); + data[0].type = BT_DATA_SVC_DATA16; + data[0].data_len = ARRAY_SIZE(ad_bap_scan_delegator); + data[0].data = &ad_bap_scan_delegator[0]; + + return 1U; +} + static struct sync_state *sync_state_get(const struct bt_bap_scan_delegator_recv_state *recv_state) { for (size_t i = 0U; i < ARRAY_SIZE(sync_states); i++) { diff --git a/subsys/bluetooth/audio/shell/bap_usb.c b/subsys/bluetooth/audio/shell/bap_usb.c new file mode 100644 index 00000000000..30afd5ae093 --- /dev/null +++ b/subsys/bluetooth/audio/shell/bap_usb.c @@ -0,0 +1,552 @@ +/** + * @file + * @brief Bluetooth Basic Audio Profile shell USB extension + * + * This files handles all the USB related functionality to audio in/out for the BAP shell + * + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_SOC_NRF5340_CPUAPP) +#include +#endif /* CONFIG_SOC_NRF5340_CPUAPP */ + +#include "shell/bt.h" +#include "audio.h" + +LOG_MODULE_REGISTER(bap_usb, CONFIG_BT_BAP_STREAM_LOG_LEVEL); + +#define USB_ENQUEUE_COUNT 30U /* 30ms */ +#define USB_FRAME_DURATION_US 1000U +#define USB_SAMPLE_CNT ((USB_FRAME_DURATION_US * USB_SAMPLE_RATE) / USEC_PER_SEC) +#define USB_BYTES_PER_SAMPLE sizeof(int16_t) +#define USB_MONO_FRAME_SIZE (USB_SAMPLE_CNT * USB_BYTES_PER_SAMPLE) +#define USB_CHANNELS 2U +#define USB_STEREO_FRAME_SIZE (USB_MONO_FRAME_SIZE * USB_CHANNELS) +#define USB_OUT_RING_BUF_SIZE (CONFIG_BT_ISO_RX_BUF_COUNT * LC3_MAX_NUM_SAMPLES_STEREO) +#define USB_IN_RING_BUF_SIZE (USB_MONO_FRAME_SIZE * USB_ENQUEUE_COUNT) + +#if defined CONFIG_BT_AUDIO_RX +struct decoded_sdu { + int16_t right_frames[MAX_CODEC_FRAMES_PER_SDU][LC3_MAX_NUM_SAMPLES_MONO]; + int16_t left_frames[MAX_CODEC_FRAMES_PER_SDU][LC3_MAX_NUM_SAMPLES_MONO]; + size_t right_frames_cnt; + size_t left_frames_cnt; + size_t mono_frames_cnt; + uint32_t ts; +} decoded_sdu; + +RING_BUF_DECLARE(usb_out_ring_buf, USB_OUT_RING_BUF_SIZE); +NET_BUF_POOL_DEFINE(usb_out_buf_pool, USB_ENQUEUE_COUNT, USB_STEREO_FRAME_SIZE, 0, net_buf_destroy); + +/* USB consumer callback, called every 1ms, consumes data from ring-buffer */ +static void usb_data_request_cb(const struct device *dev) +{ + uint8_t usb_audio_data[USB_STEREO_FRAME_SIZE] = {0}; + struct net_buf *pcm_buf; + uint32_t size; + int err; + + if (bap_get_rx_streaming_cnt() == 0) { + /* no-op as we have no streams that receive data */ + return; + } + + pcm_buf = net_buf_alloc(&usb_out_buf_pool, K_NO_WAIT); + if (pcm_buf == NULL) { + LOG_WRN("Could not allocate pcm_buf"); + return; + } + + /* This may fail without causing issues since usb_audio_data is 0-initialized */ + size = ring_buf_get(&usb_out_ring_buf, usb_audio_data, sizeof(usb_audio_data)); + + net_buf_add_mem(pcm_buf, usb_audio_data, sizeof(usb_audio_data)); + + if (size != 0) { + static size_t cnt; + + if ((++cnt % bap_get_stats_interval()) == 0U) { + LOG_INF("[%zu]: Sending USB audio", cnt); + } + } else { + static size_t cnt; + + if ((++cnt % bap_get_stats_interval()) == 0U) { + LOG_INF("[%zu]: Sending empty USB audio", cnt); + } + } + + err = usb_audio_send(dev, pcm_buf, sizeof(usb_audio_data)); + if (err != 0) { + static size_t cnt; + + cnt++; + if ((cnt % 1000) == 0) { + LOG_ERR("Failed to send USB audio: %d (%zu)", err, cnt); + } + + net_buf_unref(pcm_buf); + } +} + +static void usb_data_written_cb(const struct device *dev, struct net_buf *buf, size_t size) +{ + /* Unreference the buffer now that the USB is done with it */ + net_buf_unref(buf); +} + +static void bap_usb_send_frames_to_usb(void) +{ + const bool is_left_only = + decoded_sdu.right_frames_cnt == 0U && decoded_sdu.mono_frames_cnt == 0U; + const bool is_right_only = + decoded_sdu.left_frames_cnt == 0U && decoded_sdu.mono_frames_cnt == 0U; + const bool is_mono_only = + decoded_sdu.left_frames_cnt == 0U && decoded_sdu.right_frames_cnt == 0U; + const bool is_single_channel = is_left_only || is_right_only || is_mono_only; + const size_t frame_cnt = + MAX(decoded_sdu.mono_frames_cnt, + MAX(decoded_sdu.left_frames_cnt, decoded_sdu.right_frames_cnt)); + static size_t cnt; + + /* Send frames to USB - If we only have a single channel we mix it to stereo */ + for (size_t i = 0U; i < frame_cnt; i++) { + static int16_t stereo_frame[LC3_MAX_NUM_SAMPLES_STEREO]; + const int16_t *right_frame = decoded_sdu.right_frames[i]; + const int16_t *left_frame = decoded_sdu.left_frames[i]; + const int16_t *mono_frame = decoded_sdu.left_frames[i]; /* use left as mono */ + static size_t fail_cnt; + uint32_t rb_size; + + /* Not enough space to store data */ + if (ring_buf_space_get(&usb_out_ring_buf) < sizeof(stereo_frame)) { + if ((fail_cnt % bap_get_stats_interval()) == 0U) { + LOG_WRN("[%zu] Could not send more than %zu frames to USB", + fail_cnt, i); + } + + fail_cnt++; + + break; + } + + fail_cnt = 0U; + + /* Generate the stereo frame + * + * If we only have single channel then we mix that to stereo + */ + for (int j = 0; j < LC3_MAX_NUM_SAMPLES_MONO; j++) { + if (is_single_channel) { + int16_t sample = 0; + + /* Mix to stereo as LRLRLRLR */ + if (is_left_only) { + sample = left_frame[j]; + } else if (is_right_only) { + sample = right_frame[j]; + } else if (is_mono_only) { + sample = mono_frame[j]; + } + + stereo_frame[j * 2] = sample; + stereo_frame[j * 2 + 1] = sample; + } else { + stereo_frame[j * 2] = left_frame[j]; + stereo_frame[j * 2 + 1] = right_frame[j]; + } + } + + rb_size = ring_buf_put(&usb_out_ring_buf, (uint8_t *)stereo_frame, + sizeof(stereo_frame)); + if (rb_size != sizeof(stereo_frame)) { + LOG_WRN("Failed to put frame on USB ring buf"); + + break; + } + } + + if ((++cnt % bap_get_stats_interval()) == 0U) { + LOG_INF("[%zu]: Sending %u USB audio frame", cnt, frame_cnt); + } + + bap_usb_clear_frames_to_usb(); +} + +static bool ts_overflowed(uint32_t ts) +{ + /* If the timestamp is a factor of 10 in difference, then we assume that TS overflowed + * We cannot simply check if `ts < decoded_sdu.ts` as that could also indicate old data + */ + return ((uint64_t)ts * 10 < decoded_sdu.ts); +} + +int bap_usb_add_frame_to_usb(enum bt_audio_location chan_allocation, const int16_t *frame, + size_t frame_size, uint32_t ts) +{ + const bool is_left = (chan_allocation & BT_AUDIO_LOCATION_FRONT_LEFT) != 0; + const bool is_right = (chan_allocation & BT_AUDIO_LOCATION_FRONT_RIGHT) != 0; + const bool is_mono = chan_allocation == BT_AUDIO_LOCATION_MONO_AUDIO; + const uint8_t ts_jitter_us = 100; /* timestamps may have jitter */ + + static size_t cnt; + + if ((++cnt % bap_get_stats_interval()) == 0U) { + LOG_INF("[%zu]: Adding USB audio frame", cnt); + } + + if (frame_size > LC3_MAX_NUM_SAMPLES_MONO * sizeof(int16_t) || frame_size == 0U) { + LOG_DBG("Invalid frame of size %zu", frame_size); + + return -EINVAL; + } + + if (get_chan_cnt(chan_allocation) != 1) { + LOG_DBG("Invalid channel allocation %d", chan_allocation); + + return -EINVAL; + } + + if (((is_left || is_right) && decoded_sdu.mono_frames_cnt != 0) || + (is_mono && + (decoded_sdu.left_frames_cnt != 0U || decoded_sdu.right_frames_cnt != 0U))) { + LOG_DBG("Cannot mix and match mono with left or right"); + + return -EINVAL; + } + + /* Check if the frame can be combined with a previous frame from another channel, of if + * we have to send previous data to USB and then store the current frame + * + * This is done by comparing the timestamps of the frames, and in the case that they are the + * same, there are additional checks to see if we have received more left than right frames, + * in which case we also send existing data + */ + + if (ts + ts_jitter_us < decoded_sdu.ts && !ts_overflowed(ts)) { + /* Old data, discard */ + return -ENOEXEC; + } else if (ts > decoded_sdu.ts + ts_jitter_us || ts_overflowed(ts)) { + /* We are getting new data - Send existing data to ring buffer */ + bap_usb_send_frames_to_usb(); + } else { /* same timestamp */ + bool send = false; + + if (is_left && decoded_sdu.left_frames_cnt > decoded_sdu.right_frames_cnt) { + /* We are receiving left again before a right, send to USB */ + send = true; + } else if (is_right && decoded_sdu.right_frames_cnt > decoded_sdu.left_frames_cnt) { + /* We are receiving right again before a left, send to USB */ + send = true; + } else if (is_mono) { + /* always send mono as it comes */ + send = true; + } + + if (send) { + bap_usb_send_frames_to_usb(); + } + } + + if (is_left) { + if (decoded_sdu.left_frames_cnt >= ARRAY_SIZE(decoded_sdu.left_frames)) { + LOG_WRN("Could not add more left frames"); + + return -ENOMEM; + } + + memcpy(decoded_sdu.left_frames[decoded_sdu.left_frames_cnt++], frame, frame_size); + } else if (is_right) { + if (decoded_sdu.right_frames_cnt >= ARRAY_SIZE(decoded_sdu.right_frames)) { + LOG_WRN("Could not add more right frames"); + + return -ENOMEM; + } + + memcpy(decoded_sdu.right_frames[decoded_sdu.right_frames_cnt++], frame, frame_size); + } else if (is_mono) { + /* Use left as mono*/ + if (decoded_sdu.mono_frames_cnt >= ARRAY_SIZE(decoded_sdu.left_frames)) { + LOG_WRN("Could not add more mono frames"); + + return -ENOMEM; + } + + memcpy(decoded_sdu.left_frames[decoded_sdu.mono_frames_cnt++], frame, frame_size); + } else { + /* Unsupported channel */ + LOG_DBG("Unsupported channel %d", chan_allocation); + + return -EINVAL; + } + + decoded_sdu.ts = ts; + + return 0; +} + +void bap_usb_clear_frames_to_usb(void) +{ + decoded_sdu.mono_frames_cnt = 0U; + decoded_sdu.right_frames_cnt = 0U; + decoded_sdu.left_frames_cnt = 0U; + decoded_sdu.ts = 0U; +} +#endif /* CONFIG_BT_AUDIO_RX */ + +#if defined(CONFIG_BT_AUDIO_TX) +BUILD_ASSERT((USB_IN_RING_BUF_SIZE % USB_MONO_FRAME_SIZE) == 0); +static int16_t usb_in_left_ring_buffer[USB_IN_RING_BUF_SIZE]; +static int16_t usb_in_right_ring_buffer[USB_IN_RING_BUF_SIZE]; +static size_t write_index; /* Points to the oldest/uninitialized data */ + +size_t bap_usb_get_read_cnt(const struct shell_stream *sh_stream) +{ + return (USB_SAMPLE_CNT * sh_stream->lc3_frame_duration_us) / USEC_PER_MSEC; +} + +size_t bap_usb_get_frame_size(const struct shell_stream *sh_stream) +{ + return USB_BYTES_PER_SAMPLE * bap_usb_get_read_cnt(sh_stream); +} + +static void stream_cb(struct shell_stream *sh_stream, void *user_data) +{ + if (sh_stream->is_tx) { + const bool has_left = + (sh_stream->lc3_chan_allocation & BT_AUDIO_LOCATION_FRONT_LEFT) != 0; + const bool has_right = + (sh_stream->lc3_chan_allocation & BT_AUDIO_LOCATION_FRONT_RIGHT) != 0; + const bool has_stereo = has_right && has_left; + const bool is_mono = sh_stream->lc3_chan_allocation == BT_AUDIO_LOCATION_MONO_AUDIO; + const size_t old_write_index = POINTER_TO_UINT(user_data); + const bool overflowed = write_index < old_write_index; + size_t read_idx; + + if (has_stereo) { + /* These should always be the same */ + read_idx = MIN(sh_stream->tx.left_read_idx, sh_stream->tx.right_read_idx); + } else if (has_left || is_mono) { + read_idx = sh_stream->tx.left_read_idx; + } else if (has_right) { + read_idx = sh_stream->tx.right_read_idx; + } else { + /* Not a valid USB stream */ + return; + } + + /* If we are overwriting data that the stream is currently pointing to, then we + * need to update the index so that the stream will point to the oldest valid data + */ + if (read_idx > old_write_index) { + if (read_idx < write_index || (overflowed && read_idx < write_index)) { + sh_stream->tx.left_read_idx = write_index; + sh_stream->tx.right_read_idx = write_index; + } + } + } +} + +static void usb_data_received_cb(const struct device *dev, struct net_buf *buf, size_t size) +{ + const size_t old_write_index = write_index; + static size_t cnt; + int16_t *pcm; + + if (buf == NULL) { + return; + } + + if (size != USB_STEREO_FRAME_SIZE) { + net_buf_unref(buf); + + return; + } + + pcm = (int16_t *)buf->data; + + /* Split the data into left and right as LC3 uses LLLLRRRR instead of LRLRLRLR as USB + * + * Since the left and right buffer sizes are a factor of USB_SAMPLE_CNT, then we can always + * add USB_SAMPLE_CNT in a single go without needing to check the remaining size as that + * can be done once afterwards + */ + for (size_t i = 0U, j = 0U; i < USB_SAMPLE_CNT; i++, j += USB_CHANNELS) { + usb_in_left_ring_buffer[write_index + i] = pcm[j]; + usb_in_right_ring_buffer[write_index + i] = pcm[j + 1]; + } + + write_index += USB_SAMPLE_CNT; + + if (write_index == USB_IN_RING_BUF_SIZE) { + /* Overflow so that we start overwriting oldest */ + write_index = 0U; + } + + /* Update the read pointers of each stream to ensure that the new write index is not larger + * than their read indexes + */ + bap_foreach_stream(stream_cb, UINT_TO_POINTER(old_write_index)); + + if ((++cnt % bap_get_stats_interval()) == 0U) { + LOG_DBG("USB Data received (count = %d)", cnt); + } + + net_buf_unref(buf); +} + +bool bap_usb_can_get_full_sdu(struct shell_stream *sh_stream) +{ + const bool has_left = (sh_stream->lc3_chan_allocation & BT_AUDIO_LOCATION_FRONT_LEFT) != 0; + const bool has_right = + (sh_stream->lc3_chan_allocation & BT_AUDIO_LOCATION_FRONT_RIGHT) != 0; + const bool has_stereo = has_right && has_left; + const bool is_mono = sh_stream->lc3_chan_allocation == BT_AUDIO_LOCATION_MONO_AUDIO; + const uint32_t read_cnt = bap_usb_get_read_cnt(sh_stream); + const uint32_t retrieve_cnt = read_cnt * sh_stream->lc3_frame_blocks_per_sdu; + static bool failed_last_time; + size_t read_idx; + size_t buffer_cnt; + + if (has_stereo) { + /* These should always be the same */ + read_idx = MIN(sh_stream->tx.left_read_idx, sh_stream->tx.right_read_idx); + } else if (has_left || is_mono) { + read_idx = sh_stream->tx.left_read_idx; + } else if (has_right) { + read_idx = sh_stream->tx.right_read_idx; + } else { + return false; + } + + if (read_idx <= write_index) { + buffer_cnt = write_index - read_idx; + } else { + /* Handle the case where the read spans across the end of the buffer */ + buffer_cnt = write_index + (USB_IN_RING_BUF_SIZE - read_idx); + } + + if (buffer_cnt < retrieve_cnt) { + /* Not enough for a frame yet */ + if (!failed_last_time) { + LOG_WRN("Ring buffer (%u/%u) does not contain enough for an entire SDU %u", + buffer_cnt, USB_IN_RING_BUF_SIZE, retrieve_cnt); + } + + failed_last_time = true; + + return false; + } + + failed_last_time = false; + + return true; +} + +/** + * Reads @p size octets from src, handling wrapping and returns the new idx + * (which is lower than @p idx in the case of wrapping) + * + * bap_usb_can_get_full_sdu should always be called before this to ensure that we are getting + * valid data + */ +static size_t usb_ring_buf_get(int16_t dest[], int16_t src[], size_t idx, size_t cnt) +{ + size_t new_idx; + + if (idx >= USB_IN_RING_BUF_SIZE) { + LOG_ERR("Invalid idx %zu", idx); + + return 0; + } + + if ((idx + cnt) < USB_IN_RING_BUF_SIZE) { + /* Simply copy of the data and increment the index*/ + memcpy(dest, &src[idx], cnt * USB_BYTES_PER_SAMPLE); + new_idx = idx + cnt; + } else { + /* Handle wrapping */ + const size_t first_read_cnt = USB_IN_RING_BUF_SIZE - idx; + const size_t second_read_cnt = cnt - first_read_cnt; + + memcpy(dest, &src[idx], first_read_cnt * USB_BYTES_PER_SAMPLE); + memcpy(&dest[first_read_cnt], &src[0], second_read_cnt * USB_BYTES_PER_SAMPLE); + + new_idx = second_read_cnt; + } + + return new_idx; +} + +void bap_usb_get_frame(struct shell_stream *sh_stream, enum bt_audio_location chan_alloc, + int16_t buffer[]) +{ + const bool is_left = (chan_alloc & BT_AUDIO_LOCATION_FRONT_LEFT) != 0; + const bool is_right = (chan_alloc & BT_AUDIO_LOCATION_FRONT_RIGHT) != 0; + const bool is_mono = chan_alloc == BT_AUDIO_LOCATION_MONO_AUDIO; + const uint32_t read_cnt = bap_usb_get_read_cnt(sh_stream); + + if (is_left || is_mono) { + sh_stream->tx.left_read_idx = usb_ring_buf_get( + buffer, usb_in_left_ring_buffer, sh_stream->tx.left_read_idx, read_cnt); + } else if (is_right) { + sh_stream->tx.right_read_idx = usb_ring_buf_get( + buffer, usb_in_right_ring_buffer, sh_stream->tx.right_read_idx, read_cnt); + } +} +#endif /* CONFIG_BT_AUDIO_TX */ + +int bap_usb_init(void) +{ + const struct device *hs_dev = DEVICE_DT_GET(DT_NODELABEL(hs_0)); + static const struct usb_audio_ops usb_ops = { +#if defined(CONFIG_BT_AUDIO_RX) + .data_request_cb = usb_data_request_cb, + .data_written_cb = usb_data_written_cb, +#endif /* CONFIG_BT_AUDIO_RX */ +#if defined(CONFIG_BT_AUDIO_TX) + .data_received_cb = usb_data_received_cb, +#endif /* CONFIG_BT_AUDIO_TX */ + }; + int err; + + if (!device_is_ready(hs_dev)) { + LOG_ERR("Cannot get USB Headset Device"); + return -EIO; + } + + usb_audio_register(hs_dev, &usb_ops); + err = usb_enable(NULL); + if (err != 0) { + LOG_ERR("Failed to enable USB"); + return err; + } + + if (IS_ENABLED(CONFIG_SOC_NRF5340_CPUAPP)) { + /* Use this to turn on 128 MHz clock for the nRF5340 cpu_app + * This may not be required, but reduces the risk of not decoding fast enough + * to keep up with USB + */ + err = nrfx_clock_divider_set(NRF_CLOCK_DOMAIN_HFCLK, NRF_CLOCK_HFCLK_DIV_1); + + err -= NRFX_ERROR_BASE_NUM; + if (err != 0) { + LOG_WRN("Failed to set 128 MHz: %d", err); + } + } + + return 0; +} diff --git a/subsys/bluetooth/audio/shell/cap_commander.c b/subsys/bluetooth/audio/shell/cap_commander.c index b65ec319c45..16a6d5ce7f8 100644 --- a/subsys/bluetooth/audio/shell/cap_commander.c +++ b/subsys/bluetooth/audio/shell/cap_commander.c @@ -19,6 +19,7 @@ #include "audio.h" static void cap_discover_cb(struct bt_conn *conn, int err, + const struct bt_csip_set_coordinator_set_member *member, const struct bt_csip_set_coordinator_csis_inst *csis_inst) { if (err != 0) { @@ -103,6 +104,19 @@ static struct bt_cap_commander_cb cbs = { #endif /* CONFIG_BT_MICP_MIC_CTLR */ }; +static int cmd_cap_commander_cancel(const struct shell *sh, size_t argc, char *argv[]) +{ + int err; + + err = bt_cap_commander_cancel(); + if (err != 0) { + shell_print(sh, "Failed to cancel CAP commander procedure: %d", err); + return -ENOEXEC; + } + + return 0; +} + static int cmd_cap_commander_discover(const struct shell *sh, size_t argc, char *argv[]) { static bool cbs_registered; @@ -472,6 +486,8 @@ static int cmd_cap_commander(const struct shell *sh, size_t argc, char **argv) SHELL_STATIC_SUBCMD_SET_CREATE( cap_commander_cmds, SHELL_CMD_ARG(discover, NULL, "Discover CAS", cmd_cap_commander_discover, 1, 0), + SHELL_CMD_ARG(cancel, NULL, "CAP commander cancel current procedure", + cmd_cap_commander_cancel, 1, 0), #if defined(CONFIG_BT_VCP_VOL_CTLR) SHELL_CMD_ARG(change_volume, NULL, "Change volume on all connections ", cmd_cap_commander_change_volume, 2, 0), diff --git a/subsys/bluetooth/audio/shell/cap_initiator.c b/subsys/bluetooth/audio/shell/cap_initiator.c index 6da30a7fe17..d5b7496eb19 100644 --- a/subsys/bluetooth/audio/shell/cap_initiator.c +++ b/subsys/bluetooth/audio/shell/cap_initiator.c @@ -25,6 +25,7 @@ #define CAP_UNICAST_CLIENT_STREAM_COUNT ARRAY_SIZE(unicast_streams) static void cap_discover_cb(struct bt_conn *conn, int err, + const struct bt_csip_set_coordinator_set_member *member, const struct bt_csip_set_coordinator_csis_inst *csis_inst) { if (err != 0) { @@ -247,6 +248,7 @@ static int cmd_cap_initiator_unicast_start(const struct shell *sh, size_t argc, group_stream_params[start_param.count].stream = &stream_param[start_param.count].stream->bap_stream; + group_stream_params[start_param.count].qos = &uni_stream->qos; pair_params[pair_cnt + j].tx_param = &group_stream_params[start_param.count]; @@ -277,6 +279,7 @@ static int cmd_cap_initiator_unicast_start(const struct shell *sh, size_t argc, stream_param[start_param.count].codec_cfg = &uni_stream->codec_cfg; group_stream_params[start_param.count].stream = &stream_param[start_param.count].stream->bap_stream; + group_stream_params[start_param.count].qos = &uni_stream->qos; pair_params[pair_cnt + j].rx_param = &group_stream_params[start_param.count]; @@ -621,23 +624,6 @@ static int cap_ac_unicast_start(const struct bap_unicast_ac_param *param, snk_stream_cnt++; stream_cnt++; - - /* If we have more than 1 connection or stream in one direction, we set the - * location bit accordingly - */ - if (param->conn_cnt > 1U || param->snk_cnt[i] > 1U) { - const int err = bt_audio_codec_cfg_set_chan_allocation( - stream_param->codec_cfg, (enum bt_audio_location)BIT(i)); - - if (err < 0) { - shell_error(ctx_shell, - "Failed to set channel allocation for " - "snk[%zu][%zu]: %d", - i, j, err); - - return err; - } - } } for (size_t j = 0U; j < param->src_cnt[i]; j++) { @@ -651,42 +637,98 @@ static int cap_ac_unicast_start(const struct bap_unicast_ac_param *param, src_stream_cnt++; stream_cnt++; + } + } - /* If we have more than 1 connection or stream in one direction, we set the - * location bit accordingly - */ - if (param->conn_cnt > 1U || param->src_cnt[i] > 1U) { - const int err = bt_audio_codec_cfg_set_chan_allocation( - stream_param->codec_cfg, (enum bt_audio_location)BIT(i)); + start_param.stream_params = stream_params; + start_param.count = stream_cnt; + start_param.type = BT_CAP_SET_TYPE_AD_HOC; - if (err < 0) { - shell_error(ctx_shell, - "Failed to set channel allocation for " - "src[%zu][%zu]: %d", - i, j, err); + return bt_cap_initiator_unicast_audio_start(&start_param); +} + +static int set_codec_config(const struct shell *sh, struct shell_stream *sh_stream, + struct named_lc3_preset *preset, size_t conn_cnt, size_t ep_cnt, + size_t chan_cnt, size_t conn_index, size_t ep_index) +{ + enum bt_audio_location new_chan_alloc; + enum bt_audio_location chan_alloc; + int err; + + copy_unicast_stream_preset(sh_stream, preset); - return err; + if (chan_cnt == 1U) { + /* - When we have a single channel on a single connection then we make it mono + * - When we have a single channel on a multiple connections then we make it left on + * the first connection and right on the second connection + * - When we have multiple channels streams for a connection, we make them either + * left or right, regardless of the connection count + */ + if (ep_cnt == 1) { + if (conn_cnt == 1) { + new_chan_alloc = BT_AUDIO_LOCATION_MONO_AUDIO; + } else if (conn_cnt == 2) { + if (conn_index == 0) { + new_chan_alloc = BT_AUDIO_LOCATION_FRONT_LEFT; + } else if (conn_index == 1) { + new_chan_alloc = BT_AUDIO_LOCATION_FRONT_RIGHT; + } else { + return 0; } + } else { + return 0; } + } else if (ep_cnt == 2) { + if (ep_index == 0) { + new_chan_alloc = BT_AUDIO_LOCATION_FRONT_LEFT; + } else if (ep_index == 1) { + new_chan_alloc = BT_AUDIO_LOCATION_FRONT_RIGHT; + } else { + return 0; + } + } else { + return 0; } + } else if (chan_cnt == 2U) { + /* Some audio configuration requires multiple sink channels, + * so multiply the SDU based on the channel count + */ + sh_stream->qos.sdu *= chan_cnt; + + /* If a stream has 2 channels, we make it stereo */ + new_chan_alloc = BT_AUDIO_LOCATION_FRONT_LEFT | BT_AUDIO_LOCATION_FRONT_RIGHT; + + } else { + return 0; } - start_param.stream_params = stream_params; - start_param.count = stream_cnt; - start_param.type = BT_CAP_SET_TYPE_AD_HOC; + err = bt_audio_codec_cfg_get_chan_allocation(&sh_stream->codec_cfg, &chan_alloc); + if (err != 0) { + if (err == -ENODATA) { + chan_alloc = BT_AUDIO_LOCATION_MONO_AUDIO; + } + } - return bt_cap_initiator_unicast_audio_start(&start_param); + if (chan_alloc != new_chan_alloc) { + shell_info(sh, + "[%zu][%zu]: Overwriting existing channel allocation 0x%08X with 0x%08X", + conn_index, ep_index, chan_alloc, new_chan_alloc); + + err = bt_audio_codec_cfg_set_chan_allocation(&sh_stream->codec_cfg, new_chan_alloc); + if (err < 0) { + return err; + } + } + + return 0; } -int cap_ac_unicast(const struct shell *sh, size_t argc, char **argv, - const struct bap_unicast_ac_param *param) +int cap_ac_unicast(const struct shell *sh, const struct bap_unicast_ac_param *param) { /* Allocate params large enough for any params, but only use what is required */ struct bt_conn *connected_conns[BAP_UNICAST_AC_MAX_CONN] = {0}; struct shell_stream *snk_uni_streams[BAP_UNICAST_AC_MAX_SNK]; struct shell_stream *src_uni_streams[BAP_UNICAST_AC_MAX_SRC]; - const struct named_lc3_preset *snk_named_preset = NULL; - const struct named_lc3_preset *src_named_preset = NULL; size_t conn_avail_cnt; size_t snk_cnt = 0; size_t src_cnt = 0; @@ -736,65 +778,42 @@ int cap_ac_unicast(const struct shell *sh, size_t argc, char **argv, */ for (size_t i = 0U; i < param->conn_cnt; i++) { for (size_t j = 0U; j < param->snk_cnt[i]; j++) { - snk_cnt++; - } + struct shell_stream *snk_uni_stream; - for (size_t j = 0U; j < param->src_cnt[i]; j++) { - src_cnt++; - } - } + snk_uni_stream = snk_uni_streams[snk_cnt] = &unicast_streams[snk_cnt]; - if (snk_cnt > 0U) { - snk_named_preset = bap_get_named_preset(true, BT_AUDIO_DIR_SINK, argv[1]); - if (snk_named_preset == NULL) { - shell_error(sh, "Unable to parse snk_named_preset %s", argv[1]); - return -ENOEXEC; - } - } + err = set_codec_config(sh, snk_uni_stream, &default_sink_preset, + param->conn_cnt, param->snk_cnt[i], + param->snk_chan_cnt, i, j); + if (err != 0) { + shell_error(sh, "Failed to set codec configuration: %d", err); - if (src_cnt > 0U) { - const char *preset_arg = argc > 2 ? argv[2] : argv[1]; + return -ENOEXEC; + } - src_named_preset = bap_get_named_preset(true, BT_AUDIO_DIR_SOURCE, preset_arg); - if (src_named_preset == NULL) { - shell_error(sh, "Unable to parse src_named_preset %s", argv[1]); - return -ENOEXEC; + snk_cnt++; } - } - - if (!ctx_shell) { - ctx_shell = sh; - } - - /* Setup arrays of parameters based on the preset for easier access. This also copies the - * preset so that we can modify them (e.g. update the metadata) - */ - for (size_t i = 0U; i < snk_cnt; i++) { - struct shell_stream *snk_uni_stream = snk_uni_streams[i] = &unicast_streams[i]; - if (snk_uni_stream->stream.bap_stream.conn != NULL) { - shell_error(sh, "unicast_streams[%zu] already in use", i); - return -ENOEXEC; - } + for (size_t j = 0U; j < param->src_cnt[i]; j++) { + struct shell_stream *src_uni_stream; - copy_unicast_stream_preset(snk_uni_stream, snk_named_preset); + src_uni_stream = snk_uni_streams[src_cnt] = &unicast_streams[src_cnt]; - /* Some audio configuration requires multiple sink channels, - * so multiply the SDU based on the channel count - */ - snk_uni_stream->qos.sdu *= param->snk_chan_cnt; - } + err = set_codec_config(sh, src_uni_stream, &default_source_preset, + param->conn_cnt, param->src_cnt[i], + param->src_chan_cnt, i, j); + if (err != 0) { + shell_error(sh, "Failed to set codec configuration: %d", err); - for (size_t i = 0U; i < src_cnt; i++) { - struct shell_stream *src_uni_stream = src_uni_streams[i] = - &unicast_streams[i + snk_cnt]; + return -ENOEXEC; + } - if (src_uni_stream->stream.bap_stream.conn != NULL) { - shell_error(sh, "unicast_streams[%zu] already in use", i + snk_cnt); - return -ENOEXEC; + src_cnt++; } + } - copy_unicast_stream_preset(src_uni_stream, src_named_preset); + if (!ctx_shell) { + ctx_shell = sh; } err = bap_ac_create_unicast_group(param, snk_uni_streams, snk_cnt, src_uni_streams, @@ -836,7 +855,7 @@ static int cmd_cap_ac_1(const struct shell *sh, size_t argc, char **argv) .src_chan_cnt = 0U, }; - return cap_ac_unicast(sh, argc, argv, ¶m); + return cap_ac_unicast(sh, ¶m); } #endif /* UNICAST_SINK_SUPPORTED */ @@ -852,7 +871,7 @@ static int cmd_cap_ac_2(const struct shell *sh, size_t argc, char **argv) .src_chan_cnt = 1U, }; - return cap_ac_unicast(sh, argc, argv, ¶m); + return cap_ac_unicast(sh, ¶m); } #endif /* UNICAST_SRC_SUPPORTED */ @@ -868,7 +887,7 @@ static int cmd_cap_ac_3(const struct shell *sh, size_t argc, char **argv) .src_chan_cnt = 1U, }; - return cap_ac_unicast(sh, argc, argv, ¶m); + return cap_ac_unicast(sh, ¶m); } #endif /* UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED */ @@ -884,7 +903,7 @@ static int cmd_cap_ac_4(const struct shell *sh, size_t argc, char **argv) .src_chan_cnt = 0U, }; - return cap_ac_unicast(sh, argc, argv, ¶m); + return cap_ac_unicast(sh, ¶m); } #endif /* UNICAST_SINK_SUPPORTED */ @@ -900,7 +919,7 @@ static int cmd_cap_ac_5(const struct shell *sh, size_t argc, char **argv) .src_chan_cnt = 1U, }; - return cap_ac_unicast(sh, argc, argv, ¶m); + return cap_ac_unicast(sh, ¶m); } #endif /* UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED */ @@ -917,7 +936,7 @@ static int cmd_cap_ac_6_i(const struct shell *sh, size_t argc, char **argv) .src_chan_cnt = 0U, }; - return cap_ac_unicast(sh, argc, argv, ¶m); + return cap_ac_unicast(sh, ¶m); } #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1 */ @@ -933,7 +952,7 @@ static int cmd_cap_ac_6_ii(const struct shell *sh, size_t argc, char **argv) .src_chan_cnt = 0U, }; - return cap_ac_unicast(sh, argc, argv, ¶m); + return cap_ac_unicast(sh, ¶m); } #endif /* CONFIG_BT_MAX_CONN >= 2 */ #endif /* UNICAST_SINK_SUPPORTED */ @@ -950,7 +969,7 @@ static int cmd_cap_ac_7_i(const struct shell *sh, size_t argc, char **argv) .src_chan_cnt = 1U, }; - return cap_ac_unicast(sh, argc, argv, ¶m); + return cap_ac_unicast(sh, ¶m); } #if CONFIG_BT_MAX_CONN >= 2 @@ -965,7 +984,7 @@ static int cmd_cap_ac_7_ii(const struct shell *sh, size_t argc, char **argv) .src_chan_cnt = 1U, }; - return cap_ac_unicast(sh, argc, argv, ¶m); + return cap_ac_unicast(sh, ¶m); } #endif /* CONFIG_BT_MAX_CONN >= 2 */ @@ -981,7 +1000,7 @@ static int cmd_cap_ac_8_i(const struct shell *sh, size_t argc, char **argv) .src_chan_cnt = 1U, }; - return cap_ac_unicast(sh, argc, argv, ¶m); + return cap_ac_unicast(sh, ¶m); } #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1 */ @@ -997,7 +1016,7 @@ static int cmd_cap_ac_8_ii(const struct shell *sh, size_t argc, char **argv) .src_chan_cnt = 1U, }; - return cap_ac_unicast(sh, argc, argv, ¶m); + return cap_ac_unicast(sh, ¶m); } #endif /* CONFIG_BT_MAX_CONN >= 2 */ @@ -1013,7 +1032,7 @@ static int cmd_cap_ac_9_i(const struct shell *sh, size_t argc, char **argv) .src_chan_cnt = 1U, }; - return cap_ac_unicast(sh, argc, argv, ¶m); + return cap_ac_unicast(sh, ¶m); } #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 1 */ @@ -1029,7 +1048,7 @@ static int cmd_cap_ac_9_ii(const struct shell *sh, size_t argc, char **argv) .src_chan_cnt = 1U, }; - return cap_ac_unicast(sh, argc, argv, ¶m); + return cap_ac_unicast(sh, ¶m); } #endif /* CONFIG_BT_MAX_CONN >= 2 && CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 1 */ @@ -1045,7 +1064,7 @@ static int cmd_cap_ac_10(const struct shell *sh, size_t argc, char **argv) .src_chan_cnt = 2U, }; - return cap_ac_unicast(sh, argc, argv, ¶m); + return cap_ac_unicast(sh, ¶m); } #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 1 */ @@ -1061,7 +1080,7 @@ static int cmd_cap_ac_11_i(const struct shell *sh, size_t argc, char **argv) .src_chan_cnt = 1U, }; - return cap_ac_unicast(sh, argc, argv, ¶m); + return cap_ac_unicast(sh, ¶m); } #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1 && \ * CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 1 \ @@ -1079,7 +1098,7 @@ static int cmd_cap_ac_11_ii(const struct shell *sh, size_t argc, char **argv) .src_chan_cnt = 1U, }; - return cap_ac_unicast(sh, argc, argv, ¶m); + return cap_ac_unicast(sh, ¶m); } #endif /* CONFIG_BT_MAX_CONN >= 2 */ #endif /* UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED */ @@ -1205,7 +1224,6 @@ int cap_ac_broadcast(const struct shell *sh, size_t argc, char **argv, BT_AUDIO_LOCATION_FRONT_LEFT)}; struct bt_cap_initiator_broadcast_subgroup_param subgroup_param = {0}; struct bt_cap_initiator_broadcast_create_param create_param = {0}; - const struct named_lc3_preset *named_preset; struct bt_le_ext_adv *adv; int err; @@ -1220,13 +1238,7 @@ int cap_ac_broadcast(const struct shell *sh, size_t argc, char **argv, return -ENOEXEC; } - named_preset = bap_get_named_preset(false, BT_AUDIO_DIR_SOURCE, argv[1]); - if (named_preset == NULL) { - shell_error(sh, "Unable to parse named_preset %s", argv[1]); - return -ENOEXEC; - } - - copy_broadcast_source_preset(&default_source, named_preset); + copy_broadcast_source_preset(&default_source, &default_broadcast_source_preset); default_source.qos.sdu *= param->chan_cnt; for (size_t i = 0U; i < param->stream_cnt; i++) { @@ -1337,55 +1349,55 @@ SHELL_STATIC_SUBCMD_SET_CREATE( SHELL_CMD_ARG(unicast_cancel, NULL, "Unicast cancel current procedure", cmd_cap_initiator_unicast_cancel, 1, 0), #if UNICAST_SINK_SUPPORTED - SHELL_CMD_ARG(ac_1, NULL, "", cmd_cap_ac_1, 2, 0), + SHELL_CMD_ARG(ac_1, NULL, "Unicast audio configuration 1", cmd_cap_ac_1, 1, 0), #endif /* UNICAST_SINK_SUPPORTED */ #if UNICAST_SRC_SUPPORTED - SHELL_CMD_ARG(ac_2, NULL, "", cmd_cap_ac_2, 2, 0), + SHELL_CMD_ARG(ac_2, NULL, "Unicast audio configuration 2", cmd_cap_ac_2, 1, 0), #endif /* UNICAST_SRC_SUPPORTED */ #if UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED - SHELL_CMD_ARG(ac_3, NULL, " ", cmd_cap_ac_3, 3, 0), + SHELL_CMD_ARG(ac_3, NULL, "Unicast audio configuration 3", cmd_cap_ac_3, 1, 0), #endif /* UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED */ #if UNICAST_SINK_SUPPORTED - SHELL_CMD_ARG(ac_4, NULL, "", cmd_cap_ac_4, 2, 0), + SHELL_CMD_ARG(ac_4, NULL, "Unicast audio configuration 4", cmd_cap_ac_4, 1, 0), #endif /* UNICAST_SINK_SUPPORTED */ #if UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED - SHELL_CMD_ARG(ac_5, NULL, " ", cmd_cap_ac_5, 3, 0), + SHELL_CMD_ARG(ac_5, NULL, "Unicast audio configuration 5", cmd_cap_ac_5, 1, 0), #endif /* UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED */ #if UNICAST_SINK_SUPPORTED #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1 - SHELL_CMD_ARG(ac_6_i, NULL, "", cmd_cap_ac_6_i, 2, 0), + SHELL_CMD_ARG(ac_6_i, NULL, "Unicast audio configuration 6(i)", cmd_cap_ac_6_i, 1, 0), #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1 */ #if CONFIG_BT_MAX_CONN >= 2 - SHELL_CMD_ARG(ac_6_ii, NULL, "", cmd_cap_ac_6_ii, 2, 0), + SHELL_CMD_ARG(ac_6_ii, NULL, "Unicast audio configuration 6(ii)", cmd_cap_ac_6_ii, 1, 0), #endif /* CONFIG_BT_MAX_CONN >= 2 */ #endif /* UNICAST_SINK_SUPPORTED */ #if UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED - SHELL_CMD_ARG(ac_7_i, NULL, " ", cmd_cap_ac_7_i, 3, 0), + SHELL_CMD_ARG(ac_7_i, NULL, "Unicast audio configuration 7(i)", cmd_cap_ac_7_i, 1, 0), #if CONFIG_BT_MAX_CONN >= 2 - SHELL_CMD_ARG(ac_7_ii, NULL, " ", cmd_cap_ac_7_ii, 3, 0), + SHELL_CMD_ARG(ac_7_ii, NULL, "Unicast audio configuration 7(ii)", cmd_cap_ac_7_ii, 1, 0), #endif /* CONFIG_BT_MAX_CONN >= 2 */ #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1 - SHELL_CMD_ARG(ac_8_i, NULL, " ", cmd_cap_ac_8_i, 3, 0), + SHELL_CMD_ARG(ac_8_i, NULL, "Unicast audio configuration 8(i)", cmd_cap_ac_8_i, 1, 0), #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1 */ #if CONFIG_BT_MAX_CONN >= 2 - SHELL_CMD_ARG(ac_8_ii, NULL, " ", cmd_cap_ac_8_ii, 3, 0), + SHELL_CMD_ARG(ac_8_ii, NULL, "Unicast audio configuration 8(ii)", cmd_cap_ac_8_ii, 1, 0), #endif /* CONFIG_BT_MAX_CONN >= 2 */ #if UNICAST_SRC_SUPPORTED #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 1 - SHELL_CMD_ARG(ac_9_i, NULL, "", cmd_cap_ac_9_i, 2, 0), + SHELL_CMD_ARG(ac_9_i, NULL, "Unicast audio configuration 9(i)", cmd_cap_ac_9_i, 1, 0), #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 1 */ #if CONFIG_BT_MAX_CONN >= 2 - SHELL_CMD_ARG(ac_9_ii, NULL, "", cmd_cap_ac_9_ii, 2, 0), + SHELL_CMD_ARG(ac_9_ii, NULL, "Unicast audio configuration 9(ii)", cmd_cap_ac_9_ii, 1, 0), #endif /* CONFIG_BT_MAX_CONN >= 2 */ - SHELL_CMD_ARG(ac_10, NULL, "", cmd_cap_ac_10, 2, 0), + SHELL_CMD_ARG(ac_10, NULL, "Unicast audio configuration 10", cmd_cap_ac_10, 1, 0), #endif /* UNICAST_SRC_SUPPORTED */ #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1 && CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 1 - SHELL_CMD_ARG(ac_11_i, NULL, " ", cmd_cap_ac_11_i, 3, 0), + SHELL_CMD_ARG(ac_11_i, NULL, "Unicast audio configuration 11(i)", cmd_cap_ac_11_i, 1, 0), #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1 && \ * CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 1 \ */ #if CONFIG_BT_MAX_CONN >= 2 - SHELL_CMD_ARG(ac_11_ii, NULL, " ", cmd_cap_ac_11_ii, 3, 0), + SHELL_CMD_ARG(ac_11_ii, NULL, "Unicast audio configuration 11(ii)", cmd_cap_ac_11_ii, 1, 0), #endif /* CONFIG_BT_MAX_CONN >= 2 */ #endif /* UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED */ #endif /* CONFIG_BT_BAP_UNICAST_CLIENT */ @@ -1394,11 +1406,11 @@ SHELL_STATIC_SUBCMD_SET_CREATE( SHELL_CMD_ARG(broadcast_update, NULL, "", cmd_broadcast_update, 2, 0), SHELL_CMD_ARG(broadcast_stop, NULL, "", cmd_broadcast_stop, 1, 0), SHELL_CMD_ARG(broadcast_delete, NULL, "", cmd_broadcast_delete, 1, 0), - SHELL_CMD_ARG(ac_12, NULL, "", cmd_cap_ac_12, 2, 0), + SHELL_CMD_ARG(ac_12, NULL, "Broadcast audio configuration 12", cmd_cap_ac_12, 1, 0), #if CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT > 1 - SHELL_CMD_ARG(ac_13, NULL, "", cmd_cap_ac_13, 2, 0), + SHELL_CMD_ARG(ac_13, NULL, "Broadcast audio configuration 13", cmd_cap_ac_13, 1, 0), #endif /* CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT > 1 */ - SHELL_CMD_ARG(ac_14, NULL, "", cmd_cap_ac_14, 2, 0), + SHELL_CMD_ARG(ac_14, NULL, "Broadcast audio configuration 14", cmd_cap_ac_14, 1, 0), #endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */ SHELL_SUBCMD_SET_END); diff --git a/subsys/bluetooth/audio/shell/gmap.c b/subsys/bluetooth/audio/shell/gmap.c index cbd91f69219..79cd3b0c732 100644 --- a/subsys/bluetooth/audio/shell/gmap.c +++ b/subsys/bluetooth/audio/shell/gmap.c @@ -266,7 +266,7 @@ static int cmd_gmap_ac_1(const struct shell *sh, size_t argc, char **argv) .src_chan_cnt = 0U, }; - return cap_ac_unicast(sh, argc, argv, ¶m); + return cap_ac_unicast(sh, ¶m); } #endif /* UNICAST_SINK_SUPPORTED */ @@ -282,7 +282,7 @@ static int cmd_gmap_ac_2(const struct shell *sh, size_t argc, char **argv) .src_chan_cnt = 1U, }; - return cap_ac_unicast(sh, argc, argv, ¶m); + return cap_ac_unicast(sh, ¶m); } #endif /* UNICAST_SRC_SUPPORTED */ @@ -298,7 +298,7 @@ static int cmd_gmap_ac_3(const struct shell *sh, size_t argc, char **argv) .src_chan_cnt = 1U, }; - return cap_ac_unicast(sh, argc, argv, ¶m); + return cap_ac_unicast(sh, ¶m); } #endif /* UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED */ @@ -314,7 +314,7 @@ static int cmd_gmap_ac_4(const struct shell *sh, size_t argc, char **argv) .src_chan_cnt = 0U, }; - return cap_ac_unicast(sh, argc, argv, ¶m); + return cap_ac_unicast(sh, ¶m); } #endif /* UNICAST_SINK_SUPPORTED */ @@ -330,7 +330,7 @@ static int cmd_gmap_ac_5(const struct shell *sh, size_t argc, char **argv) .src_chan_cnt = 1U, }; - return cap_ac_unicast(sh, argc, argv, ¶m); + return cap_ac_unicast(sh, ¶m); } #endif /* UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED */ @@ -347,7 +347,7 @@ static int cmd_gmap_ac_6_i(const struct shell *sh, size_t argc, char **argv) .src_chan_cnt = 0U, }; - return cap_ac_unicast(sh, argc, argv, ¶m); + return cap_ac_unicast(sh, ¶m); } #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1 */ @@ -363,7 +363,7 @@ static int cmd_gmap_ac_6_ii(const struct shell *sh, size_t argc, char **argv) .src_chan_cnt = 0U, }; - return cap_ac_unicast(sh, argc, argv, ¶m); + return cap_ac_unicast(sh, ¶m); } #endif /* CONFIG_BT_MAX_CONN >= 2 */ #endif /* UNICAST_SINK_SUPPORTED */ @@ -381,7 +381,7 @@ static int cmd_gmap_ac_7_ii(const struct shell *sh, size_t argc, char **argv) .src_chan_cnt = 1U, }; - return cap_ac_unicast(sh, argc, argv, ¶m); + return cap_ac_unicast(sh, ¶m); } #endif /* CONFIG_BT_MAX_CONN >= 2 */ @@ -397,7 +397,7 @@ static int cmd_gmap_ac_8_i(const struct shell *sh, size_t argc, char **argv) .src_chan_cnt = 1U, }; - return cap_ac_unicast(sh, argc, argv, ¶m); + return cap_ac_unicast(sh, ¶m); } #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1 */ @@ -413,7 +413,7 @@ static int cmd_gmap_ac_8_ii(const struct shell *sh, size_t argc, char **argv) .src_chan_cnt = 1U, }; - return cap_ac_unicast(sh, argc, argv, ¶m); + return cap_ac_unicast(sh, ¶m); } #endif /* CONFIG_BT_MAX_CONN >= 2 */ @@ -429,7 +429,7 @@ static int cmd_gmap_ac_11_i(const struct shell *sh, size_t argc, char **argv) .src_chan_cnt = 1U, }; - return cap_ac_unicast(sh, argc, argv, ¶m); + return cap_ac_unicast(sh, ¶m); } #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1 && \ * CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 1 \ @@ -447,7 +447,7 @@ static int cmd_gmap_ac_11_ii(const struct shell *sh, size_t argc, char **argv) .src_chan_cnt = 1U, }; - return cap_ac_unicast(sh, argc, argv, ¶m); + return cap_ac_unicast(sh, ¶m); } #endif /* CONFIG_BT_MAX_CONN >= 2 */ #endif /* UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED */ @@ -509,55 +509,56 @@ SHELL_STATIC_SUBCMD_SET_CREATE( SHELL_CMD_ARG(discover, NULL, HELP_NONE, cmd_gmap_discover, 1, 0), #if defined(CONFIG_BT_GMAP_UGG_SUPPORTED) #if UNICAST_SINK_SUPPORTED - SHELL_CMD_ARG(ac_1, NULL, "", cmd_gmap_ac_1, 2, 0), + SHELL_CMD_ARG(ac_1, NULL, "Unicast audio configuration 1", cmd_gmap_ac_1, 1, 0), #endif /* UNICAST_SINK_SUPPORTED */ #if UNICAST_SRC_SUPPORTED - SHELL_CMD_ARG(ac_2, NULL, "", cmd_gmap_ac_2, 2, 0), + SHELL_CMD_ARG(ac_2, NULL, "Unicast audio configuration 2", cmd_gmap_ac_2, 1, 0), #endif /* UNICAST_SRC_SUPPORTED */ #if UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED - SHELL_CMD_ARG(ac_3, NULL, " ", cmd_gmap_ac_3, 3, 0), + SHELL_CMD_ARG(ac_3, NULL, "Unicast audio configuration 3", cmd_gmap_ac_3, 1, 0), #endif /* UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED */ #if UNICAST_SINK_SUPPORTED - SHELL_CMD_ARG(ac_4, NULL, "", cmd_gmap_ac_4, 2, 0), + SHELL_CMD_ARG(ac_4, NULL, "Unicast audio configuration 4", cmd_gmap_ac_4, 1, 0), #endif /* UNICAST_SINK_SUPPORTED */ #if UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED - SHELL_CMD_ARG(ac_5, NULL, " ", cmd_gmap_ac_5, 3, 0), + SHELL_CMD_ARG(ac_5, NULL, "Unicast audio configuration 5", cmd_gmap_ac_5, 1, 0), #endif /* UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED */ #if UNICAST_SINK_SUPPORTED #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1 - SHELL_CMD_ARG(ac_6_i, NULL, "", cmd_gmap_ac_6_i, 2, 0), + SHELL_CMD_ARG(ac_6_i, NULL, "Unicast audio configuration 6(i)", cmd_gmap_ac_6_i, 1, 0), #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1 */ #if CONFIG_BT_MAX_CONN >= 2 - SHELL_CMD_ARG(ac_6_ii, NULL, "", cmd_gmap_ac_6_ii, 2, 0), + SHELL_CMD_ARG(ac_6_ii, NULL, "Unicast audio configuration 6(ii)", cmd_gmap_ac_6_ii, 1, 0), #endif /* CONFIG_BT_MAX_CONN >= 2 */ #endif /* UNICAST_SINK_SUPPORTED */ #if UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED #if CONFIG_BT_MAX_CONN >= 2 - SHELL_CMD_ARG(ac_7_ii, NULL, " ", cmd_gmap_ac_7_ii, 3, 0), + SHELL_CMD_ARG(ac_7_ii, NULL, "Unicast audio configuration 7(ii)", cmd_gmap_ac_7_ii, 1, 0), #endif /* CONFIG_BT_MAX_CONN >= 2 */ #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1 - SHELL_CMD_ARG(ac_8_i, NULL, " ", cmd_gmap_ac_8_i, 3, 0), + SHELL_CMD_ARG(ac_8_i, NULL, "Unicast audio configuration 8(i)", cmd_gmap_ac_8_i, 1, 0), #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1 */ #if CONFIG_BT_MAX_CONN >= 2 - SHELL_CMD_ARG(ac_8_ii, NULL, " ", cmd_gmap_ac_8_ii, 3, 0), + SHELL_CMD_ARG(ac_8_ii, NULL, "Unicast audio configuration 8(ii)", cmd_gmap_ac_8_ii, 1, 0), #endif /* CONFIG_BT_MAX_CONN >= 2 */ #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1 && CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 1 - SHELL_CMD_ARG(ac_11_i, NULL, " ", cmd_gmap_ac_11_i, 3, 0), + SHELL_CMD_ARG(ac_11_i, NULL, "Unicast audio configuration 11(i)", cmd_gmap_ac_11_i, 1, 0), #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1 && \ * CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 1 \ */ #if CONFIG_BT_MAX_CONN >= 2 - SHELL_CMD_ARG(ac_11_ii, NULL, " ", cmd_gmap_ac_11_ii, 3, 0), + SHELL_CMD_ARG(ac_11_ii, NULL, "Unicast audio configuration 11(ii)", cmd_gmap_ac_11_ii, 1, + 0), #endif /* CONFIG_BT_MAX_CONN >= 2 */ #endif /* UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED */ #endif /* CONFIG_BT_GMAP_UGG_SUPPORTED */ #if defined(CONFIG_BT_GMAP_BGS_SUPPORTED) - SHELL_CMD_ARG(ac_12, NULL, "", cmd_gmap_ac_12, 2, 0), + SHELL_CMD_ARG(ac_12, NULL, "Broadcast audio configuration 12", cmd_gmap_ac_12, 1, 0), #if CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT > 1 - SHELL_CMD_ARG(ac_13, NULL, "", cmd_gmap_ac_13, 2, 0), + SHELL_CMD_ARG(ac_13, NULL, "Broadcast audio configuration 13", cmd_gmap_ac_13, 1, 0), #endif /* CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT > 1 */ - SHELL_CMD_ARG(ac_14, NULL, "", cmd_gmap_ac_14, 2, 0), + SHELL_CMD_ARG(ac_14, NULL, "Broadcast audio configuration 14", cmd_gmap_ac_14, 1, 0), #endif /* CONFIG_BT_GMAP_BGS_SUPPORTED*/ SHELL_SUBCMD_SET_END); diff --git a/subsys/bluetooth/audio/vcp_vol_ctlr.c b/subsys/bluetooth/audio/vcp_vol_ctlr.c index 56082740894..2abc458d797 100644 --- a/subsys/bluetooth/audio/vcp_vol_ctlr.c +++ b/subsys/bluetooth/audio/vcp_vol_ctlr.c @@ -1182,7 +1182,6 @@ int bt_vcp_vol_ctlr_set_vol(struct bt_vcp_vol_ctlr *vol_ctlr, uint8_t volume) vol_ctlr->cp_val.cp.counter = vol_ctlr->state.change_counter; vol_ctlr->cp_val.volume = volume; - vol_ctlr->busy = true; vol_ctlr->write_params.offset = 0; vol_ctlr->write_params.data = &vol_ctlr->cp_val; vol_ctlr->write_params.length = sizeof(vol_ctlr->cp_val); diff --git a/subsys/bluetooth/common/Kconfig b/subsys/bluetooth/common/Kconfig index 344823a88d1..9ccd4e184f6 100644 --- a/subsys/bluetooth/common/Kconfig +++ b/subsys/bluetooth/common/Kconfig @@ -79,7 +79,6 @@ config BT_BUF_ACL_RX_SIZE config BT_BUF_ACL_RX_COUNT int "Number of incoming ACL data buffers" - default NET_BUF_RX_COUNT if NET_L2_BT default 6 range 1 64 help @@ -97,7 +96,7 @@ config BT_BUF_ACL_RX_COUNT config BT_BUF_EVT_RX_SIZE int "Maximum supported HCI Event buffer length" - default 255 if (BT_EXT_ADV && BT_OBSERVER) || BT_PER_ADV_SYNC || BT_DF_CONNECTION_CTE_RX + default 255 if (BT_EXT_ADV && BT_OBSERVER) || BT_PER_ADV_SYNC || BT_DF_CONNECTION_CTE_RX || BT_CLASSIC # LE Read Supported Commands command complete event. default 68 range 68 255 @@ -191,32 +190,16 @@ config BT_HCI_VS Host and/or Controller. This enables Set Version Information, Supported Commands, Supported Features vendor commands. -config BT_HCI_VS_EXT - bool "Zephyr HCI Vendor-Specific Extensions" - depends on BT_HCI_VS - default y - help - Enable support for the Zephyr HCI Vendor-Specific Extensions in the - Host and/or Controller. This enables Write BD_ADDR, Read Build Info, - Read Static Addresses and Read Key Hierarchy Roots vendor commands. - -config BT_HCI_VS_EVT - bool "Zephyr HCI Vendor-Specific Events" - depends on BT_HCI_VS_EXT - help - Enable support for the Zephyr HCI Vendor-Specific Events in the - Host and/or Controller. - config BT_HCI_VS_FATAL_ERROR bool "Allow vendor specific HCI event Zephyr Fatal Error" - depends on BT_HCI_VS_EXT + depends on BT_HCI_VS help Enable emiting HCI Vendor-Specific events for system and Controller errors that are unrecoverable. config BT_HCI_VS_EXT_DETECT bool "Use heuristics to guess HCI vendor extensions support in advance" - depends on BT_HCI_VS_EXT && !BT_CTLR + depends on BT_HCI_VS && !BT_CTLR default y if BOARD_QEMU_X86 || BOARD_QEMU_CORTEX_M3 || BOARD_NATIVE_POSIX help Use some heuristics to try to guess in advance whether the controller diff --git a/subsys/bluetooth/common/Kconfig.template.log_config_bt b/subsys/bluetooth/common/Kconfig.template.log_config_bt deleted file mode 100644 index 0a1a865cfaf..00000000000 --- a/subsys/bluetooth/common/Kconfig.template.log_config_bt +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright (c) 2022 Nordic Semicoductor ASA -# SPDX-License-Identifier: Apache-2.0 - -# Usage: -# This template provides backwards compatibility for legacy kconfig symbols. -# Do not add new uses of it. -# -# The following arguments are mandatory: -# - module: -# Name of the new log level kconfig. -# Example: "BT_HCI_CORE" -# - legacy-debug-sym: -# An existing "legacy" kconfig bool. If that bool is selected, -# the new kconfig is forced to max verbosity. -# Example: "BT_DEBUG_HCI_CORE" - -config $(module)_LOG_LEVEL - default 4 if $(legacy-debug-sym) - -module := $(module) -parent-module := BT -source "subsys/logging/Kconfig.template.log_config_inherit" diff --git a/subsys/bluetooth/common/dummy.c b/subsys/bluetooth/common/dummy.c index 4b9d393cc9c..9d83e1f9276 100644 --- a/subsys/bluetooth/common/dummy.c +++ b/subsys/bluetooth/common/dummy.c @@ -9,6 +9,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include + #include #include @@ -18,18 +20,17 @@ * their members are bytes or byte arrays, the size is. They must not be padded * by the compiler, otherwise the on-wire packet will not map the packed * structure correctly. + * + * The bt_addr structs are not marked __packed because it's considered ugly by + * some. But here is a proof that the structs have all the properties of, and + * can be safely used as packed structs. */ BUILD_ASSERT(sizeof(bt_addr_t) == BT_ADDR_SIZE); +BUILD_ASSERT(alignof(bt_addr_t) == 1); BUILD_ASSERT(sizeof(bt_addr_le_t) == BT_ADDR_LE_SIZE); +BUILD_ASSERT(alignof(bt_addr_le_t) == 1); #if defined(CONFIG_BT_HCI_HOST) -/* The Bluetooth subsystem requires the Tx thread to execute at higher priority - * than the Rx thread as the Tx thread needs to process the acknowledgements - * before new Rx data is processed. This is a necessity to correctly detect - * transaction violations in ATT and SMP protocols. - */ -BUILD_ASSERT(CONFIG_BT_HCI_TX_PRIO < CONFIG_BT_RX_PRIO); - /* The Bluetooth subsystem requires that higher priority events shall be given * in a priority higher than the Bluetooth Host's Tx and the Controller's * receive thread priority. diff --git a/subsys/bluetooth/controller/CMakeLists.txt b/subsys/bluetooth/controller/CMakeLists.txt index 42008750d6d..a9761dc217d 100644 --- a/subsys/bluetooth/controller/CMakeLists.txt +++ b/subsys/bluetooth/controller/CMakeLists.txt @@ -21,6 +21,10 @@ zephyr_library_sources( ll_sw/ll_addr.c ll_sw/ull.c ll_sw/lll_common.c + ) + +zephyr_library_sources_ifdef( + CONFIG_BT_CTLR_HCI hci/hci_driver.c hci/hci.c ) @@ -208,6 +212,11 @@ add_subdirectory_ifdef( ll_sw/openisa ) +zephyr_library_compile_options_ifdef( + CONFIG_BT_CTLR_OPTIMIZE_FOR_SIZE + ${OPTIMIZE_FOR_SIZE_FLAG} + ) + zephyr_library_compile_options_ifdef( CONFIG_BT_CTLR_OPTIMIZE_FOR_SPEED ${OPTIMIZE_FOR_SPEED_FLAG} diff --git a/subsys/bluetooth/controller/Kconfig b/subsys/bluetooth/controller/Kconfig index d0a863f41cf..befbb59df13 100644 --- a/subsys/bluetooth/controller/Kconfig +++ b/subsys/bluetooth/controller/Kconfig @@ -125,6 +125,14 @@ config BT_LL_SW_SPLIT endchoice +config BT_CTLR_HCI + bool "Host Controller Interface (HCI)" + default y + help + Enable the Host Controller interface (HCI) in the Controller. + This should almost always be enabled, except in a few special + cases, like for unit testing. + comment "BLE Controller configuration" config BT_CTLR_CRYPTO @@ -138,7 +146,7 @@ config BT_CTLR_CRYPTO config BT_CTLR_HCI_VS_BUILD_INFO string "Zephyr HCI VS Build Info string" default "" - depends on BT_HCI_VS_EXT + depends on BT_CTLR_HCI && BT_HCI_VS help User-defined string that will be returned by the Zephyr VS Read Build Information command after the Zephyr version and build time. When @@ -203,12 +211,19 @@ config BT_CTLR_ISO_TX_BUFFERS config BT_CTLR_ISO_TX_BUFFER_SIZE int "Isochronous Tx buffer size" depends on BT_CTLR_ADV_ISO || BT_CTLR_CONN_ISO - range 1 4095 - default BT_ISO_TX_MTU if BT_ISO + range 9 4103 if BT_LL_SW_SPLIT + range 1 65535 + default 9 if BT_LL_SW_SPLIT default 1 help Size of the Isochronous Tx buffers and the value returned in HCI LE - Read Buffer Size V2 command response. + Read Buffer Size V2 command response. This is the data portion of the + HCI ISO Data packet, corresponding to the Data_Total_Length field. + + Currently the maximum SDU length is 4095 bytes, hence add HCI ISO + Data packet overhead (the Packet_Sequence_Number, ISO_SDU_Length, + Packet_Status_Flag fields; and the optional Time_Stamp field, if + supplied) of 8 bytes. config BT_CTLR_ISOAL_SOURCES int "Number of Isochronous Adaptation Layer sources" @@ -422,7 +437,7 @@ config BT_CTLR_TX_PWR_ANTENNA config BT_CTLR_TX_PWR_DYNAMIC_CONTROL bool "Tx Power Dynamic Control" - depends on BT_HCI_VS_EXT + depends on BT_HCI_VS help Enable dynamic control of Tx power per role/connection. Provides HCI VS commands to set and get the current Tx @@ -791,6 +806,7 @@ config BT_CTLR_ADV_ISO_SET int "LE Isochronous Channel advertising sets" depends on BT_CTLR_ADV_ISO range 1 32 + default BT_ISO_MAX_BIG help Maximum supported advertising sets. @@ -805,6 +821,7 @@ config BT_CTLR_ADV_ISO_STREAM_COUNT int "Maximum Broadcast ISO Streams" depends on BT_CTLR_ADV_ISO range BT_CTLR_ADV_ISO_STREAM_MAX 64 + default BT_ISO_MAX_CHAN help Maximum Broadcast ISO Streams supported in the the Controller across all Broadcast ISO groups. @@ -821,7 +838,7 @@ config BT_CTLR_SCAN_SYNC_ISO_SET int "LE ISO Broadcast Isochronous Groups Sync Sets" depends on BT_CTLR_SYNC_ISO range 1 64 - default 1 + default BT_ISO_MAX_BIG help Maximum supported broadcast isochronous groups (BIGs) sync sets. @@ -837,6 +854,7 @@ config BT_CTLR_SYNC_ISO_STREAM_COUNT int "Maximum ISO Synchronized Receiver Streams" depends on BT_CTLR_SYNC_ISO range BT_CTLR_SYNC_ISO_STREAM_MAX 64 + default BT_ISO_MAX_CHAN help Maximum ISO Synchronized Receiver Streams supported in the the Controller across all Broadcast ISO groups. @@ -895,7 +913,7 @@ config BT_CTLR_CONN_ISO_STREAMS int "LE Connected Isochronous Streams" depends on BT_CTLR_CONN_ISO range 1 64 - default 2 + default BT_ISO_MAX_CHAN help Maximum supported total number of CISes. @@ -903,7 +921,7 @@ config BT_CTLR_CONN_ISO_GROUPS int "LE Connected Isochronous Groups" depends on BT_CTLR_CONN_ISO range 1 240 - default 1 + default BT_ISO_MAX_CIG help Maximum supported CIGs. @@ -927,7 +945,7 @@ config BT_CTLR_CONN_ISO_PDU_LEN_MAX config BT_CTLR_CONN_ISO_SDU_LEN_MAX int "Maximum Connected Isochronous Channel SDU Length" depends on BT_CTLR_CONN_ISO - range BT_CTLR_CONN_ISO_PDU_LEN_MAX 4095 + range 1 4095 default 251 help Maximum Connected Isochronous Channel SDU Length. @@ -979,6 +997,7 @@ config BT_CTLR_SMI_TX_SETTING config BT_CTLR_HCI_CODEC_AND_DELAY_INFO bool "Codecs and controller delay information commands" + depends on BT_CTLR_HCI help Enable HCI commands to read information about supported codecs, codec capabilities, and controller delay. @@ -998,8 +1017,7 @@ config BT_CTLR_ASSERT_HANDLER config BT_CTLR_VS_SCAN_REQ_RX bool "Use scan request reporting" - depends on BT_HCI_VS_EXT && !BT_CTLR_ADV_EXT - select BT_HCI_VS_EVT + depends on BT_HCI_VS && !BT_CTLR_ADV_EXT select BT_CTLR_SCAN_REQ_NOTIFY help Enables usage of VS Scan Request Reports Command and Scan Request Received Event diff --git a/subsys/bluetooth/controller/Kconfig.df b/subsys/bluetooth/controller/Kconfig.df index 981d1b8f1fc..3f62ed8b4f1 100644 --- a/subsys/bluetooth/controller/Kconfig.df +++ b/subsys/bluetooth/controller/Kconfig.df @@ -312,8 +312,7 @@ endchoice config BT_CTLR_DF_VS_CL_IQ_REPORT_16_BITS_IQ_SAMPLES bool "Use 16 bits signed integer IQ samples in connectionless IQ reports" - depends on BT_CTLR_DF_SCAN_CTE_RX && BT_HCI_VS_EXT - select BT_HCI_VS_EVT + depends on BT_CTLR_DF_SCAN_CTE_RX && BT_HCI_VS help Direction Finging connectionless IQ reports provide a set of IQ samples collected during sampling of CTE. Bluetooth 5.3 Core Specification defines IQ samples to be 8 bits signed @@ -323,8 +322,7 @@ config BT_CTLR_DF_VS_CL_IQ_REPORT_16_BITS_IQ_SAMPLES config BT_CTLR_DF_VS_CONN_IQ_REPORT_16_BITS_IQ_SAMPLES bool "Use 16 bits signed integer IQ samples in connection IQ reports" - depends on BT_CTLR_DF_CONN_CTE_RX && BT_HCI_VS_EXT - select BT_HCI_VS_EVT + depends on BT_CTLR_DF_CONN_CTE_RX && BT_HCI_VS help Direction Finging connection IQ reports provide a set of IQ samples collected during sampling of CTE. Bluetooth 5.3 Core Specification defines IQ samples to be 8 bits signed diff --git a/subsys/bluetooth/controller/Kconfig.ll_sw_split b/subsys/bluetooth/controller/Kconfig.ll_sw_split index bce9b76186f..e4428929e35 100644 --- a/subsys/bluetooth/controller/Kconfig.ll_sw_split +++ b/subsys/bluetooth/controller/Kconfig.ll_sw_split @@ -341,9 +341,9 @@ config BT_CTLR_ADV_DATA_CHAIN bool "Advertising Data chaining [EXPERIMENTAL]" select EXPERIMENTAL help - Enable support for Advertising Data chaining in Extended and - Periodic Advertising. This will allow to have Advertising Data Length - upto 1650 bytes. + Enable support for Advertising Data chaining in Extended + (non-connectable) and Periodic Advertising. This will allow to have + Advertising Data Length up to 1650 bytes. This is experimental and work in progress, does not implement recombining the AD Data and could return BT_HCI_ERR_PACKET_TOO_LONG @@ -598,12 +598,34 @@ config BT_CTLR_DYNAMIC_INTERRUPTS permit use of SoC's peripheral for custom use when Bluetooth is not enabled. +choice + prompt "Optimization options" + depends on !LTO + default BT_CTLR_OPTIMIZE_FOR_SPEED + +config BT_CTLR_OPTIMIZE_FOR_APP_DEFAULT + bool "Optimize for application defaults" + help + Optimize compilation of Controller for application's default. + +config BT_CTLR_OPTIMIZE_FOR_SIZE + bool "Optimize for space" + help + Optimize compilation of Controller for code size. + + This is the Zephyr project default, but is overridden to use optimize + for speed when compiling the Controller to reduce application's ISR + and thread latencies. + config BT_CTLR_OPTIMIZE_FOR_SPEED - prompt "Optimize for Speed" if !(SOC_SERIES_NRF51X && BT_CTLR_LE_ENC) - bool - default y if BT_CTLR_LE_ENC + bool "Optimize for Speed" help - Optimize compilation of controller for execution speed. + Optimize compilation of Controller for execution speed. As the + Controller's Upper Link Layer and Lower Link Layer execute in ISRs, + use of speed optimizations reduces application's ISR and thread + latencies. + +endchoice config BT_CTLR_XTAL_ADVANCED bool "Advanced event preparation" @@ -671,6 +693,16 @@ config BT_CTLR_ASSERT_OVERHEAD_START otherwise leading to remote supervision timeout and possible missing local disconnect events. +config BT_CTLR_ASSERT_VENDOR + bool "Vendor Defined Assertion Information Handler" + help + This option enables a vendor specific sink for the controller assertion + mechanism, where parameter information is provided. This must be defined in + vendor debug HAL interface as \"BT_ASSERT_VND(cond, param1, param2)\", and + will be invoked whenever the controller code encounters an unrecoverable error + with parameter information. Implementation shall include the equivalent of + BT_ASSERT_DIE for halting the kernel. + config BT_CTLR_CENTRAL_SPACING int "Central Connection Spacing" depends on BT_CTLR_SCHED_ADVANCED @@ -1091,7 +1123,7 @@ config BT_TICKER_EXT config BT_TICKER_EXT_SLOT_WINDOW_YIELD bool "Tickers with slot window always yields" depends on BT_TICKER_EXT - default y if BT_CTLR_ADV_ISO + default y if BT_MESH || BT_CTLR_ADV_ISO help This options forces tickers with slot window extensions to yield to normal tickers and be placed at the end of their slot window. diff --git a/subsys/bluetooth/controller/hal/debug.h b/subsys/bluetooth/controller/hal/debug.h index 9f2fc3d0c95..653aa304b07 100644 --- a/subsys/bluetooth/controller/hal/debug.h +++ b/subsys/bluetooth/controller/hal/debug.h @@ -27,6 +27,18 @@ void bt_ctlr_assert_handle(char *file, uint32_t line); BT_ASSERT_MSG(cond, fmt, ##__VA_ARGS__) #endif +#if defined(CONFIG_BT_CTLR_ASSERT_VENDOR) +#define LL_ASSERT_INFO1(cond, param) \ + BT_ASSERT_VND(cond, param, 0) +#define LL_ASSERT_INFO2(cond, param1, param2) \ + BT_ASSERT_VND(cond, param1, param2) +#else +#define LL_ASSERT_INFO1(cond, param) \ + LL_ASSERT_MSG(cond, "param: %u", param) +#define LL_ASSERT_INFO2(cond, param1, param2) \ + LL_ASSERT_MSG(cond, "param1: %u param2: %u", param1, param2) +#endif /* CONFIG_BT_CTLR_ASSERT_VENDOR */ + #if defined(CONFIG_BT_CTLR_ASSERT_OVERHEAD_START) #define LL_ASSERT_OVERHEAD(overhead) \ LL_ASSERT_MSG(false, "%s: Actual EVENT_OVERHEAD_START_US = %u", \ diff --git a/subsys/bluetooth/controller/hci/hci.c b/subsys/bluetooth/controller/hci/hci.c index 2069d58094e..247a50959da 100644 --- a/subsys/bluetooth/controller/hci/hci.c +++ b/subsys/bluetooth/controller/hci/hci.c @@ -211,9 +211,9 @@ static uint32_t cis_pending_count; static uint64_t event_mask = DEFAULT_EVENT_MASK; static uint64_t event_mask_page_2 = DEFAULT_EVENT_MASK_PAGE_2; static uint64_t le_event_mask = DEFAULT_LE_EVENT_MASK; -#if defined(CONFIG_BT_HCI_VS_EVT) -static uint64_t vs_events_mask = DEFAULT_VS_EVT_MASK; -#endif /* CONFIG_BT_HCI_VS_EVT */ +#if defined(CONFIG_BT_HCI_VS) +__maybe_unused static uint64_t vs_events_mask = DEFAULT_VS_EVT_MASK; +#endif /* CONFIG_BT_HCI_VS */ static struct net_buf *cmd_complete_status(uint8_t status); @@ -339,8 +339,8 @@ static void *meta_evt(struct net_buf *buf, uint8_t subevt, uint8_t melen) return net_buf_add(buf, melen); } -#if defined(CONFIG_BT_HCI_VS_EVT) -static void *vs_event(struct net_buf *buf, uint8_t subevt, uint8_t evt_len) +#if defined(CONFIG_BT_HCI_VS) +__maybe_unused static void *vs_event(struct net_buf *buf, uint8_t subevt, uint8_t evt_len) { struct bt_hci_evt_vs *evt; @@ -350,7 +350,7 @@ static void *vs_event(struct net_buf *buf, uint8_t subevt, uint8_t evt_len) return net_buf_add(buf, evt_len); } -#endif /* CONFIG_BT_HCI_VS_EVT */ +#endif /* CONFIG_BT_HCI_VS */ #if defined(CONFIG_BT_HCI_MESH_EXT) static void *mesh_evt(struct net_buf *buf, uint8_t subevt, uint8_t melen) @@ -1398,7 +1398,7 @@ static void le_read_buffer_size_v2(struct net_buf *buf, struct net_buf **evt) rp->acl_max_len = sys_cpu_to_le16(LL_LENGTH_OCTETS_TX_MAX); rp->acl_max_num = CONFIG_BT_BUF_ACL_TX_COUNT; - rp->iso_max_len = sys_cpu_to_le16(CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE); + rp->iso_max_len = sys_cpu_to_le16(BT_CTLR_ISO_TX_BUFFER_SIZE); rp->iso_max_num = CONFIG_BT_CTLR_ISO_TX_BUFFERS; } #endif /* CONFIG_BT_CTLR_ADV_ISO || CONFIG_BT_CTLR_CONN_ISO */ @@ -2966,7 +2966,7 @@ static void le_df_connectionless_iq_report(struct pdu_data *pdu_rx, return; } - lll = iq_report->hdr.rx_ftr.param; + lll = iq_report->rx.rx_ftr.param; /* If there is not LLL context and CONFIG_BT_CTLR_DTM_HCI_DF_IQ_REPORT is enabled * the controller is in the Direct Test Mode and may generate @@ -3018,7 +3018,7 @@ static void le_df_connectionless_iq_report(struct pdu_data *pdu_rx, (sizeof(*sep) + (samples_cnt * sizeof(struct bt_hci_le_iq_sample)))); - rssi = RSSI_DBM_TO_DECI_DBM(iq_report->hdr.rx_ftr.rssi); + rssi = RSSI_DBM_TO_DECI_DBM(iq_report->rx.rx_ftr.rssi); sep->sync_handle = sys_cpu_to_le16(sync_handle); @@ -3116,7 +3116,7 @@ static void le_df_connection_iq_report(struct node_rx_pdu *node_rx, struct net_b return; } - lll = iq_report->hdr.rx_ftr.param; + lll = iq_report->rx.rx_ftr.param; #if defined(CONFIG_BT_CTLR_PHY) phy_rx = lll->phy_rx; @@ -3149,9 +3149,9 @@ static void le_df_connection_iq_report(struct node_rx_pdu *node_rx, struct net_b sep = meta_evt(buf, BT_HCI_EVT_LE_CONNECTION_IQ_REPORT, (sizeof(*sep) + (samples_cnt * sizeof(struct bt_hci_le_iq_sample)))); - rssi = RSSI_DBM_TO_DECI_DBM(iq_report->hdr.rx_ftr.rssi); + rssi = RSSI_DBM_TO_DECI_DBM(iq_report->rx.rx_ftr.rssi); - sep->conn_handle = sys_cpu_to_le16(iq_report->hdr.handle); + sep->conn_handle = sys_cpu_to_le16(iq_report->rx.hdr.handle); sep->rx_phy = phy_rx; sep->rssi = sys_cpu_to_le16(rssi); sep->rssi_ant_id = iq_report->rssi_ant_id; @@ -3439,6 +3439,15 @@ static void le_set_ext_adv_param(struct net_buf *buf, struct net_buf **evt) *evt = cmd_complete_status(BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL); return; } + + if ((cmd->prim_adv_phy > BT_HCI_LE_PHY_CODED) || + (cmd->sec_adv_phy > BT_HCI_LE_PHY_CODED) || + (!IS_ENABLED(CONFIG_BT_CTLR_PHY_CODED) && + ((cmd->prim_adv_phy == BT_HCI_LE_PHY_CODED) || + (cmd->sec_adv_phy == BT_HCI_LE_PHY_CODED)))) { + *evt = cmd_complete_status(BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL); + return; + } } status = ll_adv_set_by_hci_handle_get_or_new(cmd->handle, &handle); @@ -4096,6 +4105,15 @@ static void le_ext_create_connection(struct net_buf *buf, struct net_buf **evt) } phys = cmd->phys; + + /* Ignore Scan Interval and Scan Window, and ignore scanning if + * Initiating PHY is set for LE 2M PHY + * Refer to Bluetooth Core Specification Version 5.4 Vol 4, Part E + * 7.8.66 LE Extended Create Connection command + */ + phys &= ~BT_HCI_LE_EXT_SCAN_PHY_2M; + + /* Check if unsupported PHY requested for scanning */ if (IS_ENABLED(CONFIG_BT_CTLR_PARAM_CHECK) && (((phys & phys_bitmask) == 0) || (phys & ~phys_bitmask))) { *evt = cmd_status(BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL); @@ -4228,7 +4246,7 @@ static void le_cis_established(struct pdu_data *pdu_data, return; } - cis = node_rx->hdr.rx_ftr.param; + cis = node_rx->rx_ftr.param; cig = cis->group; sep = meta_evt(buf, BT_HCI_EVT_LE_CIS_ESTABLISHED, sizeof(*sep)); @@ -4770,16 +4788,6 @@ static int controller_cmd_handle(uint16_t ocf, struct net_buf *cmd, return 0; } -/* If Zephyr VS HCI commands are not enabled provide this functionality directly - */ -#if !defined(CONFIG_BT_HCI_VS_EXT) -uint8_t bt_read_static_addr(struct bt_hci_vs_static_addr addrs[], uint8_t size) -{ - return hci_vendor_read_static_addr(addrs, size); -} -#endif /* !defined(CONFIG_BT_HCI_VS_EXT) */ - - #if defined(CONFIG_BT_HCI_VS) static void vs_read_version_info(struct net_buf *buf, struct net_buf **evt) { @@ -4809,7 +4817,6 @@ static void vs_read_supported_commands(struct net_buf *buf, /* Set Version Information, Supported Commands, Supported Features. */ rp->commands[0] |= BIT(0) | BIT(1) | BIT(2); -#if defined(CONFIG_BT_HCI_VS_EXT) /* Write BD_ADDR, Read Build Info */ rp->commands[0] |= BIT(5) | BIT(7); /* Read Static Addresses, Read Key Hierarchy Roots */ @@ -4828,7 +4835,6 @@ static void vs_read_supported_commands(struct net_buf *buf, /* Set USB Transport Mode */ rp->commands[2] |= BIT(0); #endif /* USB_DEVICE_BLUETOOTH_VS_H4 */ -#endif /* CONFIG_BT_HCI_VS_EXT */ } static void vs_read_supported_features(struct net_buf *buf, @@ -4851,7 +4857,6 @@ uint8_t __weak hci_vendor_read_static_addr(struct bt_hci_vs_static_addr addrs[], return 0; } -#if defined(CONFIG_BT_HCI_VS_EXT) static void vs_write_bd_addr(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_cp_vs_write_bd_addr *cmd = (void *)buf->data; @@ -5149,7 +5154,7 @@ static void vs_le_df_connectionless_iq_report(struct pdu_data *pdu_rx, struct no return; } - lll = iq_report->hdr.rx_ftr.param; + lll = iq_report->rx.rx_ftr.param; sync = HDR_LLL2ULL(lll); @@ -5183,7 +5188,7 @@ static void vs_le_df_connectionless_iq_report(struct pdu_data *pdu_rx, struct no sep = vs_event(buf, BT_HCI_EVT_VS_LE_CONNECTIONLESS_IQ_REPORT, (sizeof(*sep) + (samples_cnt * sizeof(struct bt_hci_le_iq_sample16)))); - rssi = RSSI_DBM_TO_DECI_DBM(iq_report->hdr.rx_ftr.rssi); + rssi = RSSI_DBM_TO_DECI_DBM(iq_report->rx.rx_ftr.rssi); sep->sync_handle = sys_cpu_to_le16(sync_handle); sep->rssi = sys_cpu_to_le16(rssi); @@ -5235,7 +5240,7 @@ static void vs_le_df_connection_iq_report(struct node_rx_pdu *node_rx, struct ne return; } - lll = iq_report->hdr.rx_ftr.param; + lll = iq_report->rx.rx_ftr.param; #if defined(CONFIG_BT_CTLR_PHY) phy_rx = lll->phy_rx; @@ -5268,9 +5273,9 @@ static void vs_le_df_connection_iq_report(struct node_rx_pdu *node_rx, struct ne sep = vs_event(buf, BT_HCI_EVT_VS_LE_CONNECTION_IQ_REPORT, (sizeof(*sep) + (samples_cnt * sizeof(struct bt_hci_le_iq_sample16)))); - rssi = RSSI_DBM_TO_DECI_DBM(iq_report->hdr.rx_ftr.rssi); + rssi = RSSI_DBM_TO_DECI_DBM(iq_report->rx.rx_ftr.rssi); - sep->conn_handle = sys_cpu_to_le16(iq_report->hdr.handle); + sep->conn_handle = sys_cpu_to_le16(iq_report->rx.hdr.handle); sep->rx_phy = phy_rx; sep->rssi = sys_cpu_to_le16(rssi); sep->rssi_ant_id = iq_report->rssi_ant_id; @@ -5305,8 +5310,6 @@ static void vs_le_df_connection_iq_report(struct node_rx_pdu *node_rx, struct ne } #endif /* CONFIG_BT_CTLR_DF_VS_CONN_IQ_REPORT_16_BITS_IQ_SAMPLES */ -#endif /* CONFIG_BT_HCI_VS_EXT */ - #if defined(CONFIG_BT_HCI_MESH_EXT) static void mesh_get_opts(struct net_buf *buf, struct net_buf **evt) { @@ -5483,7 +5486,6 @@ int hci_vendor_cmd_handle_common(uint16_t ocf, struct net_buf *cmd, break; #endif /* CONFIG_USB_DEVICE_BLUETOOTH_VS_H4 */ -#if defined(CONFIG_BT_HCI_VS_EXT) case BT_OCF(BT_HCI_OP_VS_READ_BUILD_INFO): vs_read_build_info(cmd, evt); break; @@ -5521,7 +5523,6 @@ int hci_vendor_cmd_handle_common(uint16_t ocf, struct net_buf *cmd, vs_set_min_used_chans(cmd, evt); break; #endif /* CONFIG_BT_CTLR_MIN_USED_CHAN && CONFIG_BT_PERIPHERAL */ -#endif /* CONFIG_BT_HCI_VS_EXT */ #if defined(CONFIG_BT_HCI_MESH_EXT) case BT_OCF(BT_HCI_OP_VS_MESH): @@ -5691,7 +5692,7 @@ int hci_acl_handle(struct net_buf *buf, struct net_buf **evt) #if defined(CONFIG_BT_CTLR_ADV_ISO) || defined(CONFIG_BT_CTLR_CONN_ISO) int hci_iso_handle(struct net_buf *buf, struct net_buf **evt) { - struct bt_hci_iso_data_hdr *iso_data_hdr; + struct bt_hci_iso_sdu_hdr *iso_sdu_hdr; struct isoal_sdu_tx sdu_frag_tx; struct bt_hci_iso_hdr *iso_hdr; uint32_t *time_stamp; @@ -5701,7 +5702,7 @@ int hci_iso_handle(struct net_buf *buf, struct net_buf **evt) uint8_t flags; uint16_t len; - iso_data_hdr = NULL; + iso_sdu_hdr = NULL; *evt = NULL; if (buf->len < sizeof(*iso_hdr)) { @@ -5752,11 +5753,11 @@ int hci_iso_handle(struct net_buf *buf, struct net_buf **evt) /* Extract ISO data header if included (PB_Flag 0b00 or 0b10) */ if ((pb_flag & 0x01) == 0) { - iso_data_hdr = net_buf_pull_mem(buf, sizeof(*iso_data_hdr)); - len -= sizeof(*iso_data_hdr); - sdu_frag_tx.packet_sn = sys_le16_to_cpu(iso_data_hdr->sn); + iso_sdu_hdr = net_buf_pull_mem(buf, sizeof(*iso_sdu_hdr)); + len -= sizeof(*iso_sdu_hdr); + sdu_frag_tx.packet_sn = sys_le16_to_cpu(iso_sdu_hdr->sn); sdu_frag_tx.iso_sdu_length = - sys_le16_to_cpu(bt_iso_pkt_len(iso_data_hdr->slen)); + sys_le16_to_cpu(bt_iso_pkt_len(iso_sdu_hdr->slen)); } else { sdu_frag_tx.packet_sn = 0; sdu_frag_tx.iso_sdu_length = 0; @@ -5980,7 +5981,7 @@ int hci_iso_handle(struct net_buf *buf, struct net_buf **evt) ISO_INT_UNIT_US)); #else /* !CONFIG_BT_CTLR_ISOAL_PSN_IGNORE */ - uint8_t target_event; + uint64_t target_event; uint8_t event_offset; /* Determine the target event and the first event offset after @@ -6347,8 +6348,8 @@ static inline void le_mesh_scan_report(struct pdu_adv *adv, return; } - chan = node_rx->hdr.rx_ftr.chan; - instant = node_rx->hdr.rx_ftr.anchor_ticks; + chan = node_rx->rx_ftr.chan; + instant = node_rx->rx_ftr.anchor_ticks; mep = mesh_evt(buf, BT_HCI_EVT_MESH_SCANNING_REPORT, sizeof(*mep) + sizeof(*sr)); @@ -6386,12 +6387,12 @@ static void le_advertising_report(struct pdu_data *pdu_data, #endif /* CONFIG_BT_CTLR_EXT_SCAN_FP */ int8_t *prssi; - rssi = -(node_rx->hdr.rx_ftr.rssi); + rssi = -(node_rx->rx_ftr.rssi); #if defined(CONFIG_BT_CTLR_PRIVACY) - rl_idx = node_rx->hdr.rx_ftr.rl_idx; + rl_idx = node_rx->rx_ftr.rl_idx; #endif /* CONFIG_BT_CTLR_PRIVACY */ #if defined(CONFIG_BT_CTLR_EXT_SCAN_FP) - direct_report = node_rx->hdr.rx_ftr.direct; + direct_report = node_rx->rx_ftr.direct; #endif /* CONFIG_BT_CTLR_EXT_SCAN_FP */ #if defined(CONFIG_BT_CTLR_PRIVACY) @@ -6515,10 +6516,10 @@ static void le_ext_adv_legacy_report(struct pdu_data *pdu_data, } /* The Link Layer currently returns RSSI as an absolute value */ - rssi = -(node_rx->hdr.rx_ftr.rssi); + rssi = -(node_rx->rx_ftr.rssi); #if defined(CONFIG_BT_CTLR_PRIVACY) - rl_idx = node_rx->hdr.rx_ftr.rl_idx; + rl_idx = node_rx->rx_ftr.rl_idx; #endif /* CONFIG_BT_CTLR_PRIVACY */ #if defined(CONFIG_BT_CTLR_PRIVACY) @@ -6712,7 +6713,7 @@ static void node_rx_extra_list_release(struct node_rx_pdu *node_rx_extra) struct node_rx_pdu *node_rx_curr; node_rx_curr = node_rx_extra; - node_rx_extra = node_rx_curr->hdr.rx_ftr.extra; + node_rx_extra = node_rx_curr->rx_ftr.extra; node_rx_curr->hdr.next = NULL; ll_rx_mem_release((void **)&node_rx_curr); @@ -6841,7 +6842,7 @@ static void ext_adv_data_frag(const struct node_rx_pdu *node_rx_data, data, buf, evt_buf); /* Check if more PDUs in the list */ - node_rx_data = node_rx_data->hdr.rx_ftr.extra; + node_rx_data = node_rx_data->rx_ftr.extra; if (node_rx_data) { if (*data_len >= data_len_total) { /* Last fragment restricted to maximum scan @@ -6918,7 +6919,7 @@ static void le_ext_adv_report(struct pdu_data *pdu_data, */ if (!(event_mask & BT_EVT_MASK_LE_META_EVENT) || !(le_event_mask & BT_EVT_MASK_LE_EXT_ADVERTISING_REPORT)) { - node_rx_extra_list_release(node_rx->hdr.rx_ftr.extra); + node_rx_extra_list_release(node_rx->rx_ftr.extra); return; } @@ -6928,7 +6929,7 @@ static void le_ext_adv_report(struct pdu_data *pdu_data, adv = (void *)pdu_data; node_rx_curr = node_rx; - node_rx_next = node_rx_curr->hdr.rx_ftr.extra; + node_rx_next = node_rx_curr->rx_ftr.extra; do { int8_t tx_pwr_curr = BT_HCI_LE_ADV_TX_POWER_NO_PREF; struct pdu_adv_adi *adi_curr = NULL; @@ -6948,22 +6949,22 @@ static void le_ext_adv_report(struct pdu_data *pdu_data, uint8_t *ptr; #if defined(CONFIG_BT_CTLR_EXT_SCAN_FP) - bool direct_report_curr = node_rx_curr->hdr.rx_ftr.direct; + bool direct_report_curr = node_rx_curr->rx_ftr.direct; #endif /* CONFIG_BT_CTLR_EXT_SCAN_FP */ #if defined(CONFIG_BT_CTLR_PRIVACY) - uint8_t rl_idx_curr = node_rx_curr->hdr.rx_ftr.rl_idx; + uint8_t rl_idx_curr = node_rx_curr->rx_ftr.rl_idx; - direct_resolved_curr = node_rx_curr->hdr.rx_ftr.direct_resolved; + direct_resolved_curr = node_rx_curr->rx_ftr.direct_resolved; #endif /* CONFIG_BT_CTLR_PRIVACY */ #if defined(CONFIG_BT_CTLR_SYNC_PERIODIC) && \ defined(CONFIG_BT_CTLR_FILTER_ACCEPT_LIST) - const bool devmatch_curr = node_rx_curr->hdr.rx_ftr.devmatch; + const bool devmatch_curr = node_rx_curr->rx_ftr.devmatch; #endif /* CONFIG_BT_CTLR_SYNC_PERIODIC && CONFIG_BT_CTLR_FILTER_ACCEPT_LIST */ /* The Link Layer currently returns RSSI as an absolute value */ - rssi = -(node_rx_curr->hdr.rx_ftr.rssi); + rssi = -(node_rx_curr->rx_ftr.rssi); LOG_DBG("phy= 0x%x, type= 0x%x, len= %u, tat= %u, rat= %u," " rssi=%d dB", phy, adv->type, adv->len, adv->tx_addr, @@ -6988,7 +6989,7 @@ static void le_ext_adv_report(struct pdu_data *pdu_data, if (h->adv_addr) { /* AdvA is RFU in AUX_CHAIN_IND */ if (node_rx_curr == node_rx || - node_rx_curr == node_rx->hdr.rx_ftr.extra) { + node_rx_curr == node_rx->rx_ftr.extra) { bt_addr_le_t addr; adv_addr_type_curr = adv->tx_addr; @@ -7006,11 +7007,11 @@ static void le_ext_adv_report(struct pdu_data *pdu_data, if (h->tgt_addr) { /* TargetA is RFU in AUX_CHAIN_IND */ if (node_rx_curr == node_rx || - node_rx_curr == node_rx->hdr.rx_ftr.extra) { + node_rx_curr == node_rx->rx_ftr.extra) { struct lll_scan *lll; bt_addr_le_t addr; - lll = node_rx->hdr.rx_ftr.param; + lll = node_rx->rx_ftr.param; #if defined(CONFIG_BT_CTLR_EXT_SCAN_FP) direct_addr_type_curr = @@ -7056,7 +7057,7 @@ static void le_ext_adv_report(struct pdu_data *pdu_data, struct pdu_adv_aux_ptr *aux_ptr; /* AuxPtr is RFU for connectable or scannable AUX_ADV_IND */ - if (node_rx_curr != node_rx->hdr.rx_ftr.extra || + if (node_rx_curr != node_rx->rx_ftr.extra || evt_type_curr == 0U) { uint8_t aux_phy; @@ -7071,7 +7072,7 @@ static void le_ext_adv_report(struct pdu_data *pdu_data, PDU_ADV_AUX_PTR_PHY_GET(aux_ptr) > EXT_ADV_AUX_PHY_LE_CODED) { struct node_rx_ftr *ftr; - ftr = &node_rx->hdr.rx_ftr; + ftr = &node_rx->rx_ftr; node_rx_extra_list_release(ftr->extra); return; } @@ -7190,7 +7191,7 @@ static void le_ext_adv_report(struct pdu_data *pdu_data, /* TODO: Validate current value with previous */ /* Detect the scan response in the list of node_rx */ - if (node_rx_curr->hdr.rx_ftr.scan_rsp) { + if (node_rx_curr->rx_ftr.scan_rsp) { node_rx_scan_data = node_rx_curr; if (sec_phy_curr) { sec_phy_scan = sec_phy_curr; @@ -7255,14 +7256,14 @@ static void le_ext_adv_report(struct pdu_data *pdu_data, } node_rx_curr = node_rx_next; - node_rx_next = node_rx_curr->hdr.rx_ftr.extra; + node_rx_next = node_rx_curr->rx_ftr.extra; adv = (void *)node_rx_curr->pdu; } while (1); if (IS_ENABLED(CONFIG_BT_CTLR_SYNC_PERIODIC) && IS_ENABLED(CONFIG_BT_CTLR_FILTER_ACCEPT_LIST) && !devmatch) { - node_rx_extra_list_release(node_rx->hdr.rx_ftr.extra); + node_rx_extra_list_release(node_rx->rx_ftr.extra); return; } @@ -7271,7 +7272,7 @@ static void le_ext_adv_report(struct pdu_data *pdu_data, if (dup_scan && dup_found(PDU_ADV_TYPE_EXT_IND, adv_addr_type, adv_addr, (evt_type & BIT_MASK(2)), adi, data_status)) { - node_rx_extra_list_release(node_rx->hdr.rx_ftr.extra); + node_rx_extra_list_release(node_rx->rx_ftr.extra); return; } } @@ -7290,7 +7291,7 @@ static void le_ext_adv_report(struct pdu_data *pdu_data, * is present or if Tx pwr and/or data is present from * anonymous device. */ - node_rx_extra_list_release(node_rx->hdr.rx_ftr.extra); + node_rx_extra_list_release(node_rx->rx_ftr.extra); return; } } @@ -7329,7 +7330,7 @@ static void le_ext_adv_report(struct pdu_data *pdu_data, /* If scan response event to be constructed */ if (!scan_data) { - node_rx_extra_list_release(node_rx->hdr.rx_ftr.extra); + node_rx_extra_list_release(node_rx->rx_ftr.extra); return; } @@ -7370,7 +7371,7 @@ static void le_ext_adv_report(struct pdu_data *pdu_data, scan_rsp_tx_pwr, rssi, interval_le16, adi, scan_data_len, scan_data, evt_buf); - node_rx_extra_list_release(node_rx->hdr.rx_ftr.extra); + node_rx_extra_list_release(node_rx->rx_ftr.extra); } static void le_adv_ext_report(struct pdu_data *pdu_data, @@ -7449,7 +7450,7 @@ static void le_per_adv_sync_established(struct pdu_data *pdu_data, return; } - scan = node_rx->hdr.rx_ftr.param; + scan = node_rx->rx_ftr.param; #if (CONFIG_BT_CTLR_DUP_FILTER_LEN > 0) && \ defined(CONFIG_BT_CTLR_SYNC_PERIODIC_ADI_SUPPORT) @@ -7476,7 +7477,7 @@ static void le_per_adv_sync_report(struct pdu_data *pdu_data, struct node_rx_pdu *node_rx, struct net_buf *buf) { - struct node_rx_ftr *ftr = &node_rx->hdr.rx_ftr; + struct node_rx_ftr *ftr = &node_rx->rx_ftr; int8_t tx_pwr = BT_HCI_LE_ADV_TX_POWER_NO_PREF; struct pdu_adv *adv = (void *)pdu_data; struct pdu_adv_aux_ptr *aux_ptr = NULL; @@ -7520,10 +7521,10 @@ static void le_per_adv_sync_report(struct pdu_data *pdu_data, return; } - data_len_total = node_rx->hdr.rx_ftr.aux_data_len; + data_len_total = ftr->aux_data_len; if ((le_event_mask & BT_EVT_MASK_LE_PER_ADVERTISING_REPORT) && - (node_rx->hdr.rx_ftr.aux_failed || data_len_total > CONFIG_BT_CTLR_SCAN_DATA_LEN_MAX)) { + (ftr->aux_failed || data_len_total > CONFIG_BT_CTLR_SCAN_DATA_LEN_MAX)) { struct bt_hci_evt_le_per_advertising_report *sep; sep = meta_evt(buf, @@ -7541,7 +7542,7 @@ static void le_per_adv_sync_report(struct pdu_data *pdu_data, } /* The Link Layer currently returns RSSI as an absolute value */ - rssi = -(node_rx->hdr.rx_ftr.rssi); + rssi = -(ftr->rssi); LOG_DBG("len = %u, rssi = %d", adv->len, rssi); @@ -7844,7 +7845,7 @@ static void le_big_sync_established(struct pdu_data *pdu, return; } - sync_iso = node_rx->hdr.rx_ftr.param; + sync_iso = node_rx->rx_ftr.param; lll = &sync_iso->lll; evt_size = sizeof(*sep) + (lll->num_bis * sizeof(uint16_t)); @@ -7918,12 +7919,12 @@ static void le_adv_ext_terminate(struct pdu_data *pdu_data, } sep = meta_evt(buf, BT_HCI_EVT_LE_ADV_SET_TERMINATED, sizeof(*sep)); - sep->status = node_rx->hdr.rx_ftr.param_adv_term.status; + sep->status = node_rx->rx_ftr.param_adv_term.status; sep->adv_handle = ll_adv_set_hci_handle_get(node_rx->hdr.handle & 0xff); sep->conn_handle = - sys_cpu_to_le16(node_rx->hdr.rx_ftr.param_adv_term.conn_handle); + sys_cpu_to_le16(node_rx->rx_ftr.param_adv_term.conn_handle); sep->num_completed_ext_adv_evts = - node_rx->hdr.rx_ftr.param_adv_term.num_events; + node_rx->rx_ftr.param_adv_term.num_events; } #if defined(CONFIG_BT_CTLR_ADV_ISO) @@ -7936,7 +7937,7 @@ static void le_big_complete(struct pdu_data *pdu_data, struct lll_adv_iso *lll; size_t evt_size; - adv_iso = node_rx->hdr.rx_ftr.param; + adv_iso = node_rx->rx_ftr.param; lll = &adv_iso->lll; evt_size = sizeof(*sep) + (lll->num_bis * sizeof(uint16_t)); @@ -8015,7 +8016,7 @@ static void le_scan_req_received(struct pdu_data *pdu_data, sizeof(bt_addr_t)); /* The Link Layer currently returns RSSI as an absolute value */ - rssi = -(node_rx->hdr.rx_ftr.rssi); + rssi = -(node_rx->rx_ftr.rssi); LOG_DBG("handle: %d, addr: %s, rssi: %d dB.", handle, bt_addr_le_str(&addr), rssi); @@ -8029,7 +8030,7 @@ static void le_scan_req_received(struct pdu_data *pdu_data, sizeof(bt_addr_t)); #if defined(CONFIG_BT_CTLR_PRIVACY) - rl_idx = node_rx->hdr.rx_ftr.rl_idx; + rl_idx = node_rx->rx_ftr.rl_idx; if (rl_idx < ll_rl_size_get()) { /* Store identity address */ ll_rl_id_addr_get(rl_idx, &sep->addr.type, @@ -8069,7 +8070,7 @@ static void le_vs_scan_req_received(struct pdu_data *pdu, sizeof(bt_addr_t)); #if defined(CONFIG_BT_CTLR_PRIVACY) - rl_idx = node_rx->hdr.rx_ftr.rl_idx; + rl_idx = node_rx->rx_ftr.rl_idx; if (rl_idx < ll_rl_size_get()) { /* Store identity address */ ll_rl_id_addr_get(rl_idx, &sep->addr.type, @@ -8086,7 +8087,7 @@ static void le_vs_scan_req_received(struct pdu_data *pdu, } /* The Link Layer currently returns RSSI as an absolute value */ - sep->rssi = -(node_rx->hdr.rx_ftr.rssi); + sep->rssi = -(node_rx->rx_ftr.rssi); } #endif /* CONFIG_BT_CTLR_VS_SCAN_REQ_RX */ #endif /* CONFIG_BT_CTLR_SCAN_REQ_NOTIFY */ diff --git a/subsys/bluetooth/controller/hci/hci_driver.c b/subsys/bluetooth/controller/hci/hci_driver.c index 9c66594bcda..f174ca02c72 100644 --- a/subsys/bluetooth/controller/hci/hci_driver.c +++ b/subsys/bluetooth/controller/hci/hci_driver.c @@ -138,7 +138,7 @@ static int bt_recv_prio(struct net_buf *buf) #if defined(CONFIG_BT_CTLR_ISO) -#define SDU_HCI_HDR_SIZE (BT_HCI_ISO_HDR_SIZE + BT_HCI_ISO_TS_DATA_HDR_SIZE) +#define SDU_HCI_HDR_SIZE (BT_HCI_ISO_HDR_SIZE + BT_HCI_ISO_SDU_TS_HDR_SIZE) isoal_status_t sink_sdu_alloc_hci(const struct isoal_sink *sink_ctx, const struct isoal_pdu_rx *valid_pdu, @@ -167,7 +167,7 @@ isoal_status_t sink_sdu_emit_hci(const struct isoal_sink *sink_ctx, const struct isoal_emitted_sdu_frag *sdu_frag, const struct isoal_emitted_sdu *sdu) { - struct bt_hci_iso_ts_data_hdr *data_hdr; + struct bt_hci_iso_sdu_ts_hdr *sdu_hdr; uint16_t packet_status_flag; struct bt_hci_iso_hdr *hdr; uint16_t handle_packed; @@ -230,14 +230,14 @@ isoal_status_t sink_sdu_emit_hci(const struct isoal_sink *sink_ctx, ts = (pb & 0x1) == 0x0; if (ts) { - data_hdr = net_buf_push(buf, BT_HCI_ISO_TS_DATA_HDR_SIZE); + sdu_hdr = net_buf_push(buf, BT_HCI_ISO_SDU_TS_HDR_SIZE); slen_packed = bt_iso_pkt_len_pack(total_len, packet_status_flag); - data_hdr->ts = sys_cpu_to_le32((uint32_t) sdu_frag->sdu.timestamp); - data_hdr->data.sn = sys_cpu_to_le16((uint16_t) sdu_frag->sdu.sn); - data_hdr->data.slen = sys_cpu_to_le16(slen_packed); + sdu_hdr->ts = sys_cpu_to_le32((uint32_t) sdu_frag->sdu.timestamp); + sdu_hdr->sdu.sn = sys_cpu_to_le16((uint16_t) sdu_frag->sdu.sn); + sdu_hdr->sdu.slen = sys_cpu_to_le16(slen_packed); - len += BT_HCI_ISO_TS_DATA_HDR_SIZE; + len += BT_HCI_ISO_SDU_TS_HDR_SIZE; } hdr = net_buf_push(buf, BT_HCI_ISO_HDR_SIZE); @@ -256,9 +256,12 @@ isoal_status_t sink_sdu_emit_hci(const struct isoal_sink *sink_ctx, } isoal_status_t sink_sdu_write_hci(void *dbuf, + const size_t sdu_written, const uint8_t *pdu_payload, const size_t consume_len) { + ARG_UNUSED(sdu_written); + struct net_buf *buf = (struct net_buf *) dbuf; LL_ASSERT(buf); @@ -462,7 +465,7 @@ static inline struct net_buf *encode_node(struct node_rx_pdu *node_rx, if (dp && dp->path_id == BT_HCI_DATAPATH_ID_HCI) { /* If HCI datapath pass to ISO AL here */ struct isoal_pdu_rx pckt_meta = { - .meta = &node_rx->hdr.rx_iso_meta, + .meta = &node_rx->rx_iso_meta, .pdu = (void *)&node_rx->pdu[0], }; @@ -491,7 +494,7 @@ static inline struct net_buf *encode_node(struct node_rx_pdu *node_rx, */ if (stream && stream->dp && (stream->dp->path_id == BT_HCI_DATAPATH_ID_HCI)) { - isoal_rx.meta = &node_rx->hdr.rx_iso_meta; + isoal_rx.meta = &node_rx->rx_iso_meta; isoal_rx.pdu = (void *)node_rx->pdu; err = isoal_rx_pdu_recombine(stream->dp->sink_hdl, &isoal_rx); diff --git a/subsys/bluetooth/controller/include/ll_feat.h b/subsys/bluetooth/controller/include/ll_feat.h index 1eb2d86a1c3..15e4eacd966 100644 --- a/subsys/bluetooth/controller/include/ll_feat.h +++ b/subsys/bluetooth/controller/include/ll_feat.h @@ -189,10 +189,23 @@ #define LL_FEAT_BIT_CIS_PERIPHERAL 0 #endif /* !CONFIG_BT_CTLR_PERIPHERAL_ISO */ +#if defined(CONFIG_BT_CTLR_ADV_ISO) || defined(CONFIG_BT_CTLR_CONN_ISO) +#if defined(CONFIG_BT_ISO_TX_MTU) +#define BT_CTLR_ISO_TX_BUFFER_SIZE MIN((CONFIG_BT_ISO_TX_MTU + \ + BT_HCI_ISO_SDU_TS_HDR_SIZE), \ + MAX(CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE, \ + (BT_HCI_ISO_SDU_TS_HDR_SIZE + 1U))) +#else +#define BT_CTLR_ISO_TX_BUFFER_SIZE MAX(CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE, \ + (BT_HCI_ISO_SDU_TS_HDR_SIZE + 1U)) +#endif /* CONFIG_BT_ISO_TX_MTU */ +#endif /* CONFIG_BT_CTLR_ADV_ISO || CONFIG_BT_CTLR_CONN_ISO */ + #if defined(CONFIG_BT_CTLR_CENTRAL_ISO) || \ defined(CONFIG_BT_CTLR_PERIPHERAL_ISO) #define LL_CIS_OCTETS_TX_MAX MIN(CONFIG_BT_CTLR_CONN_ISO_PDU_LEN_MAX, \ - CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE) + (BT_CTLR_ISO_TX_BUFFER_SIZE - \ + BT_HCI_ISO_SDU_TS_HDR_SIZE)) #define LL_CIS_OCTETS_RX_MAX CONFIG_BT_CTLR_CONN_ISO_PDU_LEN_MAX #else /* !CONFIG_BT_CTLR_CENTRAL_ISO && !CONFIG_BT_CTLR_PERIPHERAL_ISO */ #define LL_CIS_OCTETS_TX_MAX 0 @@ -202,7 +215,8 @@ #if defined(CONFIG_BT_CTLR_ADV_ISO) #define LL_FEAT_BIT_ISO_BROADCASTER BIT64(BT_LE_FEAT_BIT_ISO_BROADCASTER) #define LL_BIS_OCTETS_TX_MAX MIN(CONFIG_BT_CTLR_ADV_ISO_PDU_LEN_MAX, \ - CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE) + (BT_CTLR_ISO_TX_BUFFER_SIZE - \ + BT_HCI_ISO_SDU_TS_HDR_SIZE)) #else /* !CONFIG_BT_CTLR_ADV_ISO */ #define LL_FEAT_BIT_ISO_BROADCASTER 0 #define LL_BIS_OCTETS_TX_MAX 0 diff --git a/subsys/bluetooth/controller/ll_sw/isoal.c b/subsys/bluetooth/controller/ll_sw/isoal.c index 48ad0835074..ff06068a8e6 100644 --- a/subsys/bluetooth/controller/ll_sw/isoal.c +++ b/subsys/bluetooth/controller/ll_sw/isoal.c @@ -694,6 +694,7 @@ static isoal_status_t isoal_rx_append_to_sdu(struct isoal_sink *sink, const struct isoal_sink_session *session = &sink->session; err |= session->sdu_write(sdu->contents.dbuf, + sp->sdu_written, pdu_payload, consume_len); pdu_payload += consume_len; diff --git a/subsys/bluetooth/controller/ll_sw/isoal.h b/subsys/bluetooth/controller/ll_sw/isoal.h index 61d3773c43d..0e50bea63be 100644 --- a/subsys/bluetooth/controller/ll_sw/isoal.h +++ b/subsys/bluetooth/controller/ll_sw/isoal.h @@ -242,6 +242,8 @@ typedef isoal_status_t (*isoal_sink_sdu_emit_cb)( typedef isoal_status_t (*isoal_sink_sdu_write_cb)( /*!< [in] Destination buffer */ void *dbuf, + /*!< [in] Number of bytes already written to this SDU */ + const size_t sdu_written, /*!< [in] Source data */ const uint8_t *pdu_payload, /*!< [in] Number of bytes to be copied */ @@ -450,6 +452,7 @@ isoal_status_t sink_sdu_emit_hci(const struct isoal_sink *sink_ctx, const struct isoal_emitted_sdu_frag *sdu_frag, const struct isoal_emitted_sdu *sdu); isoal_status_t sink_sdu_write_hci(void *dbuf, + const size_t sdu_written, const uint8_t *pdu_payload, const size_t consume_len); diff --git a/subsys/bluetooth/controller/ll_sw/lll.h b/subsys/bluetooth/controller/ll_sw/lll.h index d2e23a5a7bb..7c8aadf5efa 100644 --- a/subsys/bluetooth/controller/ll_sw/lll.h +++ b/subsys/bluetooth/controller/ll_sw/lll.h @@ -409,11 +409,19 @@ struct node_rx_hdr { memq_link_t *link; /* Supply memq_link from ULL to LLL */ uint8_t ack_last; /* Tx ack queue index at this node rx */ }; - enum node_rx_type type; uint8_t user_meta; /* User metadata */ uint16_t handle; /* State/Role instance handle */ +}; + +/* Template node rx type with memory aligned offset to PDU buffer. + * NOTE: offset to memory aligned pdu buffer location is used to reference + * node rx type specific information, like, terminate or sync lost reason + * from a dedicated node rx structure storage location. + */ +struct node_rx_pdu { + struct node_rx_hdr hdr; union { struct node_rx_ftr rx_ftr; #if defined(CONFIG_BT_CTLR_SYNC_ISO) || defined(CONFIG_BT_CTLR_CONN_ISO) @@ -423,15 +431,6 @@ struct node_rx_hdr { lll_rx_pdu_meta_t rx_pdu_meta; #endif /* CONFIG_BT_CTLR_RX_PDU_META */ }; -}; - -/* Template node rx type with memory aligned offset to PDU buffer. - * NOTE: offset to memory aligned pdu buffer location is used to reference - * node rx type specific information, like, terminate or sync lost reason - * from a dedicated node rx structure storage location. - */ -struct node_rx_pdu { - struct node_rx_hdr hdr; union { uint8_t pdu[0] __aligned(4); }; @@ -504,6 +503,9 @@ struct event_done_extra { struct { uint16_t trx_cnt; uint8_t crc_valid:1; +#if defined(CONFIG_BT_CTLR_SYNC_ISO) + uint8_t estab_failed:1; +#endif /* CONFIG_BT_CTLR_SYNC_ISO */ #if defined(CONFIG_BT_CTLR_SYNC_PERIODIC_CTE_TYPE_FILTERING) && \ defined(CONFIG_BT_CTLR_CTEINLINE_SUPPORT) /* Used to inform ULL that periodic diff --git a/subsys/bluetooth/controller/ll_sw/lll_adv.h b/subsys/bluetooth/controller/ll_sw/lll_adv.h index 2b55bee7f0d..eac2d4dcb26 100644 --- a/subsys/bluetooth/controller/ll_sw/lll_adv.h +++ b/subsys/bluetooth/controller/ll_sw/lll_adv.h @@ -195,7 +195,7 @@ struct lll_adv { struct lll_adv_pdu scan_rsp; #if defined(CONFIG_BT_CTLR_ADV_EXT) - struct node_rx_hdr *node_rx_adv_term; + struct node_rx_pdu *node_rx_adv_term; struct lll_adv_aux *aux; #if defined(CONFIG_BT_CTLR_ADV_PERIODIC) diff --git a/subsys/bluetooth/controller/ll_sw/lll_sync_iso.h b/subsys/bluetooth/controller/ll_sw/lll_sync_iso.h index c81d7d21e00..4038a04486e 100644 --- a/subsys/bluetooth/controller/ll_sw/lll_sync_iso.h +++ b/subsys/bluetooth/controller/ll_sw/lll_sync_iso.h @@ -55,6 +55,8 @@ struct lll_sync_iso { uint8_t stream_curr:5; + uint8_t establish_events:3; + uint8_t next_chan_use; /* Encryption */ diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio.c b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio.c index 71b8f3c4c79..9d5357fba8b 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio.c @@ -390,7 +390,7 @@ void radio_aa_set(const uint8_t *aa) NRF_RADIO->RXADDRESSES = ((RADIO_RXADDRESSES_ADDR0_Enabled) << RADIO_RXADDRESSES_ADDR0_Pos); NRF_RADIO->PREFIX0 = aa[3]; - NRF_RADIO->BASE0 = (aa[2] << 24) | (aa[1] << 16) | (aa[0] << 8); + NRF_RADIO->BASE0 = (((uint32_t) aa[2]) << 24) | (aa[1] << 16) | (aa[0] << 8); } void radio_pkt_configure(uint8_t bits_len, uint8_t max_len, uint8_t flags) diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/ticker.h b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/ticker.h index 10d780a559c..1a5c1a3f8a7 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/ticker.h +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/ticker.h @@ -68,8 +68,9 @@ HAL_TICKER_TICKS_TO_US(HAL_TICKER_PSEC_PER_USEC) /* Macro defining the margin for positioning re-scheduled nodes */ +#define HAL_TICKER_RESCHEDULE_MARGIN_US 150U #define HAL_TICKER_RESCHEDULE_MARGIN \ - HAL_TICKER_US_TO_TICKS(150) + HAL_TICKER_US_TO_TICKS(HAL_TICKER_RESCHEDULE_MARGIN_US) /* Remove ticks and return positive remainder value in microseconds */ static inline void hal_ticker_remove_jitter(uint32_t *ticks, diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c index ed459c20d19..6aec56a0ab4 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c @@ -719,6 +719,7 @@ int lll_prepare_resolve(lll_is_abort_cb_t is_abort_cb, lll_abort_cb_t abort_cb, struct lll_prepare_param *prepare_param, uint8_t is_resume, uint8_t is_dequeue) { + struct lll_event *ready_short = NULL; struct lll_event *ready; struct lll_event *next; uint8_t idx; @@ -728,9 +729,35 @@ int lll_prepare_resolve(lll_is_abort_cb_t is_abort_cb, lll_abort_cb_t abort_cb, idx = UINT8_MAX; ready = prepare_dequeue_iter_ready_get(&idx); + /* Find any short prepare */ + if (ready) { + uint32_t ticks_at_preempt_min = ready->prepare_param.ticks_at_expire; + + do { + uint32_t ticks_at_preempt_next; + struct lll_event *ready_next; + uint32_t diff; + + ready_next = prepare_dequeue_iter_ready_get(&idx); + if (!ready_next) { + break; + } + + ticks_at_preempt_next = ready_next->prepare_param.ticks_at_expire; + diff = ticker_ticks_diff_get(ticks_at_preempt_next, + ticks_at_preempt_min); + if ((diff & BIT(HAL_TICKER_CNTR_MSBIT)) == 0U) { + continue; + } + + ready_short = ready_next; + ticks_at_preempt_min = ticks_at_preempt_next; + } while (true); + } + /* Current event active or another prepare is ready in the pipeline */ if ((!is_dequeue && !is_done_sync()) || - event.curr.abort_cb || + event.curr.abort_cb || ready_short || (ready && is_resume)) { #if defined(CONFIG_BT_CTLR_LOW_LAT) lll_prepare_cb_t resume_cb; @@ -751,6 +778,11 @@ int lll_prepare_resolve(lll_is_abort_cb_t is_abort_cb, lll_abort_cb_t abort_cb, return -EINPROGRESS; } + /* Find any short prepare */ + if (ready_short) { + ready = ready_short; + } + /* Always start preempt timeout for first prepare in pipeline */ struct lll_event *first = ready ? ready : next; uint32_t ret; @@ -898,11 +930,21 @@ static uint8_t volatile preempt_ack; static void ticker_stop_op_cb(uint32_t status, void *param) { ARG_UNUSED(param); - ARG_UNUSED(status); LL_ASSERT(preempt_stop_req != preempt_stop_ack); preempt_stop_ack = preempt_stop_req; + /* We do not fail on status not being success because under scenarios + * where there is ticker_start then ticker_stop and then ticker_start, + * the call to ticker_stop will fail and this is acceptable. + * Also, the preempt_req and preempt_ack would not be update as the + * ticker_start was not processed before ticker_stop. Hence, it is + * safe to reset preempt_req and preempt_ack here. + */ + if (status == TICKER_STATUS_SUCCESS) { + LL_ASSERT(preempt_req != preempt_ack); + } + preempt_req = preempt_ack; } @@ -945,13 +987,6 @@ static uint32_t preempt_ticker_start(struct lll_event *first, (preempt_req != preempt_ack)) { uint32_t diff; - /* preempt timeout already started but no role/state in the head - * of prepare pipeline. - */ - if (!prev || prev->is_aborted) { - return TICKER_STATUS_SUCCESS; - } - /* Calc the preempt timeout */ p = &next->prepare_param; ull = HDR_LLL2ULL(p->param); @@ -985,14 +1020,20 @@ static uint32_t preempt_ticker_start(struct lll_event *first, * A proper solution will be to re-design the pipeline * as a ordered list, instead of the current FIFO. */ - /* Set early as we get called again through the call to - * abort_cb(). + /* preempt timeout already started but no role/state in the head + * of prepare pipeline. */ - ticks_at_preempt = ticks_at_preempt_new; - - /* Abort previous prepare that set the preempt timeout */ - prev->is_aborted = 1U; - prev->abort_cb(&prev->prepare_param, prev->prepare_param.param); + if (prev && !prev->is_aborted) { + /* Set early as we get called again through the call to + * abort_cb(). + */ + ticks_at_preempt = ticks_at_preempt_new; + + /* Abort previous prepare that set the preempt timeout */ + prev->is_aborted = 1U; + prev->abort_cb(&prev->prepare_param, + prev->prepare_param.param); + } #endif /* CONFIG_BT_CTLR_EARLY_ABORT_PREVIOUS_PREPARE */ /* Schedule short preempt timeout */ @@ -1136,6 +1177,8 @@ static void preempt(void *param) /* No ready prepare */ return; } + + LL_ASSERT(ready->prepare_param.param == param); } /* Check if current event want to continue */ diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv.c index 25c08568480..d025f4b3126 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv.c @@ -725,10 +725,10 @@ int lll_adv_scan_req_report(struct lll_adv *lll, struct pdu_adv *pdu_adv_rx, node_rx->hdr.type = NODE_RX_TYPE_SCAN_REQ; node_rx->hdr.handle = ull_adv_lll_handle_get(lll); - node_rx->hdr.rx_ftr.rssi = (rssi_ready) ? radio_rssi_get() : + node_rx->rx_ftr.rssi = (rssi_ready) ? radio_rssi_get() : BT_HCI_LE_RSSI_NOT_AVAILABLE; #if defined(CONFIG_BT_CTLR_PRIVACY) - node_rx->hdr.rx_ftr.rl_idx = rl_idx; + node_rx->rx_ftr.rl_idx = rl_idx; #endif ull_rx_put_sched(node_rx->hdr.link, node_rx); @@ -1387,15 +1387,15 @@ static void isr_done(void *param) } #if defined(CONFIG_BT_CTLR_ADV_INDICATION) - struct node_rx_hdr *node_rx = ull_pdu_rx_alloc_peek(3); + struct node_rx_pdu *node_rx = ull_pdu_rx_alloc_peek(3); if (node_rx) { ull_pdu_rx_alloc(); /* TODO: add other info by defining a payload struct */ - node_rx->type = NODE_RX_TYPE_ADV_INDICATION; + node_rx->hdr.type = NODE_RX_TYPE_ADV_INDICATION; - ull_rx_put_sched(node_rx->link, node_rx); + ull_rx_put_sched(node_rx->hdr.link, node_rx); } #endif /* CONFIG_BT_CTLR_ADV_INDICATION */ @@ -1641,7 +1641,7 @@ static inline int isr_rx_pdu(struct lll_adv *lll, rx->hdr.type = NODE_RX_TYPE_CONNECTION; rx->hdr.handle = 0xffff; - ftr = &(rx->hdr.rx_ftr); + ftr = &(rx->rx_ftr); ftr->param = lll; ftr->ticks_anchor = radio_tmr_start_get(); ftr->radio_end_us = radio_tmr_end_get() - diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_aux.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_aux.c index e16cddb5d3a..d944a52ef78 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_aux.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_aux.c @@ -788,7 +788,7 @@ static inline int isr_rx_pdu(struct lll_adv_aux *lll_aux, uint8_t phy_flags_rx, rx->hdr.type = NODE_RX_TYPE_CONNECTION; rx->hdr.handle = 0xffff; - ftr = &(rx->hdr.rx_ftr); + ftr = &(rx->rx_ftr); ftr->param = lll; ftr->ticks_anchor = radio_tmr_start_get(); ftr->radio_end_us = radio_tmr_end_get() - @@ -862,7 +862,7 @@ static void isr_tx_connect_rsp(void *param) bool is_done; rx = param; - ftr = &(rx->hdr.rx_ftr); + ftr = &(rx->rx_ftr); lll = ftr->param; is_done = radio_is_done(); diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_iso.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_iso.c index e89d5437f4b..b3a86b7acb1 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_iso.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_iso.c @@ -839,7 +839,7 @@ static void isr_done_term(void *param) sync_lll = adv_lll->sync; if (sync_lll->iso_chm_done_req == sync_lll->iso_chm_done_ack) { - struct node_rx_hdr *rx; + struct node_rx_pdu *rx; /* Request ULL to update the channel map in the * BIGInfo struct present in the current PDU of @@ -855,10 +855,10 @@ static void isr_done_term(void *param) rx = ull_pdu_rx_alloc(); LL_ASSERT(rx); - rx->type = NODE_RX_TYPE_BIG_CHM_COMPLETE; + rx->hdr.type = NODE_RX_TYPE_BIG_CHM_COMPLETE; rx->rx_ftr.param = lll; - ull_rx_put_sched(rx->link, rx); + ull_rx_put_sched(rx->hdr.link, rx); } /* Use new channel map */ diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_sync.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_sync.c index 79a8c6b25cd..c43125959a1 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_sync.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_sync.c @@ -311,7 +311,7 @@ static void isr_done(void *param) */ if ((lll->chm_first != lll->chm_last) && is_instant_or_past(lll->event_counter, lll->chm_instant)) { - struct node_rx_hdr *rx; + struct node_rx_pdu *rx; /* Allocate, prepare and dispatch Channel Map Update * complete message towards ULL, then subsequently to @@ -320,10 +320,10 @@ static void isr_done(void *param) rx = ull_pdu_rx_alloc(); LL_ASSERT(rx); - rx->type = NODE_RX_TYPE_SYNC_CHM_COMPLETE; + rx->hdr.type = NODE_RX_TYPE_SYNC_CHM_COMPLETE; rx->rx_ftr.param = lll; - ull_rx_put_sched(rx->link, rx); + ull_rx_put_sched(rx->hdr.link, rx); } lll_isr_done(lll); diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_central_iso.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_central_iso.c index 48247b18e6f..1a4d09c47c6 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_central_iso.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_central_iso.c @@ -764,7 +764,7 @@ static void isr_rx(void *param) /* Enqueue Rx ISO PDU */ node_rx->hdr.type = NODE_RX_TYPE_ISO_PDU; node_rx->hdr.handle = cis_lll->handle; - iso_meta = &node_rx->hdr.rx_iso_meta; + iso_meta = &node_rx->rx_iso_meta; iso_meta->payload_number = cis_lll->rx.payload_count + cis_lll->rx.bn_curr - 1U; iso_meta->timestamp = diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_conn.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_conn.c index faf54dac417..8d6f928ef82 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_conn.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_conn.c @@ -1095,7 +1095,7 @@ static inline bool create_iq_report(struct lll_conn *lll, uint8_t rssi_ready, ui ant = radio_df_pdu_antenna_switch_pattern_get(); iq_report = ull_df_iq_report_alloc(); - iq_report->hdr.type = NODE_RX_TYPE_CONN_IQ_SAMPLE_REPORT; + iq_report->rx.hdr.type = NODE_RX_TYPE_CONN_IQ_SAMPLE_REPORT; iq_report->sample_count = radio_df_iq_samples_amount_get(); iq_report->packet_status = packet_status; iq_report->rssi_ant_id = ant; @@ -1106,11 +1106,11 @@ static inline bool create_iq_report(struct lll_conn *lll, uint8_t rssi_ready, ui */ iq_report->event_counter = lll->event_counter - 1; - ftr = &iq_report->hdr.rx_ftr; + ftr = &iq_report->rx.rx_ftr; ftr->param = lll; ftr->rssi = ((rssi_ready) ? radio_rssi_get() : BT_HCI_LE_RSSI_NOT_AVAILABLE); - ull_rx_put(iq_report->hdr.link, iq_report); + ull_rx_put(iq_report->rx.hdr.link, iq_report); return true; } diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_df_types.h b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_df_types.h index 4087b35d3bb..d93d7902014 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_df_types.h +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_df_types.h @@ -96,11 +96,11 @@ struct iq_sample { /* Receive node aimed to report collected IQ samples during CTE receive */ struct node_rx_iq_report { - /* hdr member must be a first member of the structure. It can't be moved because + /* node_rx_pdu member must be a first member of the structure. It can't be moved because * it is expected to be in the beginning of a node memory for common handling of * all node_rx_xxx types. */ - struct node_rx_hdr hdr; + struct node_rx_pdu rx; uint8_t sample_count; struct pdu_cte_info cte_info; uint8_t local_slot_durations; diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_peripheral_iso.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_peripheral_iso.c index f1ba57cf7fb..07b6c5aae09 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_peripheral_iso.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_peripheral_iso.c @@ -594,7 +594,7 @@ static void isr_rx(void *param) /* Enqueue Rx ISO PDU */ node_rx->hdr.type = NODE_RX_TYPE_ISO_PDU; node_rx->hdr.handle = cis_lll->handle; - iso_meta = &node_rx->hdr.rx_iso_meta; + iso_meta = &node_rx->rx_iso_meta; iso_meta->payload_number = cis_lll->rx.payload_count + cis_lll->rx.bn_curr - 1U; iso_meta->timestamp = cis_lll->offset + diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan.c index a4e1a2bd705..89ebff85c02 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan.c @@ -1040,7 +1040,7 @@ static void isr_done_cleanup(void *param) TICKER_ID_SCAN_STOP, NULL, NULL); #if defined(CONFIG_BT_CTLR_SCAN_INDICATION) - struct node_rx_hdr *node_rx; + struct node_rx_pdu *node_rx; /* Check if there are enough free node rx available: * 1. For generating this scan indication @@ -1053,9 +1053,9 @@ static void isr_done_cleanup(void *param) ull_pdu_rx_alloc(); /* TODO: add other info by defining a payload struct */ - node_rx->type = NODE_RX_TYPE_SCAN_INDICATION; + node_rx->hdr.type = NODE_RX_TYPE_SCAN_INDICATION; - ull_rx_put_sched(node_rx->link, node_rx); + ull_rx_put_sched(node_rx->hdr.link, node_rx); } #endif /* CONFIG_BT_CTLR_SCAN_INDICATION */ @@ -1097,7 +1097,7 @@ static void isr_done_cleanup(void *param) node_rx2->hdr.type = NODE_RX_TYPE_EXT_AUX_RELEASE; - node_rx2->hdr.rx_ftr.param = lll; + node_rx2->rx_ftr.param = lll; ull_rx_put_sched(node_rx2->hdr.link, node_rx2); } @@ -1249,7 +1249,7 @@ static inline int isr_rx_pdu(struct lll_scan *lll, struct pdu_adv *pdu_adv_rx, pdu_adv_rx = (void *)rx->pdu; pdu_adv_rx->chan_sel = pdu_adv_rx_chan_sel; - ftr = &(rx->hdr.rx_ftr); + ftr = &(rx->rx_ftr); ftr->param = lll; ftr->ticks_anchor = radio_tmr_start_get(); @@ -1547,7 +1547,7 @@ static int isr_rx_scan_report(struct lll_scan *lll, uint8_t devmatch_ok, { struct node_rx_ftr *ftr; - ftr = &(node_rx->hdr.rx_ftr); + ftr = &(node_rx->rx_ftr); ftr->param = lll; ftr->ticks_anchor = radio_tmr_start_get(); ftr->radio_end_us = @@ -1572,32 +1572,32 @@ static int isr_rx_scan_report(struct lll_scan *lll, uint8_t devmatch_ok, node_rx->hdr.type = NODE_RX_TYPE_REPORT; } - node_rx->hdr.rx_ftr.rssi = (rssi_ready) ? radio_rssi_get() : + node_rx->rx_ftr.rssi = (rssi_ready) ? radio_rssi_get() : BT_HCI_LE_RSSI_NOT_AVAILABLE; #if defined(CONFIG_BT_CTLR_PRIVACY) /* save the resolving list index. */ - node_rx->hdr.rx_ftr.rl_idx = irkmatch_ok ? rl_idx : FILTER_IDX_NONE; + node_rx->rx_ftr.rl_idx = irkmatch_ok ? rl_idx : FILTER_IDX_NONE; #if defined(CONFIG_BT_CTLR_ADV_EXT) - node_rx->hdr.rx_ftr.direct_resolved = (rl_idx != FILTER_IDX_NONE); + node_rx->rx_ftr.direct_resolved = (rl_idx != FILTER_IDX_NONE); #endif /* CONFIG_BT_CTLR_ADV_EXT */ #endif /* CONFIG_BT_CTLR_PRIVACY */ #if defined(CONFIG_BT_CTLR_EXT_SCAN_FP) /* save the directed adv report flag */ - node_rx->hdr.rx_ftr.direct = dir_report; + node_rx->rx_ftr.direct = dir_report; #endif /* CONFIG_BT_CTLR_EXT_SCAN_FP */ #if defined(CONFIG_BT_CTLR_SYNC_PERIODIC) && \ defined(CONFIG_BT_CTLR_FILTER_ACCEPT_LIST) - node_rx->hdr.rx_ftr.devmatch = devmatch_ok; + node_rx->rx_ftr.devmatch = devmatch_ok; #endif /* CONFIG_BT_CTLR_SYNC_PERIODIC && CONFIG_BT_CTLR_FILTER_ACCEPT_LIST */ #if defined(CONFIG_BT_HCI_MESH_EXT) if (node_rx->hdr.type == NODE_RX_TYPE_MESH_REPORT) { /* save channel and anchor point ticks. */ - node_rx->hdr.rx_ftr.chan = _radio.scanner.chan - 1; - node_rx->hdr.rx_ftr.ticks_anchor = _radio.ticks_anchor; + node_rx->rx_ftr.chan = _radio.scanner.chan - 1; + node_rx->rx_ftr.ticks_anchor = _radio.ticks_anchor; } #endif /* CONFIG_BT_CTLR_EXT_SCAN_FP */ diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan_aux.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan_aux.c index a40e90e20a0..b1e95bb0632 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan_aux.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan_aux.c @@ -227,7 +227,7 @@ uint8_t lll_scan_aux_setup(struct pdu_adv *pdu, uint8_t pdu_phy, LL_ASSERT(node_rx); /* Store the lll context, aux_ptr and start of PDU in footer */ - ftr = &(node_rx->hdr.rx_ftr); + ftr = &(node_rx->rx_ftr); ftr->param = param; ftr->aux_ptr = aux_ptr; ftr->radio_end_us = radio_tmr_end_get() - @@ -258,7 +258,7 @@ void lll_scan_aux_isr_aux_setup(void *param) lll_isr_status_reset(); node_rx = param; - ftr = &node_rx->hdr.rx_ftr; + ftr = &node_rx->rx_ftr; aux_ptr = ftr->aux_ptr; phy_aux = BIT(PDU_ADV_AUX_PTR_PHY_GET(aux_ptr)); ftr->aux_phy = phy_aux; @@ -683,8 +683,8 @@ static void isr_done(void *param) node_rx->hdr.type = NODE_RX_TYPE_EXT_AUX_RELEASE; - node_rx->hdr.rx_ftr.param = lll; - node_rx->hdr.rx_ftr.aux_failed = 1U; + node_rx->rx_ftr.param = lll; + node_rx->rx_ftr.aux_failed = 1U; ull_rx_put_sched(node_rx->hdr.link, node_rx); @@ -716,8 +716,8 @@ static void isr_rx_lll_schedule(void *param) uint8_t phy_aux; node_rx = param; - lll = node_rx->hdr.rx_ftr.param; - phy_aux = node_rx->hdr.rx_ftr.aux_phy; /* PHY remembered in node rx */ + lll = node_rx->rx_ftr.param; + phy_aux = node_rx->rx_ftr.aux_phy; /* PHY remembered in node rx */ /* scan context has used LLL scheduling for aux reception */ if (lll->is_aux_sched) { @@ -866,7 +866,7 @@ static void isr_rx(struct lll_scan *lll, struct lll_scan_aux *lll_aux, * under race, if ULL execution did assign one, it will * free it. */ - node_rx2->hdr.rx_ftr.param = lll; + node_rx2->rx_ftr.param = lll; ull_rx_put_sched(node_rx2->hdr.link, node_rx2); } @@ -1061,7 +1061,7 @@ static int isr_rx_pdu(struct lll_scan *lll, struct lll_scan_aux *lll_aux, pdu = (void *)rx->pdu; pdu->chan_sel = 1; - ftr = &(rx->hdr.rx_ftr); + ftr = &(rx->rx_ftr); ftr->param = lll; ftr->ticks_anchor = radio_tmr_start_get(); ftr->radio_end_us = conn_space_us; @@ -1177,7 +1177,7 @@ static int isr_rx_pdu(struct lll_scan *lll, struct lll_scan_aux *lll_aux, node_rx->hdr.type = NODE_RX_TYPE_EXT_AUX_REPORT; - ftr = &(node_rx->hdr.rx_ftr); + ftr = &(node_rx->rx_ftr); if (lll_aux) { ftr->param = lll_aux; radio_isr_set(isr_tx_scan_req_ull_schedule, @@ -1231,7 +1231,7 @@ static int isr_rx_pdu(struct lll_scan *lll, struct lll_scan_aux *lll_aux, &dir_report)) { #endif /* !CONFIG_BT_CENTRAL */ - ftr = &(node_rx->hdr.rx_ftr); + ftr = &(node_rx->rx_ftr); if (lll_aux) { ftr->param = lll_aux; ftr->scan_rsp = lll_aux->state; @@ -1409,7 +1409,7 @@ static void isr_tx_scan_req_lll_schedule(void *param) struct node_rx_pdu *node_rx; struct lll_scan *lll; - lll = node_rx_adv->hdr.rx_ftr.param; + lll = node_rx_adv->rx_ftr.param; node_rx = ull_pdu_rx_alloc_peek(1); LL_ASSERT(node_rx); @@ -1431,6 +1431,7 @@ static void isr_tx_connect_req(void *param) static void isr_rx_connect_rsp(void *param) { struct lll_scan_aux *lll_aux; + uint8_t phy_aux_flags_rx; struct pdu_adv *pdu_rx; struct node_rx_pdu *rx; struct lll_scan *lll; @@ -1455,8 +1456,9 @@ static void isr_rx_connect_rsp(void *param) irkmatch_ok = 0U; irkmatch_id = FILTER_IDX_NONE; } + phy_aux_flags_rx = radio_phy_flags_rx_get(); } else { - crc_ok = irkmatch_ok = 0U; + crc_ok = irkmatch_ok = phy_aux_flags_rx = 0U; irkmatch_id = FILTER_IDX_NONE; } @@ -1508,7 +1510,7 @@ static void isr_rx_connect_rsp(void *param) /* Dont stop initiating events on primary channels */ lll->is_stop = 0U; - ftr = &(rx->hdr.rx_ftr); + ftr = &(rx->rx_ftr); rx->hdr.type = NODE_RX_TYPE_RELEASE; ull_rx_put(rx->hdr.link, rx); @@ -1535,6 +1537,7 @@ static void isr_rx_connect_rsp(void *param) conn_lll->phy_tx = lll_aux->phy; conn_lll->phy_tx_time = lll_aux->phy; + conn_lll->phy_flags = phy_aux_flags_rx; conn_lll->phy_rx = lll_aux->phy; #endif /* CONFIG_BT_CTLR_PHY */ @@ -1548,7 +1551,7 @@ static void isr_rx_connect_rsp(void *param) (void)memcpy(pdu->connect_ind.adv_addr, &pdu_rx->adv_ext_ind.ext_hdr.data[ADVA_OFFSET], BDADDR_SIZE); - ftr = &(rx->hdr.rx_ftr); + ftr = &(rx->rx_ftr); ftr->rl_idx = rl_idx; } #endif /* CONFIG_BT_CTLR_PRIVACY */ @@ -1569,7 +1572,7 @@ static void isr_rx_connect_rsp(void *param) node_rx->hdr.type = NODE_RX_TYPE_EXT_AUX_RELEASE; - node_rx->hdr.rx_ftr.param = lll->lll_aux; + node_rx->rx_ftr.param = lll->lll_aux; ull_rx_put_sched(node_rx->hdr.link, node_rx); diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync.c index 05b10cf994a..3c0b882a37f 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync.c @@ -660,7 +660,7 @@ static void isr_aux_setup(void *param) lll_isr_status_reset(); node_rx = param; - ftr = &node_rx->hdr.rx_ftr; + ftr = &node_rx->rx_ftr; aux_ptr = ftr->aux_ptr; phy_aux = BIT(PDU_ADV_AUX_PTR_PHY_GET(aux_ptr)); ftr->aux_phy = phy_aux; @@ -817,7 +817,7 @@ static int isr_rx(struct lll_sync *lll, uint8_t node_type, uint8_t crc_ok, node_rx->hdr.type = node_type; - ftr = &(node_rx->hdr.rx_ftr); + ftr = &(node_rx->rx_ftr); ftr->param = lll; ftr->aux_failed = 0U; ftr->rssi = (rssi_ready) ? radio_rssi_get() : @@ -977,7 +977,7 @@ static void isr_rx_adv_sync_estab(void *param) node_rx->hdr.type = NODE_RX_TYPE_SYNC; - ftr = &node_rx->hdr.rx_ftr; + ftr = &node_rx->rx_ftr; ftr->param = lll; ftr->sync_status = SYNC_STAT_TERM; @@ -1132,8 +1132,8 @@ static void isr_rx_aux_chain(void *param) node_rx->hdr.type = NODE_RX_TYPE_EXT_AUX_RELEASE; - node_rx->hdr.rx_ftr.param = lll; - node_rx->hdr.rx_ftr.aux_failed = 1U; + node_rx->rx_ftr.param = lll; + node_rx->rx_ftr.aux_failed = 1U; ull_rx_put(node_rx->hdr.link, node_rx); @@ -1227,8 +1227,8 @@ static void isr_done(void *param) node_rx->hdr.type = NODE_RX_TYPE_EXT_AUX_RELEASE; - node_rx->hdr.rx_ftr.param = lll; - node_rx->hdr.rx_ftr.aux_failed = 1U; + node_rx->rx_ftr.param = lll; + node_rx->rx_ftr.aux_failed = 1U; ull_rx_put_sched(node_rx->hdr.link, node_rx); } @@ -1247,7 +1247,7 @@ static void iq_report_create(struct lll_sync *lll, uint8_t rssi_ready, uint8_t p cte_info = radio_df_cte_status_get(); ant = radio_df_pdu_antenna_switch_pattern_get(); - iq_report->hdr.type = NODE_RX_TYPE_SYNC_IQ_SAMPLE_REPORT; + iq_report->rx.hdr.type = NODE_RX_TYPE_SYNC_IQ_SAMPLE_REPORT; iq_report->sample_count = radio_df_iq_samples_amount_get(); iq_report->packet_status = packet_status; iq_report->rssi_ant_id = ant; @@ -1258,7 +1258,7 @@ static void iq_report_create(struct lll_sync *lll, uint8_t rssi_ready, uint8_t p */ iq_report->event_counter = lll->event_counter - 1; - ftr = &iq_report->hdr.rx_ftr; + ftr = &iq_report->rx.rx_ftr; ftr->param = lll; ftr->rssi = ((rssi_ready) ? radio_rssi_get() : BT_HCI_LE_RSSI_NOT_AVAILABLE); @@ -1268,7 +1268,7 @@ static void iq_report_incomplete_create(struct lll_sync *lll, struct node_rx_iq_ { struct node_rx_ftr *ftr; - iq_report->hdr.type = NODE_RX_TYPE_SYNC_IQ_SAMPLE_REPORT; + iq_report->rx.hdr.type = NODE_RX_TYPE_SYNC_IQ_SAMPLE_REPORT; iq_report->sample_count = 0; iq_report->packet_status = BT_HCI_LE_CTE_INSUFFICIENT_RESOURCES; /* Event counter is updated to next value during event preparation, @@ -1288,7 +1288,7 @@ static void iq_report_incomplete_create(struct lll_sync *lll, struct node_rx_iq_ (struct pdu_cte_info){.time = 0, .rfu = 0, .type = 0}; iq_report->local_slot_durations = 0; - ftr = &iq_report->hdr.rx_ftr; + ftr = &iq_report->rx.rx_ftr; ftr->param = lll; ftr->rssi = BT_HCI_LE_RSSI_NOT_AVAILABLE; @@ -1337,7 +1337,7 @@ static int iq_report_create_put(struct lll_sync *lll, uint8_t rssi_ready, uint8_ } if (!err) { - ull_rx_put(iq_report->hdr.link, iq_report); + ull_rx_put(iq_report->rx.hdr.link, iq_report); cfg->cte_count += 1U; } @@ -1363,7 +1363,7 @@ static int iq_report_incomplete_create_put(struct lll_sync *lll) iq_report_incomplete_create(lll, iq_report); lll->node_cte_incomplete = NULL; - ull_rx_put(iq_report->hdr.link, iq_report); + ull_rx_put(iq_report->rx.hdr.link, iq_report); return 0; } else { @@ -1381,9 +1381,9 @@ static void iq_report_incomplete_release_put(struct lll_sync *lll) if (lll->node_cte_incomplete) { struct node_rx_iq_report *iq_report = lll->node_cte_incomplete; - iq_report->hdr.type = NODE_RX_TYPE_IQ_SAMPLE_REPORT_LLL_RELEASE; + iq_report->rx.hdr.type = NODE_RX_TYPE_IQ_SAMPLE_REPORT_LLL_RELEASE; - ull_rx_put(iq_report->hdr.link, iq_report); + ull_rx_put(iq_report->rx.hdr.link, iq_report); lll->node_cte_incomplete = NULL; } } diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync_iso.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync_iso.c index 13d101ed346..fcc37fc52d8 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync_iso.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync_iso.c @@ -456,6 +456,7 @@ static void isr_rx_estab(void *param) LL_ASSERT(e); e->type = EVENT_DONE_EXTRA_TYPE_SYNC_ISO_ESTAB; + e->estab_failed = 0U; e->trx_cnt = trx_cnt; e->crc_valid = crc_ok; @@ -1264,7 +1265,7 @@ static void isr_rx_iso_data_valid(const struct lll_sync_iso *const lll, node_rx->hdr.type = NODE_RX_TYPE_ISO_PDU; node_rx->hdr.handle = handle; - iso_meta = &node_rx->hdr.rx_iso_meta; + iso_meta = &node_rx->rx_iso_meta; iso_meta->payload_number = lll->payload_count + (lll->bn_curr - 1U) + (lll->ptc_curr * lll->pto) - lll->bn; @@ -1293,7 +1294,7 @@ static void isr_rx_iso_data_invalid(const struct lll_sync_iso *const lll, node_rx->hdr.type = NODE_RX_TYPE_ISO_PDU; node_rx->hdr.handle = handle; - iso_meta = &node_rx->hdr.rx_iso_meta; + iso_meta = &node_rx->rx_iso_meta; iso_meta->payload_number = lll->payload_count - bn - 1U; stream = ull_sync_iso_lll_stream_get(lll->stream_handle[0]); diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_test.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_test.c index 90d00e624d4..9715b934e5e 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_test.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_test.c @@ -151,7 +151,7 @@ static int create_iq_report(bool crc_ok) return -ENOBUFS; } - iq_report->hdr.type = NODE_RX_TYPE_DTM_IQ_SAMPLE_REPORT; + iq_report->rx.hdr.type = NODE_RX_TYPE_DTM_IQ_SAMPLE_REPORT; iq_report->sample_count = sample_cnt; iq_report->packet_status = ((crc_ok) ? BT_HCI_LE_CTE_CRC_OK : BT_HCI_LE_CTE_CRC_ERR_CTE_BASED_TIME); @@ -160,11 +160,11 @@ static int create_iq_report(bool crc_ok) iq_report->local_slot_durations = test_slot_duration; iq_report->chan_idx = test_chan; - ftr = &iq_report->hdr.rx_ftr; + ftr = &iq_report->rx.rx_ftr; ftr->param = NULL; ftr->rssi = BT_HCI_LE_RSSI_NOT_AVAILABLE; - ull_rx_put(iq_report->hdr.link, iq_report); + ull_rx_put(iq_report->rx.hdr.link, iq_report); return 0; } diff --git a/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_adv.c b/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_adv.c index df51202fdbc..54d7c29b9e1 100644 --- a/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_adv.c +++ b/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_adv.c @@ -654,7 +654,7 @@ static void isr_rx(void *param) static void isr_done(void *param) { - struct node_rx_hdr *node_rx; + struct node_rx_pdu *node_rx; struct lll_adv *lll = param; /* TODO: MOVE to a common interface, isr_lll_radio_status? */ @@ -728,9 +728,9 @@ static void isr_done(void *param) ull_pdu_rx_alloc(); /* TODO: add other info by defining a payload struct */ - node_rx->type = NODE_RX_TYPE_ADV_INDICATION; + node_rx->hdr.type = NODE_RX_TYPE_ADV_INDICATION; - ull_rx_put_sched(node_rx->link, node_rx); + ull_rx_put_sched(node_rx->hdr.link, node_rx); } #else /* !CONFIG_BT_CTLR_ADV_INDICATION */ ARG_UNUSED(node_rx); @@ -927,7 +927,7 @@ static inline int isr_rx_pdu(struct lll_adv *lll, memcpy(rx->pdu, pdu_rx, (offsetof(struct pdu_adv, connect_ind) + sizeof(struct pdu_adv_connect_ind))); - ftr = &(rx->hdr.rx_ftr); + ftr = &(rx->rx_ftr); ftr->param = lll; ftr->ticks_anchor = radio_tmr_start_get(); ftr->radio_end_us = radio_tmr_end_get() - @@ -1001,7 +1001,7 @@ static inline int isr_rx_sr_report(struct pdu_adv *pdu_adv_rx, pdu_len = offsetof(struct pdu_adv, payload) + pdu_adv_rx->len; memcpy(pdu_adv, pdu_adv_rx, pdu_len); - node_rx->hdr.rx_ftr.rssi = (rssi_ready) ? (radio_rssi_get() & 0x7f) : + node_rx->rx_ftr.rssi = (rssi_ready) ? (radio_rssi_get() & 0x7f) : 0x7f; ull_rx_put_sched(node_rx->hdr.link, node_rx); diff --git a/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_scan.c b/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_scan.c index ddb74fef652..013f705851c 100644 --- a/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_scan.c +++ b/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_scan.c @@ -591,7 +591,7 @@ static void isr_abort(void *param) static void isr_cleanup(void *param) { struct lll_scan *lll = param; - struct node_rx_hdr *node_rx; + struct node_rx_pdu *node_rx; int err; if (lll_is_done(param)) { @@ -617,9 +617,9 @@ static void isr_cleanup(void *param) ull_pdu_rx_alloc(); /* TODO: add other info by defining a payload struct */ - node_rx->type = NODE_RX_TYPE_SCAN_INDICATION; + node_rx->hdr.type = NODE_RX_TYPE_SCAN_INDICATION; - ull_rx_put_sched(node_rx->link, node_rx); + ull_rx_put_sched(node_rx->hdr.link, node_rx); } #else /* !CONFIG_BT_CTLR_SCAN_INDICATION */ ARG_UNUSED(node_rx); @@ -843,7 +843,7 @@ static inline uint32_t isr_rx_pdu(struct lll_scan *lll, uint8_t devmatch_ok, pdu_adv_rx = (void *)rx->pdu; pdu_adv_rx->chan_sel = pdu_adv_rx_chan_sel; - ftr = &(rx->hdr.rx_ftr); + ftr = &(rx->rx_ftr); ftr->param = lll; ftr->ticks_anchor = radio_tmr_start_get(); @@ -1121,22 +1121,22 @@ static uint32_t isr_rx_scan_report(struct lll_scan *lll, uint8_t rssi_ready, pdu_adv_rx = (void *)node_rx->pdu; - node_rx->hdr.rx_ftr.rssi = (rssi_ready) ? + node_rx->rx_ftr.rssi = (rssi_ready) ? (radio_rssi_get() & 0x7f) : 0x7f; #if defined(CONFIG_BT_CTLR_PRIVACY) /* save the resolving list index. */ - node_rx->hdr.rx_ftr.rl_idx = rl_idx; + node_rx->rx_ftr.rl_idx = rl_idx; #endif /* CONFIG_BT_CTLR_PRIVACY */ #if defined(CONFIG_BT_CTLR_EXT_SCAN_FP) /* save the directed adv report flag */ - node_rx->hdr.rx_ftr.direct = dir_report; + node_rx->rx_ftr.direct = dir_report; #endif /* CONFIG_BT_CTLR_EXT_SCAN_FP */ #if defined(CONFIG_BT_HCI_MESH_EXT) if (node_rx->hdr.type == NODE_RX_TYPE_MESH_REPORT) { /* save channel and anchor point ticks. */ - node_rx->hdr.rx_ftr.chan = _radio.scanner.chan - 1; - node_rx->hdr.rx_ftr.ticks_anchor = _radio.ticks_anchor; + node_rx->rx_ftr.chan = _radio.scanner.chan - 1; + node_rx->rx_ftr.ticks_anchor = _radio.ticks_anchor; } #endif /* CONFIG_BT_CTLR_EXT_SCAN_FP */ diff --git a/subsys/bluetooth/controller/ll_sw/ull.c b/subsys/bluetooth/controller/ll_sw/ull.c index 8caaa29b62c..b5bbec9af84 100644 --- a/subsys/bluetooth/controller/ll_sw/ull.c +++ b/subsys/bluetooth/controller/ll_sw/ull.c @@ -549,9 +549,9 @@ static inline void rx_demux_conn_tx_ack(uint8_t ack_last, uint16_t handle, memq_link_t *link, struct node_tx *node_tx); #endif /* CONFIG_BT_CONN || CONFIG_BT_CTLR_ADV_ISO */ -static inline void rx_demux_rx(memq_link_t *link, struct node_rx_hdr *rx); +static inline void rx_demux_rx(memq_link_t *link, struct node_rx_hdr *rx_hdr); static inline void rx_demux_event_done(memq_link_t *link, - struct node_rx_hdr *rx); + struct node_rx_event_done *done); static void ll_rx_link_quota_inc(void); static void ll_rx_link_quota_dec(void); static void disabled_cb(void *param); @@ -764,6 +764,12 @@ void ll_reset(void) */ #if defined(CONFIG_BT_BROADCASTER) +#if defined(CONFIG_BT_CTLR_ADV_ISO) + /* Reset adv iso sets */ + err = ull_adv_iso_reset(); + LL_ASSERT(!err); +#endif /* CONFIG_BT_CTLR_ADV_ISO */ + /* Reset adv state */ err = ull_adv_reset(); LL_ASSERT(!err); @@ -772,7 +778,7 @@ void ll_reset(void) #if defined(CONFIG_BT_OBSERVER) #if defined(CONFIG_BT_CTLR_SYNC_PERIODIC) #if defined(CONFIG_BT_CTLR_SYNC_ISO) - /* Reset periodic sync sets */ + /* Reset sync iso sets */ err = ull_sync_iso_reset(); LL_ASSERT(!err); #endif /* CONFIG_BT_CTLR_SYNC_ISO */ @@ -787,16 +793,6 @@ void ll_reset(void) LL_ASSERT(!err); #endif /* CONFIG_BT_OBSERVER */ -#if defined(CONFIG_BT_CTLR_CONN_ISO) - err = ull_conn_iso_reset(); - LL_ASSERT(!err); -#endif /* CONFIG_BT_CTLR_CONN_ISO */ - -#if defined(CONFIG_BT_CTLR_ISO) - err = ull_iso_reset(); - LL_ASSERT(!err); -#endif /* CONFIG_BT_CTLR_ISO */ - #if defined(CONFIG_BT_CTLR_PERIPHERAL_ISO) err = ull_peripheral_iso_reset(); LL_ASSERT(!err); @@ -807,11 +803,15 @@ void ll_reset(void) LL_ASSERT(!err); #endif /* CONFIG_BT_CTLR_CENTRAL_ISO */ -#if defined(CONFIG_BT_CTLR_ADV_ISO) - /* Reset periodic sync sets */ - err = ull_adv_iso_reset(); +#if defined(CONFIG_BT_CTLR_CONN_ISO) + err = ull_conn_iso_reset(); LL_ASSERT(!err); -#endif /* CONFIG_BT_CTLR_ADV_ISO */ +#endif /* CONFIG_BT_CTLR_CONN_ISO */ + +#if defined(CONFIG_BT_CTLR_ISO) + err = ull_iso_reset(); + LL_ASSERT(!err); +#endif /* CONFIG_BT_CTLR_ISO */ #if defined(CONFIG_BT_CONN) /* Reset conn role */ @@ -919,7 +919,7 @@ void ll_reset(void) */ uint8_t ll_rx_get(void **node_rx, uint16_t *handle) { - struct node_rx_hdr *rx; + struct node_rx_pdu *rx; memq_link_t *link; uint8_t cmplt = 0U; @@ -939,8 +939,7 @@ uint8_t ll_rx_get(void **node_rx, uint16_t *handle) link = memq_peek(memq_ll_rx.head, memq_ll_rx.tail, (void **)&rx); if (link) { #if defined(CONFIG_BT_CONN) || defined(CONFIG_BT_CTLR_ADV_ISO) - cmplt = tx_cmplt_get(handle, &mfifo_fifo_tx_ack.f, - rx->ack_last); + cmplt = tx_cmplt_get(handle, &mfifo_fifo_tx_ack.f, rx->hdr.ack_last); if (!cmplt) { uint8_t f, cmplt_prev, cmplt_curr; uint16_t h; @@ -961,9 +960,9 @@ uint8_t ll_rx_get(void **node_rx, uint16_t *handle) /* Do not send up buffers to Host thread that are * marked for release */ - } else if (rx->type == NODE_RX_TYPE_RELEASE) { + } else if (rx->hdr.type == NODE_RX_TYPE_RELEASE) { rx_link_dequeue_release_quota_inc(link); - rx_release_replenish(rx); + rx_release_replenish((struct node_rx_hdr *)rx); goto ll_rx_get_again; #endif /* CONFIG_BT_CONN || @@ -971,7 +970,7 @@ uint8_t ll_rx_get(void **node_rx, uint16_t *handle) */ #if defined(CONFIG_BT_CTLR_DF_SCAN_CTE_RX) - } else if (rx->type == NODE_RX_TYPE_IQ_SAMPLE_REPORT_LLL_RELEASE) { + } else if (rx->hdr.type == NODE_RX_TYPE_IQ_SAMPLE_REPORT_LLL_RELEASE) { const uint8_t report_cnt = 1U; (void)memq_dequeue(memq_ll_rx.tail, &memq_ll_rx.head, NULL); @@ -984,7 +983,7 @@ uint8_t ll_rx_get(void **node_rx, uint16_t *handle) #endif /* CONFIG_BT_CTLR_DF_SCAN_CTE_RX */ #if defined(CONFIG_BT_CTLR_ADV_PERIODIC) - } else if (rx->type == NODE_RX_TYPE_SYNC_CHM_COMPLETE) { + } else if (rx->hdr.type == NODE_RX_TYPE_SYNC_CHM_COMPLETE) { rx_link_dequeue_release_quota_inc(link); /* Remove Channel Map Update Indication from @@ -992,13 +991,13 @@ uint8_t ll_rx_get(void **node_rx, uint16_t *handle) */ ull_adv_sync_chm_complete(rx); - rx_release_replenish(rx); + rx_release_replenish((struct node_rx_hdr *)rx); goto ll_rx_get_again; #endif /* CONFIG_BT_CTLR_ADV_PERIODIC */ #if defined(CONFIG_BT_CTLR_ADV_ISO) - } else if (rx->type == NODE_RX_TYPE_BIG_CHM_COMPLETE) { + } else if (rx->hdr.type == NODE_RX_TYPE_BIG_CHM_COMPLETE) { rx_link_dequeue_release_quota_inc(link); /* Update Channel Map in BIGInfo present in @@ -1006,7 +1005,7 @@ uint8_t ll_rx_get(void **node_rx, uint16_t *handle) */ ull_adv_iso_chm_complete(rx); - rx_release_replenish(rx); + rx_release_replenish((struct node_rx_hdr *)rx); goto ll_rx_get_again; #endif /* CONFIG_BT_CTLR_ADV_ISO */ @@ -1031,7 +1030,7 @@ uint8_t ll_rx_get(void **node_rx, uint16_t *handle) */ void ll_rx_dequeue(void) { - struct node_rx_hdr *rx = NULL; + struct node_rx_pdu *rx = NULL; memq_link_t *link; link = memq_dequeue(memq_ll_rx.tail, &memq_ll_rx.head, @@ -1041,7 +1040,7 @@ void ll_rx_dequeue(void) ll_rx_link_release(link); /* handle object specific clean up */ - switch (rx->type) { + switch (rx->hdr.type) { #if defined(CONFIG_BT_CTLR_ADV_EXT) #if defined(CONFIG_BT_OBSERVER) case NODE_RX_TYPE_EXT_1M_REPORT: @@ -1051,10 +1050,10 @@ void ll_rx_dequeue(void) case NODE_RX_TYPE_SYNC_REPORT: #endif /* CONFIG_BT_CTLR_SYNC_PERIODIC */ { - struct node_rx_hdr *rx_curr; + struct node_rx_pdu *rx_curr; struct pdu_adv *adv; - adv = (void *)((struct node_rx_pdu *)rx)->pdu; + adv = (struct pdu_adv *)rx->pdu; if (adv->type != PDU_ADV_TYPE_EXT_IND) { break; } @@ -1063,7 +1062,7 @@ void ll_rx_dequeue(void) while (rx_curr) { memq_link_t *link_free; - link_free = rx_curr->link; + link_free = rx_curr->hdr.link; rx_curr = rx_curr->rx_ftr.extra; ll_rx_link_release(link_free); @@ -1073,7 +1072,7 @@ void ll_rx_dequeue(void) case NODE_RX_TYPE_EXT_SCAN_TERMINATE: { - ull_scan_term_dequeue(rx->handle); + ull_scan_term_dequeue(rx->hdr.handle); } break; #endif /* CONFIG_BT_OBSERVER */ @@ -1084,7 +1083,7 @@ void ll_rx_dequeue(void) struct ll_adv_set *adv; struct lll_adv_aux *lll_aux; - adv = ull_adv_set_get(rx->handle); + adv = ull_adv_set_get(rx->hdr.handle); LL_ASSERT(adv); lll_aux = adv->lll.aux; @@ -1134,7 +1133,7 @@ void ll_rx_dequeue(void) #if defined(CONFIG_BT_CONN) case NODE_RX_TYPE_CONNECTION: { - struct node_rx_cc *cc = (void *)((struct node_rx_pdu *)rx)->pdu; + struct node_rx_cc *cc = (void *)rx->pdu; struct node_rx_ftr *ftr = &(rx->rx_ftr); if (0) { @@ -1342,7 +1341,7 @@ void ll_rx_dequeue(void) * code block. */ case NODE_RX_TYPE_NONE: - LL_ASSERT(rx->type != NODE_RX_TYPE_NONE); + LL_ASSERT(rx->hdr.type != NODE_RX_TYPE_NONE); break; default: @@ -1353,7 +1352,7 @@ void ll_rx_dequeue(void) /* FIXME: clean up when porting Mesh Ext. */ if (0) { #if defined(CONFIG_BT_HCI_MESH_EXT) - } else if (rx->type == NODE_RX_TYPE_MESH_ADV_CPLT) { + } else if (rx->hdr.type == NODE_RX_TYPE_MESH_ADV_CPLT) { struct ll_adv_set *adv; struct ll_scan_set *scan; @@ -1373,16 +1372,16 @@ void ll_rx_dequeue(void) void ll_rx_mem_release(void **node_rx) { - struct node_rx_hdr *rx; + struct node_rx_pdu *rx; rx = *node_rx; while (rx) { - struct node_rx_hdr *rx_free; + struct node_rx_pdu *rx_free; rx_free = rx; - rx = rx->next; + rx = rx->hdr.next; - switch (rx_free->type) { + switch (rx_free->hdr.type) { #if defined(CONFIG_BT_BROADCASTER) #if defined(CONFIG_BT_CTLR_ADV_EXT) case NODE_RX_TYPE_EXT_ADV_TERMINATE: @@ -1419,7 +1418,7 @@ void ll_rx_mem_release(void **node_rx) case NODE_RX_TYPE_CONNECTION: { struct node_rx_cc *cc = - (void *)((struct node_rx_pdu *)rx_free)->pdu; + (void *)rx_free->pdu; if (0) { @@ -1532,7 +1531,7 @@ void ll_rx_mem_release(void **node_rx) * code block. */ case NODE_RX_TYPE_NONE: - LL_ASSERT(rx_free->type != NODE_RX_TYPE_NONE); + LL_ASSERT(rx_free->hdr.type != NODE_RX_TYPE_NONE); ll_rx_link_quota_inc(); ll_rx_release(rx_free); break; @@ -1541,7 +1540,7 @@ void ll_rx_mem_release(void **node_rx) case NODE_RX_TYPE_SYNC: { struct node_rx_sync *se = - (void *)((struct node_rx_pdu *)rx_free)->pdu; + (void *)rx_free->pdu; uint8_t status = se->status; /* Below status codes use node_rx_sync_estab, hence @@ -1572,7 +1571,7 @@ void ll_rx_mem_release(void **node_rx) memq_link_t *link_sync_lost; link_sync_lost = - sync->node_rx_lost.hdr.link; + sync->node_rx_lost.rx.hdr.link; ll_rx_link_release(link_sync_lost); ull_sync_release(sync); @@ -1600,7 +1599,7 @@ void ll_rx_mem_release(void **node_rx) case NODE_RX_TYPE_SYNC_ISO: { struct node_rx_sync_iso *se = - (void *)((struct node_rx_pdu *)rx_free)->pdu; + (void *)rx_free->pdu; if (!se->status) { ll_rx_release(rx_free); @@ -1639,11 +1638,11 @@ void ll_rx_mem_release(void **node_rx) #if defined(CONFIG_BT_CONN) || defined(CONFIG_BT_CTLR_CONN_ISO) case NODE_RX_TYPE_TERMINATE: { - if (IS_ACL_HANDLE(rx_free->handle)) { + if (IS_ACL_HANDLE(rx_free->hdr.handle)) { struct ll_conn *conn; memq_link_t *link; - conn = ll_conn_get(rx_free->handle); + conn = ll_conn_get(rx_free->hdr.handle); LL_ASSERT(!conn->lll.link_tx_free); link = memq_deinit(&conn->lll.memq_tx.head, @@ -1652,7 +1651,7 @@ void ll_rx_mem_release(void **node_rx) conn->lll.link_tx_free = link; ll_conn_release(conn); - } else if (IS_CIS_HANDLE(rx_free->handle)) { + } else if (IS_CIS_HANDLE(rx_free->hdr.handle)) { ll_rx_link_quota_inc(); ll_rx_release(rx_free); } @@ -1954,12 +1953,15 @@ int ull_disable(void *lll) if (!ull_ref_get(hdr)) { return -EALREADY; } + cpu_dmb(); /* Ensure synchronized data access */ k_sem_init(&sem, 0, 1); hdr->disabled_param = &sem; hdr->disabled_cb = disabled_cb; + cpu_dmb(); /* Ensure synchronized data access */ + /* ULL_HIGH can run after we have call `ull_ref_get` and it can * decrement the ref count. Hence, handle this race condition by * ensuring that `disabled_cb` has been set while the ref count is still @@ -2073,6 +2075,34 @@ void ull_prepare_dequeue(uint8_t caller_id) void *param_resume_head = NULL; void *param_resume_next = NULL; struct lll_event *next; + uint8_t loop; + + /* Development assertion check to ensure the below loop processing + * has a limit. + * + * Only 2 scanner and 1 advertiser (directed adv) gets enqueue back: + * + * Already in queue max 7 (EVENT_PIPELINE_MAX): + * - 2 continuous scan prepare in queue (1M and Coded PHY) + * - 2 continuous scan resume in queue (1M and Coded PHY) + * - 1 directed adv prepare + * - 1 directed adv resume + * - 1 any other role with time reservation + * + * The loop removes the duplicates (scan and advertiser) with is_aborted + * flag set in 7 iterations: + * - 1 scan prepare (1M) + * - 1 scan prepare (Coded PHY) + * - 1 directed adv prepare + * + * and has enqueue the following in these 7 iterations: + * - 1 scan resume (1M) + * - 1 scan resume (Coded PHY) + * - 1 directed adv resume + * + * Hence, it should be (EVENT_PIPELINE_MAX + 3U) iterations max. + */ + loop = (EVENT_PIPELINE_MAX + 3U); next = ull_prepare_dequeue_get(); while (next) { @@ -2080,6 +2110,11 @@ void ull_prepare_dequeue(uint8_t caller_id) uint8_t is_aborted = next->is_aborted; uint8_t is_resume = next->is_resume; + /* Assert if we exceed iterations processing the prepare queue + */ + LL_ASSERT(loop); + loop--; + /* Let LLL invoke the `prepare` interface if radio not in active * use. Otherwise, enqueue at end of the prepare pipeline queue. */ @@ -2730,7 +2765,7 @@ static inline void rx_demux_rx(memq_link_t *link, struct node_rx_hdr *rx) case NODE_RX_TYPE_EVENT_DONE: { (void)memq_dequeue(memq_ull_rx.tail, &memq_ull_rx.head, NULL); - rx_demux_event_done(link, rx); + rx_demux_event_done(link, (struct node_rx_event_done *)rx); } break; @@ -2753,21 +2788,21 @@ static inline void rx_demux_rx(memq_link_t *link, struct node_rx_hdr *rx) break; } - ull_scan_aux_setup(link, rx); + ull_scan_aux_setup(link, (struct node_rx_pdu *)rx); } break; case NODE_RX_TYPE_EXT_AUX_RELEASE: { (void)memq_dequeue(memq_ull_rx.tail, &memq_ull_rx.head, NULL); - ull_scan_aux_release(link, rx); + ull_scan_aux_release(link, (struct node_rx_pdu *)rx); } break; #if defined(CONFIG_BT_CTLR_SYNC_PERIODIC) case NODE_RX_TYPE_SYNC: { (void)memq_dequeue(memq_ull_rx.tail, &memq_ull_rx.head, NULL); - ull_sync_established_report(link, rx); + ull_sync_established_report(link, (struct node_rx_pdu *)rx); } break; #endif /* CONFIG_BT_CTLR_SYNC_PERIODIC */ @@ -2809,13 +2844,13 @@ static inline void rx_demux_rx(memq_link_t *link, struct node_rx_hdr *rx) case NODE_RX_TYPE_CONNECTION: { (void)memq_dequeue(memq_ull_rx.tail, &memq_ull_rx.head, NULL); - ull_conn_setup(link, rx); + ull_conn_setup(link, (struct node_rx_pdu *)rx); } break; case NODE_RX_TYPE_DC_PDU: { - ull_conn_rx(link, (void *)&rx); + ull_conn_rx(link, (struct node_rx_pdu **)&rx); (void)memq_dequeue(memq_ull_rx.tail, &memq_ull_rx.head, NULL); @@ -2898,9 +2933,8 @@ static inline void rx_demux_rx(memq_link_t *link, struct node_rx_hdr *rx) } static inline void rx_demux_event_done(memq_link_t *link, - struct node_rx_hdr *rx) + struct node_rx_event_done *done) { - struct node_rx_event_done *done = (void *)rx; struct ull_hdr *ull_hdr; void *release; diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv.c b/subsys/bluetooth/controller/ll_sw/ull_adv.c index 244719dd45f..269d4dddb5b 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_adv.c +++ b/subsys/bluetooth/controller/ll_sw/ull_adv.c @@ -117,6 +117,9 @@ static void init_set(struct ll_adv_set *adv); static struct ll_adv_set ll_adv[BT_CTLR_ADV_SET]; +static uint8_t ticker_update_req; +static uint8_t ticker_update_ack; + #if defined(CONFIG_BT_TICKER_EXT) static struct ticker_ext ll_adv_ticker_ext[BT_CTLR_ADV_SET]; #endif /* CONFIG_BT_TICKER_EXT */ @@ -315,6 +318,17 @@ uint8_t ll_adv_params_set(uint16_t interval, uint8_t adv_type, adv_type = 0x05; /* index of PDU_ADV_TYPE_EXT_IND in */ /* pdu_adv_type[] */ + /* Fallback to 1M if upper layer did not check HCI + * parameters for Coded PHY support. + * This fallback allows *testing* extended advertising + * using 1M using a upper layer that is requesting Coded + * PHY on Controllers without Coded PHY support. + */ + if (!IS_ENABLED(CONFIG_BT_CTLR_PHY_CODED) && + (phy_p == PHY_CODED)) { + phy_p = PHY_1M; + } + adv->lll.phy_p = phy_p; adv->lll.phy_flags = PHY_FLAGS_S8; } @@ -581,15 +595,28 @@ uint8_t ll_adv_params_set(uint16_t interval, uint8_t adv_type, /* No SyncInfo in primary channel PDU */ #if (CONFIG_BT_CTLR_ADV_AUX_SET > 0) + /* Fallback to 1M if upper layer did not check HCI + * parameters for Coded PHY support. + * This fallback allows *testing* extended advertising + * using 1M using a upper layer that is requesting Coded + * PHY on Controllers without Coded PHY support. + */ + if (!IS_ENABLED(CONFIG_BT_CTLR_PHY_CODED) && + (phy_s == PHY_CODED)) { + phy_s = PHY_1M; + } + + adv->lll.phy_s = phy_s; + /* AuxPtr */ if (pri_hdr_prev.aux_ptr) { pri_dptr_prev -= sizeof(struct pdu_adv_aux_ptr); } if (pri_hdr->aux_ptr) { pri_dptr -= sizeof(struct pdu_adv_aux_ptr); - ull_adv_aux_ptr_fill((void *)pri_dptr, 0U, phy_s); + ull_adv_aux_ptr_fill((void *)pri_dptr, 0U, + adv->lll.phy_s); } - adv->lll.phy_s = phy_s; #endif /* (CONFIG_BT_CTLR_ADV_AUX_SET > 0) */ /* ADI */ @@ -861,7 +888,7 @@ uint8_t ll_adv_enable(uint8_t enable) } /* Check advertising not terminated */ - type = &adv->lll.node_rx_adv_term->type; + type = &adv->lll.node_rx_adv_term->hdr.type; if (*type == NODE_RX_TYPE_NONE) { /* Reset event counter, update duration, * and max events @@ -1012,17 +1039,18 @@ uint8_t ll_adv_enable(uint8_t enable) conn_lll->empty = 0; #if defined(CONFIG_BT_CTLR_PHY) - conn_lll->phy_flags = 0; if (0) { #if defined(CONFIG_BT_CTLR_ADV_EXT) } else if (pdu_adv->type == PDU_ADV_TYPE_EXT_IND) { conn_lll->phy_tx = lll->phy_s; conn_lll->phy_tx_time = lll->phy_s; + conn_lll->phy_flags = lll->phy_flags; conn_lll->phy_rx = lll->phy_s; #endif /* CONFIG_BT_CTLR_ADV_EXT */ } else { conn_lll->phy_tx = PHY_1M; conn_lll->phy_tx_time = PHY_1M; + conn_lll->phy_flags = PHY_FLAGS_S8; conn_lll->phy_rx = PHY_1M; } #endif /* CONFIG_BT_CTLR_PHY */ @@ -1089,7 +1117,7 @@ uint8_t ll_adv_enable(uint8_t enable) /* NOTE: use allocated link for generating dedicated * terminate ind rx node */ - conn->llcp_terminate.node_rx.hdr.link = link; + conn->llcp_terminate.node_rx.rx.hdr.link = link; #if defined(CONFIG_BT_CTLR_PHY) conn->phy_pref_tx = ull_conn_default_phy_tx_get(); @@ -1940,9 +1968,6 @@ static uint32_t ticker_update_rand(struct ll_adv_set *adv, uint32_t ticks_delay_ (ret == TICKER_STATUS_BUSY) || (fp_op_func == NULL)); -#if defined(CONFIG_BT_CTLR_JIT_SCHEDULING) - adv->delay = random_delay; -#endif return random_delay; } @@ -1952,7 +1977,7 @@ void ull_adv_done(struct node_rx_event_done *done) { #if defined(CONFIG_BT_CTLR_ADV_EXT) struct lll_adv_aux *lll_aux; - struct node_rx_hdr *rx_hdr; + struct node_rx_pdu *rx; uint8_t handle; uint32_t ret; #endif /* CONFIG_BT_CTLR_ADV_EXT */ @@ -1992,8 +2017,9 @@ void ull_adv_done(struct node_rx_event_done *done) /* Check if we have enough time to re-schedule */ if (delay_remain > prepare_overhead) { - uint32_t ticks_adjust_minus; uint32_t interval_us = adv->interval * ADV_INT_UNIT_US; + uint32_t ticks_adjust_minus; + uint32_t random_delay; /* Get negative ticker adjustment needed to pull back ADV one * interval plus the randomized delay. This means that the ticker @@ -2018,10 +2044,12 @@ void ull_adv_done(struct node_rx_event_done *done) * ticker_stop, e.g. from ull_periph_setup. This is not a problem * and we can safely ignore the operation result. */ - ticker_update_rand(adv, delay_remain - prepare_overhead, - prepare_overhead, ticks_adjust_minus, NULL); + random_delay = ticker_update_rand(adv, delay_remain - prepare_overhead, + prepare_overhead, ticks_adjust_minus, + NULL); /* Delay from ticker_update_rand is in addition to the last random delay */ + adv->delay = random_delay; adv->delay += adv->delay_at_expire; /* Score of the event was increased due to the result, but since @@ -2042,15 +2070,15 @@ void ull_adv_done(struct node_rx_event_done *done) if (adv->max_events && (adv->event_counter >= adv->max_events)) { adv->max_events = 0U; - rx_hdr = (void *)lll->node_rx_adv_term; - rx_hdr->rx_ftr.param_adv_term.status = BT_HCI_ERR_LIMIT_REACHED; + rx = (void *)lll->node_rx_adv_term; + rx->rx_ftr.param_adv_term.status = BT_HCI_ERR_LIMIT_REACHED; } else if (adv->remain_duration_us && (adv->remain_duration_us <= ((uint64_t)adv->interval * ADV_INT_UNIT_US))) { adv->remain_duration_us = 0U; - rx_hdr = (void *)lll->node_rx_adv_term; - rx_hdr->rx_ftr.param_adv_term.status = BT_HCI_ERR_ADV_TIMEOUT; + rx = (void *)lll->node_rx_adv_term; + rx->rx_ftr.param_adv_term.status = BT_HCI_ERR_ADV_TIMEOUT; } else { return; } @@ -2058,10 +2086,10 @@ void ull_adv_done(struct node_rx_event_done *done) handle = ull_adv_handle_get(adv); LL_ASSERT(handle < BT_CTLR_ADV_SET); - rx_hdr->type = NODE_RX_TYPE_EXT_ADV_TERMINATE; - rx_hdr->handle = handle; - rx_hdr->rx_ftr.param_adv_term.conn_handle = 0xffff; - rx_hdr->rx_ftr.param_adv_term.num_events = adv->event_counter; + rx->hdr.type = NODE_RX_TYPE_EXT_ADV_TERMINATE; + rx->hdr.handle = handle; + rx->rx_ftr.param_adv_term.conn_handle = 0xffff; + rx->rx_ftr.param_adv_term.num_events = adv->event_counter; lll_aux = lll->aux; if (lll_aux) { @@ -2371,6 +2399,25 @@ static void ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift, TICKER_USER_ID_LLL, 0, &mfy); LL_ASSERT(!ret); +#if defined(CONFIG_BT_CTLR_JIT_SCHEDULING) || \ + (defined(CONFIG_BT_CTLR_ADV_EXT) && \ + (CONFIG_BT_CTLR_ADV_AUX_SET > 0) && \ + !defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO)) + /* Remember the ticks_at_expire, will be used by JIT scheduling + * and for checking latency calculating the aux offset for + * extended advertising. + */ + adv->ticks_at_expire = ticks_at_expire; + +#if defined(CONFIG_BT_CTLR_JIT_SCHEDULING) + adv->delay_at_expire = adv->delay; +#endif /* CONFIG_BT_CTLR_JIT_SCHEDULING */ +#endif /* CONFIG_BT_CTLR_JIT_SCHEDULING || + * (CONFIG_BT_CTLR_ADV_EXT && + * (CONFIG_BT_CTLR_ADV_AUX_SET > 0) && + * !CONFIG_BT_TICKER_EXT_EXPIRE_INFO) + */ + #if defined(CONFIG_BT_CTLR_ADV_EXT) && (CONFIG_BT_CTLR_ADV_AUX_SET > 0) && \ !defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) if (adv->lll.aux) { @@ -2379,11 +2426,6 @@ static void ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift, #endif /* CONFIG_BT_CTLR_ADV_EXT && (CONFIG_BT_CTLR_ADV_AUX_SET > 0) * !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ - -#if defined(CONFIG_BT_CTLR_JIT_SCHEDULING) - adv->ticks_at_expire = ticks_at_expire; - adv->delay_at_expire = adv->delay; -#endif /* CONFIG_BT_CTLR_JIT_SCHEDULING */ } /* Apply adv random delay */ @@ -2391,11 +2433,31 @@ static void ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift, if (!lll->is_hdcd) #endif /* CONFIG_BT_PERIPHERAL */ { - /* Apply random delay in range [0..ULL_ADV_RANDOM_DELAY] */ - random_delay = ticker_update_rand(adv, ULL_ADV_RANDOM_DELAY, - 0, 0, ticker_update_op_cb); + if (IS_ENABLED(CONFIG_BT_CTLR_JIT_SCHEDULING) || + (ticker_update_req == ticker_update_ack)) { + /* Ticker update requested */ + ticker_update_req++; + + /* Apply random delay in range [0..ULL_ADV_RANDOM_DELAY] */ + random_delay = ticker_update_rand(adv, ULL_ADV_RANDOM_DELAY, 0U, 0U, + ticker_update_op_cb); +#if defined(CONFIG_BT_CTLR_JIT_SCHEDULING) + adv->delay = random_delay; +#endif /* CONFIG_BT_CTLR_JIT_SCHEDULING */ + } else { + random_delay = 0U; + } #if defined(CONFIG_BT_CTLR_ADV_EXT) + uint16_t event_counter_inc; + + if (lazy == TICKER_LAZY_MUST_EXPIRE) { + lazy = 0U; + event_counter_inc = 0U; + } else { + event_counter_inc = (lazy + 1U); + } + if (adv->remain_duration_us && adv->event_counter > 0U) { #if defined(CONFIG_BT_CTLR_JIT_SCHEDULING) /* ticks_drift is always 0 with JIT scheduling, populate manually */ @@ -2414,7 +2476,7 @@ static void ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift, } } - adv->event_counter += (lazy + 1U); + adv->event_counter += event_counter_inc; #endif /* CONFIG_BT_CTLR_ADV_EXT */ } @@ -2423,6 +2485,9 @@ static void ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift, static void ticker_update_op_cb(uint32_t status, void *param) { + /* Reset update requested */ + ticker_update_ack = ticker_update_req; + #if defined(CONFIG_BT_PERIPHERAL) && (defined(CONFIG_BT_ASSERT) || defined(CONFIG_ASSERT)) struct ll_adv_set *adv = param; struct pdu_adv *pdu = lll_adv_data_peek(&adv->lll); @@ -2546,7 +2611,7 @@ static void disabled_cb(void *param) memset(cc, 0x00, sizeof(struct node_rx_cc)); cc->status = BT_HCI_ERR_ADV_TIMEOUT; - rx->hdr.rx_ftr.param = param; + rx->rx_ftr.param = param; #if defined(CONFIG_BT_CTLR_ADV_EXT) if (adv->lll.node_rx_adv_term) { @@ -2560,9 +2625,9 @@ static void disabled_cb(void *param) rx = (void *)adv->lll.node_rx_adv_term; rx->hdr.type = NODE_RX_TYPE_EXT_ADV_TERMINATE; rx->hdr.handle = handle; - rx->hdr.rx_ftr.param_adv_term.status = BT_HCI_ERR_ADV_TIMEOUT; - rx->hdr.rx_ftr.param_adv_term.conn_handle = 0xffff; - rx->hdr.rx_ftr.param_adv_term.num_events = adv->event_counter; + rx->rx_ftr.param_adv_term.status = BT_HCI_ERR_ADV_TIMEOUT; + rx->rx_ftr.param_adv_term.conn_handle = 0xffff; + rx->rx_ftr.param_adv_term.num_events = adv->event_counter; link = rx->hdr.link; } @@ -2727,18 +2792,18 @@ static void ext_disable(void *param) static void ext_disabled_cb(void *param) { struct lll_adv *lll = (void *)param; - struct node_rx_hdr *rx_hdr = (void *)lll->node_rx_adv_term; + struct node_rx_pdu *rx = lll->node_rx_adv_term; /* Under race condition, if a connection has been established then * node_rx is already utilized to send terminate event on connection */ - if (!rx_hdr) { + if (!rx) { return; } /* NOTE: parameters are already populated on disable, just enqueue here */ - ll_rx_put_sched(rx_hdr->link, rx_hdr); + ll_rx_put_sched(rx->hdr.link, rx); } #endif /* CONFIG_BT_CTLR_ADV_EXT */ diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv_aux.c b/subsys/bluetooth/controller/ll_sw/ull_adv_aux.c index 2480c286e4b..094ba62f853 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_adv_aux.c +++ b/subsys/bluetooth/controller/ll_sw/ull_adv_aux.c @@ -1344,11 +1344,18 @@ uint8_t ll_adv_aux_set_remove(uint8_t handle) if (lll->sync) { struct ll_adv_sync_set *sync; +#if defined(CONFIG_BT_CTLR_ADV_ISO) + if (lll->sync->iso) { + return BT_HCI_ERR_CMD_DISALLOWED; + } +#endif /* CONFIG_BT_CTLR_ADV_ISO */ + sync = HDR_LLL2ULL(lll->sync); if (sync->is_enabled) { return BT_HCI_ERR_CMD_DISALLOWED; } + lll->sync = NULL; ull_adv_sync_release(sync); @@ -2640,7 +2647,7 @@ int ull_adv_aux_stop(struct ll_adv_aux_set *aux) err = ull_ticker_stop_with_mark(TICKER_ID_ADV_AUX_BASE + aux_handle, aux, &aux->lll); - LL_ASSERT(err == 0 || err == -EALREADY); + LL_ASSERT_INFO2(err == 0 || err == -EALREADY, aux_handle, err); if (err) { return err; } @@ -2768,8 +2775,13 @@ struct pdu_adv_aux_ptr *ull_adv_aux_lll_offset_fill(struct pdu_adv *pdu, ptr += sizeof(struct pdu_adv_adi); } + /* Reference to aux ptr structure in the PDU */ aux_ptr = (void *)ptr; + + /* Aux offset value in micro seconds */ offs = HAL_TICKER_TICKS_TO_US(ticks_offset) + remainder_us - start_us; + + /* Fill aux offset in offset units 30 or 300 us */ offs = offs / OFFS_UNIT_30_US; if (!!(offs >> OFFS_UNIT_BITS)) { offs = offs / (OFFS_UNIT_300_US / OFFS_UNIT_30_US); @@ -3147,11 +3159,14 @@ static void mfy_aux_offset_get(void *param) struct lll_adv_aux *lll_aux; struct ll_adv_aux_set *aux; uint32_t ticks_to_expire; + uint32_t ticks_to_start; uint8_t data_chan_count; uint8_t *data_chan_map; uint32_t ticks_current; + uint32_t ticks_elapsed; struct ll_adv_set *adv; struct pdu_adv *pdu; + uint32_t ticks_now; uint32_t remainder; uint8_t ticker_id; uint8_t retry; @@ -3164,8 +3179,8 @@ static void mfy_aux_offset_get(void *param) id = TICKER_NULL; ticks_to_expire = 0U; - ticks_current = 0U; - retry = 4U; + ticks_current = adv->ticks_at_expire; + retry = 1U; /* Assert on first ticks_current change */ do { uint32_t volatile ret_cb; uint32_t ticks_previous; @@ -3191,6 +3206,13 @@ static void mfy_aux_offset_get(void *param) success = (ret_cb == TICKER_STATUS_SUCCESS); LL_ASSERT(success); + /* FIXME: If the reference ticks change then implement the + * compensation by adding the difference to the + * calculated ticks_to_expire. + * The ticks current can change if there are overlapping + * ticker expiry that update the ticks_current. + * For now assert until the fix implementation is added. + */ LL_ASSERT((ticks_current == ticks_previous) || retry--); LL_ASSERT(id != TICKER_NULL); @@ -3234,6 +3256,13 @@ static void mfy_aux_offset_get(void *param) aux_ptr->chan_idx = lll_chan_sel_2(lll_aux->data_chan_counter, aux->data_chan_id, data_chan_map, data_chan_count); + + ticks_now = ticker_ticks_now_get(); + ticks_elapsed = ticker_ticks_diff_get(ticks_now, ticks_current); + ticks_to_start = MAX(adv->ull.ticks_active_to_start, + adv->ull.ticks_prepare_to_start) - + adv->ull.ticks_preempt_to_start; + LL_ASSERT(ticks_elapsed < ticks_to_start); } static void ticker_op_cb(uint32_t status, void *param) diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv_internal.h b/subsys/bluetooth/controller/ll_sw/ull_adv_internal.h index a2a0db7391f..590c78bb4e0 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_adv_internal.h +++ b/subsys/bluetooth/controller/ll_sw/ull_adv_internal.h @@ -261,7 +261,7 @@ uint8_t ull_adv_sync_time_update(struct ll_adv_sync_set *sync, uint8_t ull_adv_sync_chm_update(void); /* helper function to cleanup after channel map update indications complete */ -void ull_adv_sync_chm_complete(struct node_rx_hdr *rx); +void ull_adv_sync_chm_complete(struct node_rx_pdu *rx); /* helper function to fill initial value of sync_info structure */ void ull_adv_sync_info_fill(struct ll_adv_sync_set *sync, @@ -302,7 +302,7 @@ struct ll_adv_iso_set *ull_adv_iso_get(uint8_t handle); uint8_t ull_adv_iso_chm_update(void); /* helper function to cleanup after channel map update complete */ -void ull_adv_iso_chm_complete(struct node_rx_hdr *rx); +void ull_adv_iso_chm_complete(struct node_rx_pdu *rx); /* helper function to schedule a mayfly to get BIG offset */ void ull_adv_iso_offset_get(struct ll_adv_sync_set *sync); diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv_iso.c b/subsys/bluetooth/controller/ll_sw/ull_adv_iso.c index d4e655fcf0d..4c5265b799c 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_adv_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_adv_iso.c @@ -86,11 +86,13 @@ static struct lll_adv_iso_stream stream_pool[CONFIG_BT_CTLR_ADV_ISO_STREAM_COUNT]; static void *stream_free; -uint8_t ll_big_create(uint8_t big_handle, uint8_t adv_handle, uint8_t num_bis, - uint32_t sdu_interval, uint16_t max_sdu, - uint16_t max_latency, uint8_t rtn, uint8_t phy, - uint8_t packing, uint8_t framing, uint8_t encryption, - uint8_t *bcode) +static uint8_t big_create(uint8_t big_handle, uint8_t adv_handle, uint8_t num_bis, + uint32_t sdu_interval, uint16_t max_sdu, + uint16_t max_latency, uint8_t rtn, uint8_t phy, + uint8_t packing, uint8_t framing, uint8_t encryption, + uint8_t *bcode, + uint16_t iso_interval, uint8_t nse, uint16_t max_pdu, + uint8_t bn, uint8_t irc, uint8_t pto, bool test_config) { uint8_t hdr_data[1 + sizeof(uint8_t *)]; struct lll_adv_sync *lll_adv_sync; @@ -118,7 +120,6 @@ uint8_t ll_big_create(uint8_t big_handle, uint8_t adv_handle, uint8_t num_bis, uint8_t *acad; uint32_t ret; uint8_t err; - uint8_t bn; int res; adv_iso = adv_iso_get(big_handle); @@ -156,14 +157,6 @@ uint8_t ll_big_create(uint8_t big_handle, uint8_t adv_handle, uint8_t num_bis, return BT_HCI_ERR_INVALID_PARAM; } - if (max_latency > 0x0FA0) { - return BT_HCI_ERR_INVALID_PARAM; - } - - if (rtn > 0x0F) { - return BT_HCI_ERR_INVALID_PARAM; - } - if (phy > (BT_HCI_LE_EXT_SCAN_PHY_1M | BT_HCI_LE_EXT_SCAN_PHY_2M | BT_HCI_LE_EXT_SCAN_PHY_CODED)) { @@ -181,6 +174,45 @@ uint8_t ll_big_create(uint8_t big_handle, uint8_t adv_handle, uint8_t num_bis, if (encryption > 1U) { return BT_HCI_ERR_INVALID_PARAM; } + + if (test_config) { + if (!IN_RANGE(iso_interval, 0x0004, 0x0C80)) { + return BT_HCI_ERR_INVALID_PARAM; + } + + if (!IN_RANGE(nse, 0x01, 0x1F)) { + return BT_HCI_ERR_INVALID_PARAM; + } + + if (!IN_RANGE(max_pdu, 0x01, MIN(0xFB, LL_BIS_OCTETS_TX_MAX))) { + return BT_HCI_ERR_INVALID_PARAM; + } + + if (!IN_RANGE(bn, 0x01, 0x07)) { + return BT_HCI_ERR_INVALID_PARAM; + } + + if (!IN_RANGE(irc, 0x01, 0x0F)) { + return BT_HCI_ERR_INVALID_PARAM; + } + + /* FIXME: PTO is currently limited to BN */ + if (!IN_RANGE(pto, 0x00, bn /*0x0F*/)) { + return BT_HCI_ERR_INVALID_PARAM; + } + + if (bn * irc + pto < nse) { + return BT_HCI_ERR_INVALID_PARAM; + } + } else { + if (max_latency > 0x0FA0) { + return BT_HCI_ERR_INVALID_PARAM; + } + + if (rtn > 0x0F) { + return BT_HCI_ERR_INVALID_PARAM; + } + } } /* Check if free BISes available */ @@ -276,7 +308,6 @@ uint8_t ll_big_create(uint8_t big_handle, uint8_t adv_handle, uint8_t num_bis, /* TODO: Move parameters to ULL if only accessed by ULL */ lll_adv_iso = &adv_iso->lll; lll_adv_iso->handle = big_handle; - lll_adv_iso->max_pdu = MIN(LL_BIS_OCTETS_TX_MAX, max_sdu); lll_adv_iso->phy = phy; lll_adv_iso->phy_flags = PHY_FLAGS_S8; @@ -304,32 +335,44 @@ uint8_t ll_big_create(uint8_t big_handle, uint8_t adv_handle, uint8_t num_bis, adv_iso_stream_handle_get(stream); } - /* FIXME: SDU per max latency */ - sdu_per_event = MAX((max_latency * USEC_PER_MSEC / sdu_interval), 2U) - - 1U; + if (test_config) { + lll_adv_iso->bn = bn; + lll_adv_iso->iso_interval = iso_interval; + lll_adv_iso->irc = irc; + lll_adv_iso->nse = nse; + lll_adv_iso->max_pdu = max_pdu; + iso_interval_us = iso_interval * PERIODIC_INT_UNIT_US; + + } else { + lll_adv_iso->max_pdu = MIN(LL_BIS_OCTETS_TX_MAX, max_sdu); + + /* FIXME: SDU per max latency */ + sdu_per_event = MAX((max_latency * USEC_PER_MSEC / sdu_interval), 2U) - + 1U; - /* BN (Burst Count), Mandatory BN = 1 */ - bn = DIV_ROUND_UP(max_sdu, lll_adv_iso->max_pdu) * sdu_per_event; - if (bn > PDU_BIG_BN_MAX) { - /* Restrict each BIG event to maximum burst per BIG event */ - lll_adv_iso->bn = PDU_BIG_BN_MAX; + /* BN (Burst Count), Mandatory BN = 1 */ + bn = DIV_ROUND_UP(max_sdu, lll_adv_iso->max_pdu) * sdu_per_event; + if (bn > PDU_BIG_BN_MAX) { + /* Restrict each BIG event to maximum burst per BIG event */ + lll_adv_iso->bn = PDU_BIG_BN_MAX; - /* Ceil the required burst count per SDU to next maximum burst - * per BIG event. + /* Ceil the required burst count per SDU to next maximum burst + * per BIG event. + */ + bn = DIV_ROUND_UP(bn, PDU_BIG_BN_MAX) * PDU_BIG_BN_MAX; + } else { + lll_adv_iso->bn = bn; + } + + /* Calculate ISO interval */ + /* iso_interval shall be at least SDU interval, + * or integer multiple of SDU interval for unframed PDUs */ - bn = DIV_ROUND_UP(bn, PDU_BIG_BN_MAX) * PDU_BIG_BN_MAX; - } else { - lll_adv_iso->bn = bn; + iso_interval_us = ((sdu_interval * lll_adv_iso->bn * sdu_per_event) / + (bn * PERIODIC_INT_UNIT_US)) * PERIODIC_INT_UNIT_US; + lll_adv_iso->iso_interval = iso_interval_us / PERIODIC_INT_UNIT_US; } - /* Calculate ISO interval */ - /* iso_interval shall be at least SDU interval, - * or integer multiple of SDU interval for unframed PDUs - */ - iso_interval_us = ((sdu_interval * lll_adv_iso->bn * sdu_per_event) / - (bn * PERIODIC_INT_UNIT_US)) * PERIODIC_INT_UNIT_US; - lll_adv_iso->iso_interval = iso_interval_us / PERIODIC_INT_UNIT_US; - /* Calculate max available ISO event spacing */ slot_overhead = HAL_TICKER_TICKS_TO_US(ticks_slot_overhead); if (slot_overhead < iso_interval_us) { @@ -338,42 +381,50 @@ uint8_t ll_big_create(uint8_t big_handle, uint8_t adv_handle, uint8_t num_bis, event_spacing_max = 0U; } -ll_big_create_rtn_retry: - /* Immediate Repetition Count (IRC), Mandatory IRC = 1 */ - lll_adv_iso->irc = rtn + 1U; + /* Negotiate event spacing */ + do { + if (!test_config) { + /* Immediate Repetition Count (IRC), Mandatory IRC = 1 */ + lll_adv_iso->irc = rtn + 1U; - /* Calculate NSE (No. of Sub Events), Mandatory NSE = 1, - * without PTO added. - */ - lll_adv_iso->nse = lll_adv_iso->bn * lll_adv_iso->irc; + /* Calculate NSE (No. of Sub Events), Mandatory NSE = 1, + * without PTO added. + */ + lll_adv_iso->nse = lll_adv_iso->bn * lll_adv_iso->irc; + } - /* NOTE: Calculate sub_interval, if interleaved then it is Num_BIS x - * BIS_Spacing (by BT Spec.) - * else if sequential, then by our implementation, lets keep it - * max_tx_time for Max_PDU + tMSS. - */ - lll_adv_iso->sub_interval = PDU_BIS_US(lll_adv_iso->max_pdu, encryption, - phy, lll_adv_iso->phy_flags) + - EVENT_MSS_US; - ctrl_spacing = PDU_BIS_US(sizeof(struct pdu_big_ctrl), encryption, phy, - lll_adv_iso->phy_flags); - latency_packing = lll_adv_iso->sub_interval * lll_adv_iso->nse * - lll_adv_iso->num_bis; - event_spacing = latency_packing + ctrl_spacing + - EVENT_OVERHEAD_START_US + EVENT_OVERHEAD_END_US; + /* NOTE: Calculate sub_interval, if interleaved then it is Num_BIS x + * BIS_Spacing (by BT Spec.) + * else if sequential, then by our implementation, lets keep it + * max_tx_time for Max_PDU + tMSS. + */ + lll_adv_iso->sub_interval = PDU_BIS_US(lll_adv_iso->max_pdu, encryption, + phy, lll_adv_iso->phy_flags) + + EVENT_MSS_US; + ctrl_spacing = PDU_BIS_US(sizeof(struct pdu_big_ctrl), encryption, phy, + lll_adv_iso->phy_flags); + latency_packing = lll_adv_iso->sub_interval * lll_adv_iso->nse * + lll_adv_iso->num_bis; + event_spacing = latency_packing + ctrl_spacing + + EVENT_OVERHEAD_START_US + EVENT_OVERHEAD_END_US; + + /* Check if ISO interval too small to fit the calculated BIG event + * timing required for the supplied BIG create parameters. + */ + if (event_spacing > event_spacing_max) { + /* Check if we can reduce RTN to meet eventing spacing */ + if (!test_config && rtn) { + rtn--; + } else { + break; + } + } + } while (event_spacing > event_spacing_max); /* Check if ISO interval too small to fit the calculated BIG event * timing required for the supplied BIG create parameters. */ if (event_spacing > event_spacing_max) { - - /* Check if we can reduce RTN to meet eventing spacing */ - if (rtn) { - rtn--; - - goto ll_big_create_rtn_retry; - } - /* Release allocated link buffers */ ll_rx_link_release(link_cmplt); ll_rx_link_release(link_term); @@ -381,29 +432,34 @@ uint8_t ll_big_create(uint8_t big_handle, uint8_t adv_handle, uint8_t num_bis, return BT_HCI_ERR_INVALID_PARAM; } + if (test_config) { + lll_adv_iso->pto = pto; + + } else { + lll_adv_iso->ptc = ptc_calc(lll_adv_iso, event_spacing, + event_spacing_max); + + /* Pre-Transmission Offset (PTO) */ + if (lll_adv_iso->ptc) { + lll_adv_iso->pto = bn / lll_adv_iso->bn; + } else { + lll_adv_iso->pto = 0U; + } + + /* Make room for pre-transmissions */ + lll_adv_iso->nse += lll_adv_iso->ptc; + } + /* Based on packing requested, sequential or interleaved */ if (packing) { /* Interleaved Packing */ lll_adv_iso->bis_spacing = lll_adv_iso->sub_interval; - lll_adv_iso->ptc = ptc_calc(lll_adv_iso, event_spacing, - event_spacing_max); - lll_adv_iso->nse += lll_adv_iso->ptc; lll_adv_iso->sub_interval = lll_adv_iso->bis_spacing * - lll_adv_iso->nse; + lll_adv_iso->nse; } else { /* Sequential Packing */ - lll_adv_iso->ptc = ptc_calc(lll_adv_iso, event_spacing, - event_spacing_max); - lll_adv_iso->nse += lll_adv_iso->ptc; lll_adv_iso->bis_spacing = lll_adv_iso->sub_interval * - lll_adv_iso->nse; - } - - /* Pre-Transmission Offset (PTO) */ - if (lll_adv_iso->ptc) { - lll_adv_iso->pto = bn / lll_adv_iso->bn; - } else { - lll_adv_iso->pto = 0U; + lll_adv_iso->nse; } /* TODO: Group count, GC = NSE / BN; PTO = GC - IRC; @@ -552,7 +608,7 @@ uint8_t ll_big_create(uint8_t big_handle, uint8_t adv_handle, uint8_t num_bis, /* Store the link buffer for ISO create and terminate complete event */ adv_iso->node_rx_complete.hdr.link = link_cmplt; - adv_iso->node_rx_terminate.hdr.link = link_term; + adv_iso->node_rx_terminate.rx.hdr.link = link_term; /* Initialise LLL header members */ lll_hdr_init(lll_adv_iso, adv_iso); @@ -588,6 +644,23 @@ uint8_t ll_big_create(uint8_t big_handle, uint8_t adv_handle, uint8_t num_bis, return BT_HCI_ERR_SUCCESS; } +uint8_t ll_big_create(uint8_t big_handle, uint8_t adv_handle, uint8_t num_bis, + uint32_t sdu_interval, uint16_t max_sdu, + uint16_t max_latency, uint8_t rtn, uint8_t phy, + uint8_t packing, uint8_t framing, uint8_t encryption, + uint8_t *bcode) +{ + return big_create(big_handle, adv_handle, num_bis, sdu_interval, max_sdu, + max_latency, rtn, phy, packing, framing, encryption, bcode, + 0 /*iso_interval*/, + 0 /*nse*/, + 0 /*max_pdu*/, + 0 /*bn*/, + 0 /*irc*/, + 0 /*pto*/, + false); +} + uint8_t ll_big_test_create(uint8_t big_handle, uint8_t adv_handle, uint8_t num_bis, uint32_t sdu_interval, uint16_t iso_interval, uint8_t nse, uint16_t max_sdu, @@ -595,25 +668,11 @@ uint8_t ll_big_test_create(uint8_t big_handle, uint8_t adv_handle, uint8_t framing, uint8_t bn, uint8_t irc, uint8_t pto, uint8_t encryption, uint8_t *bcode) { - /* TODO: Implement */ - ARG_UNUSED(big_handle); - ARG_UNUSED(adv_handle); - ARG_UNUSED(num_bis); - ARG_UNUSED(sdu_interval); - ARG_UNUSED(iso_interval); - ARG_UNUSED(nse); - ARG_UNUSED(max_sdu); - ARG_UNUSED(max_pdu); - ARG_UNUSED(phy); - ARG_UNUSED(packing); - ARG_UNUSED(framing); - ARG_UNUSED(bn); - ARG_UNUSED(irc); - ARG_UNUSED(pto); - ARG_UNUSED(encryption); - ARG_UNUSED(bcode); - - return BT_HCI_ERR_CMD_DISALLOWED; + return big_create(big_handle, adv_handle, num_bis, sdu_interval, max_sdu, + 0 /*max_latency*/, + 0 /*rtn*/, + phy, packing, framing, encryption, bcode, + iso_interval, nse, max_pdu, bn, irc, pto, true); } uint8_t ll_big_terminate(uint8_t big_handle, uint8_t reason) @@ -651,11 +710,8 @@ uint8_t ll_big_terminate(uint8_t big_handle, uint8_t reason) while (num_bis--) { stream_handle = lll_adv_iso->stream_handle[num_bis]; handle = LL_BIS_ADV_HANDLE_FROM_IDX(stream_handle); - err = ll_remove_iso_path(handle, + (void)ll_remove_iso_path(handle, BIT(BT_HCI_DATAPATH_DIR_HOST_TO_CTLR)); - if (err) { - return err; - } } lll_adv_sync = lll_adv->sync; @@ -681,7 +737,7 @@ uint8_t ll_big_terminate(uint8_t big_handle, uint8_t reason) node_rx = (void *)&adv_iso->node_rx_terminate; node_rx->hdr.type = NODE_RX_TYPE_BIG_TERMINATE; node_rx->hdr.handle = big_handle; - node_rx->hdr.rx_ftr.param = adv_iso; + node_rx->rx_ftr.param = adv_iso; if (reason == BT_HCI_ERR_REMOTE_USER_TERM_CONN) { *((uint8_t *)node_rx->pdu) = BT_HCI_ERR_LOCALHOST_TERM_CONN; @@ -710,8 +766,74 @@ int ull_adv_iso_init(void) int ull_adv_iso_reset(void) { + uint8_t handle; int err; + handle = CONFIG_BT_CTLR_ADV_ISO_SET; + while (handle--) { + struct lll_adv_sync *adv_sync_lll; + struct lll_adv_iso *adv_iso_lll; + struct ll_adv_iso_set *adv_iso; + volatile uint32_t ret_cb; + struct lll_adv *adv_lll; + uint32_t ret; + void *mark; + + adv_iso = &ll_adv_iso[handle]; + adv_iso_lll = &adv_iso->lll; + adv_lll = adv_iso_lll->adv; + if (!adv_lll) { + continue; + } + + mark = ull_disable_mark(adv_iso); + LL_ASSERT(mark == adv_iso); + + /* Stop event scheduling */ + ret_cb = TICKER_STATUS_BUSY; + ret = ticker_stop(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_THREAD, + TICKER_ID_ADV_ISO_BASE + adv_iso_lll->handle, + ull_ticker_status_give, (void *)&ret_cb); + ret = ull_ticker_status_take(ret, &ret_cb); + if (ret) { + mark = ull_disable_unmark(adv_iso); + LL_ASSERT(mark == adv_iso); + + /* Assert as there shall be a ticker instance active */ + LL_ASSERT(false); + + return BT_HCI_ERR_CMD_DISALLOWED; + } + + /* Abort any events in LLL pipeline */ + err = ull_disable(adv_iso_lll); + LL_ASSERT(!err || (err == -EALREADY)); + + mark = ull_disable_unmark(adv_iso); + LL_ASSERT(mark == adv_iso); + + /* Reset associated streams */ + while (adv_iso_lll->num_bis--) { + struct lll_adv_iso_stream *stream; + uint16_t stream_handle; + + stream_handle = adv_iso_lll->stream_handle[adv_iso_lll->num_bis]; + stream = ull_adv_iso_stream_get(stream_handle); + if (stream) { + stream->link_tx_free = NULL; + } + } + + /* Remove Periodic Advertising association */ + adv_sync_lll = adv_lll->sync; + if (adv_sync_lll) { + adv_sync_lll->iso = NULL; + } + + /* Remove Extended Advertising association */ + adv_iso_lll->adv = NULL; + } + err = init_reset(); if (err) { return err; @@ -740,7 +862,7 @@ uint8_t ull_adv_iso_chm_update(void) return 0; } -void ull_adv_iso_chm_complete(struct node_rx_hdr *rx) +void ull_adv_iso_chm_complete(struct node_rx_pdu *rx) { struct lll_adv_sync *sync_lll; struct lll_adv_iso *iso_lll; @@ -868,7 +990,7 @@ void ull_adv_iso_done_complete(struct node_rx_event_done *done) { struct ll_adv_iso_set *adv_iso; struct lll_adv_iso *lll; - struct node_rx_hdr *rx; + struct node_rx_pdu *rx; memq_link_t *link; /* switch to normal prepare */ @@ -880,7 +1002,7 @@ void ull_adv_iso_done_complete(struct node_rx_event_done *done) /* Prepare BIG complete event */ rx = (void *)&adv_iso->node_rx_complete; - link = rx->link; + link = rx->hdr.link; if (!link) { /* NOTE: When BIS events have overlapping prepare placed in * in the pipeline, more than one done complete event @@ -889,10 +1011,10 @@ void ull_adv_iso_done_complete(struct node_rx_event_done *done) */ return; } - rx->link = NULL; + rx->hdr.link = NULL; - rx->type = NODE_RX_TYPE_BIG_COMPLETE; - rx->handle = lll->handle; + rx->hdr.type = NODE_RX_TYPE_BIG_COMPLETE; + rx->hdr.handle = lll->handle; rx->rx_ftr.param = adv_iso; ll_rx_put_sched(link, rx); diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv_sync.c b/subsys/bluetooth/controller/ll_sw/ull_adv_sync.c index 897a39ce65f..c8f12876620 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_adv_sync.c +++ b/subsys/bluetooth/controller/ll_sw/ull_adv_sync.c @@ -1274,7 +1274,7 @@ uint8_t ull_adv_sync_chm_update(void) return 0; } -void ull_adv_sync_chm_complete(struct node_rx_hdr *rx) +void ull_adv_sync_chm_complete(struct node_rx_pdu *rx) { uint8_t hdr_data[ULL_ADV_HDR_DATA_LEN_SIZE + ULL_ADV_HDR_DATA_ACAD_PTR_SIZE]; @@ -2022,7 +2022,7 @@ static uint8_t sync_stop(struct ll_adv_sync_set *sync) err = ull_ticker_stop_with_mark(TICKER_ID_ADV_SYNC_BASE + sync_handle, sync, &sync->lll); - LL_ASSERT(err == 0 || err == -EALREADY); + LL_ASSERT_INFO2(err == 0 || err == -EALREADY, sync_handle, err); if (err) { return BT_HCI_ERR_CMD_DISALLOWED; } diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv_types.h b/subsys/bluetooth/controller/ll_sw/ull_adv_types.h index de0e4908b6f..9a9c016295e 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_adv_types.h +++ b/subsys/bluetooth/controller/ll_sw/ull_adv_types.h @@ -58,11 +58,23 @@ struct ll_adv_set { #if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX) struct lll_df_adv_cfg *df_cfg; #endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */ + + +#if defined(CONFIG_BT_CTLR_JIT_SCHEDULING) || \ + (defined(CONFIG_BT_CTLR_ADV_EXT) && \ + (CONFIG_BT_CTLR_ADV_AUX_SET > 0) && \ + !defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO)) #if defined(CONFIG_BT_CTLR_JIT_SCHEDULING) uint32_t delay; uint32_t delay_at_expire; - uint32_t ticks_at_expire; #endif /* CONFIG_BT_CTLR_JIT_SCHEDULING */ + + uint32_t ticks_at_expire; +#endif /* CONFIG_BT_CTLR_JIT_SCHEDULING || + * (CONFIG_BT_CTLR_ADV_EXT && + * (CONFIG_BT_CTLR_ADV_AUX_SET > 0) && + * !CONFIG_BT_TICKER_EXT_EXPIRE_INFO) + */ }; struct ll_adv_aux_set { @@ -106,16 +118,12 @@ struct ll_adv_iso_set { * clock. */ - struct { - struct node_rx_hdr hdr; - } node_rx_complete; + struct node_rx_pdu node_rx_complete; struct { - struct node_rx_hdr hdr; - union { - uint8_t pdu[0] __aligned(4); - uint8_t reason; - }; + struct node_rx_pdu rx; + /* Dummy declaration to ensure space allocated to hold one pdu bytes */ + uint8_t dummy; } node_rx_terminate; #if defined(CONFIG_BT_CTLR_HCI_ADV_HANDLE_MAPPING) diff --git a/subsys/bluetooth/controller/ll_sw/ull_central.c b/subsys/bluetooth/controller/ll_sw/ull_central.c index 7ea3c600ea6..a39ef8b5989 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_central.c +++ b/subsys/bluetooth/controller/ll_sw/ull_central.c @@ -215,11 +215,12 @@ uint8_t ll_create_connection(uint16_t scan_interval, uint16_t scan_window, #if defined(CONFIG_BT_CTLR_PHY) /* Use the default 1M PHY, extended connection initiation in LLL will - * update this with the correct PHY. + * update this with the correct PHY and defaults using the coding on + * which the connection is established. */ conn_lll->phy_tx = PHY_1M; - conn_lll->phy_flags = 0; conn_lll->phy_tx_time = PHY_1M; + conn_lll->phy_flags = PHY_FLAGS_S8; conn_lll->phy_rx = PHY_1M; #endif /* CONFIG_BT_CTLR_PHY */ @@ -295,7 +296,7 @@ uint8_t ll_create_connection(uint16_t scan_interval, uint16_t scan_window, /* NOTE: use allocated link for generating dedicated * terminate ind rx node */ - conn->llcp_terminate.node_rx.hdr.link = link; + conn->llcp_terminate.node_rx.rx.hdr.link = link; #if defined(CONFIG_BT_CTLR_PHY) conn->phy_pref_tx = ull_conn_default_phy_tx_get(); @@ -516,7 +517,7 @@ uint8_t ll_connect_disable(void **rx) memq_link_t *link; conn = HDR_LLL2ULL(conn_lll); - node_rx = (void *)&conn->llcp_terminate.node_rx; + node_rx = (void *)&conn->llcp_terminate.node_rx.rx; link = node_rx->hdr.link; LL_ASSERT(link); @@ -536,7 +537,7 @@ uint8_t ll_connect_disable(void **rx) * LLL context for other cases, pass LLL context as * parameter. */ - node_rx->hdr.rx_ftr.param = scan_lll; + node_rx->rx_ftr.param = scan_lll; *rx = node_rx; } @@ -613,7 +614,7 @@ int ull_central_reset(void) return err; } -void ull_central_cleanup(struct node_rx_hdr *rx_free) +void ull_central_cleanup(struct node_rx_pdu *rx_free) { struct lll_conn *conn_lll; struct ll_scan_set *scan; @@ -663,7 +664,7 @@ void ull_central_cleanup(struct node_rx_hdr *rx_free) #endif /* CONFIG_BT_CTLR_ADV_EXT && CONFIG_BT_CTLR_PHY_CODED */ } -void ull_central_setup(struct node_rx_hdr *rx, struct node_rx_ftr *ftr, +void ull_central_setup(struct node_rx_pdu *rx, struct node_rx_ftr *ftr, struct lll_conn *lll) { uint32_t conn_offset_us, conn_interval_us; @@ -683,7 +684,7 @@ void ull_central_setup(struct node_rx_hdr *rx, struct node_rx_ftr *ftr, void *node; /* Get reference to Tx-ed CONNECT_IND PDU */ - pdu_tx = (void *)((struct node_rx_pdu *)rx)->pdu; + pdu_tx = (void *)rx->pdu; /* Backup peer addr and type, as we reuse the Tx-ed PDU to generate * event towards LL @@ -742,7 +743,7 @@ void ull_central_setup(struct node_rx_hdr *rx, struct node_rx_ftr *ftr, conn = lll->hdr.parent; lll->handle = ll_conn_handle_get(conn); - rx->handle = lll->handle; + rx->hdr.handle = lll->handle; /* Set LLCP as connection-wise connected */ ull_cp_state_set(conn, ULL_CP_CONNECTED); @@ -754,7 +755,7 @@ void ull_central_setup(struct node_rx_hdr *rx, struct node_rx_ftr *ftr, /* Use the link stored in the node rx to enqueue connection * complete node rx towards LL context. */ - link = rx->link; + link = rx->hdr.link; /* Use Channel Selection Algorithm #2 if peer too supports it */ if (IS_ENABLED(CONFIG_BT_CTLR_CHAN_SEL_2)) { @@ -770,11 +771,11 @@ void ull_central_setup(struct node_rx_hdr *rx, struct node_rx_ftr *ftr, ll_rx_put(link, rx); /* use the rx node for CSA event */ - rx = (void *)rx_csa; - link = rx->link; + rx = rx_csa; + link = rx->hdr.link; - rx->handle = lll->handle; - rx->type = NODE_RX_TYPE_CHAN_SEL_ALGO; + rx->hdr.handle = lll->handle; + rx->hdr.type = NODE_RX_TYPE_CHAN_SEL_ALGO; cs = (void *)rx_csa->pdu; @@ -1057,7 +1058,7 @@ static inline void conn_release(struct ll_scan_set *scan) conn = HDR_LLL2ULL(lll); - cc = (void *)&conn->llcp_terminate.node_rx; + cc = (void *)&conn->llcp_terminate.node_rx.rx; link = cc->hdr.link; LL_ASSERT(link); diff --git a/subsys/bluetooth/controller/ll_sw/ull_central_internal.h b/subsys/bluetooth/controller/ll_sw/ull_central_internal.h index 76bf6fe81db..87270d198cc 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_central_internal.h +++ b/subsys/bluetooth/controller/ll_sw/ull_central_internal.h @@ -5,8 +5,8 @@ */ int ull_central_reset(void); -void ull_central_cleanup(struct node_rx_hdr *rx_free); -void ull_central_setup(struct node_rx_hdr *rx, struct node_rx_ftr *ftr, +void ull_central_cleanup(struct node_rx_pdu *rx_free); +void ull_central_setup(struct node_rx_pdu *rx, struct node_rx_ftr *ftr, struct lll_conn *lll); void ull_central_ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift, uint32_t remainder, uint16_t lazy, uint8_t force, diff --git a/subsys/bluetooth/controller/ll_sw/ull_conn.c b/subsys/bluetooth/controller/ll_sw/ull_conn.c index ddb9459c3dc..7383478d176 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_conn.c +++ b/subsys/bluetooth/controller/ll_sw/ull_conn.c @@ -819,7 +819,7 @@ bool ull_conn_peer_connected(uint8_t const own_id_addr_type, } #endif /* CONFIG_BT_CTLR_CHECK_SAME_PEER_CONN */ -void ull_conn_setup(memq_link_t *rx_link, struct node_rx_hdr *rx) +void ull_conn_setup(memq_link_t *rx_link, struct node_rx_pdu *rx) { struct node_rx_ftr *ftr; struct ull_hdr *hdr; @@ -827,7 +827,7 @@ void ull_conn_setup(memq_link_t *rx_link, struct node_rx_hdr *rx) /* Store the link in the node rx so that when done event is * processed it can be used to enqueue node rx towards LL context */ - rx->link = rx_link; + rx->hdr.link = rx_link; /* NOTE: LLL conn context SHALL be after lll_hdr in * struct lll_adv and struct lll_scan. @@ -1683,7 +1683,7 @@ static void ticker_start_conn_op_cb(uint32_t status, void *param) static void conn_setup_adv_scan_disabled_cb(void *param) { struct node_rx_ftr *ftr; - struct node_rx_hdr *rx; + struct node_rx_pdu *rx; struct lll_conn *lll; /* NOTE: LLL conn context SHALL be after lll_hdr in @@ -1730,7 +1730,7 @@ static inline void disable(uint16_t handle) err = ull_ticker_stop_with_mark(TICKER_ID_CONN_BASE + handle, conn, &conn->lll); - LL_ASSERT(err == 0 || err == -EALREADY); + LL_ASSERT_INFO2(err == 0 || err == -EALREADY, handle, err); conn->lll.handle = LLL_HANDLE_INVALID; conn->lll.link_tx_free = NULL; @@ -1809,7 +1809,7 @@ static void conn_cleanup(struct ll_conn *conn, uint8_t reason) * value and handle through the mayfly scheduling of the * tx_lll_flush. */ - rx = (void *)&conn->llcp_terminate.node_rx; + rx = (void *)&conn->llcp_terminate.node_rx.rx; rx->hdr.handle = conn->lll.handle; rx->hdr.type = NODE_RX_TYPE_TERMINATE; *((uint8_t *)rx->pdu) = reason; diff --git a/subsys/bluetooth/controller/ll_sw/ull_conn_internal.h b/subsys/bluetooth/controller/ll_sw/ull_conn_internal.h index e047a114008..3a869b6538f 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_conn_internal.h +++ b/subsys/bluetooth/controller/ll_sw/ull_conn_internal.h @@ -21,7 +21,7 @@ bool ull_conn_peer_connected(uint8_t const own_id_addr_type, uint8_t const *const own_id_addr, uint8_t const peer_id_addr_type, uint8_t const *const peer_id_addr); -void ull_conn_setup(memq_link_t *rx_link, struct node_rx_hdr *rx); +void ull_conn_setup(memq_link_t *rx_link, struct node_rx_pdu *rx); void ull_conn_rx(memq_link_t *link, struct node_rx_pdu **rx); int ull_conn_llcp(struct ll_conn *conn, uint32_t ticks_at_expire, uint32_t remainder, uint16_t lazy); diff --git a/subsys/bluetooth/controller/ll_sw/ull_conn_iso.c b/subsys/bluetooth/controller/ll_sw/ull_conn_iso.c index 4d390576763..06f8f9f3bc5 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_conn_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_conn_iso.c @@ -470,12 +470,15 @@ void ull_conn_iso_done(struct node_rx_event_done *done) /* CIS was setup and is now expected to be going */ if (done->extra.trx_performed_bitmask & (1U << LL_CIS_IDX_FROM_HANDLE(cis->lll.handle))) { - if (done->extra.mic_state == LLL_CONN_MIC_FAIL) { + if (false) { +#if defined(CONFIG_BT_CTLR_LE_ENC) + } else if (done->extra.mic_state == LLL_CONN_MIC_FAIL) { /* MIC failure - stop CIS and defer cleanup to after * teardown. */ ull_conn_iso_cis_stop(cis, NULL, BT_HCI_ERR_TERM_DUE_TO_MIC_FAIL); +#endif /* CONFIG_BT_CTLR_LE_ENC */ } else { cis->event_expire = 0U; } @@ -1568,8 +1571,7 @@ static void disable(uint16_t handle) err = ull_ticker_stop_with_mark(TICKER_ID_CONN_ISO_BASE + handle, cig, &cig->lll); - - LL_ASSERT(err == 0 || err == -EALREADY); + LL_ASSERT_INFO2(err == 0 || err == -EALREADY, handle, err); cig->lll.handle = LLL_HANDLE_INVALID; cig->lll.resume_cis = LLL_HANDLE_INVALID; diff --git a/subsys/bluetooth/controller/ll_sw/ull_conn_types.h b/subsys/bluetooth/controller/ll_sw/ull_conn_types.h index 8fabab03378..ac466b73dc6 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_conn_types.h +++ b/subsys/bluetooth/controller/ll_sw/ull_conn_types.h @@ -163,15 +163,15 @@ struct ll_conn { struct { uint8_t reason_final; - /* node rx type with memory aligned storage for terminate + /* node rx type with dummy uint8_t to ensure room for terminate * reason. * HCI will reference the value using the pdu member of * struct node_rx_pdu. + * */ struct { - struct node_rx_hdr hdr; - - uint8_t reason __aligned(4); + struct node_rx_pdu rx; + uint8_t dummy_reason; } node_rx; } llcp_terminate; diff --git a/subsys/bluetooth/controller/ll_sw/ull_df.c b/subsys/bluetooth/controller/ll_sw/ull_df.c index 5f34f563cf4..d281585ef9f 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_df.c +++ b/subsys/bluetooth/controller/ll_sw/ull_df.c @@ -569,7 +569,7 @@ void *ull_df_iq_report_alloc(void) return MFIFO_DEQUEUE(iq_report_free); } -void ull_df_iq_report_mem_release(struct node_rx_hdr *rx) +void ull_df_iq_report_mem_release(struct node_rx_pdu *rx) { #if defined(CONFIG_BT_CTLR_DF_DEBUG_ENABLE) IF_SINGLE_ADV_SYNC_SET(iq_report_alloc_count--); diff --git a/subsys/bluetooth/controller/ll_sw/ull_df_internal.h b/subsys/bluetooth/controller/ll_sw/ull_df_internal.h index 8f5cb47df2e..1dadcf7dcc8 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_df_internal.h +++ b/subsys/bluetooth/controller/ll_sw/ull_df_internal.h @@ -10,7 +10,7 @@ int ull_df_reset(void); /* Release link to node_rx_iq_report memory. */ void ull_df_iq_report_link_release(memq_link_t *link); /* Release memory of node_rx_iq_report. */ -void ull_df_iq_report_mem_release(struct node_rx_hdr *rx); +void ull_df_iq_report_mem_release(struct node_rx_pdu *rx); /* Change quota of free node_iq_report links. Delta may be negative, * then it will decrease number of free link elements. */ diff --git a/subsys/bluetooth/controller/ll_sw/ull_iso.c b/subsys/bluetooth/controller/ll_sw/ull_iso.c index 23a2a869ca7..04798471188 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_iso.c @@ -1634,7 +1634,7 @@ static void iso_rx_demux(void *param) * HCI context. */ struct isoal_pdu_rx pckt_meta = { - .meta = &rx_pdu->hdr.rx_iso_meta, + .meta = &rx_pdu->rx_iso_meta, .pdu = (struct pdu_iso *)&rx_pdu->pdu[0] }; diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp.c b/subsys/bluetooth/controller/ll_sw/ull_llcp.c index e412f5a18eb..4dc525adf90 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp.c @@ -284,11 +284,26 @@ void llcp_rx_node_retain(struct proc_ctx *ctx) { LL_ASSERT(ctx->node_ref.rx); - /* Mark RX node to NOT release */ - ctx->node_ref.rx->hdr.type = NODE_RX_TYPE_RETAIN; + /* Only retain if not already retained */ + if (ctx->node_ref.rx->hdr.type != NODE_RX_TYPE_RETAIN) { + /* Mark RX node to NOT release */ + ctx->node_ref.rx->hdr.type = NODE_RX_TYPE_RETAIN; - /* store link element reference to use once this node is moved up */ - ctx->node_ref.rx->hdr.link = ctx->node_ref.link; + /* store link element reference to use once this node is moved up */ + ctx->node_ref.rx->hdr.link = ctx->node_ref.link; + } +} + +void llcp_rx_node_release(struct proc_ctx *ctx) +{ + LL_ASSERT(ctx->node_ref.rx); + + /* Only release if retained */ + if (ctx->node_ref.rx->hdr.type == NODE_RX_TYPE_RETAIN) { + /* Mark RX node to release and release */ + ctx->node_ref.rx->hdr.type = NODE_RX_TYPE_RELEASE; + ll_rx_put_sched(ctx->node_ref.rx->hdr.link, ctx->node_ref.rx); + } } void llcp_nodes_release(struct ll_conn *conn, struct proc_ctx *ctx) @@ -296,12 +311,14 @@ void llcp_nodes_release(struct ll_conn *conn, struct proc_ctx *ctx) if (ctx->node_ref.rx && ctx->node_ref.rx->hdr.type == NODE_RX_TYPE_RETAIN) { /* RX node retained, so release */ ctx->node_ref.rx->hdr.link->mem = conn->llcp.rx_node_release; + ctx->node_ref.rx->hdr.type = NODE_RX_TYPE_RELEASE; conn->llcp.rx_node_release = ctx->node_ref.rx; } #if defined(CONFIG_BT_CTLR_PHY) && defined(CONFIG_BT_CTLR_DATA_LENGTH) if (ctx->proc == PROC_PHY_UPDATE && ctx->data.pu.ntf_dle_node) { /* RX node retained, so release */ ctx->data.pu.ntf_dle_node->hdr.link->mem = conn->llcp.rx_node_release; + ctx->data.pu.ntf_dle_node->hdr.type = NODE_RX_TYPE_RELEASE; conn->llcp.rx_node_release = ctx->data.pu.ntf_dle_node; } #endif @@ -326,13 +343,13 @@ static struct proc_ctx *create_procedure(enum llcp_proc proc, struct llcp_mem_po } ctx->proc = proc; - ctx->collision = 0U; ctx->done = 0U; ctx->rx_greedy = 0U; ctx->node_ref.rx = NULL; ctx->node_ref.tx_ack = NULL; + ctx->state = LLCP_STATE_IDLE; - /* Clear procedure data */ + /* Clear procedure context data */ memset((void *)&ctx->data, 0, sizeof(ctx->data)); /* Initialize opcodes fields to known values */ @@ -345,172 +362,12 @@ static struct proc_ctx *create_procedure(enum llcp_proc proc, struct llcp_mem_po struct proc_ctx *llcp_create_local_procedure(enum llcp_proc proc) { - struct proc_ctx *ctx; - - ctx = create_procedure(proc, &mem_local_ctx); - if (!ctx) { - return NULL; - } - - switch (ctx->proc) { -#if defined(CONFIG_BT_CTLR_LE_PING) - case PROC_LE_PING: - llcp_lp_comm_init_proc(ctx); - break; -#endif /* CONFIG_BT_CTLR_LE_PING */ - case PROC_FEATURE_EXCHANGE: - llcp_lp_comm_init_proc(ctx); - break; -#if defined(CONFIG_BT_CTLR_MIN_USED_CHAN) - case PROC_MIN_USED_CHANS: - llcp_lp_comm_init_proc(ctx); - break; -#endif /* CONFIG_BT_CTLR_MIN_USED_CHAN */ - case PROC_VERSION_EXCHANGE: - llcp_lp_comm_init_proc(ctx); - break; -#if defined(CONFIG_BT_CTLR_LE_ENC) && defined(CONFIG_BT_CENTRAL) - case PROC_ENCRYPTION_START: - case PROC_ENCRYPTION_PAUSE: - llcp_lp_enc_init_proc(ctx); - break; -#endif /* CONFIG_BT_CTLR_LE_ENC && CONFIG_BT_CENTRAL */ -#ifdef CONFIG_BT_CTLR_PHY - case PROC_PHY_UPDATE: - llcp_lp_pu_init_proc(ctx); - break; -#endif /* CONFIG_BT_CTLR_PHY */ - case PROC_CONN_UPDATE: - case PROC_CONN_PARAM_REQ: - llcp_lp_cu_init_proc(ctx); - break; - case PROC_TERMINATE: - llcp_lp_comm_init_proc(ctx); - break; -#if defined(CONFIG_BT_CENTRAL) - case PROC_CHAN_MAP_UPDATE: - llcp_lp_chmu_init_proc(ctx); - break; -#endif /* CONFIG_BT_CENTRAL */ -#if defined(CONFIG_BT_CTLR_DATA_LENGTH) - case PROC_DATA_LENGTH_UPDATE: - llcp_lp_comm_init_proc(ctx); - break; -#endif /* CONFIG_BT_CTLR_DATA_LENGTH */ -#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_REQ) - case PROC_CTE_REQ: - llcp_lp_comm_init_proc(ctx); - break; -#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */ -#if defined(CONFIG_BT_CTLR_CENTRAL_ISO) || defined(CONFIG_BT_CTLR_PERIPHERAL_ISO) - case PROC_CIS_TERMINATE: - llcp_lp_comm_init_proc(ctx); - break; -#endif /* defined(CONFIG_BT_CTLR_CENTRAL_ISO) || defined(CONFIG_BT_CTLR_PERIPHERAL_ISO) */ -#if defined(CONFIG_BT_CTLR_CENTRAL_ISO) - case PROC_CIS_CREATE: - llcp_lp_comm_init_proc(ctx); - break; -#endif /* defined(CONFIG_BT_CTLR_CENTRAL_ISO) */ -#if defined(CONFIG_BT_CTLR_SCA_UPDATE) - case PROC_SCA_UPDATE: - llcp_lp_comm_init_proc(ctx); - break; -#endif /* CONFIG_BT_CTLR_SCA_UPDATE */ - default: - /* Unknown procedure */ - LL_ASSERT(0); - break; - } - - return ctx; + return create_procedure(proc, &mem_local_ctx); } struct proc_ctx *llcp_create_remote_procedure(enum llcp_proc proc) { - struct proc_ctx *ctx; - - ctx = create_procedure(proc, &mem_remote_ctx); - if (!ctx) { - return NULL; - } - - switch (ctx->proc) { - case PROC_UNKNOWN: - /* Nothing to do */ - break; -#if defined(CONFIG_BT_CTLR_LE_PING) - case PROC_LE_PING: - llcp_rp_comm_init_proc(ctx); - break; -#endif /* CONFIG_BT_CTLR_LE_PING */ - case PROC_FEATURE_EXCHANGE: - llcp_rp_comm_init_proc(ctx); - break; -#if defined(CONFIG_BT_CTLR_MIN_USED_CHAN) - case PROC_MIN_USED_CHANS: - llcp_rp_comm_init_proc(ctx); - break; -#endif /* CONFIG_BT_CTLR_MIN_USED_CHAN */ - case PROC_VERSION_EXCHANGE: - llcp_rp_comm_init_proc(ctx); - break; -#if defined(CONFIG_BT_CTLR_LE_ENC) && defined(CONFIG_BT_PERIPHERAL) - case PROC_ENCRYPTION_START: - case PROC_ENCRYPTION_PAUSE: - llcp_rp_enc_init_proc(ctx); - break; -#endif /* CONFIG_BT_CTLR_LE_ENC && CONFIG_BT_PERIPHERAL */ -#ifdef CONFIG_BT_CTLR_PHY - case PROC_PHY_UPDATE: - llcp_rp_pu_init_proc(ctx); - break; -#endif /* CONFIG_BT_CTLR_PHY */ - case PROC_CONN_UPDATE: - case PROC_CONN_PARAM_REQ: - llcp_rp_cu_init_proc(ctx); - break; - case PROC_TERMINATE: - llcp_rp_comm_init_proc(ctx); - break; -#if defined(CONFIG_BT_PERIPHERAL) - case PROC_CHAN_MAP_UPDATE: - llcp_rp_chmu_init_proc(ctx); - break; -#endif /* CONFIG_BT_PERIPHERAL */ -#if defined(CONFIG_BT_CTLR_DATA_LENGTH) - case PROC_DATA_LENGTH_UPDATE: - llcp_rp_comm_init_proc(ctx); - break; -#endif /* CONFIG_BT_CTLR_DATA_LENGTH */ -#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP) - case PROC_CTE_REQ: - llcp_rp_comm_init_proc(ctx); - break; -#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */ -#if defined(CONFIG_BT_PERIPHERAL) && defined(CONFIG_BT_CTLR_PERIPHERAL_ISO) - case PROC_CIS_CREATE: - llcp_rp_cc_init_proc(ctx); - break; -#endif /* CONFIG_BT_PERIPHERAL && CONFIG_BT_CTLR_PERIPHERAL_ISO */ -#if defined(CONFIG_BT_CTLR_CENTRAL_ISO) || defined(CONFIG_BT_CTLR_PERIPHERAL_ISO) - case PROC_CIS_TERMINATE: - llcp_rp_comm_init_proc(ctx); - break; -#endif /* defined(CONFIG_BT_CTLR_CENTRAL_ISO) || defined(CONFIG_BT_CTLR_PERIPHERAL_ISO) */ -#if defined(CONFIG_BT_CTLR_SCA_UPDATE) - case PROC_SCA_UPDATE: - llcp_rp_comm_init_proc(ctx); - break; -#endif /* CONFIG_BT_CTLR_SCA_UPDATE */ - - default: - /* Unknown procedure */ - LL_ASSERT(0); - break; - } - - return ctx; + return create_procedure(proc, &mem_remote_ctx); } /* @@ -706,9 +563,6 @@ void ull_cp_release_nodes(struct ll_conn *conn) hdr = &rx->hdr; rx = hdr->link->mem; - /* Mark for buffer for release */ - hdr->type = NODE_RX_TYPE_RELEASE; - /* enqueue rx node towards Thread */ ll_rx_put(hdr->link, hdr); } diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_cc.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_cc.c index 59c23e7a0f6..a0f9b057a10 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_cc.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_cc.c @@ -68,7 +68,7 @@ static void cc_ntf_established(struct ll_conn *conn, struct proc_ctx *ctx) ntf->hdr.type = NODE_RX_TYPE_CIS_ESTABLISHED; ntf->hdr.handle = conn->lll.handle; - ntf->hdr.rx_ftr.param = ll_conn_iso_stream_get(ctx->data.cis_create.cis_handle); + ntf->rx_ftr.param = ll_conn_iso_stream_get(ctx->data.cis_create.cis_handle); pdu = (struct node_rx_conn_iso_estab *)ntf->pdu; @@ -85,7 +85,7 @@ static void cc_ntf_established(struct ll_conn *conn, struct proc_ctx *ctx) /* LLCP Remote Procedure FSM states */ enum { /* Establish Procedure */ - RP_CC_STATE_IDLE, + RP_CC_STATE_IDLE = LLCP_STATE_IDLE, RP_CC_STATE_WAIT_RX_CIS_REQ, RP_CC_STATE_WAIT_REPLY, RP_CC_STATE_WAIT_TX_CIS_RSP, @@ -590,17 +590,6 @@ void llcp_rp_cc_rx(struct ll_conn *conn, struct proc_ctx *ctx, struct node_rx_pd } } -void llcp_rp_cc_init_proc(struct proc_ctx *ctx) -{ - switch (ctx->proc) { - case PROC_CIS_CREATE: - ctx->state = RP_CC_STATE_IDLE; - break; - default: - LL_ASSERT(0); - } -} - bool llcp_rp_cc_awaiting_reply(struct proc_ctx *ctx) { return (ctx->state == RP_CC_STATE_WAIT_REPLY); @@ -642,7 +631,7 @@ static void lp_cc_execute_fsm(struct ll_conn *conn, struct proc_ctx *ctx, uint8_ /* LLCP Local Procedure FSM states */ enum { - LP_CC_STATE_IDLE, + LP_CC_STATE_IDLE = LLCP_STATE_IDLE, LP_CC_STATE_WAIT_NTF_AVAIL, LP_CC_STATE_WAIT_OFFSET_CALC, LP_CC_STATE_WAIT_OFFSET_CALC_TX_REQ, diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_chmu.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_chmu.c index d1de4e87edb..dd4e033a09d 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_chmu.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_chmu.c @@ -51,7 +51,7 @@ /* LLCP Local Procedure Channel Map Update FSM states */ enum { - LP_CHMU_STATE_IDLE, + LP_CHMU_STATE_IDLE = LLCP_STATE_IDLE, LP_CHMU_STATE_WAIT_TX_CHAN_MAP_IND, LP_CHMU_STATE_WAIT_INSTANT, }; @@ -64,7 +64,7 @@ enum { /* LLCP Remote Procedure Channel Map Update FSM states */ enum { - RP_CHMU_STATE_IDLE, + RP_CHMU_STATE_IDLE = LLCP_STATE_IDLE, RP_CHMU_STATE_WAIT_RX_CHAN_MAP_IND, RP_CHMU_STATE_WAIT_INSTANT, }; @@ -198,11 +198,6 @@ void llcp_lp_chmu_rx(struct ll_conn *conn, struct proc_ctx *ctx, struct node_rx_ } } -void llcp_lp_chmu_init_proc(struct proc_ctx *ctx) -{ - ctx->state = LP_CHMU_STATE_IDLE; -} - void llcp_lp_chmu_run(struct ll_conn *conn, struct proc_ctx *ctx, void *param) { lp_chmu_execute_fsm(conn, ctx, LP_CHMU_EVT_RUN, param); @@ -319,11 +314,6 @@ void llcp_rp_chmu_rx(struct ll_conn *conn, struct proc_ctx *ctx, struct node_rx_ } } -void llcp_rp_chmu_init_proc(struct proc_ctx *ctx) -{ - ctx->state = RP_CHMU_STATE_IDLE; -} - void llcp_rp_chmu_run(struct ll_conn *conn, struct proc_ctx *ctx, void *param) { rp_chmu_execute_fsm(conn, ctx, RP_CHMU_EVT_RUN, param); diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_common.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_common.c index 248f65374bf..10b4547698a 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_common.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_common.c @@ -54,7 +54,7 @@ /* LLCP Local Procedure FSM states */ enum { - LP_COMMON_STATE_IDLE, + LP_COMMON_STATE_IDLE = LLCP_STATE_IDLE, LP_COMMON_STATE_WAIT_TX, LP_COMMON_STATE_WAIT_TX_ACK, LP_COMMON_STATE_WAIT_RX, @@ -84,7 +84,7 @@ enum { /* LLCP Remote Procedure Common FSM states */ enum { - RP_COMMON_STATE_IDLE, + RP_COMMON_STATE_IDLE = LLCP_STATE_IDLE, RP_COMMON_STATE_WAIT_RX, RP_COMMON_STATE_POSTPONE_TERMINATE, RP_COMMON_STATE_WAIT_TX, @@ -921,11 +921,6 @@ void llcp_lp_comm_rx(struct ll_conn *conn, struct proc_ctx *ctx, struct node_rx_ lp_comm_execute_fsm(conn, ctx, LP_COMMON_EVT_RESPONSE, rx->pdu); } -void llcp_lp_comm_init_proc(struct proc_ctx *ctx) -{ - ctx->state = LP_COMMON_STATE_IDLE; -} - void llcp_lp_comm_run(struct ll_conn *conn, struct proc_ctx *ctx, void *param) { lp_comm_execute_fsm(conn, ctx, LP_COMMON_EVT_RUN, param); @@ -1139,6 +1134,7 @@ static void rp_comm_ntf(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t gene /* Allocate ntf node */ ntf = ctx->node_ref.rx; + ctx->node_ref.rx = NULL; LL_ASSERT(ntf); /* This should be an 'old' RX node, so put/sched when done */ @@ -1421,11 +1417,6 @@ void llcp_rp_comm_tx_ack(struct ll_conn *conn, struct proc_ctx *ctx, struct node rp_comm_execute_fsm(conn, ctx, RP_COMMON_EVT_ACK, tx->pdu); } -void llcp_rp_comm_init_proc(struct proc_ctx *ctx) -{ - ctx->state = RP_COMMON_STATE_IDLE; -} - void llcp_rp_comm_run(struct ll_conn *conn, struct proc_ctx *ctx, void *param) { rp_comm_execute_fsm(conn, ctx, RP_COMMON_EVT_RUN, param); diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_conn_upd.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_conn_upd.c index e922901f67d..eb1f692e55f 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_conn_upd.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_conn_upd.c @@ -79,7 +79,7 @@ /* LLCP Local Procedure Connection Update FSM states */ enum { - LP_CU_STATE_IDLE, + LP_CU_STATE_IDLE = LLCP_STATE_IDLE, LP_CU_STATE_WAIT_TX_CONN_PARAM_REQ, LP_CU_STATE_WAIT_RX_CONN_PARAM_RSP, LP_CU_STATE_WAIT_TX_CONN_UPDATE_IND, @@ -109,7 +109,7 @@ enum { /* LLCP Remote Procedure Connection Update FSM states */ enum { - RP_CU_STATE_IDLE, + RP_CU_STATE_IDLE = LLCP_STATE_IDLE, RP_CU_STATE_WAIT_RX_CONN_PARAM_REQ, RP_CU_STATE_WAIT_CONN_PARAM_REQ_AVAILABLE, RP_CU_STATE_WAIT_NTF_CONN_PARAM_REQ, @@ -585,6 +585,7 @@ static void lp_cu_st_wait_rx_conn_update_ind(struct ll_conn *conn, struct proc_c switch (evt) { case LP_CU_EVT_CONN_UPDATE_IND: llcp_pdu_decode_conn_update_ind(ctx, param); + llcp_rr_set_incompat(conn, INCOMPAT_RESERVED); /* Keep RX node to use for NTF */ llcp_rx_node_retain(ctx); ctx->state = LP_CU_STATE_WAIT_INSTANT; @@ -633,8 +634,7 @@ static void lp_cu_check_instant(struct ll_conn *conn, struct proc_ctx *ctx, uint lp_cu_ntf_complete(conn, ctx, evt, param); } else { /* Release RX node kept for NTF */ - ctx->node_ref.rx->hdr.type = NODE_RX_TYPE_RELEASE; - ll_rx_put_sched(ctx->node_ref.rx->hdr.link, ctx->node_ref.rx); + llcp_rx_node_release(ctx); ctx->node_ref.rx = NULL; lp_cu_complete(conn, ctx); @@ -727,11 +727,6 @@ void llcp_lp_cu_rx(struct ll_conn *conn, struct proc_ctx *ctx, struct node_rx_pd } } -void llcp_lp_cu_init_proc(struct proc_ctx *ctx) -{ - ctx->state = LP_CU_STATE_IDLE; -} - void llcp_lp_cu_run(struct ll_conn *conn, struct proc_ctx *ctx, void *param) { lp_cu_execute_fsm(conn, ctx, LP_CU_EVT_RUN, param); @@ -973,11 +968,18 @@ static void rp_cu_st_wait_conn_param_req_available(struct ll_conn *conn, struct case RP_CU_EVT_RUN: if (cpr_active_is_set(conn)) { ctx->state = RP_CU_STATE_WAIT_CONN_PARAM_REQ_AVAILABLE; + if (!llcp_rr_ispaused(conn) && llcp_tx_alloc_peek(conn, ctx)) { /* We're good to reject immediately */ ctx->data.cu.rejected_opcode = PDU_DATA_LLCTRL_TYPE_CONN_PARAM_REQ; ctx->data.cu.error = BT_HCI_ERR_UNSUPP_LL_PARAM_VAL; rp_cu_send_reject_ext_ind(conn, ctx, evt, param); + + /* Possibly retained rx node to be released as we won't need it */ + llcp_rx_node_release(ctx); + ctx->node_ref.rx = NULL; + + break; } /* In case we have to defer NTF */ llcp_rx_node_retain(ctx); @@ -992,6 +994,9 @@ static void rp_cu_st_wait_conn_param_req_available(struct ll_conn *conn, struct rp_cu_conn_param_req_ntf(conn, ctx); ctx->state = RP_CU_STATE_WAIT_CONN_PARAM_REQ_REPLY; } else { + /* Possibly retained rx node to be released as we won't need it */ + llcp_rx_node_release(ctx); + ctx->node_ref.rx = NULL; #if defined(CONFIG_BT_CTLR_USER_CPR_ANCHOR_POINT_MOVE) /* Handle APM as a vendor specific user extension */ if (conn->lll.role == BT_HCI_ROLE_PERIPHERAL && @@ -1177,8 +1182,7 @@ static void rp_cu_check_instant(struct ll_conn *conn, struct proc_ctx *ctx, uint cu_ntf(conn, ctx); } else { /* Release RX node kept for NTF */ - ctx->node_ref.rx->hdr.type = NODE_RX_TYPE_RELEASE; - ll_rx_put_sched(ctx->node_ref.rx->hdr.link, ctx->node_ref.rx); + llcp_rx_node_release(ctx); ctx->node_ref.rx = NULL; } rp_cu_complete(conn, ctx); @@ -1310,11 +1314,6 @@ void llcp_rp_cu_rx(struct ll_conn *conn, struct proc_ctx *ctx, struct node_rx_pd } } -void llcp_rp_cu_init_proc(struct proc_ctx *ctx) -{ - ctx->state = RP_CU_STATE_IDLE; -} - void llcp_rp_cu_run(struct ll_conn *conn, struct proc_ctx *ctx, void *param) { rp_cu_execute_fsm(conn, ctx, RP_CU_EVT_RUN, param); diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_enc.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_enc.c index 10fc39d86a5..cc112b11d3a 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_enc.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_enc.c @@ -52,8 +52,9 @@ #if defined(CONFIG_BT_CENTRAL) /* LLCP Local Procedure Encryption FSM states */ enum { - /* Start Procedure */ + LP_ENC_STATE_IDLE = LLCP_STATE_IDLE, LP_ENC_STATE_UNENCRYPTED, + /* Start Procedure */ LP_ENC_STATE_WAIT_TX_ENC_REQ, LP_ENC_STATE_WAIT_RX_ENC_RSP, LP_ENC_STATE_WAIT_RX_START_ENC_REQ, @@ -94,8 +95,9 @@ enum { #if defined(CONFIG_BT_PERIPHERAL) /* LLCP Remote Procedure Encryption FSM states */ enum { - /* Start Procedure */ + RP_ENC_STATE_IDLE = LLCP_STATE_IDLE, RP_ENC_STATE_UNENCRYPTED, + /* Start Procedure */ RP_ENC_STATE_WAIT_RX_ENC_REQ, RP_ENC_STATE_WAIT_TX_ENC_RSP, RP_ENC_STATE_WAIT_LTK_REPLY, @@ -225,6 +227,7 @@ static void lp_enc_ntf(struct ll_conn *conn, struct proc_ctx *ctx) /* Piggy-back on RX node */ ntf = ctx->node_ref.rx; + ctx->node_ref.rx = NULL; LL_ASSERT(ntf); ntf->hdr.type = NODE_RX_TYPE_DC_PDU; @@ -252,7 +255,7 @@ static void lp_enc_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t { lp_enc_ntf(conn, ctx); llcp_lr_complete(conn); - ctx->state = LP_ENC_STATE_UNENCRYPTED; + ctx->state = LP_ENC_STATE_IDLE; } static void lp_enc_store_m(struct ll_conn *conn, struct proc_ctx *ctx, struct pdu_data *pdu) @@ -340,21 +343,6 @@ static void lp_enc_send_start_enc_rsp(struct ll_conn *conn, struct proc_ctx *ctx } } -static void lp_enc_st_unencrypted(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, - void *param) -{ - switch (evt) { - case LP_ENC_EVT_RUN: - /* Pause Tx data */ - llcp_tx_pause_data(conn, LLCP_TX_QUEUE_PAUSE_DATA_ENCRYPTION); - lp_enc_send_enc_req(conn, ctx, evt, param); - break; - default: - /* Ignore other evts */ - break; - } -} - static void lp_enc_st_wait_tx_enc_req(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) { @@ -510,6 +498,21 @@ static void lp_enc_st_wait_rx_start_enc_rsp(struct ll_conn *conn, struct proc_ct } } +static void lp_enc_st_unencrypted(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, + void *param) +{ + switch (evt) { + case LP_ENC_EVT_RUN: + /* Pause Tx data */ + llcp_tx_pause_data(conn, LLCP_TX_QUEUE_PAUSE_DATA_ENCRYPTION); + lp_enc_send_enc_req(conn, ctx, evt, param); + break; + default: + /* Ignore other evts */ + break; + } +} + static void lp_enc_state_encrypted(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) { @@ -525,6 +528,23 @@ static void lp_enc_state_encrypted(struct ll_conn *conn, struct proc_ctx *ctx, u } } +static void lp_enc_st_idle(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, + void *param) +{ + switch (evt) { + case LP_ENC_EVT_RUN: + if (ctx->proc == PROC_ENCRYPTION_PAUSE) { + lp_enc_state_encrypted(conn, ctx, evt, param); + } else { + lp_enc_st_unencrypted(conn, ctx, evt, param); + } + break; + default: + /* Ignore other evts */ + break; + } +} + static void lp_enc_state_wait_tx_pause_enc_req(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) { @@ -572,6 +592,9 @@ static void lp_enc_state_wait_tx_pause_enc_rsp(struct ll_conn *conn, struct proc static void lp_enc_execute_fsm(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) { switch (ctx->state) { + case LP_ENC_STATE_IDLE: + lp_enc_st_idle(conn, ctx, evt, param); + break; /* Start Procedure */ case LP_ENC_STATE_UNENCRYPTED: lp_enc_st_unencrypted(conn, ctx, evt, param); @@ -653,20 +676,6 @@ void llcp_lp_enc_rx(struct ll_conn *conn, struct proc_ctx *ctx, struct node_rx_p } } -void llcp_lp_enc_init_proc(struct proc_ctx *ctx) -{ - switch (ctx->proc) { - case PROC_ENCRYPTION_START: - ctx->state = LP_ENC_STATE_UNENCRYPTED; - break; - case PROC_ENCRYPTION_PAUSE: - ctx->state = LP_ENC_STATE_ENCRYPTED; - break; - default: - LL_ASSERT(0); - } -} - void llcp_lp_enc_run(struct ll_conn *conn, struct proc_ctx *ctx, void *param) { lp_enc_execute_fsm(conn, ctx, LP_ENC_EVT_RUN, param); @@ -878,7 +887,7 @@ static void rp_enc_send_start_enc_rsp(struct ll_conn *conn, struct proc_ctx *ctx } else { llcp_rp_enc_tx(conn, ctx, PDU_DATA_LLCTRL_TYPE_START_ENC_RSP); llcp_rr_complete(conn); - ctx->state = RP_ENC_STATE_UNENCRYPTED; + ctx->state = RP_ENC_STATE_IDLE; /* Resume Tx data */ llcp_tx_resume_data(conn, LLCP_TX_QUEUE_PAUSE_DATA_ENCRYPTION); @@ -909,19 +918,6 @@ static void rp_enc_send_pause_enc_rsp(struct ll_conn *conn, struct proc_ctx *ctx } } -static void rp_enc_state_unencrypted(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, - void *param) -{ - switch (evt) { - case RP_ENC_EVT_RUN: - ctx->state = RP_ENC_STATE_WAIT_RX_ENC_REQ; - break; - default: - /* Ignore other evts */ - break; - } -} - static void rp_enc_store_m(struct ll_conn *conn, struct proc_ctx *ctx, struct pdu_data *pdu) { /* Store Rand */ @@ -1076,6 +1072,35 @@ static void rp_enc_state_encrypted(struct ll_conn *conn, struct proc_ctx *ctx, u } } +static void rp_enc_state_unencrypted(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, + void *param) +{ + switch (evt) { + case RP_ENC_EVT_RUN: + ctx->state = RP_ENC_STATE_WAIT_RX_ENC_REQ; + break; + default: + /* Ignore other evts */ + break; + } +} + +static void rp_enc_state_idle(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, + void *param) +{ + switch (evt) { + case RP_ENC_EVT_RUN: + if (ctx->proc == PROC_ENCRYPTION_PAUSE) { + rp_enc_state_encrypted(conn, ctx, evt, param); + } else { + rp_enc_state_unencrypted(conn, ctx, evt, param); + } + break; + default: + /* Ignore other evts */ + break; + } +} static void rp_enc_state_wait_rx_pause_enc_req(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) { @@ -1151,6 +1176,9 @@ static void rp_enc_state_wait_rx_pause_enc_rsp(struct ll_conn *conn, struct proc static void rp_enc_execute_fsm(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) { switch (ctx->state) { + case RP_ENC_STATE_IDLE: + rp_enc_state_idle(conn, ctx, evt, param); + break; /* Start Procedure */ case RP_ENC_STATE_UNENCRYPTED: rp_enc_state_unencrypted(conn, ctx, evt, param); @@ -1237,20 +1265,6 @@ void llcp_rp_enc_rx(struct ll_conn *conn, struct proc_ctx *ctx, struct node_rx_p } } -void llcp_rp_enc_init_proc(struct proc_ctx *ctx) -{ - switch (ctx->proc) { - case PROC_ENCRYPTION_START: - ctx->state = RP_ENC_STATE_UNENCRYPTED; - break; - case PROC_ENCRYPTION_PAUSE: - ctx->state = RP_ENC_STATE_ENCRYPTED; - break; - default: - LL_ASSERT(0); - } -} - void llcp_rp_enc_ltk_req_reply(struct ll_conn *conn, struct proc_ctx *ctx) { rp_enc_execute_fsm(conn, ctx, RP_ENC_EVT_LTK_REQ_REPLY, NULL); diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_internal.h b/subsys/bluetooth/controller/ll_sw/ull_llcp_internal.h index 0e1afb9ff1d..5744f9c5723 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_internal.h +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_internal.h @@ -33,6 +33,14 @@ enum llcp_proc { PROC_NONE = 0x0, }; +/* Generic IDLE state to be used across all procedures + * This allows a cheap procedure alloc/init handling + */ +enum llcp_proc_state_idle { + LLCP_STATE_IDLE +}; + + enum llcp_tx_q_pause_data_mask { LLCP_TX_QUEUE_PAUSE_DATA_ENCRYPTION = 0x01, LLCP_TX_QUEUE_PAUSE_DATA_PHY_UPDATE = 0x02, @@ -128,6 +136,11 @@ struct proc_ctx { /* llcp_mem_pool owner of this context */ struct llcp_mem_pool *owner; +#if defined(LLCP_TX_CTRL_BUF_QUEUE_ENABLE) + /* Wait list next pointer */ + sys_snode_t wait_node; +#endif /* LLCP_TX_CTRL_BUF_QUEUE_ENABLE */ + /* PROC_ */ enum llcp_proc proc; @@ -145,13 +158,13 @@ struct proc_ctx { /* Last transmitted opcode used for unknown/reject */ enum pdu_data_llctrl_type tx_opcode; - /* Instant collision */ - int collision; + /* + * This flag is set to 1 when we are finished with the control + * procedure and it is safe to release the context ctx + */ + uint8_t done; #if defined(LLCP_TX_CTRL_BUF_QUEUE_ENABLE) - /* Wait list next pointer */ - sys_snode_t wait_node; - /* Procedure wait reason */ enum llcp_wait_reason wait_reason; #endif /* LLCP_TX_CTRL_BUF_QUEUE_ENABLE */ @@ -166,11 +179,6 @@ struct proc_ctx { /* pre-allocated TX node */ struct node_tx *tx; } node_ref; - /* - * This flag is set to 1 when we are finished with the control - * procedure and it is safe to release the context ctx - */ - int done; /* Procedure data */ union { @@ -276,7 +284,7 @@ struct proc_ctx { #if defined(CONFIG_BT_PERIPHERAL) uint32_t host_request_to; #endif /* defined(CONFIG_BT_PERIPHERAL) */ -#if defined(CONFIG_BT_CENTRAL) +#if defined(CONFIG_BT_CTLR_CENTRAL_ISO) uint32_t cig_sync_delay; uint32_t cis_sync_delay; uint8_t c_phy; @@ -295,7 +303,7 @@ struct proc_ctx { uint8_t c_ft; uint8_t p_ft; uint8_t aa[4]; -#endif /* defined(CONFIG_BT_CENTRAL) */ +#endif /* defined(CONFIG_BT_CTLR_CENTRAL_ISO) */ } cis_create; struct { @@ -413,6 +421,7 @@ void llcp_ntf_set_pending(struct ll_conn *conn); void llcp_ntf_clear_pending(struct ll_conn *conn); bool llcp_ntf_pending(struct ll_conn *conn); void llcp_rx_node_retain(struct proc_ctx *ctx); +void llcp_rx_node_release(struct proc_ctx *ctx); /* * ULL -> LLL Interface diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_local.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_local.c index 793e33934bc..249943b10b2 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_local.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_local.c @@ -81,6 +81,12 @@ void llcp_lr_check_done(struct ll_conn *conn, struct proc_ctx *ctx) ctx_header = llcp_lr_peek(conn); LL_ASSERT(ctx_header == ctx); + /* If we have a node rx it must not be marked RETAIN as + * the memory referenced would leak + */ + LL_ASSERT(ctx->node_ref.rx == NULL || + ctx->node_ref.rx->hdr.type != NODE_RX_TYPE_RETAIN); + lr_dequeue(conn); llcp_proc_ctx_release(ctx); @@ -312,6 +318,11 @@ void llcp_lr_rx(struct ll_conn *conn, struct proc_ctx *ctx, memq_link_t *link, break; } + /* If rx node was not retained clear reference */ + if (ctx->node_ref.rx && ctx->node_ref.rx->hdr.type != NODE_RX_TYPE_RETAIN) { + ctx->node_ref.rx = NULL; + } + llcp_lr_check_done(conn, ctx); } diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_phy.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_phy.c index 61ee2250606..006938d9b2f 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_phy.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_phy.c @@ -51,7 +51,7 @@ /* LLCP Local Procedure PHY Update FSM states */ enum { - LP_PU_STATE_IDLE, + LP_PU_STATE_IDLE = LLCP_STATE_IDLE, LP_PU_STATE_WAIT_TX_PHY_REQ, LP_PU_STATE_WAIT_TX_ACK_PHY_REQ, LP_PU_STATE_WAIT_RX_PHY_RSP, @@ -89,7 +89,7 @@ enum { /* LLCP Remote Procedure PHY Update FSM states */ enum { - RP_PU_STATE_IDLE, + RP_PU_STATE_IDLE = LLCP_STATE_IDLE, RP_PU_STATE_WAIT_RX_PHY_REQ, RP_PU_STATE_WAIT_TX_PHY_RSP, RP_PU_STATE_WAIT_TX_ACK_PHY_RSP, @@ -433,6 +433,7 @@ static void pu_ntf(struct ll_conn *conn, struct proc_ctx *ctx) /* Piggy-back on stored RX node */ ntf = ctx->node_ref.rx; + ctx->node_ref.rx = NULL; LL_ASSERT(ntf); if (ctx->data.pu.ntf_pu) { @@ -449,15 +450,9 @@ static void pu_ntf(struct ll_conn *conn, struct proc_ctx *ctx) } /* Enqueue notification towards LL */ -#if defined(CONFIG_BT_CTLR_DATA_LENGTH) - /* only 'put' as the 'sched' is handled when handling DLE ntf */ - ll_rx_put(ntf->hdr.link, ntf); -#else ll_rx_put_sched(ntf->hdr.link, ntf); -#endif /* CONFIG_BT_CTLR_DATA_LENGTH */ ctx->data.pu.ntf_pu = 0; - ctx->node_ref.rx = NULL; } #if defined(CONFIG_BT_CTLR_DATA_LENGTH) @@ -717,6 +712,7 @@ static void lp_pu_st_wait_rx_phy_update_ind(struct ll_conn *conn, struct proc_ct switch (evt) { case LP_PU_EVT_PHY_UPDATE_IND: LL_ASSERT(conn->lll.role == BT_HCI_ROLE_PERIPHERAL); + llcp_rr_set_incompat(conn, INCOMPAT_RESERVED); llcp_pdu_decode_phy_update_ind(ctx, (struct pdu_data *)param); const uint8_t end_procedure = pu_check_update_ind(conn, ctx); @@ -904,11 +900,6 @@ void llcp_lp_pu_rx(struct ll_conn *conn, struct proc_ctx *ctx, struct node_rx_pd } } -void llcp_lp_pu_init_proc(struct proc_ctx *ctx) -{ - ctx->state = LP_PU_STATE_IDLE; -} - void llcp_lp_pu_run(struct ll_conn *conn, struct proc_ctx *ctx, void *param) { lp_pu_execute_fsm(conn, ctx, LP_PU_EVT_RUN, param); @@ -1322,11 +1313,6 @@ void llcp_rp_pu_rx(struct ll_conn *conn, struct proc_ctx *ctx, struct node_rx_pd } } -void llcp_rp_pu_init_proc(struct proc_ctx *ctx) -{ - ctx->state = RP_PU_STATE_IDLE; -} - void llcp_rp_pu_run(struct ll_conn *conn, struct proc_ctx *ctx, void *param) { rp_pu_execute_fsm(conn, ctx, RP_PU_EVT_RUN, param); diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_remote.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_remote.c index 2263cd1b23d..66476aae6dd 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_remote.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_remote.c @@ -118,6 +118,12 @@ void llcp_rr_check_done(struct ll_conn *conn, struct proc_ctx *ctx) ctx_header = llcp_rr_peek(conn); LL_ASSERT(ctx_header == ctx); + /* If we have a node rx it must not be marked RETAIN as + * the memory referenced would leak + */ + LL_ASSERT(ctx->node_ref.rx == NULL || + ctx->node_ref.rx->hdr.type != NODE_RX_TYPE_RETAIN); + rr_dequeue(conn); llcp_proc_ctx_release(ctx); @@ -307,6 +313,12 @@ void llcp_rr_rx(struct ll_conn *conn, struct proc_ctx *ctx, memq_link_t *link, LL_ASSERT(0); break; } + + /* If rx node was not retained clear reference */ + if (ctx->node_ref.rx && ctx->node_ref.rx->hdr.type != NODE_RX_TYPE_RETAIN) { + ctx->node_ref.rx = NULL; + } + llcp_rr_check_done(conn, ctx); } diff --git a/subsys/bluetooth/controller/ll_sw/ull_peripheral.c b/subsys/bluetooth/controller/ll_sw/ull_peripheral.c index 5a34f787ec7..5abde0647e8 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_peripheral.c +++ b/subsys/bluetooth/controller/ll_sw/ull_peripheral.c @@ -61,13 +61,13 @@ #include "hal/debug.h" static void invalid_release(struct ull_hdr *hdr, struct lll_conn *lll, - memq_link_t *link, struct node_rx_hdr *rx); + memq_link_t *link, struct node_rx_pdu *rx); static void ticker_op_stop_adv_cb(uint32_t status, void *param); static void ticker_op_cb(uint32_t status, void *param); static void ticker_update_latency_cancel_op_cb(uint32_t ticker_status, void *param); -void ull_periph_setup(struct node_rx_hdr *rx, struct node_rx_ftr *ftr, +void ull_periph_setup(struct node_rx_pdu *rx, struct node_rx_ftr *ftr, struct lll_conn *lll) { uint32_t conn_offset_us, conn_interval_us; @@ -97,7 +97,7 @@ void ull_periph_setup(struct node_rx_hdr *rx, struct node_rx_ftr *ftr, conn = lll->hdr.parent; /* Populate the peripheral context */ - pdu_adv = (void *)((struct node_rx_pdu *)rx)->pdu; + pdu_adv = (void *)rx->pdu; peer_addr_type = pdu_adv->tx_addr; memcpy(peer_addr, pdu_adv->connect_ind.init_addr, BDADDR_SIZE); @@ -120,7 +120,7 @@ void ull_periph_setup(struct node_rx_hdr *rx, struct node_rx_ftr *ftr, /* Use the link stored in the node rx to enqueue connection * complete node rx towards LL context. */ - link = rx->link; + link = rx->hdr.link; #if defined(CONFIG_BT_CTLR_CHECK_SAME_PEER_CONN) const uint8_t peer_id_addr_type = (peer_addr_type & 0x01); @@ -277,7 +277,7 @@ void ull_periph_setup(struct node_rx_hdr *rx, struct node_rx_ftr *ftr, cc->sca = conn->periph.sca; lll->handle = ll_conn_handle_get(conn); - rx->handle = lll->handle; + rx->hdr.handle = lll->handle; #if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL) lll->tx_pwr_lvl = RADIO_TXP_DEFAULT; @@ -297,11 +297,11 @@ void ull_periph_setup(struct node_rx_hdr *rx, struct node_rx_ftr *ftr, ll_rx_put(link, rx); /* use the rx node for CSA event */ - rx = (void *)rx_csa; - link = rx->link; + rx = rx_csa; + link = rx->hdr.link; - rx->handle = lll->handle; - rx->type = NODE_RX_TYPE_CHAN_SEL_ALGO; + rx->hdr.handle = lll->handle; + rx->hdr.type = NODE_RX_TYPE_CHAN_SEL_ALGO; cs = (void *)rx_csa->pdu; @@ -326,13 +326,13 @@ void ull_periph_setup(struct node_rx_hdr *rx, struct node_rx_ftr *ftr, * advertising terminate event */ rx = adv->lll.node_rx_adv_term; - link = rx->link; + link = rx->hdr.link; handle = ull_adv_handle_get(adv); LL_ASSERT(handle < BT_CTLR_ADV_SET); - rx->type = NODE_RX_TYPE_EXT_ADV_TERMINATE; - rx->handle = handle; + rx->hdr.type = NODE_RX_TYPE_EXT_ADV_TERMINATE; + rx->hdr.handle = handle; rx->rx_ftr.param_adv_term.status = 0U; rx->rx_ftr.param_adv_term.conn_handle = lll->handle; rx->rx_ftr.param_adv_term.num_events = 0U; @@ -593,7 +593,7 @@ uint8_t ll_start_enc_req_send(uint16_t handle, uint8_t error_code, #endif /* CONFIG_BT_CTLR_LE_ENC */ static void invalid_release(struct ull_hdr *hdr, struct lll_conn *lll, - memq_link_t *link, struct node_rx_hdr *rx) + memq_link_t *link, struct node_rx_pdu *rx) { /* Reset the advertising disabled callback */ hdr->disabled_cb = NULL; @@ -602,7 +602,7 @@ static void invalid_release(struct ull_hdr *hdr, struct lll_conn *lll, lll->periph.initiated = 0U; /* Mark for buffer for release */ - rx->type = NODE_RX_TYPE_RELEASE; + rx->hdr.type = NODE_RX_TYPE_RELEASE; /* Release CSA#2 related node rx too */ if (IS_ENABLED(CONFIG_BT_CTLR_CHAN_SEL_2)) { @@ -617,11 +617,11 @@ static void invalid_release(struct ull_hdr *hdr, struct lll_conn *lll, ll_rx_put(link, rx); /* Use the rx node for CSA event */ - rx = (void *)rx_csa; - link = rx->link; + rx = rx_csa; + link = rx->hdr.link; /* Mark for buffer for release */ - rx->type = NODE_RX_TYPE_RELEASE; + rx->hdr.type = NODE_RX_TYPE_RELEASE; } /* Enqueue connection or CSA event to be release */ diff --git a/subsys/bluetooth/controller/ll_sw/ull_peripheral_internal.h b/subsys/bluetooth/controller/ll_sw/ull_peripheral_internal.h index c5a5935447a..19162c1fddc 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_peripheral_internal.h +++ b/subsys/bluetooth/controller/ll_sw/ull_peripheral_internal.h @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -void ull_periph_setup(struct node_rx_hdr *rx, struct node_rx_ftr *ftr, +void ull_periph_setup(struct node_rx_pdu *rx, struct node_rx_ftr *ftr, struct lll_conn *lll); void ull_periph_latency_cancel(struct ll_conn *conn, uint16_t handle); void ull_periph_ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift, diff --git a/subsys/bluetooth/controller/ll_sw/ull_scan.c b/subsys/bluetooth/controller/ll_sw/ull_scan.c index 21d6cc9c401..36763a7c0f7 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_scan.c +++ b/subsys/bluetooth/controller/ll_sw/ull_scan.c @@ -653,7 +653,7 @@ uint8_t ull_scan_disable(uint8_t handle, struct ll_scan_set *scan) err = ull_ticker_stop_with_mark(TICKER_ID_SCAN_BASE + handle, scan, &scan->lll); - LL_ASSERT(err == 0 || err == -EALREADY); + LL_ASSERT_INFO2(err == 0 || err == -EALREADY, handle, err); if (err) { return BT_HCI_ERR_CMD_DISALLOWED; } @@ -699,7 +699,7 @@ uint8_t ull_scan_disable(uint8_t handle, struct ll_scan_set *scan) #if defined(CONFIG_BT_CTLR_ADV_EXT) void ull_scan_done(struct node_rx_event_done *done) { - struct node_rx_hdr *rx_hdr; + struct node_rx_pdu *rx; struct ll_scan_set *scan; struct lll_scan *lll; uint8_t handle; @@ -734,9 +734,9 @@ void ull_scan_done(struct node_rx_event_done *done) scan_other->lll.duration_reload = 0U; #endif /* CONFIG_BT_CTLR_PHY_CODED */ - rx_hdr = (void *)scan->node_rx_scan_term; - rx_hdr->type = NODE_RX_TYPE_EXT_SCAN_TERMINATE; - rx_hdr->handle = handle; + rx = (void *)scan->node_rx_scan_term; + rx->hdr.type = NODE_RX_TYPE_EXT_SCAN_TERMINATE; + rx->hdr.handle = handle; ret = ticker_stop(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_ULL_HIGH, (TICKER_ID_SCAN_BASE + handle), ticker_stop_ext_op_cb, @@ -985,7 +985,7 @@ static uint8_t is_scan_update(uint8_t handle, uint16_t duration, struct node_rx_pdu **node_rx_scan_term) { *scan = ull_scan_set_get(handle); - *node_rx_scan_term = (void *)(*scan)->node_rx_scan_term; + *node_rx_scan_term = (*scan)->node_rx_scan_term; return duration && period && (*scan)->lll.duration_reload && (*scan)->duration_lazy; } @@ -1019,8 +1019,7 @@ static uint8_t duration_period_setup(struct ll_scan_set *scan, scan->duration_lazy = 0U; if (*node_rx_scan_term) { - scan->node_rx_scan_term = - (void *)*node_rx_scan_term; + scan->node_rx_scan_term = *node_rx_scan_term; return 0; } @@ -1039,7 +1038,7 @@ static uint8_t duration_period_setup(struct ll_scan_set *scan, } node_rx->hdr.link = (void *)link_scan_term; - scan->node_rx_scan_term = (void *)node_rx; + scan->node_rx_scan_term = node_rx; *node_rx_scan_term = node_rx; } } else { @@ -1134,7 +1133,7 @@ static void ext_disable(void *param) static void ext_disabled_cb(void *param) { - struct node_rx_hdr *rx_hdr; + struct node_rx_pdu *rx; struct ll_scan_set *scan; struct lll_scan *lll; @@ -1143,15 +1142,15 @@ static void ext_disabled_cb(void *param) */ lll = (void *)param; scan = HDR_LLL2ULL(lll); - rx_hdr = (void *)scan->node_rx_scan_term; - if (!rx_hdr) { + rx = scan->node_rx_scan_term; + if (!rx) { return; } /* NOTE: parameters are already populated on disable, * just enqueue here */ - ll_rx_put_sched(rx_hdr->link, rx_hdr); + ll_rx_put_sched(rx->hdr.link, rx); } #endif /* CONFIG_BT_CTLR_ADV_EXT */ @@ -1180,8 +1179,7 @@ static uint8_t disable(uint8_t handle) #if defined(CONFIG_BT_CTLR_ADV_EXT) if (scan->node_rx_scan_term) { - struct node_rx_pdu *node_rx_scan_term = - (void *)scan->node_rx_scan_term; + struct node_rx_pdu *node_rx_scan_term = scan->node_rx_scan_term; scan->node_rx_scan_term = NULL; diff --git a/subsys/bluetooth/controller/ll_sw/ull_scan_aux.c b/subsys/bluetooth/controller/ll_sw/ull_scan_aux.c index f6560ab397a..409c9f1cb0b 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_scan_aux.c +++ b/subsys/bluetooth/controller/ll_sw/ull_scan_aux.c @@ -57,7 +57,7 @@ static inline struct ll_sync_iso_set * static void done_disabled_cb(void *param); static void flush_safe(void *param); static void flush(void *param); -static void rx_release_put(struct node_rx_hdr *rx); +static void rx_release_put(struct node_rx_pdu *rx); static void aux_sync_incomplete(void *param); static void ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift, uint32_t remainder, uint16_t lazy, uint8_t force, @@ -96,9 +96,9 @@ int ull_scan_aux_reset(void) return 0; } -void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) +void ull_scan_aux_setup(memq_link_t *link, struct node_rx_pdu *rx) { - struct node_rx_hdr *rx_incomplete; + struct node_rx_pdu *rx_incomplete; struct ll_sync_iso_set *sync_iso; struct pdu_adv_aux_ptr *aux_ptr; struct pdu_adv_com_ext_adv *p; @@ -132,7 +132,7 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) is_scan_req = false; ftr = &rx->rx_ftr; - switch (rx->type) { + switch (rx->hdr.type) { case NODE_RX_TYPE_EXT_1M_REPORT: lll_aux = NULL; aux = NULL; @@ -245,14 +245,14 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) /* Generate report based on PHY scanned */ switch (phy) { case PHY_1M: - rx->type = NODE_RX_TYPE_EXT_1M_REPORT; + rx->hdr.type = NODE_RX_TYPE_EXT_1M_REPORT; break; case PHY_2M: - rx->type = NODE_RX_TYPE_EXT_2M_REPORT; + rx->hdr.type = NODE_RX_TYPE_EXT_2M_REPORT; break; #if defined(CONFIG_BT_CTLR_PHY_CODED) case PHY_CODED: - rx->type = NODE_RX_TYPE_EXT_CODED_REPORT; + rx->hdr.type = NODE_RX_TYPE_EXT_CODED_REPORT; break; #endif /* CONFIG_BT_CTLR_PHY_CODED */ default: @@ -269,8 +269,8 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) #if defined(CONFIG_BT_CTLR_SYNC_PERIODIC) } else { /* Here we are periodic sync context */ - rx->type = NODE_RX_TYPE_SYNC_REPORT; - rx->handle = ull_sync_handle_get(sync); + rx->hdr.type = NODE_RX_TYPE_SYNC_REPORT; + rx->hdr.handle = ull_sync_handle_get(sync); /* Check if we need to create BIG sync */ sync_iso = sync_iso_create_get(sync); @@ -294,7 +294,7 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) LL_ASSERT(!sync_lll->lll_aux); ull_sync = HDR_LLL2ULL(sync_lll); - rx->handle = ull_sync_handle_get(ull_sync); + rx->hdr.handle = ull_sync_handle_get(ull_sync); /* Check if we need to create BIG sync */ sync_iso = sync_iso_create_get(ull_sync); @@ -326,12 +326,12 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) return; } - rx->link = link; + rx->hdr.link = link; ftr->extra = NULL; ftr->aux_sched = 0U; - pdu = (void *)((struct node_rx_pdu *)rx)->pdu; + pdu = (void *)rx->pdu; p = (void *)&pdu->adv_ext_ind; if (!pdu->len || !p->ext_hdr_len) { if (pdu->len) { @@ -449,10 +449,10 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) * synchronization */ if (IS_ENABLED(CONFIG_BT_CTLR_SYNC_PERIODIC) && - (rx->type == NODE_RX_TYPE_SYNC_REPORT) && + (rx->hdr.type == NODE_RX_TYPE_SYNC_REPORT) && acad_len) { /* Periodic Advertising Channel Map Indication */ - ull_sync_chm_update(rx->handle, ptr, acad_len); + ull_sync_chm_update(rx->hdr.handle, ptr, acad_len); #if defined(CONFIG_BT_CTLR_SYNC_ISO) struct ll_sync_set *sync_set; @@ -621,16 +621,32 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) * with a valid context. */ if (ftr->aux_lll_sched) { - /* AUX_ADV_IND/AUX_CHAIN_IND PDU reception is being setup */ - ftr->aux_sched = 1U; - if (IS_ENABLED(CONFIG_BT_CTLR_SYNC_PERIODIC) && sync_lll) { sync_lll->lll_aux = lll_aux; + /* AUX_ADV_IND/AUX_CHAIN_IND PDU reception is being + * setup + */ + ftr->aux_sched = 1U; + /* In sync context, dispatch immediately */ ll_rx_put_sched(link, rx); } else { + /* check scan context is not already using LLL + * scheduling, or receiving a chain then it will + * reuse the aux context. + */ + LL_ASSERT(!lll->lll_aux || (lll->lll_aux == lll_aux)); + + /* scan context get the aux context so that it can + * continue reception in LLL scheduling. + */ lll->lll_aux = lll_aux; + + /* AUX_ADV_IND/AUX_CHAIN_IND PDU reception is being + * setup + */ + ftr->aux_sched = 1U; } /* Reset auxiliary channel PDU scan state which otherwise is @@ -950,7 +966,7 @@ struct lll_scan_aux *ull_scan_aux_lll_is_valid_get(struct lll_scan_aux *lll) return NULL; } -void ull_scan_aux_release(memq_link_t *link, struct node_rx_hdr *rx) +void ull_scan_aux_release(memq_link_t *link, struct node_rx_pdu *rx) { struct lll_scan_aux *lll_aux; void *param_ull; @@ -961,7 +977,7 @@ void ull_scan_aux_release(memq_link_t *link, struct node_rx_hdr *rx) struct lll_scan *lll; /* Mark for buffer for release */ - rx->type = NODE_RX_TYPE_RELEASE; + rx->hdr.type = NODE_RX_TYPE_RELEASE; lll = rx->rx_ftr.param; lll_aux = lll->lll_aux; @@ -969,7 +985,7 @@ void ull_scan_aux_release(memq_link_t *link, struct node_rx_hdr *rx) } else if (!IS_ENABLED(CONFIG_BT_CTLR_SYNC_PERIODIC) || ull_scan_aux_is_valid_get(param_ull)) { /* Mark for buffer for release */ - rx->type = NODE_RX_TYPE_RELEASE; + rx->hdr.type = NODE_RX_TYPE_RELEASE; lll_aux = rx->rx_ftr.param; @@ -988,8 +1004,8 @@ void ull_scan_aux_release(memq_link_t *link, struct node_rx_hdr *rx) /* Change node type so HCI can dispatch report for truncated * data properly. */ - rx->type = NODE_RX_TYPE_SYNC_REPORT; - rx->handle = ull_sync_handle_get(sync); + rx->hdr.type = NODE_RX_TYPE_SYNC_REPORT; + rx->hdr.handle = ull_sync_handle_get(sync); /* Dequeue will try releasing list of node rx, set the extra * pointer to NULL. @@ -1033,7 +1049,7 @@ void ull_scan_aux_release(memq_link_t *link, struct node_rx_hdr *rx) /* Sync terminate requested, enqueue node rx so that it * be flushed by ull_scan_aux_stop(). */ - rx->link = link; + rx->hdr.link = link; if (aux->rx_last) { aux->rx_last->rx_ftr.extra = rx; } else { @@ -1213,7 +1229,7 @@ static void flush(void *param) { struct ll_scan_aux_set *aux; struct ll_scan_set *scan; - struct node_rx_hdr *rx; + struct node_rx_pdu *rx; struct lll_scan *lll; bool sched = false; @@ -1227,7 +1243,7 @@ static void flush(void *param) if (rx) { aux->rx_head = NULL; - ll_rx_put(rx->link, rx); + ll_rx_put(rx->hdr.link, rx); sched = true; } @@ -1264,17 +1280,17 @@ static void flush(void *param) aux_release(aux); } -static void rx_release_put(struct node_rx_hdr *rx) +static void rx_release_put(struct node_rx_pdu *rx) { - rx->type = NODE_RX_TYPE_RELEASE; + rx->hdr.type = NODE_RX_TYPE_RELEASE; - ll_rx_put(rx->link, rx); + ll_rx_put(rx->hdr.link, rx); } static void aux_sync_partial(void *param) { struct ll_scan_aux_set *aux; - struct node_rx_hdr *rx; + struct node_rx_pdu *rx; aux = param; rx = aux->rx_head; @@ -1283,7 +1299,7 @@ static void aux_sync_partial(void *param) LL_ASSERT(rx); rx->rx_ftr.aux_sched = 1U; - ll_rx_put_sched(rx->link, rx); + ll_rx_put_sched(rx->hdr.link, rx); } static void aux_sync_incomplete(void *param) @@ -1299,7 +1315,7 @@ static void aux_sync_incomplete(void *param) */ if (!aux->rx_head) { struct ll_sync_set *sync; - struct node_rx_hdr *rx; + struct node_rx_pdu *rx; struct lll_sync *lll; /* get reference to sync context */ @@ -1316,8 +1332,8 @@ static void aux_sync_incomplete(void *param) aux->rx_incomplete = NULL; /* prepare sync report with failure */ - rx->type = NODE_RX_TYPE_SYNC_REPORT; - rx->handle = ull_sync_handle_get(sync); + rx->hdr.type = NODE_RX_TYPE_SYNC_REPORT; + rx->hdr.handle = ull_sync_handle_get(sync); rx->rx_ftr.param = lll; /* flag chain reception failure */ diff --git a/subsys/bluetooth/controller/ll_sw/ull_scan_internal.h b/subsys/bluetooth/controller/ll_sw/ull_scan_internal.h index e74b5dc7b48..a399cbfd863 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_scan_internal.h +++ b/subsys/bluetooth/controller/ll_sw/ull_scan_internal.h @@ -76,7 +76,7 @@ int ull_scan_aux_init(void); int ull_scan_aux_reset(void); /* Helper to setup scanning on auxiliary channel */ -void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx); +void ull_scan_aux_setup(memq_link_t *link, struct node_rx_pdu *rx); /* Helper to clean up auxiliary channel scanning */ void ull_scan_aux_done(struct node_rx_event_done *done); @@ -88,7 +88,7 @@ struct ll_scan_aux_set *ull_scan_aux_set_get(uint8_t handle); struct ll_scan_aux_set *ull_scan_aux_is_valid_get(struct ll_scan_aux_set *aux); /* Helper function to flush and release incomplete auxiliary PDU chaining */ -void ull_scan_aux_release(memq_link_t *link, struct node_rx_hdr *rx); +void ull_scan_aux_release(memq_link_t *link, struct node_rx_pdu *rx); /* Helper function to stop auxiliary scan context */ int ull_scan_aux_stop(struct ll_scan_aux_set *aux); diff --git a/subsys/bluetooth/controller/ll_sw/ull_scan_types.h b/subsys/bluetooth/controller/ll_sw/ull_scan_types.h index 0c6a85f3f43..41c2bbd4628 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_scan_types.h +++ b/subsys/bluetooth/controller/ll_sw/ull_scan_types.h @@ -11,7 +11,7 @@ struct ll_scan_set { uint32_t ticks_window; #if defined(CONFIG_BT_CTLR_ADV_EXT) - struct node_rx_hdr *node_rx_scan_term; + struct node_rx_pdu *node_rx_scan_term; uint16_t duration_lazy; uint8_t is_stop:1; @@ -47,12 +47,12 @@ struct ll_scan_aux_set { /* lll_scan or lll_sync */ void *volatile parent; - struct node_rx_hdr *rx_head; - struct node_rx_hdr *rx_last; + struct node_rx_pdu *rx_head; + struct node_rx_pdu *rx_last; uint16_t data_len; #if defined(CONFIG_BT_CTLR_SYNC_PERIODIC) - struct node_rx_hdr *rx_incomplete; + struct node_rx_pdu *rx_incomplete; #endif }; diff --git a/subsys/bluetooth/controller/ll_sw/ull_sched.c b/subsys/bluetooth/controller/ll_sw/ull_sched.c index 980a4b7a221..0725d6784db 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_sched.c +++ b/subsys/bluetooth/controller/ll_sw/ull_sched.c @@ -423,10 +423,11 @@ static uint8_t after_match_slot_get(uint8_t user_id, uint32_t ticks_slot_abs, * found ticker to change. In this case the iterations have to be * restarted with the new reference ticks_anchor value. * Simultaneous continuous scanning on 1M and Coded PHY, alongwith - * directed advertising and one other state/role could expire in quick - * succession, hence have a retry count of 4. + * directed advertising and N other state/role could expire in quick + * succession, hence have a retry count of UINT8_MAX, which is possible + * maximum implementation limit for ticker nodes. */ - retry = 4U; + retry = UINT8_MAX; /* Initialize variable required for iterations to find a free slot */ ticker_id = ticker_id_prev = TICKER_NULL; diff --git a/subsys/bluetooth/controller/ll_sw/ull_sync.c b/subsys/bluetooth/controller/ll_sw/ull_sync.c index 4c2bec76483..0917e594edf 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_sync.c +++ b/subsys/bluetooth/controller/ll_sw/ull_sync.c @@ -100,7 +100,7 @@ uint8_t ll_sync_create(uint8_t options, uint8_t sid, uint8_t adv_addr_type, struct ll_scan_set *scan_coded; memq_link_t *link_sync_estab; memq_link_t *link_sync_lost; - struct node_rx_hdr *node_rx; + struct node_rx_pdu *node_rx; struct lll_sync *lll_sync; struct ll_scan_set *scan; struct ll_sync_set *sync; @@ -180,8 +180,8 @@ uint8_t ll_sync_create(uint8_t options, uint8_t sid, uint8_t adv_addr_type, } /* Initialize sync context */ - node_rx->link = link_sync_estab; - sync->node_rx_lost.hdr.link = link_sync_lost; + node_rx->hdr.link = link_sync_estab; + sync->node_rx_lost.rx.hdr.link = link_sync_lost; /* Make sure that the node_rx_sync_establ hasn't got anything assigned. It is used to * mark when sync establishment is in progress. @@ -360,9 +360,9 @@ uint8_t ll_sync_create_cancel(void **rx) sync->timeout = 0U; } - node_rx = (void *)sync->node_rx_sync_estab; + node_rx = sync->node_rx_sync_estab; link_sync_estab = node_rx->hdr.link; - link_sync_lost = sync->node_rx_lost.hdr.link; + link_sync_lost = sync->node_rx_lost.rx.hdr.link; ll_rx_link_release(link_sync_lost); ll_rx_link_release(link_sync_estab); @@ -386,7 +386,7 @@ uint8_t ll_sync_create_cancel(void **rx) /* NOTE: Since NODE_RX_TYPE_SYNC is only generated from ULL context, * pass ULL sync context as parameter. */ - node_rx->hdr.rx_ftr.param = sync; + node_rx->rx_ftr.param = sync; *rx = node_rx; @@ -412,7 +412,7 @@ uint8_t ll_sync_terminate(uint16_t handle) /* Stop periodic sync ticker timeouts */ err = ull_ticker_stop_with_mark(TICKER_ID_SCAN_SYNC_BASE + handle, sync, &sync->lll); - LL_ASSERT(err == 0 || err == -EALREADY); + LL_ASSERT_INFO2(err == 0 || err == -EALREADY, handle, err); if (err) { return BT_HCI_ERR_CMD_DISALLOWED; } @@ -431,7 +431,7 @@ uint8_t ll_sync_terminate(uint16_t handle) LL_ASSERT(!aux->parent); } - link_sync_lost = sync->node_rx_lost.hdr.link; + link_sync_lost = sync->node_rx_lost.rx.hdr.link; ll_rx_link_release(link_sync_lost); /* Mark sync context not sync established */ @@ -568,15 +568,15 @@ void ull_sync_release(struct ll_sync_set *sync) if (lll->node_cte_incomplete) { const uint8_t release_cnt = 1U; - struct node_rx_hdr *node_hdr; + struct node_rx_pdu *node_rx; memq_link_t *link; - node_hdr = &lll->node_cte_incomplete->hdr; - link = node_hdr->link; + node_rx = &lll->node_cte_incomplete->rx; + link = node_rx->hdr.link; ll_rx_link_release(link); ull_iq_report_link_inc_quota(release_cnt); - ull_df_iq_report_mem_release(node_hdr); + ull_df_iq_report_mem_release(node_rx); ull_df_rx_iq_report_alloc(release_cnt); lll->node_cte_incomplete = NULL; @@ -661,7 +661,7 @@ bool ull_sync_setup_sid_match(struct ll_scan_set *scan, uint8_t sid) } void ull_sync_setup(struct ll_scan_set *scan, struct ll_scan_aux_set *aux, - struct node_rx_hdr *node_rx, struct pdu_adv_sync_info *si) + struct node_rx_pdu *node_rx, struct pdu_adv_sync_info *si) { uint32_t ticks_slot_overhead; uint32_t ticks_slot_offset; @@ -802,7 +802,7 @@ void ull_sync_setup(struct ll_scan_set *scan, struct ll_scan_aux_set *aux, rx = (void *)sync->node_rx_sync_estab; rx->hdr.type = NODE_RX_TYPE_SYNC; rx->hdr.handle = sync_handle; - rx->hdr.rx_ftr.param = scan; + rx->rx_ftr.param = scan; se = (void *)rx->pdu; se->interval = interval; se->phy = lll->phy; @@ -911,7 +911,7 @@ void ull_sync_setup_reset(struct ll_scan_set *scan) } } -void ull_sync_established_report(memq_link_t *link, struct node_rx_hdr *rx) +void ull_sync_established_report(memq_link_t *link, struct node_rx_pdu *rx) { struct node_rx_pdu *rx_establ; struct ll_sync_set *sync; @@ -936,7 +936,7 @@ void ull_sync_established_report(memq_link_t *link, struct node_rx_hdr *rx) #else struct pdu_cte_info *rx_cte_info; - rx_cte_info = pdu_cte_info_get((struct pdu_adv *)((struct node_rx_pdu *)rx)->pdu); + rx_cte_info = pdu_cte_info_get((struct pdu_adv *)rx->pdu); if (rx_cte_info != NULL) { sync_status = lll_sync_cte_is_allowed(lll->cte_type, lll->filter_policy, rx_cte_info->time, rx_cte_info->type); @@ -964,7 +964,7 @@ void ull_sync_established_report(memq_link_t *link, struct node_rx_hdr *rx) #endif /* !CONFIG_BT_CTLR_SYNC_PERIODIC_CTE_TYPE_FILTERING */ /* Prepare and dispatch sync notification */ - rx_establ = (void *)sync->node_rx_sync_estab; + rx_establ = sync->node_rx_sync_estab; rx_establ->hdr.type = NODE_RX_TYPE_SYNC; rx_establ->hdr.handle = ull_sync_handle_get(sync); se = (void *)rx_establ->pdu; @@ -1005,10 +1005,10 @@ void ull_sync_established_report(memq_link_t *link, struct node_rx_hdr *rx) /* Change node type to appropriately handle periodic * advertising PDU report. */ - rx->type = NODE_RX_TYPE_SYNC_REPORT; + rx->hdr.type = NODE_RX_TYPE_SYNC_REPORT; ull_scan_aux_setup(link, rx); } else { - rx->type = NODE_RX_TYPE_RELEASE; + rx->hdr.type = NODE_RX_TYPE_RELEASE; ll_rx_put_sched(link, rx); } } @@ -1441,7 +1441,7 @@ static void sync_lost(void *param) rx = (void *)&sync->node_rx_lost; rx->hdr.handle = ull_sync_handle_get(sync); rx->hdr.type = NODE_RX_TYPE_SYNC_LOST; - rx->hdr.rx_ftr.param = sync; + rx->rx_ftr.param = sync; /* Enqueue the sync lost towards ULL context */ ll_rx_put_sched(rx->hdr.link, rx); diff --git a/subsys/bluetooth/controller/ll_sw/ull_sync_internal.h b/subsys/bluetooth/controller/ll_sw/ull_sync_internal.h index 62d50bd8021..dacc48ccdc7 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_sync_internal.h +++ b/subsys/bluetooth/controller/ll_sw/ull_sync_internal.h @@ -13,9 +13,9 @@ void ull_sync_setup_addr_check(struct ll_scan_set *scan, uint8_t addr_type, uint8_t *addr, uint8_t rl_idx); bool ull_sync_setup_sid_match(struct ll_scan_set *scan, uint8_t sid); void ull_sync_setup(struct ll_scan_set *scan, struct ll_scan_aux_set *aux, - struct node_rx_hdr *node_rx, struct pdu_adv_sync_info *si); + struct node_rx_pdu *node_rx, struct pdu_adv_sync_info *si); void ull_sync_setup_reset(struct ll_scan_set *scan); -void ull_sync_established_report(memq_link_t *link, struct node_rx_hdr *rx); +void ull_sync_established_report(memq_link_t *link, struct node_rx_pdu *rx); void ull_sync_done(struct node_rx_event_done *done); void ull_sync_chm_update(uint8_t sync_handle, uint8_t *acad, uint8_t acad_len); int ull_sync_slot_update(struct ll_sync_set *sync, uint32_t slot_plus_us, diff --git a/subsys/bluetooth/controller/ll_sw/ull_sync_iso.c b/subsys/bluetooth/controller/ll_sw/ull_sync_iso.c index 50172cff8b1..f6c68436b5e 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_sync_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_sync_iso.c @@ -83,7 +83,7 @@ uint8_t ll_big_sync_create(uint8_t big_handle, uint16_t sync_handle, struct ll_sync_iso_set *sync_iso; memq_link_t *link_sync_estab; memq_link_t *link_sync_lost; - struct node_rx_hdr *node_rx; + struct node_rx_pdu *node_rx; struct ll_sync_set *sync; struct lll_sync_iso *lll; int8_t last_index; @@ -160,9 +160,9 @@ uint8_t ll_big_sync_create(uint8_t big_handle, uint16_t sync_handle, sync_iso->timeout_expire = 0U; /* Setup the periodic sync to establish ISO sync */ - node_rx->link = link_sync_estab; + node_rx->hdr.link = link_sync_estab; sync->iso.node_rx_estab = node_rx; - sync_iso->node_rx_lost.hdr.link = link_sync_lost; + sync_iso->node_rx_lost.rx.hdr.link = link_sync_lost; /* Initialize sync LLL context */ lll = &sync_iso->lll; @@ -241,9 +241,9 @@ uint8_t ll_big_sync_terminate(uint8_t big_handle, void **rx) } sync->iso.sync_iso = NULL; - node_rx = (void *)sync->iso.node_rx_estab; + node_rx = sync->iso.node_rx_estab; link_sync_estab = node_rx->hdr.link; - link_sync_lost = sync_iso->node_rx_lost.hdr.link; + link_sync_lost = sync_iso->node_rx_lost.rx.hdr.link; ll_rx_link_release(link_sync_lost); ll_rx_link_release(link_sync_estab); @@ -256,10 +256,9 @@ uint8_t ll_big_sync_terminate(uint8_t big_handle, void **rx) /* NOTE: Since NODE_RX_TYPE_SYNC_ISO is only generated from ULL * context, pass ULL context as parameter. */ - node_rx->hdr.rx_ftr.param = sync_iso; + node_rx->rx_ftr.param = sync_iso; - /* NOTE: struct node_rx_lost has uint8_t member following the - * struct node_rx_hdr to store the reason. + /* NOTE: struct node_rx_lost has uint8_t member store the reason. */ se = (void *)node_rx->pdu; se->status = BT_HCI_ERR_OP_CANCELLED_BY_HOST; @@ -271,14 +270,14 @@ uint8_t ll_big_sync_terminate(uint8_t big_handle, void **rx) err = ull_ticker_stop_with_mark((TICKER_ID_SCAN_SYNC_ISO_BASE + big_handle), sync_iso, &sync_iso->lll); - LL_ASSERT(err == 0 || err == -EALREADY); + LL_ASSERT_INFO2(err == 0 || err == -EALREADY, big_handle, err); if (err) { return BT_HCI_ERR_CMD_DISALLOWED; } ull_sync_iso_stream_release(sync_iso); - link_sync_lost = sync_iso->node_rx_lost.hdr.link; + link_sync_lost = sync_iso->node_rx_lost.rx.hdr.link; ll_rx_link_release(link_sync_lost); return BT_HCI_ERR_SUCCESS; @@ -368,7 +367,7 @@ void ull_sync_iso_stream_release(struct ll_sync_iso_set *sync_iso) } void ull_sync_iso_setup(struct ll_sync_iso_set *sync_iso, - struct node_rx_hdr *node_rx, + struct node_rx_pdu *node_rx, uint8_t *acad, uint8_t acad_len) { struct lll_sync_iso_stream *stream; @@ -465,6 +464,9 @@ void ull_sync_iso_setup(struct ll_sync_iso_set *sync_iso, lll->payload_count |= (uint64_t)bi->payload_count_framing[3] << 24; lll->payload_count |= (uint64_t)(bi->payload_count_framing[4] & 0x7f) << 32; + /* Set establishment event countdown */ + lll->establish_events = CONN_ESTAB_COUNTDOWN; + if (lll->enc && (bi_size == PDU_BIG_INFO_ENCRYPTED_SIZE)) { const uint8_t BIG3[4] = {0x33, 0x47, 0x49, 0x42}; struct ccm *ccm_rx; @@ -652,22 +654,25 @@ void ull_sync_iso_estab_done(struct node_rx_event_done *done) struct node_rx_sync_iso *se; struct node_rx_pdu *rx; - /* switch to normal prepare */ - mfy_lll_prepare.fp = lll_sync_iso_prepare; + if (done->extra.trx_cnt || done->extra.estab_failed) { + /* Switch to normal prepare */ + mfy_lll_prepare.fp = lll_sync_iso_prepare; - /* Get reference to ULL context */ - sync_iso = CONTAINER_OF(done->param, struct ll_sync_iso_set, ull); + /* Get reference to ULL context */ + sync_iso = CONTAINER_OF(done->param, struct ll_sync_iso_set, ull); - /* Prepare BIG Sync Established */ - rx = (void *)sync_iso->sync->iso.node_rx_estab; - rx->hdr.type = NODE_RX_TYPE_SYNC_ISO; - rx->hdr.handle = sync_iso_handle_get(sync_iso); - rx->hdr.rx_ftr.param = sync_iso; + /* Prepare BIG Sync Established */ + rx = (void *)sync_iso->sync->iso.node_rx_estab; + rx->hdr.type = NODE_RX_TYPE_SYNC_ISO; + rx->hdr.handle = sync_iso_handle_get(sync_iso); + rx->rx_ftr.param = sync_iso; - se = (void *)rx->pdu; - se->status = BT_HCI_ERR_SUCCESS; + se = (void *)rx->pdu; + se->status = done->extra.estab_failed ? + BT_HCI_ERR_CONN_FAIL_TO_ESTAB : BT_HCI_ERR_SUCCESS; - ll_rx_put_sched(rx->hdr.link, rx); + ll_rx_put_sched(rx->hdr.link, rx); + } ull_sync_iso_done(done); } @@ -785,7 +790,7 @@ void ull_sync_iso_done_terminate(struct node_rx_event_done *done) rx = (void *)&sync_iso->node_rx_lost; rx->hdr.handle = sync_iso_handle_get(sync_iso); rx->hdr.type = NODE_RX_TYPE_SYNC_ISO_LOST; - rx->hdr.rx_ftr.param = sync_iso; + rx->rx_ftr.param = sync_iso; *((uint8_t *)rx->pdu) = lll->term_reason; /* Stop Sync ISO Ticker */ @@ -818,7 +823,7 @@ static void disable(uint8_t sync_idx) err = ull_ticker_stop_with_mark(TICKER_ID_SCAN_SYNC_ISO_BASE + sync_idx, sync_iso, &sync_iso->lll); - LL_ASSERT(err == 0 || err == -EALREADY); + LL_ASSERT_INFO2(err == 0 || err == -EALREADY, sync_idx, err); } static int init_reset(void) @@ -872,9 +877,15 @@ static void timeout_cleanup(struct ll_sync_iso_set *sync_iso) /* Populate the Sync Lost which will be enqueued in disabled_cb */ rx = (void *)&sync_iso->node_rx_lost; rx->hdr.handle = sync_iso_handle_get(sync_iso); - rx->hdr.type = NODE_RX_TYPE_SYNC_ISO_LOST; - rx->hdr.rx_ftr.param = sync_iso; - *((uint8_t *)rx->pdu) = BT_HCI_ERR_CONN_TIMEOUT; + rx->rx_ftr.param = sync_iso; + + if (mfy_lll_prepare.fp == lll_sync_iso_prepare) { + rx->hdr.type = NODE_RX_TYPE_SYNC_ISO_LOST; + *((uint8_t *)rx->pdu) = BT_HCI_ERR_CONN_TIMEOUT; + } else { + rx->hdr.type = NODE_RX_TYPE_SYNC_ISO; + *((uint8_t *)rx->pdu) = BT_HCI_ERR_CONN_FAIL_TO_ESTAB; + } /* Stop Sync ISO Ticker */ handle = sync_iso_handle_get(sync_iso); diff --git a/subsys/bluetooth/controller/ll_sw/ull_sync_iso_internal.h b/subsys/bluetooth/controller/ll_sw/ull_sync_iso_internal.h index 65287328594..19c5315bfee 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_sync_iso_internal.h +++ b/subsys/bluetooth/controller/ll_sw/ull_sync_iso_internal.h @@ -10,7 +10,7 @@ struct ll_sync_iso_set *ull_sync_iso_by_stream_get(uint16_t handle); struct lll_sync_iso_stream *ull_sync_iso_stream_get(uint16_t handle); void ull_sync_iso_stream_release(struct ll_sync_iso_set *sync_iso); void ull_sync_iso_setup(struct ll_sync_iso_set *sync_iso, - struct node_rx_hdr *node_rx, + struct node_rx_pdu *node_rx, uint8_t *acad, uint8_t acad_len); void ull_sync_iso_estab_done(struct node_rx_event_done *done); void ull_sync_iso_done(struct node_rx_event_done *done); diff --git a/subsys/bluetooth/controller/ll_sw/ull_sync_types.h b/subsys/bluetooth/controller/ll_sw/ull_sync_types.h index 36532d76102..38a92f40c9e 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_sync_types.h +++ b/subsys/bluetooth/controller/ll_sw/ull_sync_types.h @@ -71,21 +71,19 @@ struct ll_sync_set { * struct node_rx_pdu. */ struct { - struct node_rx_hdr hdr; - union { - uint8_t pdu[0] __aligned(4); - uint8_t reason; - }; + struct node_rx_pdu rx; + /* Dummy declaration to ensure space allocated to hold one pdu bytes */ + uint8_t dummy; } node_rx_lost; /* Not-Null when sync was setup and Controller is waiting for first AUX_SYNC_IND PDU. * It means the sync was not estalished yet. */ - struct node_rx_hdr *node_rx_sync_estab; + struct node_rx_pdu *node_rx_sync_estab; #if defined(CONFIG_BT_CTLR_SYNC_ISO) struct { - struct node_rx_hdr *node_rx_estab; + struct node_rx_pdu *node_rx_estab; /* Non-Null when creating sync, reset in ISR context on * synchronisation state and checked in Thread context when @@ -126,14 +124,9 @@ struct ll_sync_iso_set { * struct node_rx_pdu. */ struct { - struct node_rx_hdr hdr; - union { - uint8_t pdu[0] __aligned(4); - struct { - uint8_t handle; - uint8_t reason; - }; - }; + struct node_rx_pdu rx; + /* Dummy declaration to ensure space allocated to hold two pdu bytes */ + uint8_t dummy[2]; } node_rx_lost; }; diff --git a/subsys/bluetooth/controller/ticker/ticker.c b/subsys/bluetooth/controller/ticker/ticker.c index 639cd0ed57d..efeeff1bae7 100644 --- a/subsys/bluetooth/controller/ticker/ticker.c +++ b/subsys/bluetooth/controller/ticker/ticker.c @@ -840,6 +840,7 @@ static uint8_t ticker_resolve_collision(struct ticker_node *nodes, while (id_head != TICKER_NULL) { struct ticker_node *ticker_next = &nodes[id_head]; + uint32_t ticker_next_ticks_slot; /* Accumulate ticks_to_expire for each node */ acc_ticks_to_expire += ticker_next->ticks_to_expire; @@ -847,8 +848,17 @@ static uint8_t ticker_resolve_collision(struct ticker_node *nodes, break; } + if (TICKER_HAS_SLOT_WINDOW(ticker_next) && + (ticker_next->ticks_slot == 0U)) { + ticker_next_ticks_slot = + HAL_TICKER_RESCHEDULE_MARGIN; + } else { + ticker_next_ticks_slot = + ticker_next->ticks_slot; + } + /* We only care about nodes with slot reservation */ - if (ticker_next->ticks_slot == 0U) { + if (ticker_next_ticks_slot == 0U) { id_head = ticker_next->next; continue; } @@ -977,7 +987,8 @@ static uint8_t ticker_resolve_collision(struct ticker_node *nodes, /* Check if next node is within this reservation slot * and wins conflict resolution */ - if (curr_has_ticks_slot_window || + if ((curr_has_ticks_slot_window && + next_not_ticks_slot_window) || (!lazy_next_periodic_skip && (next_is_critical || next_force || @@ -1295,11 +1306,19 @@ void ticker_worker(void *param) #if !defined(CONFIG_BT_TICKER_LOW_LAT) && \ !defined(CONFIG_BT_TICKER_SLOT_AGNOSTIC) + uint32_t ticker_ticks_slot; + + if (TICKER_HAS_SLOT_WINDOW(ticker) && + (ticker->ticks_slot == 0U)) { + ticker_ticks_slot = HAL_TICKER_RESCHEDULE_MARGIN; + } else { + ticker_ticks_slot = ticker->ticks_slot; + } + /* Check if node has slot reservation and resolve any collision * with other ticker nodes */ - if (((ticker->ticks_slot != 0U) || - TICKER_HAS_SLOT_WINDOW(ticker)) && + if ((ticker_ticks_slot != 0U) && (slot_reserved || (instance->ticks_slot_previous > ticks_expired) || ticker_resolve_collision(node, ticker))) { @@ -1431,7 +1450,7 @@ void ticker_worker(void *param) #if !defined(CONFIG_BT_TICKER_LOW_LAT) && \ !defined(CONFIG_BT_TICKER_SLOT_AGNOSTIC) - if (ticker->ticks_slot != 0U) { + if (ticker_ticks_slot != 0U) { /* Any further nodes will be skipped */ slot_reserved = 1U; } @@ -2061,13 +2080,21 @@ static inline void ticker_job_worker_bh(struct ticker_instance *instance, instance->ticks_slot_previous = 0U; } + uint32_t ticker_ticks_slot; + + if (TICKER_HAS_SLOT_WINDOW(ticker) && !ticker->ticks_slot) { + ticker_ticks_slot = HAL_TICKER_RESCHEDULE_MARGIN; + } else { + ticker_ticks_slot = ticker->ticks_slot; + } + /* If a reschedule is set pending, we will need to keep * the slot_previous information */ - if (ticker->ticks_slot && (state == 2U) && !skip_collision && + if (ticker_ticks_slot && (state == 2U) && !skip_collision && !TICKER_RESCHEDULE_PENDING(ticker)) { instance->ticker_id_slot_previous = id_expired; - instance->ticks_slot_previous = ticker->ticks_slot; + instance->ticks_slot_previous = ticker_ticks_slot; } #endif /* CONFIG_BT_TICKER_SLOT_AGNOSTIC */ diff --git a/subsys/bluetooth/host/Kconfig b/subsys/bluetooth/host/Kconfig index 1753c7a2d6a..f880ed805d9 100644 --- a/subsys/bluetooth/host/Kconfig +++ b/subsys/bluetooth/host/Kconfig @@ -72,27 +72,6 @@ config BT_HCI_TX_PRIO int default 7 -config BT_HCI_RESERVE - int - default 0 if BT_H4 - default 1 if BT_H5 - default 1 if BT_HCI_IPC - default 1 if BT_SPI - default 1 if BT_STM32_IPM - default 1 if BT_STM32WBA - default 1 if BT_USERCHAN - default 1 if BT_ESP32 - default 0 if BT_B91 - default 1 if BT_AMBIQ_HCI - default 1 if BT_SILABS_HCI - # Even if no driver is selected the following default is still - # needed e.g. for unit tests. - default 0 - help - Headroom that the driver needs for sending and receiving buffers. Add a - new 'default' entry for each new driver. - - choice BT_RECV_CONTEXT prompt "BT RX Thread Selection" default BT_RECV_WORKQ_SYS if SOC_SERIES_NRF51X @@ -902,8 +881,7 @@ config BT_DF_CTE_TX_AOD config BT_DF_VS_CL_IQ_REPORT_16_BITS_IQ_SAMPLES bool "Use 16 bits signed integer IQ samples in connectionless IQ reports" - depends on BT_DF_CONNECTIONLESS_CTE_RX && BT_HCI_VS_EXT - select BT_HCI_VS_EVT + depends on BT_DF_CONNECTIONLESS_CTE_RX && BT_HCI_VS help Direction Finging connectionless IQ reports provide a set of IQ samples collected during sampling of CTE. Bluetooth 5.3 Core Specification defines IQ samples to be 8 bits signed @@ -913,8 +891,7 @@ config BT_DF_VS_CL_IQ_REPORT_16_BITS_IQ_SAMPLES config BT_DF_VS_CONN_IQ_REPORT_16_BITS_IQ_SAMPLES bool "Use 16 bits signed integer IQ samples in connection IQ reports" - depends on BT_DF_CONNECTION_CTE_RX && BT_HCI_VS_EXT - select BT_HCI_VS_EVT + depends on BT_DF_CONNECTION_CTE_RX && BT_HCI_VS help Direction Finging connection IQ reports provide a set of IQ samples collected during sampling of CTE. Bluetooth 5.3 Core Specification defines IQ samples to be 8 bits signed @@ -1019,88 +996,7 @@ config BT_CONN_DISABLE_SECURITY WARNING: This option enables anyone to snoop on-air traffic. Use of this feature in production is strongly discouraged. -config BT_CLASSIC - bool "Bluetooth BR/EDR support [EXPERIMENTAL]" - depends on BT_HCI_HOST - select BT_PERIPHERAL - select BT_CENTRAL - select BT_SMP - select BT_L2CAP_DYNAMIC_CHANNEL - select EXPERIMENTAL - help - This option enables Bluetooth BR/EDR support - -if BT_CLASSIC -config BT_MAX_SCO_CONN - int "Maximum number of simultaneous SCO connections" - default 1 - range 1 3 - help - Maximum number of simultaneous Bluetooth synchronous connections - supported. The minimum (and default) number is 1. - -config BT_RFCOMM - bool "Bluetooth RFCOMM protocol support [EXPERIMENTAL]" - select EXPERIMENTAL - help - This option enables Bluetooth RFCOMM support - -config BT_RFCOMM_L2CAP_MTU - int "L2CAP MTU for RFCOMM frames" - depends on BT_RFCOMM - # RX MTU will be truncated to account for the L2CAP PDU header. - default BT_BUF_ACL_RX_SIZE - range 23 32767 - help - Maximum size of L2CAP PDU for RFCOMM frames. - -config BT_RFCOMM_TX_MAX - int "Maximum number of pending TX buffers for RFCOMM" - default BT_MAX_CONN - range BT_MAX_CONN 255 - help - Maximum number of pending TX buffers that have an associated - sending buf. Normally this can be left to the default value, which - is equal to the number of session in the stack-internal pool. - -config BT_HFP_HF - bool "Bluetooth Handsfree profile HF Role support [EXPERIMENTAL]" - depends on PRINTK - select BT_RFCOMM - select EXPERIMENTAL - help - This option enables Bluetooth HF support - -config BT_AVDTP - bool "Bluetooth AVDTP protocol support [EXPERIMENTAL]" - select EXPERIMENTAL - help - This option enables Bluetooth AVDTP support - -config BT_A2DP - bool "Bluetooth A2DP Profile [EXPERIMENTAL]" - select BT_AVDTP - select EXPERIMENTAL - help - This option enables the A2DP profile - -config BT_PAGE_TIMEOUT - hex "Bluetooth Page Timeout" - default 0x2000 - range 0x0001 0xffff - help - This option sets the page timeout value. Value is selected as - (N * 0.625) ms. - -config BT_COD - hex "Bluetooth Class of Device(CoD)" - default 0 - help - This option sets the class of device.For the list of possible values please - consult the following link: - https://www.bluetooth.com/specifications/assigned-numbers - -endif # BT_CLASSIC +rsource "./classic/Kconfig" config BT_HCI_VS_EVT_USER bool "User Vendor-Specific event handling" diff --git a/subsys/bluetooth/host/Kconfig.l2cap b/subsys/bluetooth/host/Kconfig.l2cap index 52a21e2d87d..94fc58b08af 100644 --- a/subsys/bluetooth/host/Kconfig.l2cap +++ b/subsys/bluetooth/host/Kconfig.l2cap @@ -8,7 +8,6 @@ menu "L2CAP Options" config BT_L2CAP_TX_BUF_COUNT int "Number of L2CAP TX buffers" - default NET_BUF_TX_COUNT if NET_L2_BT default BT_BUF_ACL_TX_COUNT range 2 255 help @@ -16,7 +15,6 @@ config BT_L2CAP_TX_BUF_COUNT config BT_L2CAP_TX_FRAG_COUNT int "Number of L2CAP TX fragment buffers" - default NET_BUF_TX_COUNT if NET_L2_BT default 2 range 0 255 help diff --git a/subsys/bluetooth/host/adv.c b/subsys/bluetooth/host/adv.c index 7a312d5e05c..a6d62bd6db9 100644 --- a/subsys/bluetooth/host/adv.c +++ b/subsys/bluetooth/host/adv.c @@ -661,6 +661,12 @@ static int hci_set_ad_ext(struct bt_le_ext_adv *adv, uint16_t hci_op, return -EAGAIN; } + if (total_len_bytes > bt_dev.le.max_adv_data_len) { + LOG_WRN("adv or scan rsp data too large (%d > max %d)", total_len_bytes, + bt_dev.le.max_adv_data_len); + return -EDOM; + } + if (total_len_bytes <= BT_HCI_LE_EXT_ADV_FRAG_MAX_LEN) { /* If possible, set all data at once. * This allows us to update advertising data while advertising. @@ -921,7 +927,7 @@ static int le_adv_start_add_conn(const struct bt_le_ext_adv *adv, return -ENOMEM; } - bt_conn_set_state(conn, BT_CONN_CONNECTING_ADV); + bt_conn_set_state(conn, BT_CONN_ADV_CONNECTABLE); *out_conn = conn; return 0; } @@ -935,7 +941,7 @@ static int le_adv_start_add_conn(const struct bt_le_ext_adv *adv, return -ENOMEM; } - bt_conn_set_state(conn, BT_CONN_CONNECTING_DIR_ADV); + bt_conn_set_state(conn, BT_CONN_ADV_DIR_CONNECTABLE); *out_conn = conn; return 0; } @@ -946,10 +952,10 @@ static void le_adv_stop_free_conn(const struct bt_le_ext_adv *adv, uint8_t statu if (!adv_is_directed(adv)) { conn = bt_conn_lookup_state_le(adv->id, BT_ADDR_LE_NONE, - BT_CONN_CONNECTING_ADV); + BT_CONN_ADV_CONNECTABLE); } else { conn = bt_conn_lookup_state_le(adv->id, &adv->target_addr, - BT_CONN_CONNECTING_DIR_ADV); + BT_CONN_ADV_DIR_CONNECTABLE); } if (conn) { diff --git a/subsys/bluetooth/host/att.c b/subsys/bluetooth/host/att.c index 2ed3dfcb768..0efeccd76da 100644 --- a/subsys/bluetooth/host/att.c +++ b/subsys/bluetooth/host/att.c @@ -3550,6 +3550,10 @@ int bt_eatt_connect(struct bt_conn *conn, size_t num_channels) size_t i = 0; int err; + if (!conn) { + return -EINVAL; + } + /* Check the encryption level for EATT */ if (bt_conn_get_security(conn) < BT_SECURITY_L2) { /* Vol 3, Part G, Section 5.3.2 Channel Requirements states: @@ -3562,10 +3566,6 @@ int bt_eatt_connect(struct bt_conn *conn, size_t num_channels) return -EINVAL; } - if (!conn) { - return -EINVAL; - } - att_chan = att_get_fixed_chan(conn); att = att_chan->att; @@ -3647,22 +3647,23 @@ int bt_eatt_disconnect(struct bt_conn *conn) #if defined(CONFIG_BT_TESTING) int bt_eatt_disconnect_one(struct bt_conn *conn) { - struct bt_att_chan *chan = att_get_fixed_chan(conn); - struct bt_att *att = chan->att; - int err = -ENOTCONN; + struct bt_att *att; + struct bt_att_chan *chan; if (!conn) { return -EINVAL; } + chan = att_get_fixed_chan(conn); + att = chan->att; + SYS_SLIST_FOR_EACH_CONTAINER(&att->chans, chan, node) { if (bt_att_is_enhanced(chan)) { - err = bt_l2cap_chan_disconnect(&chan->chan.chan); - return err; + return bt_l2cap_chan_disconnect(&chan->chan.chan); } } - return err; + return -ENOTCONN; } int bt_eatt_reconfigure(struct bt_conn *conn, uint16_t mtu) @@ -3807,6 +3808,7 @@ struct bt_att_req *bt_att_req_alloc(k_timeout_t timeout) /* No req will be fulfilled while blocking on the bt_recv thread. * Blocking would cause deadlock. */ + LOG_DBG("Timeout discarded. No blocking on bt_recv thread."); timeout = K_NO_WAIT; } diff --git a/subsys/bluetooth/host/buf.c b/subsys/bluetooth/host/buf.c index eeaacd49aae..1f2918fb8a9 100644 --- a/subsys/bluetooth/host/buf.c +++ b/subsys/bluetooth/host/buf.c @@ -28,13 +28,17 @@ #define NUM_COMLETE_EVENT_SIZE BT_BUF_EVT_SIZE( \ sizeof(struct bt_hci_cp_host_num_completed_packets) + \ MAX_EVENT_COUNT * sizeof(struct bt_hci_handle_count)) -/* Dedicated pool for HCI_Number_of_Completed_Packets. This event is always - * consumed synchronously by bt_recv_prio() so a single buffer is enough. - * Having a dedicated pool for it ensures that exhaustion of the RX pool - * cannot block the delivery of this priority event. + +/* Pool for RX HCI buffers that are always freed by `bt_recv` + * before it returns. + * + * A singleton buffer shall be sufficient for correct operation. + * The buffer count may be increased as an optimization to allow + * the HCI transport to fill buffers in parallel with `bt_recv` + * consuming them. */ -NET_BUF_POOL_FIXED_DEFINE(num_complete_pool, 1, NUM_COMLETE_EVENT_SIZE, - sizeof(struct bt_buf_data), NULL); +#define SYNC_EVT_SIZE NUM_COMLETE_EVENT_SIZE +NET_BUF_POOL_FIXED_DEFINE(sync_evt_pool, 1, SYNC_EVT_SIZE, sizeof(struct bt_buf_data), NULL); #endif /* CONFIG_BT_CONN || CONFIG_BT_ISO */ NET_BUF_POOL_FIXED_DEFINE(discardable_pool, CONFIG_BT_BUF_EVT_DISCARDABLE_COUNT, @@ -92,7 +96,7 @@ struct net_buf *bt_buf_get_evt(uint8_t evt, bool discardable, switch (evt) { #if defined(CONFIG_BT_CONN) || defined(CONFIG_BT_ISO) case BT_HCI_EVT_NUM_COMPLETED_PACKETS: - buf = net_buf_alloc(&num_complete_pool, timeout); + buf = net_buf_alloc(&sync_evt_pool, timeout); break; #endif /* CONFIG_BT_CONN || CONFIG_BT_ISO */ default: @@ -139,7 +143,7 @@ struct net_buf_pool *bt_buf_get_discardable_pool(void) #if defined(CONFIG_BT_CONN) || defined(CONFIG_BT_ISO) struct net_buf_pool *bt_buf_get_num_complete_pool(void) { - return &num_complete_pool; + return &sync_evt_pool; } #endif /* CONFIG_BT_CONN || CONFIG_BT_ISO */ #endif /* ZTEST_UNITTEST */ diff --git a/subsys/bluetooth/host/classic/CMakeLists.txt b/subsys/bluetooth/host/classic/CMakeLists.txt index 48b3935f86f..039f961c786 100644 --- a/subsys/bluetooth/host/classic/CMakeLists.txt +++ b/subsys/bluetooth/host/classic/CMakeLists.txt @@ -22,3 +22,8 @@ zephyr_library_sources_ifdef( hfp_hf.c at.c ) + +zephyr_library_sources_ifdef( + CONFIG_BT_HFP_AG + hfp_ag.c + ) diff --git a/subsys/bluetooth/host/classic/Kconfig b/subsys/bluetooth/host/classic/Kconfig new file mode 100644 index 00000000000..2869978f9c7 --- /dev/null +++ b/subsys/bluetooth/host/classic/Kconfig @@ -0,0 +1,175 @@ +# Bluetooth Calssic configuration options + +# Copyright (c) 2016-2020 Nordic Semiconductor ASA +# Copyright (c) 2015-2016 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +menu "Bluetooth Classic Options" + +config BT_CLASSIC + bool "Bluetooth BR/EDR support [EXPERIMENTAL]" + depends on BT_HCI_HOST + select BT_PERIPHERAL + select BT_CENTRAL + select BT_SMP + select BT_L2CAP_DYNAMIC_CHANNEL + select EXPERIMENTAL + help + This option enables Bluetooth BR/EDR support + +if BT_CLASSIC +config BT_MAX_SCO_CONN + int "Maximum number of simultaneous SCO connections" + default 1 + range 1 3 + help + Maximum number of simultaneous Bluetooth synchronous connections + supported. The minimum (and default) number is 1. + +config BT_RFCOMM + bool "Bluetooth RFCOMM protocol support [EXPERIMENTAL]" + select EXPERIMENTAL + help + This option enables Bluetooth RFCOMM support + +config BT_RFCOMM_L2CAP_MTU + int "L2CAP MTU for RFCOMM frames" + depends on BT_RFCOMM + default BT_BUF_ACL_RX_SIZE + range 23 32767 + help + Maximum size of L2CAP PDU for RFCOMM frames. + RX MTU will be truncated to account for the L2CAP PDU header. + +config BT_RFCOMM_TX_MAX + int "Maximum number of pending TX buffers for RFCOMM" + default BT_CONN_TX_MAX + range BT_CONN_TX_MAX 255 + help + Maximum number of pending TX buffers that have an associated + sending buf. Normally this can be left to the default value, which + is equal to the number of session in the stack-internal pool. + +config BT_RFCOMM_DLC_STACK_SIZE + int "Stack size of DLC for RFCOMM" + default 512 if BT_HFP_AG + default 256 + help + Stack size of DLC for RFCOMM. This is the context from which + all datas of upper layer are sent and disconnect + callback to the upper layer. The default value is sufficient + for basic operation, but if the application needs to do + advanced things in its callbacks that require extra stack + space, this value can be increased to accommodate for that. + +config BT_HFP_HF + bool "Bluetooth Handsfree profile HF Role support [EXPERIMENTAL]" + depends on PRINTK + select BT_RFCOMM + select EXPERIMENTAL + help + This option enables Bluetooth HF support + +config BT_HFP_AG + bool "Bluetooth Handsfree profile AG Role support [EXPERIMENTAL]" + depends on PRINTK + select BT_RFCOMM + select EXPERIMENTAL + help + This option enables Bluetooth AG support + +if BT_HFP_AG +config BT_HFP_AG_TX_BUF_COUNT + int "Maximum number of TX buffers for HFP AG [EXPERIMENTAL]" + default BT_RFCOMM_TX_MAX + range BT_RFCOMM_TX_MAX 255 + help + Maximum number of pending TX buffers that have an associated + sending buf. Normally this can be left to the default value, which + is equal to the number of session in the stack-internal pool. + +config BT_HFP_AG_THREAD_STACK_SIZE + int "Size of the HFP AG thread stack [EXPERIMENTAL]" + default 1024 + help + Stack size needed for executing thread for HFP AG. + +config BT_HFP_AG_THREAD_PRIO + # Hidden option for HFP AG thread priority + int + default 6 + +config BT_HFP_AG_OUTGOING_TIMEOUT + int "Call outgoing timeout value for HFP AG [EXPERIMENTAL]" + default 3 + range 1 10 + help + The option sets the timeout of call outgoing. If the call does + not switch to alerting state before timeout, it will be + stopped by the HFP AG. The unit is seconds. + +config BT_HFP_AG_INCOMING_TIMEOUT + int "Incoming call timeout value for HFP AG [EXPERIMENTAL]" + default 3 + range 1 10 + help + The option sets the timeout of incoming call. If the call does + not switch to ringing state before timeout, it will be + stopped by the HFP AG. The unit is seconds. + +config BT_HFP_AG_ALERTING_TIMEOUT + int "Call alerting/ringing timeout value for HFP AG [EXPERIMENTAL]" + default 60 + range 10 60 + help + The option sets the timeout of call alerting/ringing. If the + call is not active before timeout, it will be stopped + by the HFP AG. The unit is seconds. + +config BT_HFP_AG_PHONE_NUMBER_MAX_LEN + int "Supported max length of phone number for HFP AG [EXPERIMENTAL]" + default 32 + range 1 255 + help + Supported max length of phone number for HFP AG. + +config BT_HFP_AG_RING_NOTIFY_INTERVAL + int "Ring notification interval [EXPERIMENTAL]" + default 3 + help + Ring notification interval if the call is in alert state. + The unit is seconds. +endif # BT_HFP_AG + +config BT_AVDTP + bool "Bluetooth AVDTP protocol support [EXPERIMENTAL]" + select EXPERIMENTAL + help + This option enables Bluetooth AVDTP support + +config BT_A2DP + bool "Bluetooth A2DP Profile [EXPERIMENTAL]" + select BT_AVDTP + select EXPERIMENTAL + help + This option enables the A2DP profile + +config BT_PAGE_TIMEOUT + hex "Bluetooth Page Timeout" + default 0x2000 + range 0x0001 0xffff + help + This option sets the page timeout value. Value is selected as + (N * 0.625) ms. + +config BT_COD + hex "Bluetooth Class of Device(CoD)" + default 0 + help + This option sets the class of device.For the list of possible values please + consult the following link: + https://www.bluetooth.com/specifications/assigned-numbers + +endif # BT_CLASSIC + +endmenu diff --git a/subsys/bluetooth/host/classic/br.c b/subsys/bluetooth/host/classic/br.c index d176994a552..80b010798c1 100644 --- a/subsys/bluetooth/host/classic/br.c +++ b/subsys/bluetooth/host/classic/br.c @@ -98,7 +98,7 @@ void bt_hci_conn_req(struct net_buf *buf) accept_conn(&evt->bdaddr); conn->role = BT_HCI_ROLE_PERIPHERAL; - bt_conn_set_state(conn, BT_CONN_CONNECTING); + bt_conn_set_state(conn, BT_CONN_INITIATING); bt_conn_unref(conn); } diff --git a/subsys/bluetooth/host/classic/hfp_ag.c b/subsys/bluetooth/host/classic/hfp_ag.c new file mode 100644 index 00000000000..034cd324b6a --- /dev/null +++ b/subsys/bluetooth/host/classic/hfp_ag.c @@ -0,0 +1,2255 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "common/assert.h" + +#include +#include + +#include "host/hci_core.h" +#include "host/conn_internal.h" +#include "l2cap_br_internal.h" +#include "rfcomm_internal.h" +#include "at.h" +#include "sco_internal.h" + +#include "hfp_internal.h" +#include "hfp_ag_internal.h" + +#define LOG_LEVEL CONFIG_BT_HFP_AG_LOG_LEVEL +#include +LOG_MODULE_REGISTER(bt_hfp_ag); + +typedef int (*bt_hfp_ag_parse_command_t)(struct bt_hfp_ag *ag, struct net_buf *buf); + +struct bt_hfp_ag_at_cmd_handler { + const char *cmd; + bt_hfp_ag_parse_command_t handler; +}; + +static const struct { + const char *name; + const char *connector; + uint32_t min; + uint32_t max; +} ag_ind[] = { + {"service", "-", 0, 1}, /* BT_HFP_AG_SERVICE_IND */ + {"call", ",", 0, 1}, /* BT_HFP_AG_CALL_IND */ + {"callsetup", "-", 0, 3}, /* BT_HFP_AG_CALL_SETUP_IND */ + {"callheld", "-", 0, 2}, /* BT_HFP_AG_CALL_HELD_IND */ + {"signal", "-", 0, 5}, /* BT_HFP_AG_SIGNAL_IND */ + {"roam", ",", 0, 1}, /* BT_HFP_AG_ROAM_IND */ + {"battchg", "-", 0, 5} /* BT_HFP_AG_BATTERY_IND */ +}; + +typedef void (*bt_hfp_ag_tx_cb_t)(struct bt_hfp_ag *ag, void *user_data); + +struct bt_ag_tx { + sys_snode_t node; + + struct bt_hfp_ag *ag; + struct net_buf *buf; + bt_hfp_ag_tx_cb_t cb; + void *user_data; +}; + +NET_BUF_POOL_FIXED_DEFINE(ag_pool, CONFIG_BT_HFP_AG_TX_BUF_COUNT, + BT_RFCOMM_BUF_SIZE(BT_HF_CLIENT_MAX_PDU), + CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); + +static struct bt_hfp_ag bt_hfp_ag_pool[CONFIG_BT_MAX_CONN]; + +static struct bt_hfp_ag_cb *bt_ag; + +/* Sent but not acknowledged TX packets with a callback */ +static struct bt_ag_tx ag_tx[CONFIG_BT_HFP_AG_TX_BUF_COUNT * 2]; +static K_FIFO_DEFINE(ag_tx_free); +static K_FIFO_DEFINE(ag_tx_notify); + +struct k_thread ag_thread; +static K_KERNEL_STACK_MEMBER(ag_thread_stack, CONFIG_BT_HFP_AG_THREAD_STACK_SIZE); +static k_tid_t ag_thread_id; + +static enum at_cme bt_hfp_ag_get_cme_err(int err) +{ + enum at_cme cme_err; + + switch (err) { + case -EOPNOTSUPP: + cme_err = CME_ERROR_OPERATION_NOT_SUPPORTED; + break; + case -EFAULT: + cme_err = CME_ERROR_AG_FAILURE; + break; + case -ENOSR: + cme_err = CME_ERROR_MEMORY_FAILURE; + break; + case -ENOMEM: + __fallthrough; + case -ENOBUFS: + cme_err = CME_ERROR_MEMORY_FULL; + break; + case -ENAMETOOLONG: + cme_err = CME_ERROR_DIAL_STRING_TO_LONG; + break; + case -EINVAL: + cme_err = CME_ERROR_INVALID_INDEX; + break; + case -ENOTSUP: + cme_err = CME_ERROR_OPERATION_NOT_ALLOWED; + break; + case -ENOTCONN: + cme_err = CME_ERROR_NO_CONNECTION_TO_PHONE; + break; + default: + cme_err = CME_ERROR_AG_FAILURE; + break; + } + + return cme_err; +} + +static void hfp_ag_lock(struct bt_hfp_ag *ag) +{ + k_sem_take(&ag->lock, K_FOREVER); +} + +static void hfp_ag_unlock(struct bt_hfp_ag *ag) +{ + k_sem_give(&ag->lock); +} + +static void bt_hfp_ag_set_state(struct bt_hfp_ag *ag, bt_hfp_state_t state) +{ + LOG_DBG("update state %p, old %d -> new %d", ag, ag->state, state); + + hfp_ag_lock(ag); + ag->state = state; + hfp_ag_unlock(ag); + + switch (state) { + case BT_HFP_DISCONNECTED: + if (bt_ag && bt_ag->disconnected) { + bt_ag->disconnected(ag); + } + break; + case BT_HFP_CONNECTING: + break; + case BT_HFP_CONFIG: + break; + case BT_HFP_CONNECTED: + if (bt_ag && bt_ag->connected) { + bt_ag->connected(ag); + } + break; + case BT_HFP_DISCONNECTING: + break; + default: + LOG_WRN("no valid (%u) state was set", state); + break; + } +} + +static void bt_hfp_ag_set_call_state(struct bt_hfp_ag *ag, bt_hfp_call_state_t call_state) +{ + bt_hfp_state_t state; + + LOG_DBG("update call state %p, old %d -> new %d", ag, ag->call_state, call_state); + + hfp_ag_lock(ag); + ag->call_state = call_state; + state = ag->state; + hfp_ag_unlock(ag); + + switch (call_state) { + case BT_HFP_CALL_TERMINATE: + atomic_clear(ag->flags); + k_work_cancel_delayable(&ag->deferred_work); + break; + case BT_HFP_CALL_OUTGOING: + k_work_reschedule(&ag->deferred_work, K_SECONDS(CONFIG_BT_HFP_AG_OUTGOING_TIMEOUT)); + break; + case BT_HFP_CALL_INCOMING: + k_work_reschedule(&ag->deferred_work, K_SECONDS(CONFIG_BT_HFP_AG_INCOMING_TIMEOUT)); + break; + case BT_HFP_CALL_ALERTING: + k_work_reschedule(&ag->ringing_work, K_NO_WAIT); + k_work_reschedule(&ag->deferred_work, K_SECONDS(CONFIG_BT_HFP_AG_ALERTING_TIMEOUT)); + break; + case BT_HFP_CALL_ACTIVE: + k_work_cancel_delayable(&ag->ringing_work); + k_work_cancel_delayable(&ag->deferred_work); + break; + case BT_HFP_CALL_HOLD: + break; + default: + /* Invalid state */ + break; + } + + if (state == BT_HFP_DISCONNECTING) { + int err = bt_rfcomm_dlc_disconnect(&ag->rfcomm_dlc); + + if (err) { + LOG_ERR("Fail to disconnect DLC %p", &ag->rfcomm_dlc); + } + } +} + +static struct bt_ag_tx *bt_ag_tx_alloc(void) +{ + /* The TX context always get freed in the system workqueue, + * so if we're in the same workqueue but there are no immediate + * contexts available, there's no chance we'll get one by waiting. + */ + if (k_current_get() == &k_sys_work_q.thread) { + return k_fifo_get(&ag_tx_free, K_NO_WAIT); + } + + if (IS_ENABLED(CONFIG_BT_HFP_AG_LOG_LEVEL_DBG)) { + struct bt_ag_tx *tx = k_fifo_get(&ag_tx_free, K_NO_WAIT); + + if (tx) { + return tx; + } + + LOG_WRN("Unable to get an immediate free bt_ag_tx"); + } + + return k_fifo_get(&ag_tx_free, K_FOREVER); +} + +static void bt_ag_tx_free(struct bt_ag_tx *tx) +{ + LOG_DBG("Free tx buffer %p", tx); + + (void)memset(tx, 0, sizeof(*tx)); + + k_fifo_put(&ag_tx_free, tx); +} + +static int hfp_ag_next_step(struct bt_hfp_ag *ag, bt_hfp_ag_tx_cb_t cb, void *user_data) +{ + struct bt_ag_tx *tx; + + LOG_DBG("cb %p user_data %p", cb, user_data); + + tx = bt_ag_tx_alloc(); + if (tx == NULL) { + LOG_ERR("No tx buffers!"); + return -ENOMEM; + } + + LOG_DBG("Alloc tx buffer %p", tx); + + tx->ag = ag; + tx->buf = NULL; + tx->cb = cb; + tx->user_data = user_data; + + k_fifo_put(&ag_tx_notify, tx); + + return 0; +} + +static int hfp_ag_send(struct bt_hfp_ag *ag, struct bt_ag_tx *tx) +{ + return bt_rfcomm_dlc_send(&ag->rfcomm_dlc, tx->buf); +} + +static int hfp_ag_send_data(struct bt_hfp_ag *ag, bt_hfp_ag_tx_cb_t cb, void *user_data, + const char *format, ...) +{ + struct net_buf *buf; + struct bt_ag_tx *tx; + va_list vargs; + int err; + + LOG_DBG("AG %p sending data cb %p user_data %p", ag, cb, user_data); + + buf = bt_rfcomm_create_pdu(&ag_pool); + if (!buf) { + LOG_ERR("No Buffers!"); + return -ENOMEM; + } + + tx = bt_ag_tx_alloc(); + if (tx == NULL) { + LOG_ERR("No tx buffers!"); + net_buf_unref(buf); + return -ENOMEM; + } + + LOG_DBG("buf %p tx %p", buf, tx); + + tx->ag = ag; + tx->buf = buf; + tx->cb = cb; + tx->user_data = user_data; + + va_start(vargs, format); + err = vsnprintk((char *)buf->data, (net_buf_tailroom(buf) - 1), format, vargs); + va_end(vargs); + + if (err < 0) { + LOG_ERR("Unable to format variable arguments"); + net_buf_unref(buf); + bt_ag_tx_free(tx); + return err; + } + + net_buf_add(buf, err); + + LOG_HEXDUMP_DBG(buf->data, buf->len, "Sending:"); + + hfp_ag_lock(ag); + sys_slist_append(&ag->tx_pending, &tx->node); + hfp_ag_unlock(ag); + + err = hfp_ag_send(ag, tx); + if (err < 0) { + LOG_ERR("Rfcomm send error :(%d)", err); + hfp_ag_lock(ag); + sys_slist_find_and_remove(&ag->tx_pending, &tx->node); + hfp_ag_unlock(ag); + net_buf_unref(buf); + bt_ag_tx_free(tx); + return err; + } + + return 0; +} + +static void skip_space(struct net_buf *buf) +{ + while ((buf->len > 0) && (buf->data[0] == ' ')) { + (void)net_buf_pull(buf, 1); + } +} + +static int get_number(struct net_buf *buf, uint32_t *number) +{ + int err = -EINVAL; + + *number = 0; + + skip_space(buf); + while (buf->len > 0) { + if ((buf->data[0] >= '0') && (buf->data[0] <= '9')) { + *number = *number * 10 + buf->data[0] - '0'; + (void)net_buf_pull(buf, 1); + err = 0; + } else { + break; + } + } + skip_space(buf); + + return err; +} + +static bool is_char(struct net_buf *buf, uint8_t c) +{ + bool found = false; + + skip_space(buf); + if (buf->len > 0) { + if (buf->data[0] == c) { + (void)net_buf_pull(buf, 1); + found = true; + } + } + skip_space(buf); + + return found; +} + +static int bt_hfp_ag_brsf_handler(struct bt_hfp_ag *ag, struct net_buf *buf) +{ + uint32_t hf_features; + int err; + + if (!is_char(buf, '=')) { + return -ENOTSUP; + } + + err = get_number(buf, &hf_features); + if (err != 0) { + return -ENOTSUP; + } + + if (!is_char(buf, '\r')) { + return -ENOTSUP; + } + + hfp_ag_lock(ag); + ag->hf_features = hf_features; + hfp_ag_unlock(ag); + + return hfp_ag_send_data(ag, NULL, NULL, "\r\n+BRSF:%d\r\n", ag->ag_features); +} + +static int bt_hfp_ag_bac_handler(struct bt_hfp_ag *ag, struct net_buf *buf) +{ + uint32_t codec; + uint32_t codec_ids = 0U; + int err; + + if (!is_char(buf, '=')) { + return -ENOTSUP; + } + + hfp_ag_lock(ag); + if (!(ag->hf_features & BT_HFP_HF_FEATURE_CODEC_NEG) || + !(ag->ag_features & BT_HFP_AG_FEATURE_CODEC_NEG)) { + hfp_ag_unlock(ag); + return -EOPNOTSUPP; + } + hfp_ag_unlock(ag); + + while (err == 0) { + err = get_number(buf, &codec); + if (err != 0) { + return -ENOTSUP; + } + + if (!is_char(buf, ',')) { + if (!is_char(buf, '\r')) { + return -ENOTSUP; + } + } + + if (codec < (sizeof(codec_ids) * 8)) { + codec_ids |= BIT(codec); + } + } + + hfp_ag_lock(ag); + ag->hf_codec_ids = codec_ids; + hfp_ag_unlock(ag); + + if (bt_ag && bt_ag->codec) { + bt_ag->codec(ag, ag->hf_codec_ids); + } + + return 0; +} + +static int bt_hfp_ag_cind_handler(struct bt_hfp_ag *ag, struct net_buf *buf) +{ + int err; + bool inquiry_status = true; + + if (is_char(buf, '=')) { + inquiry_status = false; + } + + if (!is_char(buf, '?')) { + return -ENOTSUP; + } + + if (!is_char(buf, '\r')) { + return -ENOTSUP; + } + + if (!inquiry_status) { + err = hfp_ag_send_data( + ag, NULL, NULL, + "\r\n+CIND:(\"%s\",(%d%s%d)),(\"%s\",(%d%s%d)),(\"%s\",(%d%s%d)),(\"%s\",(%" + "d%s%d)),(\"%s\",(%d%s%d)),(\"%s\",(%d%s%d)),(\"%s\",(%d%s%d))\r\n", + ag_ind[BT_HFP_AG_SERVICE_IND].name, ag_ind[BT_HFP_AG_SERVICE_IND].min, + ag_ind[BT_HFP_AG_SERVICE_IND].connector, ag_ind[BT_HFP_AG_SERVICE_IND].max, + ag_ind[BT_HFP_AG_CALL_IND].name, ag_ind[BT_HFP_AG_CALL_IND].min, + ag_ind[BT_HFP_AG_CALL_IND].connector, ag_ind[BT_HFP_AG_CALL_IND].max, + ag_ind[BT_HFP_AG_CALL_SETUP_IND].name, ag_ind[BT_HFP_AG_CALL_SETUP_IND].min, + ag_ind[BT_HFP_AG_CALL_SETUP_IND].connector, + ag_ind[BT_HFP_AG_CALL_SETUP_IND].max, ag_ind[BT_HFP_AG_CALL_HELD_IND].name, + ag_ind[BT_HFP_AG_CALL_HELD_IND].min, + ag_ind[BT_HFP_AG_CALL_HELD_IND].connector, + ag_ind[BT_HFP_AG_CALL_HELD_IND].max, ag_ind[BT_HFP_AG_SIGNAL_IND].name, + ag_ind[BT_HFP_AG_SIGNAL_IND].min, ag_ind[BT_HFP_AG_SIGNAL_IND].connector, + ag_ind[BT_HFP_AG_SIGNAL_IND].max, ag_ind[BT_HFP_AG_ROAM_IND].name, + ag_ind[BT_HFP_AG_ROAM_IND].min, ag_ind[BT_HFP_AG_ROAM_IND].connector, + ag_ind[BT_HFP_AG_ROAM_IND].max, ag_ind[BT_HFP_AG_BATTERY_IND].name, + ag_ind[BT_HFP_AG_BATTERY_IND].min, ag_ind[BT_HFP_AG_BATTERY_IND].connector, + ag_ind[BT_HFP_AG_BATTERY_IND].max); + } else { + err = hfp_ag_send_data(ag, NULL, NULL, "\r\n+CIND:%d,%d,%d,%d,%d,%d,%d\r\n", + ag->indicator_value[BT_HFP_AG_SERVICE_IND], + ag->indicator_value[BT_HFP_AG_CALL_IND], + ag->indicator_value[BT_HFP_AG_CALL_SETUP_IND], + ag->indicator_value[BT_HFP_AG_CALL_HELD_IND], + ag->indicator_value[BT_HFP_AG_SIGNAL_IND], + ag->indicator_value[BT_HFP_AG_ROAM_IND], + ag->indicator_value[BT_HFP_AG_BATTERY_IND]); + } + + return err; +} + +static void bt_hfp_ag_set_in_band_ring(struct bt_hfp_ag *ag, void *user_data) +{ + bool is_inband_ringtone; + + hfp_ag_lock(ag); + is_inband_ringtone = (ag->ag_features & BT_HFP_AG_FEATURE_INBAND_RINGTONE) ? true : false; + hfp_ag_unlock(ag); + + if (is_inband_ringtone) { + int err = hfp_ag_send_data(ag, NULL, NULL, "\r\n+BSIR:1\r\n"); + + atomic_set_bit_to(ag->flags, BT_HFP_AG_INBAND_RING, err == 0); + } +} + +static int bt_hfp_ag_cmer_handler(struct bt_hfp_ag *ag, struct net_buf *buf) +{ + uint32_t number; + int err; + static const uint32_t command_line_prefix[] = {3, 0, 0}; + + if (!is_char(buf, '=')) { + return -ENOTSUP; + } + + for (int i = 0; i < ARRAY_SIZE(command_line_prefix); i++) { + err = get_number(buf, &number); + if (err != 0) { + return -ENOTSUP; + } + + if (!is_char(buf, ',')) { + return -ENOTSUP; + } + + if (command_line_prefix[i] != number) { + return -ENOTSUP; + } + } + + err = get_number(buf, &number); + if (err != 0) { + return -ENOTSUP; + } + + if (!is_char(buf, '\r')) { + return -ENOTSUP; + } + + if (number == 1) { + atomic_set_bit(ag->flags, BT_HFP_AG_CMER_ENABLE); + bt_hfp_ag_set_state(ag, BT_HFP_CONNECTED); + err = hfp_ag_next_step(ag, bt_hfp_ag_set_in_band_ring, NULL); + return err; + } else if (number == 0) { + atomic_clear_bit(ag->flags, BT_HFP_AG_CMER_ENABLE); + } else { + return -ENOTSUP; + } + + return 0; +} + +static int bt_hfp_ag_chld_handler(struct bt_hfp_ag *ag, struct net_buf *buf) +{ + return -EOPNOTSUPP; +} + +static int bt_hfp_ag_bind_handler(struct bt_hfp_ag *ag, struct net_buf *buf) +{ + uint32_t indicator; + uint32_t hf_indicators = 0U; + int err; + char *data; + uint32_t len; + + hfp_ag_lock(ag); + if (!((ag->ag_features & BT_HFP_AG_FEATURE_HF_IND) && + (ag->hf_features & BT_HFP_HF_FEATURE_HF_IND))) { + hfp_ag_unlock(ag); + return -EOPNOTSUPP; + } + hfp_ag_unlock(ag); + + if (is_char(buf, '?')) { + if (!is_char(buf, '\r')) { + return -ENOTSUP; + } + + hfp_ag_lock(ag); + hf_indicators = ag->hf_indicators_of_hf & ag->hf_indicators_of_ag; + hfp_ag_unlock(ag); + len = (sizeof(hf_indicators) * 8) > HFP_HF_IND_MAX ? HFP_HF_IND_MAX + : (sizeof(hf_indicators) * 8); + for (int i = 1; i < len; i++) { + if (BIT(i) & hf_indicators) { + err = hfp_ag_send_data(ag, NULL, NULL, "\r\n+BIND:%d,%d\r\n", i, 1); + } else { + err = hfp_ag_send_data(ag, NULL, NULL, "\r\n+BIND:%d,%d\r\n", i, 0); + } + if (err < 0) { + return err; + } + if (hf_indicators == 0) { + break; + } + } + return 0; + } + + if (!is_char(buf, '=')) { + return -ENOTSUP; + } + + if (is_char(buf, '?')) { + if (!is_char(buf, '\r')) { + return -ENOTSUP; + } + + data = &ag->buffer[0]; + *data = '('; + data++; + hfp_ag_lock(ag); + hf_indicators = ag->hf_indicators_of_ag; + hfp_ag_unlock(ag); + len = (sizeof(hf_indicators) * 8) > HFP_HF_IND_MAX ? HFP_HF_IND_MAX + : (sizeof(hf_indicators) * 8); + for (int i = 1; (i < len) && (hf_indicators != 0); i++) { + if (BIT(i) & hf_indicators) { + int length = snprintk( + data, (char *)&ag->buffer[HF_MAX_BUF_LEN - 1] - data - 3, + "%d", i); + data += length; + hf_indicators &= ~BIT(i); + } + if (hf_indicators != 0) { + *data = ','; + data++; + } + } + *data = ')'; + data++; + *data = '\r'; + data++; + *data = '\0'; + data++; + + err = hfp_ag_send_data(ag, NULL, NULL, "\r\n+BIND:%s\r\n", &ag->buffer[0]); + return err; + } + + while (buf->len > 0) { + err = get_number(buf, &indicator); + if (err != 0) { + return -ENOTSUP; + } + + if (!is_char(buf, ',')) { + if (!is_char(buf, '\r')) { + return -ENOTSUP; + } + } + + if (indicator < (sizeof(hf_indicators) * 8)) { + hf_indicators |= BIT(indicator); + } + } + + hfp_ag_lock(ag); + ag->hf_indicators_of_hf = hf_indicators; + hfp_ag_unlock(ag); + + return 0; +} + +static int bt_hfp_ag_cmee_handler(struct bt_hfp_ag *ag, struct net_buf *buf) +{ + uint32_t cmee; + int err; + + if (!is_char(buf, '=')) { + return -ENOTSUP; + } + + err = get_number(buf, &cmee); + if (err != 0) { + return -ENOTSUP; + } + + if (!is_char(buf, '\r')) { + return -ENOTSUP; + } + + if (cmee > 1) { + return -ENOTSUP; + } + + atomic_set_bit_to(ag->flags, BT_HFP_AG_CMEE_ENABLE, cmee == 1); + + return 0; +} + +static int hfp_ag_update_indicator(struct bt_hfp_ag *ag, enum bt_hfp_ag_indicator index, + uint8_t value, bt_hfp_ag_tx_cb_t cb, void *user_data) +{ + int err; + uint8_t old_value; + + hfp_ag_lock(ag); + old_value = ag->indicator_value[index]; + if (value == old_value) { + LOG_ERR("Duplicate value setting, indicator %d, old %d -> new %d", index, old_value, + value); + hfp_ag_unlock(ag); + return -EINVAL; + } + + ag->indicator_value[index] = value; + hfp_ag_unlock(ag); + + LOG_DBG("indicator %d, old %d -> new %d", index, old_value, value); + + err = hfp_ag_send_data(ag, cb, user_data, "\r\n+CIEV:%d,%d\r\n", (uint8_t)index + 1, value); + if (err) { + hfp_ag_lock(ag); + ag->indicator_value[index] = old_value; + hfp_ag_unlock(ag); + LOG_ERR("Fail to update indicator %d, current %d", index, old_value); + } + + return err; +} + +static void hfp_ag_close_sco(struct bt_hfp_ag *ag) +{ + struct bt_conn *sco; + + LOG_DBG(""); + + hfp_ag_lock(ag); + sco = ag->sco_chan.sco; + ag->sco_chan.sco = NULL; + hfp_ag_unlock(ag); + if (sco != NULL) { + LOG_DBG("Disconnect sco %p", sco); + bt_conn_disconnect(sco, BT_HCI_ERR_LOCALHOST_TERM_CONN); + } +} + +static void bt_hfp_ag_reject_cb(struct bt_hfp_ag *ag, void *user_data) +{ + hfp_ag_close_sco(ag); + bt_hfp_ag_set_call_state(ag, BT_HFP_CALL_TERMINATE); + + if (bt_ag && bt_ag->reject) { + bt_ag->reject(ag); + } +} + +static void bt_hfp_ag_call_reject(struct bt_hfp_ag *ag, void *user_data) +{ + int err = hfp_ag_update_indicator(ag, BT_HFP_AG_CALL_SETUP_IND, BT_HFP_CALL_SETUP_NONE, + bt_hfp_ag_reject_cb, user_data); + if (err != 0) { + LOG_ERR("Fail to send err :(%d)", err); + } +} + +static void bt_hfp_ag_terminate_cb(struct bt_hfp_ag *ag, void *user_data) +{ + hfp_ag_close_sco(ag); + bt_hfp_ag_set_call_state(ag, BT_HFP_CALL_TERMINATE); + + if (bt_ag && bt_ag->terminate) { + bt_ag->terminate(ag); + } +} + +static void bt_hfp_ag_unit_call_terminate(struct bt_hfp_ag *ag, void *user_data) +{ + int err = hfp_ag_update_indicator(ag, BT_HFP_AG_CALL_IND, 0, bt_hfp_ag_terminate_cb, + user_data); + if (err != 0) { + LOG_ERR("Fail to send err :(%d)", err); + } +} + +static int bt_hfp_ag_chup_handler(struct bt_hfp_ag *ag, struct net_buf *buf) +{ + int err; + bt_hfp_call_state_t call_state; + + if (!is_char(buf, '\r')) { + return -ENOTSUP; + } + + hfp_ag_lock(ag); + call_state = ag->call_state; + hfp_ag_unlock(ag); + + if (call_state == BT_HFP_CALL_ALERTING) { + if (!atomic_test_bit(ag->flags, BT_HFP_AG_INCOMING_CALL)) { + return -ENOTSUP; + } + err = hfp_ag_next_step(ag, bt_hfp_ag_call_reject, NULL); + } else if ((call_state == BT_HFP_CALL_ACTIVE) || (call_state == BT_HFP_CALL_HOLD)) { + err = hfp_ag_next_step(ag, bt_hfp_ag_unit_call_terminate, NULL); + } else { + return -ENOTSUP; + } + return err; +} + +static uint8_t bt_hfp_get_call_state(struct bt_hfp_ag *ag) +{ + uint8_t status = HFP_AG_CLCC_STATUS_INVALID; + + hfp_ag_lock(ag); + switch (ag->call_state) { + case BT_HFP_CALL_TERMINATE: + break; + case BT_HFP_CALL_OUTGOING: + status = HFP_AG_CLCC_STATUS_DIALING; + break; + case BT_HFP_CALL_INCOMING: + status = HFP_AG_CLCC_STATUS_INCOMING; + break; + case BT_HFP_CALL_ALERTING: + if (atomic_test_bit(ag->flags, BT_HFP_AG_INCOMING_CALL)) { + status = HFP_AG_CLCC_STATUS_WAITING; + } else { + status = HFP_AG_CLCC_STATUS_ALERTING; + } + break; + case BT_HFP_CALL_ACTIVE: + status = HFP_AG_CLCC_STATUS_ACTIVE; + break; + case BT_HFP_CALL_HOLD: + status = HFP_AG_CLCC_STATUS_HELD; + break; + default: + break; + } + hfp_ag_unlock(ag); + + return status; +} + +static int bt_hfp_ag_clcc_handler(struct bt_hfp_ag *ag, struct net_buf *buf) +{ + int err; + uint8_t dir; + uint8_t status; + uint8_t mode; + uint8_t mpty; + + if (!is_char(buf, '\r')) { + return -ENOTSUP; + } + + hfp_ag_lock(ag); + if (ag->call_state == BT_HFP_CALL_TERMINATE) { + /* AG shall always send OK response to HF */ + hfp_ag_unlock(ag); + return 0; + } + hfp_ag_unlock(ag); + + dir = atomic_test_bit(ag->flags, BT_HFP_AG_INCOMING_CALL) ? 1 : 0; + status = bt_hfp_get_call_state(ag); + mode = 0; + mpty = 0; + err = hfp_ag_send_data(ag, NULL, NULL, "\r\n+CLCC:%d,%d,%d,%d,%d\r\n", 1, dir, status, mode, + mpty); + if (err != 0) { + LOG_ERR("Fail to send err :(%d)", err); + } + + /* AG shall always send OK response to HF */ + return 0; +} + +static int bt_hfp_ag_bia_handler(struct bt_hfp_ag *ag, struct net_buf *buf) +{ + uint32_t number; + int err; + int index = 0; + uint32_t indicator; + + if (!is_char(buf, '=')) { + return -ENOTSUP; + } + + hfp_ag_lock(ag); + indicator = ag->indicator; + hfp_ag_unlock(ag); + + while (buf->len > 0) { + err = get_number(buf, &number); + if (err == 0) { + /* Valid number */ + if (number) { + indicator |= BIT(index); + } else { + indicator &= ~BIT(index); + } + } + + if (is_char(buf, ',')) { + index++; + } else { + if (!is_char(buf, '\r')) { + return -ENOTSUP; + } + if (buf->len != 0) { + return -ENOTSUP; + } + } + } + + /* Force call, call setup and held call indicators are enabled. */ + indicator = BIT(BT_HFP_AG_CALL_IND) | BIT(BT_HFP_AG_CALL_SETUP_IND) | + BIT(BT_HFP_AG_CALL_HELD_IND); + + hfp_ag_lock(ag); + ag->indicator = indicator; + hfp_ag_unlock(ag); + + return 0; +} + +static void bt_hfp_ag_accept_cb(struct bt_hfp_ag *ag, void *user_data) +{ + bt_hfp_ag_set_call_state(ag, BT_HFP_CALL_ACTIVE); + + if (bt_ag && bt_ag->accept) { + bt_ag->accept(ag); + } +} + +static void bt_hfp_ag_call_ringing_cb(struct bt_hfp_ag *ag, bool in_bond) +{ + if (bt_ag && bt_ag->ringing) { + bt_ag->ringing(ag, in_bond); + } +} + +static void hfp_ag_sco_connected(struct bt_sco_chan *chan) +{ + struct bt_hfp_ag *ag = CONTAINER_OF(chan, struct bt_hfp_ag, sco_chan); + bt_hfp_call_state_t call_state; + + hfp_ag_lock(ag); + call_state = ag->call_state; + hfp_ag_unlock(ag); + if (call_state == BT_HFP_CALL_INCOMING) { + bt_hfp_ag_set_call_state(ag, BT_HFP_CALL_ALERTING); + bt_hfp_ag_call_ringing_cb(ag, true); + } + + if ((bt_ag) && bt_ag->sco_connected) { + bt_ag->sco_connected(ag, chan->sco); + } +} + +static void hfp_ag_sco_disconnected(struct bt_sco_chan *chan, uint8_t reason) +{ + struct bt_hfp_ag *ag = CONTAINER_OF(chan, struct bt_hfp_ag, sco_chan); + bt_hfp_call_state_t call_state; + + if ((bt_ag) && bt_ag->sco_disconnected) { + bt_ag->sco_disconnected(ag); + } + + hfp_ag_lock(ag); + call_state = ag->call_state; + hfp_ag_unlock(ag); + if ((call_state == BT_HFP_CALL_INCOMING) || (call_state == BT_HFP_CALL_OUTGOING)) { + bt_hfp_ag_call_reject(ag, NULL); + } +} + +static struct bt_conn *bt_hfp_ag_create_sco(struct bt_hfp_ag *ag) +{ + struct bt_conn *sco_conn; + + static struct bt_sco_chan_ops ops = { + .connected = hfp_ag_sco_connected, + .disconnected = hfp_ag_sco_disconnected, + }; + + LOG_DBG(""); + + if (ag->sco_chan.sco == NULL) { + ag->sco_chan.ops = &ops; + + /* create SCO connection*/ + sco_conn = bt_conn_create_sco(&ag->acl_conn->br.dst, &ag->sco_chan); + if (sco_conn != NULL) { + LOG_DBG("Created sco %p", sco_conn); + bt_conn_unref(sco_conn); + } + } else { + sco_conn = ag->sco_chan.sco; + } + + return sco_conn; +} + +static int hfp_ag_open_sco(struct bt_hfp_ag *ag) +{ + hfp_ag_lock(ag); + if (ag->sco_chan.sco == NULL) { + struct bt_conn *sco_conn = bt_hfp_ag_create_sco(ag); + + if (sco_conn == NULL) { + LOG_ERR("Fail to create sco connection!"); + hfp_ag_unlock(ag); + return -ENOTCONN; + } + + LOG_DBG("SCO connection created (%p)", sco_conn); + } + hfp_ag_unlock(ag); + + return 0; +} + +static int bt_hfp_ag_codec_select(struct bt_hfp_ag *ag) +{ + int err; + + LOG_DBG(""); + + hfp_ag_lock(ag); + if (ag->selected_codec_id == 0) { + LOG_ERR("Codec is invalid"); + hfp_ag_unlock(ag); + return -EINVAL; + } + + if (!(ag->hf_codec_ids & BIT(ag->selected_codec_id))) { + LOG_ERR("Codec is unsupported (codec id %d)", ag->selected_codec_id); + hfp_ag_unlock(ag); + return -EINVAL; + } + hfp_ag_unlock(ag); + + err = hfp_ag_send_data(ag, NULL, NULL, "\r\n+BCS:%d\r\n", ag->selected_codec_id); + if (err != 0) { + LOG_ERR("Fail to send err :(%d)", err); + } + return err; +} + +static int bt_hfp_ag_create_audio_connection(struct bt_hfp_ag *ag) +{ + int err; + uint32_t hf_codec_ids; + + hfp_ag_lock(ag); + hf_codec_ids = ag->hf_codec_ids; + hfp_ag_unlock(ag); + + if ((hf_codec_ids != 0) && atomic_test_bit(ag->flags, BT_HFP_AG_CODEC_CHANGED)) { + atomic_set_bit(ag->flags, BT_HFP_AG_CODEC_CONN); + err = bt_hfp_ag_codec_select(ag); + } else { + err = hfp_ag_open_sco(ag); + } + + return err; +} + +static void bt_hfp_ag_audio_connection(struct bt_hfp_ag *ag, void *user_data) +{ + int err; + + err = bt_hfp_ag_create_audio_connection(ag); + if (err) { + bt_hfp_ag_unit_call_terminate(ag, user_data); + } +} + +static void bt_hfp_ag_unit_call_accept(struct bt_hfp_ag *ag, void *user_data) +{ + int err; + + err = hfp_ag_update_indicator(ag, BT_HFP_AG_CALL_IND, 1, bt_hfp_ag_accept_cb, user_data); + if (err != 0) { + LOG_ERR("Fail to send err :(%d)", err); + } + + err = hfp_ag_update_indicator(ag, BT_HFP_AG_CALL_SETUP_IND, BT_HFP_CALL_SETUP_NONE, + bt_hfp_ag_audio_connection, user_data); + if (err != 0) { + LOG_ERR("Fail to send err :(%d)", err); + } +} + +static int bt_hfp_ag_ata_handler(struct bt_hfp_ag *ag, struct net_buf *buf) +{ + int err; + + if (!is_char(buf, '\r')) { + return -ENOTSUP; + } + + hfp_ag_lock(ag); + if (ag->call_state != BT_HFP_CALL_ALERTING) { + hfp_ag_unlock(ag); + return -ENOTSUP; + } + hfp_ag_unlock(ag); + + if (!atomic_test_bit(ag->flags, BT_HFP_AG_INCOMING_CALL)) { + return -ENOTSUP; + } + + err = hfp_ag_next_step(ag, bt_hfp_ag_unit_call_accept, NULL); + + return err; +} + +static int bt_hfp_ag_cops_handler(struct bt_hfp_ag *ag, struct net_buf *buf) +{ + int err; + uint32_t number; + + if (is_char(buf, '=')) { + static const uint32_t command_line_prefix[] = {3, 0}; + + for (int i = 0; i < ARRAY_SIZE(command_line_prefix); i++) { + err = get_number(buf, &number); + if (err != 0) { + return -ENOTSUP; + } + + if (command_line_prefix[i] != number) { + return -ENOTSUP; + } + + if (!is_char(buf, ',')) { + if (!is_char(buf, '\r')) { + return -ENOTSUP; + } + } + } + + atomic_set_bit(ag->flags, BT_HFP_AG_COPS_SET); + return 0; + } + + if (!atomic_test_bit(ag->flags, BT_HFP_AG_COPS_SET)) { + return -ENOTSUP; + } + + if (!is_char(buf, '?')) { + return -ENOTSUP; + } + + if (!is_char(buf, '\r')) { + return -ENOTSUP; + } + + err = hfp_ag_send_data(ag, NULL, NULL, "\r\n+COPS:%d,%d,\"%s\"\r\n", 0, 0, ag->operator); + if (err != 0) { + LOG_ERR("Fail to send err :(%d)", err); + } + + return err; +} + +static int bt_hfp_ag_bcc_handler(struct bt_hfp_ag *ag, struct net_buf *buf) +{ + int err; + + if (!is_char(buf, '\r')) { + return -ENOTSUP; + } + + hfp_ag_lock(ag); + if ((ag->selected_codec_id == 0) || + (!(ag->hf_codec_ids & BIT(ag->selected_codec_id))) || + (ag->call_state == BT_HFP_CALL_TERMINATE) || + (ag->sco_chan.sco != NULL)) { + hfp_ag_unlock(ag); + return -ENOTSUP; + } + hfp_ag_unlock(ag); + + err = hfp_ag_next_step(ag, bt_hfp_ag_audio_connection, NULL); + + return 0; +} + +static void bt_hfp_ag_unit_codec_conn_setup(struct bt_hfp_ag *ag, void *user_data) +{ + int err = hfp_ag_open_sco(ag); + + if (err) { + bt_hfp_ag_call_reject(ag, user_data); + } +} + +static int bt_hfp_ag_bcs_handler(struct bt_hfp_ag *ag, struct net_buf *buf) +{ + int err; + uint32_t number; + + if (!is_char(buf, '=')) { + return -ENOTSUP; + } + + err = get_number(buf, &number); + if (err != 0) { + return -ENOTSUP; + } + + if (!is_char(buf, '\r')) { + return -ENOTSUP; + } + + if (!atomic_test_bit(ag->flags, BT_HFP_AG_CODEC_CONN)) { + return -ESRCH; + } + + hfp_ag_lock(ag); + if (ag->selected_codec_id != number) { + LOG_ERR("Received codec id %d is not aligned with selected %d", + number, ag->selected_codec_id); + err = -ENOTSUP; + } else if (!(ag->hf_codec_ids & BIT(ag->selected_codec_id))) { + LOG_ERR("Selected codec id %d is unsupported %d", + ag->selected_codec_id, ag->hf_codec_ids); + err = -ENOTSUP; + } + hfp_ag_unlock(ag); + + atomic_clear_bit(ag->flags, BT_HFP_AG_CODEC_CONN); + atomic_clear_bit(ag->flags, BT_HFP_AG_CODEC_CHANGED); + + if (err == 0) { + err = hfp_ag_next_step(ag, bt_hfp_ag_unit_codec_conn_setup, NULL); + } else { + bt_hfp_call_state_t call_state; + + hfp_ag_lock(ag); + call_state = ag->call_state; + hfp_ag_unlock(ag); + if (call_state != BT_HFP_CALL_TERMINATE) { + (void)hfp_ag_next_step(ag, bt_hfp_ag_unit_call_terminate, NULL); + } + } + + return err; +} + +static void bt_hfp_ag_unit_call_outgoing(struct bt_hfp_ag *ag, void *user_data) +{ + int err = bt_hfp_ag_outgoing(ag, ag->number); + + if (err != 0) { + LOG_ERR("Fail to send err :(%d)", err); + } +} + +static int bt_hfp_ag_atd_handler(struct bt_hfp_ag *ag, struct net_buf *buf) +{ + int err; + char *number = NULL; + bool is_memory_dial = false; + size_t len; + + if (buf->data[buf->len - 1] != '\r') { + return -ENOTSUP; + } + + if (is_char(buf, '>')) { + is_memory_dial = true; + } + + if ((buf->len - 1) > CONFIG_BT_HFP_AG_PHONE_NUMBER_MAX_LEN) { + return -ENAMETOOLONG; + } + + buf->data[buf->len - 1] = '\0'; + + if (is_memory_dial) { + if (bt_ag && bt_ag->memory_dial) { + err = bt_ag->memory_dial(ag, &buf->data[0], &number); + if ((err != 0) || (number == NULL)) { + return -ENOTSUP; + } + } else { + return -ENOTSUP; + } + } else { + number = &buf->data[0]; + } + + len = strlen(number); + if (len == 0) { + return -ENOTSUP; + } + + if (len > CONFIG_BT_HFP_AG_PHONE_NUMBER_MAX_LEN) { + return -ENAMETOOLONG; + } + + hfp_ag_lock(ag); + if (ag->call_state != BT_HFP_CALL_TERMINATE) { + hfp_ag_unlock(ag); + return -EBUSY; + } + + /* Copy number to ag->number including null-character */ + memcpy(ag->number, number, len + 1); + hfp_ag_unlock(ag); + + err = hfp_ag_next_step(ag, bt_hfp_ag_unit_call_outgoing, NULL); + + return err; +} + +static int bt_hfp_ag_bldn_handler(struct bt_hfp_ag *ag, struct net_buf *buf) +{ + int err; + + if (!is_char(buf, '\r')) { + return -ENOTSUP; + } + + hfp_ag_lock(ag); + if (strlen(ag->number) == 0) { + hfp_ag_unlock(ag); + return -ENOSR; + } + + if (ag->call_state != BT_HFP_CALL_TERMINATE) { + hfp_ag_unlock(ag); + return -EBUSY; + } + hfp_ag_unlock(ag); + + err = hfp_ag_next_step(ag, bt_hfp_ag_unit_call_outgoing, NULL); + + return err; +} + +static int bt_hfp_ag_clip_handler(struct bt_hfp_ag *ag, struct net_buf *buf) +{ + int err; + uint32_t clip; + + err = get_number(buf, &clip); + if (err != 0) { + return -ENOTSUP; + } + + if (!is_char(buf, '\r')) { + return -ENOTSUP; + } + + if (clip > 1) { + return -ENOTSUP; + } + + atomic_set_bit_to(ag->flags, BT_HFP_AG_CLIP_ENABLE, clip == 1); + + return err; +} + +static struct bt_hfp_ag_at_cmd_handler cmd_handlers[] = { + {"AT+BRSF", bt_hfp_ag_brsf_handler}, {"AT+BAC", bt_hfp_ag_bac_handler}, + {"AT+CIND", bt_hfp_ag_cind_handler}, {"AT+CMER", bt_hfp_ag_cmer_handler}, + {"AT+CHLD", bt_hfp_ag_chld_handler}, {"AT+BIND", bt_hfp_ag_bind_handler}, + {"AT+CMEE", bt_hfp_ag_cmee_handler}, {"AT+CHUP", bt_hfp_ag_chup_handler}, + {"AT+CLCC", bt_hfp_ag_clcc_handler}, {"AT+BIA", bt_hfp_ag_bia_handler}, + {"ATA", bt_hfp_ag_ata_handler}, {"AT+COPS", bt_hfp_ag_cops_handler}, + {"AT+BCC", bt_hfp_ag_bcc_handler}, {"AT+BCS", bt_hfp_ag_bcs_handler}, + {"ATD", bt_hfp_ag_atd_handler}, {"AT+BLDN", bt_hfp_ag_bldn_handler}, + {"AT+CLIP", bt_hfp_ag_clip_handler}, +}; + +static void hfp_ag_connected(struct bt_rfcomm_dlc *dlc) +{ + struct bt_hfp_ag *ag = CONTAINER_OF(dlc, struct bt_hfp_ag, rfcomm_dlc); + + bt_hfp_ag_set_state(ag, BT_HFP_CONFIG); + + LOG_DBG("AG %p", ag); +} + +static void hfp_ag_disconnected(struct bt_rfcomm_dlc *dlc) +{ + struct bt_hfp_ag *ag = CONTAINER_OF(dlc, struct bt_hfp_ag, rfcomm_dlc); + bt_hfp_call_state_t call_state; + + bt_hfp_ag_set_state(ag, BT_HFP_DISCONNECTED); + + hfp_ag_lock(ag); + call_state = ag->call_state; + hfp_ag_unlock(ag); + if ((call_state == BT_HFP_CALL_ALERTING) || (call_state == BT_HFP_CALL_ACTIVE) || + (call_state == BT_HFP_CALL_HOLD)) { + bt_hfp_ag_terminate_cb(ag, NULL); + } + + LOG_DBG("AG %p", ag); +} + +static void hfp_ag_recv(struct bt_rfcomm_dlc *dlc, struct net_buf *buf) +{ + struct bt_hfp_ag *ag = CONTAINER_OF(dlc, struct bt_hfp_ag, rfcomm_dlc); + uint8_t *data = buf->data; + uint16_t len = buf->len; + enum at_cme cme_err; + int err = -EOPNOTSUPP; + + LOG_HEXDUMP_DBG(data, len, "Received:"); + + for (uint32_t index = 0; index < ARRAY_SIZE(cmd_handlers); index++) { + if (strlen(cmd_handlers[index].cmd) > len) { + continue; + } + if (strncmp((char *)data, cmd_handlers[index].cmd, + strlen(cmd_handlers[index].cmd)) != 0) { + continue; + } + if (NULL != cmd_handlers[index].handler) { + (void)net_buf_pull(buf, strlen(cmd_handlers[index].cmd)); + err = cmd_handlers[index].handler(ag, buf); + LOG_DBG("AT commander is handled (err %d)", err); + break; + } + } + + if ((err != 0) && atomic_test_bit(ag->flags, BT_HFP_AG_CMEE_ENABLE)) { + cme_err = bt_hfp_ag_get_cme_err(err); + err = hfp_ag_send_data(ag, NULL, NULL, "\r\n+CME ERROR:%d\r\n", (uint32_t)cme_err); + } else { + err = hfp_ag_send_data(ag, NULL, NULL, "\r\n%s\r\n", (err == 0) ? "OK" : "ERROR"); + } + + if (err != 0) { + LOG_ERR("HFP AG send response err :(%d)", err); + } +} + +static void bt_hfp_ag_thread(void *p1, void *p2, void *p3) +{ + struct bt_ag_tx *tx; + bt_hfp_ag_tx_cb_t cb; + struct bt_hfp_ag *ag; + void *user_data; + + while (true) { + tx = (struct bt_ag_tx *)k_fifo_get(&ag_tx_notify, K_FOREVER); + + if (tx == NULL) { + continue; + } + + cb = tx->cb; + ag = tx->ag; + user_data = tx->user_data; + + bt_ag_tx_free(tx); + + if (cb) { + cb(ag, user_data); + } + } +} + +static void hfp_ag_sent(struct bt_rfcomm_dlc *dlc, struct net_buf *buf, int err) +{ + struct bt_hfp_ag *ag = CONTAINER_OF(dlc, struct bt_hfp_ag, rfcomm_dlc); + struct bt_ag_tx *t, *tmp, *tx = NULL; + bool found; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&ag->tx_pending, t, tmp, node) { + if (t->buf == buf) { + tx = t; + break; + } + } + + if (tx == NULL) { + LOG_ERR("Node %p is not found", tx); + return; + } + + hfp_ag_lock(ag); + found = sys_slist_find_and_remove(&ag->tx_pending, &tx->node); + hfp_ag_unlock(ag); + + if (!found) { + LOG_ERR("Node %p is not found", tx); + } + + k_fifo_put(&ag_tx_notify, tx); +} + +static void bt_ag_deferred_work_cb(struct bt_hfp_ag *ag, void *user_data) +{ + int err; + bt_hfp_call_state_t call_state; + + LOG_DBG(""); + + hfp_ag_lock(ag); + call_state = ag->call_state; + hfp_ag_unlock(ag); + + switch (call_state) { + case BT_HFP_CALL_TERMINATE: + break; + case BT_HFP_CALL_ACTIVE: + break; + case BT_HFP_CALL_HOLD: + break; + case BT_HFP_CALL_OUTGOING: + __fallthrough; + case BT_HFP_CALL_INCOMING: + __fallthrough; + case BT_HFP_CALL_ALERTING: + __fallthrough; + default: + if (ag->indicator_value[BT_HFP_AG_CALL_SETUP_IND] && + ag->indicator_value[BT_HFP_AG_CALL_IND]) { + err = hfp_ag_update_indicator(ag, BT_HFP_AG_CALL_SETUP_IND, + BT_HFP_CALL_SETUP_NONE, NULL, NULL); + if (err) { + LOG_ERR("Fail to send indicator"); + bt_hfp_ag_terminate_cb(ag, NULL); + } else { + err = hfp_ag_update_indicator(ag, BT_HFP_AG_CALL_IND, 0, + bt_hfp_ag_terminate_cb, NULL); + if (err) { + LOG_ERR("Fail to send indicator"); + bt_hfp_ag_terminate_cb(ag, NULL); + } + } + } else if (ag->indicator_value[BT_HFP_AG_CALL_SETUP_IND]) { + err = hfp_ag_update_indicator(ag, BT_HFP_AG_CALL_SETUP_IND, + BT_HFP_CALL_SETUP_NONE, bt_hfp_ag_reject_cb, + NULL); + if (err) { + LOG_ERR("Fail to send indicator"); + bt_hfp_ag_terminate_cb(ag, NULL); + } + } else if (ag->indicator_value[BT_HFP_AG_CALL_IND]) { + err = hfp_ag_update_indicator(ag, BT_HFP_AG_CALL_IND, 0, + bt_hfp_ag_terminate_cb, NULL); + if (err) { + LOG_ERR("Fail to send indicator"); + bt_hfp_ag_terminate_cb(ag, NULL); + } + } + break; + } +} + +static void bt_ag_deferred_work(struct k_work *work) +{ + struct k_work_delayable *dwork = k_work_delayable_from_work(work); + struct bt_hfp_ag *ag = CONTAINER_OF(dwork, struct bt_hfp_ag, deferred_work); + + (void)hfp_ag_next_step(ag, bt_ag_deferred_work_cb, NULL); +} + +static void bt_ag_ringing_work_cb(struct bt_hfp_ag *ag, void *user_data) +{ + int err; + bt_hfp_call_state_t call_state; + + LOG_DBG(""); + + hfp_ag_lock(ag); + call_state = ag->call_state; + hfp_ag_unlock(ag); + if (call_state == BT_HFP_CALL_ALERTING) { + + if (!atomic_test_bit(ag->flags, BT_HFP_AG_INCOMING_CALL)) { + return; + } + + k_work_reschedule(&ag->ringing_work, + K_SECONDS(CONFIG_BT_HFP_AG_RING_NOTIFY_INTERVAL)); + + err = hfp_ag_send_data(ag, NULL, NULL, "\r\nRING\r\n"); + if (err) { + LOG_ERR("Fail to send RING %d", err); + } else { + if (atomic_test_bit(ag->flags, BT_HFP_AG_CLIP_ENABLE)) { + err = hfp_ag_send_data(ag, NULL, NULL, "\r\n+CLIP:\"%s\",%d\r\n", + ag->number, 0); + if (err) { + LOG_ERR("Fail to send CLIP %d", err); + } + } + } + } +} + +static void bt_ag_ringing_work(struct k_work *work) +{ + struct k_work_delayable *dwork = k_work_delayable_from_work(work); + struct bt_hfp_ag *ag = CONTAINER_OF(dwork, struct bt_hfp_ag, ringing_work); + + (void)hfp_ag_next_step(ag, bt_ag_ringing_work_cb, NULL); +} + +int bt_hfp_ag_connect(struct bt_conn *conn, struct bt_hfp_ag **ag, uint8_t channel) +{ + int i; + int err; + + static struct bt_rfcomm_dlc_ops ops = { + .connected = hfp_ag_connected, + .disconnected = hfp_ag_disconnected, + .recv = hfp_ag_recv, + .sent = hfp_ag_sent, + }; + + LOG_DBG(""); + + if (ag == NULL) { + return -EINVAL; + } + + *ag = NULL; + + if (ag_thread_id == NULL) { + + k_fifo_init(&ag_tx_free); + k_fifo_init(&ag_tx_notify); + + for (i = 0; i < ARRAY_SIZE(ag_tx); i++) { + k_fifo_put(&ag_tx_free, &ag_tx[i]); + } + + ag_thread_id = k_thread_create( + &ag_thread, ag_thread_stack, K_KERNEL_STACK_SIZEOF(ag_thread_stack), + bt_hfp_ag_thread, NULL, NULL, NULL, + K_PRIO_COOP(CONFIG_BT_HFP_AG_THREAD_PRIO), 0, K_NO_WAIT); + if (ag_thread_id == NULL) { + return -ENOMEM; + } + k_thread_name_set(ag_thread_id, "HFP AG"); + } + + for (i = 0; i < ARRAY_SIZE(bt_hfp_ag_pool); i++) { + struct bt_hfp_ag *_ag = &bt_hfp_ag_pool[i]; + + if (_ag->rfcomm_dlc.session) { + continue; + } + + (void)memset(_ag, 0, sizeof(struct bt_hfp_ag)); + + sys_slist_init(&_ag->tx_pending); + + k_sem_init(&_ag->lock, 1, 1); + + _ag->rfcomm_dlc.ops = &ops; + _ag->rfcomm_dlc.mtu = BT_HFP_MAX_MTU; + + /* Set the supported features*/ + _ag->ag_features = BT_HFP_AG_SUPPORTED_FEATURES; + + /* If supported codec ids cannot be notified, disable codec negotiation. */ + if (!(bt_ag && bt_ag->codec)) { + _ag->ag_features &= ~BT_HFP_AG_FEATURE_CODEC_NEG; + } + + _ag->hf_features = 0; + _ag->hf_codec_ids = 0; + + _ag->acl_conn = conn; + + /* Set AG indicator value */ + _ag->indicator_value[BT_HFP_AG_SERVICE_IND] = 0; + _ag->indicator_value[BT_HFP_AG_CALL_IND] = 0; + _ag->indicator_value[BT_HFP_AG_CALL_SETUP_IND] = 0; + _ag->indicator_value[BT_HFP_AG_CALL_HELD_IND] = 0; + _ag->indicator_value[BT_HFP_AG_SIGNAL_IND] = 0; + _ag->indicator_value[BT_HFP_AG_ROAM_IND] = 0; + _ag->indicator_value[BT_HFP_AG_BATTERY_IND] = 0; + + /* Set AG indicator status */ + _ag->indicator = BIT(BT_HFP_AG_SERVICE_IND) | BIT(BT_HFP_AG_CALL_IND) | + BIT(BT_HFP_AG_CALL_SETUP_IND) | BIT(BT_HFP_AG_CALL_HELD_IND) | + BIT(BT_HFP_AG_SIGNAL_IND) | BIT(BT_HFP_AG_ROAM_IND) | + BIT(BT_HFP_AG_BATTERY_IND); + + /* Set AG operator */ + memcpy(_ag->operator, "UNKNOWN", sizeof("UNKNOWN")); + + /* Set Codec ID*/ + _ag->selected_codec_id = BT_HFP_AG_CODEC_CVSD; + + /* Init delay work */ + k_work_init_delayable(&_ag->deferred_work, bt_ag_deferred_work); + + k_work_init_delayable(&_ag->ringing_work, bt_ag_ringing_work); + + atomic_set_bit(_ag->flags, BT_HFP_AG_CODEC_CHANGED); + + *ag = _ag; + } + + if (*ag == NULL) { + return -ENOMEM; + } + + err = bt_rfcomm_dlc_connect(conn, &(*ag)->rfcomm_dlc, channel); + if (err != 0) { + (void)memset(*ag, 0, sizeof(struct bt_hfp_ag)); + *ag = NULL; + } else { + bt_hfp_ag_set_state(*ag, BT_HFP_CONNECTING); + } + + return err; +} + +int bt_hfp_ag_disconnect(struct bt_hfp_ag *ag) +{ + int err; + bt_hfp_call_state_t call_state; + + LOG_DBG(""); + + if (ag == NULL) { + return -EINVAL; + } + + hfp_ag_lock(ag); + call_state = ag->call_state; + hfp_ag_unlock(ag); + + bt_hfp_ag_set_state(ag, BT_HFP_DISCONNECTING); + + if ((call_state == BT_HFP_CALL_ACTIVE) || (call_state == BT_HFP_CALL_HOLD)) { + err = hfp_ag_update_indicator(ag, BT_HFP_AG_CALL_IND, 0, bt_hfp_ag_terminate_cb, + NULL); + if (err != 0) { + LOG_ERR("HFP AG send response err :(%d)", err); + } + return err; + } else if (call_state != BT_HFP_CALL_TERMINATE) { + err = hfp_ag_update_indicator(ag, BT_HFP_AG_CALL_SETUP_IND, BT_HFP_CALL_SETUP_NONE, + bt_hfp_ag_reject_cb, NULL); + if (err != 0) { + LOG_ERR("HFP AG send response err :(%d)", err); + } + return err; + } + + return bt_rfcomm_dlc_disconnect(&ag->rfcomm_dlc); +} + +int bt_hfp_ag_register(struct bt_hfp_ag_cb *cb) +{ + if (!cb) { + return -EINVAL; + } + + if (bt_ag) { + return -EALREADY; + } + + bt_ag = cb; + + return 0; +} + +static void bt_hfp_ag_incoming_cb(struct bt_hfp_ag *ag, void *user_data) +{ + bt_hfp_ag_set_call_state(ag, BT_HFP_CALL_INCOMING); + + if (bt_ag && bt_ag->incoming) { + bt_ag->incoming(ag, ag->number); + } + + if (atomic_test_bit(ag->flags, BT_HFP_AG_INBAND_RING)) { + int err; + + err = bt_hfp_ag_create_audio_connection(ag); + if (err) { + bt_hfp_ag_call_reject(ag, NULL); + } + } else { + bt_hfp_ag_set_call_state(ag, BT_HFP_CALL_ALERTING); + bt_hfp_ag_call_ringing_cb(ag, false); + } +} + +int bt_hfp_ag_remote_incoming(struct bt_hfp_ag *ag, const char *number) +{ + int err = 0; + size_t len; + + LOG_DBG(""); + + if (ag == NULL) { + return -EINVAL; + } + + hfp_ag_lock(ag); + if (ag->state != BT_HFP_CONNECTED) { + hfp_ag_unlock(ag); + return -ENOTCONN; + } + + if (ag->call_state != BT_HFP_CALL_TERMINATE) { + hfp_ag_unlock(ag); + return -EBUSY; + } + hfp_ag_unlock(ag); + + len = strlen(number); + if ((len == 0) || (len > CONFIG_BT_HFP_AG_PHONE_NUMBER_MAX_LEN)) { + return -EINVAL; + } + + hfp_ag_lock(ag); + /* Copy number to ag->number including null-character */ + memcpy(ag->number, number, len + 1); + hfp_ag_unlock(ag); + + atomic_set_bit(ag->flags, BT_HFP_AG_INCOMING_CALL); + + err = hfp_ag_update_indicator(ag, BT_HFP_AG_CALL_SETUP_IND, BT_HFP_CALL_SETUP_INCOMING, + bt_hfp_ag_incoming_cb, NULL); + if (err != 0) { + atomic_clear_bit(ag->flags, BT_HFP_AG_INCOMING_CALL); + } + + return err; +} + +int bt_hfp_ag_reject(struct bt_hfp_ag *ag) +{ + int err; + + LOG_DBG(""); + + if (ag == NULL) { + return -EINVAL; + } + + hfp_ag_lock(ag); + if (ag->state != BT_HFP_CONNECTED) { + hfp_ag_unlock(ag); + return -ENOTCONN; + } + + if ((ag->call_state != BT_HFP_CALL_ALERTING) && (ag->call_state != BT_HFP_CALL_INCOMING)) { + hfp_ag_unlock(ag); + return -EINVAL; + } + hfp_ag_unlock(ag); + + if (!atomic_test_bit(ag->flags, BT_HFP_AG_INCOMING_CALL)) { + return -EINVAL; + } + + err = hfp_ag_update_indicator(ag, BT_HFP_AG_CALL_SETUP_IND, BT_HFP_CALL_SETUP_NONE, + bt_hfp_ag_reject_cb, NULL); + + return err; +} + +int bt_hfp_ag_accept(struct bt_hfp_ag *ag) +{ + int err; + + LOG_DBG(""); + + if (ag == NULL) { + return -EINVAL; + } + + hfp_ag_lock(ag); + if (ag->state != BT_HFP_CONNECTED) { + hfp_ag_unlock(ag); + return -ENOTCONN; + } + + if (ag->call_state != BT_HFP_CALL_ALERTING) { + hfp_ag_unlock(ag); + return -EINVAL; + } + hfp_ag_unlock(ag); + + if (!atomic_test_bit(ag->flags, BT_HFP_AG_INCOMING_CALL)) { + return -EINVAL; + } + + err = hfp_ag_update_indicator(ag, BT_HFP_AG_CALL_IND, 1, bt_hfp_ag_accept_cb, NULL); + if (err != 0) { + LOG_ERR("Fail to send err :(%d)", err); + } + + err = hfp_ag_update_indicator(ag, BT_HFP_AG_CALL_SETUP_IND, BT_HFP_CALL_SETUP_NONE, + bt_hfp_ag_audio_connection, NULL); + if (err != 0) { + LOG_ERR("Fail to send err :(%d)", err); + } + + return err; +} + +int bt_hfp_ag_terminate(struct bt_hfp_ag *ag) +{ + int err; + + LOG_DBG(""); + + if (ag == NULL) { + return -EINVAL; + } + + hfp_ag_lock(ag); + if (ag->state != BT_HFP_CONNECTED) { + hfp_ag_unlock(ag); + return -ENOTCONN; + } + + if ((ag->call_state != BT_HFP_CALL_ACTIVE) || (ag->call_state != BT_HFP_CALL_HOLD)) { + hfp_ag_unlock(ag); + return -EINVAL; + } + hfp_ag_unlock(ag); + + err = hfp_ag_update_indicator(ag, BT_HFP_AG_CALL_IND, 0, bt_hfp_ag_terminate_cb, NULL); + + return err; +} + +static void bt_hfp_ag_outgoing_cb(struct bt_hfp_ag *ag, void *user_data) +{ + bt_hfp_ag_set_call_state(ag, BT_HFP_CALL_OUTGOING); + + if (bt_ag && bt_ag->outgoing) { + bt_ag->outgoing(ag, ag->number); + } + + if (atomic_test_bit(ag->flags, BT_HFP_AG_INBAND_RING)) { + int err; + + err = bt_hfp_ag_create_audio_connection(ag); + if (err) { + bt_hfp_ag_call_reject(ag, NULL); + } + } +} + +int bt_hfp_ag_outgoing(struct bt_hfp_ag *ag, const char *number) +{ + int err = 0; + size_t len; + + LOG_DBG(""); + + if (ag == NULL) { + return -EINVAL; + } + + hfp_ag_lock(ag); + if (ag->state != BT_HFP_CONNECTED) { + hfp_ag_unlock(ag); + return -ENOTCONN; + } + + if (ag->call_state != BT_HFP_CALL_TERMINATE) { + hfp_ag_unlock(ag); + return -EBUSY; + } + hfp_ag_unlock(ag); + + len = strlen(number); + if ((len == 0) || (len > CONFIG_BT_HFP_AG_PHONE_NUMBER_MAX_LEN)) { + return -EINVAL; + } + + hfp_ag_lock(ag); + /* Copy number to ag->number including null-character */ + memcpy(ag->number, number, len + 1); + hfp_ag_unlock(ag); + + atomic_clear_bit(ag->flags, BT_HFP_AG_INCOMING_CALL); + + err = hfp_ag_update_indicator(ag, BT_HFP_AG_CALL_SETUP_IND, BT_HFP_CALL_SETUP_OUTGOING, + bt_hfp_ag_outgoing_cb, NULL); + + return err; +} + +static void bt_hfp_ag_ringing_cb(struct bt_hfp_ag *ag, void *user_data) +{ + bt_hfp_ag_set_call_state(ag, BT_HFP_CALL_ALERTING); + + if (atomic_test_bit(ag->flags, BT_HFP_AG_INBAND_RING)) { + bt_hfp_ag_call_ringing_cb(ag, true); + } else { + bt_hfp_ag_call_ringing_cb(ag, false); + } +} + +int bt_hfp_ag_remote_ringing(struct bt_hfp_ag *ag) +{ + int err = 0; + + LOG_DBG(""); + + if (ag == NULL) { + return -EINVAL; + } + + hfp_ag_lock(ag); + if (ag->state != BT_HFP_CONNECTED) { + hfp_ag_unlock(ag); + return -ENOTCONN; + } + + if (ag->call_state != BT_HFP_CALL_OUTGOING) { + hfp_ag_unlock(ag); + return -EBUSY; + } + + if (atomic_test_bit(ag->flags, BT_HFP_AG_INBAND_RING)) { + if (ag->sco_chan.sco == NULL) { + hfp_ag_unlock(ag); + return -ENOTCONN; + } + } + hfp_ag_unlock(ag); + + err = hfp_ag_update_indicator(ag, BT_HFP_AG_CALL_SETUP_IND, + BT_HFP_CALL_SETUP_REMOTE_ALERTING, bt_hfp_ag_ringing_cb, + NULL); + + return err; +} + +int bt_hfp_ag_remote_reject(struct bt_hfp_ag *ag) +{ + int err; + + LOG_DBG(""); + + if (ag == NULL) { + return -EINVAL; + } + + hfp_ag_lock(ag); + if (ag->state != BT_HFP_CONNECTED) { + hfp_ag_unlock(ag); + return -ENOTCONN; + } + + if ((ag->call_state != BT_HFP_CALL_ALERTING) && (ag->call_state != BT_HFP_CALL_OUTGOING)) { + hfp_ag_unlock(ag); + return -EINVAL; + } + hfp_ag_unlock(ag); + + if (atomic_test_bit(ag->flags, BT_HFP_AG_INCOMING_CALL)) { + return -EINVAL; + } + + err = hfp_ag_update_indicator(ag, BT_HFP_AG_CALL_SETUP_IND, BT_HFP_CALL_SETUP_NONE, + bt_hfp_ag_reject_cb, NULL); + + return err; +} + +int bt_hfp_ag_remote_accept(struct bt_hfp_ag *ag) +{ + int err; + + LOG_DBG(""); + + if (ag == NULL) { + return -EINVAL; + } + + hfp_ag_lock(ag); + if (ag->state != BT_HFP_CONNECTED) { + hfp_ag_unlock(ag); + return -ENOTCONN; + } + + if (ag->call_state != BT_HFP_CALL_ALERTING) { + hfp_ag_unlock(ag); + return -EINVAL; + } + hfp_ag_unlock(ag); + + if (atomic_test_bit(ag->flags, BT_HFP_AG_INCOMING_CALL)) { + return -EINVAL; + } + + err = hfp_ag_update_indicator(ag, BT_HFP_AG_CALL_IND, 1, bt_hfp_ag_accept_cb, NULL); + if (err != 0) { + LOG_ERR("Fail to send err :(%d)", err); + } + + err = hfp_ag_update_indicator(ag, BT_HFP_AG_CALL_SETUP_IND, BT_HFP_CALL_SETUP_NONE, + bt_hfp_ag_audio_connection, NULL); + if (err != 0) { + LOG_ERR("Fail to send err :(%d)", err); + } + + return err; +} + +int bt_hfp_ag_remote_terminate(struct bt_hfp_ag *ag) +{ + int err; + + LOG_DBG(""); + + if (ag == NULL) { + return -EINVAL; + } + + hfp_ag_lock(ag); + if (ag->state != BT_HFP_CONNECTED) { + hfp_ag_unlock(ag); + return -ENOTCONN; + } + + if ((ag->call_state != BT_HFP_CALL_ACTIVE) || (ag->call_state != BT_HFP_CALL_HOLD)) { + hfp_ag_unlock(ag); + return -EINVAL; + } + hfp_ag_unlock(ag); + + err = hfp_ag_update_indicator(ag, BT_HFP_AG_CALL_IND, 0, bt_hfp_ag_terminate_cb, NULL); + + return err; +} + +int bt_hfp_ag_set_indicator(struct bt_hfp_ag *ag, enum bt_hfp_ag_indicator index, uint8_t value) +{ + int err; + + LOG_DBG(""); + + if (ag == NULL) { + return -EINVAL; + } + + hfp_ag_lock(ag); + if (ag->state != BT_HFP_CONNECTED) { + hfp_ag_unlock(ag); + return -ENOTCONN; + } + hfp_ag_unlock(ag); + + switch (index) { + case BT_HFP_AG_SERVICE_IND: + __fallthrough; + case BT_HFP_AG_SIGNAL_IND: + __fallthrough; + case BT_HFP_AG_ROAM_IND: + __fallthrough; + case BT_HFP_AG_BATTERY_IND: + if ((ag_ind[(uint8_t)index].min > value) || (ag_ind[(uint8_t)index].max < value)) { + return -EINVAL; + } + break; + case BT_HFP_AG_CALL_IND: + __fallthrough; + case BT_HFP_AG_CALL_SETUP_IND: + __fallthrough; + case BT_HFP_AG_CALL_HELD_IND: + __fallthrough; + default: + return -EINVAL; + } + + err = hfp_ag_update_indicator(ag, index, value, NULL, NULL); + + return err; +} + +int bt_hfp_ag_set_operator(struct bt_hfp_ag *ag, char *name) +{ + int len; + + LOG_DBG(""); + + if (ag == NULL) { + return -EINVAL; + } + + hfp_ag_lock(ag); + if (ag->state != BT_HFP_CONNECTED) { + hfp_ag_unlock(ag); + return -ENOTCONN; + } + + len = strlen(name); + len = MIN(sizeof(ag->operator) - 1, len); + memcpy(ag->operator, name, len); + ag->operator[len] = '\0'; + hfp_ag_unlock(ag); + + return 0; +} + +int bt_hfp_ag_select_codec(struct bt_hfp_ag *ag, uint8_t id) +{ + int err; + + LOG_DBG(""); + + if (ag == NULL) { + return -EINVAL; + } + + hfp_ag_lock(ag); + if (ag->state != BT_HFP_CONNECTED) { + hfp_ag_unlock(ag); + return -ENOTCONN; + } + + if (!(ag->hf_codec_ids && BIT(id))) { + hfp_ag_unlock(ag); + return -ENOTSUP; + } + hfp_ag_unlock(ag); + + if (atomic_test_bit(ag->flags, BT_HFP_AG_CODEC_CONN)) { + return -EBUSY; + } + + hfp_ag_lock(ag); + ag->selected_codec_id = id; + hfp_ag_unlock(ag); + + atomic_set_bit(ag->flags, BT_HFP_AG_CODEC_CHANGED); + + err = bt_hfp_ag_create_audio_connection(ag); + + return err; +} diff --git a/subsys/bluetooth/host/classic/hfp_ag_internal.h b/subsys/bluetooth/host/classic/hfp_ag_internal.h new file mode 100644 index 00000000000..82b3aa88131 --- /dev/null +++ b/subsys/bluetooth/host/classic/hfp_ag_internal.h @@ -0,0 +1,135 @@ +/** @file + * @brief Internal APIs for Bluetooth Handsfree profile handling. + */ + +/* + * Copyright (c) 2015-2016 Intel Corporation + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* HFP AG Supported features */ +#define BT_HFP_AG_SUPPORTED_FEATURES (BT_HFP_AG_FEATURE_INBAND_RINGTONE | BT_HFP_AG_FEATURE_EXT_ERR) + +/* bt_hfp_ag flags: the flags defined here represent HFP AG parameters */ +enum { + BT_HFP_AG_CMEE_ENABLE, /* Extended Audio Gateway Error Result Code */ + BT_HFP_AG_CMER_ENABLE, /* Indicator Events Reporting */ + BT_HFP_AG_CLIP_ENABLE, /* Calling Line Identification notification */ + BT_HFP_AG_INBAND_RING, /* In-band ring */ + BT_HFP_AG_COPS_SET, /* Query Operator selection */ + BT_HFP_AG_INCOMING_CALL, /* Incoming call */ + BT_HFP_AG_CODEC_CONN, /* Codec connection is ongoing */ + BT_HFP_AG_CODEC_CHANGED, /* Codec Id Changed */ + + /* Total number of flags - must be at the end of the enum */ + BT_HFP_AG_NUM_FLAGS, +}; + +/* HFP HF Indicators */ +enum { + HFP_HF_ENHANCED_SAFETY_IND = 1, /* Enhanced Safety */ + HFP_HF_BATTERY_LEVEL_IND = 2, /* Remaining level of Battery */ + HFP_HF_IND_MAX +}; + +typedef enum __packed { + /** Session disconnected */ + BT_HFP_DISCONNECTED, + /** Session in connecting state */ + BT_HFP_CONNECTING, + /** Session in config state, HFP configuration */ + BT_HFP_CONFIG, + /** Session ready for upper layer traffic on it */ + BT_HFP_CONNECTED, + /** Session in disconnecting state */ + BT_HFP_DISCONNECTING, +} bt_hfp_state_t; + +typedef enum __packed { + /** Call terminate */ + BT_HFP_CALL_TERMINATE, + /** Call outgoing */ + BT_HFP_CALL_OUTGOING, + /** Call incoming */ + BT_HFP_CALL_INCOMING, + /** Call alerting */ + BT_HFP_CALL_ALERTING, + /** Call active */ + BT_HFP_CALL_ACTIVE, + /** Call hold */ + BT_HFP_CALL_HOLD, +} bt_hfp_call_state_t; + +#define AT_COPS_OPERATOR_MAX_LEN 16 + +struct bt_hfp_ag { + struct bt_rfcomm_dlc rfcomm_dlc; + char buffer[HF_MAX_BUF_LEN]; + uint32_t hf_features; + uint32_t ag_features; + + /* HF Supported Codec Ids*/ + uint32_t hf_codec_ids; + uint8_t selected_codec_id; + + ATOMIC_DEFINE(flags, BT_HFP_AG_NUM_FLAGS); + + /* ACL Connection Object */ + struct bt_conn *acl_conn; + + /* HFP Connection state */ + bt_hfp_state_t state; + + /* HFP Call state */ + bt_hfp_call_state_t call_state; + + /* Delayed work deferred tasks: + * - call status cleanup. + */ + struct k_work_delayable deferred_work; + + /* AG Indicators */ + uint8_t indicator_value[BT_HFP_AG_IND_MAX]; + uint32_t indicator; + + /* HF Indicators */ + uint32_t hf_indicators_of_ag; + uint32_t hf_indicators_of_hf; + uint8_t hf_indicator_value[HFP_HF_IND_MAX]; + + /* operator */ + char operator[AT_COPS_OPERATOR_MAX_LEN + 1]; + + /* SCO Connection Object */ + struct bt_sco_chan sco_chan; + /* HFP TX pending */ + sys_slist_t tx_pending; + + /* Dial number or incoming number */ + char number[CONFIG_BT_HFP_AG_PHONE_NUMBER_MAX_LEN + 1]; + + /* Calling Line Identification notification */ + struct k_work_delayable ringing_work; + + /* Critical locker */ + struct k_sem lock; +}; + +/* Active */ +#define HFP_AG_CLCC_STATUS_ACTIVE 0 +/* Held */ +#define HFP_AG_CLCC_STATUS_HELD 1 +/* Dialing (outgoing calls only) */ +#define HFP_AG_CLCC_STATUS_DIALING 2 +/* Alerting (outgoing calls only) */ +#define HFP_AG_CLCC_STATUS_ALERTING 3 +/* Incoming (incoming calls only) */ +#define HFP_AG_CLCC_STATUS_INCOMING 4 +/* Waiting (incoming calls only) */ +#define HFP_AG_CLCC_STATUS_WAITING 5 +/* Call held by Response and Hold */ +#define HFP_AG_CLCC_STATUS_CALL_HELD_HOLD 6 +/* Invalid status */ +#define HFP_AG_CLCC_STATUS_INVALID 0xFFU diff --git a/subsys/bluetooth/host/classic/hfp_hf.c b/subsys/bluetooth/host/classic/hfp_hf.c index 63872f8af47..7262311008d 100644 --- a/subsys/bluetooth/host/classic/hfp_hf.c +++ b/subsys/bluetooth/host/classic/hfp_hf.c @@ -18,6 +18,7 @@ #include #include +#include #include "host/hci_core.h" #include "host/conn_internal.h" @@ -56,6 +57,73 @@ static const struct { {"battchg", 0, 5} /* HF_BATTERY_IND */ }; +/* HFP Hands-Free SDP record */ +static struct bt_sdp_attribute hfp_attrs[] = { + BT_SDP_NEW_SERVICE, + BT_SDP_LIST( + BT_SDP_ATTR_SVCLASS_ID_LIST, + BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 6), + BT_SDP_DATA_ELEM_LIST( + { + BT_SDP_TYPE_SIZE(BT_SDP_UUID16), + BT_SDP_ARRAY_16(BT_SDP_HANDSFREE_SVCLASS) + }, + { + BT_SDP_TYPE_SIZE(BT_SDP_UUID16), + BT_SDP_ARRAY_16(BT_SDP_GENERIC_AUDIO_SVCLASS) + } + ) + ), + BT_SDP_LIST( + BT_SDP_ATTR_PROTO_DESC_LIST, + BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 12), + BT_SDP_DATA_ELEM_LIST( + { + BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 3), + BT_SDP_DATA_ELEM_LIST( + { + BT_SDP_TYPE_SIZE(BT_SDP_UUID16), + BT_SDP_ARRAY_16(BT_SDP_PROTO_L2CAP) + }, + ) + }, + { + BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 5), + BT_SDP_DATA_ELEM_LIST( + { + BT_SDP_TYPE_SIZE(BT_SDP_UUID16), + BT_SDP_ARRAY_16(BT_SDP_PROTO_RFCOMM) + }, + { + BT_SDP_TYPE_SIZE(BT_SDP_UINT8), + BT_SDP_ARRAY_8(BT_RFCOMM_CHAN_HFP_HF) + }, + ) + }, + ) + ), + BT_SDP_LIST( + BT_SDP_ATTR_PROFILE_DESC_LIST, + BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 6), + BT_SDP_DATA_ELEM_LIST( + { + BT_SDP_TYPE_SIZE(BT_SDP_UUID16), + BT_SDP_ARRAY_16(BT_SDP_HANDSFREE_SVCLASS) + }, + { + BT_SDP_TYPE_SIZE(BT_SDP_UINT16), + BT_SDP_ARRAY_16(0x0109) + }, + ) + ), + /* The values of the ā€œSupportedFeaturesā€ bitmap shall be the same as the + * values of the Bits 0 to 4 of the AT-command AT+BRSF (see Section 5.3). + */ + BT_SDP_SUPPORTED_FEATURES(BT_HFP_HF_SUPPORTED_FEATURES & 0x1f), +}; + +static struct bt_sdp_record hfp_rec = BT_SDP_RECORD(hfp_attrs); + void hf_slc_error(struct at_client *hf_at) { struct bt_hfp_hf *hf = CONTAINER_OF(hf_at, struct bt_hfp_hf, at); @@ -755,6 +823,8 @@ static void hfp_hf_init(void) }; bt_sco_server_register(&sco_server); + + bt_sdp_register_service(&hfp_rec); } int bt_hfp_hf_register(struct bt_hfp_hf_cb *cb) diff --git a/subsys/bluetooth/host/classic/hfp_internal.h b/subsys/bluetooth/host/classic/hfp_internal.h index 50c883fedec..11680718704 100644 --- a/subsys/bluetooth/host/classic/hfp_internal.h +++ b/subsys/bluetooth/host/classic/hfp_internal.h @@ -8,41 +8,44 @@ * SPDX-License-Identifier: Apache-2.0 */ -#define BT_HFP_MAX_MTU 140 -#define BT_HF_CLIENT_MAX_PDU BT_HFP_MAX_MTU +#define BT_HFP_MAX_MTU 140 +#define BT_HF_CLIENT_MAX_PDU BT_HFP_MAX_MTU /* HFP AG Features */ -#define BT_HFP_AG_FEATURE_3WAY_CALL 0x00000001 /* Three-way calling */ -#define BT_HFP_AG_FEATURE_ECNR 0x00000002 /* EC and/or NR function */ -#define BT_HFP_AG_FEATURE_VOICE_RECG 0x00000004 /* Voice recognition */ -#define BT_HFP_AG_INBAND_RING_TONE 0x00000008 /* In-band ring capability */ -#define BT_HFP_AG_VOICE_TAG 0x00000010 /* Attach no. to voice tag */ -#define BT_HFP_AG_FEATURE_REJECT_CALL 0x00000020 /* Ability to reject call */ -#define BT_HFP_AG_FEATURE_ECS 0x00000040 /* Enhanced call status */ -#define BT_HFP_AG_FEATURE_ECC 0x00000080 /* Enhanced call control */ -#define BT_HFP_AG_FEATURE_EXT_ERR 0x00000100 /* Extended error codes */ -#define BT_HFP_AG_FEATURE_CODEC_NEG 0x00000200 /* Codec negotiation */ -#define BT_HFP_AG_FEATURE_HF_IND 0x00000400 /* HF Indicators */ -#define BT_HFP_AG_FEARTURE_ESCO_S4 0x00000800 /* eSCO S4 Settings */ +#define BT_HFP_AG_FEATURE_3WAY_CALL 0x00000001 /* Three-way calling */ +#define BT_HFP_AG_FEATURE_ECNR 0x00000002 /* EC and/or NR function */ +#define BT_HFP_AG_FEATURE_VOICE_RECG 0x00000004 /* Voice recognition */ +#define BT_HFP_AG_FEATURE_INBAND_RINGTONE 0x00000008 /* In-band ring capability */ +#define BT_HFP_AG_FEATURE_VOICE_TAG 0x00000010 /* Attach no. to voice tag */ +#define BT_HFP_AG_FEATURE_REJECT_CALL 0x00000020 /* Ability to reject call */ +#define BT_HFP_AG_FEATURE_ECS 0x00000040 /* Enhanced call status */ +#define BT_HFP_AG_FEATURE_ECC 0x00000080 /* Enhanced call control */ +#define BT_HFP_AG_FEATURE_EXT_ERR 0x00000100 /* Extended error codes */ +#define BT_HFP_AG_FEATURE_CODEC_NEG 0x00000200 /* Codec negotiation */ +#define BT_HFP_AG_FEATURE_HF_IND 0x00000400 /* HF Indicators */ +#define BT_HFP_AG_FEATURE_ESCO_S4 0x00000800 /* eSCO S4 Settings */ +#define BT_HFP_AG_FEATURE_ENH_VOICE_RECG 0x00001000 /* Enhanced Voice Recognition Status */ +#define BT_HFP_AG_FEATURE_VOICE_RECG_TEXT 0x00002000 /* Voice Recognition Text */ /* HFP HF Features */ -#define BT_HFP_HF_FEATURE_ECNR 0x00000001 /* EC and/or NR */ -#define BT_HFP_HF_FEATURE_3WAY_CALL 0x00000002 /* Three-way calling */ -#define BT_HFP_HF_FEATURE_CLI 0x00000004 /* CLI presentation */ -#define BT_HFP_HF_FEATURE_VOICE_RECG 0x00000008 /* Voice recognition */ -#define BT_HFP_HF_FEATURE_VOLUME 0x00000010 /* Remote volume control */ -#define BT_HFP_HF_FEATURE_ECS 0x00000020 /* Enhanced call status */ -#define BT_HFP_HF_FEATURE_ECC 0x00000040 /* Enhanced call control */ -#define BT_HFP_HF_FEATURE_CODEC_NEG 0x00000080 /* CODEC Negotiation */ -#define BT_HFP_HF_FEATURE_HF_IND 0x00000100 /* HF Indicators */ -#define BT_HFP_HF_FEATURE_ESCO_S4 0x00000200 /* eSCO S4 Settings */ +#define BT_HFP_HF_FEATURE_ECNR 0x00000001 /* EC and/or NR function */ +#define BT_HFP_HF_FEATURE_3WAY_CALL 0x00000002 /* Three-way calling */ +#define BT_HFP_HF_FEATURE_CLI 0x00000004 /* CLI presentation */ +#define BT_HFP_HF_FEATURE_VOICE_RECG 0x00000008 /* Voice recognition */ +#define BT_HFP_HF_FEATURE_VOLUME 0x00000010 /* Remote volume control */ +#define BT_HFP_HF_FEATURE_ECS 0x00000020 /* Enhanced call status */ +#define BT_HFP_HF_FEATURE_ECC 0x00000040 /* Enhanced call control */ +#define BT_HFP_HF_FEATURE_CODEC_NEG 0x00000080 /* CODEC Negotiation */ +#define BT_HFP_HF_FEATURE_HF_IND 0x00000100 /* HF Indicators */ +#define BT_HFP_HF_FEATURE_ESCO_S4 0x00000200 /* eSCO S4 Settings */ +#define BT_HFP_HF_FEATURE_ENH_VOICE_RECG 0x00000400 /* Enhanced Voice Recognition Status */ +#define BT_HFP_HF_FEATURE_VOICE_RECG_TEXT 0x00000800 /* Voice Recognition Text */ /* HFP HF Supported features */ -#define BT_HFP_HF_SUPPORTED_FEATURES (BT_HFP_HF_FEATURE_CLI | \ - BT_HFP_HF_FEATURE_VOLUME) +#define BT_HFP_HF_SUPPORTED_FEATURES (BT_HFP_HF_FEATURE_CLI | BT_HFP_HF_FEATURE_VOLUME) -#define HF_MAX_BUF_LEN BT_HF_CLIENT_MAX_PDU -#define HF_MAX_AG_INDICATORS 20 +#define HF_MAX_BUF_LEN BT_HF_CLIENT_MAX_PDU +#define HF_MAX_AG_INDICATORS 20 struct bt_hfp_hf { struct bt_rfcomm_dlc rfcomm_dlc; @@ -66,3 +69,9 @@ enum hfp_hf_ag_indicators { HF_ROAM_IND, HF_BATTERY_IND }; + +/* HFP call setup status */ +#define BT_HFP_CALL_SETUP_NONE 0 +#define BT_HFP_CALL_SETUP_INCOMING 1 +#define BT_HFP_CALL_SETUP_OUTGOING 2 +#define BT_HFP_CALL_SETUP_REMOTE_ALERTING 3 diff --git a/subsys/bluetooth/host/classic/l2cap_br.c b/subsys/bluetooth/host/classic/l2cap_br.c index f4f45db481f..2174aa1ceb1 100644 --- a/subsys/bluetooth/host/classic/l2cap_br.c +++ b/subsys/bluetooth/host/classic/l2cap_br.c @@ -238,8 +238,8 @@ static uint8_t l2cap_br_get_ident(void) return ident; } -static int l2cap_br_send_cb(struct bt_conn *conn, uint16_t cid, struct net_buf *buf, - bt_conn_tx_cb_t cb, void *user_data) +int bt_l2cap_br_send_cb(struct bt_conn *conn, uint16_t cid, struct net_buf *buf, + bt_conn_tx_cb_t cb, void *user_data) { struct bt_l2cap_hdr *hdr; @@ -259,7 +259,7 @@ static int l2cap_br_send_cb(struct bt_conn *conn, uint16_t cid, struct net_buf * static inline void l2cap_send(struct bt_conn *conn, uint16_t cid, struct net_buf *buf) { - if (l2cap_br_send_cb(conn, cid, buf, NULL, NULL)) { + if (bt_l2cap_br_send_cb(conn, cid, buf, NULL, NULL)) { net_buf_unref(buf); } } @@ -268,7 +268,7 @@ static void l2cap_br_chan_send_req(struct bt_l2cap_br_chan *chan, struct net_buf *buf, k_timeout_t timeout) { - if (l2cap_br_send_cb(chan->chan.conn, BT_L2CAP_CID_BR_SIG, buf, + if (bt_l2cap_br_send_cb(chan->chan.conn, BT_L2CAP_CID_BR_SIG, buf, NULL, NULL)) { net_buf_unref(buf); return; @@ -1491,7 +1491,7 @@ int bt_l2cap_br_chan_send_cb(struct bt_l2cap_chan *chan, struct net_buf *buf, bt return -EMSGSIZE; } - return l2cap_br_send_cb(br_chan->chan.conn, br_chan->tx.cid, buf, cb, user_data); + return bt_l2cap_br_send_cb(br_chan->chan.conn, br_chan->tx.cid, buf, cb, user_data); } int bt_l2cap_br_chan_send(struct bt_l2cap_chan *chan, struct net_buf *buf) diff --git a/subsys/bluetooth/host/classic/l2cap_br_interface.h b/subsys/bluetooth/host/classic/l2cap_br_interface.h index 60393490938..b7978dc9bfb 100644 --- a/subsys/bluetooth/host/classic/l2cap_br_interface.h +++ b/subsys/bluetooth/host/classic/l2cap_br_interface.h @@ -32,6 +32,12 @@ int bt_l2cap_br_chan_send(struct bt_l2cap_chan *chan, struct net_buf *buf); int bt_l2cap_br_chan_send_cb(struct bt_l2cap_chan *chan, struct net_buf *buf, bt_conn_tx_cb_t cb, void *user_data); +/* Send a single PDU over a BR channel. + * Used by e.g. SMP. + */ +int bt_l2cap_br_send_cb(struct bt_conn *conn, uint16_t cid, struct net_buf *buf, + bt_conn_tx_cb_t cb, void *user_data); + /* * Handle security level changed on link passing HCI status of performed * security procedure. diff --git a/subsys/bluetooth/host/classic/sco.c b/subsys/bluetooth/host/classic/sco.c index 95054184455..51433c9090b 100644 --- a/subsys/bluetooth/host/classic/sco.c +++ b/subsys/bluetooth/host/classic/sco.c @@ -312,7 +312,7 @@ uint8_t bt_esco_conn_req(struct bt_hci_evt_conn_request *evt) } sco_conn->role = BT_HCI_ROLE_PERIPHERAL; - bt_conn_set_state(sco_conn, BT_CONN_CONNECTING); + bt_conn_set_state(sco_conn, BT_CONN_INITIATING); bt_conn_unref(sco_conn); return BT_HCI_ERR_SUCCESS; @@ -368,7 +368,7 @@ struct bt_conn *bt_conn_create_sco(const bt_addr_t *peer, struct bt_sco_chan *ch sco_conn = bt_conn_lookup_addr_sco(peer); if (sco_conn) { switch (sco_conn->state) { - case BT_CONN_CONNECTING: + case BT_CONN_INITIATING: case BT_CONN_CONNECTED: return sco_conn; default: @@ -391,7 +391,7 @@ struct bt_conn *bt_conn_create_sco(const bt_addr_t *peer, struct bt_sco_chan *ch sco_conn->sco.link_type = link_type; bt_sco_chan_add(sco_conn, chan); - bt_conn_set_state(chan->sco, BT_CONN_CONNECTING); + bt_conn_set_state(chan->sco, BT_CONN_INITIATING); bt_sco_chan_set_state(chan, BT_SCO_STATE_CONNECTING); if (sco_setup_sync_conn(sco_conn) < 0) { diff --git a/subsys/bluetooth/host/conn.c b/subsys/bluetooth/host/conn.c index c0235506af5..244658e6c74 100644 --- a/subsys/bluetooth/host/conn.c +++ b/subsys/bluetooth/host/conn.c @@ -183,16 +183,16 @@ static inline const char *state2str(bt_conn_state_t state) return "disconnected"; case BT_CONN_DISCONNECT_COMPLETE: return "disconnect-complete"; - case BT_CONN_CONNECTING_SCAN: - return "connecting-scan"; - case BT_CONN_CONNECTING_DIR_ADV: - return "connecting-dir-adv"; - case BT_CONN_CONNECTING_ADV: - return "connecting-adv"; - case BT_CONN_CONNECTING_AUTO: - return "connecting-auto"; - case BT_CONN_CONNECTING: - return "connecting"; + case BT_CONN_INITIATING: + return "initiating"; + case BT_CONN_SCAN_BEFORE_INITIATING: + return "scan-before-initiating"; + case BT_CONN_INITIATING_FILTER_LIST: + return "initiating-filter-list"; + case BT_CONN_ADV_CONNECTABLE: + return "adv-connectable"; + case BT_CONN_ADV_DIR_CONNECTABLE: + return "adv-dir-connectable"; case BT_CONN_CONNECTED: return "connected"; case BT_CONN_DISCONNECTING: @@ -383,20 +383,19 @@ static void wait_for_tx_work(struct bt_conn *conn) #if defined(CONFIG_BT_CONN_TX) LOG_DBG("conn %p", conn); - if (IS_ENABLED(CONFIG_BT_RECV_WORKQ_SYS)) { + if (IS_ENABLED(CONFIG_BT_RECV_WORKQ_SYS) || + k_current_get() == k_work_queue_thread_get(&k_sys_work_q)) { tx_notify(conn); } else { struct k_work_sync sync; + int err; - /* API docs mention undefined behavior if syncing on work item - * from wq execution context. - */ - __ASSERT_NO_MSG(k_current_get() != - k_work_queue_thread_get(&k_sys_work_q)); + err = k_work_submit(&conn->tx_complete_work); + __ASSERT(err >= 0, "couldn't submit (err %d)", err); - k_work_submit(&conn->tx_complete_work); k_work_flush(&conn->tx_complete_work, &sync); } + LOG_DBG("done"); #else ARG_UNUSED(conn); #endif /* CONFIG_BT_CONN_TX */ @@ -479,6 +478,16 @@ int bt_conn_send_cb(struct bt_conn *conn, struct net_buf *buf, LOG_DBG("conn handle %u buf len %u cb %p user_data %p", conn->handle, buf->len, cb, user_data); + if (buf->ref != 1) { + /* The host may alter the buf contents when fragmenting. Higher + * layers cannot expect the buf contents to stay intact. Extra + * refs suggests a silent data corruption would occur if not for + * this error. + */ + LOG_ERR("buf given to conn has other refs"); + return -EINVAL; + } + if (buf->user_data_size < CONFIG_BT_CONN_TX_USER_DATA_SIZE) { LOG_ERR("not enough room in user_data %d < %d pool %u", buf->user_data_size, @@ -853,7 +862,9 @@ static void conn_destroy(struct bt_conn *conn, void *data) bt_conn_set_state(conn, BT_CONN_DISCONNECT_COMPLETE); } - bt_conn_set_state(conn, BT_CONN_DISCONNECTED); + if (conn->state != BT_CONN_DISCONNECTED) { + bt_conn_set_state(conn, BT_CONN_DISCONNECTED); + } } void bt_conn_cleanup_all(void) @@ -1091,7 +1102,7 @@ void bt_conn_set_state(struct bt_conn *conn, bt_conn_state_t state) bt_conn_ref(conn); } break; - case BT_CONN_CONNECTING: + case BT_CONN_INITIATING: if (IS_ENABLED(CONFIG_BT_CENTRAL) && conn->type == BT_CONN_TYPE_LE) { k_work_cancel_delayable(&conn->deferred_work); @@ -1167,7 +1178,7 @@ void bt_conn_set_state(struct bt_conn *conn, bt_conn_state_t state) k_poll_signal_raise(&conn_change, 0); /* The last ref will be dropped during cleanup */ break; - case BT_CONN_CONNECTING: + case BT_CONN_INITIATING: /* LE Create Connection command failed. This might be * directly from the API, don't notify application in * this case. @@ -1178,8 +1189,8 @@ void bt_conn_set_state(struct bt_conn *conn, bt_conn_state_t state) bt_conn_unref(conn); break; - case BT_CONN_CONNECTING_SCAN: - /* this indicate LE Create Connection with peer address + case BT_CONN_SCAN_BEFORE_INITIATING: + /* This indicates that connection establishment * has been stopped. This could either be triggered by * the application through bt_conn_disconnect or by * timeout set by bt_conn_le_create_param.timeout. @@ -1190,7 +1201,7 @@ void bt_conn_set_state(struct bt_conn *conn, bt_conn_state_t state) bt_conn_unref(conn); break; - case BT_CONN_CONNECTING_DIR_ADV: + case BT_CONN_ADV_DIR_CONNECTABLE: /* this indicate Directed advertising stopped */ if (conn->err) { notify_connected(conn); @@ -1198,14 +1209,14 @@ void bt_conn_set_state(struct bt_conn *conn, bt_conn_state_t state) bt_conn_unref(conn); break; - case BT_CONN_CONNECTING_AUTO: + case BT_CONN_INITIATING_FILTER_LIST: /* this indicates LE Create Connection with filter * policy has been stopped. This can only be triggered * by the application, so don't notify. */ bt_conn_unref(conn); break; - case BT_CONN_CONNECTING_ADV: + case BT_CONN_ADV_CONNECTABLE: /* This can only happen when application stops the * advertiser, conn->err is never set in this case. */ @@ -1219,15 +1230,15 @@ void bt_conn_set_state(struct bt_conn *conn, bt_conn_state_t state) break; } break; - case BT_CONN_CONNECTING_AUTO: + case BT_CONN_INITIATING_FILTER_LIST: break; - case BT_CONN_CONNECTING_ADV: + case BT_CONN_ADV_CONNECTABLE: break; - case BT_CONN_CONNECTING_SCAN: + case BT_CONN_SCAN_BEFORE_INITIATING: break; - case BT_CONN_CONNECTING_DIR_ADV: + case BT_CONN_ADV_DIR_CONNECTABLE: break; - case BT_CONN_CONNECTING: + case BT_CONN_INITIATING: if (conn->type == BT_CONN_TYPE_SCO) { break; } @@ -1471,6 +1482,12 @@ struct net_buf *bt_conn_create_pdu_timeout(struct net_buf_pool *pool, */ __ASSERT_NO_MSG(!k_is_in_isr()); + if (!K_TIMEOUT_EQ(timeout, K_NO_WAIT) && + k_current_get() == k_work_queue_thread_get(&k_sys_work_q)) { + LOG_DBG("Timeout discarded. No blocking in syswq."); + timeout = K_NO_WAIT; + } + if (!pool) { #if defined(CONFIG_BT_CONN) pool = &acl_tx_pool; @@ -1581,14 +1598,14 @@ int bt_conn_disconnect(struct bt_conn *conn, uint8_t reason) #endif /* !defined(CONFIG_BT_FILTER_ACCEPT_LIST) */ switch (conn->state) { - case BT_CONN_CONNECTING_SCAN: + case BT_CONN_SCAN_BEFORE_INITIATING: conn->err = reason; bt_conn_set_state(conn, BT_CONN_DISCONNECTED); if (IS_ENABLED(CONFIG_BT_CENTRAL)) { bt_le_scan_update(false); } return 0; - case BT_CONN_CONNECTING: + case BT_CONN_INITIATING: if (conn->type == BT_CONN_TYPE_LE) { if (IS_ENABLED(CONFIG_BT_CENTRAL)) { k_work_cancel_delayable(&conn->deferred_work); @@ -2023,7 +2040,7 @@ struct bt_conn *bt_conn_create_br(const bt_addr_t *peer, conn = bt_conn_lookup_addr_br(peer); if (conn) { switch (conn->state) { - case BT_CONN_CONNECTING: + case BT_CONN_INITIATING: case BT_CONN_CONNECTED: return conn; default: @@ -2058,7 +2075,7 @@ struct bt_conn *bt_conn_create_br(const bt_addr_t *peer, return NULL; } - bt_conn_set_state(conn, BT_CONN_CONNECTING); + bt_conn_set_state(conn, BT_CONN_INITIATING); conn->role = BT_CONN_ROLE_CENTRAL; return conn; @@ -2596,11 +2613,11 @@ static enum bt_conn_state conn_internal_to_public_state(bt_conn_state_t state) case BT_CONN_DISCONNECTED: case BT_CONN_DISCONNECT_COMPLETE: return BT_CONN_STATE_DISCONNECTED; - case BT_CONN_CONNECTING_SCAN: - case BT_CONN_CONNECTING_AUTO: - case BT_CONN_CONNECTING_ADV: - case BT_CONN_CONNECTING_DIR_ADV: - case BT_CONN_CONNECTING: + case BT_CONN_SCAN_BEFORE_INITIATING: + case BT_CONN_INITIATING_FILTER_LIST: + case BT_CONN_ADV_CONNECTABLE: + case BT_CONN_ADV_DIR_CONNECTABLE: + case BT_CONN_INITIATING: return BT_CONN_STATE_CONNECTING; case BT_CONN_CONNECTED: return BT_CONN_STATE_CONNECTED; @@ -3008,7 +3025,7 @@ int bt_conn_le_create_auto(const struct bt_conn_le_create_param *create_param, } conn = bt_conn_lookup_state_le(BT_ID_DEFAULT, BT_ADDR_LE_NONE, - BT_CONN_CONNECTING_AUTO); + BT_CONN_INITIATING_FILTER_LIST); if (conn) { bt_conn_unref(conn); return -EALREADY; @@ -3038,7 +3055,7 @@ int bt_conn_le_create_auto(const struct bt_conn_le_create_param *create_param, create_param_setup(create_param); atomic_set_bit(conn->flags, BT_CONN_AUTO_CONNECT); - bt_conn_set_state(conn, BT_CONN_CONNECTING_AUTO); + bt_conn_set_state(conn, BT_CONN_INITIATING_FILTER_LIST); err = bt_le_create_conn(conn); if (err) { @@ -3066,7 +3083,7 @@ int bt_conn_create_auto_stop(void) } conn = bt_conn_lookup_state_le(BT_ID_DEFAULT, BT_ADDR_LE_NONE, - BT_CONN_CONNECTING_AUTO); + BT_CONN_INITIATING_FILTER_LIST); if (!conn) { return -EINVAL; } @@ -3167,7 +3184,7 @@ int bt_conn_le_create(const bt_addr_le_t *peer, const struct bt_conn_le_create_p #if defined(CONFIG_BT_SMP) if (bt_dev.le.rl_entries > bt_dev.le.rl_size) { /* Use host-based identity resolving. */ - bt_conn_set_state(conn, BT_CONN_CONNECTING_SCAN); + bt_conn_set_state(conn, BT_CONN_SCAN_BEFORE_INITIATING); err = bt_le_scan_update(true); if (err) { @@ -3182,7 +3199,7 @@ int bt_conn_le_create(const bt_addr_le_t *peer, const struct bt_conn_le_create_p } #endif - bt_conn_set_state(conn, BT_CONN_CONNECTING); + bt_conn_set_state(conn, BT_CONN_INITIATING); err = bt_le_create_conn(conn); if (err) { @@ -3233,7 +3250,7 @@ int bt_conn_le_create_synced(const struct bt_le_ext_adv *adv, * used, so disable the timeout. */ bt_dev.create_param.timeout = 0; - bt_conn_set_state(conn, BT_CONN_CONNECTING); + bt_conn_set_state(conn, BT_CONN_INITIATING); err = bt_le_create_conn_synced(conn, adv, synced_param->subevent); if (err) { @@ -3286,7 +3303,7 @@ int bt_le_set_auto_conn(const bt_addr_le_t *addr, if (atomic_test_and_clear_bit(conn->flags, BT_CONN_AUTO_CONNECT)) { bt_conn_unref(conn); - if (conn->state == BT_CONN_CONNECTING_SCAN) { + if (conn->state == BT_CONN_SCAN_BEFORE_INITIATING) { bt_conn_set_state(conn, BT_CONN_DISCONNECTED); } } @@ -3295,7 +3312,7 @@ int bt_le_set_auto_conn(const bt_addr_le_t *addr, if (conn->state == BT_CONN_DISCONNECTED && atomic_test_bit(bt_dev.flags, BT_DEV_READY)) { if (param) { - bt_conn_set_state(conn, BT_CONN_CONNECTING_SCAN); + bt_conn_set_state(conn, BT_CONN_SCAN_BEFORE_INITIATING); } bt_le_scan_update(false); } @@ -3552,7 +3569,7 @@ int bt_conn_init(void) /* Only the default identity is supported */ conn->id = BT_ID_DEFAULT; bt_conn_set_state(conn, - BT_CONN_CONNECTING_SCAN); + BT_CONN_SCAN_BEFORE_INITIATING); } #endif /* !defined(CONFIG_BT_FILTER_ACCEPT_LIST) */ diff --git a/subsys/bluetooth/host/conn_internal.h b/subsys/bluetooth/host/conn_internal.h index cce4af3fd8c..5bdbc947b64 100644 --- a/subsys/bluetooth/host/conn_internal.h +++ b/subsys/bluetooth/host/conn_internal.h @@ -14,17 +14,47 @@ typedef enum __packed { BT_CONN_DISCONNECTED, /* Disconnected, conn is completely down */ BT_CONN_DISCONNECT_COMPLETE, /* Received disconn comp event, transition to DISCONNECTED */ - BT_CONN_CONNECTING_SCAN, /* Central passive scanning */ - BT_CONN_CONNECTING_AUTO, /* Central connection establishment w/ filter */ - BT_CONN_CONNECTING_ADV, /* Peripheral connectable advertising */ - BT_CONN_CONNECTING_DIR_ADV, /* Peripheral directed advertising */ - BT_CONN_CONNECTING, /* Central connection establishment */ + + BT_CONN_INITIATING, /* Central connection establishment */ + /** Central scans for a device preceding establishing a connection to it. + * + * This can happen when: + * - The application has explicitly configured the stack to connect to the device, + * but the controller resolving list is too small. The stack therefore first + * scans to be able to retrieve the currently used (private) address, resolving + * the address in the host if needed. + * - The stack uses this connection context for automatic connection establishment + * without the use of filter accept list. Instead of immediately starting + * the initiator, it first starts scanning. This allows the application to start + * scanning while automatic connection establishment in ongoing. + * It also allows the stack to use host based privacy for cases where this is needed. + */ + BT_CONN_SCAN_BEFORE_INITIATING, + + /** Central initiates a connection to a device in the filter accept list. + * + * For this type of connection establishment, the controller's initiator is started + * immediately. That is, it is assumed that the controller resolving list + * holds all entries that are part of the filter accept list if private addresses are used. + */ + BT_CONN_INITIATING_FILTER_LIST, + + BT_CONN_ADV_CONNECTABLE, /* Peripheral connectable advertising */ + BT_CONN_ADV_DIR_CONNECTABLE, /* Peripheral directed advertising */ BT_CONN_CONNECTED, /* Peripheral or Central connected */ BT_CONN_DISCONNECTING, /* Peripheral or Central issued disconnection command */ } bt_conn_state_t; /* bt_conn flags: the flags defined here represent connection parameters */ enum { + /** The connection context is used for automatic connection establishment + * + * That is, with @ref bt_conn_le_create_auto() or bt_le_set_auto_conn(). + * This flag is set even after the connection has been established so + * that the connection can be reestablished once disconnected. + * The connection establishment may be performed with or without the filter + * accept list. + */ BT_CONN_AUTO_CONNECT, BT_CONN_BR_LEGACY_SECURE, /* 16 digits legacy PIN tracker */ BT_CONN_USER, /* user I/O when pairing */ @@ -293,6 +323,8 @@ int bt_conn_iso_init(void); /* Cleanup ISO references */ void bt_iso_cleanup_acl(struct bt_conn *iso_conn); +void bt_iso_reset(void); + /* Add a new BR/EDR connection */ struct bt_conn *bt_conn_add_br(const bt_addr_t *peer); @@ -326,7 +358,7 @@ static inline bool bt_conn_is_handle_valid(struct bt_conn *conn) case BT_CONN_DISCONNECTING: case BT_CONN_DISCONNECT_COMPLETE: return true; - case BT_CONN_CONNECTING: + case BT_CONN_INITIATING: /* ISO connection handle assigned at connect state */ if (IS_ENABLED(CONFIG_BT_ISO) && conn->type == BT_CONN_TYPE_ISO) { diff --git a/subsys/bluetooth/host/gatt.c b/subsys/bluetooth/host/gatt.c index 6744d772105..6a967f9672a 100644 --- a/subsys/bluetooth/host/gatt.c +++ b/subsys/bluetooth/host/gatt.c @@ -1048,6 +1048,11 @@ static int bt_gatt_store_cf(uint8_t id, const bt_addr_le_t *peer) } +static bool is_host_managed_ccc(const struct bt_gatt_attr *attr) +{ + return (attr->write == bt_gatt_attr_write_ccc); +} + #if defined(CONFIG_BT_SETTINGS) && defined(CONFIG_BT_SMP) /** Struct used to store both the id and the random address of a device when replacing * random addresses in the ccc attribute's cfg array with the device's id address after @@ -1064,8 +1069,7 @@ static uint8_t convert_to_id_on_match(const struct bt_gatt_attr *attr, struct _bt_gatt_ccc *ccc; struct addr_match *match = user_data; - /* Check if attribute is a CCC */ - if (attr->write != bt_gatt_attr_write_ccc) { + if (!is_host_managed_ccc(attr)) { return BT_GATT_ITER_CONTINUE; } @@ -1630,7 +1634,7 @@ static int gatt_unregister(struct bt_gatt_service *svc) for (uint16_t i = 0; i < svc->attr_count; i++) { struct bt_gatt_attr *attr = &svc->attrs[i]; - if (attr->write == bt_gatt_attr_write_ccc) { + if (is_host_managed_ccc(attr)) { gatt_unregister_ccc(attr->user_data); } } @@ -1859,7 +1863,7 @@ struct gatt_chrc { union { uint16_t uuid16; uint8_t uuid[16]; - }; + } __packed; } __packed; uint16_t bt_gatt_attr_value_handle(const struct bt_gatt_attr *attr) @@ -2652,8 +2656,7 @@ static uint8_t notify_cb(const struct bt_gatt_attr *attr, uint16_t handle, struct _bt_gatt_ccc *ccc; size_t i; - /* Check attribute user_data must be of type struct _bt_gatt_ccc */ - if (attr->write != bt_gatt_attr_write_ccc) { + if (!is_host_managed_ccc(attr)) { return BT_GATT_ITER_CONTINUE; } @@ -3230,8 +3233,7 @@ static uint8_t update_ccc(const struct bt_gatt_attr *attr, uint16_t handle, size_t i; uint8_t err; - /* Check attribute user_data must be of type struct _bt_gatt_ccc */ - if (attr->write != bt_gatt_attr_write_ccc) { + if (!is_host_managed_ccc(attr)) { return BT_GATT_ITER_CONTINUE; } @@ -3293,8 +3295,7 @@ static uint8_t disconnected_cb(const struct bt_gatt_attr *attr, uint16_t handle, bool value_used; size_t i; - /* Check attribute user_data must be of type struct _bt_gatt_ccc */ - if (attr->write != bt_gatt_attr_write_ccc) { + if (!is_host_managed_ccc(attr)) { return BT_GATT_ITER_CONTINUE; } @@ -5649,8 +5650,7 @@ static uint8_t ccc_load(const struct bt_gatt_attr *attr, uint16_t handle, struct _bt_gatt_ccc *ccc; struct bt_gatt_ccc_cfg *cfg; - /* Check if attribute is a CCC */ - if (attr->write != bt_gatt_attr_write_ccc) { + if (!is_host_managed_ccc(attr)) { return BT_GATT_ITER_CONTINUE; } @@ -5987,8 +5987,7 @@ static uint8_t ccc_save(const struct bt_gatt_attr *attr, uint16_t handle, struct _bt_gatt_ccc *ccc; struct bt_gatt_ccc_cfg *cfg; - /* Check if attribute is a CCC */ - if (attr->write != bt_gatt_attr_write_ccc) { + if (!is_host_managed_ccc(attr)) { return BT_GATT_ITER_CONTINUE; } @@ -6265,8 +6264,7 @@ static uint8_t remove_peer_from_attr(const struct bt_gatt_attr *attr, struct _bt_gatt_ccc *ccc; struct bt_gatt_ccc_cfg *cfg; - /* Check if attribute is a CCC */ - if (attr->write != bt_gatt_attr_write_ccc) { + if (!is_host_managed_ccc(attr)) { return BT_GATT_ITER_CONTINUE; } diff --git a/subsys/bluetooth/host/hci_core.c b/subsys/bluetooth/host/hci_core.c index 35ba75701b4..1c4a5ca67e1 100644 --- a/subsys/bluetooth/host/hci_core.c +++ b/subsys/bluetooth/host/hci_core.c @@ -253,8 +253,12 @@ struct net_buf *bt_hci_cmd_create(uint16_t opcode, uint8_t param_len) LOG_DBG("opcode 0x%04x param_len %u", opcode, param_len); + /* net_buf_alloc(K_FOREVER) can fail when run from the syswq */ buf = net_buf_alloc(&hci_cmd_pool, K_FOREVER); - __ASSERT_NO_MSG(buf); + if (!buf) { + LOG_DBG("Unable to allocate a command buffer"); + return NULL; + } LOG_DBG("buf %p", buf); @@ -340,6 +344,8 @@ int bt_hci_cmd_send_sync(uint16_t opcode, struct net_buf *buf, return -ENOMEM; case BT_HCI_ERR_INVALID_PARAM: return -EINVAL; + case BT_HCI_ERR_CMD_DISALLOWED: + return -EACCES; default: return -EIO; } @@ -807,12 +813,14 @@ int bt_hci_disconnect(uint16_t handle, uint8_t reason) } static uint16_t disconnected_handles[CONFIG_BT_MAX_CONN]; +static uint8_t disconnected_handles_reason[CONFIG_BT_MAX_CONN]; + static void disconnected_handles_reset(void) { (void)memset(disconnected_handles, 0, sizeof(disconnected_handles)); } -static void conn_handle_disconnected(uint16_t handle) +static void conn_handle_disconnected(uint16_t handle, uint8_t disconnect_reason) { for (int i = 0; i < ARRAY_SIZE(disconnected_handles); i++) { if (!disconnected_handles[i]) { @@ -820,22 +828,24 @@ static void conn_handle_disconnected(uint16_t handle) * handle 0 can be used as a valid non-zero handle. */ disconnected_handles[i] = ~BT_ACL_HANDLE_MASK | handle; + disconnected_handles_reason[i] = disconnect_reason; } } } -static bool conn_handle_is_disconnected(uint16_t handle) +/** @returns the disconnect reason. */ +static uint8_t conn_handle_is_disconnected(uint16_t handle) { handle |= ~BT_ACL_HANDLE_MASK; for (int i = 0; i < ARRAY_SIZE(disconnected_handles); i++) { if (disconnected_handles[i] == handle) { disconnected_handles[i] = 0; - return true; + return disconnected_handles_reason[i]; } } - return false; + return 0; } static void hci_disconn_complete_prio(struct net_buf *buf) @@ -855,7 +865,7 @@ static void hci_disconn_complete_prio(struct net_buf *buf) /* Priority disconnect complete event received before normal * connection complete event. */ - conn_handle_disconnected(handle); + conn_handle_disconnected(handle, evt->reason); return; } @@ -906,7 +916,7 @@ static void hci_disconn_complete(struct net_buf *buf) #if defined(CONFIG_BT_CENTRAL) && !defined(CONFIG_BT_FILTER_ACCEPT_LIST) if (atomic_test_bit(conn->flags, BT_CONN_AUTO_CONNECT)) { - bt_conn_set_state(conn, BT_CONN_CONNECTING_SCAN); + bt_conn_set_state(conn, BT_CONN_SCAN_BEFORE_INITIATING); bt_le_scan_update(false); } #endif /* defined(CONFIG_BT_CENTRAL) && !defined(CONFIG_BT_FILTER_ACCEPT_LIST) */ @@ -1039,11 +1049,11 @@ static struct bt_conn *find_pending_connect(uint8_t role, bt_addr_le_t *peer_add */ if (IS_ENABLED(CONFIG_BT_CENTRAL) && role == BT_HCI_ROLE_CENTRAL) { conn = bt_conn_lookup_state_le(BT_ID_DEFAULT, peer_addr, - BT_CONN_CONNECTING); + BT_CONN_INITIATING); if (IS_ENABLED(CONFIG_BT_FILTER_ACCEPT_LIST) && !conn) { conn = bt_conn_lookup_state_le(BT_ID_DEFAULT, BT_ADDR_LE_NONE, - BT_CONN_CONNECTING_AUTO); + BT_CONN_INITIATING_FILTER_LIST); } return conn; @@ -1051,11 +1061,11 @@ static struct bt_conn *find_pending_connect(uint8_t role, bt_addr_le_t *peer_add if (IS_ENABLED(CONFIG_BT_PERIPHERAL) && role == BT_HCI_ROLE_PERIPHERAL) { conn = bt_conn_lookup_state_le(bt_dev.adv_conn_id, peer_addr, - BT_CONN_CONNECTING_DIR_ADV); + BT_CONN_ADV_DIR_CONNECTABLE); if (!conn) { conn = bt_conn_lookup_state_le(bt_dev.adv_conn_id, BT_ADDR_LE_NONE, - BT_CONN_CONNECTING_ADV); + BT_CONN_ADV_CONNECTABLE); } return conn; @@ -1174,7 +1184,7 @@ static void le_conn_complete_cancel(uint8_t err) /* Check if device is marked for autoconnect. */ if (atomic_test_bit(conn->flags, BT_CONN_AUTO_CONNECT)) { /* Restart passive scanner for device */ - bt_conn_set_state(conn, BT_CONN_CONNECTING_SCAN); + bt_conn_set_state(conn, BT_CONN_SCAN_BEFORE_INITIATING); } } else { if (atomic_test_bit(conn->flags, BT_CONN_AUTO_CONNECT)) { @@ -1293,7 +1303,7 @@ static void update_conn(struct bt_conn *conn, const bt_addr_le_t *id_addr, void bt_hci_le_enh_conn_complete(struct bt_hci_evt_le_enh_conn_complete *evt) { uint16_t handle = sys_le16_to_cpu(evt->handle); - bool is_disconnected = conn_handle_is_disconnected(handle); + uint8_t disconnect_reason = conn_handle_is_disconnected(handle); bt_addr_le_t peer_addr, id_addr; struct bt_conn *conn; uint8_t id; @@ -1459,11 +1469,12 @@ void bt_hci_le_enh_conn_complete(struct bt_hci_evt_le_enh_conn_complete *evt) bt_conn_set_state(conn, BT_CONN_CONNECTED); - if (is_disconnected) { + if (disconnect_reason) { /* Mark the connection as already disconnected before calling * the connected callback, so that the application cannot * start sending packets */ + conn->err = disconnect_reason; bt_conn_set_state(conn, BT_CONN_DISCONNECT_COMPLETE); } @@ -1485,7 +1496,7 @@ void bt_hci_le_enh_conn_complete_sync(struct bt_hci_evt_le_enh_conn_complete_v2 struct bt_le_per_adv_sync *sync) { uint16_t handle = sys_le16_to_cpu(evt->handle); - bool is_disconnected = conn_handle_is_disconnected(handle); + uint8_t disconnect_reason = conn_handle_is_disconnected(handle); bt_addr_le_t peer_addr, id_addr; struct bt_conn *conn; @@ -1547,11 +1558,12 @@ void bt_hci_le_enh_conn_complete_sync(struct bt_hci_evt_le_enh_conn_complete_v2 bt_conn_set_state(conn, BT_CONN_CONNECTED); - if (is_disconnected) { + if (disconnect_reason) { /* Mark the connection as already disconnected before calling * the connected callback, so that the application cannot * start sending packets */ + conn->err = disconnect_reason; bt_conn_set_state(conn, BT_CONN_DISCONNECT_COMPLETE); } @@ -2514,7 +2526,7 @@ static void hci_vendor_event(struct net_buf *buf) } #endif /* CONFIG_BT_HCI_VS_EVT_USER */ - if (IS_ENABLED(CONFIG_BT_HCI_VS_EVT) && !handled) { + if (IS_ENABLED(CONFIG_BT_HCI_VS) && !handled) { struct bt_hci_evt_vs *evt; evt = net_buf_pull_mem(buf, sizeof(*evt)); @@ -3080,6 +3092,17 @@ static void le_read_supp_states_complete(struct net_buf *buf) bt_dev.le.states = sys_get_le64(rp->le_states); } +#if defined(CONFIG_BT_BROADCASTER) +static void le_read_maximum_adv_data_len_complete(struct net_buf *buf) +{ + struct bt_hci_rp_le_read_max_adv_data_len *rp = (void *)buf->data; + + LOG_DBG("status 0x%02x", rp->status); + + bt_dev.le.max_adv_data_len = sys_le16_to_cpu(rp->max_adv_data_len); +} +#endif /* CONFIG_BT_BROADCASTER */ + #if defined(CONFIG_BT_SMP) static void le_read_resolving_list_size_complete(struct net_buf *buf) { @@ -3381,6 +3404,25 @@ static int le_init(void) net_buf_unref(rsp); } +#if defined(CONFIG_BT_BROADCASTER) + if (IS_ENABLED(CONFIG_BT_EXT_ADV) && BT_DEV_FEAT_LE_EXT_ADV(bt_dev.le.features)) { + /* Read LE Max Adv Data Len */ + err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_READ_MAX_ADV_DATA_LEN, NULL, &rsp); + if (err == 0) { + le_read_maximum_adv_data_len_complete(rsp); + net_buf_unref(rsp); + } else if (err == -EIO) { + LOG_WRN("Controller does not support 'LE_READ_MAX_ADV_DATA_LEN'. " + "Assuming maximum length is 31 bytes."); + bt_dev.le.max_adv_data_len = 31; + } else { + return err; + } + } else { + bt_dev.le.max_adv_data_len = 31; + } +#endif /* CONFIG_BT_BROADCASTER */ + if (BT_FEAT_BREDR(bt_dev.features)) { buf = bt_hci_cmd_create(BT_HCI_OP_LE_WRITE_LE_HOST_SUPP, sizeof(*cp_le)); @@ -3623,7 +3665,7 @@ static void bt_dev_show_info(void) bt_dev.lmp_version, bt_dev.lmp_subversion); } -#if defined(CONFIG_BT_HCI_VS_EXT) +#if defined(CONFIG_BT_HCI_VS) static const char *vs_hw_platform(uint16_t platform) { static const char * const plat_str[] = { @@ -3761,7 +3803,7 @@ static void hci_vs_init(void) net_buf_unref(rsp); } } -#endif /* CONFIG_BT_HCI_VS_EXT */ +#endif /* CONFIG_BT_HCI_VS */ static int hci_init(void) { @@ -3816,7 +3858,7 @@ static int hci_init(void) return err; } -#if defined(CONFIG_BT_HCI_VS_EXT) +#if defined(CONFIG_BT_HCI_VS) hci_vs_init(); #endif err = bt_id_init(); @@ -3900,7 +3942,7 @@ static void rx_queue_put(struct net_buf *buf) } } -int bt_recv(struct net_buf *buf) +static int bt_recv_unsafe(struct net_buf *buf) { bt_monitor_send(bt_monitor_opcode(buf), buf->data, buf->len); @@ -3939,6 +3981,17 @@ int bt_recv(struct net_buf *buf) } } +int bt_recv(struct net_buf *buf) +{ + int err; + + k_sched_lock(); + err = bt_recv_unsafe(buf); + k_sched_unlock(); + + return err; +} + int bt_hci_driver_register(const struct bt_hci_driver *drv) { if (bt_dev.drv) { @@ -4211,6 +4264,10 @@ int bt_disable(void) k_thread_abort(&bt_workq.thread); #endif + if (IS_ENABLED(CONFIG_BT_ISO)) { + bt_iso_reset(); + } + bt_monitor_send(BT_MONITOR_CLOSE_INDEX, NULL, 0); /* Clear BT_DEV_ENABLE here to prevent early bt_enable() calls, before disable is diff --git a/subsys/bluetooth/host/hci_core.h b/subsys/bluetooth/host/hci_core.h index dc6b52c51c8..8c5dcb6d31f 100644 --- a/subsys/bluetooth/host/hci_core.h +++ b/subsys/bluetooth/host/hci_core.h @@ -35,12 +35,40 @@ enum { BT_DEV_HAS_PUB_KEY, BT_DEV_PUB_KEY_BUSY, - BT_DEV_SCANNING, + /** The application explicitly instructed the stack to scan for advertisers + * using the API @ref bt_le_scan_start(). + */ BT_DEV_EXPLICIT_SCAN, + + /** The application either explicitly or implicitly instructed the stack to scan + * for advertisers. + * + * Examples of such cases + * - Explicit scanning, @ref BT_DEV_EXPLICIT_SCAN. + * - The application instructed the stack to automatically connect if a given device + * is detected. + * - The application wants to connect to a peer device using private addresses, but + * the controller resolving list is too small. The host will fallback to using + * host-based privacy and first scan for the device before it initiates a connection. + * - The application wants to synchronize to a periodic advertiser. + * The host will implicitly start scanning if it is not already doing so. + * + * The host needs to keep track of this state to ensure it can restart scanning + * when a connection is established/lost, explicit scanning is started or stopped etc. + * Also, when the scanner and advertiser share the same identity, the scanner may need + * to be restarted upon RPA refresh. + */ + BT_DEV_SCANNING, + + /* Cached parameters used when initially enabling the scanner. + * These are needed to ensure the same parameters are used when restarting + * the scanner after refreshing an RPA. + */ BT_DEV_ACTIVE_SCAN, BT_DEV_SCAN_FILTER_DUP, BT_DEV_SCAN_FILTERED, BT_DEV_SCAN_LIMITED, + BT_DEV_INITIATING, BT_DEV_RPA_VALID, @@ -266,6 +294,9 @@ struct bt_dev_le { uint8_t iso_limit; struct k_sem iso_pkts; #endif /* CONFIG_BT_ISO */ +#if defined(CONFIG_BT_BROADCASTER) + uint16_t max_adv_data_len; +#endif /* CONFIG_BT_BROADCASTER */ #if defined(CONFIG_BT_SMP) /* Size of the the controller resolving list */ @@ -342,7 +373,7 @@ struct bt_dev { /* Supported commands */ uint8_t supported_commands[64]; -#if defined(CONFIG_BT_HCI_VS_EXT) +#if defined(CONFIG_BT_HCI_VS) /* Vendor HCI support */ uint8_t vs_features[BT_DEV_VS_FEAT_MAX]; uint8_t vs_commands[BT_DEV_VS_CMDS_MAX]; diff --git a/subsys/bluetooth/host/id.c b/subsys/bluetooth/host/id.c index c49e42bf508..d6f23f2db64 100644 --- a/subsys/bluetooth/host/id.c +++ b/subsys/bluetooth/host/id.c @@ -141,6 +141,15 @@ static int set_random_address(const bt_addr_t *addr) err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_SET_RANDOM_ADDRESS, buf, NULL); if (err) { + if (err == -EACCES) { + /* If we are here we probably tried to set a random + * address while a legacy advertising, scanning or + * initiating is enabled, this is illegal. + * + * See Core Spec @ Vol 4, Part E 7.8.4 + */ + LOG_WRN("cmd disallowed"); + } return err; } @@ -669,7 +678,7 @@ static void rpa_timeout(struct k_work *work) if (IS_ENABLED(CONFIG_BT_CENTRAL)) { struct bt_conn *conn = bt_conn_lookup_state_le(BT_ID_DEFAULT, NULL, - BT_CONN_CONNECTING_SCAN); + BT_CONN_SCAN_BEFORE_INITIATING); if (conn) { bt_conn_unref(conn); @@ -998,7 +1007,7 @@ void bt_id_add(struct bt_keys *keys) return; } - conn = bt_conn_lookup_state_le(BT_ID_DEFAULT, NULL, BT_CONN_CONNECTING); + conn = bt_conn_lookup_state_le(BT_ID_DEFAULT, NULL, BT_CONN_INITIATING); if (conn) { bt_id_pending_keys_update_set(keys, BT_KEYS_ID_PENDING_ADD); bt_conn_unref(conn); @@ -1147,7 +1156,7 @@ void bt_id_del(struct bt_keys *keys) return; } - conn = bt_conn_lookup_state_le(BT_ID_DEFAULT, NULL, BT_CONN_CONNECTING); + conn = bt_conn_lookup_state_le(BT_ID_DEFAULT, NULL, BT_CONN_INITIATING); if (conn) { bt_id_pending_keys_update_set(keys, BT_KEYS_ID_PENDING_DEL); bt_conn_unref(conn); @@ -1478,7 +1487,7 @@ static void bt_read_identity_root(uint8_t *ir) /* Invalid IR */ memset(ir, 0, 16); -#if defined(CONFIG_BT_HCI_VS_EXT) +#if defined(CONFIG_BT_HCI_VS) struct bt_hci_rp_vs_read_key_hierarchy_roots *rp; struct net_buf *rsp; int err; @@ -1505,7 +1514,7 @@ static void bt_read_identity_root(uint8_t *ir) memcpy(ir, rp->ir, 16); net_buf_unref(rsp); -#endif /* defined(CONFIG_BT_HCI_VS_EXT) */ +#endif /* defined(CONFIG_BT_HCI_VS) */ } #endif /* defined(CONFIG_BT_PRIVACY) */ @@ -1580,9 +1589,9 @@ int bt_setup_public_id_addr(void) return id_create(BT_ID_DEFAULT, &addr, irk); } -#if defined(CONFIG_BT_HCI_VS_EXT) -uint8_t bt_read_static_addr(struct bt_hci_vs_static_addr addrs[], uint8_t size) +static uint8_t vs_read_static_addr(struct bt_hci_vs_static_addr addrs[], uint8_t size) { +#if defined(CONFIG_BT_HCI_VS) struct bt_hci_rp_vs_read_static_addrs *rp; struct net_buf *rsp; int err, i; @@ -1628,59 +1637,58 @@ uint8_t bt_read_static_addr(struct bt_hci_vs_static_addr addrs[], uint8_t size) } return cnt; +#else + return 0; +#endif } -#endif /* CONFIG_BT_HCI_VS_EXT */ int bt_setup_random_id_addr(void) { -#if defined(CONFIG_BT_HCI_VS_EXT) || defined(CONFIG_BT_CTLR) /* Only read the addresses if the user has not already configured one or * more identities (!bt_dev.id_count). */ - if (!bt_dev.id_count) { + if (IS_ENABLED(CONFIG_BT_HCI_VS) && !bt_dev.id_count) { struct bt_hci_vs_static_addr addrs[CONFIG_BT_ID_MAX]; - bt_dev.id_count = bt_read_static_addr(addrs, CONFIG_BT_ID_MAX); - - if (bt_dev.id_count) { - for (uint8_t i = 0; i < bt_dev.id_count; i++) { - int err; - bt_addr_le_t addr; - uint8_t *irk = NULL; -#if defined(CONFIG_BT_PRIVACY) - uint8_t ir_irk[16]; + bt_dev.id_count = vs_read_static_addr(addrs, CONFIG_BT_ID_MAX); - if (!IS_ENABLED(CONFIG_BT_PRIVACY_RANDOMIZE_IR)) { - if (!bt_smp_irk_get(addrs[i].ir, ir_irk)) { - irk = ir_irk; - } + for (uint8_t i = 0; i < bt_dev.id_count; i++) { + int err; + bt_addr_le_t addr; + uint8_t *irk = NULL; + uint8_t ir_irk[16]; + + if (IS_ENABLED(CONFIG_BT_PRIVACY) && + !IS_ENABLED(CONFIG_BT_PRIVACY_RANDOMIZE_IR)) { + if (!bt_smp_irk_get(addrs[i].ir, ir_irk)) { + irk = ir_irk; } -#endif /* CONFIG_BT_PRIVACY */ + } - /* If true, `id_create` will randomize the IRK. */ - if (!irk && IS_ENABLED(CONFIG_BT_PRIVACY)) { - /* `id_create` will not store the id when called before - * BT_DEV_READY. But since part of the id will be - * randomized, it needs to be stored. - */ - if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - atomic_set_bit(bt_dev.flags, BT_DEV_STORE_ID); - } + /* If true, `id_create` will randomize the IRK. */ + if (!irk && IS_ENABLED(CONFIG_BT_PRIVACY)) { + /* `id_create` will not store the id when called before + * BT_DEV_READY. But since part of the id will be + * randomized, it needs to be stored. + */ + if (IS_ENABLED(CONFIG_BT_SETTINGS)) { + atomic_set_bit(bt_dev.flags, BT_DEV_STORE_ID); } + } - bt_addr_copy(&addr.a, &addrs[i].bdaddr); - addr.type = BT_ADDR_LE_RANDOM; + bt_addr_copy(&addr.a, &addrs[i].bdaddr); + addr.type = BT_ADDR_LE_RANDOM; - err = id_create(i, &addr, irk); - if (err) { - return err; - } + err = id_create(i, &addr, irk); + if (err) { + return err; } + } + if (bt_dev.id_count > 0) { return 0; } } -#endif /* defined(CONFIG_BT_HCI_VS_EXT) || defined(CONFIG_BT_CTLR) */ if (IS_ENABLED(CONFIG_BT_PRIVACY) && IS_ENABLED(CONFIG_BT_SETTINGS)) { atomic_set_bit(bt_dev.flags, BT_DEV_STORE_ID); @@ -1985,7 +1993,7 @@ int bt_le_oob_get_local(uint8_t id, struct bt_le_oob *oob) struct bt_conn *conn; conn = bt_conn_lookup_state_le(BT_ID_DEFAULT, NULL, - BT_CONN_CONNECTING_SCAN); + BT_CONN_SCAN_BEFORE_INITIATING); if (conn) { /* Cannot set new RPA while creating * connections. @@ -2061,7 +2069,7 @@ int bt_le_ext_adv_oob_get_local(struct bt_le_ext_adv *adv, conn = bt_conn_lookup_state_le( BT_ID_DEFAULT, NULL, - BT_CONN_CONNECTING_SCAN); + BT_CONN_SCAN_BEFORE_INITIATING); if (conn) { /* Cannot set new RPA while creating diff --git a/subsys/bluetooth/host/iso.c b/subsys/bluetooth/host/iso.c index f71625f22ac..6df42691a28 100644 --- a/subsys/bluetooth/host/iso.c +++ b/subsys/bluetooth/host/iso.c @@ -168,7 +168,7 @@ struct net_buf *bt_iso_create_pdu_timeout(struct net_buf_pool *pool, pool = &iso_tx_pool; } - reserve += sizeof(struct bt_hci_iso_data_hdr); + reserve += sizeof(struct bt_hci_iso_sdu_hdr); #if defined(CONFIG_NET_BUF_LOG) return bt_conn_create_pdu_timeout_debug(pool, reserve, timeout, func, @@ -585,7 +585,7 @@ struct net_buf *bt_iso_get_rx(k_timeout_t timeout) void bt_iso_recv(struct bt_conn *iso, struct net_buf *buf, uint8_t flags) { - struct bt_hci_iso_data_hdr *hdr; + struct bt_hci_iso_sdu_hdr *hdr; struct bt_iso_chan *chan; uint8_t pb, ts; uint16_t len, pkt_seq_no; @@ -609,12 +609,12 @@ void bt_iso_recv(struct bt_conn *iso, struct net_buf *buf, uint8_t flags) * of an SDU or a complete SDU. */ if (ts) { - struct bt_hci_iso_ts_data_hdr *ts_hdr; + struct bt_hci_iso_sdu_ts_hdr *ts_hdr; ts_hdr = net_buf_pull_mem(buf, sizeof(*ts_hdr)); iso_info(buf)->ts = sys_le32_to_cpu(ts_hdr->ts); - hdr = &ts_hdr->data; + hdr = &ts_hdr->sdu; iso_info(buf)->flags |= BT_ISO_FLAGS_TS; } else { hdr = net_buf_pull_mem(buf, sizeof(*hdr)); @@ -764,25 +764,26 @@ static int validate_send(const struct bt_iso_chan *chan, const struct net_buf *b BT_ISO_DATA_DBG("chan %p len %zu", chan, net_buf_frags_len(buf)); if (chan->state != BT_ISO_STATE_CONNECTED) { - LOG_DBG("Not connected"); + LOG_DBG("Channel %p not connected", chan); return -ENOTCONN; } iso_conn = chan->iso; if (!iso_conn->iso.info.can_send) { - LOG_DBG("Channel not able to send"); + LOG_DBG("Channel %p not able to send", chan); return -EINVAL; } if (buf->size < hdr_size) { - LOG_DBG("Cannot send ISO packet with buffer size %u", buf->size); + LOG_DBG("Channel %p cannot send ISO packet with buffer size %u", chan, buf->size); return -EMSGSIZE; } max_data_len = iso_chan_max_data_len(chan); if (buf->len > max_data_len) { - LOG_DBG("Cannot send %u octets, maximum %u", buf->len, max_data_len); + LOG_DBG("Channel %p cannot send %u octets, maximum %u", chan, buf->len, + max_data_len); return -EMSGSIZE; } @@ -791,11 +792,11 @@ static int validate_send(const struct bt_iso_chan *chan, const struct net_buf *b int bt_iso_chan_send(struct bt_iso_chan *chan, struct net_buf *buf, uint16_t seq_num) { - struct bt_hci_iso_data_hdr *hdr; + struct bt_hci_iso_sdu_hdr *hdr; struct bt_conn *iso_conn; int err; - err = validate_send(chan, buf, BT_HCI_ISO_DATA_HDR_SIZE); + err = validate_send(chan, buf, BT_HCI_ISO_SDU_HDR_SIZE); if (err != 0) { return err; } @@ -815,11 +816,11 @@ int bt_iso_chan_send(struct bt_iso_chan *chan, struct net_buf *buf, uint16_t seq int bt_iso_chan_send_ts(struct bt_iso_chan *chan, struct net_buf *buf, uint16_t seq_num, uint32_t ts) { - struct bt_hci_iso_ts_data_hdr *hdr; + struct bt_hci_iso_sdu_ts_hdr *hdr; struct bt_conn *iso_conn; int err; - err = validate_send(chan, buf, BT_HCI_ISO_TS_DATA_HDR_SIZE); + err = validate_send(chan, buf, BT_HCI_ISO_SDU_TS_HDR_SIZE); if (err != 0) { return err; } @@ -828,8 +829,8 @@ int bt_iso_chan_send_ts(struct bt_iso_chan *chan, struct net_buf *buf, uint16_t hdr = net_buf_push(buf, sizeof(*hdr)); hdr->ts = ts; - hdr->data.sn = sys_cpu_to_le16(seq_num); - hdr->data.slen = sys_cpu_to_le16( + hdr->sdu.sn = sys_cpu_to_le16(seq_num); + hdr->sdu.slen = sys_cpu_to_le16( bt_iso_pkt_len_pack(net_buf_frags_len(buf) - sizeof(*hdr), BT_ISO_DATA_VALID)); iso_conn = chan->iso; @@ -1371,7 +1372,7 @@ void hci_le_cis_req(struct net_buf *buf) iso->handle = cis_handle; iso->role = BT_HCI_ROLE_PERIPHERAL; - bt_conn_set_state(iso, BT_CONN_CONNECTING); + bt_conn_set_state(iso, BT_CONN_INITIATING); err = hci_le_accept_cis(cis_handle); if (err) { @@ -2194,6 +2195,11 @@ void bt_iso_security_changed(struct bt_conn *acl, uint8_t hci_status) continue; } + /* Set state to disconnected to indicate that we are no longer waiting for + * encryption. + * TODO: Remove the BT_ISO_STATE_ENCRYPT_PENDING state and replace with a flag to + * avoid these unnecessary state changes + */ bt_iso_chan_set_state(iso_chan, BT_ISO_STATE_DISCONNECTED); if (hci_status == BT_HCI_ERR_SUCCESS) { @@ -2247,7 +2253,7 @@ void bt_iso_security_changed(struct bt_conn *acl, uint8_t hci_status) __ASSERT(cig != NULL, "CIG was NULL"); cig->state = BT_ISO_CIG_STATE_ACTIVE; - bt_conn_set_state(iso_chan->iso, BT_CONN_CONNECTING); + bt_conn_set_state(iso_chan->iso, BT_CONN_INITIATING); bt_iso_chan_set_state(iso_chan, BT_ISO_STATE_CONNECTING); } } @@ -2454,7 +2460,7 @@ int bt_iso_chan_connect(const struct bt_iso_connect_param *param, size_t count) } iso_chan->iso->iso.acl = bt_conn_ref(param[i].acl); - bt_conn_set_state(iso_chan->iso, BT_CONN_CONNECTING); + bt_conn_set_state(iso_chan->iso, BT_CONN_INITIATING); bt_iso_chan_set_state(iso_chan, BT_ISO_STATE_CONNECTING); cig = get_cig(iso_chan); @@ -2528,7 +2534,7 @@ static void big_disconnect(struct bt_iso_big *big, uint8_t reason) SYS_SLIST_FOR_EACH_CONTAINER(&big->bis_channels, bis, node) { bis->iso->err = reason; - bt_iso_disconnected(bis->iso); + bt_iso_chan_disconnected(bis, reason); } } @@ -3278,3 +3284,31 @@ int bt_iso_big_sync(struct bt_le_per_adv_sync *sync, struct bt_iso_big_sync_para } #endif /* CONFIG_BT_ISO_SYNC_RECEIVER */ #endif /* CONFIG_BT_ISO_BROADCAST */ + +void bt_iso_reset(void) +{ +#if defined(CONFIG_BT_ISO_CENTRAL) + for (size_t i = 0U; i < ARRAY_SIZE(cigs); i++) { + struct bt_iso_cig *cig = &cigs[i]; + struct bt_iso_chan *cis, *tmp; + + /* Call the disconnected callback for each CIS that is no idle */ + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&cig->cis_channels, cis, tmp, node) { + if (cis->state != BT_ISO_STATE_DISCONNECTED) { + bt_iso_chan_disconnected(cis, BT_HCI_ERR_UNSPECIFIED); + } + } + + cleanup_cig(cig); + } +#endif /* CONFIG_BT_ISO_CENTRAL */ + +#if defined(CONFIG_BT_ISO_BROADCAST) + for (size_t i = 0U; i < ARRAY_SIZE(bigs); i++) { + struct bt_iso_big *big = &bigs[i]; + + big_disconnect(big, BT_HCI_ERR_UNSPECIFIED); + cleanup_big(big); + } +#endif /* CONFIG_BT_ISO_BROADCAST */ +} diff --git a/subsys/bluetooth/host/l2cap.c b/subsys/bluetooth/host/l2cap.c index 75e8bc396bd..df312f5dd03 100644 --- a/subsys/bluetooth/host/l2cap.c +++ b/subsys/bluetooth/host/l2cap.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -440,13 +441,13 @@ static struct net_buf *l2cap_create_le_sig_pdu(uint8_t code, uint8_t ident, return buf; } -/* Send the buffer and release it in case of failure. +/* Send the buffer over the signalling channel. Release it in case of failure. * Any other cleanup in failure to send should be handled by the disconnected * handler. */ -static inline int l2cap_send(struct bt_conn *conn, uint16_t cid, struct net_buf *buf) +static int l2cap_send_sig(struct bt_conn *conn, struct net_buf *buf) { - int err = bt_l2cap_send(conn, cid, buf); + int err = bt_l2cap_send(conn, BT_L2CAP_CID_LE_SIG, buf); if (err) { net_buf_unref(buf); @@ -459,7 +460,7 @@ static inline int l2cap_send(struct bt_conn *conn, uint16_t cid, struct net_buf static void l2cap_chan_send_req(struct bt_l2cap_chan *chan, struct net_buf *buf, k_timeout_t timeout) { - if (l2cap_send(chan->conn, BT_L2CAP_CID_LE_SIG, buf)) { + if (l2cap_send_sig(chan->conn, buf)) { return; } @@ -521,6 +522,10 @@ static int l2cap_ecred_conn_req(struct bt_l2cap_chan **chan, int channels) sizeof(*req) + (channels * sizeof(uint16_t))); + if (!buf) { + return -ENOMEM; + } + req = net_buf_add(buf, sizeof(*req)); ch = BT_L2CAP_LE_CHAN(chan[0]); @@ -637,7 +642,7 @@ int bt_l2cap_send_cb(struct bt_conn *conn, uint16_t cid, struct net_buf *buf, { struct bt_l2cap_hdr *hdr; - LOG_DBG("conn %p cid %u len %zu", conn, cid, net_buf_frags_len(buf)); + LOG_DBG("conn %p cid %u len %zu", conn, cid, buf->len); hdr = net_buf_push(buf, sizeof(*hdr)); hdr->len = sys_cpu_to_le16(buf->len - sizeof(*hdr)); @@ -665,7 +670,7 @@ static void l2cap_send_reject(struct bt_conn *conn, uint8_t ident, net_buf_add_mem(buf, data, data_len); } - l2cap_send(conn, BT_L2CAP_CID_LE_SIG, buf); + l2cap_send_sig(conn, buf); } static void le_conn_param_rsp(struct bt_l2cap *l2cap, struct net_buf *buf) @@ -728,7 +733,7 @@ static void le_conn_param_update_req(struct bt_l2cap *l2cap, uint8_t ident, rsp->result = sys_cpu_to_le16(BT_L2CAP_CONN_PARAM_REJECTED); } - l2cap_send(conn, BT_L2CAP_CID_LE_SIG, buf); + l2cap_send_sig(conn, buf); if (accepted) { bt_conn_le_conn_update(conn, ¶m); @@ -893,7 +898,23 @@ static struct net_buf *l2cap_chan_le_get_tx_buf(struct bt_l2cap_le_chan *ch) } static int l2cap_chan_le_send_sdu(struct bt_l2cap_le_chan *ch, - struct net_buf **buf); + struct net_buf *buf); + +/** @brief Get @c chan->state. + * + * This field does not exist when @kconfig{CONFIG_BT_L2CAP_DYNAMIC_CHANNEL} is + * disabled. In that case, this function returns @ref BT_L2CAP_CONNECTED since + * the struct can only represent static channels in that case and static + * channels are always connected. + */ +static bt_l2cap_chan_state_t bt_l2cap_chan_get_state(struct bt_l2cap_chan *chan) +{ +#if defined(CONFIG_BT_L2CAP_DYNAMIC_CHANNEL) + return BT_L2CAP_LE_CHAN(chan)->state; +#else + return BT_L2CAP_CONNECTED; +#endif +} static void l2cap_chan_tx_process(struct k_work *work) { @@ -903,6 +924,11 @@ static void l2cap_chan_tx_process(struct k_work *work) ch = CONTAINER_OF(k_work_delayable_from_work(work), struct bt_l2cap_le_chan, tx_work); + if (bt_l2cap_chan_get_state(&ch->chan) != BT_L2CAP_CONNECTED) { + LOG_DBG("Cannot send on non-connected channel"); + return; + } + /* Resume tx in case there are buffers in the queue */ while ((buf = l2cap_chan_le_get_tx_buf(ch))) { /* Here buf is either: @@ -911,7 +937,7 @@ static void l2cap_chan_tx_process(struct k_work *work) */ LOG_DBG("chan %p buf %p", ch, buf); - ret = l2cap_chan_le_send_sdu(ch, &buf); + ret = l2cap_chan_le_send_sdu(ch, buf); if (ret < 0) { if (ret == -EAGAIN) { ch->tx_buf = buf; @@ -1183,7 +1209,7 @@ static void le_conn_req(struct bt_l2cap *l2cap, uint8_t ident, rsp: rsp->result = sys_cpu_to_le16(result); - if (l2cap_send(conn, BT_L2CAP_CID_LE_SIG, buf)) { + if (l2cap_send_sig(conn, buf)) { return; } @@ -1302,7 +1328,7 @@ static void le_ecred_conn_req(struct bt_l2cap *l2cap, uint8_t ident, net_buf_add_mem(buf, dcid, sizeof(scid) * req_cid_count); - if (l2cap_send(conn, BT_L2CAP_CID_LE_SIG, buf)) { + if (l2cap_send_sig(conn, buf)) { goto callback; } @@ -1407,11 +1433,14 @@ static void le_ecred_reconf_req(struct bt_l2cap *l2cap, uint8_t ident, response: buf = l2cap_create_le_sig_pdu(BT_L2CAP_ECRED_RECONF_RSP, ident, sizeof(*rsp)); + if (!buf) { + return; + } rsp = net_buf_add(buf, sizeof(*rsp)); rsp->result = sys_cpu_to_le16(result); - l2cap_send(conn, BT_L2CAP_CID_LE_SIG, buf); + l2cap_send_sig(conn, buf); } static void le_ecred_reconf_rsp(struct bt_l2cap *l2cap, uint8_t ident, @@ -1516,7 +1545,7 @@ static void le_disconn_req(struct bt_l2cap *l2cap, uint8_t ident, bt_l2cap_chan_del(&chan->chan); - l2cap_send(conn, BT_L2CAP_CID_LE_SIG, buf); + l2cap_send_sig(conn, buf); } static int l2cap_change_security(struct bt_l2cap_le_chan *chan, uint16_t err) @@ -1916,7 +1945,8 @@ static int l2cap_chan_le_send(struct bt_l2cap_le_chan *ch, if ((buf->len <= ch->tx.mps) && (net_buf_headroom(buf) >= BT_L2CAP_BUF_SIZE(0))) { LOG_DBG("len <= MPS, not allocating seg for %p", buf); - seg = net_buf_ref(buf); + /* move `buf` to `seg`. `buf` now borrows `seg`. */ + seg = buf; len = seg->len; } else { @@ -1945,11 +1975,10 @@ static int l2cap_chan_le_send(struct bt_l2cap_le_chan *ch, len = seg->len - sdu_hdr_len; /* SDU will be considered sent when there is no data left in the - * buffers, or if there will be no data left, if we are sending `buf` + * buffer, or if there will be no data left, if we are sending `buf` * directly. */ - if (net_buf_frags_len(buf) == 0 || - (buf == seg && net_buf_frags_len(buf) == len)) { + if (buf->len == 0 || (buf == seg && buf->len == len)) { cb = l2cap_chan_sdu_sent; } else { cb = l2cap_chan_seg_sent; @@ -1974,14 +2003,21 @@ static int l2cap_chan_le_send(struct bt_l2cap_le_chan *ch, */ LOG_DBG("unref %p (%s)", seg, buf == seg ? "orig" : "seg"); - net_buf_unref(seg); + + if (seg == buf) { + /* move `seg` to `buf` */ + } else { + net_buf_unref(seg); + } if (err == -ENOBUFS) { /* Restore state since segment could not be sent */ net_buf_simple_restore(&buf->b, &state); - return -EAGAIN; + err = -EAGAIN; } + /* move `buf` back to caller */ + return err; } @@ -1998,47 +2034,36 @@ static int l2cap_chan_le_send(struct bt_l2cap_le_chan *ch, return len; } -/* return next netbuf fragment if present, also assign metadata */ +/** + * @param buf [move on success] + */ static int l2cap_chan_le_send_sdu(struct bt_l2cap_le_chan *ch, - struct net_buf **buf) + struct net_buf *buf) { int ret; - size_t sent, rem_len, frag_len; - struct net_buf *frag; + size_t sent = 0; + size_t rem_len; - frag = *buf; - if (!frag->len && frag->frags) { - frag = frag->frags; - } + __ASSERT_NO_MSG(buf); - rem_len = net_buf_frags_len(frag); - sent = 0; - while (frag && sent != rem_len) { - LOG_DBG("send frag %p (orig buf %p)", frag, *buf); + rem_len = buf->len; - frag_len = frag->len; - ret = l2cap_chan_le_send(ch, frag, 0); + while (sent != rem_len) { + ret = l2cap_chan_le_send(ch, buf, 0); if (ret < 0) { - *buf = frag; - - LOG_DBG("failed to send frag (ch %p cid 0x%04x sent %d)", + LOG_DBG("failed to send buf (ch %p cid 0x%04x sent %d)", ch, ch->tx.cid, sent); return ret; } sent += ret; - - /* If the current buffer has been fully consumed, destroy it and - * proceed to the next fragment of the netbuf chain. - */ - if (ret == frag_len) { - frag = net_buf_frag_del(NULL, frag); - } } LOG_DBG("ch %p cid 0x%04x sent %u", ch, ch->tx.cid, sent); + /* `l2cap_chan_le_send` moved `buf` for final seg */ + return sent; } @@ -2088,13 +2113,9 @@ static void reject_cmd(struct bt_l2cap *l2cap, uint8_t ident, struct bt_conn *conn = l2cap->chan.chan.conn; struct bt_l2cap_le_chan *chan; - /* Check if there is a outstanding channel */ - chan = l2cap_remove_ident(conn, ident); - if (!chan) { - return; + while ((chan = l2cap_remove_ident(conn, ident))) { + bt_l2cap_chan_del(&chan->chan); } - - bt_l2cap_chan_del(&chan->chan); } #endif /* CONFIG_BT_L2CAP_DYNAMIC_CHANNEL */ @@ -2222,22 +2243,6 @@ static void l2cap_chan_shutdown(struct bt_l2cap_chan *chan) } } -/** @brief Get @c chan->state. - * - * This field does not exist when @kconfig{CONFIG_BT_L2CAP_DYNAMIC_CHANNEL} is - * disabled. In that case, this function returns @ref BT_L2CAP_CONNECTED since - * the struct can only represent static channels in that case and static - * channels are always connected. - */ -static inline bt_l2cap_chan_state_t bt_l2cap_chan_get_state(struct bt_l2cap_chan *chan) -{ -#if defined(CONFIG_BT_L2CAP_DYNAMIC_CHANNEL) - return BT_L2CAP_LE_CHAN(chan)->state; -#else - return BT_L2CAP_CONNECTED; -#endif -} - static void l2cap_chan_send_credits(struct bt_l2cap_le_chan *chan, uint16_t credits) { @@ -2264,7 +2269,7 @@ static void l2cap_chan_send_credits(struct bt_l2cap_le_chan *chan, ev->cid = sys_cpu_to_le16(chan->rx.cid); ev->credits = sys_cpu_to_le16(credits); - l2cap_send(chan->chan.conn, BT_L2CAP_CID_LE_SIG, buf); + l2cap_send_sig(chan->chan.conn, buf); LOG_DBG("chan %p credits %lu", chan, atomic_get(&chan->rx.credits)); } @@ -2286,7 +2291,7 @@ static int l2cap_chan_send_credits_pdu(struct bt_conn *conn, uint16_t cid, uint1 .credits = sys_cpu_to_le16(credits), }; - return l2cap_send(conn, BT_L2CAP_CID_LE_SIG, buf); + return l2cap_send_sig(conn, buf); } /** @@ -2398,7 +2403,7 @@ static void l2cap_chan_le_recv_sdu(struct bt_l2cap_le_chan *chan, { int err; - LOG_DBG("chan %p len %zu", chan, net_buf_frags_len(buf)); + LOG_DBG("chan %p len %zu", chan, buf->len); __ASSERT_NO_MSG(bt_l2cap_chan_get_state(&chan->chan) == BT_L2CAP_CONNECTED); __ASSERT_NO_MSG(atomic_get(&chan->rx.credits) == 0); @@ -2425,7 +2430,7 @@ static void l2cap_chan_le_recv_seg(struct bt_l2cap_le_chan *chan, uint16_t len; uint16_t seg = 0U; - len = net_buf_frags_len(chan->_sdu); + len = chan->_sdu->len; if (len) { memcpy(&seg, net_buf_user_data(chan->_sdu), sizeof(seg)); } @@ -2440,7 +2445,7 @@ static void l2cap_chan_le_recv_seg(struct bt_l2cap_le_chan *chan, /* Store received segments in user_data */ memcpy(net_buf_user_data(chan->_sdu), &seg, sizeof(seg)); - LOG_DBG("chan %p seg %d len %zu", chan, seg, net_buf_frags_len(buf)); + LOG_DBG("chan %p seg %d len %zu", chan, seg, buf->len); /* Append received segment to SDU */ len = net_buf_append_bytes(chan->_sdu, buf->len, buf->data, K_NO_WAIT, @@ -2451,7 +2456,7 @@ static void l2cap_chan_le_recv_seg(struct bt_l2cap_le_chan *chan, return; } - if (net_buf_frags_len(chan->_sdu) < chan->_sdu_len) { + if (chan->_sdu->len < chan->_sdu_len) { /* Give more credits if remote has run out of them, this * should only happen if the remote cannot fully utilize the * MPS for some reason. @@ -2716,7 +2721,7 @@ int bt_l2cap_update_conn_param(struct bt_conn *conn, req->latency = sys_cpu_to_le16(param->latency); req->timeout = sys_cpu_to_le16(param->timeout); - return l2cap_send(conn, BT_L2CAP_CID_LE_SIG, buf); + return l2cap_send_sig(conn, buf); } static void l2cap_connected(struct bt_l2cap_chan *chan) @@ -3054,16 +3059,29 @@ int bt_l2cap_chan_disconnect(struct bt_l2cap_chan *chan) static int bt_l2cap_dyn_chan_send(struct bt_l2cap_le_chan *le_chan, struct net_buf *buf) { - uint16_t sdu_len = net_buf_frags_len(buf); + uint16_t sdu_len = buf->len; LOG_DBG("chan %p buf %p", le_chan, buf); + /* Frags are not supported. */ + __ASSERT_NO_MSG(buf->frags == NULL); + if (sdu_len > le_chan->tx.mtu) { LOG_ERR("attempt to send %u bytes on %u MTU chan", sdu_len, le_chan->tx.mtu); return -EMSGSIZE; } + if (buf->ref != 1) { + /* The host may alter the buf contents when segmenting. Higher + * layers cannot expect the buf contents to stay intact. Extra + * refs suggests a silent data corruption would occur if not for + * this error. + */ + LOG_ERR("buf given to l2cap has other refs"); + return -EINVAL; + } + if (net_buf_headroom(buf) < BT_L2CAP_SDU_CHAN_SEND_RESERVE) { /* Call `net_buf_reserve(buf, BT_L2CAP_SDU_CHAN_SEND_RESERVE)` * when allocating buffers intended for bt_l2cap_chan_send(). @@ -3108,7 +3126,7 @@ int bt_l2cap_chan_send(struct bt_l2cap_chan *chan, struct net_buf *buf) return -EINVAL; } - LOG_DBG("chan %p buf %p len %zu", chan, buf, net_buf_frags_len(buf)); + LOG_DBG("chan %p buf %p len %zu", chan, buf, buf->len); if (!chan->conn || chan->conn->state != BT_CONN_CONNECTED) { return -ENOTCONN; diff --git a/subsys/bluetooth/host/scan.c b/subsys/bluetooth/host/scan.c index 4ee6b46307f..4d4233895ac 100644 --- a/subsys/bluetooth/host/scan.c +++ b/subsys/bluetooth/host/scan.c @@ -344,14 +344,14 @@ int bt_le_scan_update(bool fast_scan) /* don't restart scan if we have pending connection */ conn = bt_conn_lookup_state_le(BT_ID_DEFAULT, NULL, - BT_CONN_CONNECTING); + BT_CONN_INITIATING); if (conn) { bt_conn_unref(conn); return 0; } conn = bt_conn_lookup_state_le(BT_ID_DEFAULT, NULL, - BT_CONN_CONNECTING_SCAN); + BT_CONN_SCAN_BEFORE_INITIATING); if (conn) { atomic_set_bit(bt_dev.flags, BT_DEV_SCAN_FILTER_DUP); @@ -389,7 +389,7 @@ static void check_pending_conn(const bt_addr_le_t *id_addr, } conn = bt_conn_lookup_state_le(BT_ID_DEFAULT, id_addr, - BT_CONN_CONNECTING_SCAN); + BT_CONN_SCAN_BEFORE_INITIATING); if (!conn) { return; } @@ -404,7 +404,7 @@ static void check_pending_conn(const bt_addr_le_t *id_addr, goto failed; } - bt_conn_set_state(conn, BT_CONN_CONNECTING); + bt_conn_set_state(conn, BT_CONN_INITIATING); bt_conn_unref(conn); return; @@ -674,6 +674,19 @@ void bt_hci_le_adv_ext_report(struct net_buf *buf) reassembling_advertiser.state = FRAG_ADV_DISCARDING; } + if (evt->length > buf->len) { + LOG_WRN("Adv report corrupted (wants %u out of %u)", evt->length, buf->len); + + /* Start discarding irrespective of the `more_to_come` flag. We + * assume we may have lost a partial adv report in the truncated + * data. + */ + reassembling_advertiser.state = FRAG_ADV_DISCARDING; + net_buf_reset(buf); + + return; + } + if (reassembling_advertiser.state == FRAG_ADV_DISCARDING) { if (!more_to_come) { /* We do no longer need to keep track of this advertiser as diff --git a/subsys/bluetooth/host/smp.c b/subsys/bluetooth/host/smp.c index 3099c0f4ada..5de1b5b5ed3 100644 --- a/subsys/bluetooth/host/smp.c +++ b/subsys/bluetooth/host/smp.c @@ -37,6 +37,7 @@ #include "keys.h" #include "conn_internal.h" #include "l2cap_internal.h" +#include "classic/l2cap_br_interface.h" #include "smp.h" #define LOG_LEVEL CONFIG_BT_SMP_LOG_LEVEL @@ -815,7 +816,7 @@ static void smp_br_timeout(struct k_work *work) static void smp_br_send(struct bt_smp_br *smp, struct net_buf *buf, bt_conn_tx_cb_t cb) { - int err = bt_l2cap_send_cb(smp->chan.chan.conn, BT_L2CAP_CID_BR_SMP, buf, cb, NULL); + int err = bt_l2cap_br_send_cb(smp->chan.chan.conn, BT_L2CAP_CID_BR_SMP, buf, cb, NULL); if (err) { if (err == -ENOBUFS) { @@ -1397,7 +1398,8 @@ static int smp_br_error(struct bt_smp_br *smp, uint8_t reason) * SMP timer is not restarted for PairingFailed so don't use * smp_br_send */ - if (bt_l2cap_send(smp->chan.chan.conn, BT_L2CAP_CID_SMP, buf)) { + if (bt_l2cap_br_send_cb(smp->chan.chan.conn, BT_L2CAP_CID_SMP, buf, + NULL, NULL)) { net_buf_unref(buf); } diff --git a/subsys/bluetooth/mesh/Kconfig b/subsys/bluetooth/mesh/Kconfig index a79e0e4d4e9..6b647c7ab86 100644 --- a/subsys/bluetooth/mesh/Kconfig +++ b/subsys/bluetooth/mesh/Kconfig @@ -1349,6 +1349,7 @@ config BT_MESH_USES_MBEDTLS_PSA select MBEDTLS select MBEDTLS_ZEPHYR_ENTROPY select MBEDTLS_PSA_CRYPTO_C + select MBEDTLS_USE_PSA_CRYPTO select MBEDTLS_MAC_CMAC_ENABLED select MBEDTLS_CIPHER_AES_ENABLED select MBEDTLS_AES_ROM_TABLES diff --git a/subsys/bluetooth/mesh/access.c b/subsys/bluetooth/mesh/access.c index 0ad4e7164ad..da04b15db73 100644 --- a/subsys/bluetooth/mesh/access.c +++ b/subsys/bluetooth/mesh/access.c @@ -220,7 +220,7 @@ static size_t metadata_model_size(const struct bt_mesh_model *mod, size += sizeof(uint8_t); - for (entry = *mod->metadata; entry && entry->len; ++entry) { + for (entry = mod->metadata; entry && entry->len; ++entry) { size += sizeof(entry->len) + sizeof(entry->id) + entry->len; } @@ -286,7 +286,7 @@ static int metadata_add_model(const struct bt_mesh_model *mod, count_ptr = data_buf_add_u8_offset(buf, 0, offset); if (mod->metadata) { - for (entry = *mod->metadata; entry && entry->data != NULL; ++entry) { + for (entry = mod->metadata; entry && entry->data != NULL; ++entry) { data_buf_add_le16_offset(buf, entry->len, offset); data_buf_add_le16_offset(buf, entry->id, offset); data_buf_add_mem_offset(buf, entry->data, entry->len, offset); @@ -1487,12 +1487,13 @@ static int element_model_recv(struct bt_mesh_msg_ctx *ctx, struct net_buf_simple } if (!bt_mesh_model_has_key(model, ctx->app_idx)) { - LOG_ERR("Wrong key"); + LOG_DBG("Model at 0x%04x is not bound to app idx %d", elem->rt->addr, ctx->app_idx); return ACCESS_STATUS_WRONG_KEY; } if (!model_has_dst(model, ctx->recv_dst, ctx->uuid)) { - LOG_ERR("Invalid address 0x%02x", ctx->recv_dst); + LOG_DBG("Dst addr 0x%02x is invalid for model at 0x%04x", ctx->recv_dst, + elem->rt->addr); return ACCESS_STATUS_INVALID_ADDRESS; } diff --git a/subsys/bluetooth/mesh/dfu_cli.c b/subsys/bluetooth/mesh/dfu_cli.c index 2345ef8e33b..f02b884d222 100644 --- a/subsys/bluetooth/mesh/dfu_cli.c +++ b/subsys/bluetooth/mesh/dfu_cli.c @@ -6,11 +6,11 @@ #include #include +#include #include #include "access.h" #include "dfu.h" #include "blob.h" -#include #include #define LOG_LEVEL CONFIG_BT_MESH_DFU_LOG_LEVEL @@ -1017,7 +1017,11 @@ int bt_mesh_dfu_cli_send(struct bt_mesh_dfu_cli *cli, cli->xfer.blob.size = xfer->slot->size; if (xfer->blob_id == 0) { - sys_rand_get(&cli->xfer.blob.id, sizeof(cli->xfer.blob.id)); + int err = bt_rand(&cli->xfer.blob.id, sizeof(cli->xfer.blob.id)); + + if (err) { + return err; + } } else { cli->xfer.blob.id = xfer->blob_id; } diff --git a/subsys/bluetooth/mesh/dfu_srv.c b/subsys/bluetooth/mesh/dfu_srv.c index f8e87e29da9..0cb4b5e524e 100644 --- a/subsys/bluetooth/mesh/dfu_srv.c +++ b/subsys/bluetooth/mesh/dfu_srv.c @@ -78,7 +78,9 @@ static void apply_rsp_sent(int err, void *cb_params) struct bt_mesh_dfu_srv *srv = cb_params; if (err) { - LOG_WRN("Apply response failed, wait for retry"); + /* return phase back to give client one more chance. */ + srv->update.phase = BT_MESH_DFU_PHASE_VERIFY_OK; + LOG_WRN("Apply response failed, wait for retry (err %d)", err); return; } @@ -87,15 +89,18 @@ static void apply_rsp_sent(int err, void *cb_params) if (!srv->cb->apply || srv->update.idx == UPDATE_IDX_NONE) { srv->update.phase = BT_MESH_DFU_PHASE_IDLE; store_state(srv); + LOG_DBG("Prerequisites for apply callback are wrong"); return; } + store_state(srv); + err = srv->cb->apply(srv, &srv->imgs[srv->update.idx]); if (err) { srv->update.phase = BT_MESH_DFU_PHASE_IDLE; + store_state(srv); + LOG_DBG("Application apply callback failed (err %d)", err); } - - store_state(srv); } static void apply_rsp_sending(uint16_t duration, int err, void *cb_params) @@ -418,8 +423,6 @@ static int handle_apply(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx * case it triggers a reboot: */ srv->update.phase = BT_MESH_DFU_PHASE_APPLYING; - store_state(srv); - update_status_rsp(srv, ctx, BT_MESH_DFU_SUCCESS, &send_cb); return 0; diff --git a/subsys/bluetooth/mesh/pb_adv.c b/subsys/bluetooth/mesh/pb_adv.c index c5c56b1e5b0..e5946e739d6 100644 --- a/subsys/bluetooth/mesh/pb_adv.c +++ b/subsys/bluetooth/mesh/pb_adv.c @@ -482,6 +482,11 @@ static void gen_prov_cont(struct prov_rx *rx, struct net_buf_simple *buf) { uint8_t seg = CONT_SEG_INDEX(rx->gpc); + if (link.tx.adv[0]) { + LOG_DBG("Ongoing tx transaction has not been completed yet"); + return; + } + LOG_DBG("len %u, seg_index %u", buf->len, seg); if (!link.rx.seg && link.rx.id == rx->xact_id) { @@ -570,6 +575,11 @@ static void gen_prov_start(struct prov_rx *rx, struct net_buf_simple *buf) { uint8_t seg = SEG_NVAL; + if (link.tx.adv[0]) { + LOG_DBG("Ongoing tx transaction has not been completed yet"); + return; + } + if (rx->xact_id == link.rx.id) { if (!link.rx.seg) { if (!ack_pending()) { diff --git a/subsys/bluetooth/mesh/pb_gatt_srv.c b/subsys/bluetooth/mesh/pb_gatt_srv.c index f4fdac53570..62436a3c8d0 100644 --- a/subsys/bluetooth/mesh/pb_gatt_srv.c +++ b/subsys/bluetooth/mesh/pb_gatt_srv.c @@ -33,16 +33,9 @@ #include LOG_MODULE_REGISTER(bt_mesh_pb_gatt_srv); -#if defined(CONFIG_BT_MESH_PB_GATT_USE_DEVICE_NAME) -#define ADV_OPT_USE_NAME BT_LE_ADV_OPT_USE_NAME -#else -#define ADV_OPT_USE_NAME 0 -#endif - #define ADV_OPT_PROV \ (BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_SCANNABLE | \ - BT_LE_ADV_OPT_ONE_TIME | ADV_OPT_USE_IDENTITY | \ - ADV_OPT_USE_NAME) + BT_LE_ADV_OPT_ONE_TIME | ADV_OPT_USE_IDENTITY) #define FAST_ADV_TIME (60LL * MSEC_PER_SEC) @@ -222,8 +215,10 @@ static const struct bt_data prov_ad[] = { BT_DATA(BT_DATA_SVC_DATA16, prov_svc_data, sizeof(prov_svc_data)), }; -static size_t gatt_prov_adv_create(struct bt_data prov_sd[1]) +static size_t gatt_prov_adv_create(struct bt_data prov_sd[2]) { + size_t prov_sd_len = 0; + const struct bt_mesh_prov *prov = bt_mesh_prov_get(); size_t uri_len; @@ -245,7 +240,17 @@ static size_t gatt_prov_adv_create(struct bt_data prov_sd[1]) prov_sd[0].data_len = uri_len; prov_sd[0].data = (const uint8_t *)prov->uri; - return 1; + prov_sd_len += 1; + +#if defined(CONFIG_BT_MESH_PB_GATT_USE_DEVICE_NAME) + prov_sd[1].type = BT_DATA_NAME_COMPLETE; + prov_sd[1].data_len = sizeof(CONFIG_BT_DEVICE_NAME) - 1; + prov_sd[1].data = CONFIG_BT_DEVICE_NAME; + + prov_sd_len += 1; +#endif + + return prov_sd_len; } static int gatt_send(struct bt_conn *conn, @@ -279,7 +284,7 @@ int bt_mesh_pb_gatt_srv_adv_start(void) .options = ADV_OPT_PROV, ADV_FAST_INT, }; - struct bt_data prov_sd[1]; + struct bt_data prov_sd[2]; size_t prov_sd_len; int64_t timestamp = fast_adv_timestamp; int64_t elapsed_time = k_uptime_delta(×tamp); diff --git a/subsys/bluetooth/mesh/proxy_srv.c b/subsys/bluetooth/mesh/proxy_srv.c index a903d94ffa9..ca5e8bb76d1 100644 --- a/subsys/bluetooth/mesh/proxy_srv.c +++ b/subsys/bluetooth/mesh/proxy_srv.c @@ -44,18 +44,12 @@ LOG_MODULE_REGISTER(bt_mesh_gatt); */ #define PROXY_RANDOM_UPDATE_INTERVAL (10 * 60 * MSEC_PER_SEC) -#if defined(CONFIG_BT_MESH_PROXY_USE_DEVICE_NAME) -#define ADV_OPT_USE_NAME BT_LE_ADV_OPT_USE_NAME -#else -#define ADV_OPT_USE_NAME 0 -#endif - #define ADV_OPT_ADDR(private) (IS_ENABLED(CONFIG_BT_MESH_DEBUG_USE_ID_ADDR) ? \ BT_LE_ADV_OPT_USE_IDENTITY : (private) ? BT_LE_ADV_OPT_USE_NRPA : 0) #define ADV_OPT_PROXY(private) \ (BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_SCANNABLE | ADV_OPT_ADDR(private) | \ - BT_LE_ADV_OPT_ONE_TIME | ADV_OPT_USE_NAME) + BT_LE_ADV_OPT_ONE_TIME) static void proxy_send_beacons(struct k_work *work); static int proxy_send(struct bt_conn *conn, @@ -489,6 +483,12 @@ static const struct bt_data net_id_ad[] = { BT_DATA(BT_DATA_SVC_DATA16, proxy_svc_data, NET_ID_LEN), }; +static const struct bt_data sd[] = { +#if defined(CONFIG_BT_MESH_PROXY_USE_DEVICE_NAME) + BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1), +#endif +}; + static int randomize_bt_addr(void) { /* TODO: There appears to be no way to force an RPA/NRPA refresh. */ @@ -531,7 +531,7 @@ static int enc_id_adv(struct bt_mesh_subnet *sub, uint8_t type, err = bt_mesh_adv_gatt_start( type == BT_MESH_ID_TYPE_PRIV_NET ? &slow_adv_param : &fast_adv_param, - duration, enc_id_ad, ARRAY_SIZE(enc_id_ad), NULL, 0); + duration, enc_id_ad, ARRAY_SIZE(enc_id_ad), sd, ARRAY_SIZE(sd)); if (err) { LOG_WRN("Failed to advertise using type 0x%02x (err %d)", type, err); return err; @@ -616,7 +616,7 @@ static int net_id_adv(struct bt_mesh_subnet *sub, int32_t duration) memcpy(proxy_svc_data + 3, sub->keys[SUBNET_KEY_TX_IDX(sub)].net_id, 8); err = bt_mesh_adv_gatt_start(&slow_adv_param, duration, net_id_ad, - ARRAY_SIZE(net_id_ad), NULL, 0); + ARRAY_SIZE(net_id_ad), sd, ARRAY_SIZE(sd)); if (err) { LOG_WRN("Failed to advertise using Network ID (err %d)", err); return err; diff --git a/subsys/bluetooth/mesh/rpr_cli.c b/subsys/bluetooth/mesh/rpr_cli.c index cbb92e75b40..5d5aeb9ee60 100644 --- a/subsys/bluetooth/mesh/rpr_cli.c +++ b/subsys/bluetooth/mesh/rpr_cli.c @@ -298,7 +298,7 @@ static int handle_scan_report(const struct bt_mesh_model *mod, struct bt_mesh_ms return -EINVAL; } - if (IS_ENABLED(CONFIG_BT_MESH_DEBUG)) { + if (IS_ENABLED(CONFIG_BT_MESH_MODEL_LOG_LEVEL_DBG)) { struct bt_uuid_128 uuid_repr = { .uuid = { BT_UUID_TYPE_128 } }; memcpy(uuid_repr.val, dev.uuid, 16); diff --git a/subsys/bluetooth/mesh/rpr_srv.c b/subsys/bluetooth/mesh/rpr_srv.c index ac3fd190880..ed8d87f3c04 100644 --- a/subsys/bluetooth/mesh/rpr_srv.c +++ b/subsys/bluetooth/mesh/rpr_srv.c @@ -6,9 +6,9 @@ #include #include -#include #include #include +#include #include #include #include @@ -193,14 +193,15 @@ static void link_report_send(void) static void scan_report_schedule(void) { - uint32_t delay; + uint32_t delay = 0; if (k_work_delayable_remaining_get(&srv.scan.report) || atomic_test_bit(srv.flags, SCAN_REPORT_PENDING)) { return; } - delay = (sys_rand32_get() % 480) + 20; + (void)bt_rand(&delay, sizeof(uint32_t)); + delay = (delay % 480) + 20; k_work_reschedule(&srv.scan.report, K_MSEC(delay)); } @@ -1172,7 +1173,7 @@ static void adv_handle_ext_scan(const struct bt_le_scan_recv_info *info, srv.scan.addr = *info->addr; atomic_set_bit(srv.flags, SCAN_EXT_HAS_ADDR); - if (IS_ENABLED(CONFIG_BT_MESH_DEBUG_MODEL)) { + if (IS_ENABLED(CONFIG_BT_MESH_MODEL_LOG_LEVEL_DBG)) { struct bt_uuid_128 uuid_repr = { .uuid = { BT_UUID_TYPE_128 } }; memcpy(uuid_repr.val, dev->uuid, 16); diff --git a/subsys/bluetooth/mesh/shell/dfd.c b/subsys/bluetooth/mesh/shell/dfd.c index 4b3d4970282..81c9d557c5d 100644 --- a/subsys/bluetooth/mesh/shell/dfd.c +++ b/subsys/bluetooth/mesh/shell/dfd.c @@ -223,7 +223,7 @@ static int cmd_dfd_start(const struct shell *sh, size_t argc, char *argv[]) } if (argc > 4) { - params.apply = strcmp(argv[4], "true") ? false : true; + params.apply = shell_strtobool(argv[4], 0, &err); } else { params.apply = true; } diff --git a/subsys/bluetooth/mesh/shell/shell.c b/subsys/bluetooth/mesh/shell/shell.c index 78c503c29ac..511f50a78f9 100644 --- a/subsys/bluetooth/mesh/shell/shell.c +++ b/subsys/bluetooth/mesh/shell/shell.c @@ -144,13 +144,13 @@ static const struct bt_mesh_health_srv_cb health_srv_cb = { }; #endif /* CONFIG_BT_MESH_SHELL_HEALTH_SRV_INSTANCE */ -#ifdef CONFIG_BT_MESH_LARGE_COMP_DATA_SRV +#if defined(CONFIG_BT_MESH_LARGE_COMP_DATA_SRV) static const uint8_t health_tests[] = { BT_MESH_HEALTH_TEST_INFO(COMPANY_ID_LF, 6, 0x01, 0x02, 0x03, 0x04, 0x34, 0x15), BT_MESH_HEALTH_TEST_INFO(COMPANY_ID_NORDIC_SEMI, 3, 0x01, 0x02, 0x03), }; -static const struct bt_mesh_models_metadata_entry health_srv_meta[] = { +const struct bt_mesh_models_metadata_entry health_srv_meta[] = { BT_MESH_HEALTH_TEST_INFO_METADATA(health_tests), BT_MESH_MODELS_METADATA_END, }; @@ -160,9 +160,6 @@ struct bt_mesh_health_srv bt_mesh_shell_health_srv = { #if defined(CONFIG_BT_MESH_SHELL_HEALTH_SRV_INSTANCE) .cb = &health_srv_cb, #endif -#ifdef CONFIG_BT_MESH_LARGE_COMP_DATA_SRV - .metadata = health_srv_meta, -#endif }; #if defined(CONFIG_BT_MESH_SHELL_HEALTH_CLI) diff --git a/subsys/bluetooth/services/ots/ots.c b/subsys/bluetooth/services/ots/ots.c index f054b9a5e59..e2c4e90db13 100644 --- a/subsys/bluetooth/services/ots/ots.c +++ b/subsys/bluetooth/services/ots/ots.c @@ -42,7 +42,7 @@ LOG_MODULE_REGISTER(bt_ots, CONFIG_BT_OTS_LOG_LEVEL); #define OACP_FEAT_BIT_DELETE 0 #endif -#if defined(BT_OTS_OACP_CHECKSUM_SUPPORT) +#if defined(CONFIG_BT_OTS_OACP_CHECKSUM_SUPPORT) #define OACP_FEAT_BIT_CRC BIT(BT_OTS_OACP_FEAT_CHECKSUM) #else #define OACP_FEAT_BIT_CRC 0 @@ -318,7 +318,7 @@ int bt_ots_obj_add_internal(struct bt_ots *ots, struct bt_conn *conn, (void)memset(&created_desc, 0, sizeof(created_desc)); if (ots->cb->obj_created) { - err = ots->cb->obj_created(ots, NULL, new_obj->id, param, &created_desc); + err = ots->cb->obj_created(ots, conn, new_obj->id, param, &created_desc); if (err) { (void)bt_gatt_ots_obj_manager_obj_delete(new_obj); @@ -442,6 +442,22 @@ void *bt_ots_svc_decl_get(struct bt_ots *ots) } #endif +static void oacp_indicate_work_handler(struct k_work *work) +{ + struct bt_gatt_ots_indicate *ind = CONTAINER_OF(work, struct bt_gatt_ots_indicate, work); + struct bt_ots *ots = CONTAINER_OF(ind, struct bt_ots, oacp_ind); + + bt_gatt_indicate(NULL, &ots->oacp_ind.params); +} + +static void olcp_indicate_work_handler(struct k_work *work) +{ + struct bt_gatt_ots_indicate *ind = CONTAINER_OF(work, struct bt_gatt_ots_indicate, work); + struct bt_ots *ots = CONTAINER_OF(ind, struct bt_ots, olcp_ind); + + bt_gatt_indicate(NULL, &ots->olcp_ind.params); +} + int bt_ots_init(struct bt_ots *ots, struct bt_ots_init_param *ots_init) { @@ -506,6 +522,9 @@ int bt_ots_init(struct bt_ots *ots, bt_ots_dir_list_init(&ots->dir_list, ots->obj_manager); } + k_work_init(&ots->oacp_ind.work, oacp_indicate_work_handler); + k_work_init(&ots->olcp_ind.work, olcp_indicate_work_handler); + LOG_DBG("Initialized OTS"); return 0; diff --git a/subsys/bluetooth/services/ots/ots_internal.h b/subsys/bluetooth/services/ots/ots_internal.h index f68472ee887..af1cafb0251 100644 --- a/subsys/bluetooth/services/ots/ots_internal.h +++ b/subsys/bluetooth/services/ots/ots_internal.h @@ -16,6 +16,25 @@ extern "C" { #include "ots_oacp_internal.h" #include "ots_olcp_internal.h" +/** + * Both OACP and OLCP have same max size of 7 bytes + * + * Table 3.10: Format of OACP Response Value + * OACP Response Value contains + * 1 octet Procedure code + * 1 octet Request op code + * 1 octet Result Code + * 4 octet CRC checksum (if present) + * + * Table 3.24: Format of the OLCP Response Value + * 1 octet Procedure code + * 1 octet Request op code + * 1 octet Result Code + * 0 or 4 octets Response Parameter + * + **/ +#define OACP_OLCP_RES_MAX_SIZE 7 + #define BT_OTS_VALID_OBJ_ID(id) (IN_RANGE((id), BT_OTS_OBJ_ID_MIN, BT_OTS_OBJ_ID_MAX) || \ (id) == OTS_OBJ_ID_DIR_LIST) @@ -103,6 +122,8 @@ struct bt_gatt_ots_indicate { struct bt_gatt_attr attr; struct _bt_gatt_ccc ccc; bool is_enabled; + struct k_work work; + uint8_t res[OACP_OLCP_RES_MAX_SIZE]; }; struct bt_ots { diff --git a/subsys/bluetooth/services/ots/ots_oacp.c b/subsys/bluetooth/services/ots/ots_oacp.c index 7d34e7061c4..c92521953c1 100644 --- a/subsys/bluetooth/services/ots/ots_oacp.c +++ b/subsys/bluetooth/services/ots/ots_oacp.c @@ -25,16 +25,6 @@ LOG_MODULE_DECLARE(bt_ots, CONFIG_BT_OTS_LOG_LEVEL); #define OACP_PROC_TYPE_SIZE 1 -/** - * OTS_v10.pdf Table 3.10: Format of OACP Response V - * OACP Response Value contains - * 1 octet Procedure code - * 1 octet Request op code - * 1 octet Result Code - * 4 octet CRC checksum (if present) - * Execute operation is not supported - **/ -#define OACP_RES_MAX_SIZE (3 + sizeof(uint32_t)) #if defined(CONFIG_BT_OTS_OACP_WRITE_SUPPORT) static ssize_t oacp_write_proc_cb(struct bt_gatt_ots_l2cap *l2cap_ctx, @@ -644,14 +634,14 @@ static void oacp_ind_cb(struct bt_conn *conn, } } -static int oacp_ind_send(const struct bt_gatt_attr *oacp_attr, +static void oacp_ind_send(const struct bt_gatt_attr *oacp_attr, struct bt_gatt_ots_oacp_proc oacp_proc, enum bt_gatt_ots_oacp_res_code oacp_status, struct net_buf_simple *resp_param) { - uint8_t oacp_res[OACP_RES_MAX_SIZE]; - uint16_t oacp_res_len = 0; struct bt_ots *ots = (struct bt_ots *) oacp_attr->user_data; + uint8_t *oacp_res = ots->oacp_ind.res; + uint16_t oacp_res_len = 0; /* Encode OACP Response */ oacp_res[oacp_res_len++] = BT_GATT_OTS_OACP_PROC_RESP; @@ -673,7 +663,8 @@ static int oacp_ind_send(const struct bt_gatt_attr *oacp_attr, LOG_DBG("Sending OACP indication"); - return bt_gatt_indicate(NULL, &ots->oacp_ind.params); + + k_work_submit(&ots->oacp_ind.work); } ssize_t bt_gatt_ots_oacp_write(struct bt_conn *conn, @@ -699,6 +690,11 @@ ssize_t bt_gatt_ots_oacp_write(struct bt_conn *conn, return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET); } + if (k_work_is_pending(&ots->oacp_ind.work)) { + LOG_ERR("OACP Write received before indication sent"); + return BT_GATT_ERR(BT_ATT_ERR_PROCEDURE_IN_PROGRESS); + } + decode_status = oacp_command_decode(buf, len, &oacp_proc); switch (decode_status) { case 0: diff --git a/subsys/bluetooth/services/ots/ots_olcp.c b/subsys/bluetooth/services/ots/ots_olcp.c index 1b9461c07a7..7a7efb56435 100644 --- a/subsys/bluetooth/services/ots/ots_olcp.c +++ b/subsys/bluetooth/services/ots/ots_olcp.c @@ -23,7 +23,6 @@ LOG_MODULE_DECLARE(bt_ots, CONFIG_BT_OTS_LOG_LEVEL); #define OLCP_PROC_TYPE_SIZE 1 -#define OLCP_RES_MAX_SIZE 7 static enum bt_gatt_ots_olcp_res_code obj_manager_to_olcp_err_map(int err) { @@ -205,13 +204,13 @@ static void olcp_ind_cb(struct bt_conn *conn, LOG_DBG("Received OLCP Indication ACK with status: 0x%04X", err); } -static int olcp_ind_send(const struct bt_gatt_attr *olcp_attr, +static void olcp_ind_send(const struct bt_gatt_attr *olcp_attr, enum bt_gatt_ots_olcp_proc_type req_op_code, enum bt_gatt_ots_olcp_res_code olcp_status) { - uint8_t olcp_res[OLCP_RES_MAX_SIZE]; - uint16_t olcp_res_len = 0; struct bt_ots *ots = (struct bt_ots *) olcp_attr->user_data; + uint8_t *olcp_res = ots->olcp_ind.res; + uint16_t olcp_res_len = 0; /* Encode OLCP Response */ olcp_res[olcp_res_len++] = BT_GATT_OTS_OLCP_PROC_RESP; @@ -231,7 +230,7 @@ static int olcp_ind_send(const struct bt_gatt_attr *olcp_attr, LOG_DBG("Sending OLCP indication"); - return bt_gatt_indicate(NULL, &ots->olcp_ind.params); + k_work_submit(&ots->olcp_ind.work); } ssize_t bt_gatt_ots_olcp_write(struct bt_conn *conn, @@ -257,6 +256,11 @@ ssize_t bt_gatt_ots_olcp_write(struct bt_conn *conn, return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET); } + if (k_work_is_pending(&ots->olcp_ind.work)) { + LOG_ERR("OLCP Write received before indication sent"); + return BT_GATT_ERR(BT_ATT_ERR_PROCEDURE_IN_PROGRESS); + } + old_obj = ots->cur_obj; decode_status = olcp_command_decode(buf, len, &olcp_proc); diff --git a/subsys/bluetooth/shell/bt.c b/subsys/bluetooth/shell/bt.c index f69702ba184..16f02e7d504 100644 --- a/subsys/bluetooth/shell/bt.c +++ b/subsys/bluetooth/shell/bt.c @@ -1762,14 +1762,33 @@ static ssize_t ad_init(struct bt_data *data_array, const size_t data_array_size, return ad_len; } +void set_ad_name_complete(struct bt_data *ad, const char *name) +{ + ad->type = BT_DATA_NAME_COMPLETE; + ad->data_len = strlen(name); + ad->data = name; +} + +void set_ad_device_name_complete(struct bt_data *ad) +{ + const char *name = bt_get_name(); + + set_ad_name_complete(ad, name); +} + static int cmd_advertise(const struct shell *sh, size_t argc, char *argv[]) { struct bt_le_adv_param param = {}; - struct bt_data ad[3]; + struct bt_data ad[4]; + struct bt_data sd[4]; bool discoverable = true; bool appearance = false; - ssize_t ad_len; + ssize_t ad_len = 0; + ssize_t sd_len = 0; int err; + bool with_name = true; + bool name_ad = false; + bool name_sd = true; if (!strcmp(argv[1], "off")) { if (bt_le_adv_stop() < 0) { @@ -1787,10 +1806,7 @@ static int cmd_advertise(const struct shell *sh, size_t argc, char *argv[]) param.interval_max = BT_GAP_ADV_FAST_INT_MAX_2; if (!strcmp(argv[1], "on")) { - param.options = (BT_LE_ADV_OPT_CONNECTABLE | - BT_LE_ADV_OPT_USE_NAME); - } else if (!strcmp(argv[1], "scan")) { - param.options = BT_LE_ADV_OPT_USE_NAME; + param.options = BT_LE_ADV_OPT_CONNECTABLE; } else if (!strcmp(argv[1], "nconn")) { param.options = 0U; } else { @@ -1816,10 +1832,10 @@ static int cmd_advertise(const struct shell *sh, size_t argc, char *argv[]) } else if (!strcmp(arg, "identity")) { param.options |= BT_LE_ADV_OPT_USE_IDENTITY; } else if (!strcmp(arg, "no-name")) { - param.options &= ~BT_LE_ADV_OPT_USE_NAME; + with_name = false; } else if (!strcmp(arg, "name-ad")) { - param.options |= BT_LE_ADV_OPT_USE_NAME; - param.options |= BT_LE_ADV_OPT_FORCE_NAME_IN_AD; + name_ad = true; + name_sd = false; } else if (!strcmp(arg, "one-time")) { param.options |= BT_LE_ADV_OPT_ONE_TIME; } else if (!strcmp(arg, "disable-37")) { @@ -1833,18 +1849,30 @@ static int cmd_advertise(const struct shell *sh, size_t argc, char *argv[]) } } + if (name_ad && with_name) { + set_ad_device_name_complete(&ad[0]); + ad_len++; + } + + if (name_sd && with_name) { + set_ad_device_name_complete(&sd[0]); + sd_len++; + } + atomic_clear(adv_opt); atomic_set_bit_to(adv_opt, SHELL_ADV_OPT_CONNECTABLE, (param.options & BT_LE_ADV_OPT_CONNECTABLE) > 0); atomic_set_bit_to(adv_opt, SHELL_ADV_OPT_DISCOVERABLE, discoverable); atomic_set_bit_to(adv_opt, SHELL_ADV_OPT_APPEARANCE, appearance); - ad_len = ad_init(ad, ARRAY_SIZE(ad), adv_opt); - if (ad_len < 0) { + err = ad_init(&ad[ad_len], ARRAY_SIZE(ad) - ad_len, adv_opt); + if (err < 0) { return -ENOEXEC; } + ad_len += err; - err = bt_le_adv_start(¶m, ad_len > 0 ? ad : NULL, ad_len, NULL, 0); + err = bt_le_adv_start(¶m, ad_len > 0 ? ad : NULL, ad_len, sd_len > 0 ? sd : NULL, + sd_len); if (err < 0) { shell_error(sh, "Failed to start advertising (err %d)", err); @@ -1954,11 +1982,6 @@ static bool adv_param_parse(size_t argc, char *argv[], param->options |= BT_LE_ADV_OPT_FILTER_CONN; } else if (!strcmp(arg, "identity")) { param->options |= BT_LE_ADV_OPT_USE_IDENTITY; - } else if (!strcmp(arg, "name")) { - param->options |= BT_LE_ADV_OPT_USE_NAME; - } else if (!strcmp(arg, "name-ad")) { - param->options |= BT_LE_ADV_OPT_USE_NAME; - param->options |= BT_LE_ADV_OPT_FORCE_NAME_IN_AD; } else if (!strcmp(arg, "low")) { param->options |= BT_LE_ADV_OPT_DIR_MODE_LOW_DUTY; } else if (!strcmp(arg, "dir-rpa")) { @@ -2069,6 +2092,9 @@ static int cmd_adv_data(const struct shell *sh, size_t argc, char *argv[]) bool discoverable = false; size_t *data_len; int err; + bool name = false; + bool dev_name = false; + const char *name_value = NULL; if (!adv) { return -EINVAL; @@ -2081,11 +2107,31 @@ static int cmd_adv_data(const struct shell *sh, size_t argc, char *argv[]) for (size_t argn = 1; argn < argc; argn++) { const char *arg = argv[argn]; - if (strcmp(arg, "scan-response") && - *data_len == ARRAY_SIZE(ad)) { + if (name && !dev_name && name_value == NULL) { + if (*data_len == ARRAY_SIZE(ad)) { + /* Maximum entries limit reached. */ + shell_print(sh, "Failed to set advertising data: " + "Maximum entries limit reached"); + + return -ENOEXEC; + } + + len = strlen(arg); + memcpy(&hex_data[hex_data_len], arg, len); + name_value = &hex_data[hex_data_len]; + + set_ad_name_complete(&data[*data_len], name_value); + + (*data_len)++; + hex_data_len += len; + + continue; + } + + if (strcmp(arg, "scan-response") && *data_len == ARRAY_SIZE(ad)) { /* Maximum entries limit reached. */ shell_print(sh, "Failed to set advertising data: " - "Maximum entries limit reached"); + "Maximum entries limit reached"); return -ENOEXEC; } @@ -2099,19 +2145,24 @@ static int cmd_adv_data(const struct shell *sh, size_t argc, char *argv[]) } else if (!strcmp(arg, "scan-response")) { if (data == sd) { shell_print(sh, "Failed to set advertising data: " - "duplicate scan-response option"); + "duplicate scan-response option"); return -ENOEXEC; } data = sd; data_len = &sd_len; + } else if (!strcmp(arg, "name") && !name) { + name = true; + } else if (!strcmp(arg, "dev-name")) { + name = true; + dev_name = true; } else { len = hex2bin(arg, strlen(arg), &hex_data[hex_data_len], sizeof(hex_data) - hex_data_len); if (!len || (len - 1) != (hex_data[hex_data_len])) { shell_print(sh, "Failed to set advertising data: " - "malformed hex data"); + "malformed hex data"); return -ENOEXEC; } @@ -2123,6 +2174,25 @@ static int cmd_adv_data(const struct shell *sh, size_t argc, char *argv[]) } } + if (name && !dev_name && name_value == NULL) { + shell_error(sh, "Failed to set advertising data: Expected a value for 'name'"); + return -ENOEXEC; + } + + if (name && dev_name && name_value == NULL) { + if (*data_len == ARRAY_SIZE(ad)) { + /* Maximum entries limit reached. */ + shell_print(sh, "Failed to set advertising data: " + "Maximum entries limit reached"); + + return -ENOEXEC; + } + + set_ad_device_name_complete(&data[*data_len]); + + (*data_len)++; + } + atomic_set_bit_to(adv_set_opt[selected_adv], SHELL_ADV_OPT_DISCOVERABLE, discoverable); atomic_set_bit_to(adv_set_opt[selected_adv], SHELL_ADV_OPT_APPEARANCE, appearance); @@ -2324,7 +2394,7 @@ static int cmd_adv_rpa_expire(const struct shell *sh, size_t argc, char *argv[]) return 0; } -#endif +#endif /* CONFIG_BT_PRIVACY */ #if defined(CONFIG_BT_PER_ADV) static int cmd_per_adv(const struct shell *sh, size_t argc, char *argv[]) @@ -4472,8 +4542,8 @@ static int cmd_default_handler(const struct shell *sh, size_t argc, char **argv) #define EXT_ADV_PARAM \ " " \ "[ext-adv] [no-2m] [coded] [anon] [tx-power] [scan-reports] " \ - "[filter-accept-list: fal, fal-scan, fal-conn] [identity] [name] " \ - "[name-ad] [directed " HELP_ADDR_LE "] [mode: low] [dir-rpa] " \ + "[filter-accept-list: fal, fal-scan, fal-conn] [identity] " \ + "[directed " HELP_ADDR_LE "] [mode: low] [dir-rpa] " \ "[disable-37] [disable-38] [disable-39]" #else #define EXT_ADV_SCAN_OPT "" @@ -4551,7 +4621,7 @@ SHELL_STATIC_SUBCMD_SET_CREATE(bt_cmds, #endif #if defined(CONFIG_BT_BROADCASTER) SHELL_CMD_ARG(advertise, NULL, - " [mode: discov, non_discov] " + " [mode: discov, non_discov] " "[filter-accept-list: fal, fal-scan, fal-conn] [identity] [no-name] " "[one-time] [name-ad] [appearance] " "[disable-37] [disable-38] [disable-39]", @@ -4565,7 +4635,8 @@ SHELL_STATIC_SUBCMD_SET_CREATE(bt_cmds, SHELL_CMD_ARG(adv-create, NULL, EXT_ADV_PARAM, cmd_adv_create, 2, 11), SHELL_CMD_ARG(adv-param, NULL, EXT_ADV_PARAM, cmd_adv_param, 2, 11), SHELL_CMD_ARG(adv-data, NULL, " [scan-response ] " - " [appearance] ", + " [appearance] " + "[name ] [dev-name]", cmd_adv_data, 1, 16), SHELL_CMD_ARG(adv-start, NULL, "[timeout ] [num-events ]", diff --git a/subsys/canbus/isotp/isotp.c b/subsys/canbus/isotp/isotp.c index b36665a2776..dcb3438dc29 100644 --- a/subsys/canbus/isotp/isotp.c +++ b/subsys/canbus/isotp/isotp.c @@ -595,8 +595,10 @@ static inline int add_ff_sf_filter(struct isotp_recv_ctx *rctx) if ((rctx->rx_addr.flags & ISOTP_MSG_FIXED_ADDR) != 0) { mask = ISOTP_FIXED_ADDR_RX_MASK; - } else { + } else if ((rctx->rx_addr.flags & ISOTP_MSG_IDE) != 0) { mask = CAN_EXT_ID_MASK; + } else { + mask = CAN_STD_ID_MASK; } prepare_filter(&filter, &rctx->rx_addr, mask); @@ -1167,8 +1169,15 @@ static void send_work_handler(struct k_work *item) static inline int add_fc_filter(struct isotp_send_ctx *sctx) { struct can_filter filter; + uint32_t mask; + + if ((sctx->rx_addr.flags & ISOTP_MSG_IDE) != 0) { + mask = CAN_EXT_ID_MASK; + } else { + mask = CAN_STD_ID_MASK; + } - prepare_filter(&filter, &sctx->rx_addr, CAN_EXT_ID_MASK); + prepare_filter(&filter, &sctx->rx_addr, mask); sctx->filter_id = can_add_rx_filter(sctx->can_dev, send_can_rx_cb, sctx, &filter); diff --git a/subsys/debug/CMakeLists.txt b/subsys/debug/CMakeLists.txt index a6e59d54325..d9cbc68b975 100644 --- a/subsys/debug/CMakeLists.txt +++ b/subsys/debug/CMakeLists.txt @@ -29,3 +29,8 @@ zephyr_sources_ifdef( CONFIG_GDBSTUB_SERIAL_BACKEND gdbstub/gdbstub_backend_serial.c ) + +zephyr_sources_ifdef( + CONFIG_MIPI_STP_DECODER + mipi_stp_decoder.c + ) diff --git a/subsys/debug/Kconfig b/subsys/debug/Kconfig index 1f14b80b47c..5fd5d9bfd5d 100644 --- a/subsys/debug/Kconfig +++ b/subsys/debug/Kconfig @@ -444,3 +444,9 @@ config SEGGER_DEBUGMON This option will enable Segger's implementation of the debug monitor interrupt, overriding the default z_arm_debug_monitor symbol. + +config MIPI_STP_DECODER + bool "MIPI STPv2 decoder" + depends on !BIG_ENDIAN + help + Module decodes a stream of STPv2 data. diff --git a/subsys/debug/mipi_stp_decoder.c b/subsys/debug/mipi_stp_decoder.c new file mode 100644 index 00000000000..39aacbdd4d7 --- /dev/null +++ b/subsys/debug/mipi_stp_decoder.c @@ -0,0 +1,791 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA. + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include + +#if defined(CONFIG_CPU_CORTEX_M) && !defined(CONFIG_CPU_CORTEX_M0) +#define UNALIGNED_ACCESS_SUPPORTED 1 +#else +#define UNALIGNED_ACCESS_SUPPORTED 0 +#endif + +enum stp_state { + STP_STATE_OP, + STP_STATE_DATA, + STP_STATE_TS, + STP_STATE_OUT_OF_SYNC, +}; + +enum stp_id { + STP_NULL, + STP_M8, + STP_MERR, + STP_C8, + STP_D8, + STP_D16, + STP_D32, + STP_D64, + STP_D8MTS, + STP_D16MTS, + STP_D32MTS, + STP_D64MTS, + STP_D4, + STP_D4MTS, + STP_FLAG_TS, + STP_VERSION, + STP_TAG_3NIBBLE_OP = STP_VERSION, + STP_NULL_TS, + STP_USER, + STP_USER_TS, + STP_TIME, + STP_TIME_TS, + STP_TRIG, + STP_TRIG_TS, + STP_FREQ, + STP_FREQ_TS, + STP_XSYNC, + STP_XSYNC_TS, + STP_FREQ_40, + STP_TAG_4NIBBLE_OP = STP_FREQ_40, + STP_FREQ_40_TS, + STP_DIP, + STP_M16, + STP_TAG_2NIBBLE_OP = STP_M16, + STP_GERR, + STP_C16, + STP_D8TS, + STP_D16TS, + STP_D32TS, + STP_D64TS, + STP_D8M, + STP_D16M, + STP_D32M, + STP_D64M, + STP_D4TS, + STP_D4M, + STP_FLAG, + STP_ASYNC, + STP_INVALID, + STP_OP_MAX +}; + +#define STP_LONG_OP_ID 0xF +#define STP_2B_OP_ID 0xF0 + +#define STP_VAR_DATA 0xff + +typedef void (*stp_cb)(uint64_t data, uint64_t ts); + +struct stp_item { + const char *name; + enum stp_id type; + uint8_t id[3]; + uint8_t id_ncnt; + uint8_t d_ncnt; + bool has_ts; + stp_cb cb; +}; + +#define STP_ITEM(_type, _id, _id_ncnt, _d_ncnt, _has_ts, _cb) \ + { \ + .name = STRINGIFY(_type), .type = _type, .id = {__DEBRACKET _id}, \ + .id_ncnt = _id_ncnt, .d_ncnt = _d_ncnt, \ + .has_ts = _has_ts, .cb = (stp_cb)_cb \ + } + +static struct mipi_stp_decoder_config cfg; +static uint64_t prev_ts; +static uint64_t base_ts; +static enum stp_state state; +static size_t ntotal; +static size_t ncnt; +static size_t noff; +static uint16_t curr_ch; + +static void data4_cb(uint64_t data, uint64_t ts) +{ + ARG_UNUSED(ts); + union mipi_stp_decoder_data d = {.data = data}; + + cfg.cb(STP_DATA4, d, NULL, false); +} + +static void data8_cb(uint64_t data, uint64_t ts) +{ + ARG_UNUSED(ts); + union mipi_stp_decoder_data d = {.data = data}; + + cfg.cb(STP_DATA8, d, NULL, false); +} + +static void data16_cb(uint64_t data, uint64_t ts) +{ + ARG_UNUSED(ts); + union mipi_stp_decoder_data d = {.data = data}; + + cfg.cb(STP_DATA16, d, NULL, false); +} + +static void data32_cb(uint64_t data, uint64_t ts) +{ + ARG_UNUSED(ts); + union mipi_stp_decoder_data d = {.data = data}; + + cfg.cb(STP_DATA32, d, NULL, false); +} + +static void data64_cb(uint64_t data, uint64_t ts) +{ + ARG_UNUSED(ts); + union mipi_stp_decoder_data d = {.data = data}; + + cfg.cb(STP_DATA64, d, NULL, false); +} + +static void data4_m_cb(uint64_t data, uint64_t ts) +{ + ARG_UNUSED(ts); + union mipi_stp_decoder_data d = {.data = data}; + + cfg.cb(STP_DATA4, d, NULL, true); +} + +static void data8_m_cb(uint64_t data, uint64_t ts) +{ + ARG_UNUSED(ts); + union mipi_stp_decoder_data d = {.data = data}; + + cfg.cb(STP_DATA8, d, NULL, true); +} + +static void data16_m_cb(uint64_t data, uint64_t ts) +{ + ARG_UNUSED(ts); + union mipi_stp_decoder_data d = {.data = data}; + + cfg.cb(STP_DATA16, d, NULL, true); +} + +static void data32_m_cb(uint64_t data, uint64_t ts) +{ + ARG_UNUSED(ts); + union mipi_stp_decoder_data d = {.data = data}; + + cfg.cb(STP_DATA32, d, NULL, true); +} + +static void data64_m_cb(uint64_t data, uint64_t ts) +{ + ARG_UNUSED(ts); + union mipi_stp_decoder_data d = {.data = data}; + + cfg.cb(STP_DATA64, d, NULL, true); +} + +static void data4_ts_cb(uint64_t data, uint64_t ts) +{ + union mipi_stp_decoder_data d = {.data = data}; + + cfg.cb(STP_DATA4, d, &ts, false); +} + +static void data8_ts_cb(uint64_t data, uint64_t ts) +{ + union mipi_stp_decoder_data d = {.data = data}; + + cfg.cb(STP_DATA8, d, &ts, false); +} + +static void data16_ts_cb(uint64_t data, uint64_t ts) +{ + union mipi_stp_decoder_data d = {.data = data}; + + cfg.cb(STP_DATA16, d, &ts, false); +} + +static void data32_ts_cb(uint64_t data, uint64_t ts) +{ + union mipi_stp_decoder_data d = {.data = data}; + + cfg.cb(STP_DATA32, d, &ts, false); +} + +static void data64_ts_cb(uint64_t data, uint64_t ts) +{ + union mipi_stp_decoder_data d = {.data = data}; + + cfg.cb(STP_DATA64, d, &ts, false); +} + +static void data4_mts_cb(uint64_t data, uint64_t ts) +{ + union mipi_stp_decoder_data d = {.data = data}; + + cfg.cb(STP_DATA4, d, &ts, true); +} + +static void data8_mts_cb(uint64_t data, uint64_t ts) +{ + union mipi_stp_decoder_data d = {.data = data}; + + cfg.cb(STP_DATA8, d, &ts, true); +} + +static void data16_mts_cb(uint64_t data, uint64_t ts) +{ + union mipi_stp_decoder_data d = {.data = data}; + + cfg.cb(STP_DATA16, d, &ts, true); +} + +static void data32_mts_cb(uint64_t data, uint64_t ts) +{ + union mipi_stp_decoder_data d = {.data = data}; + + cfg.cb(STP_DATA32, d, &ts, true); +} + +static void data64_mts_cb(uint64_t data, uint64_t ts) +{ + union mipi_stp_decoder_data d = {.data = data}; + + cfg.cb(STP_DATA64, d, &ts, true); +} + +static void master_cb(uint64_t id, uint64_t ts) +{ + ARG_UNUSED(ts); + uint16_t m_id = (uint16_t)id; + union mipi_stp_decoder_data data = {.id = m_id}; + + curr_ch = 0; + + cfg.cb(STP_DECODER_MASTER, data, NULL, false); +} + +static void channel16_cb(uint64_t id, uint64_t ts) +{ + uint16_t ch = (uint16_t)id; + + curr_ch = 0xFF00 & ch; + + ARG_UNUSED(ts); + union mipi_stp_decoder_data data = {.id = ch}; + + cfg.cb(STP_DECODER_CHANNEL, data, NULL, false); +} +static void channel_cb(uint64_t id, uint64_t ts) +{ + uint16_t ch = (uint16_t)id; + + ch |= curr_ch; + + ARG_UNUSED(ts); + union mipi_stp_decoder_data data = {.id = ch}; + + cfg.cb(STP_DECODER_CHANNEL, data, NULL, false); +} + +static void merror_cb(uint64_t err, uint64_t ts) +{ + ARG_UNUSED(ts); + union mipi_stp_decoder_data data = {.err = (uint32_t)err}; + + cfg.cb(STP_DECODER_MERROR, data, NULL, false); +} + +static void gerror_cb(uint64_t err, uint64_t ts) +{ + ARG_UNUSED(ts); + union mipi_stp_decoder_data data = {.err = (uint32_t)err}; + + cfg.cb(STP_DECODER_GERROR, data, NULL, false); +} + +static void flag_cb(uint64_t data, uint64_t ts) +{ + ARG_UNUSED(ts); + ARG_UNUSED(data); + union mipi_stp_decoder_data dummy = {.dummy = 0}; + + cfg.cb(STP_DECODER_FLAG, dummy, NULL, false); +} + +static void flag_ts_cb(uint64_t unused, uint64_t ts) +{ + ARG_UNUSED(unused); + union mipi_stp_decoder_data data = {.dummy = 0}; + + cfg.cb(STP_DECODER_FLAG, data, &ts, false); +} + +static void version_cb(uint64_t version, uint64_t ts) +{ + ARG_UNUSED(ts); + + curr_ch = 0; + + union mipi_stp_decoder_data data = {.ver = version}; + + cfg.cb(STP_DECODER_VERSION, data, NULL, false); +} + +static void notsup_cb(uint64_t data, uint64_t ts) +{ + ARG_UNUSED(ts); + ARG_UNUSED(data); + + union mipi_stp_decoder_data dummy = {.dummy = 0}; + + cfg.cb(STP_DECODER_NOT_SUPPORTED, dummy, NULL, false); +} + +static void freq_cb(uint64_t freq, uint64_t ts) +{ + ARG_UNUSED(ts); + + union mipi_stp_decoder_data data = {.freq = freq}; + + cfg.cb(STP_DECODER_FREQ, data, NULL, false); +} + +static void freq_ts_cb(uint64_t freq, uint64_t ts) +{ + union mipi_stp_decoder_data data = {.freq = freq}; + + cfg.cb(STP_DECODER_FREQ, data, &ts, false); +} + +static void null_cb(uint64_t data, uint64_t ts) +{ + ARG_UNUSED(ts); + ARG_UNUSED(data); + + union mipi_stp_decoder_data dummy = {.dummy = 0}; + + cfg.cb(STP_DECODER_NULL, dummy, NULL, false); +} + +static void async_cb(uint64_t data, uint64_t ts) +{ + ARG_UNUSED(ts); + ARG_UNUSED(data); + + union mipi_stp_decoder_data dummy = {.dummy = 0}; + + cfg.cb(STP_DECODER_ASYNC, dummy, NULL, false); +} + +static const struct stp_item items[] = { + STP_ITEM(STP_NULL, (0x0), 1, 0, false, null_cb), + STP_ITEM(STP_M8, (0x1), 1, 2, false, master_cb), + STP_ITEM(STP_MERR, (0x2), 1, 2, false, merror_cb), + STP_ITEM(STP_C8, (0x3), 1, 2, false, channel_cb), + STP_ITEM(STP_D8, (0x4), 1, 2, false, data8_cb), + STP_ITEM(STP_D16, (0x5), 1, 4, false, data16_cb), + STP_ITEM(STP_D32, (0x6), 1, 8, false, data32_cb), + STP_ITEM(STP_D64, (0x7), 1, 16, false, data64_cb), + STP_ITEM(STP_D8MTS, (0x8), 1, 2, true, data8_mts_cb), + STP_ITEM(STP_D16MTS, (0x9), 1, 4, true, data16_mts_cb), + STP_ITEM(STP_D32MTS, (0xa), 1, 8, true, data32_mts_cb), + STP_ITEM(STP_D64MTS, (0xb), 1, 16, true, data64_mts_cb), + STP_ITEM(STP_D4, (0xc), 1, 1, false, data4_cb), + STP_ITEM(STP_D4MTS, (0xd), 1, 1, true, data4_mts_cb), + STP_ITEM(STP_FLAG_TS, (0xe), 1, 0, true, flag_ts_cb), + STP_ITEM(STP_VERSION, (0xf0, 0x00), 3, 1, false, version_cb), + STP_ITEM(STP_NULL_TS, (0xf0, 0x01), 3, 0, true, notsup_cb), + STP_ITEM(STP_USER, (0xf0, 0x02), 3, 0, false, notsup_cb), + STP_ITEM(STP_USER_TS, (0xf0, 0x03), 3, 0, true, notsup_cb), + STP_ITEM(STP_TIME, (0xf0, 0x04), 3, 0, false, notsup_cb), + STP_ITEM(STP_TIME_TS, (0xf0, 0x05), 3, 0, true, notsup_cb), + STP_ITEM(STP_TRIG, (0xf0, 0x06), 3, 0, false, notsup_cb), + STP_ITEM(STP_TRIG_TS, (0xf0, 0x07), 3, 0, true, notsup_cb), + STP_ITEM(STP_FREQ, (0xf0, 0x08), 3, 8, false, freq_cb), + STP_ITEM(STP_FREQ_TS, (0xf0, 0x09), 3, 8, true, freq_ts_cb), + STP_ITEM(STP_XSYNC, (0xf0, 0x0a), 3, 0, false, notsup_cb), + STP_ITEM(STP_XSYNC_TS, (0xf0, 0x0b), 3, 0, true, notsup_cb), + STP_ITEM(STP_FREQ_40, (0xf0, 0xf0), 4, 10, false, freq_cb), + STP_ITEM(STP_FREQ_40_TS, (0xf0, 0xf1), 4, 0, true, notsup_cb), + STP_ITEM(STP_DIP, (0xf0, 0xf2), 4, 0, false, notsup_cb), + STP_ITEM(STP_M16, (0xf1), 2, 4, false, master_cb), + STP_ITEM(STP_GERR, (0xf2), 2, 2, false, gerror_cb), + STP_ITEM(STP_C16, (0xf3), 2, 4, false, channel16_cb), + STP_ITEM(STP_D8TS, (0xf4), 2, 2, true, data8_ts_cb), + STP_ITEM(STP_D16TS, (0xf5), 2, 4, true, data16_ts_cb), + STP_ITEM(STP_D32TS, (0xf6), 2, 8, true, data32_ts_cb), + STP_ITEM(STP_D64TS, (0xf7), 2, 16, true, data64_ts_cb), + STP_ITEM(STP_D8M, (0xf8), 2, 2, false, data8_m_cb), + STP_ITEM(STP_D16M, (0xf9), 2, 4, false, data16_m_cb), + STP_ITEM(STP_D32M, (0xfa), 2, 8, false, data32_m_cb), + STP_ITEM(STP_D64M, (0xfb), 2, 16, false, data64_m_cb), + STP_ITEM(STP_D4TS, (0xfc), 2, 1, true, data4_ts_cb), + STP_ITEM(STP_D4M, (0xfd), 2, 1, false, data4_m_cb), + STP_ITEM(STP_FLAG, (0xfe), 2, 0, false, flag_cb), + STP_ITEM(STP_ASYNC, (0xff, 0xff, 0xff), 6, 16, false, async_cb), + STP_ITEM(STP_INVALID, (0x0), 0, 0, false, NULL), +}; + +/** @brief Decode a nibble and read opcode from the stream. + * + * Function reads a nibble and continues or starts decoding of a STP opcode. + * + * @param data Pointer to the stream. + * @param[in,out] noff Offset (in nibbles). + * @param nlen Length (in nibbles). + * @param[in,out] ncnt Current number of nibbles + * @param[in,out] ntotal Number of nibbles in the opcode. + * + * @retval STP_INVALID Opcode decoding is in progress. + * @retval opcode Decoded opcode. + */ +static inline uint8_t get_nibble(const uint8_t *data, size_t noff) +{ + uint8_t ret = data[noff / 2]; + + if (noff & 0x1UL) { + ret >>= 4; + } + + ret &= 0x0F; + + return ret; +} + +static inline void get_nibbles64(const uint8_t *src, size_t src_noff, uint8_t *dst, size_t dst_noff, + size_t nlen) +{ + bool src_ba = (src_noff & 0x1UL) == 0; + bool dst_ba = (dst_noff & 0x1UL) == 0; + uint64_t *src64 = (uint64_t *)&src[src_noff / 2]; + uint64_t *dst64 = (uint64_t *)&dst[dst_noff / 2]; + + if (nlen == 16) { + /* dst must be aligned. */ + if (src_ba) { + uint32_t *s32 = (uint32_t *)src64; + uint32_t *d32 = (uint32_t *)dst64; + + d32[0] = s32[0]; + d32[1] = s32[1]; + } else { + uint64_t part_a = src64[0] >> 4; + uint64_t part_b = src64[1] << 60; + + dst64[0] = part_a | part_b; + } + return; + } + + uint64_t mask = BIT64_MASK(nlen * 4) << (src_ba ? 0 : 4); + uint64_t src_d = src64[0] & mask; + + if (((src_noff ^ dst_noff) & 0x1UL) == 0) { + dst64[0] |= src_d; + } else if (dst_ba) { + dst64[0] |= (src_d >> 4); + } else { + dst64[0] |= (src_d << 4); + } +} + +/* Function performs getting nibbles in less efficient way but does not use unaligned + * access which may not be supported by some platforms. + */ +static void get_nibbles_unaligned(const uint8_t *src, size_t src_noff, uint8_t *dst, + size_t dst_noff, size_t nlen) +{ + for (size_t i = 0; i < nlen; i++) { + size_t idx = (src_noff + i) / 2; + size_t ni = (src_noff + i) & 0x1; + uint8_t n = src[idx] >> (ni ? 4 : 0); + size_t d_idx = (dst_noff + i) / 2; + size_t dni = (dst_noff + i) & 0x1; + + if (dni == 0) { + dst[d_idx] = n; + } else { + dst[d_idx] |= n << 4; + } + } +} + +static inline void get_nibbles(const uint8_t *src, size_t src_noff, uint8_t *dst, size_t dst_noff, + size_t nlen) +{ + if (!UNALIGNED_ACCESS_SUPPORTED) { + get_nibbles_unaligned(src, src_noff, dst, dst_noff, nlen); + return; + } + + bool src_ba = (src_noff & 0x1UL) == 0; + bool dst_ba = (dst_noff & 0x1UL) == 0; + uint32_t *src32 = (uint32_t *)&src[src_noff / 2]; + uint32_t *dst32 = (uint32_t *)&dst[dst_noff / 2]; + + if (nlen > 8) { + get_nibbles64(src, src_noff, dst, dst_noff, nlen); + return; + } else if (nlen == 8) { + /* dst must be aligned. */ + if (src_ba) { + dst32[0] = src32[0]; + } else { + uint32_t part_a = src32[0] >> 4; + uint32_t part_b = src32[1] << 28; + + dst32[0] = part_a | part_b; + } + return; + } + + uint32_t mask = BIT_MASK(nlen * 4) << (src_ba ? 0 : 4); + uint32_t src_d = src32[0] & mask; + + if (((src_noff ^ dst_noff) & 0x1UL) == 0) { + dst32[0] |= src_d; + } else if (dst_ba) { + dst32[0] |= (src_d >> 4); + } else { + dst32[0] |= (src_d << 4); + } +} + +/* Function swaps nibbles in a byte. */ +static uint8_t swap8(uint8_t byte) +{ + return (byte << 4) | (byte >> 4); +} + +/* Function swaps nibbles in a 16 bit variable. */ +static uint16_t swap16(uint16_t halfword) +{ + halfword = __builtin_bswap16(halfword); + uint16_t d1 = (halfword & 0xf0f0) >> 4; + uint16_t d2 = (halfword & 0x0f0f) << 4; + + return d1 | d2; +} + +/* Function swaps nibbles in a 32 bit word. */ +static uint32_t swap32(uint32_t word) +{ + word = __builtin_bswap32(word); + uint32_t d1 = (word & 0xf0f0f0f0) >> 4; + uint32_t d2 = (word & 0x0f0f0f0f) << 4; + + return d1 | d2; +} + +/* Function swaps nibbles in a 64 bit word. */ +static uint64_t swap64(uint64_t dword) +{ + uint32_t l = (uint32_t)dword; + uint32_t u = (uint32_t)(dword >> 32); + + return ((uint64_t)swap32(l) << 32) | (uint64_t)swap32(u); +} + +static void swap_n(uint8_t *data, uint32_t n) +{ + switch (n) { + case 2: + *data = swap8(*data); + break; + case 4: + *(uint16_t *)data = swap16(*(uint16_t *)data); + break; + case 8: + *(uint32_t *)data = swap32(*(uint32_t *)data); + break; + case 16: + *(uint64_t *)data = swap64(*(uint64_t *)data); + break; + default: + *(uint64_t *)data = swap64(*(uint64_t *)data); + *(uint64_t *)data >>= (4 * (16 - n)); + break; + } +} + +static enum stp_id get_op(const uint8_t *data, size_t *noff, size_t *nlen, size_t *ncnt, + size_t *ntotal) +{ + uint8_t op = 0; + + op = get_nibble(data, *noff); + + *noff += 1; + *ncnt += 1; + if (*ntotal == 0 && *ncnt == 1) { + /* Starting to read op. */ + /* op code has only 1 nibble. */ + if (op != 0xF) { + return (enum stp_id)op; + } + } else if (*ncnt == 2) { + if (op == 0xF) { + /* ASYNC*/ + *ntotal = 6; + } else if (op != 0) { + return (enum stp_id)(STP_TAG_2NIBBLE_OP - 1 + op); + } + } else if (*ncnt == 3) { + if (op != 0xf) { + return (enum stp_id)(STP_TAG_3NIBBLE_OP + op); + } else if (*ntotal == 0) { + *ntotal = 4; + } + } else if (*ncnt == *ntotal) { + if (*ntotal == 4) { + return (enum stp_id)(STP_TAG_4NIBBLE_OP + op); + } else { + return STP_ASYNC; + } + } + + return STP_INVALID; +} + +void mipi_stp_decoder_sync_loss(void) +{ + state = STP_STATE_OUT_OF_SYNC; + ncnt = 0; + ntotal = 0; +} + +int mipi_stp_decoder_decode(const uint8_t *data, size_t len) +{ + static enum stp_id curr_id = STP_INVALID; + static uint8_t data_buf[8] __aligned(sizeof(uint64_t)); + static uint8_t ts_buf[8] __aligned(sizeof(uint64_t)); + uint64_t *data64 = (uint64_t *)data_buf; + uint64_t *ts64 = (uint64_t *)ts_buf; + size_t nlen = 2 * len; + + do { + switch (state) { + case STP_STATE_OUT_OF_SYNC: { + uint8_t b = get_nibble(data, noff); + + noff++; + if (ncnt < 21 && b == 0xF) { + ncnt++; + } else if (ncnt == 21 && b == 0) { + curr_id = STP_INVALID; + ncnt = 0; + + items[STP_ASYNC].cb(0, 0); + state = STP_STATE_OP; + } else { + ncnt = 0; + } + break; + } + case STP_STATE_OP: { + curr_id = get_op(data, &noff, &nlen, &ncnt, &ntotal); + if (curr_id != STP_INVALID) { + ntotal = items[curr_id].d_ncnt; + ncnt = 0; + if (ntotal > 0) { + state = STP_STATE_DATA; + data64[0] = 0; + } else if (items[curr_id].has_ts) { + state = STP_STATE_TS; + } else { + /* item without data and ts, notify. */ + items[curr_id].cb(0, 0); + curr_id = STP_INVALID; + } + } + break; + } + case STP_STATE_DATA: { + size_t ncpy = MIN(ntotal - ncnt, nlen - noff); + + get_nibbles(data, noff, data_buf, ncnt, ncpy); + + ncnt += ncpy; + noff += ncpy; + if (ncnt == ntotal) { + swap_n(data_buf, ntotal); + ncnt = 0; + if (items[curr_id].has_ts) { + ncnt = 0; + ntotal = 0; + state = STP_STATE_TS; + } else { + items[curr_id].cb(*data64, 0); + curr_id = STP_INVALID; + state = STP_STATE_OP; + ntotal = 0; + ncnt = 0; + } + } + break; + } + case STP_STATE_TS: + if (ntotal == 0 && ncnt == 0) { + /* TS to be read but length is unknown yet */ + *ts64 = 0; + ntotal = get_nibble(data, noff); + noff++; + /* Values up to 12 represents number of nibbles on which + * timestamp is encoded. Above are the exceptions: + * - 13 => 14 nibbles + * - 14 => 16 nibbles + */ + if (ntotal > 12) { + if (ntotal == 13) { + ntotal = 14; + base_ts = ~BIT64_MASK(4 * ntotal) & prev_ts; + } else { + ntotal = 16; + base_ts = 0; + } + } else { + base_ts = ~BIT64_MASK(4 * ntotal) & prev_ts; + } + + } else { + size_t ncpy = MIN(ntotal - ncnt, nlen - noff); + + get_nibbles(data, noff, ts_buf, ncnt, ncpy); + ncnt += ncpy; + noff += ncpy; + if (ncnt == ntotal) { + swap_n(ts_buf, ntotal); + prev_ts = base_ts | *ts64; + items[curr_id].cb(*data64, prev_ts); + curr_id = STP_INVALID; + state = STP_STATE_OP; + ntotal = 0; + ncnt = 0; + } + } + break; + + default: + break; + } + } while (noff < nlen); + + noff = 0; + + return 0; +} + +int mipi_stp_decoder_init(const struct mipi_stp_decoder_config *config) +{ + state = config->start_out_of_sync ? STP_STATE_OUT_OF_SYNC : STP_STATE_OP; + ntotal = 0; + ncnt = 0; + cfg = *config; + prev_ts = 0; + base_ts = 0; + noff = 0; + + return 0; +} diff --git a/subsys/demand_paging/backing_store/backing_store_qemu_x86_tiny.c b/subsys/demand_paging/backing_store/backing_store_qemu_x86_tiny.c index 9f100649d49..28fb66fec4b 100644 --- a/subsys/demand_paging/backing_store/backing_store_qemu_x86_tiny.c +++ b/subsys/demand_paging/backing_store/backing_store_qemu_x86_tiny.c @@ -45,7 +45,7 @@ int k_mem_paging_backing_store_location_get(struct z_page_frame *pf, bool page_fault) { /* Simply returns the virtual address */ - *location = POINTER_TO_UINT(pf->addr); + *location = POINTER_TO_UINT(z_page_frame_to_virt(pf)); return 0; } diff --git a/subsys/demand_paging/eviction/nru.c b/subsys/demand_paging/eviction/nru.c index 83c4a3b53d7..7429b4e3fdb 100644 --- a/subsys/demand_paging/eviction/nru.c +++ b/subsys/demand_paging/eviction/nru.c @@ -36,7 +36,7 @@ static void nru_periodic_update(struct k_timer *timer) } /* Clear accessed bit in page tables */ - (void)arch_page_info_get(pf->addr, NULL, true); + (void)arch_page_info_get(z_page_frame_to_virt(pf), NULL, true); } irq_unlock(key); @@ -58,7 +58,7 @@ struct z_page_frame *k_mem_paging_eviction_select(bool *dirty_ptr) continue; } - flags = arch_page_info_get(pf->addr, NULL, false); + flags = arch_page_info_get(z_page_frame_to_virt(pf), NULL, false); accessed = (flags & ARCH_DATA_PAGE_ACCESSED) != 0UL; dirty = (flags & ARCH_DATA_PAGE_DIRTY) != 0UL; diff --git a/subsys/emul/espi/emul_espi_host.c b/subsys/emul/espi/emul_espi_host.c index 97aaedcb31e..f1a4a369221 100644 --- a/subsys/emul/espi/emul_espi_host.c +++ b/subsys/emul/espi/emul_espi_host.c @@ -25,39 +25,40 @@ struct vw_data { /* The level(state) of the virtual wire */ uint8_t level; /* The direction of the virtual wire. Possible values: - * ESPI_MASTER_TO_SLAVE or ESPI_SLAVE_TO_MASTER */ + * ESPI_CONTROLLER_TO_TARGET or ESPI_TARGET_TO_CONTROLLER + */ uint8_t dir; }; /** Declare the default state of virtual wires */ const static struct vw_data vw_state_default[] = { - { ESPI_VWIRE_SIGNAL_SLP_S3, 0, ESPI_MASTER_TO_SLAVE }, - { ESPI_VWIRE_SIGNAL_SLP_S4, 0, ESPI_MASTER_TO_SLAVE }, - { ESPI_VWIRE_SIGNAL_SLP_S5, 0, ESPI_MASTER_TO_SLAVE }, - { ESPI_VWIRE_SIGNAL_SUS_STAT, 0, ESPI_MASTER_TO_SLAVE }, - { ESPI_VWIRE_SIGNAL_PLTRST, 0, ESPI_MASTER_TO_SLAVE }, - { ESPI_VWIRE_SIGNAL_OOB_RST_WARN, 0, ESPI_MASTER_TO_SLAVE }, - { ESPI_VWIRE_SIGNAL_OOB_RST_ACK, 0, ESPI_SLAVE_TO_MASTER }, - { ESPI_VWIRE_SIGNAL_WAKE, 0, ESPI_SLAVE_TO_MASTER }, - { ESPI_VWIRE_SIGNAL_PME, 0, ESPI_SLAVE_TO_MASTER }, - { ESPI_VWIRE_SIGNAL_SLV_BOOT_DONE, 0, ESPI_SLAVE_TO_MASTER }, - { ESPI_VWIRE_SIGNAL_ERR_FATAL, 0, ESPI_SLAVE_TO_MASTER }, - { ESPI_VWIRE_SIGNAL_ERR_NON_FATAL, 0, ESPI_SLAVE_TO_MASTER }, - { ESPI_VWIRE_SIGNAL_SLV_BOOT_STS, 0, ESPI_SLAVE_TO_MASTER }, - { ESPI_VWIRE_SIGNAL_SCI, 0, ESPI_SLAVE_TO_MASTER }, - { ESPI_VWIRE_SIGNAL_SMI, 0, ESPI_SLAVE_TO_MASTER }, - { ESPI_VWIRE_SIGNAL_RST_CPU_INIT, 0, ESPI_SLAVE_TO_MASTER }, - { ESPI_VWIRE_SIGNAL_HOST_RST_ACK, 0, ESPI_SLAVE_TO_MASTER }, - { ESPI_VWIRE_SIGNAL_HOST_RST_WARN, 0, ESPI_MASTER_TO_SLAVE }, - { ESPI_VWIRE_SIGNAL_SUS_ACK, 0, ESPI_SLAVE_TO_MASTER }, - { ESPI_VWIRE_SIGNAL_DNX_ACK, 0, ESPI_SLAVE_TO_MASTER }, - { ESPI_VWIRE_SIGNAL_SUS_WARN, 0, ESPI_MASTER_TO_SLAVE }, - { ESPI_VWIRE_SIGNAL_SUS_PWRDN_ACK, 0, ESPI_MASTER_TO_SLAVE }, - { ESPI_VWIRE_SIGNAL_SLP_A, 0, ESPI_MASTER_TO_SLAVE }, - { ESPI_VWIRE_SIGNAL_SLP_LAN, 0, ESPI_MASTER_TO_SLAVE }, - { ESPI_VWIRE_SIGNAL_SLP_WLAN, 0, ESPI_MASTER_TO_SLAVE }, - { ESPI_VWIRE_SIGNAL_HOST_C10, 0, ESPI_MASTER_TO_SLAVE }, - { ESPI_VWIRE_SIGNAL_DNX_WARN, 0, ESPI_MASTER_TO_SLAVE }, + { ESPI_VWIRE_SIGNAL_SLP_S3, 0, ESPI_CONTROLLER_TO_TARGET }, + { ESPI_VWIRE_SIGNAL_SLP_S4, 0, ESPI_CONTROLLER_TO_TARGET }, + { ESPI_VWIRE_SIGNAL_SLP_S5, 0, ESPI_CONTROLLER_TO_TARGET }, + { ESPI_VWIRE_SIGNAL_SUS_STAT, 0, ESPI_CONTROLLER_TO_TARGET }, + { ESPI_VWIRE_SIGNAL_PLTRST, 0, ESPI_CONTROLLER_TO_TARGET }, + { ESPI_VWIRE_SIGNAL_OOB_RST_WARN, 0, ESPI_CONTROLLER_TO_TARGET }, + { ESPI_VWIRE_SIGNAL_OOB_RST_ACK, 0, ESPI_TARGET_TO_CONTROLLER }, + { ESPI_VWIRE_SIGNAL_WAKE, 0, ESPI_TARGET_TO_CONTROLLER }, + { ESPI_VWIRE_SIGNAL_PME, 0, ESPI_TARGET_TO_CONTROLLER }, + { ESPI_VWIRE_SIGNAL_TARGET_BOOT_DONE, 0, ESPI_TARGET_TO_CONTROLLER }, + { ESPI_VWIRE_SIGNAL_ERR_FATAL, 0, ESPI_TARGET_TO_CONTROLLER }, + { ESPI_VWIRE_SIGNAL_ERR_NON_FATAL, 0, ESPI_TARGET_TO_CONTROLLER }, + { ESPI_VWIRE_SIGNAL_TARGET_BOOT_STS, 0, ESPI_TARGET_TO_CONTROLLER }, + { ESPI_VWIRE_SIGNAL_SCI, 0, ESPI_TARGET_TO_CONTROLLER }, + { ESPI_VWIRE_SIGNAL_SMI, 0, ESPI_TARGET_TO_CONTROLLER }, + { ESPI_VWIRE_SIGNAL_RST_CPU_INIT, 0, ESPI_TARGET_TO_CONTROLLER }, + { ESPI_VWIRE_SIGNAL_HOST_RST_ACK, 0, ESPI_TARGET_TO_CONTROLLER }, + { ESPI_VWIRE_SIGNAL_HOST_RST_WARN, 0, ESPI_CONTROLLER_TO_TARGET }, + { ESPI_VWIRE_SIGNAL_SUS_ACK, 0, ESPI_TARGET_TO_CONTROLLER }, + { ESPI_VWIRE_SIGNAL_DNX_ACK, 0, ESPI_TARGET_TO_CONTROLLER }, + { ESPI_VWIRE_SIGNAL_SUS_WARN, 0, ESPI_CONTROLLER_TO_TARGET }, + { ESPI_VWIRE_SIGNAL_SUS_PWRDN_ACK, 0, ESPI_CONTROLLER_TO_TARGET }, + { ESPI_VWIRE_SIGNAL_SLP_A, 0, ESPI_CONTROLLER_TO_TARGET }, + { ESPI_VWIRE_SIGNAL_SLP_LAN, 0, ESPI_CONTROLLER_TO_TARGET }, + { ESPI_VWIRE_SIGNAL_SLP_WLAN, 0, ESPI_CONTROLLER_TO_TARGET }, + { ESPI_VWIRE_SIGNAL_HOST_C10, 0, ESPI_CONTROLLER_TO_TARGET }, + { ESPI_VWIRE_SIGNAL_DNX_WARN, 0, ESPI_CONTROLLER_TO_TARGET }, }; #define NUMBER_OF_VWIRES ARRAY_SIZE(vw_state_default) @@ -131,7 +132,7 @@ static int emul_host_set_vw(const struct emul *target, idx = emul_host_find_index(data, vw); - if (idx < 0 || data->vw_state[idx].dir != ESPI_SLAVE_TO_MASTER) { + if (idx < 0 || data->vw_state[idx].dir != ESPI_TARGET_TO_CONTROLLER) { LOG_ERR("%s: invalid vw: %d", __func__, vw); return -EPERM; } @@ -149,7 +150,7 @@ static int emul_host_get_vw(const struct emul *target, idx = emul_host_find_index(data, vw); - if (idx < 0 || data->vw_state[idx].dir != ESPI_MASTER_TO_SLAVE) { + if (idx < 0 || data->vw_state[idx].dir != ESPI_CONTROLLER_TO_TARGET) { LOG_ERR("%s: invalid vw: %d", __func__, vw); return -EPERM; } @@ -178,7 +179,7 @@ int emul_espi_host_send_vw(const struct device *espi_dev, enum espi_vwire_signal data_host = emul_espi->target->data; idx = emul_host_find_index(data_host, vw); - if (idx < 0 || data_host->vw_state[idx].dir != ESPI_MASTER_TO_SLAVE) { + if (idx < 0 || data_host->vw_state[idx].dir != ESPI_CONTROLLER_TO_TARGET) { LOG_ERR("%s: invalid vw: %d", __func__, vw); return -EPERM; } diff --git a/subsys/fs/CMakeLists.txt b/subsys/fs/CMakeLists.txt index e6c66d304ce..fb774711543 100644 --- a/subsys/fs/CMakeLists.txt +++ b/subsys/fs/CMakeLists.txt @@ -30,7 +30,7 @@ if(CONFIG_FUSE_FS_ACCESS) zephyr_library_named(FS_FUSE) find_package(PkgConfig REQUIRED) pkg_search_module(FUSE REQUIRED fuse) - zephyr_include_directories(${FUSE_INCLUDE_DIR}) + zephyr_include_directories(${FUSE_INCLUDE_DIRS}) if (CONFIG_NATIVE_LIBRARY) target_link_options(native_simulator INTERFACE "-l${FUSE_LIBRARIES}") else() diff --git a/subsys/fs/ext2/ext2_diskops.c b/subsys/fs/ext2/ext2_diskops.c index 92fd298d644..7e6016a8bab 100644 --- a/subsys/fs/ext2/ext2_diskops.c +++ b/subsys/fs/ext2/ext2_diskops.c @@ -669,9 +669,11 @@ int64_t ext2_inode_remove_blocks(struct ext2_inode *inode, uint32_t first) max_lvl = get_level_offsets(inode->i_fs, first, offsets); - if (all_zero(offsets, max_lvl)) { - /* We remove also the first block because all blocks referenced from it will be - * deleted. + if (all_zero(&offsets[1], max_lvl)) { + /* The first block to remove is either: + * - one of the first 12 blocks in the indode + * - the first referenced block in the indirect block list; + * we remove also the indirect block */ start = offsets[0]; } else { diff --git a/subsys/fs/ext2/ext2_ops.c b/subsys/fs/ext2/ext2_ops.c index 1f8cbdaf04a..297601c5646 100644 --- a/subsys/fs/ext2/ext2_ops.c +++ b/subsys/fs/ext2/ext2_ops.c @@ -59,7 +59,7 @@ static int ext2_open(struct fs_file_t *filp, const char *fs_path, fs_mode_t flag /* Inodes allocated by lookup. Must be freed in manually. */ struct ext2_inode *found_inode = args.inode; - /* Not NULL iff FS_O_CREATE and found_inode == NULL */ + /* Not NULL if FS_O_CREATE and found_inode == NULL */ struct ext2_inode *parent = args.parent; /* File has to be created */ diff --git a/subsys/ipc/ipc_service/backends/ipc_icbmsg.c b/subsys/ipc/ipc_service/backends/ipc_icbmsg.c index 37594025313..4a3fdad1adf 100644 --- a/subsys/ipc/ipc_service/backends/ipc_icbmsg.c +++ b/subsys/ipc/ipc_service/backends/ipc_icbmsg.c @@ -501,7 +501,7 @@ static int send_control_message(struct backend_data *dev_data, enum msg_type msg r = icmsg_send(&conf->control_config, &dev_data->control_data, &message, sizeof(message)); k_mutex_unlock(&dev_data->mutex); - if (r < 0) { + if (r < sizeof(message)) { LOG_ERR("Cannot send over ICMsg, err %d", r); } return r; @@ -541,7 +541,7 @@ static int send_release(struct backend_data *dev_data, const uint8_t *buffer, * @param[in] size Actual size of the data, can be smaller than allocated, * but it cannot change number of required blocks. * - * @return O or negative error code. + * @return number of bytes sent in the message or negative error code. */ static int send_block(struct backend_data *dev_data, enum msg_type msg_type, uint8_t ept_addr, size_t tx_block_index, size_t size) @@ -656,7 +656,7 @@ static int match_bound_msg(struct backend_data *dev_data, size_t rx_block_index, * * @param[in] ept Endpoint to use. * - * @return O or negative error code. + * @return non-negative value in case of success or negative error code. */ static int send_bound_message(struct backend_data *dev_data, struct ept_data *ept) { @@ -992,7 +992,12 @@ static int send(const struct device *instance, void *token, const void *msg, siz memcpy(buffer, msg, len); /* Send data message. */ - return send_block(dev_data, MSG_DATA, ept->addr, r, len); + r = send_block(dev_data, MSG_DATA, ept->addr, r, len); + if (r < 0) { + return r; + } + + return len; } /** diff --git a/subsys/ipc/ipc_service/backends/ipc_rpmsg_static_vrings.c b/subsys/ipc/ipc_service/backends/ipc_rpmsg_static_vrings.c index 24653585202..a2c0883c054 100644 --- a/subsys/ipc/ipc_service/backends/ipc_rpmsg_static_vrings.c +++ b/subsys/ipc/ipc_service/backends/ipc_rpmsg_static_vrings.c @@ -325,13 +325,14 @@ static int mbox_init(const struct device *instance) { const struct backend_config_t *conf = instance->config; struct backend_data_t *data = instance->data; + struct k_work_queue_config wq_cfg = {.name = instance->name}; int prio, err; prio = (conf->wq_prio_type == PRIO_COOP) ? K_PRIO_COOP(conf->wq_prio) : K_PRIO_PREEMPT(conf->wq_prio); k_work_queue_init(&data->mbox_wq); - k_work_queue_start(&data->mbox_wq, mbox_stack[conf->id], WQ_STACK_SIZE, prio, NULL); + k_work_queue_start(&data->mbox_wq, mbox_stack[conf->id], WQ_STACK_SIZE, prio, &wq_cfg); if (IS_ENABLED(CONFIG_THREAD_NAME)) { char name[THREAD_MAX_NAME_LEN]; diff --git a/subsys/ipc/ipc_service/lib/icmsg_me.c b/subsys/ipc/ipc_service/lib/icmsg_me.c index 24e3ba6514e..b4d384e6bb0 100644 --- a/subsys/ipc/ipc_service/lib/icmsg_me.c +++ b/subsys/ipc/ipc_service/lib/icmsg_me.c @@ -5,6 +5,7 @@ */ #include +#include #include @@ -20,14 +21,24 @@ static void *icmsg_buffer_to_user_buffer(const void *icmsg_buffer) return (void *)(((char *)icmsg_buffer) + HEADER_SIZE); } -static size_t icmsg_buffer_len_to_user_buffer_len(size_t icmsg_buffer_len) +static ssize_t icmsg_buffer_len_to_user_buffer_len(size_t icmsg_buffer_len) { - return icmsg_buffer_len - HEADER_SIZE; + if (icmsg_buffer_len < HEADER_SIZE) { + return -EINVAL; + } + + return (ssize_t)(icmsg_buffer_len - HEADER_SIZE); } -static size_t user_buffer_len_to_icmsg_buffer_len(size_t user_buffer_len) +static ssize_t user_buffer_len_to_icmsg_buffer_len(size_t user_buffer_len) { - return user_buffer_len + HEADER_SIZE; + size_t ret; + + if (size_add_overflow(user_buffer_len, HEADER_SIZE, &ret)) { + return -EINVAL; + } + + return (ssize_t)ret; } static void set_ept_id_in_send_buffer(uint8_t *send_buffer, @@ -141,6 +152,7 @@ void icmsg_me_received_data(struct icmsg_me_data_t *data, icmsg_me_ept_id_t id, { int r; const struct ipc_ept_cfg *ept; + ssize_t user_buffer_len; r = icmsg_me_get_ept_cfg(data, id, &ept); if (r < 0) { @@ -151,10 +163,14 @@ void icmsg_me_received_data(struct icmsg_me_data_t *data, icmsg_me_ept_id_t id, return; } + user_buffer_len = icmsg_buffer_len_to_user_buffer_len(len); + if (user_buffer_len < 0) { + return; + } + if (ept->cb.received) { ept->cb.received(icmsg_buffer_to_user_buffer(msg), - icmsg_buffer_len_to_user_buffer_len(len), - ept->priv); + user_buffer_len, ept->priv); } } @@ -164,8 +180,9 @@ int icmsg_me_send(const struct icmsg_config_t *conf, { int r; int sent_bytes = 0; + ssize_t icmsg_buffer_len = user_buffer_len_to_icmsg_buffer_len(len); - if (user_buffer_len_to_icmsg_buffer_len(len) >= SEND_BUF_SIZE) { + if ((icmsg_buffer_len < 0) || (icmsg_buffer_len >= SEND_BUF_SIZE)) { return -EBADMSG; } @@ -179,7 +196,7 @@ int icmsg_me_send(const struct icmsg_config_t *conf, memcpy(icmsg_buffer_to_user_buffer(data->send_buffer), msg, len); r = icmsg_send(conf, &data->icmsg_data, data->send_buffer, - user_buffer_len_to_icmsg_buffer_len(len)); + icmsg_buffer_len); if (r > 0) { sent_bytes = icmsg_buffer_len_to_user_buffer_len(r); } diff --git a/subsys/llext/Kconfig b/subsys/llext/Kconfig index 59a4129a1ad..c0dc5e5e881 100644 --- a/subsys/llext/Kconfig +++ b/subsys/llext/Kconfig @@ -4,11 +4,43 @@ menuconfig LLEXT bool "Linkable loadable extensions" select CACHE_MANAGEMENT if DCACHE + select KERNEL_WHOLE_ARCHIVE help Enable the linkable loadable extension subsystem if LLEXT +choice LLEXT_BINARY_TYPE + prompt "Binary object type for llext" + default LLEXT_TYPE_ELF_OBJECT if ARM + default LLEXT_TYPE_ELF_SHAREDLIB if XTENSA + help + Object type for llext + +config LLEXT_TYPE_ELF_OBJECT + bool "Single object ELF file" + help + Build and expect object files as binary object type for the + llext subsystem. A single compiler invocation is used to + generate the object file. + +config LLEXT_TYPE_ELF_RELOCATABLE + bool "Relocatable ELF file" + help + Build and expect relocatable (partially linked )files as the + binary object type for the llext subsystem. These object files + are generated by the linker by combining multiple object files + into a single one. + +config LLEXT_TYPE_ELF_SHAREDLIB + bool "Shared library ELF file" + help + Build and expect shared libraries as binary object type for + the llext subsystem. The usual linking process is used to + generate the shared library from multiple object files. + +endchoice + config LLEXT_HEAP_SIZE int "llext heap memory size in kilobytes" default 8 @@ -39,3 +71,24 @@ module-str = llext source "subsys/logging/Kconfig.template.log_config" endif + +menu "Linkable loadable Extension Development Kit (EDK)" + +config LLEXT_EDK_NAME + string "Name for llext EDK (Extension Development Kit)" + default "llext-edk" + help + Name will be used when generating the EDK file, as .tar.xz. + It will also be used, normalized, as the prefix for the variable + stating EDK location, used on generated Makefile.cflags. For + instance, the default name, "llext-edk", becomes LLEXT_EDK_INSTALL_DIR. + +config LLEXT_EDK_USERSPACE_ONLY + bool "Only generate the Userpace codepath on syscall stubs for the EDK" + help + Syscall stubs can contain code that verifies if running code is at user + or kernel space and route the call accordingly. If the EDK is expected + to be used by userspace only extensions, this option will make EDK stubs + not contain the routing code, and only generate the userspace one. + +endmenu diff --git a/subsys/llext/llext.c b/subsys/llext/llext.c index 8222de55028..d0a04ff7d8c 100644 --- a/subsys/llext/llext.c +++ b/subsys/llext/llext.c @@ -114,7 +114,7 @@ int llext_iterate(int (*fn)(struct llext *ext, void *arg), void *arg) return ret; } -const void * const llext_find_sym(const struct llext_symtable *sym_table, const char *sym_name) +const void *llext_find_sym(const struct llext_symtable *sym_table, const char *sym_name) { if (sym_table == NULL) { /* Built-in symbol table */ @@ -471,7 +471,7 @@ static int llext_count_export_syms(struct llext_loader *ldr, struct llext *ext) name = llext_string(ldr, ext, LLEXT_MEM_STRTAB, sym.st_name); - if (stt == STT_FUNC && stb == STB_GLOBAL) { + if ((stt == STT_FUNC || stt == STT_OBJECT) && stb == STB_GLOBAL) { LOG_DBG("function symbol %d, name %s, type tag %d, bind %d, sect %d", i, name, stt, stb, sect); ext->sym_tab.sym_cnt++; @@ -562,7 +562,8 @@ static int llext_copy_symbols(struct llext_loader *ldr, struct llext *ext) uint32_t stb = ELF_ST_BIND(sym.st_info); unsigned int sect = sym.st_shndx; - if (stt == STT_FUNC && stb == STB_GLOBAL && sect != SHN_UNDEF) { + if ((stt == STT_FUNC || stt == STT_OBJECT) && + stb == STB_GLOBAL && sect != SHN_UNDEF) { enum llext_mem mem_idx = ldr->sect_map[sect]; const char *name = llext_string(ldr, ext, LLEXT_MEM_STRTAB, sym.st_name); @@ -659,6 +660,7 @@ static void llext_link_plt(struct llext_loader *ldr, struct llext *ext, if (stt != STT_FUNC && stt != STT_SECTION && + stt != STT_OBJECT && (stt != STT_NOTYPE || sym_tbl.st_shndx != SHN_UNDEF)) { continue; } diff --git a/subsys/logging/Kconfig.mode b/subsys/logging/Kconfig.mode index 61c304ad0b5..b573aa59906 100644 --- a/subsys/logging/Kconfig.mode +++ b/subsys/logging/Kconfig.mode @@ -4,6 +4,7 @@ choice LOG_MODE prompt "Mode" depends on !LOG_FRONTEND_ONLY + default LOG_MODE_IMMEDIATE if ARCH_POSIX default LOG_MODE_MINIMAL if LOG_DEFAULT_MINIMAL default LOG_MODE_DEFERRED diff --git a/subsys/logging/backends/log_backend_fs.c b/subsys/logging/backends/log_backend_fs.c index f12ba05adda..845b03d1518 100644 --- a/subsys/logging/backends/log_backend_fs.c +++ b/subsys/logging/backends/log_backend_fs.c @@ -35,7 +35,7 @@ static int get_log_file_id(struct fs_dirent *ent); static uint32_t log_format_current = CONFIG_LOG_BACKEND_FS_OUTPUT_DEFAULT; #endif -static int check_log_volumen_available(void) +static int check_log_volume_available(void) { int index = 0; char const *name; @@ -152,7 +152,7 @@ int write_log_to_file(uint8_t *data, size_t length, void *ctx) struct fs_file_t *f = &fs_file; if (backend_state == BACKEND_FS_NOT_INITIALIZED) { - if (check_log_volumen_available()) { + if (check_log_volume_available()) { return length; } rc = create_log_dir(CONFIG_LOG_BACKEND_FS_DIR); diff --git a/subsys/logging/backends/log_backend_net.c b/subsys/logging/backends/log_backend_net.c index 0f15770cd46..3f49e0a4088 100644 --- a/subsys/logging/backends/log_backend_net.c +++ b/subsys/logging/backends/log_backend_net.c @@ -12,6 +12,8 @@ LOG_MODULE_REGISTER(log_backend_net, CONFIG_LOG_DEFAULT_LEVEL); #include #include #include +#include +#include #include /* Set this to 1 if you want to see what is being sent to server */ diff --git a/subsys/logging/log_cache.c b/subsys/logging/log_cache.c index 5bc51f3635b..4899a3435d9 100644 --- a/subsys/logging/log_cache.c +++ b/subsys/logging/log_cache.c @@ -4,6 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include + #include "log_cache.h" #define LOG_CACHE_DBG 0 @@ -29,6 +31,11 @@ int log_cache_init(struct log_cache *cache, const struct log_cache_config *confi uint32_t entry_cnt = config->buf_len / entry_size; struct log_cache_entry *entry = config->buf; + /* Ensure the cache has at least one entry */ + if (entry_cnt == 0) { + return -EINVAL; + } + /* Add all entries to idle list */ for (uint32_t i = 0; i < entry_cnt; i++) { sys_slist_append(&cache->idle, &entry->node); diff --git a/subsys/logging/log_core.c b/subsys/logging/log_core.c index b4b6152806c..3e767092b76 100644 --- a/subsys/logging/log_core.c +++ b/subsys/logging/log_core.c @@ -322,13 +322,13 @@ static uint32_t z_log_init(bool blocking, bool can_sleep) return 0; } - int i = 0; if (IS_ENABLED(CONFIG_LOG_MULTIDOMAIN)) { z_log_links_initiate(); } + int backend_index = 0; - /* Assign ids to backends. */ + /* Activate autostart backends */ STRUCT_SECTION_FOREACH(log_backend, backend) { if (backend->autostart) { log_backend_init(backend); @@ -341,11 +341,11 @@ static uint32_t z_log_init(bool blocking, bool can_sleep) backend->cb->ctx, CONFIG_LOG_MAX_LEVEL); } else { - mask |= BIT(i); + mask |= BIT(backend_index); } - - i++; } + + ++backend_index; } /* If blocking init, wait until all backends are activated. */ @@ -366,6 +366,16 @@ void log_init(void) (void)z_log_init(true, true); } +void log_thread_trigger(void) +{ + if (IS_ENABLED(CONFIG_LOG_MODE_IMMEDIATE)) { + return; + } + + k_timer_stop(&log_process_thread_timer); + k_sem_give(&log_process_thread_sem); +} + static void thread_set(k_tid_t process_tid) { proc_tid = process_tid; @@ -466,18 +476,16 @@ static bool msg_filter_check(struct log_backend const *backend, uint8_t level; uint8_t domain_id; int16_t source_id; - struct log_source_dynamic_data *source; - source = (struct log_source_dynamic_data *)log_msg_get_source(&msg->log); level = log_msg_get_level(&msg->log); domain_id = log_msg_get_domain(&msg->log); + source_id = log_msg_get_source_id(&msg->log); /* Accept all non-logging messages. */ if (level == LOG_LEVEL_NONE) { return true; } - if (source) { - source_id = log_dynamic_source_id(source); + if (source_id >= 0) { backend_level = log_filter_get(backend, domain_id, source_id, true); return (level <= backend_level); diff --git a/subsys/logging/log_mgmt.c b/subsys/logging/log_mgmt.c index 190c452a2d6..ec6441379e3 100644 --- a/subsys/logging/log_mgmt.c +++ b/subsys/logging/log_mgmt.c @@ -450,7 +450,8 @@ uint32_t filter_set(int id, uint32_t domain_id, int16_t source_id, uint32_t leve STRUCT_SECTION_COUNT(log_backend, &backend_cnt); for (size_t i = 0; i < backend_cnt; i++) { - uint32_t current = filter_set(i, domain_id, source_id, level); + uint32_t current = filter_set(log_backend_id_get(log_backend_get(i)), + domain_id, source_id, level); max = MAX(current, max); } diff --git a/subsys/logging/log_msg.c b/subsys/logging/log_msg.c index 6c1cc3c5783..11a8a9735d3 100644 --- a/subsys/logging/log_msg.c +++ b/subsys/logging/log_msg.c @@ -389,3 +389,21 @@ void z_log_msg_runtime_vcreate(uint8_t domain_id, const void *source, z_log_msg_finalize(msg, source, desc, data); } } + +int16_t log_msg_get_source_id(struct log_msg *msg) +{ + if (!z_log_is_local_domain(log_msg_get_domain(msg))) { + /* Remote domain is converting source pointer to ID */ + return (int16_t)(uintptr_t)log_msg_get_source(msg); + } + + void *source = (void *)log_msg_get_source(msg); + + if (source != NULL) { + return IS_ENABLED(CONFIG_LOG_RUNTIME_FILTERING) + ? log_dynamic_source_id(source) + : log_const_source_id(source); + } + + return -1; +} diff --git a/subsys/logging/log_multidomain_link.c b/subsys/logging/log_multidomain_link.c index c730f405455..92018b31a5e 100644 --- a/subsys/logging/log_multidomain_link.c +++ b/subsys/logging/log_multidomain_link.c @@ -76,11 +76,13 @@ void log_multidomain_link_on_recv_cb(struct log_multidomain_link *link_remote, case Z_LOG_MULTIDOMAIN_ID_SET_RUNTIME_LEVEL: link_remote->dst.set_runtime_level.level = msg->data.set_rt_level.runtime_level; break; + case Z_LOG_MULTIDOMAIN_ID_DROPPED: + return; case Z_LOG_MULTIDOMAIN_ID_READY: break; default: __ASSERT(0, "Unexpected message"); - break; + return; } exit: diff --git a/subsys/logging/log_output.c b/subsys/logging/log_output.c index dd62fb76aa1..cd8e898a354 100644 --- a/subsys/logging/log_output.c +++ b/subsys/logging/log_output.c @@ -152,11 +152,11 @@ static void buffer_write(log_output_func_t outf, uint8_t *buf, size_t len, { int processed; - do { + while (len != 0) { processed = outf(buf, len, ctx); len -= processed; buf += processed; - } while (len != 0); + } } @@ -717,22 +717,7 @@ void log_output_msg_process(const struct log_output *output, log_timestamp_t timestamp = log_msg_get_timestamp(msg); uint8_t level = log_msg_get_level(msg); uint8_t domain_id = log_msg_get_domain(msg); - int16_t source_id; - - if (IS_ENABLED(CONFIG_LOG_MULTIDOMAIN) && domain_id != Z_LOG_LOCAL_DOMAIN_ID) { - /* Remote domain is converting source pointer to ID */ - source_id = (int16_t)(uintptr_t)log_msg_get_source(msg); - } else { - void *source = (void *)log_msg_get_source(msg); - - if (source != NULL) { - source_id = IS_ENABLED(CONFIG_LOG_RUNTIME_FILTERING) ? - log_dynamic_source_id(source) : - log_const_source_id(source); - } else { - source_id = -1; - } - } + int16_t source_id = log_msg_get_source_id(msg); const char *sname = source_id >= 0 ? log_source_name_get(domain_id, source_id) : NULL; size_t plen, dlen; diff --git a/subsys/lorawan/lorawan.c b/subsys/lorawan/lorawan.c index 56731dfc454..b37f24a7cdd 100644 --- a/subsys/lorawan/lorawan.c +++ b/subsys/lorawan/lorawan.c @@ -16,25 +16,35 @@ #include "nvm/lorawan_nvm.h" #ifdef CONFIG_LORAMAC_REGION_AS923 -#define DEFAULT_LORAWAN_REGION LORAMAC_REGION_AS923 +#define DEFAULT_LORAWAN_REGION LORAMAC_REGION_AS923 +#define DEFAULT_LORAWAN_CHANNELS_MASK_SIZE LORAWAN_CHANNELS_MASK_SIZE_AS923 #elif CONFIG_LORAMAC_REGION_AU915 -#define DEFAULT_LORAWAN_REGION LORAMAC_REGION_AU915 +#define DEFAULT_LORAWAN_REGION LORAMAC_REGION_AU915 +#define DEFAULT_LORAWAN_CHANNELS_MASK_SIZE LORAWAN_CHANNELS_MASK_SIZE_AU915 #elif CONFIG_LORAMAC_REGION_CN470 -#define DEFAULT_LORAWAN_REGION LORAMAC_REGION_CN470 +#define DEFAULT_LORAWAN_REGION LORAMAC_REGION_CN470 +#define DEFAULT_LORAWAN_CHANNELS_MASK_SIZE LORAWAN_CHANNELS_MASK_SIZE_CN470 #elif CONFIG_LORAMAC_REGION_CN779 -#define DEFAULT_LORAWAN_REGION LORAMAC_REGION_CN779 +#define DEFAULT_LORAWAN_REGION LORAMAC_REGION_CN779 +#define DEFAULT_LORAWAN_CHANNELS_MASK_SIZE LORAWAN_CHANNELS_MASK_SIZE_CN779 #elif CONFIG_LORAMAC_REGION_EU433 -#define DEFAULT_LORAWAN_REGION LORAMAC_REGION_EU433 +#define DEFAULT_LORAWAN_REGION LORAMAC_REGION_EU433 +#define DEFAULT_LORAWAN_CHANNELS_MASK_SIZE LORAWAN_CHANNELS_MASK_SIZE_EU433 #elif CONFIG_LORAMAC_REGION_EU868 -#define DEFAULT_LORAWAN_REGION LORAMAC_REGION_EU868 +#define DEFAULT_LORAWAN_REGION LORAMAC_REGION_EU868 +#define DEFAULT_LORAWAN_CHANNELS_MASK_SIZE LORAWAN_CHANNELS_MASK_SIZE_EU868 #elif CONFIG_LORAMAC_REGION_KR920 -#define DEFAULT_LORAWAN_REGION LORAMAC_REGION_KR920 +#define DEFAULT_LORAWAN_REGION LORAMAC_REGION_KR920 +#define DEFAULT_LORAWAN_CHANNELS_MASK_SIZE LORAWAN_CHANNELS_MASK_SIZE_KR920 #elif CONFIG_LORAMAC_REGION_IN865 -#define DEFAULT_LORAWAN_REGION LORAMAC_REGION_IN865 +#define DEFAULT_LORAWAN_REGION LORAMAC_REGION_IN865 +#define DEFAULT_LORAWAN_CHANNELS_MASK_SIZE LORAWAN_CHANNELS_MASK_SIZE_IN865 #elif CONFIG_LORAMAC_REGION_US915 -#define DEFAULT_LORAWAN_REGION LORAMAC_REGION_US915 +#define DEFAULT_LORAWAN_REGION LORAMAC_REGION_US915 +#define DEFAULT_LORAWAN_CHANNELS_MASK_SIZE LORAWAN_CHANNELS_MASK_SIZE_US915 #elif CONFIG_LORAMAC_REGION_RU864 -#define DEFAULT_LORAWAN_REGION LORAMAC_REGION_RU864 +#define DEFAULT_LORAWAN_REGION LORAMAC_REGION_RU864 +#define DEFAULT_LORAWAN_CHANNELS_MASK_SIZE LORAWAN_CHANNELS_MASK_SIZE_RU864 #else #error "At least one LoRaWAN region should be selected" #endif @@ -72,6 +82,9 @@ static LoRaMacEventInfoStatus_t last_mlme_indication_status; static LoRaMacRegion_t selected_region = DEFAULT_LORAWAN_REGION; +static enum lorawan_channels_mask_size region_channels_mask_size = + DEFAULT_LORAWAN_CHANNELS_MASK_SIZE; + static lorawan_battery_level_cb_t battery_level_cb; static lorawan_dr_changed_cb_t dr_changed_cb; @@ -292,60 +305,70 @@ int lorawan_set_region(enum lorawan_region region) #if defined(CONFIG_LORAMAC_REGION_AS923) case LORAWAN_REGION_AS923: selected_region = LORAMAC_REGION_AS923; + region_channels_mask_size = LORAWAN_CHANNELS_MASK_SIZE_AS923; break; #endif #if defined(CONFIG_LORAMAC_REGION_AU915) case LORAWAN_REGION_AU915: selected_region = LORAMAC_REGION_AU915; + region_channels_mask_size = LORAWAN_CHANNELS_MASK_SIZE_AU915; break; #endif #if defined(CONFIG_LORAMAC_REGION_CN470) case LORAWAN_REGION_CN470: selected_region = LORAMAC_REGION_CN470; + region_channels_mask_size = LORAWAN_CHANNELS_MASK_SIZE_CN470; break; #endif #if defined(CONFIG_LORAMAC_REGION_CN779) case LORAWAN_REGION_CN779: selected_region = LORAMAC_REGION_CN779; + region_channels_mask_size = LORAWAN_CHANNELS_MASK_SIZE_CN779; break; #endif #if defined(CONFIG_LORAMAC_REGION_EU433) case LORAWAN_REGION_EU433: selected_region = LORAMAC_REGION_EU433; + region_channels_mask_size = LORAWAN_CHANNELS_MASK_SIZE_EU433; break; #endif #if defined(CONFIG_LORAMAC_REGION_EU868) case LORAWAN_REGION_EU868: selected_region = LORAMAC_REGION_EU868; + region_channels_mask_size = LORAWAN_CHANNELS_MASK_SIZE_EU868; break; #endif #if defined(CONFIG_LORAMAC_REGION_KR920) case LORAWAN_REGION_KR920: selected_region = LORAMAC_REGION_KR920; + region_channels_mask_size = LORAWAN_CHANNELS_MASK_SIZE_KR920; break; #endif #if defined(CONFIG_LORAMAC_REGION_IN865) case LORAWAN_REGION_IN865: selected_region = LORAMAC_REGION_IN865; + region_channels_mask_size = LORAWAN_CHANNELS_MASK_SIZE_IN865; break; #endif #if defined(CONFIG_LORAMAC_REGION_US915) case LORAWAN_REGION_US915: selected_region = LORAMAC_REGION_US915; + region_channels_mask_size = LORAWAN_CHANNELS_MASK_SIZE_US915; break; #endif #if defined(CONFIG_LORAMAC_REGION_RU864) case LORAWAN_REGION_RU864: selected_region = LORAMAC_REGION_RU864; + region_channels_mask_size = LORAWAN_CHANNELS_MASK_SIZE_RU864; break; #endif @@ -472,6 +495,26 @@ int lorawan_set_class(enum lorawan_class dev_class) return 0; } +int lorawan_set_channels_mask(uint16_t *channels_mask, size_t channels_mask_size) +{ + MibRequestConfirm_t mib_req; + + if ((channels_mask == NULL) || (channels_mask_size != region_channels_mask_size)) { + return -EINVAL; + } + + /* Notify MAC layer of the requested channel mask. */ + mib_req.Type = MIB_CHANNELS_MASK; + mib_req.Param.ChannelsMask = channels_mask; + + if (LoRaMacMibSetRequestConfirm(&mib_req) != LORAMAC_STATUS_OK) { + /* Channels mask is invalid for this region. */ + return -EINVAL; + } + + return 0; +} + int lorawan_set_datarate(enum lorawan_datarate dr) { MibRequestConfirm_t mib_req; @@ -552,7 +595,7 @@ int lorawan_send(uint8_t port, uint8_t *data, uint8_t len, int ret = 0; bool empty_frame = false; - if (data == NULL) { + if (data == NULL && len > 0) { return -EINVAL; } diff --git a/subsys/lorawan/nvm/lorawan_nvm_settings.c b/subsys/lorawan/nvm/lorawan_nvm_settings.c index 3b062299c51..b56784ad627 100644 --- a/subsys/lorawan/nvm/lorawan_nvm_settings.c +++ b/subsys/lorawan/nvm/lorawan_nvm_settings.c @@ -77,8 +77,6 @@ static void lorawan_nvm_save_settings(uint16_t nvm_notify_flag) } } } - - settings_save(); } void lorawan_nvm_data_mgmt_event(uint16_t flags) diff --git a/subsys/lorawan/services/CMakeLists.txt b/subsys/lorawan/services/CMakeLists.txt index b634efd69b3..2f3aeeeaca2 100644 --- a/subsys/lorawan/services/CMakeLists.txt +++ b/subsys/lorawan/services/CMakeLists.txt @@ -9,6 +9,12 @@ if(CONFIG_LORAWAN_SERVICES) clock_sync.c ) + zephyr_library_sources_ifdef( + CONFIG_LORAWAN_FRAG_TRANSPORT + frag_flash.c + frag_transport.c + ) + zephyr_library_sources_ifdef( CONFIG_LORAWAN_REMOTE_MULTICAST multicast.c diff --git a/subsys/lorawan/services/Kconfig b/subsys/lorawan/services/Kconfig index 6ab6d4e55af..95905a7cbff 100644 --- a/subsys/lorawan/services/Kconfig +++ b/subsys/lorawan/services/Kconfig @@ -54,6 +54,90 @@ config LORAWAN_APP_CLOCK_SYNC_PERIODICITY Default setting: 24h. +config LORAWAN_FRAG_TRANSPORT + bool "Fragmented Data Block Transport" + select FLASH_MAP + select FLASH_PAGE_LAYOUT + select IMG_MANAGER + help + Enables the LoRaWAN Fragmented Data Block Transport service + according to TS004-1.0.0 as published by the LoRa Alliance. + + The used default port for this service is 201. + +DT_CHOSEN_Z_CODE_PARTITION := zephyr,code-partition + +config LORAWAN_FRAG_TRANSPORT_IMAGE_SIZE + int "Total size of firmware image" + depends on LORAWAN_FRAG_TRANSPORT + default $(dt_chosen_reg_size_int,$(DT_CHOSEN_Z_CODE_PARTITION)) + help + Size of the flash partition for the application firmware image + in bytes. + + The minimum number of fragments to be transferred is calculated from + this value divided by the fragment size. + + This setting has significant influence on RAM usage. + +config LORAWAN_FRAG_TRANSPORT_MAX_FRAG_SIZE + int "Maximum size of transported fragments" + depends on LORAWAN_FRAG_TRANSPORT + range 1 239 + default 232 + help + Maximum size of one fragment transferred during the fragmented data + block transport session of the FUOTA process. It is chosen on the + server side. + + The fragment has to fit into the LoRaWAN payload, which can be up to + 242 bytes depending on the region and frequency settings. 3 bytes of + the payload are consumed for protocol information. + + For some MCUs like the STM32WL the fragment size has to be a multiple + of 8 (see flash driver for further information). + + This setting has significant influence on RAM usage. If the exact + fragment size is known, use that value for MIN and MAX config to + reduce memory consumption. + +config LORAWAN_FRAG_TRANSPORT_MIN_FRAG_SIZE + int "Minimum size of transported fragments" + depends on LORAWAN_FRAG_TRANSPORT + range 1 239 + default 48 + help + Minimum size of one fragment transferred during the fragmented data + block transport session of the FUOTA process. It is chosen on the + server side. + + The fragment has to fit into the LoRaWAN payload, which can be up to + 242 bytes depending on the region and frequency settings. 3 bytes of + the payload are consumed for protocol information. + + For some MCUs like the STM32WL the fragment size has to be a multiple + of 8 (see flash driver for further information). + + This setting has significant influence on RAM usage. If the exact + fragment size is known, use that value for MIN and MAX config to + reduce memory consumption. + +config LORAWAN_FRAG_TRANSPORT_MAX_REDUNDANCY + int "Percentage of redundant fragments" + depends on LORAWAN_FRAG_TRANSPORT + range 1 100 + default 20 + help + The built-in forward error correction (FEC) mechanism allows to + reconstruct missed packages from additional redundant packages + sent by the server after all packages have been sent. + + This parameter specifies the maximum amount of packet loss (in + percent) for which it should be possible to reconstruct the full + firmware image. + + This setting has significant influence on RAM usage. + config LORAWAN_REMOTE_MULTICAST bool "Remote Multicast Setup" depends on LORAWAN_APP_CLOCK_SYNC diff --git a/subsys/lorawan/services/clock_sync.c b/subsys/lorawan/services/clock_sync.c index a4532fdee14..c736a396dee 100644 --- a/subsys/lorawan/services/clock_sync.c +++ b/subsys/lorawan/services/clock_sync.c @@ -71,7 +71,7 @@ static struct clock_sync_context ctx; */ static int clock_sync_serialize_device_time(uint8_t *buf, size_t size) { - uint32_t device_time = k_uptime_get() / MSEC_PER_SEC + ctx.time_offset; + uint32_t device_time = k_uptime_seconds() + ctx.time_offset; if (size < sizeof(uint32_t)) { return -ENOSPC; @@ -221,7 +221,7 @@ int lorawan_clock_sync_get(uint32_t *gps_time) __ASSERT(gps_time != NULL, "gps_time parameter is required"); if (ctx.synchronized) { - *gps_time = (uint32_t)(k_uptime_get() / MSEC_PER_SEC + ctx.time_offset); + *gps_time = k_uptime_seconds() + ctx.time_offset; return 0; } else { return -EAGAIN; diff --git a/subsys/lorawan/services/frag_flash.c b/subsys/lorawan/services/frag_flash.c new file mode 100644 index 00000000000..2d5db55a7a8 --- /dev/null +++ b/subsys/lorawan/services/frag_flash.c @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2022-2024 Libre Solar Technologies GmbH + * Copyright (c) 2022-2024 tado GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "frag_flash.h" + +#include + +#include +#include +#include +#include + +LOG_MODULE_REGISTER(lorawan_frag_flash, CONFIG_LORAWAN_SERVICES_LOG_LEVEL); + +#define TARGET_IMAGE_AREA FIXED_PARTITION_ID(slot1_partition) + +struct frag_cache_entry { + uint32_t addr; + uint8_t data[FRAG_MAX_SIZE]; +}; + +static struct frag_cache_entry frag_cache[FRAG_MAX_REDUNDANCY]; +static uint32_t frag_size; +static int cached_frags; +static bool use_cache; + +static const struct flash_area *fa; + +int frag_flash_init(uint32_t fragment_size) +{ + int err; + + if (fragment_size > FRAG_MAX_SIZE) { + return -ENOSPC; + } + + frag_size = fragment_size; + cached_frags = 0; + use_cache = false; + + err = flash_area_open(TARGET_IMAGE_AREA, &fa); + if (err) { + return err; + } + + LOG_DBG("Starting to erase flash area"); + + err = flash_area_erase(fa, 0, fa->fa_size); + + LOG_DBG("Finished erasing flash area"); + + return err; +} + +int8_t frag_flash_write(uint32_t addr, uint8_t *data, uint32_t size) +{ + int8_t err = 0; + + if (!use_cache) { + LOG_DBG("Writing %u bytes to addr 0x%X", size, addr); + + err = flash_area_write(fa, addr, data, size); + } else { + LOG_DBG("Caching %u bytes for addr 0x%X", size, addr); + + if (size != frag_size) { + LOG_ERR("Invalid fragment size %d", size); + return -EINVAL; + } + + /* overwrite fragment in cache if existing */ + for (int i = 0; i < cached_frags; i++) { + if (frag_cache[i].addr == addr) { + memcpy(frag_cache[i].data, data, size); + return 0; + } + } + + /* otherwise create new cache entry */ + if (cached_frags < ARRAY_SIZE(frag_cache)) { + frag_cache[cached_frags].addr = addr; + memcpy(frag_cache[cached_frags].data, data, size); + cached_frags++; + } else { + LOG_ERR("Fragment cache too small"); + err = -ENOSPC; + } + } + + return err == 0 ? 0 : -1; +} + +int8_t frag_flash_read(uint32_t addr, uint8_t *data, uint32_t size) +{ + for (int i = 0; i < cached_frags; i++) { + if (frag_cache[i].addr == addr) { + memcpy(data, frag_cache[i].data, size); + return 0; + } + } + + return flash_area_read(fa, addr, data, size) == 0 ? 0 : -1; +} + +void frag_flash_use_cache(void) +{ + use_cache = true; +} + +void frag_flash_finish(void) +{ + int err; + + for (int i = 0; i < cached_frags; i++) { + LOG_DBG("Writing %u bytes to addr 0x%x", frag_size, frag_cache[i].addr); + flash_area_write(fa, frag_cache[i].addr, frag_cache[i].data, frag_size); + } + + flash_area_close(fa); + + err = boot_request_upgrade(BOOT_UPGRADE_TEST); + if (err) { + LOG_ERR("Failed to request upgrade (err %d)", err); + } +} diff --git a/subsys/lorawan/services/frag_flash.h b/subsys/lorawan/services/frag_flash.h new file mode 100644 index 00000000000..cecb91f3acc --- /dev/null +++ b/subsys/lorawan/services/frag_flash.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2022-2024 Libre Solar Technologies GmbH + * Copyright (c) 2022-2024 tado GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_SUBSYS_LORAWAN_SERVICES_FRAG_FLASH_H_ +#define ZEPHYR_SUBSYS_LORAWAN_SERVICES_FRAG_FLASH_H_ + +#include + +/** + * Initialize flash driver and prepare partition for new firmware image. + * + * This function mass-erases the flash partition and may take a while to return. + * + * @param frag_size Fragment size used for this session + * + * @returns 0 for success, otherwise negative error code + */ +int frag_flash_init(uint32_t frag_size); + +/** + * Write received data fragment to flash. + * + * This function is called by FragDecoder from LoRaMAC-node stack. + * + * @param addr Flash address relative to start of slot + * @param data Data buffer + * @param size Number of bytes in the buffer + * + * @returns 0 for success, otherwise negative error code + */ +int8_t frag_flash_write(uint32_t addr, uint8_t *data, uint32_t size); + +/** + * Read back data from flash. + * + * This function is called by FragDecoder from LoRaMAC-node stack. + * + * @param addr Flash address relative to start of slot + * @param data Data buffer + * @param size Number of bytes in the buffer + * + * @returns 0 for success, otherwise negative error code + */ +int8_t frag_flash_read(uint32_t addr, uint8_t *data, uint32_t size); + +/** + * Start caching fragments in RAM. + * + * Coded/redundant fragments may be overwritten with future fragments, + * so we have to cache them in RAM instead of flash. + * + * This function must be called once all uncoded fragments have been received. + */ +void frag_flash_use_cache(void); + +/** + * Finalize flashing after sufficient fragments have been received. + * + * This call will also write cached fragments to flash. + * + * After this call the new firmware is ready to be checked and booted. + */ +void frag_flash_finish(void); + +#endif /* ZEPHYR_SUBSYS_LORAWAN_SERVICES_FRAG_FLASH_H_ */ diff --git a/subsys/lorawan/services/frag_transport.c b/subsys/lorawan/services/frag_transport.c new file mode 100644 index 00000000000..2db28bb0366 --- /dev/null +++ b/subsys/lorawan/services/frag_transport.c @@ -0,0 +1,310 @@ +/* + * Copyright (c) 2022-2024 Libre Solar Technologies GmbH + * Copyright (c) 2022-2024 tado GmbH + * + * Parts of this implementation were inspired by LmhpFragmentation.c from the + * LoRaMac-node firmware repository https://github.com/Lora-net/LoRaMac-node + * written by Miguel Luis (Semtech). + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "frag_flash.h" +#include "lorawan_services.h" + +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(lorawan_frag_transport, CONFIG_LORAWAN_SERVICES_LOG_LEVEL); + +/** + * Version of LoRaWAN Fragmented Data Block Transport Specification + * + * This implementation only supports TS004-1.0.0. + */ +#define FRAG_TRANSPORT_VERSION 1 + +/** + * Maximum expected number of frag transport commands per packet + * + * The standard states "A message MAY carry more than one command". Even though this was not + * observed during testing, space for up to 3 packages is reserved. + */ +#define FRAG_TRANSPORT_MAX_CMDS_PER_PACKAGE 3 + +/* maximum length of frag_transport answers */ +#define FRAG_TRANSPORT_MAX_ANS_LEN 5 + +enum frag_transport_commands { + FRAG_TRANSPORT_CMD_PKG_VERSION = 0x00, + FRAG_TRANSPORT_CMD_FRAG_STATUS = 0x01, + FRAG_TRANSPORT_CMD_FRAG_SESSION_SETUP = 0x02, + FRAG_TRANSPORT_CMD_FRAG_SESSION_DELETE = 0x03, + FRAG_TRANSPORT_CMD_DATA_FRAGMENT = 0x08, +}; + +struct frag_transport_context { + /** Stores if a session is active */ + bool is_active; + union { + uint8_t frag_session; + struct { + /** Multicast groups allowed to input to this frag session */ + uint8_t mc_group_bit_mask: 4; + /** Identifies this session */ + uint8_t frag_index: 2; + }; + }; + /** Number of fragments of the data block for this session, max. 2^14-1 */ + uint16_t nb_frag; + /** Number of fragments received in this session (including coded, uncoded and repeated) */ + uint16_t nb_frag_received; + /** Size of each fragment in octets */ + uint8_t frag_size; + union { + uint8_t control; + struct { + /** Random delay for some responses between 0 and 2^(BlockAckDelay + 4) */ + uint8_t block_ack_delay: 3; + /** Used fragmentation algorithm (0 for forward error correction) */ + uint8_t frag_algo: 3; + }; + }; + /** Padding in the last fragment if total size is not a multiple of frag_size */ + uint8_t padding; + /** Application-specific descriptor for the data block, e.g. firmware version */ + uint32_t descriptor; + + /* variables required for FragDecoder.h */ + FragDecoderCallbacks_t decoder_callbacks; + int32_t decoder_process_status; +}; + +/* + * The frag decoder is a singleton, so we can only have one ongoing frag session at a time, even + * though the standard allows up to 4 sessions + */ +static struct frag_transport_context ctx; + +/* Callback for notification of finished firmware transfer */ +static void (*finished_cb)(void); + +static void frag_transport_package_callback(uint8_t port, bool data_pending, int16_t rssi, + int8_t snr, uint8_t len, const uint8_t *rx_buf) +{ + uint8_t tx_buf[FRAG_TRANSPORT_MAX_CMDS_PER_PACKAGE * FRAG_TRANSPORT_MAX_ANS_LEN]; + uint8_t tx_pos = 0; + uint8_t rx_pos = 0; + int ans_delay = 0; + + __ASSERT(port == LORAWAN_PORT_FRAG_TRANSPORT, "Wrong port %d", port); + + while (rx_pos < len) { + uint8_t command_id = rx_buf[rx_pos++]; + + if (sizeof(tx_buf) - tx_pos < FRAG_TRANSPORT_MAX_ANS_LEN) { + LOG_ERR("insufficient tx_buf size, some requests discarded"); + break; + } + + switch (command_id) { + case FRAG_TRANSPORT_CMD_PKG_VERSION: + tx_buf[tx_pos++] = FRAG_TRANSPORT_CMD_PKG_VERSION; + tx_buf[tx_pos++] = LORAWAN_PACKAGE_ID_FRAG_TRANSPORT_BLOCK; + tx_buf[tx_pos++] = FRAG_TRANSPORT_VERSION; + break; + case FRAG_TRANSPORT_CMD_FRAG_STATUS: { + uint8_t frag_status = rx_buf[rx_pos++] & 0x07; + uint8_t participants = frag_status & 0x01; + uint8_t index = frag_status >> 1; + + LOG_DBG("FragSessionStatusReq index %d, participants: %u", index, + participants); + + uint8_t missing_frag = CLAMP(ctx.nb_frag - ctx.nb_frag_received, 0, 255); + + FragDecoderStatus_t decoder_status = FragDecoderGetStatus(); + uint8_t memory_error = decoder_status.MatrixError; + + if (participants == 1 || missing_frag > 0) { + tx_buf[tx_pos++] = FRAG_TRANSPORT_CMD_FRAG_STATUS; + tx_buf[tx_pos++] = ctx.nb_frag_received & 0xFF; + tx_buf[tx_pos++] = + (index << 6) | ((ctx.nb_frag_received >> 8) & 0x3F); + tx_buf[tx_pos++] = missing_frag; + tx_buf[tx_pos++] = memory_error & 0x01; + + ans_delay = sys_rand32_get() % (1U << (ctx.block_ack_delay + 4)); + + LOG_DBG("FragSessionStatusAns index %d, NbFragReceived: %u, " + "MissingFrag: %u, MemoryError: %u, delay: %d", + index, ctx.nb_frag_received, missing_frag, memory_error, + ans_delay); + } + break; + } + case FRAG_TRANSPORT_CMD_FRAG_SESSION_SETUP: { + uint8_t frag_session = rx_buf[rx_pos++] & 0x3F; + uint8_t index = frag_session >> 4; + uint8_t status = index << 6; + + if (!ctx.is_active || ctx.frag_index == index) { + ctx.frag_session = frag_session; + ctx.nb_frag_received = 0; + + ctx.nb_frag = sys_get_le16(rx_buf + rx_pos); + rx_pos += sizeof(uint16_t); + + ctx.frag_size = rx_buf[rx_pos++]; + ctx.control = rx_buf[rx_pos++]; + ctx.padding = rx_buf[rx_pos++]; + + ctx.descriptor = sys_get_le32(rx_buf + rx_pos); + rx_pos += sizeof(uint32_t); + + LOG_INF("FragSessionSetupReq index %d, nb_frag: %u, frag_size: %u, " + "padding: %u, control: 0x%x, descriptor: 0x%.8x", + index, ctx.nb_frag, ctx.frag_size, ctx.padding, ctx.control, + ctx.descriptor); + } else { + /* FragIndex unsupported */ + status |= BIT(2); + + LOG_WRN("FragSessionSetupReq failed. Session %u still active", + ctx.frag_index); + } + + if (ctx.frag_algo > 0) { + /* FragAlgo unsupported */ + status |= BIT(0); + } + + if (ctx.nb_frag > FRAG_MAX_NB || ctx.frag_size > FRAG_MAX_SIZE || + ctx.nb_frag * ctx.frag_size > FragDecoderGetMaxFileSize()) { + /* Not enough memory */ + status |= BIT(1); + } + + /* Descriptor not used: Ignore Wrong Descriptor error */ + + if ((status & 0x1F) == 0) { + /* + * Assign callbacks after initialization to prevent the FragDecoder + * from writing byte-wise 0xFF to the entire flash. Instead, erase + * flash properly with own implementation. + */ + ctx.decoder_callbacks.FragDecoderWrite = NULL; + ctx.decoder_callbacks.FragDecoderRead = NULL; + + FragDecoderInit(ctx.nb_frag, ctx.frag_size, &ctx.decoder_callbacks); + + ctx.decoder_callbacks.FragDecoderWrite = frag_flash_write; + ctx.decoder_callbacks.FragDecoderRead = frag_flash_read; + + frag_flash_init(ctx.frag_size); + ctx.is_active = true; + ctx.decoder_process_status = FRAG_SESSION_ONGOING; + } + + tx_buf[tx_pos++] = FRAG_TRANSPORT_CMD_FRAG_SESSION_SETUP; + tx_buf[tx_pos++] = status; + break; + } + case FRAG_TRANSPORT_CMD_FRAG_SESSION_DELETE: { + uint8_t index = rx_buf[rx_pos++] & 0x03; + uint8_t status = 0x00; + + status |= index; + if (!ctx.is_active || ctx.frag_index != index) { + /* Session does not exist */ + status |= BIT(2); + } else { + ctx.is_active = false; + } + + tx_buf[tx_pos++] = FRAG_TRANSPORT_CMD_FRAG_SESSION_DELETE; + tx_buf[tx_pos++] = status; + break; + } + case FRAG_TRANSPORT_CMD_DATA_FRAGMENT: { + ctx.nb_frag_received++; + + uint16_t frag_index_n = sys_get_le16(rx_buf + rx_pos); + + rx_pos += 2; + + uint16_t frag_counter = frag_index_n & 0x3FFF; + uint8_t index = (frag_index_n >> 14) & 0x03; + + if (!ctx.is_active || index != ctx.frag_index) { + LOG_DBG("DataFragment received for inactive session %u", index); + break; + } + + if (ctx.decoder_process_status == FRAG_SESSION_ONGOING) { + if (frag_counter > ctx.nb_frag) { + /* Additional fragments have to be cached in RAM for + * recovery algorithm. + */ + frag_flash_use_cache(); + } + + ctx.decoder_process_status = FragDecoderProcess( + frag_counter, (uint8_t *)&rx_buf[rx_pos]); + } + + LOG_INF("DataFragment %u of %u (%u lost), session: %u, decoder result: %d", + frag_counter, ctx.nb_frag, frag_counter - ctx.nb_frag_received, + index, ctx.decoder_process_status); + + if (ctx.decoder_process_status >= 0) { + /* Positive status corresponds to number of lost (but recovered) + * fragments. Value >= 0 means the transport is done. + */ + frag_flash_finish(); + + LOG_INF("Frag Transport finished successfully"); + + if (finished_cb != NULL) { + finished_cb(); + } + + ctx.is_active = false; + /* avoid processing further fragments */ + ctx.decoder_process_status = FRAG_SESSION_NOT_STARTED; + } + + rx_pos += ctx.frag_size; + break; + } + default: + return; + } + } + + if (tx_pos > 0) { + lorawan_services_schedule_uplink(LORAWAN_PORT_FRAG_TRANSPORT, tx_buf, tx_pos, + ans_delay); + } +} + +static struct lorawan_downlink_cb downlink_cb = { + .port = (uint8_t)LORAWAN_PORT_FRAG_TRANSPORT, + .cb = frag_transport_package_callback, +}; + +int lorawan_frag_transport_run(void (*transport_finished_cb)(void)) +{ + finished_cb = transport_finished_cb; + + /* initialize non-zero static variables */ + ctx.decoder_process_status = FRAG_SESSION_NOT_STARTED; + + lorawan_register_downlink_callback(&downlink_cb); + + return 0; +} diff --git a/subsys/mgmt/hawkbit/Kconfig b/subsys/mgmt/hawkbit/Kconfig index e2365cf3c1d..e2011fd4cad 100644 --- a/subsys/mgmt/hawkbit/Kconfig +++ b/subsys/mgmt/hawkbit/Kconfig @@ -1,9 +1,9 @@ # Copyright (c) 2020 Linumiz -# SPDX -License-Identifier: Apache-2.0 +# SPDX-License-Identifier: Apache-2.0 menuconfig HAWKBIT bool "Eclipse hawkBit Firmware Over-the-Air support" - depends on NVS + depends on SETTINGS depends on FLASH depends on REBOOT depends on HWINFO @@ -45,11 +45,16 @@ config HAWKBIT_SERVER Configure the hawkbit server address. config HAWKBIT_PORT - string "Port address for the hawkbit server" - default "8080" + int "Port number for the hawkbit server" + default 8080 help Configure the hawkbit port number. +config HAWKBIT_SET_SETTINGS_RUNTIME + bool "Set hawkbit settings at runtime" + help + Enable to set hawkbit settings at runtime. + choice HAWKBIT_DDI_SECURITY prompt "hawkBit DDI API authentication modes" default HAWKBIT_DDI_NO_SECURITY @@ -79,6 +84,67 @@ config HAWKBIT_DDI_SECURITY_TOKEN Authentication security token for the configured hawkBit DDI authentication mode. +config HAWKBIT_CUSTOM_ATTRIBUTES + bool "Custom device attributes" + help + Use custom definition of device attributes. + +config HAWKBIT_STATUS_BUFFER_SIZE + int "hawkBit status buffer size" + default 200 + help + Set the size of the buffer, which is used to store the + json strings, that are sent to the hawkBit server. It might + be increased if the custom attributes are used extensively. + +config HAWKBIT_CUSTOM_DEVICE_ID + bool "Custom device id through callback function" + help + Be able to customize the device id during runtime to a custom value, + by configuring the callback function. See `hawkbit_set_device_identity_cb` + +config HAWKBIT_DEVICE_ID_MAX_LENGTH + int "Maximum length of the device id" + depends on HAWKBIT_CUSTOM_DEVICE_ID + range 1 128 + default 32 + help + Maximum length of the device id. + +config HAWKBIT_USE_TLS + bool "Use TLS for hawkBit server connection" + depends on NET_SOCKETS_SOCKOPT_TLS + help + Use TLS for hawkBit connection. + +if HAWKBIT_USE_TLS + +choice HAWKBIT_CERT_TAG + prompt "hawkBit certificate tag" + default HAWKBIT_USE_STATIC_CERT_TAG + +config HAWKBIT_USE_STATIC_CERT_TAG + bool "Use static certificate tag" + help + Use static certificate tag for TLS connection to the hawkBit server. + +config HAWKBIT_USE_DYNAMIC_CERT_TAG + bool "Use dynamic certificate tag" + depends on HAWKBIT_SET_SETTINGS_RUNTIME + help + Use dynamic certificate tag for TLS connection to the hawkBit server. + +endchoice + +config HAWKBIT_STATIC_CERT_TAG + int "Static certificate tag" + depends on HAWKBIT_USE_STATIC_CERT_TAG + default 1 + help + Static certificate tag for TLS connection to the hawkBit server. + +endif + module = HAWKBIT module-str = Log Level for hawkbit module-help = Enables logging for hawkBit code. diff --git a/subsys/mgmt/hawkbit/hawkbit.c b/subsys/mgmt/hawkbit/hawkbit.c index d986b05f571..854500850b6 100644 --- a/subsys/mgmt/hawkbit/hawkbit.c +++ b/subsys/mgmt/hawkbit/hawkbit.c @@ -14,7 +14,6 @@ #include #include -#include #include #include #include @@ -24,6 +23,7 @@ #include #include #include +#include #include #include @@ -31,37 +31,83 @@ #include "hawkbit_firmware.h" #include "hawkbit_priv.h" -#if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS) -#define CA_CERTIFICATE_TAG 1 -#include -#endif - LOG_MODULE_REGISTER(hawkbit, CONFIG_HAWKBIT_LOG_LEVEL); -#define ADDRESS_ID 1 - #define CANCEL_BASE_SIZE 50 #define RECV_BUFFER_SIZE 640 #define URL_BUFFER_SIZE 300 #define SHA256_HASH_SIZE 32 -#define STATUS_BUFFER_SIZE 200 #define DOWNLOAD_HTTP_SIZE 200 #define DEPLOYMENT_BASE_SIZE 50 #define RESPONSE_BUFFER_SIZE 1100 +#define DDI_SECURITY_TOKEN_SIZE 32 #define HAWKBIT_RECV_TIMEOUT (300 * MSEC_PER_SEC) +#define HAWKBIT_SET_SERVER_TIMEOUT K_MSEC(300) #define HTTP_HEADER_CONTENT_TYPE_JSON "application/json;charset=UTF-8" #define SLOT1_LABEL slot1_partition #define SLOT1_SIZE FIXED_PARTITION_SIZE(SLOT1_LABEL) -#define STORAGE_LABEL storage_partition -#define STORAGE_DEV FIXED_PARTITION_DEVICE(STORAGE_LABEL) -#define STORAGE_OFFSET FIXED_PARTITION_OFFSET(STORAGE_LABEL) - static uint32_t poll_sleep = (CONFIG_HAWKBIT_POLL_INTERVAL * SEC_PER_MIN); -static struct nvs_fs fs; +static bool hawkbit_initialized; + +#ifndef CONFIG_HAWKBIT_DDI_NO_SECURITY + +#ifdef CONFIG_HAWKBIT_DDI_GATEWAY_SECURITY +#define AUTH_HEADER_START "Authorization: GatewayToken " +#else +#define AUTH_HEADER_START "Authorization: TargetToken " +#endif /* CONFIG_HAWKBIT_DDI_GATEWAY_SECURITY */ + +#ifdef CONFIG_HAWKBIT_SET_SETTINGS_RUNTIME +#define AUTH_HEADER_FULL AUTH_HEADER_START "%s" HTTP_CRLF +#else +#define AUTH_HEADER_FULL AUTH_HEADER_START CONFIG_HAWKBIT_DDI_SECURITY_TOKEN HTTP_CRLF +#endif /* CONFIG_HAWKBIT_SET_SETTINGS_RUNTIME */ + +#endif /* CONFIG_HAWKBIT_DDI_NO_SECURITY */ + +static struct hawkbit_config { + int32_t action_id; +#ifdef CONFIG_HAWKBIT_SET_SETTINGS_RUNTIME + char server_addr[DNS_MAX_NAME_SIZE + 1]; + char server_port[sizeof(STRINGIFY(__UINT16_MAX__))]; +#ifndef CONFIG_HAWKBIT_DDI_NO_SECURITY + char ddi_security_token[DDI_SECURITY_TOKEN_SIZE + 1]; +#endif +#ifdef CONFIG_HAWKBIT_USE_DYNAMIC_CERT_TAG + sec_tag_t tls_tag; +#endif +#endif /* CONFIG_HAWKBIT_SET_SETTINGS_RUNTIME */ +} hb_cfg; + +#ifdef CONFIG_HAWKBIT_SET_SETTINGS_RUNTIME +#define HAWKBIT_SERVER hb_cfg.server_addr +#define HAWKBIT_PORT hb_cfg.server_port +#define HAWKBIT_PORT_INT atoi(hb_cfg.server_port) +#else +#define HAWKBIT_SERVER CONFIG_HAWKBIT_SERVER +#define HAWKBIT_PORT STRINGIFY(CONFIG_HAWKBIT_PORT) +#define HAWKBIT_PORT_INT CONFIG_HAWKBIT_PORT +#endif /* CONFIG_HAWKBIT_SET_SETTINGS_RUNTIME */ + +#ifdef CONFIG_HAWKBIT_DDI_NO_SECURITY +#define HAWKBIT_DDI_SECURITY_TOKEN NULL +#elif defined(CONFIG_HAWKBIT_SET_SETTINGS_RUNTIME) +#define HAWKBIT_DDI_SECURITY_TOKEN hb_cfg.ddi_security_token +#else +#define HAWKBIT_DDI_SECURITY_TOKEN CONFIG_HAWKBIT_DDI_SECURITY_TOKEN +#endif /* CONFIG_HAWKBIT_DDI_NO_SECURITY */ + +#ifdef CONFIG_HAWKBIT_USE_DYNAMIC_CERT_TAG +#define HAWKBIT_CERT_TAG hb_cfg.tls_tag +#elif defined(HAWKBIT_USE_STATIC_CERT_TAG) +#define HAWKBIT_CERT_TAG CONFIG_HAWKBIT_STATIC_CERT_TAG +#else +#define HAWKBIT_CERT_TAG 0 +#endif /* CONFIG_HAWKBIT_USE_DYNAMIC_CERT_TAG */ struct hawkbit_download { int download_status; @@ -80,7 +126,7 @@ static struct hawkbit_context { struct http_request http_req; struct flash_img_context flash_ctx; uint8_t url_buffer[URL_BUFFER_SIZE]; - uint8_t status_buffer[STATUS_BUFFER_SIZE]; + uint8_t status_buffer[CONFIG_HAWKBIT_STATUS_BUFFER_SIZE]; uint8_t recv_buf_tcp[RECV_BUFFER_SIZE]; enum hawkbit_response code_status; bool final_data_received; @@ -92,9 +138,15 @@ static union { struct hawkbit_cancel cancel; } hawkbit_results; +int hawkbit_default_config_data_cb(const char *device_id, uint8_t *buffer, + const size_t buffer_size); + +static hawkbit_config_device_data_cb_handler_t hawkbit_config_device_data_cb_handler = + hawkbit_default_config_data_cb; + static struct k_work_delayable hawkbit_work_handle; -static struct k_sem probe_sem; +K_SEM_DEFINE(probe_sem, 1, 1); static const struct json_obj_descr json_href_descr[] = { JSON_OBJ_DESCR_PRIM(struct hawkbit_href, href, JSON_TOK_STRING), @@ -130,20 +182,14 @@ static const struct json_obj_descr json_ctl_res_descr[] = { static const struct json_obj_descr json_cfg_data_descr[] = { JSON_OBJ_DESCR_PRIM(struct hawkbit_cfg_data, VIN, JSON_TOK_STRING), - JSON_OBJ_DESCR_PRIM(struct hawkbit_cfg_data, hwRevision, JSON_TOK_STRING), }; static const struct json_obj_descr json_cfg_descr[] = { JSON_OBJ_DESCR_PRIM(struct hawkbit_cfg, mode, JSON_TOK_STRING), JSON_OBJ_DESCR_OBJECT(struct hawkbit_cfg, data, json_cfg_data_descr), - JSON_OBJ_DESCR_PRIM(struct hawkbit_cfg, id, JSON_TOK_STRING), - JSON_OBJ_DESCR_PRIM(struct hawkbit_cfg, time, JSON_TOK_STRING), - JSON_OBJ_DESCR_OBJECT(struct hawkbit_cfg, status, json_status_descr), }; static const struct json_obj_descr json_close_descr[] = { - JSON_OBJ_DESCR_PRIM(struct hawkbit_close, id, JSON_TOK_STRING), - JSON_OBJ_DESCR_PRIM(struct hawkbit_close, time, JSON_TOK_STRING), JSON_OBJ_DESCR_OBJECT(struct hawkbit_close, status, json_status_descr), }; @@ -190,17 +236,118 @@ static const struct json_obj_descr json_dep_res_descr[] = { }; static const struct json_obj_descr json_dep_fbk_descr[] = { - JSON_OBJ_DESCR_PRIM(struct hawkbit_dep_fbk, id, JSON_TOK_STRING), JSON_OBJ_DESCR_OBJECT(struct hawkbit_dep_fbk, status, json_status_descr), }; +static int hawkbit_settings_set(const char *name, size_t len, settings_read_cb read_cb, + void *cb_arg) +{ + const char *next; + int rc; + + if (settings_name_steq(name, "action_id", &next) && !next) { + if (len != sizeof(hb_cfg.action_id)) { + return -EINVAL; + } + + rc = read_cb(cb_arg, &hb_cfg.action_id, sizeof(hb_cfg.action_id)); + LOG_DBG("<%s> = %d", "hawkbit/action_id", hb_cfg.action_id); + if (rc >= 0) { + return 0; + } + + return rc; + } + +#ifdef CONFIG_HAWKBIT_SET_SETTINGS_RUNTIME + if (settings_name_steq(name, "server_addr", &next) && !next) { + if (len != sizeof(hb_cfg.server_addr)) { + return -EINVAL; + } + + rc = read_cb(cb_arg, &hb_cfg.server_addr, sizeof(hb_cfg.server_addr)); + LOG_DBG("<%s> = %s", "hawkbit/server_addr", hb_cfg.server_addr); + if (rc >= 0) { + return 0; + } + + return rc; + } + + if (settings_name_steq(name, "server_port", &next) && !next) { + if (len != sizeof(uint16_t)) { + return -EINVAL; + } + + uint16_t hawkbit_port = atoi(hb_cfg.server_port); + + rc = read_cb(cb_arg, &hawkbit_port, sizeof(hawkbit_port)); + if (hawkbit_port != atoi(hb_cfg.server_port)) { + snprintf(hb_cfg.server_port, sizeof(hb_cfg.server_port), "%u", + hawkbit_port); + } + LOG_DBG("<%s> = %s", "hawkbit/server_port", hb_cfg.server_port); + if (rc >= 0) { + return 0; + } + + return rc; + } + + if (settings_name_steq(name, "ddi_token", &next) && !next) { +#ifdef CONFIG_HAWKBIT_DDI_NO_SECURITY + rc = read_cb(cb_arg, NULL, 0); +#else + if (len != sizeof(hb_cfg.ddi_security_token)) { + return -EINVAL; + } + + rc = read_cb(cb_arg, &hb_cfg.ddi_security_token, sizeof(hb_cfg.ddi_security_token)); + LOG_DBG("<%s> = %s", "hawkbit/ddi_token", hb_cfg.ddi_security_token); + if (rc >= 0) { + return 0; + } +#endif /* CONFIG_HAWKBIT_DDI_NO_SECURITY */ + return rc; + } +#else /* CONFIG_HAWKBIT_SET_SETTINGS_RUNTIME */ + if (settings_name_steq(name, "server_addr", NULL) || + settings_name_steq(name, "server_port", NULL) || + settings_name_steq(name, "ddi_token", NULL)) { + rc = read_cb(cb_arg, NULL, 0); + return 0; + } +#endif /* CONFIG_HAWKBIT_SET_SETTINGS_RUNTIME */ + + return -ENOENT; +} + +static int hawkbit_settings_export(int (*cb)(const char *name, const void *value, size_t val_len)) +{ + LOG_DBG("export hawkbit settings"); + (void)cb("hawkbit/action_id", &hb_cfg.action_id, sizeof(hb_cfg.action_id)); +#ifdef CONFIG_HAWKBIT_SET_SETTINGS_RUNTIME + (void)cb("hawkbit/server_addr", &hb_cfg.server_addr, sizeof(hb_cfg.server_addr)); + uint16_t hawkbit_port = atoi(hb_cfg.server_port); + (void)cb("hawkbit/server_port", &hawkbit_port, sizeof(hawkbit_port)); +#ifndef CONFIG_HAWKBIT_DDI_NO_SECURITY + (void)cb("hawkbit/ddi_token", &hb_cfg.ddi_security_token, + sizeof(hb_cfg.ddi_security_token)); +#endif /* CONFIG_HAWKBIT_DDI_NO_SECURITY */ +#endif /* CONFIG_HAWKBIT_SET_SETTINGS_RUNTIME */ + return 0; +} + +SETTINGS_STATIC_HANDLER_DEFINE(hawkbit, "hawkbit", NULL, hawkbit_settings_set, NULL, + hawkbit_settings_export); + static bool start_http_client(void) { int ret = -1; struct zsock_addrinfo *addr; struct zsock_addrinfo hints = {0}; int resolve_attempts = 10; - int protocol = IS_ENABLED(CONFIG_NET_SOCKETS_SOCKOPT_TLS) ? IPPROTO_TLS_1_2 : IPPROTO_TCP; + int protocol = IS_ENABLED(CONFIG_HAWKBIT_USE_TLS) ? IPPROTO_TLS_1_2 : IPPROTO_TCP; if (IS_ENABLED(CONFIG_NET_IPV6)) { hints.ai_family = AF_INET6; @@ -211,7 +358,7 @@ static bool start_http_client(void) } while (resolve_attempts--) { - ret = zsock_getaddrinfo(CONFIG_HAWKBIT_SERVER, CONFIG_HAWKBIT_PORT, &hints, &addr); + ret = zsock_getaddrinfo(HAWKBIT_SERVER, HAWKBIT_PORT, &hints, &addr); if (ret == 0) { break; } @@ -230,9 +377,9 @@ static bool start_http_client(void) goto err; } -#if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS) +#ifdef CONFIG_HAWKBIT_USE_TLS sec_tag_t sec_tag_opt[] = { - CA_CERTIFICATE_TAG, + HAWKBIT_CERT_TAG, }; if (zsock_setsockopt(hb_context.sock, SOL_TLS, TLS_SEC_TAG_LIST, sec_tag_opt, @@ -240,12 +387,11 @@ static bool start_http_client(void) LOG_ERR("Failed to set TLS_TAG option"); goto err_sock; } - - if (zsock_setsockopt(hb_context.sock, SOL_TLS, TLS_HOSTNAME, CONFIG_HAWKBIT_SERVER, - sizeof(CONFIG_HAWKBIT_SERVER)) < 0) { + if (zsock_setsockopt(hb_context.sock, SOL_TLS, TLS_HOSTNAME, HAWKBIT_SERVER, + sizeof(HAWKBIT_SERVER)) < 0) { goto err_sock; } -#endif +#endif /* CONFIG_HAWKBIT_USE_TLS */ if (zsock_connect(hb_context.sock, addr->ai_addr, addr->ai_addrlen) < 0) { LOG_ERR("Failed to connect to server"); @@ -326,8 +472,9 @@ static const char *hawkbit_status_execution(enum hawkbit_status_exec e) static int hawkbit_device_acid_update(int32_t new_value) { int ret; + hb_cfg.action_id = new_value; - ret = nvs_write(&fs, ADDRESS_ID, &new_value, sizeof(new_value)); + ret = settings_save_one("hawkbit/action_id", &hb_cfg.action_id, sizeof(hb_cfg.action_id)); if (ret < 0) { LOG_ERR("Failed to write device id: %d", ret); return -EIO; @@ -336,6 +483,23 @@ static int hawkbit_device_acid_update(int32_t new_value) return 0; } +int hawkbit_reset_action_id(void) +{ + int ret; + + if (k_sem_take(&probe_sem, K_NO_WAIT) == 0) { + ret = hawkbit_device_acid_update(0); + k_sem_give(&probe_sem); + return ret; + } + return -EAGAIN; +} + +int32_t hawkbit_get_action_id(void) +{ + return hb_cfg.action_id; +} + /* * Update sleep interval, based on results from hawkBit base polling * resource @@ -553,37 +717,105 @@ static void hawkbit_dump_deployment(struct hawkbit_dep_res *d) LOG_DBG("%s=%s", "md5sum-http", l->md5sum_http.href); } +int hawkbit_set_custom_data_cb(hawkbit_config_device_data_cb_handler_t cb) +{ + if (IS_ENABLED(CONFIG_HAWKBIT_CUSTOM_ATTRIBUTES)) { + if (cb == NULL) { + LOG_ERR("Invalid callback"); + return -EINVAL; + } + + hawkbit_config_device_data_cb_handler = cb; + + return 0; + } + return -ENOTSUP; +} + +int hawkbit_default_config_data_cb(const char *device_id, uint8_t *buffer, const size_t buffer_size) +{ + struct hawkbit_cfg cfg = { + .mode = "merge", + .data.VIN = device_id, + }; + + return json_obj_encode_buf(json_cfg_descr, ARRAY_SIZE(json_cfg_descr), &cfg, buffer, + buffer_size); +} + +#ifdef CONFIG_HAWKBIT_SET_SETTINGS_RUNTIME +int hawkbit_set_config(struct hawkbit_runtime_config *config) +{ + if (k_sem_take(&probe_sem, HAWKBIT_SET_SERVER_TIMEOUT) == 0) { + if (config->server_addr != NULL) { + strncpy(hb_cfg.server_addr, config->server_addr, + sizeof(hb_cfg.server_addr)); + LOG_DBG("configured %s: %s", "hawkbit/server_addr", hb_cfg.server_addr); + } + if (config->server_port != 0) { + snprintf(hb_cfg.server_port, sizeof(hb_cfg.server_port), "%u", + config->server_port); + LOG_DBG("configured %s: %s", "hawkbit/server_port", hb_cfg.server_port); + } +#ifndef CONFIG_HAWKBIT_DDI_NO_SECURITY + if (config->auth_token != NULL) { + strncpy(hb_cfg.ddi_security_token, config->auth_token, + sizeof(hb_cfg.ddi_security_token)); + LOG_DBG("configured %s: %s", "hawkbit/ddi_token", + hb_cfg.ddi_security_token); + } +#endif /* CONFIG_HAWKBIT_DDI_NO_SECURITY */ +#ifdef CONFIG_HAWKBIT_USE_DYNAMIC_CERT_TAG + if (config->tls_tag != 0) { + hb_cfg.tls_tag = config->tls_tag; + LOG_DBG("configured %s: %d", "hawkbit/tls_tag", hb_cfg.tls_tag); + } +#endif /* CONFIG_HAWKBIT_USE_DYNAMIC_CERT_TAG */ + settings_save(); + k_sem_give(&probe_sem); + } else { + LOG_WRN("failed setting config"); + return -EAGAIN; + } + + return 0; +} +#endif /* CONFIG_HAWKBIT_SET_SETTINGS_RUNTIME */ + +struct hawkbit_runtime_config hawkbit_get_config(void) +{ + struct hawkbit_runtime_config config = { + .server_addr = HAWKBIT_SERVER, + .server_port = HAWKBIT_PORT_INT, + .auth_token = HAWKBIT_DDI_SECURITY_TOKEN, + .tls_tag = HAWKBIT_CERT_TAG, + }; + + return config; +} + int hawkbit_init(void) { bool image_ok; - int ret = 0, rc = 0; - struct flash_pages_info info; - int32_t action_id; + int ret = 0; - fs.flash_device = STORAGE_DEV; - if (!device_is_ready(fs.flash_device)) { - LOG_ERR("Flash device not ready"); - return -ENODEV; + if (hawkbit_initialized) { + return 0; } - fs.offset = STORAGE_OFFSET; - rc = flash_get_page_info_by_offs(fs.flash_device, fs.offset, &info); - if (rc) { - LOG_ERR("Failed to get storage page info: %d", rc); - return -EIO; + ret = settings_subsys_init(); + if (ret < 0) { + LOG_ERR("Failed to initialize settings subsystem: %d", ret); + return ret; } - fs.sector_size = info.size; - fs.sector_count = 3U; - - rc = nvs_mount(&fs); - if (rc) { - LOG_ERR("Failed to mount storage flash: %d", rc); - return rc; + ret = settings_load_subtree("hawkbit"); + if (ret < 0) { + LOG_ERR("Failed to load settings: %d", ret); + return ret; } - rc = nvs_read(&fs, ADDRESS_ID, &action_id, sizeof(action_id)); - LOG_DBG("Current action_id: %d", action_id); + LOG_DBG("Current action_id: %d", hb_cfg.action_id); image_ok = boot_is_img_confirmed(); LOG_INF("Current image is%s confirmed", image_ok ? "" : " not"); @@ -596,13 +828,12 @@ int hawkbit_init(void) LOG_DBG("Marked current image as OK"); ret = boot_erase_img_bank(FIXED_PARTITION_ID(SLOT1_LABEL)); - if (ret) { + if (ret < 0) { LOG_ERR("Failed to erase second slot: %d", ret); return ret; } } - - k_sem_init(&probe_sem, 1, 1); + hawkbit_initialized = true; return ret; } @@ -779,35 +1010,23 @@ static bool send_request(enum http_method method, enum hawkbit_http_request type enum hawkbit_status_fini finished, enum hawkbit_status_exec execution) { int ret = 0; - - struct hawkbit_cfg cfg; - struct hawkbit_close close; - struct hawkbit_dep_fbk feedback; - char acid[11]; - const char *fini = hawkbit_status_finished(finished); - const char *exec = hawkbit_status_execution(execution); - char device_id[DEVICE_ID_HEX_MAX_SIZE] = { 0 }; #ifndef CONFIG_HAWKBIT_DDI_NO_SECURITY - static const char *const headers[] = { -#ifdef CONFIG_HAWKBIT_DDI_GATEWAY_SECURITY - "Authorization: GatewayToken " CONFIG_HAWKBIT_DDI_SECURITY_TOKEN "\r\n", +#ifdef CONFIG_HAWKBIT_SET_SETTINGS_RUNTIME + char header[DDI_SECURITY_TOKEN_SIZE + sizeof(AUTH_HEADER_START) + sizeof(HTTP_CRLF) - 1]; + + snprintf(header, sizeof(header), AUTH_HEADER_FULL, hb_cfg.ddi_security_token); + const char *const headers[] = {header, NULL}; #else - "Authorization: TargetToken " CONFIG_HAWKBIT_DDI_SECURITY_TOKEN "\r\n", -#endif /* CONFIG_HAWKBIT_DDI_GATEWAY_SECURITY */ - NULL - }; + static const char *const headers[] = {AUTH_HEADER_FULL, NULL}; +#endif /* CONFIG_HAWKBIT_SET_SETTINGS_RUNTIME */ #endif /* CONFIG_HAWKBIT_DDI_NO_SECURITY */ - if (!hawkbit_get_device_identity(device_id, DEVICE_ID_HEX_MAX_SIZE)) { - hb_context.code_status = HAWKBIT_METADATA_ERROR; - } - memset(&hb_context.http_req, 0, sizeof(hb_context.http_req)); memset(&hb_context.recv_buf_tcp, 0, sizeof(hb_context.recv_buf_tcp)); hb_context.http_req.url = hb_context.url_buffer; hb_context.http_req.method = method; - hb_context.http_req.host = CONFIG_HAWKBIT_SERVER; - hb_context.http_req.port = CONFIG_HAWKBIT_PORT; + hb_context.http_req.host = HAWKBIT_SERVER; + hb_context.http_req.port = HAWKBIT_PORT; hb_context.http_req.protocol = "HTTP/1.1"; hb_context.http_req.response = response_cb; hb_context.http_req.recv_buf = hb_context.recv_buf_tcp; @@ -819,6 +1038,10 @@ static bool send_request(enum http_method method, enum hawkbit_http_request type switch (type) { case HAWKBIT_PROBE: + /* + * Root resource for an individual Target + * GET: /{tenant}/controller/v1/{controllerId} + */ ret = http_client_req(hb_context.sock, &hb_context.http_req, HAWKBIT_RECV_TIMEOUT, "HAWKBIT_PROBE"); if (ret < 0) { @@ -829,18 +1052,18 @@ static bool send_request(enum http_method method, enum hawkbit_http_request type break; case HAWKBIT_CONFIG_DEVICE: - memset(&cfg, 0, sizeof(cfg)); - cfg.mode = "merge"; - cfg.data.VIN = device_id; - cfg.data.hwRevision = "3"; - cfg.id = ""; - cfg.time = ""; - cfg.status.execution = exec; - cfg.status.result.finished = fini; - - ret = json_obj_encode_buf(json_cfg_descr, ARRAY_SIZE(json_cfg_descr), &cfg, - hb_context.status_buffer, - sizeof(hb_context.status_buffer)); + /* + * Feedback channel for the config data action + * POST: /{tenant}/controller/v1/{controllerId}/configData + */ + char device_id[DEVICE_ID_HEX_MAX_SIZE] = {0}; + + if (!hawkbit_get_device_identity(device_id, DEVICE_ID_HEX_MAX_SIZE)) { + hb_context.code_status = HAWKBIT_METADATA_ERROR; + } + + ret = hawkbit_config_device_data_cb_handler(device_id, hb_context.status_buffer, + sizeof(hb_context.status_buffer)); if (ret) { LOG_ERR("Can't encode the JSON script (%s): %d", "HAWKBIT_CONFIG_DEVICE", ret); @@ -862,13 +1085,14 @@ static bool send_request(enum http_method method, enum hawkbit_http_request type break; case HAWKBIT_CLOSE: - memset(&close, 0, sizeof(close)); - memset(&hb_context.status_buffer, 0, sizeof(hb_context.status_buffer)); - snprintk(acid, sizeof(acid), "%d", hb_context.action_id); - close.id = acid; - close.time = ""; - close.status.execution = exec; - close.status.result.finished = fini; + /* + * Feedback channel for cancel actions + * POST: /{tenant}/controller/v1/{controllerId}/cancelAction/{actionId}/feedback + */ + struct hawkbit_close close = { + .status.execution = hawkbit_status_execution(execution), + .status.result.finished = hawkbit_status_finished(finished), + }; ret = json_obj_encode_buf(json_close_descr, ARRAY_SIZE(json_close_descr), &close, hb_context.status_buffer, @@ -892,6 +1116,10 @@ static bool send_request(enum http_method method, enum hawkbit_http_request type break; case HAWKBIT_PROBE_DEPLOYMENT_BASE: + /* + * Resource for software module (Deployment Base) + * GET: /{tenant}/controller/v1/{controllerId}/deploymentBase/{actionId} + */ hb_context.http_req.content_type_value = NULL; ret = http_client_req(hb_context.sock, &hb_context.http_req, HAWKBIT_RECV_TIMEOUT, "HAWKBIT_PROBE_DEPLOYMENT_BASE"); @@ -904,18 +1132,20 @@ static bool send_request(enum http_method method, enum hawkbit_http_request type break; case HAWKBIT_REPORT: - if (!fini || !exec) { - return -EINVAL; - } + /* + * Feedback channel for the DeploymentBase action + * POST: /{tenant}/controller/v1/{controllerId}/deploymentBase/{actionId}/feedback + */ + const char *fini = hawkbit_status_finished(finished); + const char *exec = hawkbit_status_execution(execution); LOG_INF("Reporting deployment feedback %s (%s) for action %d", fini, exec, hb_context.json_action_id); - /* Build JSON */ - memset(&feedback, 0, sizeof(feedback)); - snprintk(acid, sizeof(acid), "%d", hb_context.json_action_id); - feedback.id = acid; - feedback.status.result.finished = fini; - feedback.status.execution = exec; + + struct hawkbit_dep_fbk feedback = { + .status.execution = exec, + .status.result.finished = fini, + }; ret = json_obj_encode_buf(json_dep_fbk_descr, ARRAY_SIZE(json_dep_fbk_descr), &feedback, hb_context.status_buffer, @@ -939,6 +1169,11 @@ static bool send_request(enum http_method method, enum hawkbit_http_request type break; case HAWKBIT_DOWNLOAD: + /* + * Resource for software module (Deployment Base) + * GET: /{tenant}/controller/v1/{controllerId}/softwaremodules/{softwareModuleId}/ + * artifacts/{fileName} + */ ret = http_client_req(hb_context.sock, &hb_context.http_req, HAWKBIT_RECV_TIMEOUT, "HAWKBIT_DOWNLOAD"); if (ret < 0) { @@ -958,10 +1193,43 @@ void hawkbit_reboot(void) sys_reboot(SYS_REBOOT_WARM); } +static bool check_hawkbit_server(void) +{ + if (strlen(HAWKBIT_SERVER) == 0) { + if (sizeof(CONFIG_HAWKBIT_SERVER) > 1) { + hawkbit_set_server_addr(CONFIG_HAWKBIT_SERVER); + } else { + LOG_ERR("no valid %s found", "hawkbit/server_addr"); + return false; + } + } + + if (HAWKBIT_PORT_INT == 0) { + if (CONFIG_HAWKBIT_PORT > 0) { + hawkbit_set_server_port(CONFIG_HAWKBIT_PORT); + } else { + LOG_ERR("no valid %s found", "hawkbit/server_port"); + return false; + } + } + +#ifndef CONFIG_HAWKBIT_DDI_NO_SECURITY + if (strlen(HAWKBIT_DDI_SECURITY_TOKEN) == 0) { + if (sizeof(CONFIG_HAWKBIT_DDI_SECURITY_TOKEN) > 1) { + hawkbit_set_ddi_security_token(CONFIG_HAWKBIT_DDI_SECURITY_TOKEN); + } else { + LOG_ERR("no valid %s found", "hawkbit/ddi_token"); + return false; + } + } +#endif /* CONFIG_HAWKBIT_DDI_NO_SECURITY */ + + return true; +} + enum hawkbit_response hawkbit_probe(void) { int ret; - int32_t action_id; int32_t file_size = 0; struct flash_img_check fic; char device_id[DEVICE_ID_HEX_MAX_SIZE] = { 0 }, @@ -970,6 +1238,14 @@ enum hawkbit_response hawkbit_probe(void) deployment_base[DEPLOYMENT_BASE_SIZE] = { 0 }, firmware_version[BOOT_IMG_VER_STRLEN_MAX] = { 0 }; + if (!hawkbit_initialized) { + return HAWKBIT_NOT_INITIALIZED; + } + + if (!check_hawkbit_server()) { + return HAWKBIT_NETWORKING_ERROR; + } + if (k_sem_take(&probe_sem, K_NO_WAIT) != 0) { return HAWKBIT_PROBE_IN_PROGRESS; } @@ -1106,9 +1382,7 @@ enum hawkbit_response hawkbit_probe(void) goto cleanup; } - nvs_read(&fs, ADDRESS_ID, &action_id, sizeof(action_id)); - - if (action_id == (int32_t)hb_context.json_action_id) { + if (hb_cfg.action_id == (int32_t)hb_context.json_action_id) { LOG_INF("Preventing repeated attempt to install %d", hb_context.json_action_id); hb_context.dl.http_content_size = 0; memset(hb_context.url_buffer, 0, sizeof(hb_context.url_buffer)); @@ -1228,6 +1502,10 @@ static void autohandler(struct k_work *work) LOG_INF("Metadata error"); break; + case HAWKBIT_NOT_INITIALIZED: + LOG_INF("hawkBit not initialized"); + break; + case HAWKBIT_PROBE_IN_PROGRESS: LOG_INF("hawkBit is already running"); break; diff --git a/subsys/mgmt/hawkbit/hawkbit_device.c b/subsys/mgmt/hawkbit/hawkbit_device.c index 05b92026dc3..b2d2183558a 100644 --- a/subsys/mgmt/hawkbit/hawkbit_device.c +++ b/subsys/mgmt/hawkbit/hawkbit_device.c @@ -5,8 +5,19 @@ */ #include "hawkbit_device.h" #include +#include + +static bool hawkbit_get_device_identity_default(char *id, int id_max_len); + +static hawkbit_get_device_identity_cb_handler_t hawkbit_get_device_identity_cb_handler = + hawkbit_get_device_identity_default; bool hawkbit_get_device_identity(char *id, int id_max_len) +{ + return hawkbit_get_device_identity_cb_handler(id, id_max_len); +} + +static bool hawkbit_get_device_identity_default(char *id, int id_max_len) { uint8_t hwinfo_id[DEVICE_ID_BIN_MAX_SIZE]; ssize_t length; @@ -21,3 +32,16 @@ bool hawkbit_get_device_identity(char *id, int id_max_len) return length > 0; } + +#ifdef CONFIG_HAWKBIT_CUSTOM_DEVICE_ID +int hawkbit_set_device_identity_cb(hawkbit_get_device_identity_cb_handler_t cb) +{ + if (cb == NULL) { + return -EINVAL; + } + + hawkbit_get_device_identity_cb_handler = cb; + + return 0; +} +#endif /* CONFIG_HAWKBIT_CUSTOM_DEVICE_ID */ diff --git a/subsys/mgmt/hawkbit/hawkbit_device.h b/subsys/mgmt/hawkbit/hawkbit_device.h index 9af19794e92..3016263fe70 100644 --- a/subsys/mgmt/hawkbit/hawkbit_device.h +++ b/subsys/mgmt/hawkbit/hawkbit_device.h @@ -10,8 +10,13 @@ #include #include +#ifdef CONFIG_HAWKBIT_CUSTOM_DEVICE_ID +#define DEVICE_ID_BIN_MAX_SIZE (CONFIG_HAWKBIT_DEVICE_ID_MAX_LENGTH / 2) +#define DEVICE_ID_HEX_MAX_SIZE (CONFIG_HAWKBIT_DEVICE_ID_MAX_LENGTH + 1) +#else #define DEVICE_ID_BIN_MAX_SIZE 16 #define DEVICE_ID_HEX_MAX_SIZE ((DEVICE_ID_BIN_MAX_SIZE * 2) + 1) +#endif bool hawkbit_get_device_identity(char *id, int id_max_len); diff --git a/subsys/mgmt/hawkbit/hawkbit_priv.h b/subsys/mgmt/hawkbit/hawkbit_priv.h index aa1b97524f3..508d3b16f33 100644 --- a/subsys/mgmt/hawkbit/hawkbit_priv.h +++ b/subsys/mgmt/hawkbit/hawkbit_priv.h @@ -81,20 +81,14 @@ struct hawkbit_ctl_res { struct hawkbit_cfg_data { const char *VIN; - const char *hwRevision; }; struct hawkbit_cfg { const char *mode; struct hawkbit_cfg_data data; - const char *id; - const char *time; - struct hawkbit_status status; }; struct hawkbit_close { - char *id; - const char *time; struct hawkbit_status status; }; @@ -142,7 +136,6 @@ struct hawkbit_dep_res { }; struct hawkbit_dep_fbk { - const char *id; struct hawkbit_status status; }; diff --git a/subsys/mgmt/hawkbit/shell.c b/subsys/mgmt/hawkbit/shell.c index 8b79eb7b223..f4df6474cd1 100644 --- a/subsys/mgmt/hawkbit/shell.c +++ b/subsys/mgmt/hawkbit/shell.c @@ -4,6 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include #include #include #include @@ -17,48 +18,49 @@ static void cmd_run(const struct shell *sh, size_t argc, char **argv) ARG_UNUSED(argc); ARG_UNUSED(argv); - shell_fprintf(sh, SHELL_INFO, "Starting hawkBit run...\n"); + + shell_info(sh, "Starting hawkBit run..."); switch (hawkbit_probe()) { case HAWKBIT_UNCONFIRMED_IMAGE: - shell_fprintf( - sh, SHELL_ERROR, - "Image is unconfirmed." - "Rebooting to revert back to previous confirmed image\n"); - hawkbit_reboot(); + shell_error(sh, "Image is unconfirmed." + "Rebooting to revert back to previous confirmed image"); break; case HAWKBIT_CANCEL_UPDATE: - shell_fprintf(sh, SHELL_INFO, - "hawkBit update Cancelled from server\n"); + shell_info(sh, "hawkBit update cancelled from server"); break; case HAWKBIT_NO_UPDATE: - shell_fprintf(sh, SHELL_INFO, "No update found\n"); + shell_info(sh, "No update found"); break; case HAWKBIT_OK: - shell_fprintf(sh, SHELL_INFO, "Image Already updated\n"); + shell_info(sh, "Image already updated"); break; case HAWKBIT_UPDATE_INSTALLED: - shell_fprintf(sh, SHELL_INFO, "Update Installed\n"); + shell_info(sh, "Update installed"); hawkbit_reboot(); break; case HAWKBIT_DOWNLOAD_ERROR: - shell_fprintf(sh, SHELL_INFO, "Download Error\n"); + shell_error(sh, "Download error"); break; case HAWKBIT_NETWORKING_ERROR: - shell_fprintf(sh, SHELL_INFO, "Networking Error\n"); + shell_error(sh, "Networking error"); break; case HAWKBIT_METADATA_ERROR: - shell_fprintf(sh, SHELL_INFO, "Metadata Error\n"); + shell_error(sh, "Metadata error"); + break; + + case HAWKBIT_NOT_INITIALIZED: + shell_error(sh, "hawkBit not initialized"); break; default: - shell_fprintf(sh, SHELL_ERROR, "Invalid response\n"); + shell_error(sh, "Invalid response"); break; } k_sleep(K_MSEC(1)); @@ -75,17 +77,102 @@ static int cmd_info(const struct shell *sh, size_t argc, char *argv) hawkbit_get_firmware_version(firmware_version, BOOT_IMG_VER_STRLEN_MAX); hawkbit_get_device_identity(device_id, DEVICE_ID_HEX_MAX_SIZE); - shell_fprintf(sh, SHELL_NORMAL, "Unique device id: %s\n", device_id); - shell_fprintf(sh, SHELL_NORMAL, "Firmware Version: %s\n", - firmware_version); + shell_print(sh, "Action id: %d", hawkbit_get_action_id()); + shell_print(sh, "Unique device id: %s", device_id); + shell_print(sh, "Firmware Version: %s", firmware_version); + shell_print(sh, "Server address: %s", hawkbit_get_server_addr()); + shell_print(sh, "Server port: %d", hawkbit_get_server_port()); + shell_print(sh, "DDI security token: %s", + (IS_ENABLED(CONFIG_HAWKBIT_DDI_NO_SECURITY) + ? "" + : hawkbit_get_ddi_security_token())); + + return 0; +} + +static int cmd_init(const struct shell *sh, size_t argc, char *argv) +{ + ARG_UNUSED(argc); + ARG_UNUSED(argv); + + shell_info(sh, "Init hawkBit ..."); + + hawkbit_init(); + + return 0; +} + +static int cmd_reset(const struct shell *sh, size_t argc, char *argv) +{ + ARG_UNUSED(argc); + ARG_UNUSED(argv); + + int ret = hawkbit_reset_action_id(); + + shell_print(sh, "Reset action id %s", (ret == 0) ? "success" : "failed"); return 0; } +#ifdef CONFIG_HAWKBIT_SET_SETTINGS_RUNTIME + +static int cmd_set_addr(const struct shell *sh, size_t argc, char **argv) +{ + if (argc < 2) { + shell_error(sh, "Invalid number of arguments"); + return -EINVAL; + } + + hawkbit_set_server_addr(argv[1]); + + return 0; +} + +static int cmd_set_port(const struct shell *sh, size_t argc, char **argv) +{ + if (argc < 2) { + shell_error(sh, "Invalid number of arguments"); + return -EINVAL; + } + + hawkbit_set_server_port(atoi(argv[1])); + + return 0; +} + +#ifndef CONFIG_HAWKBIT_DDI_NO_SECURITY +static int cmd_set_token(const struct shell *sh, size_t argc, char **argv) +{ + if (argc < 2) { + shell_error(sh, "Invalid number of arguments"); + return -EINVAL; + } + + hawkbit_set_ddi_security_token(argv[1]); + + return 0; +} +#endif /* CONFIG_HAWKBIT_DDI_NO_SECURITY */ + +SHELL_STATIC_SUBCMD_SET_CREATE( + sub_hawkbit_set, + SHELL_CMD(addr, NULL, "Set hawkBit server address", cmd_set_addr), + SHELL_CMD(port, NULL, "Set hawkBit server port", cmd_set_port), +#ifndef CONFIG_HAWKBIT_DDI_NO_SECURITY + SHELL_CMD(ddi_token, NULL, "Set hawkBit DDI Security token", cmd_set_token), +#endif + SHELL_SUBCMD_SET_END); +#endif /* CONFIG_HAWKBIT_SET_SETTINGS_RUNTIME */ + SHELL_STATIC_SUBCMD_SET_CREATE( sub_hawkbit, SHELL_CMD(info, NULL, "Dump hawkBit information", cmd_info), + SHELL_CMD(init, NULL, "Initialize hawkBit", cmd_init), SHELL_CMD(run, NULL, "Trigger an hawkBit update run", cmd_run), + SHELL_CMD(reset, NULL, "Reset the hawkBit action id", cmd_reset), +#ifdef CONFIG_HAWKBIT_SET_SETTINGS_RUNTIME + SHELL_CMD(set, &sub_hawkbit_set, "Set hawkBit settings", NULL), +#endif SHELL_SUBCMD_SET_END); SHELL_CMD_REGISTER(hawkbit, &sub_hawkbit, "hawkBit commands", NULL); diff --git a/subsys/mgmt/mcumgr/grp/fs_mgmt/Kconfig b/subsys/mgmt/mcumgr/grp/fs_mgmt/Kconfig index 95e8a1c2658..2bb7e74fb63 100644 --- a/subsys/mgmt/mcumgr/grp/fs_mgmt/Kconfig +++ b/subsys/mgmt/mcumgr/grp/fs_mgmt/Kconfig @@ -125,7 +125,8 @@ config MCUMGR_GRP_FS_CHECKSUM_IEEE_CRC32 config MCUMGR_GRP_FS_HASH_SHA256 bool "SHA256 hash support" - depends on TINYCRYPT_SHA256 || MBEDTLS_MAC_SHA256_ENABLED + depends on BUILD_WITH_TFM || MBEDTLS_MAC_SHA256_ENABLED + select PSA_WANT_ALG_SHA_256 if BUILD_WITH_TFM help Enable SHA256 hash support for MCUmgr. diff --git a/subsys/mgmt/mcumgr/grp/fs_mgmt/src/fs_mgmt_hash_checksum_sha256.c b/subsys/mgmt/mcumgr/grp/fs_mgmt/src/fs_mgmt_hash_checksum_sha256.c index 118dc93f9ed..5005067f38c 100644 --- a/subsys/mgmt/mcumgr/grp/fs_mgmt/src/fs_mgmt_hash_checksum_sha256.c +++ b/subsys/mgmt/mcumgr/grp/fs_mgmt/src/fs_mgmt_hash_checksum_sha256.c @@ -13,89 +13,41 @@ #include #include -#if defined(CONFIG_TINYCRYPT_SHA256) -#include -#include +#ifdef CONFIG_MBEDTLS_PSA_CRYPTO_CLIENT +#include +typedef psa_hash_operation_t hash_ctx_t; +#define SUCCESS_VALUE PSA_SUCCESS + #else -#include #include -#endif - -#define SHA256_DIGEST_SIZE 32 - -#if defined(CONFIG_TINYCRYPT_SHA256) -/* Tinycrypt SHA256 implementation */ -static int fs_mgmt_hash_checksum_sha256(struct fs_file_t *file, uint8_t *output, - size_t *out_len, size_t len) -{ - int rc = 0; - ssize_t bytes_read = 0; - size_t read_size = CONFIG_MCUMGR_GRP_FS_CHECKSUM_HASH_CHUNK_SIZE; - uint8_t buffer[CONFIG_MCUMGR_GRP_FS_CHECKSUM_HASH_CHUNK_SIZE]; - struct tc_sha256_state_struct sha; - - /* Clear variables prior to calculation */ - *out_len = 0; - memset(output, 0, SHA256_DIGEST_SIZE); - - if (tc_sha256_init(&sha) != TC_CRYPTO_SUCCESS) { - return MGMT_ERR_EUNKNOWN; - } +typedef mbedtls_sha256_context hash_ctx_t; +#define SUCCESS_VALUE 0 - /* Read all data from file and add to SHA256 hash calculation */ - do { - if ((read_size + *out_len) >= len) { - /* Limit read size to size of requested data */ - read_size = len - *out_len; - } - - bytes_read = fs_read(file, buffer, read_size); +#endif /* CONFIG_MBEDTLS_PSA_CRYPTO_CLIENT */ - if (bytes_read < 0) { - /* Failed to read file data, pass generic unknown error back */ - return MGMT_ERR_EUNKNOWN; - } else if (bytes_read > 0) { - if (tc_sha256_update(&sha, buffer, bytes_read) != TC_CRYPTO_SUCCESS) { - return MGMT_ERR_EUNKNOWN; - } +#define SHA256_DIGEST_SIZE 32 - *out_len += bytes_read; - } - } while (bytes_read > 0 && *out_len < len); +/* The API that the different hash implementations provide further down. */ +static int hash_setup(hash_ctx_t *); +static int hash_update(hash_ctx_t *, const uint8_t *input, size_t ilen); +static int hash_finish(hash_ctx_t *, uint8_t *output); +static void hash_teardown(hash_ctx_t *); - /* Finalise SHA256 hash calculation and store output in provided output buffer */ - if (tc_sha256_final(output, &sha) != TC_CRYPTO_SUCCESS) { - rc = MGMT_ERR_EUNKNOWN; - } - - return rc; -} -#else -/* mbedtls SHA256 implementation */ static int fs_mgmt_hash_checksum_sha256(struct fs_file_t *file, uint8_t *output, size_t *out_len, size_t len) { - int rc = 0; + int rc = MGMT_ERR_EUNKNOWN; ssize_t bytes_read = 0; size_t read_size = CONFIG_MCUMGR_GRP_FS_CHECKSUM_HASH_CHUNK_SIZE; uint8_t buffer[CONFIG_MCUMGR_GRP_FS_CHECKSUM_HASH_CHUNK_SIZE]; - mbedtls_md_context_t mbed_hash_ctx; - const mbedtls_md_info_t *mbed_hash_info; + hash_ctx_t hash_ctx; /* Clear variables prior to calculation */ *out_len = 0; memset(output, 0, SHA256_DIGEST_SIZE); - mbed_hash_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256); - mbedtls_md_init(&mbed_hash_ctx); - - if (mbedtls_md_setup(&mbed_hash_ctx, mbed_hash_info, 0) != 0) { - return MGMT_ERR_EUNKNOWN; - } - - if (mbedtls_md_starts(&mbed_hash_ctx)) { - rc = MGMT_ERR_EUNKNOWN; - goto error; + if (hash_setup(&hash_ctx) != SUCCESS_VALUE) { + goto teardown; } /* Read all data from file and add to SHA256 hash calculation */ @@ -108,13 +60,11 @@ static int fs_mgmt_hash_checksum_sha256(struct fs_file_t *file, uint8_t *output, bytes_read = fs_read(file, buffer, read_size); if (bytes_read < 0) { - /* Failed to read file data, pass generic unknown error back */ - rc = MGMT_ERR_EUNKNOWN; - goto error; + /* Failed to read file data */ + goto teardown; } else if (bytes_read > 0) { - if (mbedtls_md_update(&mbed_hash_ctx, buffer, bytes_read) != 0) { - rc = MGMT_ERR_EUNKNOWN; - goto error; + if (hash_update(&hash_ctx, buffer, bytes_read) != SUCCESS_VALUE) { + goto teardown; } *out_len += bytes_read; @@ -122,16 +72,15 @@ static int fs_mgmt_hash_checksum_sha256(struct fs_file_t *file, uint8_t *output, } while (bytes_read > 0 && *out_len < len); /* Finalise SHA256 hash calculation and store output in provided output buffer */ - if (mbedtls_md_finish(&mbed_hash_ctx, output) != 0) { - rc = MGMT_ERR_EUNKNOWN; + if (hash_finish(&hash_ctx, output) == SUCCESS_VALUE) { + rc = 0; } -error: - mbedtls_md_free(&mbed_hash_ctx); +teardown: + hash_teardown(&hash_ctx); return rc; } -#endif static struct fs_mgmt_hash_checksum_group sha256 = { .group_name = "sha256", @@ -149,3 +98,47 @@ void fs_mgmt_hash_checksum_unregister_sha256(void) { fs_mgmt_hash_checksum_unregister_group(&sha256); } + +#ifdef CONFIG_MBEDTLS_PSA_CRYPTO_CLIENT + +static int hash_setup(psa_hash_operation_t *ctx) +{ + *ctx = psa_hash_operation_init(); + return psa_hash_setup(ctx, PSA_ALG_SHA_256); +} +static int hash_update(psa_hash_operation_t *ctx, const uint8_t *input, size_t ilen) +{ + return psa_hash_update(ctx, input, ilen); +} +static int hash_finish(psa_hash_operation_t *ctx, uint8_t *output) +{ + size_t output_length; + + return psa_hash_finish(ctx, output, SHA256_DIGEST_SIZE, &output_length); +} +static void hash_teardown(psa_hash_operation_t *ctx) +{ + psa_hash_abort(ctx); +} + +#else + +static int hash_setup(mbedtls_sha256_context *ctx) +{ + mbedtls_sha256_init(ctx); + return mbedtls_sha256_starts(ctx, false); +} +static int hash_update(mbedtls_sha256_context *ctx, const uint8_t *input, size_t ilen) +{ + return mbedtls_sha256_update(ctx, input, ilen); +} +static int hash_finish(mbedtls_sha256_context *ctx, uint8_t *output) +{ + return mbedtls_sha256_finish(ctx, output); +} +static void hash_teardown(mbedtls_sha256_context *ctx) +{ + mbedtls_sha256_free(ctx); +} + +#endif /* CONFIG_MBEDTLS_PSA_CRYPTO_CLIENT */ diff --git a/subsys/mgmt/mcumgr/grp/img_mgmt/src/zephyr_img_mgmt.c b/subsys/mgmt/mcumgr/grp/img_mgmt/src/zephyr_img_mgmt.c index a67db362366..c899e31a3fb 100644 --- a/subsys/mgmt/mcumgr/grp/img_mgmt/src/zephyr_img_mgmt.c +++ b/subsys/mgmt/mcumgr/grp/img_mgmt/src/zephyr_img_mgmt.c @@ -226,14 +226,11 @@ static int img_mgmt_get_unused_slot_area_id(int slot) #endif } #elif CONFIG_MCUMGR_GRP_IMG_UPDATABLE_IMAGE_NUMBER >= 2 -static int img_mgmt_get_unused_slot_area_id(int image) +static int img_mgmt_get_unused_slot_area_id(unsigned int image) { int area_id = -1; int slot = 0; - if (image == -1) { - image = 0; - } slot = img_mgmt_get_opposite_slot(img_mgmt_active_slot(image)); if (!img_mgmt_slot_in_use(slot)) { diff --git a/subsys/mgmt/mcumgr/transport/src/smp_shell.c b/subsys/mgmt/mcumgr/transport/src/smp_shell.c index 527ab2e47fa..0660235ab69 100644 --- a/subsys/mgmt/mcumgr/transport/src/smp_shell.c +++ b/subsys/mgmt/mcumgr/transport/src/smp_shell.c @@ -242,7 +242,7 @@ int smp_shell_init(void) rc = smp_transport_init(&smp_shell_transport); #ifdef CONFIG_SMP_CLIENT if (rc == 0) { - smp_client_transport.smpt = &CONFIG_SMP_CLIENT; + smp_client_transport.smpt = &smp_shell_transport; smp_client_transport.smpt_type = SMP_SHELL_TRANSPORT; smp_client_transport_register(&smp_client_transport); } diff --git a/subsys/mgmt/mcumgr/transport/src/smp_udp.c b/subsys/mgmt/mcumgr/transport/src/smp_udp.c index 7daedb861c3..4e47ac8ab11 100644 --- a/subsys/mgmt/mcumgr/transport/src/smp_udp.c +++ b/subsys/mgmt/mcumgr/transport/src/smp_udp.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include diff --git a/subsys/mgmt/updatehub/CMakeLists.txt b/subsys/mgmt/updatehub/CMakeLists.txt index 067e6168d97..7db24bf51e2 100644 --- a/subsys/mgmt/updatehub/CMakeLists.txt +++ b/subsys/mgmt/updatehub/CMakeLists.txt @@ -1,7 +1,7 @@ # # Copyright (c) 2018-2023 O.S.Systems # -# SPDX -License-Identifier: Apache-2.0 +# SPDX-License-Identifier: Apache-2.0 # zephyr_syscall_header( diff --git a/subsys/mgmt/updatehub/Kconfig b/subsys/mgmt/updatehub/Kconfig index bc1c4fb1d1c..93859499e59 100644 --- a/subsys/mgmt/updatehub/Kconfig +++ b/subsys/mgmt/updatehub/Kconfig @@ -1,5 +1,5 @@ # Copyright (c) 2018-2023 O.S.Systems -# SPDX -License-Identifier: Apache-2.0 +# SPDX-License-Identifier: Apache-2.0 menuconfig UPDATEHUB bool"UpdateHub Firmware Over-the-Air support" diff --git a/subsys/mgmt/updatehub/updatehub.c b/subsys/mgmt/updatehub/updatehub.c index 886f10634bc..1886b634a76 100644 --- a/subsys/mgmt/updatehub/updatehub.c +++ b/subsys/mgmt/updatehub/updatehub.c @@ -847,19 +847,31 @@ enum updatehub_response z_impl_updatehub_probe(void) recv_probe_sh_string_descr, ARRAY_SIZE(recv_probe_sh_string_descr), &metadata_any_boards) < 0) { - LOG_ERR("Could not parse json"); + LOG_ERR("Could not parse the json"); ctx.code_status = UPDATEHUB_METADATA_ERROR; goto cleanup; } + LOG_DBG("elements: %d", metadata_any_boards.objects_len); + for (size_t i = 0; i < metadata_any_boards.objects_len; ++i) { + LOG_DBG("obj[%d].elements: %d", + i, metadata_any_boards.objects[i].objects_len); + for (size_t j = 0; j < metadata_any_boards.objects[i].objects_len; ++j) { + struct resp_probe_objects *obj = + &metadata_any_boards.objects[i].objects[j].objects; + LOG_DBG("\tMode: %s\n\tSHA: %s\n\tSize: %d", + obj->mode, obj->sha256sum, obj->size); + } + } + if (metadata_any_boards.objects_len != 2) { - LOG_ERR("Could not parse json"); + LOG_ERR("Object length of type 'any metadata' is incorrect"); ctx.code_status = UPDATEHUB_METADATA_ERROR; goto cleanup; } sha256size = strlen( - metadata_any_boards.objects[1].objects.sha256sum) + 1; + metadata_any_boards.objects[1].objects[0].objects.sha256sum) + 1; if (sha256size != SHA256_HEX_DIGEST_SIZE) { LOG_ERR("SHA256 size is invalid"); @@ -868,14 +880,26 @@ enum updatehub_response z_impl_updatehub_probe(void) } memcpy(update_info.sha256sum_image, - metadata_any_boards.objects[1].objects.sha256sum, + metadata_any_boards.objects[1].objects[0].objects.sha256sum, SHA256_HEX_DIGEST_SIZE); - update_info.image_size = metadata_any_boards.objects[1].objects.size; + update_info.image_size = metadata_any_boards.objects[1].objects[0].objects.size; LOG_DBG("metadata_any: %s", update_info.sha256sum_image); } else { + LOG_DBG("elements: %d\n", metadata_some_boards.objects_len); + for (size_t i = 0; i < metadata_some_boards.objects_len; ++i) { + LOG_DBG("obj[%d].elements: %d\n", + i, metadata_some_boards.objects[i].objects_len); + for (size_t j = 0; j < metadata_some_boards.objects[i].objects_len; ++j) { + struct resp_probe_objects *obj = + &metadata_some_boards.objects[i].objects[j].objects; + LOG_DBG("\tMode: %s\n\tSHA: %s\n\tSize: %d\n", + obj->mode, obj->sha256sum, obj->size); + } + } + if (metadata_some_boards.objects_len != 2) { - LOG_ERR("Could not parse json"); + LOG_ERR("Object length of type 'some metadata' is incorrect"); ctx.code_status = UPDATEHUB_METADATA_ERROR; goto cleanup; } @@ -888,7 +912,7 @@ enum updatehub_response z_impl_updatehub_probe(void) } sha256size = strlen( - metadata_some_boards.objects[1].objects.sha256sum) + 1; + metadata_some_boards.objects[1].objects[0].objects.sha256sum) + 1; if (sha256size != SHA256_HEX_DIGEST_SIZE) { LOG_ERR("SHA256 size is invalid"); @@ -897,10 +921,10 @@ enum updatehub_response z_impl_updatehub_probe(void) } memcpy(update_info.sha256sum_image, - metadata_some_boards.objects[1].objects.sha256sum, + metadata_some_boards.objects[1].objects[0].objects.sha256sum, SHA256_HEX_DIGEST_SIZE); update_info.image_size = - metadata_some_boards.objects[1].objects.size; + metadata_some_boards.objects[1].objects[0].objects.size; LOG_DBG("metadata_some: %s", update_info.sha256sum_image); } @@ -942,7 +966,7 @@ enum updatehub_response z_impl_updatehub_update(void) if (updatehub_storage_mark_partition_to_upgrade(&ctx.storage_ctx, UPDATEHUB_SLOT_PARTITION_1)) { - LOG_ERR("Could not reporting downloaded state"); + LOG_ERR("Could not mark partition to upgrade"); ctx.code_status = UPDATEHUB_INSTALL_ERROR; goto error; } diff --git a/subsys/mgmt/updatehub/updatehub_priv.h b/subsys/mgmt/updatehub/updatehub_priv.h index ebfedcbb02a..707e2db6c6d 100644 --- a/subsys/mgmt/updatehub/updatehub_priv.h +++ b/subsys/mgmt/updatehub/updatehub_priv.h @@ -97,15 +97,20 @@ struct resp_probe_objects_array { struct resp_probe_objects objects; }; +struct resp_probe_objects_array_array { + struct resp_probe_objects_array objects[4]; + size_t objects_len; +}; + struct resp_probe_any_boards { - struct resp_probe_objects_array objects[2]; + struct resp_probe_objects_array_array objects[2]; size_t objects_len; const char *product; const char *supported_hardware; }; struct resp_probe_some_boards { - struct resp_probe_objects_array objects[2]; + struct resp_probe_objects_array_array objects[2]; size_t objects_len; const char *product; const char *supported_hardware[CONFIG_UPDATEHUB_SUPPORTED_HARDWARE_MAX]; @@ -148,6 +153,13 @@ static const struct json_obj_descr recv_probe_objects_descr_array[] = { objects, recv_probe_objects_descr), }; +static const struct json_obj_descr recv_probe_objects_descr_array_array[] = { + JSON_OBJ_DESCR_ARRAY_ARRAY(struct resp_probe_objects_array_array, + objects, 4, objects_len, + recv_probe_objects_descr_array, + ARRAY_SIZE(recv_probe_objects_descr_array)), +}; + static const struct json_obj_descr recv_probe_sh_string_descr[] = { JSON_OBJ_DESCR_PRIM(struct resp_probe_any_boards, product, JSON_TOK_STRING), @@ -156,8 +168,8 @@ static const struct json_obj_descr recv_probe_sh_string_descr[] = { JSON_TOK_STRING), JSON_OBJ_DESCR_ARRAY_ARRAY(struct resp_probe_any_boards, objects, 2, objects_len, - recv_probe_objects_descr_array, - ARRAY_SIZE(recv_probe_objects_descr_array)), + recv_probe_objects_descr_array_array, + ARRAY_SIZE(recv_probe_objects_descr_array_array)), }; static const struct json_obj_descr recv_probe_sh_array_descr[] = { @@ -169,8 +181,8 @@ static const struct json_obj_descr recv_probe_sh_array_descr[] = { supported_hardware_len, JSON_TOK_STRING), JSON_OBJ_DESCR_ARRAY_ARRAY(struct resp_probe_some_boards, objects, 2, objects_len, - recv_probe_objects_descr_array, - ARRAY_SIZE(recv_probe_objects_descr_array)), + recv_probe_objects_descr_array_array, + ARRAY_SIZE(recv_probe_objects_descr_array_array)), }; static const struct json_obj_descr device_identity_descr[] = { diff --git a/subsys/mgmt/updatehub/updatehub_storage.c b/subsys/mgmt/updatehub/updatehub_storage.c index d18b24be4bc..81886a9044e 100644 --- a/subsys/mgmt/updatehub/updatehub_storage.c +++ b/subsys/mgmt/updatehub/updatehub_storage.c @@ -73,7 +73,7 @@ int updatehub_storage_mark_partition_to_upgrade(struct updatehub_storage_context return -EINVAL; } - return boot_request_upgrade_multi(partition_id, BOOT_UPGRADE_TEST); + return boot_request_upgrade(BOOT_UPGRADE_TEST); } int updatehub_storage_mark_partition_as_confirmed(const uint32_t partition_id) diff --git a/subsys/modem/CMakeLists.txt b/subsys/modem/CMakeLists.txt index a19916a0dd3..b366b73ce21 100644 --- a/subsys/modem/CMakeLists.txt +++ b/subsys/modem/CMakeLists.txt @@ -9,6 +9,7 @@ zephyr_library_sources_ifdef(CONFIG_MODEM_CHAT modem_chat.c) zephyr_library_sources_ifdef(CONFIG_MODEM_CMUX modem_cmux.c) zephyr_library_sources_ifdef(CONFIG_MODEM_PIPE modem_pipe.c) zephyr_library_sources_ifdef(CONFIG_MODEM_PPP modem_ppp.c) +zephyr_library_sources_ifdef(CONFIG_MODEM_STATS modem_stats.c) zephyr_library_sources_ifdef(CONFIG_MODEM_UBX modem_ubx.c) add_subdirectory(backends) diff --git a/subsys/modem/Kconfig b/subsys/modem/Kconfig index a71542a706a..7dfdcbfe635 100644 --- a/subsys/modem/Kconfig +++ b/subsys/modem/Kconfig @@ -59,6 +59,19 @@ config MODEM_PPP_NET_BUF_FRAG_SIZE endif +config MODEM_STATS + bool "Modem statistics" + depends on SHELL + help + Enables modem statistics shell commands which track the usage of + buffers across the modem modules. The statistics are useful for + scaling buffer sizes, as these are application specific. + +config MODEM_STATS_BUFFER_NAME_SIZE + int "Maximum string size of modem stats buffer name" + default 32 + range 8 64 + config MODEM_UBX bool "Modem U-BLOX module" select RING_BUFFER diff --git a/subsys/modem/backends/modem_backend_uart_async.c b/subsys/modem/backends/modem_backend_uart_async.c index c7d4b6297e6..184f83a8e46 100644 --- a/subsys/modem/backends/modem_backend_uart_async.c +++ b/subsys/modem/backends/modem_backend_uart_async.c @@ -42,6 +42,11 @@ static bool modem_backend_uart_async_is_open(struct modem_backend_uart *backend) MODEM_BACKEND_UART_ASYNC_STATE_OPEN_BIT); } +static uint32_t get_receive_buf_length(struct modem_backend_uart *backend) +{ + return ring_buf_size_get(&backend->async.receive_rb); +} + static void modem_backend_uart_async_event_handler(const struct device *dev, struct uart_event *evt, void *user_data) { @@ -54,7 +59,6 @@ static void modem_backend_uart_async_event_handler(const struct device *dev, atomic_clear_bit(&backend->async.state, MODEM_BACKEND_UART_ASYNC_STATE_TRANSMITTING_BIT); k_work_submit(&backend->transmit_idle_work); - break; case UART_TX_ABORTED: @@ -112,7 +116,7 @@ static void modem_backend_uart_async_event_handler(const struct device *dev, evt->data.rx.len); if (received < evt->data.rx.len) { - const unsigned int buf_size = ring_buf_size_get(&backend->async.receive_rb); + const unsigned int buf_size = get_receive_buf_length(backend); ring_buf_reset(&backend->async.receive_rb); k_spin_unlock(&backend->async.receive_rb_lock, key); @@ -171,6 +175,31 @@ static int modem_backend_uart_async_open(void *data) return 0; } +#if CONFIG_MODEM_STATS +static uint32_t get_receive_buf_size(struct modem_backend_uart *backend) +{ + return ring_buf_capacity_get(&backend->async.receive_rb); +} + +static void advertise_transmit_buf_stats(struct modem_backend_uart *backend, uint32_t length) +{ + modem_stats_buffer_advertise_length(&backend->transmit_buf_stats, length); +} + +static void advertise_receive_buf_stats(struct modem_backend_uart *backend) +{ + uint32_t length; + + length = get_receive_buf_length(backend); + modem_stats_buffer_advertise_length(&backend->receive_buf_stats, length); +} +#endif + +static uint32_t get_transmit_buf_size(struct modem_backend_uart *backend) +{ + return backend->async.transmit_buf_size; +} + static int modem_backend_uart_async_transmit(void *data, const uint8_t *buf, size_t size) { struct modem_backend_uart *backend = (struct modem_backend_uart *)data; @@ -185,7 +214,7 @@ static int modem_backend_uart_async_transmit(void *data, const uint8_t *buf, siz } /* Determine amount of bytes to transmit */ - bytes_to_transmit = MIN(size, backend->async.transmit_buf_size); + bytes_to_transmit = MIN(size, get_transmit_buf_size(backend)); /* Copy buf to transmit buffer which is passed to UART */ memcpy(backend->async.transmit_buf, buf, bytes_to_transmit); @@ -193,6 +222,10 @@ static int modem_backend_uart_async_transmit(void *data, const uint8_t *buf, siz ret = uart_tx(backend->uart, backend->async.transmit_buf, bytes_to_transmit, CONFIG_MODEM_BACKEND_UART_ASYNC_TRANSMIT_TIMEOUT_MS * 1000L); +#if CONFIG_MODEM_STATS + advertise_transmit_buf_stats(backend, bytes_to_transmit); +#endif + if (ret != 0) { LOG_ERR("Failed to %s %u bytes. (%d)", "start async transmit for", bytes_to_transmit, ret); @@ -210,6 +243,11 @@ static int modem_backend_uart_async_receive(void *data, uint8_t *buf, size_t siz bool empty; key = k_spin_lock(&backend->async.receive_rb_lock); + +#if CONFIG_MODEM_STATS + advertise_receive_buf_stats(backend); +#endif + received = ring_buf_get(&backend->async.receive_rb, buf, size); empty = ring_buf_is_empty(&backend->async.receive_rb); k_spin_unlock(&backend->async.receive_rb_lock, key); @@ -255,6 +293,23 @@ static void modem_backend_uart_async_notify_closed(struct k_work *item) modem_pipe_notify_closed(&backend->pipe); } +#if CONFIG_MODEM_STATS +static void init_stats(struct modem_backend_uart *backend) +{ + char name[CONFIG_MODEM_STATS_BUFFER_NAME_SIZE]; + uint32_t receive_buf_size; + uint32_t transmit_buf_size; + + receive_buf_size = get_receive_buf_size(backend); + transmit_buf_size = get_transmit_buf_size(backend); + + snprintk(name, sizeof(name), "%s_%s", backend->uart->name, "rx"); + modem_stats_buffer_init(&backend->receive_buf_stats, name, receive_buf_size); + snprintk(name, sizeof(name), "%s_%s", backend->uart->name, "tx"); + modem_stats_buffer_init(&backend->transmit_buf_stats, name, transmit_buf_size); +} +#endif + void modem_backend_uart_async_init(struct modem_backend_uart *backend, const struct modem_backend_uart_config *config) { @@ -273,4 +328,8 @@ void modem_backend_uart_async_init(struct modem_backend_uart *backend, backend->async.transmit_buf_size = config->transmit_buf_size; k_work_init(&backend->async.rx_disabled_work, modem_backend_uart_async_notify_closed); modem_pipe_init(&backend->pipe, backend, &modem_backend_uart_async_api); + +#if CONFIG_MODEM_STATS + init_stats(backend); +#endif } diff --git a/subsys/modem/backends/modem_backend_uart_isr.c b/subsys/modem/backends/modem_backend_uart_isr.c index c67c8f7644e..ea8d99d6032 100644 --- a/subsys/modem/backends/modem_backend_uart_isr.c +++ b/subsys/modem/backends/modem_backend_uart_isr.c @@ -118,9 +118,51 @@ static int modem_backend_uart_isr_open(void *data) return 0; } +static uint32_t get_transmit_buf_length(struct modem_backend_uart *backend) +{ + return atomic_get(&backend->isr.transmit_buf_len); +} + +#if CONFIG_MODEM_STATS +static uint32_t get_receive_buf_length(struct modem_backend_uart *backend) +{ + return ring_buf_size_get(&backend->isr.receive_rdb[0]) + + ring_buf_size_get(&backend->isr.receive_rdb[1]); +} + +static uint32_t get_receive_buf_size(struct modem_backend_uart *backend) +{ + return ring_buf_capacity_get(&backend->isr.receive_rdb[0]) + + ring_buf_capacity_get(&backend->isr.receive_rdb[1]); +} + +static uint32_t get_transmit_buf_size(struct modem_backend_uart *backend) +{ + return ring_buf_capacity_get(&backend->isr.transmit_rb); +} + +static void advertise_transmit_buf_stats(struct modem_backend_uart *backend) +{ + uint32_t length; + + length = get_transmit_buf_length(backend); + modem_stats_buffer_advertise_length(&backend->transmit_buf_stats, length); +} + +static void advertise_receive_buf_stats(struct modem_backend_uart *backend) +{ + uint32_t length; + + uart_irq_rx_disable(backend->uart); + length = get_receive_buf_length(backend); + uart_irq_rx_enable(backend->uart); + modem_stats_buffer_advertise_length(&backend->receive_buf_stats, length); +} +#endif + static bool modem_backend_uart_isr_transmit_buf_above_limit(struct modem_backend_uart *backend) { - return backend->isr.transmit_buf_put_limit < atomic_get(&backend->isr.transmit_buf_len); + return backend->isr.transmit_buf_put_limit < get_transmit_buf_length(backend); } static int modem_backend_uart_isr_transmit(void *data, const uint8_t *buf, size_t size) @@ -138,6 +180,11 @@ static int modem_backend_uart_isr_transmit(void *data, const uint8_t *buf, size_ /* Update transmit buf capacity tracker */ atomic_add(&backend->isr.transmit_buf_len, written); + +#if CONFIG_MODEM_STATS + advertise_transmit_buf_stats(backend); +#endif + return written; } @@ -148,6 +195,10 @@ static int modem_backend_uart_isr_receive(void *data, uint8_t *buf, size_t size) uint32_t read_bytes; uint8_t receive_rdb_unused; +#if CONFIG_MODEM_STATS + advertise_receive_buf_stats(backend); +#endif + read_bytes = 0; receive_rdb_unused = (backend->isr.receive_rdb_used == 1) ? 0 : 1; @@ -189,6 +240,23 @@ struct modem_pipe_api modem_backend_uart_isr_api = { .close = modem_backend_uart_isr_close, }; +#if CONFIG_MODEM_STATS +static void init_stats(struct modem_backend_uart *backend) +{ + char name[CONFIG_MODEM_STATS_BUFFER_NAME_SIZE]; + uint32_t receive_buf_size; + uint32_t transmit_buf_size; + + receive_buf_size = get_receive_buf_size(backend); + transmit_buf_size = get_transmit_buf_size(backend); + + snprintk(name, sizeof(name), "%s_%s", backend->uart->name, "rx"); + modem_stats_buffer_init(&backend->receive_buf_stats, name, receive_buf_size); + snprintk(name, sizeof(name), "%s_%s", backend->uart->name, "tx"); + modem_stats_buffer_init(&backend->transmit_buf_stats, name, transmit_buf_size); +} +#endif + void modem_backend_uart_isr_init(struct modem_backend_uart *backend, const struct modem_backend_uart_config *config) { @@ -215,4 +283,8 @@ void modem_backend_uart_isr_init(struct modem_backend_uart *backend, backend); modem_pipe_init(&backend->pipe, backend, &modem_backend_uart_isr_api); + +#if CONFIG_MODEM_STATS + init_stats(backend); +#endif } diff --git a/subsys/modem/modem_chat.c b/subsys/modem/modem_chat.c index e2b36d19c31..b13334d145b 100644 --- a/subsys/modem/modem_chat.c +++ b/subsys/modem/modem_chat.c @@ -12,6 +12,10 @@ LOG_MODULE_REGISTER(modem_chat, CONFIG_MODEM_MODULES_LOG_LEVEL); #include +const struct modem_chat_match modem_chat_any_match = MODEM_CHAT_MATCH("", "", NULL); +const struct modem_chat_match modem_chat_empty_matches[0]; +const struct modem_chat_script_chat modem_chat_empty_script_chats[0]; + #define MODEM_CHAT_MATCHES_INDEX_RESPONSE (0) #define MODEM_CHAT_MATCHES_INDEX_ABORT (1) #define MODEM_CHAT_MATCHES_INDEX_UNSOL (2) @@ -138,6 +142,42 @@ static void modem_chat_script_clear_response_matches(struct modem_chat *chat) chat->matches_size[MODEM_CHAT_MATCHES_INDEX_RESPONSE] = 0; } +static bool modem_chat_script_chat_has_request(struct modem_chat *chat) +{ + const struct modem_chat_script_chat *script_chat = + &chat->script->script_chats[chat->script_chat_it]; + + return script_chat->request_size > 0; +} + +static bool modem_chat_script_chat_has_matches(struct modem_chat *chat) +{ + const struct modem_chat_script_chat *script_chat = + &chat->script->script_chats[chat->script_chat_it]; + + return script_chat->response_matches_size > 0; +} + +static uint16_t modem_chat_script_chat_get_send_timeout(struct modem_chat *chat) +{ + const struct modem_chat_script_chat *script_chat = + &chat->script->script_chats[chat->script_chat_it]; + + return script_chat->timeout; +} + +static bool modem_chat_script_chat_has_send_timeout(struct modem_chat *chat) +{ + return modem_chat_script_chat_get_send_timeout(chat) > 0; +} + +static void modem_chat_script_chat_schedule_send_timeout(struct modem_chat *chat) +{ + uint16_t timeout = modem_chat_script_chat_get_send_timeout(chat); + + k_work_schedule(&chat->script_send_timeout_work, K_MSEC(timeout)); +} + static void modem_chat_script_next(struct modem_chat *chat, bool initial) { const struct modem_chat_script_chat *script_chat; @@ -162,13 +202,15 @@ static void modem_chat_script_next(struct modem_chat *chat, bool initial) script_chat = &chat->script->script_chats[chat->script_chat_it]; - /* Check if request must be sent */ - if (script_chat->request_size > 0) { + /* Continue script */ + if (modem_chat_script_chat_has_request(chat)) { LOG_DBG("sending: %.*s", script_chat->request_size, script_chat->request); modem_chat_script_clear_response_matches(chat); modem_chat_script_send(chat); - } else { + } else if (modem_chat_script_chat_has_matches(chat)) { modem_chat_script_set_response_matches(chat); + } else { + modem_chat_script_chat_schedule_send_timeout(chat); } } @@ -222,22 +264,6 @@ static void modem_chat_script_abort_handler(struct k_work *item) modem_chat_script_stop(chat, MODEM_CHAT_SCRIPT_RESULT_ABORT); } -static bool modem_chat_script_chat_is_no_response(struct modem_chat *chat) -{ - const struct modem_chat_script_chat *script_chat = - &chat->script->script_chats[chat->script_chat_it]; - - return (script_chat->response_matches_size == 0) ? true : false; -} - -static uint16_t modem_chat_script_chat_get_send_timeout(struct modem_chat *chat) -{ - const struct modem_chat_script_chat *script_chat = - &chat->script->script_chats[chat->script_chat_it]; - - return script_chat->timeout; -} - /* Returns true when request part has been sent */ static bool modem_chat_send_script_request_part(struct modem_chat *chat) { @@ -267,6 +293,9 @@ static bool modem_chat_send_script_request_part(struct modem_chat *chat) request_part_size = request_size - chat->script_send_pos; ret = modem_pipe_transmit(chat->pipe, request_part, request_part_size); if (ret < 1) { + if (ret < 0) { + LOG_ERR("Failed to %s %u bytes. (%d)", "transmit", request_part_size, ret); + } return false; } @@ -279,7 +308,6 @@ static bool modem_chat_send_script_request_part(struct modem_chat *chat) static void modem_chat_script_send_handler(struct k_work *item) { struct modem_chat *chat = CONTAINER_OF(item, struct modem_chat, script_send_work); - uint16_t timeout; if (chat->script == NULL) { return; @@ -306,15 +334,12 @@ static void modem_chat_script_send_handler(struct k_work *item) break; } - if (modem_chat_script_chat_is_no_response(chat)) { - timeout = modem_chat_script_chat_get_send_timeout(chat); - if (timeout == 0) { - modem_chat_script_next(chat, false); - } else { - k_work_schedule(&chat->script_send_timeout_work, K_MSEC(timeout)); - } - } else { + if (modem_chat_script_chat_has_matches(chat)) { modem_chat_script_set_response_matches(chat); + } else if (modem_chat_script_chat_has_send_timeout(chat)) { + modem_chat_script_chat_schedule_send_timeout(chat); + } else { + modem_chat_script_next(chat, false); } } @@ -331,8 +356,27 @@ static void modem_chat_script_send_timeout_handler(struct k_work *item) modem_chat_script_next(chat, false); } +#if CONFIG_MODEM_STATS +static uint32_t get_receive_buf_length(struct modem_chat *chat) +{ + return chat->receive_buf_len; +} + +static void advertise_receive_buf_stats(struct modem_chat *chat) +{ + uint32_t length; + + length = get_receive_buf_length(chat); + modem_stats_buffer_advertise_length(&chat->receive_buf_stats, length); +} +#endif + static void modem_chat_parse_reset(struct modem_chat *chat) { +#if CONFIG_MODEM_STATS + advertise_receive_buf_stats(chat); +#endif + /* Reset parameters used for parsing */ chat->receive_buf_len = 0; chat->delimiter_match_len = 0; @@ -660,6 +704,21 @@ static void modem_chat_process_bytes(struct modem_chat *chat) } } +#if CONFIG_MODEM_STATS +static uint32_t get_work_buf_length(struct modem_chat *chat) +{ + return chat->work_buf_len; +} + +static void advertise_work_buf_stats(struct modem_chat *chat) +{ + uint32_t length; + + length = get_work_buf_length(chat); + modem_stats_buffer_advertise_length(&chat->work_buf_stats, length); +} +#endif + static void modem_chat_process_handler(struct k_work *item) { struct modem_chat *chat = CONTAINER_OF(item, struct modem_chat, receive_work); @@ -674,6 +733,10 @@ static void modem_chat_process_handler(struct k_work *item) /* Save received data length */ chat->work_buf_len = (size_t)ret; +#if CONFIG_MODEM_STATS + advertise_work_buf_stats(chat); +#endif + /* Process data */ modem_chat_process_bytes(chat); k_work_submit(&chat->receive_work); @@ -698,6 +761,28 @@ static void modem_chat_pipe_callback(struct modem_pipe *pipe, enum modem_pipe_ev } } +#if CONFIG_MODEM_STATS +static uint32_t get_receive_buf_size(struct modem_chat *chat) +{ + return chat->receive_buf_size; +} + +static uint32_t get_work_buf_size(struct modem_chat *chat) +{ + return sizeof(chat->work_buf); +} + +static void init_buf_stats(struct modem_chat *chat) +{ + uint32_t size; + + size = get_receive_buf_size(chat); + modem_stats_buffer_init(&chat->receive_buf_stats, "chat_rx", size); + size = get_work_buf_size(chat); + modem_stats_buffer_init(&chat->work_buf_stats, "chat_work", size); +} +#endif + int modem_chat_init(struct modem_chat *chat, const struct modem_chat_config *config) { __ASSERT_NO_MSG(chat != NULL); @@ -734,6 +819,10 @@ int modem_chat_init(struct modem_chat *chat, const struct modem_chat_config *con k_work_init_delayable(&chat->script_send_timeout_work, modem_chat_script_send_timeout_handler); +#if CONFIG_MODEM_STATS + init_buf_stats(chat); +#endif + return 0; } @@ -754,15 +843,20 @@ int modem_chat_run_script_async(struct modem_chat *chat, const struct modem_chat } /* Validate script */ - if ((script->script_chats == NULL) || (script->script_chats_size == 0) || - ((script->abort_matches != NULL) && (script->abort_matches_size == 0))) { + if (script->script_chats == NULL || + (script->script_chats_size == 0 + && script->script_chats != modem_chat_empty_script_chats) || + (script->abort_matches_size == 0 + && script->abort_matches != NULL + && script->abort_matches != modem_chat_empty_matches)) { return -EINVAL; } /* Validate script commands */ for (uint16_t i = 0; i < script->script_chats_size; i++) { if ((script->script_chats[i].request_size == 0) && - (script->script_chats[i].response_matches_size == 0)) { + (script->script_chats[i].response_matches_size == 0) && + (script->script_chats[i].timeout == 0)) { return -EINVAL; } } @@ -795,7 +889,7 @@ int modem_chat_run_script(struct modem_chat *chat, const struct modem_chat_scrip return ret; } - return chat->script_result == MODEM_CHAT_SCRIPT_RESULT_SUCCESS ? 0 : -EAGAIN; + return (chat->script_result == MODEM_CHAT_SCRIPT_RESULT_SUCCESS) ? 0 : -EAGAIN; } void modem_chat_script_abort(struct modem_chat *chat) diff --git a/subsys/modem/modem_cmux.c b/subsys/modem/modem_cmux.c index 3fcca3d6068..f4e2280dccb 100644 --- a/subsys/modem/modem_cmux.c +++ b/subsys/modem/modem_cmux.c @@ -144,6 +144,54 @@ static void modem_cmux_log_received_frame(const struct modem_cmux_frame *frame) modem_cmux_log_frame(frame, "rcvd", frame->data_len); } +#if CONFIG_MODEM_STATS +static uint32_t modem_cmux_get_receive_buf_length(struct modem_cmux *cmux) +{ + return cmux->receive_buf_len; +} + +static uint32_t modem_cmux_get_receive_buf_size(struct modem_cmux *cmux) +{ + return cmux->receive_buf_size; +} + +static uint32_t modem_cmux_get_transmit_buf_length(struct modem_cmux *cmux) +{ + return ring_buf_size_get(&cmux->transmit_rb); +} + +static uint32_t modem_cmux_get_transmit_buf_size(struct modem_cmux *cmux) +{ + return ring_buf_capacity_get(&cmux->transmit_rb); +} + +static void modem_cmux_init_buf_stats(struct modem_cmux *cmux) +{ + uint32_t size; + + size = modem_cmux_get_receive_buf_size(cmux); + modem_stats_buffer_init(&cmux->receive_buf_stats, "cmux_rx", size); + size = modem_cmux_get_transmit_buf_size(cmux); + modem_stats_buffer_init(&cmux->transmit_buf_stats, "cmux_tx", size); +} + +static void modem_cmux_advertise_transmit_buf_stats(struct modem_cmux *cmux) +{ + uint32_t length; + + length = modem_cmux_get_transmit_buf_length(cmux); + modem_stats_buffer_advertise_length(&cmux->transmit_buf_stats, length); +} + +static void modem_cmux_advertise_receive_buf_stats(struct modem_cmux *cmux) +{ + uint32_t length; + + length = modem_cmux_get_receive_buf_length(cmux); + modem_stats_buffer_advertise_length(&cmux->receive_buf_stats, length); +} +#endif + static const char *modem_cmux_command_type_to_str(enum modem_cmux_command_types command_type) { switch (command_type) { @@ -649,6 +697,10 @@ static void modem_cmux_on_dlci_frame(struct modem_cmux *cmux) static void modem_cmux_on_frame(struct modem_cmux *cmux) { +#if CONFIG_MODEM_STATS + modem_cmux_advertise_receive_buf_stats(cmux); +#endif + if (cmux->frame.dlci_address == 0) { modem_cmux_on_control_frame(cmux); } else { @@ -658,6 +710,10 @@ static void modem_cmux_on_frame(struct modem_cmux *cmux) static void modem_cmux_drop_frame(struct modem_cmux *cmux) { +#if CONFIG_MODEM_STATS + modem_cmux_advertise_receive_buf_stats(cmux); +#endif + LOG_WRN("Dropped frame"); cmux->receive_state = MODEM_CMUX_RECEIVE_STATE_SOF; @@ -884,6 +940,10 @@ static void modem_cmux_transmit_handler(struct k_work *item) k_mutex_lock(&cmux->transmit_rb_lock, K_FOREVER); +#if CONFIG_MODEM_STATS + modem_cmux_advertise_transmit_buf_stats(cmux); +#endif + while (true) { transmit_rb_empty = ring_buf_is_empty(&cmux->transmit_rb); @@ -975,6 +1035,36 @@ static void modem_cmux_disconnect_handler(struct k_work *item) k_work_schedule(&cmux->disconnect_work, MODEM_CMUX_T1_TIMEOUT); } +#if CONFIG_MODEM_STATS +static uint32_t modem_cmux_dlci_get_receive_buf_length(struct modem_cmux_dlci *dlci) +{ + return ring_buf_size_get(&dlci->receive_rb); +} + +static uint32_t modem_cmux_dlci_get_receive_buf_size(struct modem_cmux_dlci *dlci) +{ + return ring_buf_capacity_get(&dlci->receive_rb); +} + +static void modem_cmux_dlci_init_buf_stats(struct modem_cmux_dlci *dlci) +{ + uint32_t size; + char name[sizeof("dlci_xxxxx_rx")]; + + size = modem_cmux_dlci_get_receive_buf_size(dlci); + snprintk(name, sizeof(name), "dlci_%u_rx", dlci->dlci_address); + modem_stats_buffer_init(&dlci->receive_buf_stats, name, size); +} + +static void modem_cmux_dlci_advertise_receive_buf_stat(struct modem_cmux_dlci *dlci) +{ + uint32_t length; + + length = modem_cmux_dlci_get_receive_buf_length(dlci); + modem_stats_buffer_advertise_length(&dlci->receive_buf_stats, length); +} +#endif + static int modem_cmux_dlci_pipe_api_open(void *data) { struct modem_cmux_dlci *dlci = (struct modem_cmux_dlci *)data; @@ -1010,6 +1100,11 @@ static int modem_cmux_dlci_pipe_api_receive(void *data, uint8_t *buf, size_t siz uint32_t ret; k_mutex_lock(&dlci->receive_rb_lock, K_FOREVER); + +#if CONFIG_MODEM_STATS + modem_cmux_dlci_advertise_receive_buf_stat(dlci); +#endif + ret = ring_buf_get(&dlci->receive_rb, buf, size); k_mutex_unlock(&dlci->receive_rb_lock); return ret; @@ -1126,6 +1221,10 @@ void modem_cmux_init(struct modem_cmux *cmux, const struct modem_cmux_config *co k_event_init(&cmux->event); k_event_clear(&cmux->event, MODEM_CMUX_EVENT_CONNECTED_BIT); k_event_post(&cmux->event, MODEM_CMUX_EVENT_DISCONNECTED_BIT); + +#if CONFIG_MODEM_STATS + modem_cmux_init_buf_stats(cmux); +#endif } struct modem_pipe *modem_cmux_dlci_init(struct modem_cmux *cmux, struct modem_cmux_dlci *dlci, @@ -1148,6 +1247,11 @@ struct modem_pipe *modem_cmux_dlci_init(struct modem_cmux *cmux, struct modem_cm k_work_init_delayable(&dlci->close_work, modem_cmux_dlci_close_handler); dlci->state = MODEM_CMUX_DLCI_STATE_CLOSED; sys_slist_append(&dlci->cmux->dlcis, &dlci->node); + +#if CONFIG_MODEM_STATS + modem_cmux_dlci_init_buf_stats(dlci); +#endif + return &dlci->pipe; } diff --git a/subsys/modem/modem_ppp.c b/subsys/modem/modem_ppp.c index 91085317d99..17e3081f55a 100644 --- a/subsys/modem/modem_ppp.c +++ b/subsys/modem/modem_ppp.c @@ -313,6 +313,26 @@ static void modem_ppp_process_received_byte(struct modem_ppp *ppp, uint8_t byte) } } +#if CONFIG_MODEM_STATS +static uint32_t get_transmit_buf_length(struct modem_ppp *ppp) +{ + return ring_buf_size_get(&ppp->transmit_rb); +} + +static void advertise_transmit_buf_stats(struct modem_ppp *ppp) +{ + uint32_t length; + + length = get_transmit_buf_length(ppp); + modem_stats_buffer_advertise_length(&ppp->transmit_buf_stats, length); +} + +static void advertise_receive_buf_stats(struct modem_ppp *ppp, uint32_t length) +{ + modem_stats_buffer_advertise_length(&ppp->receive_buf_stats, length); +} +#endif + static void modem_ppp_pipe_callback(struct modem_pipe *pipe, enum modem_pipe_event event, void *user_data) { @@ -365,6 +385,10 @@ static void modem_ppp_send_handler(struct k_work *item) } } +#if CONFIG_MODEM_STATS + advertise_transmit_buf_stats(ppp); +#endif + while (!ring_buf_is_empty(&ppp->transmit_rb)) { reserved_size = ring_buf_get_claim(&ppp->transmit_rb, &reserved, UINT32_MAX); @@ -392,6 +416,10 @@ static void modem_ppp_process_handler(struct k_work *item) return; } +#if CONFIG_MODEM_STATS + advertise_receive_buf_stats(ppp, ret); +#endif + for (int i = 0; i < ret; i++) { modem_ppp_process_received_byte(ppp, ppp->receive_buf[i]); } @@ -460,6 +488,32 @@ static struct net_stats_ppp *modem_ppp_ppp_get_stats(const struct device *dev) } #endif +#if CONFIG_MODEM_STATS +static uint32_t get_buf_size(struct modem_ppp *ppp) +{ + return ppp->buf_size; +} + +static void init_buf_stats(struct modem_ppp *ppp) +{ + char iface_name[CONFIG_MODEM_STATS_BUFFER_NAME_SIZE - sizeof("_xx")]; + char name[CONFIG_MODEM_STATS_BUFFER_NAME_SIZE]; + int ret; + uint32_t size; + + ret = net_if_get_name(ppp->iface, iface_name, sizeof(iface_name)); + if (ret < 0) { + snprintk(iface_name, sizeof(iface_name), "ppp"); + } + + size = get_buf_size(ppp); + snprintk(name, sizeof(name), "%s_rx", iface_name); + modem_stats_buffer_init(&ppp->receive_buf_stats, name, size); + snprintk(name, sizeof(name), "%s_tx", iface_name); + modem_stats_buffer_init(&ppp->transmit_buf_stats, name, size); +} +#endif + const struct ppp_api modem_ppp_ppp_api = { .iface_api.init = modem_ppp_ppp_api_init, .start = modem_ppp_ppp_api_start, @@ -535,5 +589,8 @@ int modem_ppp_init_internal(const struct device *dev) k_work_init(&ppp->process_work, modem_ppp_process_handler); k_fifo_init(&ppp->tx_pkt_fifo); +#if CONFIG_MODEM_STATS + init_buf_stats(ppp); +#endif return 0; } diff --git a/subsys/modem/modem_stats.c b/subsys/modem/modem_stats.c new file mode 100644 index 00000000000..2ab90d3be6e --- /dev/null +++ b/subsys/modem/modem_stats.c @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2024 Trackunit Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifdef _POSIX_VERSION +#undef _POSIX_VERSION +#endif +#define _POSIX_VERSION 200809L + +#include +#include + +#include +LOG_MODULE_REGISTER(modem_stats); + +static struct k_spinlock stats_buffer_lock; +static sys_slist_t stats_buffer_list; + +static struct modem_stats_buffer *stats_buffer_from_node(sys_snode_t *node) +{ + return (struct modem_stats_buffer *)node; +} + +static void stats_buffer_list_append(struct modem_stats_buffer *buffer) +{ + K_SPINLOCK(&stats_buffer_lock) { + sys_slist_append(&stats_buffer_list, &buffer->node); + } +} + +static struct modem_stats_buffer *stats_buffer_list_first(void) +{ + struct modem_stats_buffer *first; + + K_SPINLOCK(&stats_buffer_lock) { + first = stats_buffer_from_node(sys_slist_peek_head(&stats_buffer_list)); + } + + return first; +} + +static struct modem_stats_buffer *stats_buffer_list_next(struct modem_stats_buffer *buffer) +{ + struct modem_stats_buffer *next; + + K_SPINLOCK(&stats_buffer_lock) { + next = stats_buffer_from_node(sys_slist_peek_next(&buffer->node)); + } + + return next; +} + +static uint8_t percent_used(uint32_t max_used, uint32_t cap) +{ + uint64_t percent; + + if (max_used == 0) { + return 0; + } + + if (max_used == cap) { + return 100; + } + + percent = 100; + percent *= max_used; + percent /= cap; + + return (uint8_t)percent; +} + +static void stats_buffer_get_and_clear_max_used(struct modem_stats_buffer *buffer, + uint32_t *max_used) +{ + K_SPINLOCK(&stats_buffer_lock) { + *max_used = buffer->max_used; + buffer->max_used = 0; + } +} + +static bool stats_buffer_length_is_valid(const struct modem_stats_buffer *buffer, uint32_t length) +{ + return length <= buffer->size; +} + +static void stats_buffer_log_invalid_length(const struct modem_stats_buffer *buffer, + uint32_t length) +{ + LOG_ERR("%s: length (%u) exceeds size (%u)", buffer->name, length, buffer->size); +} + +static void stats_buffer_update_max_used(struct modem_stats_buffer *buffer, uint32_t length) +{ + K_SPINLOCK(&stats_buffer_lock) { + if (buffer->max_used < length) { + buffer->max_used = length; + } + } +} + +static void stats_buffer_print_to_shell(const struct shell *sh, + const struct modem_stats_buffer *buffer, + uint32_t max_used) +{ + shell_print(sh, "%s: used at most: %u of %u (%u%%)", buffer->name, max_used, + buffer->size, percent_used(max_used, buffer->size)); +} + +static int stats_buffer_shell_cmd_handler(const struct shell *sh, size_t argc, char **argv) +{ + struct modem_stats_buffer *buffer; + uint32_t max_used; + + ARG_UNUSED(argc); + ARG_UNUSED(argv); + + buffer = stats_buffer_list_first(); + + if (buffer == NULL) { + shell_print(sh, "no buffers exist"); + return 0; + } + + while (buffer != NULL) { + stats_buffer_get_and_clear_max_used(buffer, &max_used); + stats_buffer_print_to_shell(sh, buffer, max_used); + buffer = stats_buffer_list_next(buffer); + } + + return 0; +} + +SHELL_STATIC_SUBCMD_SET_CREATE( + sub_stats_cmds, + SHELL_CMD(buffer, NULL, "Get buffer statistics", stats_buffer_shell_cmd_handler), + SHELL_SUBCMD_SET_END +); + +SHELL_CMD_REGISTER(modem_stats, &sub_stats_cmds, "Modem statistics commands", NULL); + +static void stats_buffer_set_name(struct modem_stats_buffer *buffer, const char *name) +{ + buffer->name[sizeof(buffer->name) - 1] = '\0'; + strncpy(buffer->name, name, sizeof(buffer->name) - 1); +} + +void modem_stats_buffer_init(struct modem_stats_buffer *buffer, + const char *name, uint32_t size) +{ + stats_buffer_set_name(buffer, name); + buffer->max_used = 0; + buffer->size = size; + stats_buffer_list_append(buffer); +} + +void modem_stats_buffer_advertise_length(struct modem_stats_buffer *buffer, uint32_t length) +{ + if (!stats_buffer_length_is_valid(buffer, length)) { + stats_buffer_log_invalid_length(buffer, length); + return; + } + + stats_buffer_update_max_used(buffer, length); +} diff --git a/subsys/net/buf.c b/subsys/net/buf.c index 8f65c402806..4ef60e90fd3 100644 --- a/subsys/net/buf.c +++ b/subsys/net/buf.c @@ -271,6 +271,12 @@ struct net_buf *net_buf_alloc_len(struct net_buf_pool *pool, size_t size, k_spin_unlock(&pool->lock, key); + if (!K_TIMEOUT_EQ(timeout, K_NO_WAIT) && + k_current_get() == k_work_queue_thread_get(&k_sys_work_q)) { + LOG_DBG("Timeout discarded. No blocking in syswq"); + timeout = K_NO_WAIT; + } + #if defined(CONFIG_NET_BUF_LOG) && (CONFIG_NET_BUF_LOG_LEVEL >= LOG_LEVEL_WRN) if (K_TIMEOUT_EQ(timeout, K_FOREVER)) { uint32_t ref = k_uptime_get_32(); diff --git a/subsys/net/conn_mgr/CMakeLists.txt b/subsys/net/conn_mgr/CMakeLists.txt index 567bbf07d69..68ca0f1388f 100644 --- a/subsys/net/conn_mgr/CMakeLists.txt +++ b/subsys/net/conn_mgr/CMakeLists.txt @@ -10,4 +10,4 @@ zephyr_library_sources( ) zephyr_linker_sources(DATA_SECTIONS conn_mgr.ld) -zephyr_iterable_section(NAME conn_mgr_conn_binding GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) +zephyr_iterable_section(NAME conn_mgr_conn_binding GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) diff --git a/subsys/net/conn_mgr/conn_mgr.ld b/subsys/net/conn_mgr/conn_mgr.ld index ed09ad0c396..9efd726b368 100644 --- a/subsys/net/conn_mgr/conn_mgr.ld +++ b/subsys/net/conn_mgr/conn_mgr.ld @@ -6,4 +6,4 @@ #include -ITERABLE_SECTION_RAM(conn_mgr_conn_binding, 4) +ITERABLE_SECTION_RAM(conn_mgr_conn_binding, Z_LINK_ITERABLE_SUBALIGN) diff --git a/subsys/net/ip/CMakeLists.txt b/subsys/net/ip/CMakeLists.txt index dd15c21906d..abb26e3dafe 100644 --- a/subsys/net/ip/CMakeLists.txt +++ b/subsys/net/ip/CMakeLists.txt @@ -37,8 +37,10 @@ zephyr_library_sources_ifdef(CONFIG_NET_IPV4_IGMP igmp.c) zephyr_library_sources_ifdef(CONFIG_NET_IPV6 icmpv6.c nbr.c ipv6.c ipv6_nbr.c) zephyr_library_sources_ifdef(CONFIG_NET_IPV6_MLD ipv6_mld.c) +zephyr_library_sources_ifdef(CONFIG_NET_IPV6_PE ipv6_pe.c) zephyr_library_sources_ifdef(CONFIG_NET_IPV6_FRAGMENT ipv6_fragment.c) zephyr_library_sources_ifdef(CONFIG_NET_IPV4_FRAGMENT ipv4_fragment.c) +zephyr_library_sources_ifdef(CONFIG_NET_MGMT_EVENT net_mgmt.c) zephyr_library_sources_ifdef(CONFIG_NET_ROUTE route.c) zephyr_library_sources_ifdef(CONFIG_NET_STATISTICS net_stats.c) zephyr_library_sources_ifdef(CONFIG_NET_TCP tcp.c) @@ -51,7 +53,7 @@ zephyr_library_sources_ifdef(CONFIG_NET_CONNECTION_SOCKETS connection.c) zephyr_library_sources_ifdef(CONFIG_NET_SOCKETS_PACKET packet_socket.c) zephyr_library_sources_ifdef(CONFIG_NET_SOCKETS_CAN canbus_socket.c) -if(CONFIG_NET_TCP_ISN_RFC6528) +if(CONFIG_NET_TCP_ISN_RFC6528 OR CONFIG_NET_IPV6_PE) zephyr_library_link_libraries_ifdef(CONFIG_MBEDTLS mbedTLS) endif() endif() diff --git a/subsys/net/ip/Kconfig b/subsys/net/ip/Kconfig index 29553e464c1..b8907125109 100644 --- a/subsys/net/ip/Kconfig +++ b/subsys/net/ip/Kconfig @@ -426,6 +426,23 @@ config NET_MAX_MCAST_ROUTES This determines how many entries can be stored in multicast routing table. +config NET_MCAST_ROUTE_MAX_IFACES + int "Max number of network interfaces per multicast routing entry" + default 1 + range 1 8 + depends on NET_ROUTE_MCAST + help + Determines how many network interfaces can be assigned to a + single multicast route entry. + +config NET_MCAST_ROUTE_MLD_REPORTS + bool "Report multicast routes as a part of MLDv2 reports" + depends on NET_ROUTE_MCAST + depends on NET_IPV6_MLD + help + Determines whether a multicast route entry should be advertised + in MLDv2 reports. + source "subsys/net/ip/Kconfig.tcp" config NET_TEST_PROTOCOL @@ -695,9 +712,7 @@ config NET_PKT_BUF_TX_DATA_POOL_SIZE config NET_PKT_BUF_USER_DATA_SIZE int "Size of user_data available in rx and tx network buffers" - default BT_CONN_TX_USER_DATA_SIZE if NET_L2_BT default 4 - range BT_CONN_TX_USER_DATA_SIZE 16 if NET_L2_BT range 4 16 help User data size used in rx and tx network buffers. @@ -736,10 +751,6 @@ config NET_DEFAULT_IF_ETHERNET bool "Ethernet" depends on NET_L2_ETHERNET -config NET_DEFAULT_IF_BLUETOOTH - bool "Bluetooth" - depends on NET_L2_BT - config NET_DEFAULT_IF_IEEE802154 bool "IEEE 802.15.4" depends on NET_L2_IEEE802154 diff --git a/subsys/net/ip/Kconfig.ipv6 b/subsys/net/ip/Kconfig.ipv6 index d132febf727..aa1f215b1ff 100644 --- a/subsys/net/ip/Kconfig.ipv6 +++ b/subsys/net/ip/Kconfig.ipv6 @@ -14,7 +14,6 @@ if NET_IPV6 config NET_IF_MAX_IPV6_COUNT int "Max number of IPv6 network interfaces in the system" - default BT_MAX_CONN if NET_L2_BT default NET_VLAN_COUNT if NET_VLAN default 2 if NET_LOOPBACK default 1 @@ -160,12 +159,70 @@ config NET_IPV6_DAD config NET_IPV6_RA_RDNSS bool "Support RA RDNSS option" depends on NET_IPV6_ND - select DNS_RESOLVER + depends on DNS_RESOLVER default y help Support Router Advertisement Recursive DNS Server option. See RFC 6106 for details. The value depends on your network needs. +config NET_IPV6_PE + bool "Privacy extension (RFC 8981) support [EXPERIMENTAL]" + select MBEDTLS + select EXPERIMENTAL + select NET_MGMT + select NET_MGMT_EVENT + select NET_MGMT_EVENT_INFO + help + This enables IPv6 privacy extension (RFC 8981) support. + The interface identifier is randomized and SLAAC addresses + generated from it will expire. This requires that applications are + prepared to use new IPv6 addresses when old ones will expire. + Note that you should make sure that the value of config option + CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT should be large enough so that + two PE generated IPv6 addresses can be added to the network interface + at the same time. + +if NET_IPV6_PE + +config NET_IPV6_PE_FILTER_PREFIX_COUNT + int "Size of the IPv6 prefix filter list" + default 0 + help + Size of the allow/deny filter list of IPv6 prefixes. User can + set filters at runtime and it is possible to enable or disable + privacy extension support according to this filter list. + By default no filters are enabled. + +config NET_IPV6_PE_PREFER_PUBLIC_ADDRESSES + bool "Prefer public preferred address over temporary one" + help + Prefer public addresses over temporary addresses. + +config NET_IPV6_PE_TEMP_VALID_LIFETIME + int "Max lifetime for temporary address (in minutes)" + default 1440 + help + No temporary address should ever remain valid for longer than this + value. The value is in minutes. Default value is 1 day (24*60). + +config NET_IPV6_PE_TEMP_PREFERRED_LIFETIME + int "Max preferred lifetime for temporary address (in minutes)" + default 1380 + help + No temporary address should ever remain preferred for longer than this + value. The value is in minutes. Default value is 23 hours (23*60). + +config NET_IPV6_PE_TEMP_IDGEN_RETRIES + int "Max amount of failed DAD attempts" + default 3 + help + The node MUST perform duplicate address detection (DAD) on the + generated temporary address. If after TEMP_IDGEN_RETRIES consecutive + attempts no non-unique address was generated then there will be no + attempt to generate temporary addresses for that interface. + +endif + config NET_6LO bool "6lowpan IPv6 Compression library" default y if NET_L2_IEEE802154 @@ -212,6 +269,12 @@ module-str = Log level for IPv6 Neighbor Discovery module-help = Enables IPv6 Neighbor Discovery code to output debug messages. source "subsys/net/Kconfig.template.log_config.net" +module = NET_IPV6_PE +module-dep = NET_LOG +module-str = Log level for IPv6 Privacy Extension +module-help = Enables IPv6 Privacy Extension code to output debug messages. +source "subsys/net/Kconfig.template.log_config.net" + module = NET_ICMPV6 module-dep = NET_LOG module-str = Log level for ICMPv6 diff --git a/subsys/net/ip/Kconfig.mgmt b/subsys/net/ip/Kconfig.mgmt index e5adb9e5728..04fe2adf14e 100644 --- a/subsys/net/ip/Kconfig.mgmt +++ b/subsys/net/ip/Kconfig.mgmt @@ -57,7 +57,7 @@ config NET_MGMT_EVENT_QUEUE config NET_MGMT_EVENT_STACK_SIZE int "Stack size for the inner thread handling event callbacks" - default 4096 if WIFI_NM_WPA_SUPPLICANT + default 4200 if WIFI_NM_WPA_SUPPLICANT default 2048 if COVERAGE_GCOV default 840 if X86 default 800 if THREAD_LOCAL_STORAGE diff --git a/subsys/net/ip/Kconfig.tcp b/subsys/net/ip/Kconfig.tcp index e7d45f46c7a..9df87e31b60 100644 --- a/subsys/net/ip/Kconfig.tcp +++ b/subsys/net/ip/Kconfig.tcp @@ -229,9 +229,7 @@ config NET_TCP_ISN_RFC6528 bool "Use ISN algorithm from RFC 6528" default y depends on NET_TCP - select MBEDTLS - select MBEDTLS_MD - select MBEDTLS_MAC_MD5_ENABLED + depends on PSA_WANT_ALG_SHA_256 help Implement Initial Sequence Number calculation as described in RFC 6528 chapter 3. https://tools.ietf.org/html/rfc6528 diff --git a/subsys/net/ip/ipv6.c b/subsys/net/ip/ipv6.c index 2a99abc6b89..9d094c9c4c9 100644 --- a/subsys/net/ip/ipv6.c +++ b/subsys/net/ip/ipv6.c @@ -505,6 +505,8 @@ enum net_verdict net_ipv6_input(struct net_pkt *pkt, bool is_loopback) } if (!is_loopback) { + struct net_if_addr *ifaddr; + if (net_ipv6_is_addr_loopback((struct in6_addr *)hdr->dst) || net_ipv6_is_addr_loopback((struct in6_addr *)hdr->src)) { NET_DBG("DROP: ::1 packet"); @@ -521,7 +523,12 @@ enum net_verdict net_ipv6_input(struct net_pkt *pkt, bool is_loopback) goto drop; } - if (net_ipv6_is_my_addr((struct in6_addr *)hdr->src)) { + /* We need to pass the packet through in case our address is + * tentative, as receiving a packet with a tentative address as + * source means that duplicate address has been detected. + */ + ifaddr = net_if_ipv6_addr_lookup((struct in6_addr *)hdr->src, NULL); + if (ifaddr != NULL && ifaddr->addr_state != NET_ADDR_TENTATIVE) { NET_DBG("DROP: src addr is %s", "mine"); goto drop; } @@ -549,7 +556,7 @@ enum net_verdict net_ipv6_input(struct net_pkt *pkt, bool is_loopback) } if (IS_ENABLED(CONFIG_NET_ROUTE_MCAST) && - net_ipv6_is_addr_mcast((struct in6_addr *)hdr->dst)) { + net_ipv6_is_addr_mcast((struct in6_addr *)hdr->dst) && !net_pkt_forwarding(pkt)) { /* If the packet is a multicast packet and multicast routing * is activated, we give the packet to the routing engine. * diff --git a/subsys/net/ip/ipv6.h b/subsys/net/ip/ipv6.h index 0079b8b4815..3319582ce19 100644 --- a/subsys/net/ip/ipv6.h +++ b/subsys/net/ip/ipv6.h @@ -240,6 +240,29 @@ net_ipv6_mld_leave(struct net_if *iface, const struct in6_addr *addr) } #endif /* CONFIG_NET_IPV6_MLD */ +/** + * @brief Send MLDv2 report message with a single entry. + * + * @param iface Network interface where message is sent + * @param addr Mutlicast group + * @param mode MLDv2 mode (NET_IPV6_MLDv2_MODE_IS_INCLUDE NET_IPV6_MLDv2_MODE_IS_EXCLUDE) + * + * @return Return 0 if leaving is done, <0 otherwise. + */ +#if defined(CONFIG_NET_IPV6_MLD) +int net_ipv6_mld_send_single(struct net_if *iface, const struct in6_addr *addr, uint8_t mode); +#else +static inline int +net_ipv6_mld_send_single(struct net_if *iface, const struct in6_addr *addr, uint8_t mode) +{ + ARG_UNUSED(iface); + ARG_UNUSED(addr); + ARG_UNUSED(mode); + + return -ENOTSUP; +} +#endif /* CONFIG_NET_IPV6_MLD */ + /** * @typedef net_nbr_cb_t * @brief Callback used while iterating over neighbors. @@ -595,5 +618,94 @@ static inline void net_ipv6_set_ecn(uint8_t *tc, uint8_t ecn) *tc |= ecn & NET_IPV6_ECN_MASK; } +/** + * @brief Start IPv6 privacy extension procedure. + * + * @param iface Interface to use. + * @param prefix IPv6 prefix to use. + * @param vlifetime Lifetime of this IPv6 prefix (in seconds). + * @param preferred_lifetime Preferred lifetime of this IPv6 prefix (in seconds) + */ +#if defined(CONFIG_NET_IPV6_PE) +void net_ipv6_pe_start(struct net_if *iface, const struct in6_addr *prefix, + uint32_t vlifetime, uint32_t preferred_lifetime); + +#else +static inline void net_ipv6_pe_start(struct net_if *iface, + const struct in6_addr *prefix, + uint32_t vlifetime, + uint32_t preferred_lifetime) +{ + ARG_UNUSED(iface); + ARG_UNUSED(prefix); + ARG_UNUSED(vlifetime); + ARG_UNUSED(preferred_lifetime); +} +#endif /* CONFIG_NET_IPV6_PE */ + +/** + * @brief Check if maximum number of Duplicate Address Detection (DAD) requests + * have been done. + * + * @param count Number of DAD requests done. + * + * @return Return True if DAD can continue, False if max amount of DAD + * requests have been done. + */ +#if defined(CONFIG_NET_IPV6_PE) +bool net_ipv6_pe_check_dad(int count); +#else +static inline bool net_ipv6_pe_check_dad(int count) +{ + ARG_UNUSED(count); + + return false; +} +#endif /* CONFIG_NET_IPV6_PE */ + +/** + * @brief Initialize IPv6 privacy extension support for a network interface. + * + * @param iface Network interface + * + * @return Return 0 if ok or <0 if there is an error. + */ +#if defined(CONFIG_NET_IPV6_PE) +int net_ipv6_pe_init(struct net_if *iface); +#else +static inline int net_ipv6_pe_init(struct net_if *iface) +{ + iface->pe_enabled = false; + iface->pe_prefer_public = false; + + return 0; +} +#endif /* CONFIG_NET_IPV6_PE */ + +typedef void (*net_ipv6_pe_filter_cb_t)(struct in6_addr *prefix, + bool is_blacklist, + void *user_data); + +/** + * @brief Go through all the IPv6 privacy extension filters and call callback + * for each IPv6 prefix. + * + * @param cb User supplied callback function to call. + * @param user_data User specified data. + * + * @return Total number of filters found. + */ +#if defined(CONFIG_NET_IPV6_PE) +int net_ipv6_pe_filter_foreach(net_ipv6_pe_filter_cb_t cb, void *user_data); +#else +static inline int net_ipv6_pe_filter_foreach(net_ipv6_pe_filter_cb_t cb, + void *user_data) +{ + ARG_UNUSED(cb); + ARG_UNUSED(user_data); + + return 0; +} +#endif #endif /* __IPV6_H */ diff --git a/subsys/net/ip/ipv6_mld.c b/subsys/net/ip/ipv6_mld.c index f2ae80e0f10..75644c2ca58 100644 --- a/subsys/net/ip/ipv6_mld.c +++ b/subsys/net/ip/ipv6_mld.c @@ -34,13 +34,21 @@ LOG_MODULE_DECLARE(net_ipv6, CONFIG_NET_IPV6_LOG_LEVEL); #define MLDv2_MCAST_RECORD_LEN sizeof(struct net_icmpv6_mld_mcast_record) #define IPV6_OPT_HDR_ROUTER_ALERT_LEN 8 +#define MLDV2_REPORT_RESERVED_BYTES 2 #define MLDv2_LEN (MLDv2_MCAST_RECORD_LEN + sizeof(struct in6_addr)) +/* Internal structure used for appending multicast routes to MLDv2 reports */ +struct mcast_route_appending_info { + int status; + struct net_pkt *pkt; + struct net_if *iface; + size_t skipped; +}; + static int mld_create(struct net_pkt *pkt, const struct in6_addr *addr, - uint8_t record_type, - uint16_t num_sources) + uint8_t record_type) { NET_PKT_DATA_ACCESS_DEFINE(mld_access, struct net_icmpv6_mld_mcast_record); @@ -54,7 +62,7 @@ static int mld_create(struct net_pkt *pkt, mld->record_type = record_type; mld->aux_data_len = 0U; - mld->num_sources = htons(num_sources); + mld->num_sources = 0U; net_ipv6_addr_copy_raw(mld->mcast_address, (uint8_t *)addr); @@ -62,15 +70,6 @@ static int mld_create(struct net_pkt *pkt, return -ENOBUFS; } - if (num_sources > 0) { - /* All source addresses, RFC 3810 ch 3 */ - if (net_pkt_write(pkt, - net_ipv6_unspecified_address()->s6_addr, - sizeof(struct in6_addr))) { - return -ENOBUFS; - } - } - return 0; } @@ -145,9 +144,38 @@ static int mld_send(struct net_pkt *pkt) return 0; } -static int mld_send_generic(struct net_if *iface, - const struct in6_addr *addr, - uint8_t mode) +#if defined(CONFIG_NET_MCAST_ROUTE_MLD_REPORTS) +static void count_mcast_routes(struct net_route_entry_mcast *entry, void *user_data) +{ + (*((int *)user_data))++; +} + +static void append_mcast_routes(struct net_route_entry_mcast *entry, void *user_data) +{ + struct mcast_route_appending_info *info = (struct mcast_route_appending_info *)user_data; + struct net_if_mcast_addr *mcasts = info->iface->config.ip.ipv6->mcast; + + if (info->status != 0 || entry->prefix_len != 128) { + return; + } + + for (int i = 0; i < NET_IF_MAX_IPV6_MADDR; i++) { + if (!mcasts[i].is_used || !mcasts[i].is_joined) { + continue; + } + + if (net_ipv6_addr_cmp(&entry->group, &mcasts[i].address.in6_addr)) { + /* Address was already added to the report */ + info->skipped++; + return; + } + } + + info->status = mld_create(info->pkt, &entry->group, NET_IPV6_MLDv2_MODE_IS_EXCLUDE); +} +#endif + +int net_ipv6_mld_send_single(struct net_if *iface, const struct in6_addr *addr, uint8_t mode) { struct net_pkt *pkt; int ret; @@ -163,7 +191,7 @@ static int mld_send_generic(struct net_if *iface, } if (mld_create_packet(pkt, 1) || - mld_create(pkt, addr, mode, 1)) { + mld_create(pkt, addr, mode)) { ret = -ENOBUFS; goto drop; } @@ -206,7 +234,7 @@ int net_ipv6_mld_join(struct net_if *iface, const struct in6_addr *addr) return -ENETDOWN; } - ret = mld_send_generic(iface, addr, NET_IPV6_MLDv2_MODE_IS_EXCLUDE); + ret = net_ipv6_mld_send_single(iface, addr, NET_IPV6_MLDv2_CHANGE_TO_EXCLUDE_MODE); if (ret < 0) { return ret; } @@ -240,7 +268,7 @@ int net_ipv6_mld_leave(struct net_if *iface, const struct in6_addr *addr) return 0; } - ret = mld_send_generic(iface, addr, NET_IPV6_MLDv2_MODE_IS_INCLUDE); + ret = net_ipv6_mld_send_single(iface, addr, NET_IPV6_MLDv2_CHANGE_TO_INCLUDE_MODE); if (ret < 0) { return ret; } @@ -271,6 +299,14 @@ static int send_mld_report(struct net_if *iface) count++; } +#if defined(CONFIG_NET_MCAST_ROUTE_MLD_REPORTS) + /* Increase number of slots by a number of multicast routes that + * can be later added to the report. Checking for duplicates is done + * while appending an entry. + */ + net_route_mcast_foreach(count_mcast_routes, NULL, (void *)&count); +#endif + pkt = net_pkt_alloc_with_buffer(iface, IPV6_OPT_HDR_ROUTER_ALERT_LEN + NET_ICMPV6_UNUSED_LEN + count * MLDv2_MCAST_RECORD_LEN, @@ -291,11 +327,50 @@ static int send_mld_report(struct net_if *iface) } ret = mld_create(pkt, &ipv6->mcast[i].address.in6_addr, - NET_IPV6_MLDv2_MODE_IS_EXCLUDE, 0); + NET_IPV6_MLDv2_MODE_IS_EXCLUDE); + if (ret < 0) { + goto drop; + } + } + +#if defined(CONFIG_NET_MCAST_ROUTE_MLD_REPORTS) + /* Append information about multicast routes as packets will be + * forwarded to these interfaces on reception. + */ + struct mcast_route_appending_info info; + + info.status = 0; + info.pkt = pkt; + info.iface = iface; + info.skipped = 0; + + net_route_mcast_foreach(append_mcast_routes, NULL, &info); + + ret = info.status; + if (ret < 0) { + goto drop; + } + + /* We may have skipped duplicated addresses that we reserved space for, + * modify number of records. + */ + if (info.skipped) { + net_pkt_cursor_init(pkt); + net_pkt_set_overwrite(pkt, true); + + net_pkt_skip(pkt, net_pkt_ip_hdr_len(pkt) + net_pkt_ipv6_ext_len(pkt) + + sizeof(struct net_icmp_hdr) + MLDV2_REPORT_RESERVED_BYTES); + + count -= info.skipped; + + ret = net_pkt_write_be16(pkt, count); if (ret < 0) { goto drop; } + + net_pkt_remove_tail(pkt, info.skipped * sizeof(struct net_icmpv6_mld_mcast_record)); } +#endif ret = mld_send(pkt); if (ret < 0) { diff --git a/subsys/net/ip/ipv6_nbr.c b/subsys/net/ip/ipv6_nbr.c index 34979eeb87d..aea731dade8 100644 --- a/subsys/net/ip/ipv6_nbr.c +++ b/subsys/net/ip/ipv6_nbr.c @@ -2231,6 +2231,7 @@ static inline uint32_t remaining_lifetime(struct net_if_addr *ifaddr) static inline void handle_prefix_autonomous(struct net_pkt *pkt, struct net_icmpv6_nd_opt_prefix_info *prefix_info) { + struct net_if *iface = net_pkt_iface(pkt); struct in6_addr addr = { }; struct net_if_addr *ifaddr; @@ -2238,9 +2239,8 @@ static inline void handle_prefix_autonomous(struct net_pkt *pkt, * setup link local address, and then copy prefix over first 8 * bytes of that address. */ - net_ipv6_addr_create_iid(&addr, - net_if_get_link_addr(net_pkt_iface(pkt))); - memcpy(&addr, prefix_info->prefix, sizeof(prefix_info->prefix) / 2); + net_ipv6_addr_create_iid(&addr, net_if_get_link_addr(iface)); + memcpy(&addr, prefix_info->prefix, sizeof(struct in6_addr) / 2); ifaddr = net_if_ipv6_addr_lookup(&addr, NULL); if (ifaddr && ifaddr->addr_type == NET_ADDR_AUTOCONF) { @@ -2274,14 +2274,23 @@ static inline void handle_prefix_autonomous(struct net_pkt *pkt, } else { if (prefix_info->valid_lifetime == NET_IPV6_ND_INFINITE_LIFETIME) { - net_if_ipv6_addr_add(net_pkt_iface(pkt), - &addr, NET_ADDR_AUTOCONF, 0); + net_if_ipv6_addr_add(iface, &addr, + NET_ADDR_AUTOCONF, 0); } else { - net_if_ipv6_addr_add(net_pkt_iface(pkt), - &addr, NET_ADDR_AUTOCONF, + net_if_ipv6_addr_add(iface, &addr, NET_ADDR_AUTOCONF, prefix_info->valid_lifetime); } } + + /* If privacy extensions are enabled, then start the procedure for that + * too. + */ + if (IS_ENABLED(CONFIG_NET_IPV6_PE) && iface->pe_enabled) { + net_ipv6_pe_start(iface, + (const struct in6_addr *)prefix_info->prefix, + prefix_info->valid_lifetime, + prefix_info->preferred_lifetime); + } } static inline bool handle_ra_prefix(struct net_pkt *pkt) diff --git a/subsys/net/ip/ipv6_pe.c b/subsys/net/ip/ipv6_pe.c new file mode 100644 index 00000000000..e31eaa3bae1 --- /dev/null +++ b/subsys/net/ip/ipv6_pe.c @@ -0,0 +1,763 @@ +/** @file + * @brief IPv6 privacy extension (RFC 8981) + */ + +/* + * Copyright (c) 2018 Intel Corporation + * Copyright (c) 2024 Nordic Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +LOG_MODULE_REGISTER(net_ipv6_pe, CONFIG_NET_IPV6_PE_LOG_LEVEL); + +#include +#include + +#include +#include + +#include + +#include +#include +#include + +#include "net_private.h" +#include "ipv6.h" + +/* From RFC 5453 */ +static const struct in6_addr reserved_anycast_subnet = { { { + 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, + 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + } } }; + +/* RFC 8981 ch 3.8 preferred lifetime must be smaller than valid lifetime */ +BUILD_ASSERT(CONFIG_NET_IPV6_PE_TEMP_PREFERRED_LIFETIME < + CONFIG_NET_IPV6_PE_TEMP_VALID_LIFETIME); + +/* IPv6 privacy extension (RFC 8981) constants. Note that the code uses + * seconds value internally for applicaple options. These are also values + * that can be changed at runtime if needed as recommended in RFC 8981 + * chapter 3.6. + */ +static uint32_t temp_valid_lifetime = + CONFIG_NET_IPV6_PE_TEMP_VALID_LIFETIME * SEC_PER_MIN; +#define TEMP_VALID_LIFETIME temp_valid_lifetime + +static uint32_t temp_preferred_lifetime = + CONFIG_NET_IPV6_PE_TEMP_PREFERRED_LIFETIME * SEC_PER_MIN; +#define TEMP_PREFERRED_LIFETIME temp_preferred_lifetime + +/* This is the upper bound on DESYNC_FACTOR. The value is in seconds. + * See RFC 8981 ch 3.8 for details. + * + * RFC says the DESYNC_FACTOR should be 0.4 times the preferred lifetime. + * This is too short for Zephyr as it means that the address is very long + * time in deprecated state and not being used. Make this 7% of the preferred + * time to deprecate the addresses later. + */ +#define MAX_DESYNC_FACTOR ((uint32_t)((uint64_t)TEMP_PREFERRED_LIFETIME * \ + (uint64_t)7U) / (uint64_t)100U) +#define DESYNC_FACTOR(ipv6) ((ipv6)->desync_factor) + +#define TEMP_IDGEN_RETRIES CONFIG_NET_IPV6_PE_TEMP_IDGEN_RETRIES + +/* The REGEN_ADVANCE is in seconds + * retrans_timer (in ms) is specified in RFC 4861 + * dup_addr_detect_transmits (in ms) is specified in RFC 4862 + */ +static inline uint32_t REGEN_ADVANCE(uint32_t retrans_timer, + uint32_t dup_addr_detect_transmits) +{ + return (2U + (uint32_t)((uint64_t)TEMP_IDGEN_RETRIES * + (uint64_t)retrans_timer * + (uint64_t)dup_addr_detect_transmits / + (uint64_t)1000U)); +} + +#if CONFIG_NET_IPV6_PE_FILTER_PREFIX_COUNT > 0 +/* Is this denylisting filter or not */ +static bool ipv6_pe_denylist; +static struct in6_addr ipv6_pe_filter[CONFIG_NET_IPV6_PE_FILTER_PREFIX_COUNT]; + +static K_MUTEX_DEFINE(lock); +#endif + +/* We need to periodically update the private address. */ +static struct k_work_delayable temp_lifetime; + +static bool ipv6_pe_use_this_prefix(const struct in6_addr *prefix) +{ +#if CONFIG_NET_IPV6_PE_FILTER_PREFIX_COUNT > 0 + int filter_found = false; + bool ret = true; + + k_mutex_lock(&lock, K_FOREVER); + + ARRAY_FOR_EACH(ipv6_pe_filter, i) { + if (net_ipv6_is_addr_unspecified(&ipv6_pe_filter[i])) { + continue; + } + + filter_found = true; + + if (net_ipv6_addr_cmp(prefix, &ipv6_pe_filter[i])) { + if (ipv6_pe_denylist) { + ret = false; + } + + goto out; + } + } + + if (filter_found) { + /* There was no match so if we are deny listing, then this + * address must be acceptable. + */ + if (!ipv6_pe_denylist) { + ret = false; + goto out; + } + } + +out: + k_mutex_unlock(&lock); + + return ret; +#else + ARG_UNUSED(prefix); + + return true; +#endif +} + +static bool ipv6_pe_prefix_already_exists(struct net_if_ipv6 *ipv6, + const struct in6_addr *prefix) +{ + ARRAY_FOR_EACH(ipv6->unicast, i) { + if (!ipv6->unicast[i].is_used || + ipv6->unicast[i].address.family != AF_INET6 || + !ipv6->unicast[i].is_temporary || + ipv6->unicast[i].addr_state == NET_ADDR_DEPRECATED) { + continue; + } + + if (net_ipv6_is_prefix( + (uint8_t *)&ipv6->unicast[i].address.in6_addr, + (uint8_t *)prefix, 64)) { + return true; + } + } + + return false; +} + +static int ipv6_pe_prefix_remove(struct net_if *iface, + struct net_if_ipv6 *ipv6, + const struct in6_addr *prefix) +{ + int count = 0; + + ARRAY_FOR_EACH(ipv6->unicast, i) { + if (ipv6->unicast[i].is_used && + ipv6->unicast[i].address.family == AF_INET6 && + ipv6->unicast[i].is_temporary && + net_ipv6_is_prefix( + (uint8_t *)&ipv6->unicast[i].address.in6_addr, + (uint8_t *)prefix, 64)) { + net_if_ipv6_addr_rm(iface, + &ipv6->unicast[i].address.in6_addr); + count++; + } + } + + return count; +} + +static bool ipv6_pe_prefix_update_lifetimes(struct net_if_ipv6 *ipv6, + const struct in6_addr *prefix, + uint32_t vlifetime) +{ + int32_t addr_age, new_age; + + ARRAY_FOR_EACH(ipv6->unicast, i) { + if (!(ipv6->unicast[i].is_used && + ipv6->unicast[i].address.family == AF_INET6 && + ipv6->unicast[i].is_temporary && + ipv6->unicast[i].addr_state == NET_ADDR_PREFERRED && + net_ipv6_is_prefix( + (uint8_t *)&ipv6->unicast[i].address.in6_addr, + (uint8_t *)prefix, 64))) { + continue; + } + + addr_age = k_uptime_seconds() - ipv6->unicast[i].addr_create_time; + new_age = abs(addr_age) + vlifetime; + + if ((new_age >= TEMP_VALID_LIFETIME) || + (new_age >= (TEMP_PREFERRED_LIFETIME - + DESYNC_FACTOR(ipv6)))) { + break; + } + + net_if_ipv6_addr_update_lifetime(&ipv6->unicast[i], vlifetime); + + /* RFC 8981 ch 3.5, "... at most one temporary address per + * prefix should be in a non-deprecated state at any given + * time on a given interface." + * Because of this there is no need to continue the loop. + */ + return true; + } + + return false; +} + +/* RFC 8981 ch 3.3.2 */ +static void gen_temporary_iid(struct net_if *iface, + const struct in6_addr *prefix, + uint8_t *network_id, size_t network_id_len, + uint8_t dad_counter, + uint8_t *temporary_iid, + size_t temporary_iid_len) +{ + const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256); + mbedtls_md_context_t ctx; + uint8_t digest[32]; + static bool once; + static uint8_t secret_key[16]; /* Min 128 bits, RFC 8981 ch 3.3.2 */ + struct { + struct in6_addr prefix; + uint32_t current_time; + uint8_t network_id[16]; + uint8_t mac[6]; + uint8_t dad_counter; + } buf = { + .current_time = k_uptime_get_32(), + .dad_counter = dad_counter, + }; + + memcpy(&buf.prefix, prefix, sizeof(struct in6_addr)); + + if (network_id != NULL && network_id_len > 0) { + memcpy(buf.network_id, network_id, + MIN(network_id_len, sizeof(buf.network_id))); + } + + memcpy(buf.mac, net_if_get_link_addr(iface)->addr, + MIN(sizeof(buf.mac), net_if_get_link_addr(iface)->len)); + + if (!once) { + sys_rand_get(&secret_key, sizeof(secret_key)); + once = true; + } + + mbedtls_md_init(&ctx); + mbedtls_md_setup(&ctx, md_info, true); + mbedtls_md_hmac_starts(&ctx, secret_key, sizeof(secret_key)); + mbedtls_md_hmac_update(&ctx, (uint8_t *)&buf, sizeof(buf)); + mbedtls_md_hmac_finish(&ctx, digest); + mbedtls_md_free(&ctx); + + memcpy(temporary_iid, digest, MIN(sizeof(digest), temporary_iid_len)); +} + +void net_ipv6_pe_start(struct net_if *iface, const struct in6_addr *prefix, + uint32_t vlifetime, uint32_t preferred_lifetime) +{ + struct net_if_addr *ifaddr; + struct net_if_ipv6 *ipv6; + struct in6_addr addr; + k_ticks_t remaining; + k_timeout_t vlifetimeout; + int i, dad_count = 1; + int32_t lifetime; + bool valid = false; + + net_if_lock(iface); + + if (net_if_config_ipv6_get(iface, &ipv6) < 0) { + NET_WARN("Cannot do DAD IPv6 config is not valid."); + goto out; + } + + if (!ipv6) { + goto out; + } + + /* Check if user agrees to use this prefix */ + if (!ipv6_pe_use_this_prefix(prefix)) { + NET_DBG("Prefix %s/64 is not to be used", + net_sprint_ipv6_addr(prefix)); + goto out; + } + + /* If the prefix is already added and it is still valid and is not + * deprecated, then we do not try to add it again. + */ + if (ipv6_pe_prefix_already_exists(ipv6, prefix)) { + if (vlifetime == 0) { + i = ipv6_pe_prefix_remove(iface, ipv6, prefix); + + NET_DBG("Removed %d addresses using prefix %s/64", + i, net_sprint_ipv6_addr(prefix)); + } else { + ipv6_pe_prefix_update_lifetimes(ipv6, prefix, vlifetime); + } + + goto out; + } + + preferred_lifetime = MIN(preferred_lifetime, + TEMP_PREFERRED_LIFETIME - + DESYNC_FACTOR(ipv6)); + if (preferred_lifetime == 0 || + preferred_lifetime <= REGEN_ADVANCE(ipv6->retrans_timer, 1U)) { + NET_DBG("Too short preferred lifetime (%u <= %u), temp address not " + "created for prefix %s/64", preferred_lifetime, + REGEN_ADVANCE(ipv6->retrans_timer, 1U), + net_sprint_ipv6_addr(prefix)); + goto out; + } + + NET_DBG("Starting PE process for prefix %s/64", + net_sprint_ipv6_addr(prefix)); + + net_ipaddr_copy(&addr, prefix); + + do { + gen_temporary_iid(iface, prefix, + COND_CODE_1(CONFIG_NET_INTERFACE_NAME, + (iface->config.name, + sizeof(iface->config.name)), + (net_if_get_device(iface)->name, + strlen(net_if_get_device(iface)->name))), + dad_count, + &addr.s6_addr[8], 8U); + + ifaddr = net_if_ipv6_addr_lookup(&addr, NULL); + if (ifaddr == NULL && !net_ipv6_is_addr_unspecified(&addr) && + memcmp(&addr, &reserved_anycast_subnet, + sizeof(struct in6_addr)) != 0) { + valid = true; + break; + } + + } while (dad_count++ < TEMP_IDGEN_RETRIES); + + if (valid == false) { + NET_WARN("Could not create a valid iid for prefix %s/64 for interface %d", + net_sprint_ipv6_addr(prefix), + net_if_get_by_iface(iface)); + NET_WARN("Disabling IPv6 PE for interface %d", + net_if_get_by_iface(iface)); + net_mgmt_event_notify(NET_EVENT_IPV6_PE_DISABLED, iface); + iface->pe_enabled = false; + goto out; + } + + vlifetime = MIN(TEMP_VALID_LIFETIME, vlifetime); + + ifaddr = net_if_ipv6_addr_add(iface, &addr, NET_ADDR_AUTOCONF, vlifetime); + if (!ifaddr) { + NET_ERR("Cannot add %s address to interface %d", + net_sprint_ipv6_addr(&addr), + net_if_get_by_iface(iface)); + goto out; + } + + lifetime = TEMP_VALID_LIFETIME - + REGEN_ADVANCE(net_if_ipv6_get_retrans_timer(iface), 1U); + + DESYNC_FACTOR(ipv6) = sys_rand32_get() % MAX_DESYNC_FACTOR; + + /* Make sure that the address timeout happens at least two seconds + * after the deprecation. + */ + DESYNC_FACTOR(ipv6) = MIN(DESYNC_FACTOR(ipv6) + 2U, lifetime); + + ifaddr->is_temporary = true; + ifaddr->addr_preferred_lifetime = preferred_lifetime; + ifaddr->addr_timeout = ifaddr->addr_preferred_lifetime - DESYNC_FACTOR(ipv6); + ifaddr->addr_create_time = k_uptime_seconds(); + + NET_DBG("Lifetime %d desync %d timeout %d preferred %d valid %d", + lifetime, DESYNC_FACTOR(ipv6), ifaddr->addr_timeout, + ifaddr->addr_preferred_lifetime, vlifetime); + + NET_DBG("Starting DAD for %s iface %d", net_sprint_ipv6_addr(&addr), + net_if_get_by_iface(iface)); + + net_if_ipv6_start_dad(iface, ifaddr); + + vlifetimeout = K_SECONDS(ifaddr->addr_timeout); + + remaining = k_work_delayable_remaining_get(&temp_lifetime); + if (remaining == 0 || remaining > vlifetimeout.ticks) { + NET_DBG("Next check for temp addresses in %d seconds", + ifaddr->addr_timeout); + k_work_schedule(&temp_lifetime, vlifetimeout); + } + +out: + net_if_unlock(iface); +} + +#if CONFIG_NET_IPV6_PE_FILTER_PREFIX_COUNT > 0 + +static void iface_cb(struct net_if *iface, void *user_data) +{ + bool is_new_filter_denylist = !ipv6_pe_denylist; + struct in6_addr *prefix = user_data; + struct net_if_ipv6 *ipv6; + int ret; + + net_if_lock(iface); + + if (net_if_config_ipv6_get(iface, &ipv6) < 0) { + goto out; + } + + if (!ipv6) { + goto out; + } + + ARRAY_FOR_EACH(ipv6->unicast, i) { + if (!ipv6->unicast[i].is_used || + ipv6->unicast[i].address.family != AF_INET6 || + !ipv6->unicast[i].is_temporary) { + continue; + } + + ret = net_ipv6_is_prefix( + (uint8_t *)&ipv6->unicast[i].address.in6_addr, + (uint8_t *)prefix, 64); + + /* TODO: Do this removal gracefully so that applications + * have time to cope with this change. + */ + if (is_new_filter_denylist) { + if (ret) { + net_if_ipv6_addr_rm(iface, + &ipv6->unicast[i].address.in6_addr); + } + } else { + if (!ret) { + net_if_ipv6_addr_rm(iface, + &ipv6->unicast[i].address.in6_addr); + } + } + } + +out: + net_if_unlock(iface); +} + +/* If we change filter value, then check if existing IPv6 prefixes will + * conflict with the new filter. + */ +static void ipv6_pe_recheck_filters(bool is_denylist) +{ + k_mutex_lock(&lock, K_FOREVER); + + ARRAY_FOR_EACH(ipv6_pe_filter, i) { + if (net_ipv6_is_addr_unspecified(&ipv6_pe_filter[i])) { + continue; + } + + net_if_foreach(iface_cb, &ipv6_pe_filter[i]); + } + + k_mutex_unlock(&lock); +} +#endif /* CONFIG_NET_IPV6_PE_FILTER_PREFIX_COUNT > 0 */ + +#if CONFIG_NET_IPV6_PE_FILTER_PREFIX_COUNT > 0 +static void send_filter_event(struct in6_addr *addr, bool is_denylist, + int event_type) +{ + if (IS_ENABLED(CONFIG_NET_MGMT_EVENT_INFO)) { + struct net_event_ipv6_pe_filter info; + + net_ipaddr_copy(&info.prefix, addr); + info.is_deny_list = is_denylist; + + net_mgmt_event_notify_with_info(event_type, + NULL, + (const void *)&info, + sizeof(info)); + } else { + net_mgmt_event_notify(event_type, NULL); + } +} +#endif + +int net_ipv6_pe_add_filter(struct in6_addr *addr, bool is_denylist) +{ +#if CONFIG_NET_IPV6_PE_FILTER_PREFIX_COUNT > 0 + bool found = false; + int free_slot = -1; + int ret = 0; + + k_mutex_lock(&lock, K_FOREVER); + + ARRAY_FOR_EACH(ipv6_pe_filter, i) { + if (free_slot < 0 && + net_ipv6_is_addr_unspecified(&ipv6_pe_filter[i])) { + free_slot = i; + continue; + } + + if (net_ipv6_is_prefix((uint8_t *)addr, + (uint8_t *)&ipv6_pe_filter[i], + 64)) { + found = true; + break; + } + } + + if (found) { + NET_DBG("Filter %s already in the list", + net_sprint_ipv6_addr(addr)); + ret = -EALREADY; + goto out; + } + + if (free_slot < 0) { + NET_DBG("All filters in use"); + ret = -ENOMEM; + goto out; + } + + net_ipaddr_copy(&ipv6_pe_filter[free_slot], addr); + + if (ipv6_pe_denylist != is_denylist) { + ipv6_pe_recheck_filters(is_denylist); + } + + ipv6_pe_denylist = is_denylist ? true : false; + + NET_DBG("Adding %s list filter %s", + ipv6_pe_denylist ? "deny" : "allow", + net_sprint_ipv6_addr(&ipv6_pe_filter[free_slot])); + + send_filter_event(&ipv6_pe_filter[free_slot], + is_denylist, + NET_EVENT_IPV6_PE_FILTER_ADD); +out: + k_mutex_unlock(&lock); + + return ret; +#else + ARG_UNUSED(addr); + ARG_UNUSED(is_denylist); + + return -ENOTSUP; +#endif +} + +int net_ipv6_pe_del_filter(struct in6_addr *addr) +{ +#if CONFIG_NET_IPV6_PE_FILTER_PREFIX_COUNT > 0 + int ret = -ENOENT; + + k_mutex_lock(&lock, K_FOREVER); + + ARRAY_FOR_EACH(ipv6_pe_filter, i) { + if (net_ipv6_addr_cmp(&ipv6_pe_filter[i], addr)) { + NET_DBG("Removing %s list filter %s", + ipv6_pe_denylist ? "deny" : "allow", + net_sprint_ipv6_addr(&ipv6_pe_filter[i])); + + send_filter_event(&ipv6_pe_filter[i], + ipv6_pe_denylist, + NET_EVENT_IPV6_PE_FILTER_DEL); + + net_ipaddr_copy(&ipv6_pe_filter[i], + net_ipv6_unspecified_address()); + + ret = 0; + goto out; + } + } + +out: + k_mutex_unlock(&lock); + + return ret; +#else + ARG_UNUSED(addr); + + return -ENOTSUP; +#endif +} + +bool net_ipv6_pe_check_dad(int count) +{ + return count <= TEMP_IDGEN_RETRIES; +} + +int net_ipv6_pe_filter_foreach(net_ipv6_pe_filter_cb_t cb, void *user_data) +{ +#if CONFIG_NET_IPV6_PE_FILTER_PREFIX_COUNT > 0 + int i, count = 0; + + k_mutex_lock(&lock, K_FOREVER); + + for (i = 0; i < CONFIG_NET_IPV6_PE_FILTER_PREFIX_COUNT; i++) { + if (net_ipv6_is_addr_unspecified(&ipv6_pe_filter[i])) { + continue; + } + + cb(&ipv6_pe_filter[i], ipv6_pe_denylist, user_data); + + count++; + } + + k_mutex_unlock(&lock); + + return count; +#else + ARG_UNUSED(cb); + ARG_UNUSED(user_data); + + return 0; +#endif +} + +struct deprecated_work { + struct k_work_delayable work; + struct net_if *iface; + struct in6_addr addr; +}; + +static struct deprecated_work trigger_deprecated_event; + +static void send_deprecated_event(struct k_work *work) +{ + struct k_work_delayable *dwork = k_work_delayable_from_work(work); + struct deprecated_work *dw = CONTAINER_OF(dwork, + struct deprecated_work, + work); + + net_mgmt_event_notify_with_info(NET_EVENT_IPV6_ADDR_DEPRECATED, + dw->iface, &dw->addr, + sizeof(struct in6_addr)); +} + +static void renewal_cb(struct net_if *iface, void *user_data) +{ + struct net_if_ipv6 *ipv6; + struct in6_addr prefix; + + if (net_if_config_ipv6_get(iface, &ipv6) < 0) { + return; + } + + if (!ipv6) { + return; + } + + ARRAY_FOR_EACH(ipv6->unicast, i) { + int32_t diff; + + if (!ipv6->unicast[i].is_used || + ipv6->unicast[i].address.family != AF_INET6 || + !ipv6->unicast[i].is_temporary || + ipv6->unicast[i].addr_state == NET_ADDR_DEPRECATED) { + continue; + } + + /* If the address is too old, then generate a new one + * and remove the old address. + */ + diff = (int32_t)(ipv6->unicast[i].addr_create_time - k_uptime_seconds()); + diff = abs(diff); + + if (diff < (ipv6->unicast[i].addr_preferred_lifetime - + REGEN_ADVANCE(ipv6->retrans_timer, 1U) - + DESYNC_FACTOR(ipv6))) { + continue; + } + + net_ipaddr_copy(&prefix, &ipv6->unicast[i].address.in6_addr); + memset(prefix.s6_addr + 8, 0, sizeof(prefix) - 8); + + NET_DBG("IPv6 address %s is deprecated", + net_sprint_ipv6_addr(&ipv6->unicast[i].address.in6_addr)); + + ipv6->unicast[i].addr_state = NET_ADDR_DEPRECATED; + + /* Create a new temporary address and then notify users + * that the old address is deprecated so that they can + * re-connect to use the new address. We cannot send deprecated + * event immediately because the new IPv6 will need to do DAD + * and that takes a bit time. + */ + net_ipv6_pe_start(iface, &prefix, + TEMP_VALID_LIFETIME, + TEMP_PREFERRED_LIFETIME); + + /* It is very unlikely but still a small possibility that there + * could be another work already pending. + * Fixing this would require allocating space for the work + * somewhere. Currently this does not look like worth fixing. + * Print a warning if there is a work already pending. + */ + if (k_work_delayable_is_pending(&trigger_deprecated_event.work)) { + NET_WARN("Work already pending for deprecated event sending."); + } + + trigger_deprecated_event.iface = iface; + memcpy(&trigger_deprecated_event.addr, + &ipv6->unicast[i].address.in6_addr, + sizeof(struct in6_addr)); + + /* 500ms should be enough for DAD to pass */ + k_work_schedule(&trigger_deprecated_event.work, K_MSEC(500)); + } +} + +static void ipv6_pe_renew(struct k_work *work) +{ + ARG_UNUSED(work); + + net_if_foreach(renewal_cb, NULL); +} + +int net_ipv6_pe_init(struct net_if *iface) +{ + int32_t lifetime; + int ret = 0; + + net_mgmt_event_notify(NET_EVENT_IPV6_PE_ENABLED, iface); + + lifetime = TEMP_VALID_LIFETIME - + REGEN_ADVANCE(net_if_ipv6_get_retrans_timer(iface), 1U); + + if (lifetime <= 0) { + iface->pe_enabled = false; + net_mgmt_event_notify(NET_EVENT_IPV6_PE_DISABLED, iface); + ret = -EINVAL; + goto out; + } + + iface->pe_enabled = true; + iface->pe_prefer_public = + IS_ENABLED(CONFIG_NET_IPV6_PE_PREFER_PUBLIC_ADDRESSES) ? + true : false; + + k_work_init_delayable(&temp_lifetime, ipv6_pe_renew); + k_work_init_delayable(&trigger_deprecated_event.work, + send_deprecated_event); + +out: + NET_DBG("pe %s prefer %s lifetime %d sec", + iface->pe_enabled ? "enabled" : "disabled", + iface->pe_prefer_public ? "public" : "temporary", + lifetime); + + return ret; +} diff --git a/subsys/net/ip/net_context.c b/subsys/net/ip/net_context.c index 5ec66ee7240..20b85237aea 100644 --- a/subsys/net/ip/net_context.c +++ b/subsys/net/ip/net_context.c @@ -156,7 +156,8 @@ static inline bool is_in_tcp_time_wait_state(struct net_context *context) #endif } -static int check_used_port(struct net_if *iface, +static int check_used_port(struct net_context *context, + struct net_if *iface, enum net_ip_protocol proto, uint16_t local_port, const struct sockaddr *local_addr, @@ -170,6 +171,10 @@ static int check_used_port(struct net_if *iface, continue; } + if (context != NULL && context == &contexts[i]) { + continue; + } + if (!(net_context_get_proto(&contexts[i]) == proto && net_sin((struct sockaddr *)& contexts[i].local)->sin_port == local_port)) { @@ -313,7 +318,7 @@ static uint16_t find_available_port(struct net_context *context, do { local_port = sys_rand16_get() | 0x8000; - } while (check_used_port(NULL, net_context_get_proto(context), + } while (check_used_port(context, NULL, net_context_get_proto(context), htons(local_port), addr, false, false) == -EEXIST); return htons(local_port); @@ -327,7 +332,8 @@ bool net_context_port_in_use(enum net_ip_protocol proto, uint16_t local_port, const struct sockaddr *local_addr) { - return check_used_port(NULL, proto, htons(local_port), local_addr, false, false) != 0; + return check_used_port(NULL, NULL, proto, htons(local_port), + local_addr, false, false) != 0; } #if defined(CONFIG_NET_CONTEXT_CHECK) @@ -468,6 +474,10 @@ int net_context_get(sa_family_t family, enum net_sock_type type, uint16_t proto, net_context_set_type(&contexts[i], type); net_context_set_proto(&contexts[i], proto); +#if defined(CONFIG_NET_IPV6) + contexts[i].options.addr_preferences = IPV6_PREFER_SRC_PUBTMP_DEFAULT; +#endif + #if defined(CONFIG_NET_CONTEXT_RCVTIMEO) contexts[i].options.rcvtimeo = K_FOREVER; #endif @@ -790,7 +800,7 @@ int net_context_bind(struct net_context *context, const struct sockaddr *addr, ret = 0; if (addr6->sin6_port) { - ret = check_used_port(iface, + ret = check_used_port(context, iface, context->proto, addr6->sin6_port, addr, @@ -890,7 +900,7 @@ int net_context_bind(struct net_context *context, const struct sockaddr *addr, ret = 0; if (addr4->sin_port) { - ret = check_used_port(iface, + ret = check_used_port(context, iface, context->proto, addr4->sin_port, addr, @@ -1131,10 +1141,10 @@ int net_context_create_ipv6_new(struct net_context *context, src = ((struct sockaddr_in6_ptr *)&context->local)->sin6_addr; } - if (net_ipv6_is_addr_unspecified(src) - || net_ipv6_is_addr_mcast(src)) { - src = net_if_ipv6_select_src_addr(net_pkt_iface(pkt), - (struct in6_addr *)dst); + if (net_ipv6_is_addr_unspecified(src) || net_ipv6_is_addr_mcast(src)) { + src = net_if_ipv6_select_src_addr_hint(net_pkt_iface(pkt), + (struct in6_addr *)dst, + context->options.addr_preferences); } #if defined(CONFIG_NET_CONTEXT_DSCP_ECN) @@ -1711,6 +1721,21 @@ static int get_context_recv_pktinfo(struct net_context *context, #endif } +static int get_context_addr_preferences(struct net_context *context, + void *value, size_t *len) +{ +#if defined(CONFIG_NET_IPV6) + return get_uint16_option(context->options.addr_preferences, + value, len); +#else + ARG_UNUSED(context); + ARG_UNUSED(value); + ARG_UNUSED(len); + + return -ENOTSUP; +#endif +} + /* If buf is not NULL, then use it. Otherwise read the data to be written * to net_pkt from msghdr. */ @@ -3001,6 +3026,21 @@ static int set_context_recv_pktinfo(struct net_context *context, #endif } +static int set_context_addr_preferences(struct net_context *context, + const void *value, size_t len) +{ +#if defined(CONFIG_NET_IPV6) + return set_uint16_option(&context->options.addr_preferences, + value, len); +#else + ARG_UNUSED(context); + ARG_UNUSED(value); + ARG_UNUSED(len); + + return -ENOTSUP; +#endif +} + int net_context_set_option(struct net_context *context, enum net_context_option option, const void *value, size_t len) @@ -3064,6 +3104,9 @@ int net_context_set_option(struct net_context *context, case NET_OPT_RECV_PKTINFO: ret = set_context_recv_pktinfo(context, value, len); break; + case NET_OPT_ADDR_PREFERENCES: + ret = set_context_addr_preferences(context, value, len); + break; } k_mutex_unlock(&context->lock); @@ -3134,6 +3177,9 @@ int net_context_get_option(struct net_context *context, case NET_OPT_RECV_PKTINFO: ret = get_context_recv_pktinfo(context, value, len); break; + case NET_OPT_ADDR_PREFERENCES: + ret = get_context_addr_preferences(context, value, len); + break; } k_mutex_unlock(&context->lock); @@ -3141,6 +3187,51 @@ int net_context_get_option(struct net_context *context, return ret; } +int net_context_get_local_addr(struct net_context *ctx, + struct sockaddr *addr, + socklen_t *addrlen) +{ + if (ctx == NULL || addr == NULL || addrlen == NULL) { + return -EINVAL; + } + + if (IS_ENABLED(CONFIG_NET_TCP) && + net_context_get_type(ctx) == SOCK_STREAM) { + return net_tcp_endpoint_copy(ctx, addr, NULL, addrlen); + } + + if (IS_ENABLED(CONFIG_NET_UDP) && net_context_get_type(ctx) == SOCK_DGRAM) { + socklen_t newlen; + + if (IS_ENABLED(CONFIG_NET_IPV4) && ctx->local.family == AF_INET) { + newlen = MIN(*addrlen, sizeof(struct sockaddr_in)); + + net_sin(addr)->sin_family = AF_INET; + net_sin(addr)->sin_port = net_sin_ptr(&ctx->local)->sin_port; + memcpy(&net_sin(addr)->sin_addr, + net_sin_ptr(&ctx->local)->sin_addr, + sizeof(struct in_addr)); + + } else if (IS_ENABLED(CONFIG_NET_IPV6) && ctx->local.family == AF_INET6) { + newlen = MIN(*addrlen, sizeof(struct sockaddr_in6)); + + net_sin6(addr)->sin6_family = AF_INET6; + net_sin6(addr)->sin6_port = net_sin6_ptr(&ctx->local)->sin6_port; + memcpy(&net_sin6(addr)->sin6_addr, + net_sin6_ptr(&ctx->local)->sin6_addr, + sizeof(struct in6_addr)); + } else { + return -EAFNOSUPPORT; + } + + *addrlen = newlen; + + return 0; + } + + return -ENOPROTOOPT; +} + void net_context_foreach(net_context_cb_t cb, void *user_data) { int i; diff --git a/subsys/net/ip/net_if.c b/subsys/net/ip/net_if.c index 15a66af477c..dc115aaf2c3 100644 --- a/subsys/net/ip/net_if.c +++ b/subsys/net/ip/net_if.c @@ -24,6 +24,7 @@ LOG_MODULE_REGISTER(net_if, CONFIG_NET_IF_LOG_LEVEL); #include #include #include +#include #include #include "net_private.h" @@ -431,6 +432,8 @@ static inline void init_iface(struct net_if *iface) k_mutex_init(&iface->tx_lock); api->init(iface); + + net_ipv6_pe_init(iface); } enum net_verdict net_if_send_data(struct net_if *iface, struct net_pkt *pkt) @@ -576,6 +579,7 @@ struct net_if *net_if_get_default(void) struct net_if *iface = NULL; if (&_net_if_list_start[0] == &_net_if_list_end[0]) { + NET_WARN("No default interface found!"); return NULL; } @@ -589,9 +593,6 @@ struct net_if *net_if_get_default(void) #if defined(CONFIG_NET_DEFAULT_IF_IEEE802154) iface = net_if_get_first_by_type(&NET_L2_GET_NAME(IEEE802154)); #endif -#if defined(CONFIG_NET_DEFAULT_IF_BLUETOOTH) - iface = net_if_get_first_by_type(&NET_L2_GET_NAME(BLUETOOTH)); -#endif #if defined(CONFIG_NET_DEFAULT_IF_DUMMY) iface = net_if_get_first_by_type(&NET_L2_GET_NAME(DUMMY)); #endif @@ -1235,8 +1236,8 @@ static void dad_timeout(struct k_work *work) } } -static void net_if_ipv6_start_dad(struct net_if *iface, - struct net_if_addr *ifaddr) +void net_if_ipv6_start_dad(struct net_if *iface, + struct net_if_addr *ifaddr) { ifaddr->addr_state = NET_ADDR_TENTATIVE; @@ -1327,6 +1328,7 @@ void net_if_start_dad(struct net_if *iface) void net_if_ipv6_dad_failed(struct net_if *iface, const struct in6_addr *addr) { struct net_if_addr *ifaddr; + uint32_t timeout, preferred_lifetime; net_if_lock(iface); @@ -1338,12 +1340,36 @@ void net_if_ipv6_dad_failed(struct net_if *iface, const struct in6_addr *addr) } + if (IS_ENABLED(CONFIG_NET_IPV6_PE)) { + ifaddr->dad_count++; + + timeout = COND_CODE_1(CONFIG_NET_IPV6_PE, + (ifaddr->addr_timeout), (0)); + preferred_lifetime = COND_CODE_1(CONFIG_NET_IPV6_PE, + (ifaddr->addr_preferred_lifetime), (0U)); + + if (!net_ipv6_pe_check_dad(ifaddr->dad_count)) { + NET_ERR("Cannot generate PE address for interface %p", + iface); + iface->pe_enabled = false; + net_mgmt_event_notify(NET_EVENT_IPV6_PE_DISABLED, iface); + } + } + net_mgmt_event_notify_with_info(NET_EVENT_IPV6_DAD_FAILED, iface, &ifaddr->address.in6_addr, sizeof(struct in6_addr)); + /* The old address needs to be removed from the interface before we can + * start new DAD for the new PE address as the amount of address slots + * is limited. + */ net_if_ipv6_addr_rm(iface, addr); + if (IS_ENABLED(CONFIG_NET_IPV6_PE) && iface->pe_enabled) { + net_ipv6_pe_start(iface, addr, timeout, preferred_lifetime); + } + out: net_if_unlock(iface); } @@ -1632,37 +1658,68 @@ static void rejoin_ipv6_mcast_groups(struct net_if *iface) net_if_lock(iface); + if (!net_if_flag_is_set(iface, NET_IF_IPV6) || + net_if_flag_is_set(iface, NET_IF_IPV6_NO_ND)) { + goto out; + } + if (net_if_config_ipv6_get(iface, &ipv6) < 0) { goto out; } + /* Rejoin solicited node multicasts. */ ARRAY_FOR_EACH(ipv6->unicast, i) { - struct net_if_mcast_addr *maddr; - struct in6_addr addr; - int ret; - if (!ipv6->unicast[i].is_used) { continue; } - net_ipv6_addr_create_solicited_node( - &ipv6->unicast[i].address.in6_addr, - &addr); + join_mcast_nodes(iface, &ipv6->unicast[i].address.in6_addr); + } + + /* Rejoin any mcast address present on the interface, but marked as not joined. */ + ARRAY_FOR_EACH(ipv6->mcast, i) { + int ret; - maddr = net_if_ipv6_maddr_lookup(&addr, &iface); - if (!maddr) { + if (!ipv6->mcast[i].is_used || + net_if_ipv4_maddr_is_joined(&ipv6->mcast[i])) { continue; } - if (net_if_ipv4_maddr_is_joined(maddr)) { - continue; + ret = net_ipv6_mld_join(iface, &ipv6->mcast[i].address.in6_addr); + if (ret < 0) { + NET_ERR("Cannot join mcast address %s for %d (%d)", + net_sprint_ipv6_addr(&ipv6->mcast[i].address.in6_addr), + net_if_get_by_iface(iface), ret); } + } + +out: + net_if_unlock(iface); +} + +/* To be called when interface comes operational down so that multicast + * groups are rejoined when back up. + */ +static void clear_joined_ipv6_mcast_groups(struct net_if *iface) +{ + struct net_if_ipv6 *ipv6; + + net_if_lock(iface); + + if (!net_if_flag_is_set(iface, NET_IF_IPV6)) { + goto out; + } + + if (net_if_config_ipv6_get(iface, &ipv6) < 0) { + goto out; + } - ret = net_ipv6_mld_join(iface, &addr); - if (ret < 0 && ret != EALREADY) { - NET_DBG("Cannot rejoin multicast group %s (%d)", - net_sprint_ipv6_addr(&addr), ret); + ARRAY_FOR_EACH(ipv6->mcast, i) { + if (!ipv6->mcast[i].is_used) { + continue; } + + net_if_ipv6_maddr_leave(iface, &ipv6->mcast[i]); } out: @@ -1671,15 +1728,23 @@ static void rejoin_ipv6_mcast_groups(struct net_if *iface) static void address_expired(struct net_if_addr *ifaddr) { - NET_DBG("IPv6 address %s is deprecated", + NET_DBG("IPv6 address %s is expired", net_sprint_ipv6_addr(&ifaddr->address.in6_addr)); - ifaddr->addr_state = NET_ADDR_DEPRECATED; - sys_slist_find_and_remove(&active_address_lifetime_timers, &ifaddr->lifetime.node); net_timeout_set(&ifaddr->lifetime, 0, 0); + + STRUCT_SECTION_FOREACH(net_if, iface) { + ARRAY_FOR_EACH(iface->config.ip.ipv6->unicast, i) { + if (&iface->config.ip.ipv6->unicast[i] == ifaddr) { + net_if_ipv6_addr_rm(iface, + &iface->config.ip.ipv6->unicast[i].address.in6_addr); + return; + } + } + } } static void address_lifetime_timeout(struct k_work *work) @@ -1730,6 +1795,12 @@ void net_address_lifetime_timeout(void) static void address_start_timer(struct net_if_addr *ifaddr, uint32_t vlifetime) { + /* Make sure that we do not insert the address twice to + * the lifetime timer list. + */ + sys_slist_find_and_remove(&active_address_lifetime_timers, + &ifaddr->lifetime.node); + sys_slist_append(&active_address_lifetime_timers, &ifaddr->lifetime.node); @@ -1779,8 +1850,11 @@ static inline void net_if_addr_init(struct net_if_addr *ifaddr, uint32_t vlifetime) { ifaddr->is_used = true; + ifaddr->is_temporary = false; ifaddr->address.family = AF_INET6; ifaddr->addr_type = addr_type; + ifaddr->atomic_ref = ATOMIC_INIT(1); + net_ipaddr_copy(&ifaddr->address.in6_addr, addr); /* FIXME - set the mcast addr for this node */ @@ -1871,105 +1945,28 @@ struct net_if_addr *net_if_ipv6_addr_add(struct net_if *iface, bool net_if_ipv6_addr_rm(struct net_if *iface, const struct in6_addr *addr) { - bool ret = false; struct net_if_ipv6 *ipv6; - struct in6_addr maddr; - int found = -1; - unsigned int maddr_count = 0; + int ret; NET_ASSERT(addr); - net_if_lock(iface); - ipv6 = iface->config.ip.ipv6; if (!ipv6) { - goto out; - } - - net_ipv6_addr_create_solicited_node(addr, &maddr); - - ARRAY_FOR_EACH(ipv6->unicast, i) { - struct in6_addr unicast_maddr; - - if (!ipv6->unicast[i].is_used) { - continue; - } - - /* count how many times this solicited-node multicast address is identical - * for all the used unicast addresses - */ - net_ipv6_addr_create_solicited_node(&ipv6->unicast[i].address.in6_addr, - &unicast_maddr); - if (net_ipv6_addr_cmp(&maddr, &unicast_maddr)) { - maddr_count++; - } - - if (!net_ipv6_addr_cmp(&ipv6->unicast[i].address.in6_addr, - addr)) { - continue; - } - - found = i; + return false; } - if (found >= 0) { - if (!ipv6->unicast[found].is_infinite) { - k_mutex_lock(&lock, K_FOREVER); - - sys_slist_find_and_remove( - &active_address_lifetime_timers, - &ipv6->unicast[found].lifetime.node); - - if (sys_slist_is_empty( - &active_address_lifetime_timers)) { - k_work_cancel_delayable( - &address_lifetime_timer); - } - - k_mutex_unlock(&lock); - } - -#if defined(CONFIG_NET_IPV6_DAD) - if (!net_if_flag_is_set(iface, NET_IF_IPV6_NO_ND)) { - k_mutex_lock(&lock, K_FOREVER); - sys_slist_find_and_remove(&active_dad_timers, - &ipv6->unicast[found].dad_node); - k_mutex_unlock(&lock); - } -#endif - - ipv6->unicast[found].is_used = false; - - if (maddr_count == 1) { - /* remove the solicited-node multicast address only if no other - * unicast address is also using it - */ - net_if_ipv6_maddr_rm(iface, &maddr); - } - - NET_DBG("[%d] interface %d (%p) address %s type %s removed", - found, net_if_get_by_iface(iface), iface, - net_sprint_ipv6_addr(addr), - net_addr_type2str(ipv6->unicast[found].addr_type)); - - /* Using the IPv6 address pointer here can give false - * info if someone adds a new IP address into this position - * in the address array. This is quite unlikely thou. - */ - net_mgmt_event_notify_with_info( - NET_EVENT_IPV6_ADDR_DEL, - iface, - &ipv6->unicast[found].address.in6_addr, - sizeof(struct in6_addr)); + ret = net_if_addr_unref(iface, AF_INET6, addr); + if (ret > 0) { + NET_DBG("Address %s still in use (ref %d)", + net_sprint_ipv6_addr(addr), ret); + return false; - ret = true; - goto out; + } else if (ret < 0) { + NET_DBG("Address %s not found (%d)", + net_sprint_ipv6_addr(addr), ret); } -out: - net_if_unlock(iface); - - return ret; + return true; } bool z_impl_net_if_ipv6_addr_add_by_index(int index, @@ -2562,7 +2559,7 @@ bool net_if_ipv6_prefix_rm(struct net_if *iface, struct in6_addr *addr, } struct net_if_ipv6_prefix *net_if_ipv6_prefix_get(struct net_if *iface, - struct in6_addr *addr) + const struct in6_addr *addr) { struct net_if_ipv6_prefix *prefix = NULL; struct net_if_ipv6 *ipv6; @@ -2571,6 +2568,10 @@ struct net_if_ipv6_prefix *net_if_ipv6_prefix_get(struct net_if *iface, iface = net_if_get_default(); } + if (!iface) { + return NULL; + } + net_if_lock(iface); ipv6 = iface->config.ip.ipv6; @@ -2956,13 +2957,41 @@ static inline bool is_proper_ipv6_address(struct net_if_addr *addr) return false; } +static bool use_public_address(bool prefer_public, bool is_temporary, + int flags) +{ + if (IS_ENABLED(CONFIG_NET_IPV6_PE)) { + if (!prefer_public && is_temporary) { + + /* Allow socket to override the kconfig option */ + if (flags & IPV6_PREFER_SRC_PUBLIC) { + return true; + } + + return false; + } + } + + if (flags & IPV6_PREFER_SRC_TMP) { + return false; + } + + return true; +} + static struct in6_addr *net_if_ipv6_get_best_match(struct net_if *iface, const struct in6_addr *dst, - uint8_t *best_so_far) + uint8_t prefix_len, + uint8_t *best_so_far, + int flags) { - struct net_if_ipv6 *ipv6; + struct net_if_ipv6 *ipv6 = iface->config.ip.ipv6; + struct net_if_addr *public_addr = NULL; struct in6_addr *src = NULL; - uint8_t len; + uint8_t public_addr_len = 0; + struct in6_addr *temp_addr = NULL; + uint8_t len, temp_addr_len = 0; + bool ret; net_if_lock(iface); @@ -2977,6 +3006,10 @@ static struct in6_addr *net_if_ipv6_get_best_match(struct net_if *iface, } len = get_diff_ipv6(dst, &ipv6->unicast[i].address.in6_addr); + if (len >= prefix_len) { + len = prefix_len; + } + if (len >= *best_so_far) { /* Mesh local address can only be selected for the same * subnet. @@ -2986,19 +3019,61 @@ static struct in6_addr *net_if_ipv6_get_best_match(struct net_if *iface, continue; } + ret = use_public_address(iface->pe_prefer_public, + ipv6->unicast[i].is_temporary, + flags); + if (!ret) { + temp_addr = &ipv6->unicast[i].address.in6_addr; + temp_addr_len = len; + + *best_so_far = len; + src = &ipv6->unicast[i].address.in6_addr; + continue; + } + + if (!ipv6->unicast[i].is_temporary) { + public_addr = &ipv6->unicast[i]; + public_addr_len = len; + } + *best_so_far = len; src = &ipv6->unicast[i].address.in6_addr; } } + if (IS_ENABLED(CONFIG_NET_IPV6_PE) && !iface->pe_prefer_public && temp_addr) { + if (temp_addr_len >= *best_so_far) { + *best_so_far = temp_addr_len; + src = temp_addr; + } + } else { + /* By default prefer always public address if found */ + if (flags & IPV6_PREFER_SRC_PUBLIC) { +use_public: + if (public_addr && + !net_ipv6_addr_cmp(&public_addr->address.in6_addr, src)) { + src = &public_addr->address.in6_addr; + *best_so_far = public_addr_len; + } + } else if (flags & IPV6_PREFER_SRC_TMP) { + if (temp_addr && !net_ipv6_addr_cmp(temp_addr, src)) { + src = temp_addr; + *best_so_far = temp_addr_len; + } + } else if (flags & IPV6_PREFER_SRC_PUBTMP_DEFAULT) { + goto use_public; + } + } + out: net_if_unlock(iface); return src; } -const struct in6_addr *net_if_ipv6_select_src_addr(struct net_if *dst_iface, - const struct in6_addr *dst) +const struct in6_addr *net_if_ipv6_select_src_addr_hint(struct net_if *dst_iface, + const struct in6_addr *dst, + int flags) { const struct in6_addr *src = NULL; uint8_t best_match = 0U; @@ -3006,16 +3081,28 @@ const struct in6_addr *net_if_ipv6_select_src_addr(struct net_if *dst_iface, NET_ASSERT(dst); if (!net_ipv6_is_ll_addr(dst) && !net_ipv6_is_addr_mcast_link(dst)) { + struct net_if_ipv6_prefix *prefix; + uint8_t prefix_len = 128; + + prefix = net_if_ipv6_prefix_get(dst_iface, dst); + if (prefix) { + prefix_len = prefix->len; + } + /* If caller has supplied interface, then use that */ if (dst_iface) { src = net_if_ipv6_get_best_match(dst_iface, dst, - &best_match); + prefix_len, + &best_match, + flags); } else { STRUCT_SECTION_FOREACH(net_if, iface) { struct in6_addr *addr; addr = net_if_ipv6_get_best_match(iface, dst, - &best_match); + prefix_len, + &best_match, + flags); if (addr) { src = addr; } @@ -3053,6 +3140,14 @@ const struct in6_addr *net_if_ipv6_select_src_addr(struct net_if *dst_iface, return src; } +const struct in6_addr *net_if_ipv6_select_src_addr(struct net_if *dst_iface, + const struct in6_addr *dst) +{ + return net_if_ipv6_select_src_addr_hint(dst_iface, + dst, + IPV6_PREFER_SRC_PUBTMP_DEFAULT); +} + struct net_if *net_if_ipv6_select_src_iface(const struct in6_addr *dst) { struct net_if *iface = NULL; @@ -3107,6 +3202,20 @@ static void iface_ipv6_start(struct net_if *iface) net_if_start_rs(iface); } +static void iface_ipv6_stop(struct net_if *iface) +{ + struct in6_addr addr = { }; + + if (!net_if_flag_is_set(iface, NET_IF_IPV6) || + net_if_flag_is_set(iface, NET_IF_IPV6_NO_ND)) { + return; + } + + net_ipv6_addr_create_iid(&addr, net_if_get_link_addr(iface)); + + (void)net_if_ipv6_addr_rm(iface, &addr); +} + static void iface_ipv6_init(int if_count) { iface_ipv6_dad_init(); @@ -3137,8 +3246,10 @@ static void iface_ipv6_init(int if_count) #define join_mcast_allnodes(...) #define join_mcast_solicit_node(...) #define leave_mcast_all(...) +#define clear_joined_ipv6_mcast_groups(...) #define join_mcast_nodes(...) #define iface_ipv6_start(...) +#define iface_ipv6_stop(...) #define iface_ipv6_init(...) struct net_if_mcast_addr *net_if_ipv6_maddr_lookup(const struct in6_addr *addr, @@ -3438,7 +3549,7 @@ static bool ipv4_is_broadcast_address(struct net_if *iface, bcast.s_addr = ipv4->unicast[i].ipv4.address.in_addr.s_addr | ~ipv4->unicast[i].netmask.s_addr; - if (bcast.s_addr == addr->s_addr) { + if (bcast.s_addr == UNALIGNED_GET(&addr->s_addr)) { ret = true; goto out; } @@ -4087,6 +4198,7 @@ struct net_if_addr *net_if_ipv4_addr_add(struct net_if *iface, ifaddr->address.in_addr.s4_addr32[0] = addr->s4_addr32[0]; ifaddr->addr_type = addr_type; + ifaddr->atomic_ref = ATOMIC_INIT(1); /* Caller has to take care of timers and their expiry */ if (vlifetime) { @@ -4121,44 +4233,27 @@ struct net_if_addr *net_if_ipv4_addr_add(struct net_if *iface, bool net_if_ipv4_addr_rm(struct net_if *iface, const struct in_addr *addr) { struct net_if_ipv4 *ipv4; - bool ret = false; + int ret; - net_if_lock(iface); + NET_ASSERT(addr); ipv4 = iface->config.ip.ipv4; if (!ipv4) { - goto out; + return false; } - ARRAY_FOR_EACH(ipv4->unicast, i) { - if (!ipv4->unicast[i].ipv4.is_used) { - continue; - } - - if (!net_ipv4_addr_cmp(&ipv4->unicast[i].ipv4.address.in_addr, - addr)) { - continue; - } - - ipv4->unicast[i].ipv4.is_used = false; - - NET_DBG("[%zu] interface %d (%p) address %s removed", - i, net_if_get_by_iface(iface), iface, - net_sprint_ipv4_addr(addr)); - - net_mgmt_event_notify_with_info( - NET_EVENT_IPV4_ADDR_DEL, iface, - &ipv4->unicast[i].ipv4.address.in_addr, - sizeof(struct in_addr)); + ret = net_if_addr_unref(iface, AF_INET, addr); + if (ret > 0) { + NET_DBG("Address %s still in use (ref %d)", + net_sprint_ipv4_addr(addr), ret); + return false; - ret = true; - goto out; + } else if (ret < 0) { + NET_DBG("Address %s not found (%d)", + net_sprint_ipv4_addr(addr), ret); } -out: - net_if_unlock(iface); - - return ret; + return true; } bool z_impl_net_if_ipv4_addr_add_by_index(int index, @@ -4531,6 +4626,304 @@ struct net_if *net_if_select_src_iface(const struct sockaddr *dst) return iface; } +static struct net_if_addr *get_ifaddr(struct net_if *iface, + sa_family_t family, + const void *addr, + unsigned int *mcast_addr_count) +{ + struct net_if_addr *ifaddr = NULL; + + net_if_lock(iface); + + if (IS_ENABLED(CONFIG_NET_IPV6) && family == AF_INET6) { + struct net_if_ipv6 *ipv6 = + COND_CODE_1(CONFIG_NET_NATIVE_IPV6, (iface->config.ip.ipv6), (NULL)); + + struct in6_addr maddr; + unsigned int maddr_count = 0; + int found = -1; + + net_ipv6_addr_create_solicited_node((struct in6_addr *)addr, + &maddr); + + ARRAY_FOR_EACH(ipv6->unicast, i) { + struct in6_addr unicast_maddr; + + if (!ipv6->unicast[i].is_used) { + continue; + } + + /* Count how many times this solicited-node multicast address is identical + * for all the used unicast addresses + */ + net_ipv6_addr_create_solicited_node( + &ipv6->unicast[i].address.in6_addr, + &unicast_maddr); + + if (net_ipv6_addr_cmp(&maddr, &unicast_maddr)) { + maddr_count++; + } + + if (!net_ipv6_addr_cmp(&ipv6->unicast[i].address.in6_addr, addr)) { + continue; + } + + found = i; + } + + if (found >= 0) { + ifaddr = &ipv6->unicast[found]; + + if (mcast_addr_count != NULL) { + *mcast_addr_count = maddr_count; + } + } + + goto out; + } + + if (IS_ENABLED(CONFIG_NET_IPV4) && family == AF_INET) { + struct net_if_ipv4 *ipv4 = + COND_CODE_1(CONFIG_NET_NATIVE_IPV4, (iface->config.ip.ipv4), (NULL)); + + ARRAY_FOR_EACH(ipv4->unicast, i) { + if (!ipv4->unicast[i].ipv4.is_used) { + continue; + } + + if (!net_ipv4_addr_cmp(&ipv4->unicast[i].ipv4.address.in_addr, + addr)) { + continue; + } + + ifaddr = &ipv4->unicast[i].ipv4; + + goto out; + } + } + +out: + net_if_unlock(iface); + + return ifaddr; +} + +static void remove_ipv6_ifaddr(struct net_if *iface, + struct net_if_addr *ifaddr, + unsigned int maddr_count) +{ + struct net_if_ipv6 *ipv6; + + net_if_lock(iface); + + ipv6 = COND_CODE_1(CONFIG_NET_NATIVE_IPV6, (iface->config.ip.ipv6), (NULL)); + if (!ipv6) { + goto out; + } + + if (!ifaddr->is_infinite) { + k_mutex_lock(&lock, K_FOREVER); + +#if defined(CONFIG_NET_NATIVE_IPV6) + sys_slist_find_and_remove(&active_address_lifetime_timers, + &ifaddr->lifetime.node); + + if (sys_slist_is_empty(&active_address_lifetime_timers)) { + k_work_cancel_delayable(&address_lifetime_timer); + } +#endif + k_mutex_unlock(&lock); + } + +#if defined(CONFIG_NET_IPV6_DAD) + if (!net_if_flag_is_set(iface, NET_IF_IPV6_NO_ND)) { + k_mutex_lock(&lock, K_FOREVER); + sys_slist_find_and_remove(&active_dad_timers, + &ifaddr->dad_node); + k_mutex_unlock(&lock); + } +#endif + + if (maddr_count == 1) { + /* Remove the solicited-node multicast address only if no other + * unicast address is also using it + */ + struct in6_addr maddr; + + net_ipv6_addr_create_solicited_node(&ifaddr->address.in6_addr, + &maddr); + net_if_ipv6_maddr_rm(iface, &maddr); + } + + /* Using the IPv6 address pointer here can give false + * info if someone adds a new IP address into this position + * in the address array. This is quite unlikely thou. + */ + net_mgmt_event_notify_with_info(NET_EVENT_IPV6_ADDR_DEL, + iface, + &ifaddr->address.in6_addr, + sizeof(struct in6_addr)); +out: + net_if_unlock(iface); +} + +static void remove_ipv4_ifaddr(struct net_if *iface, + struct net_if_addr *ifaddr) +{ + struct net_if_ipv4 *ipv4; + + net_if_lock(iface); + + ipv4 = COND_CODE_1(CONFIG_NET_NATIVE_IPV4, (iface->config.ip.ipv4), (NULL)); + if (!ipv4) { + goto out; + } + + net_mgmt_event_notify_with_info(NET_EVENT_IPV4_ADDR_DEL, + iface, + &ifaddr->address.in_addr, + sizeof(struct in_addr)); +out: + net_if_unlock(iface); +} + +#if defined(CONFIG_NET_IF_LOG_LEVEL) +#define NET_LOG_LEVEL CONFIG_NET_IF_LOG_LEVEL +#else +#define NET_LOG_LEVEL 0 +#endif + +#if NET_LOG_LEVEL >= LOG_LEVEL_DBG +struct net_if_addr *net_if_addr_ref_debug(struct net_if *iface, + sa_family_t family, + const void *addr, + const char *caller, + int line) +#else +struct net_if_addr *net_if_addr_ref(struct net_if *iface, + sa_family_t family, + const void *addr) +#endif /* NET_LOG_LEVEL >= LOG_LEVEL_DBG */ +{ + struct net_if_addr *ifaddr; + atomic_val_t ref; + +#if NET_LOG_LEVEL >= LOG_LEVEL_DBG + char addr_str[IS_ENABLED(CONFIG_NET_IPV6) ? + INET6_ADDRSTRLEN : INET_ADDRSTRLEN]; + + __ASSERT(iface, "iface is NULL (%s():%d)", caller, line); +#endif + + ifaddr = get_ifaddr(iface, family, addr, NULL); + + do { + ref = ifaddr ? atomic_get(&ifaddr->atomic_ref) : 0; + if (!ref) { +#if NET_LOG_LEVEL >= LOG_LEVEL_DBG + NET_ERR("iface %d addr %s (%s():%d)", + net_if_get_by_iface(iface), + net_addr_ntop(family, + addr, + addr_str, sizeof(addr_str)), + caller, line); +#endif + return NULL; + } + } while (!atomic_cas(&ifaddr->atomic_ref, ref, ref + 1)); + +#if NET_LOG_LEVEL >= LOG_LEVEL_DBG + NET_DBG("[%d] ifaddr %s state %d ref %ld (%s():%d)", + net_if_get_by_iface(iface), + net_addr_ntop(ifaddr->address.family, + (void *)&ifaddr->address.in_addr, + addr_str, sizeof(addr_str)), + ifaddr->addr_state, + ref + 1, + caller, line); +#endif + + return ifaddr; +} + +#if NET_LOG_LEVEL >= LOG_LEVEL_DBG +int net_if_addr_unref_debug(struct net_if *iface, + sa_family_t family, + const void *addr, + const char *caller, int line) +#else +int net_if_addr_unref(struct net_if *iface, + sa_family_t family, + const void *addr) +#endif /* NET_LOG_LEVEL >= LOG_LEVEL_DBG */ +{ + struct net_if_addr *ifaddr; + unsigned int maddr_count = 0; + atomic_val_t ref; + +#if NET_LOG_LEVEL >= LOG_LEVEL_DBG + char addr_str[IS_ENABLED(CONFIG_NET_IPV6) ? + INET6_ADDRSTRLEN : INET_ADDRSTRLEN]; + + __ASSERT(iface, "iface is NULL (%s():%d)", caller, line); +#endif + + ifaddr = get_ifaddr(iface, family, addr, &maddr_count); + + if (!ifaddr) { +#if NET_LOG_LEVEL >= LOG_LEVEL_DBG + NET_ERR("iface %d addr %s (%s():%d)", + net_if_get_by_iface(iface), + net_addr_ntop(family, + addr, + addr_str, sizeof(addr_str)), + caller, line); +#endif + return -EINVAL; + } + + do { + ref = atomic_get(&ifaddr->atomic_ref); + if (!ref) { +#if NET_LOG_LEVEL >= LOG_LEVEL_DBG + NET_ERR("*** ERROR *** iface %d ifaddr %p " + "is freed already (%s():%d)", + net_if_get_by_iface(iface), + ifaddr, + caller, line); +#endif + return -EINVAL; + } + + } while (!atomic_cas(&ifaddr->atomic_ref, ref, ref - 1)); + +#if NET_LOG_LEVEL >= LOG_LEVEL_DBG + NET_DBG("[%d] ifaddr %s state %d ref %ld (%s():%d)", + net_if_get_by_iface(iface), + net_addr_ntop(ifaddr->address.family, + (void *)&ifaddr->address.in_addr, + addr_str, sizeof(addr_str)), + ifaddr->addr_state, + ref - 1, caller, line); +#endif + + if (ref > 1) { + return ref - 1; + } + + ifaddr->is_used = false; + + if (IS_ENABLED(CONFIG_NET_IPV6) && family == AF_INET6 && addr != NULL) { + remove_ipv6_ifaddr(iface, ifaddr, maddr_count); + } + + if (IS_ENABLED(CONFIG_NET_IPV4) && family == AF_INET && addr != NULL) { + remove_ipv4_ifaddr(iface, ifaddr); + } + + return 0; +} + enum net_verdict net_if_recv_data(struct net_if *iface, struct net_pkt *pkt) { if (IS_ENABLED(CONFIG_NET_PROMISCUOUS_MODE) && @@ -4688,6 +5081,8 @@ static void notify_iface_down(struct net_if *iface) if (!net_if_is_offloaded(iface) && !(l2_flags_get(iface) & NET_L2_POINT_TO_POINT)) { + iface_ipv6_stop(iface); + clear_joined_ipv6_mcast_groups(iface); net_ipv4_autoconf_reset(iface); } } diff --git a/subsys/net/ip/net_pkt.c b/subsys/net/ip/net_pkt.c index 81d9d35b736..3a72522c928 100644 --- a/subsys/net/ip/net_pkt.c +++ b/subsys/net/ip/net_pkt.c @@ -315,10 +315,10 @@ void net_pkt_print_frags(struct net_pkt *pkt) while (frag) { total += frag->len; - frag_size = frag->size; + frag_size = net_buf_max_len(frag); NET_INFO("[%d] frag %p len %d max len %u size %d pool %p", - count, frag, frag->len, net_buf_max_len(frag), + count, frag, frag->len, frag->size, frag_size, net_buf_pool_get(frag->pool_id)); count++; @@ -2130,8 +2130,9 @@ size_t net_pkt_get_contiguous_len(struct net_pkt *pkt) size_t len; len = net_pkt_is_being_overwritten(pkt) ? - pkt->cursor.buf->len : pkt->cursor.buf->size; + pkt->cursor.buf->len : net_buf_max_len(pkt->cursor.buf); len -= pkt->cursor.pos - pkt->cursor.buf->data; + return len; } diff --git a/subsys/net/ip/net_private.h b/subsys/net/ip/net_private.h index 0cd007595f6..cb9d8dc396f 100644 --- a/subsys/net/ip/net_private.h +++ b/subsys/net/ip/net_private.h @@ -81,6 +81,9 @@ extern bool net_context_is_recv_pktinfo_set(struct net_context *context); extern void net_pkt_init(void); extern void net_tc_tx_init(void); extern void net_tc_rx_init(void); +int net_context_get_local_addr(struct net_context *context, + struct sockaddr *addr, + socklen_t *addrlen); #else static inline void net_context_init(void) { } static inline void net_pkt_init(void) { } @@ -106,6 +109,17 @@ static inline bool net_context_is_recv_pktinfo_set(struct net_context *context) ARG_UNUSED(context); return false; } + +static inline int net_context_get_local_addr(struct net_context *context, + struct sockaddr *addr, + socklen_t *addrlen) +{ + ARG_UNUSED(context); + ARG_UNUSED(addr); + ARG_UNUSED(addrlen); + + return -ENOTSUP; +} #endif #if defined(CONFIG_NET_NATIVE) @@ -174,6 +188,12 @@ struct sock_obj { }; #endif /* CONFIG_NET_SOCKETS_OBJ_CORE */ +#if defined(CONFIG_NET_IPV6_PE) +/* This is needed by ipv6_pe.c when privacy extension support is enabled */ +void net_if_ipv6_start_dad(struct net_if *iface, + struct net_if_addr *ifaddr); +#endif + #if defined(CONFIG_NET_GPTP) /** * @brief Initialize Precision Time Protocol Layer. diff --git a/subsys/net/ip/route.c b/subsys/net/ip/route.c index 6d4ae1ff5f7..09f71c5b179 100644 --- a/subsys/net/ip/route.c +++ b/subsys/net/ip/route.c @@ -729,43 +729,128 @@ int net_route_foreach(net_route_cb_t cb, void *user_data) static struct net_route_entry_mcast route_mcast_entries[CONFIG_NET_MAX_MCAST_ROUTES]; +static int mcast_route_iface_lookup(struct net_route_entry_mcast *entry, struct net_if *iface) +{ + ARRAY_FOR_EACH(entry->ifaces, i) { + if (entry->ifaces[i] == iface) { + return i; + } + } + + return -1; +} + +bool net_route_mcast_iface_add(struct net_route_entry_mcast *entry, struct net_if *iface) +{ + if (!net_if_flag_is_set(iface, NET_IF_FORWARD_MULTICASTS)) { + return false; + } + + if (mcast_route_iface_lookup(entry, iface) >= 0) { + /* Interface is already added */ + return true; + } + + ARRAY_FOR_EACH(entry->ifaces, i) { + if (entry->ifaces[i] == NULL) { + entry->ifaces[i] = iface; + + return true; + } + } + + /* There are no empty slots */ + return false; +} + +bool net_route_mcast_iface_del(struct net_route_entry_mcast *entry, + struct net_if *iface) +{ + int pos = mcast_route_iface_lookup(entry, iface); + + if (pos < 0) { + return false; + } + + entry->ifaces[pos] = NULL; + + return true; +} + +#if defined(CONFIG_NET_MCAST_ROUTE_MLD_REPORTS) +struct mcast_route_mld_event { + struct in6_addr *addr; + uint8_t mode; +}; + +static void send_mld_event(struct net_if *iface, void *user_data) +{ + struct mcast_route_mld_event *event = (struct mcast_route_mld_event *)user_data; + + /* Do not send events for ifaces without IPv6, without MLD, already or still in + * a given group + */ + if (!iface->config.ip.ipv6 || net_if_flag_is_set(iface, NET_IF_IPV6_NO_MLD) || + net_if_ipv6_maddr_lookup(event->addr, &iface)) { + return; + } + + net_ipv6_mld_send_single(iface, event->addr, event->mode); +} + +static void propagate_mld_event(struct net_route_entry_mcast *route, bool route_added) +{ + struct mcast_route_mld_event mld_event; + + /* Apply only for complete addresses */ + if (route->prefix_len == 128) { + mld_event.addr = &route->group; + mld_event.mode = route_added ? NET_IPV6_MLDv2_CHANGE_TO_EXCLUDE_MODE : + NET_IPV6_MLDv2_CHANGE_TO_INCLUDE_MODE; + + net_if_foreach(send_mld_event, &mld_event); + } +} +#else +#define propagate_mld_event(...) +#endif /* CONFIG_NET_MCAST_ROUTE_MLD_REPORTS */ + int net_route_mcast_forward_packet(struct net_pkt *pkt, const struct net_ipv6_hdr *hdr) { - int i, ret = 0, err = 0; + int ret = 0, err = 0; - for (i = 0; i < CONFIG_NET_MAX_MCAST_ROUTES; ++i) { - struct net_route_entry_mcast *route = &route_mcast_entries[i]; + ARRAY_FOR_EACH_PTR(route_mcast_entries, route) { struct net_pkt *pkt_cpy = NULL; - if (!route->is_used) { + if (!route->is_used || + !net_ipv6_is_prefix(hdr->dst, route->group.s6_addr, route->prefix_len)) { continue; } - if (!net_if_flag_is_set(route->iface, - NET_IF_FORWARD_MULTICASTS) || - !net_ipv6_is_prefix(hdr->dst, - route->group.s6_addr, - route->prefix_len) || - (pkt->iface == route->iface)) { - continue; - } + ARRAY_FOR_EACH(route->ifaces, i) { + if (!route->ifaces[i] || pkt->iface == route->ifaces[i] || + !net_if_flag_is_set(route->ifaces[i], NET_IF_FORWARD_MULTICASTS)) { + continue; + } - pkt_cpy = net_pkt_shallow_clone(pkt, K_NO_WAIT); + pkt_cpy = net_pkt_shallow_clone(pkt, K_NO_WAIT); - if (pkt_cpy == NULL) { - err--; - continue; - } + if (pkt_cpy == NULL) { + err--; + continue; + } - net_pkt_set_forwarding(pkt_cpy, true); - net_pkt_set_iface(pkt_cpy, route->iface); + net_pkt_set_forwarding(pkt_cpy, true); + net_pkt_set_orig_iface(pkt_cpy, pkt->iface); + net_pkt_set_iface(pkt_cpy, route->ifaces[i]); - if (net_send_data(pkt_cpy) >= 0) { - ++ret; - } else { - net_pkt_unref(pkt_cpy); - --err; + if (net_send_data(pkt_cpy) >= 0) { + ++ret; + } else { + net_pkt_unref(pkt_cpy); + --err; + } } } @@ -776,11 +861,9 @@ int net_route_mcast_foreach(net_route_mcast_cb_t cb, struct in6_addr *skip, void *user_data) { - int i, ret = 0; - - for (i = 0; i < CONFIG_NET_MAX_MCAST_ROUTES; i++) { - struct net_route_entry_mcast *route = &route_mcast_entries[i]; + int ret = 0; + ARRAY_FOR_EACH_PTR(route_mcast_entries, route) { if (route->is_used) { if (skip && net_ipv6_is_prefix(skip->s6_addr, route->group.s6_addr, @@ -801,8 +884,6 @@ struct net_route_entry_mcast *net_route_mcast_add(struct net_if *iface, struct in6_addr *group, uint8_t prefix_len) { - int i; - net_ipv6_nbr_lock(); if ((!net_if_flag_is_set(iface, NET_IF_FORWARD_MULTICASTS)) || @@ -813,16 +894,20 @@ struct net_route_entry_mcast *net_route_mcast_add(struct net_if *iface, return NULL; } - for (i = 0; i < CONFIG_NET_MAX_MCAST_ROUTES; i++) { - struct net_route_entry_mcast *route = &route_mcast_entries[i]; - + ARRAY_FOR_EACH_PTR(route_mcast_entries, route) { if (!route->is_used) { net_ipaddr_copy(&route->group, group); + ARRAY_FOR_EACH(route->ifaces, i) { + route->ifaces[i] = NULL; + } + route->prefix_len = prefix_len; - route->iface = iface; + route->ifaces[0] = iface; route->is_used = true; + propagate_mld_event(route, true); + net_ipv6_nbr_unlock(); return route; } @@ -843,6 +928,8 @@ bool net_route_mcast_del(struct net_route_entry_mcast *route) "Multicast route %p to %s was already removed", route, net_sprint_ipv6_addr(&route->group)); + propagate_mld_event(route, false); + route->is_used = false; return true; @@ -851,11 +938,7 @@ bool net_route_mcast_del(struct net_route_entry_mcast *route) struct net_route_entry_mcast * net_route_mcast_lookup(struct in6_addr *group) { - int i; - - for (i = 0; i < CONFIG_NET_MAX_MCAST_ROUTES; i++) { - struct net_route_entry_mcast *route = &route_mcast_entries[i]; - + ARRAY_FOR_EACH_PTR(route_mcast_entries, route) { if (!route->is_used) { continue; } @@ -1027,5 +1110,8 @@ void net_route_init(void) NET_DBG("Allocated %d nexthop entries (%zu bytes)", CONFIG_NET_MAX_NEXTHOPS, sizeof(net_route_nexthop_pool)); +#if defined(CONFIG_NET_ROUTE_MCAST) + memset(route_mcast_entries, 0, sizeof(route_mcast_entries)); +#endif k_work_init_delayable(&route_lifetime_timer, route_lifetime_timeout); } diff --git a/subsys/net/ip/route.h b/subsys/net/ip/route.h index 1f2d36ee4a8..e6dc4a1aac9 100644 --- a/subsys/net/ip/route.h +++ b/subsys/net/ip/route.h @@ -183,12 +183,13 @@ typedef void (*net_route_cb_t)(struct net_route_entry *entry, */ int net_route_foreach(net_route_cb_t cb, void *user_data); +#if defined(CONFIG_NET_ROUTE_MCAST) /** * @brief Multicast route entry. */ struct net_route_entry_mcast { - /** Network interface for the route. */ - struct net_if *iface; + /** Network interfaces for the route. */ + struct net_if *ifaces[CONFIG_NET_MCAST_ROUTE_MAX_IFACES]; /** Extra routing engine specific data */ void *data; @@ -205,6 +206,9 @@ struct net_route_entry_mcast { /** IPv6 multicast group prefix length. */ uint8_t prefix_len; }; +#else +struct net_route_entry_mcast; +#endif typedef void (*net_route_mcast_cb_t)(struct net_route_entry_mcast *entry, void *user_data); @@ -268,6 +272,27 @@ bool net_route_mcast_del(struct net_route_entry_mcast *route); struct net_route_entry_mcast * net_route_mcast_lookup(struct in6_addr *group); +/** + * @brief Add an interface to multicast routing entry. + * + * @param entry Multicast routing entry. + * @param iface Network interface to be added. + * + * @return True if the interface was added or found on the + * list, false otherwise. + */ +bool net_route_mcast_iface_add(struct net_route_entry_mcast *entry, struct net_if *iface); + +/** + * @brief Delete an interface from multicast routing entry. + * + * @param entry Multicast routing entry. + * @param iface Network interface to be deleted. + * + * @return True if entry was deleted, false otherwise. + */ +bool net_route_mcast_iface_del(struct net_route_entry_mcast *entry, struct net_if *iface); + /** * @brief Return a route to destination via some intermediate host. * diff --git a/subsys/net/ip/tcp.c b/subsys/net/ip/tcp.c index 5c36199971c..0c747449f85 100644 --- a/subsys/net/ip/tcp.c +++ b/subsys/net/ip/tcp.c @@ -14,7 +14,7 @@ LOG_MODULE_REGISTER(net_tcp, CONFIG_NET_TCP_LOG_LEVEL); #include #if defined(CONFIG_NET_TCP_ISN_RFC6528) -#include +#include #endif #include #include @@ -111,7 +111,7 @@ static int tcp_pkt_linearize(struct net_pkt *pkt, size_t pos, size_t len) buf = net_pkt_get_frag(pkt, len, TCP_PKT_ALLOC_TIMEOUT); - if (!buf || buf->size < len) { + if (!buf || net_buf_max_len(buf) < len) { if (buf) { net_buf_unref(buf); } @@ -119,7 +119,7 @@ static int tcp_pkt_linearize(struct net_pkt *pkt, size_t pos, size_t len) goto out; } - net_buf_linearize(buf->data, buf->size, pkt->frags, pos, len); + net_buf_linearize(buf->data, net_buf_max_len(buf), pkt->frags, pos, len); net_buf_add(buf, len); len1 = first->len - (pkt->cursor.pos - pkt->cursor.buf->data); @@ -239,6 +239,51 @@ static int tcp_endpoint_set(union tcp_endpoint *ep, struct net_pkt *pkt, return ret; } +int net_tcp_endpoint_copy(struct net_context *ctx, + struct sockaddr *local, + struct sockaddr *peer, + socklen_t *addrlen) +{ + const struct tcp *conn = ctx->tcp; + socklen_t newlen = ctx->local.family == AF_INET ? + sizeof(struct sockaddr_in) : + sizeof(struct sockaddr_in6); + + if (local != NULL) { + /* If we are connected, then get the address we are actually + * using, otherwise get the address we are bound as these might + * be different if we are bound to any address. + */ + if (conn->state < TCP_ESTABLISHED) { + if (IS_ENABLED(CONFIG_NET_IPV4) && ctx->local.family == AF_INET) { + memcpy(&net_sin(local)->sin_addr, + net_sin_ptr(&ctx->local)->sin_addr, + sizeof(struct in_addr)); + net_sin(local)->sin_port = net_sin_ptr(&ctx->local)->sin_port; + net_sin(local)->sin_family = AF_INET; + } else if (IS_ENABLED(CONFIG_NET_IPV4) && ctx->local.family == AF_INET6) { + memcpy(&net_sin6(local)->sin6_addr, + net_sin6_ptr(&ctx->local)->sin6_addr, + sizeof(struct in6_addr)); + net_sin6(local)->sin6_port = net_sin6_ptr(&ctx->local)->sin6_port; + net_sin6(local)->sin6_family = AF_INET6; + net_sin6(local)->sin6_scope_id = + net_sin6_ptr(&ctx->local)->sin6_scope_id; + } else { + return -EINVAL; + } + } else { + memcpy(local, &conn->src.sa, newlen); + } + } + + if (peer != NULL) { + memcpy(local, &conn->dst.sa, newlen); + } + + return 0; +} + static const char *tcp_flags(uint8_t flags) { #define BUF_SIZE 25 /* 6 * 4 + 1 */ @@ -317,10 +362,8 @@ static const char *tcp_th(struct net_pkt *pkt) #define is_6lo_technology(pkt) \ (IS_ENABLED(CONFIG_NET_IPV6) && net_pkt_family(pkt) == AF_INET6 && \ - ((IS_ENABLED(CONFIG_NET_L2_BT) && \ - net_pkt_lladdr_dst(pkt)->type == NET_LINK_BLUETOOTH) || \ - (IS_ENABLED(CONFIG_NET_L2_IEEE802154) && \ - net_pkt_lladdr_dst(pkt)->type == NET_LINK_IEEE802154))) + (IS_ENABLED(CONFIG_NET_L2_IEEE802154) && \ + net_pkt_lladdr_dst(pkt)->type == NET_LINK_IEEE802154)) static void tcp_send(struct net_pkt *pkt) { @@ -733,6 +776,16 @@ static void tcp_conn_release(struct k_work *work) conn->context->conn_handler = NULL; } + /* As the TCP socket could be closed without connect being called, + * check if the address reference is done before releasing the address. + */ + if (conn->iface != NULL && conn->addr_ref_done) { + net_if_addr_unref(conn->iface, conn->src.sa.sa_family, + conn->src.sa.sa_family == AF_INET ? + (const void *)&conn->src.sin.sin_addr : + (const void *)&conn->src.sin6.sin6_addr); + } + conn->context->tcp = NULL; conn->state = TCP_UNUSED; @@ -2062,6 +2115,7 @@ static struct tcp *tcp_conn_alloc(void) conn->send_win_max = MAX(tcp_tx_window, NET_IPV6_MTU); conn->send_win = conn->send_win_max; conn->tcp_nodelay = false; + conn->addr_ref_done = false; #ifdef CONFIG_NET_TCP_FAST_RETRANSMIT conn->dup_ack_cnt = 0; #endif @@ -2237,14 +2291,17 @@ static uint32_t tcpv6_init_isn(struct in6_addr *saddr, static bool once; if (!once) { - sys_rand_get(unique_key, sizeof(unique_key)); + sys_csrand_get(unique_key, sizeof(unique_key)); once = true; } memcpy(buf.key, unique_key, sizeof(buf.key)); #if defined(CONFIG_NET_TCP_ISN_RFC6528) - mbedtls_md5((const unsigned char *)&buf, sizeof(buf), hash); + size_t hash_len; + + psa_hash_compute(PSA_ALG_SHA_256, (const unsigned char *)&buf, sizeof(buf), + hash, sizeof(hash), &hash_len); #endif return seq_scale(UNALIGNED_GET((uint32_t *)&hash[0])); @@ -2272,14 +2329,17 @@ static uint32_t tcpv4_init_isn(struct in_addr *saddr, static bool once; if (!once) { - sys_rand_get(unique_key, sizeof(unique_key)); + sys_csrand_get(unique_key, sizeof(unique_key)); once = true; } memcpy(buf.key, unique_key, sizeof(unique_key)); #if defined(CONFIG_NET_TCP_ISN_RFC6528) - mbedtls_md5((const unsigned char *)&buf, sizeof(buf), hash); + size_t hash_len; + + psa_hash_compute(PSA_ALG_SHA_256, (const unsigned char *)&buf, sizeof(buf), + hash, sizeof(hash), &hash_len); #endif return seq_scale(UNALIGNED_GET((uint32_t *)&hash[0])); @@ -2415,6 +2475,13 @@ static struct tcp *tcp_conn_new(struct net_pkt *pkt) conn = NULL; goto err; } + + net_if_addr_ref(conn->iface, conn->dst.sa.sa_family, + conn->src.sa.sa_family == AF_INET ? + (const void *)&conn->src.sin.sin_addr : + (const void *)&conn->src.sin6.sin6_addr); + conn->addr_ref_done = true; + err: if (!conn) { net_stats_update_tcp_seg_conndrop(net_pkt_iface(pkt)); @@ -3000,30 +3067,9 @@ static enum net_verdict tcp_in(struct tcp *conn, struct net_pkt *pkt) break; case TCP_ESTABLISHED: /* full-close */ - if (th && FL(&fl, ==, (FIN | ACK), th_seq(th) == conn->ack)) { - if (net_tcp_seq_cmp(th_ack(th), conn->seq) > 0) { - uint32_t len_acked = th_ack(th) - conn->seq; - - conn_seq(conn, + len_acked); - } + if (th && FL(&fl, &, FIN, th_seq(th) == conn->ack)) { + bool acked = false; - conn_ack(conn, + 1); - tcp_out(conn, FIN | ACK); - conn_seq(conn, + 1); - next = TCP_LAST_ACK; - verdict = NET_OK; - keep_alive_timer_stop(conn); - tcp_setup_last_ack_timer(conn); - break; - } else if (th && FL(&fl, ==, FIN, th_seq(th) == conn->ack)) { - conn_ack(conn, + 1); - tcp_out(conn, ACK); - next = TCP_CLOSE_WAIT; - verdict = NET_OK; - keep_alive_timer_stop(conn); - break; - } else if (th && FL(&fl, ==, (FIN | ACK | PSH), - th_seq(th) == conn->ack)) { if (len) { verdict = tcp_data_get(conn, pkt, &len); if (verdict == NET_OK) { @@ -3035,11 +3081,28 @@ static enum net_verdict tcp_in(struct tcp *conn, struct net_pkt *pkt) } conn_ack(conn, + len + 1); - tcp_out(conn, FIN | ACK); - conn_seq(conn, + 1); - next = TCP_LAST_ACK; keep_alive_timer_stop(conn); - tcp_setup_last_ack_timer(conn); + + if (FL(&fl, &, ACK)) { + acked = true; + + if (net_tcp_seq_cmp(th_ack(th), conn->seq) > 0) { + uint32_t len_acked = th_ack(th) - conn->seq; + + conn_seq(conn, + len_acked); + } + } + + if (acked) { + tcp_out(conn, FIN | ACK); + conn_seq(conn, + 1); + tcp_setup_last_ack_timer(conn); + next = TCP_LAST_ACK; + } else { + tcp_out(conn, ACK); + next = TCP_CLOSE_WAIT; + } + break; } @@ -3839,6 +3902,12 @@ int net_tcp_connect(struct net_context *context, goto out; } + net_if_addr_ref(conn->iface, conn->src.sa.sa_family, + conn->src.sa.sa_family == AF_INET ? + (const void *)&conn->src.sin.sin_addr : + (const void *)&conn->src.sin6.sin6_addr); + conn->addr_ref_done = true; + conn->connect_cb = cb; context->user_data = user_data; diff --git a/subsys/net/ip/tcp_internal.h b/subsys/net/ip/tcp_internal.h index a9921bbe91f..309ed8cdb0d 100644 --- a/subsys/net/ip/tcp_internal.h +++ b/subsys/net/ip/tcp_internal.h @@ -448,6 +448,21 @@ static inline void net_tcp_reply_rst(struct net_pkt *pkt) } #endif +/** + * @brief Get the TCP connection endpoint information. + * + * @param context Network context + * @param local TCP connection local socket information is copied here + * @param peer TCP connection peer socket information is copied here + * @param addrlen Size of the sockaddr struct. Copied size is returned. + * + * @return <0 if there was an error, 0 if ok + */ +int net_tcp_endpoint_copy(struct net_context *ctx, + struct sockaddr *local, + struct sockaddr *peer, + socklen_t *addrlen); + #ifdef __cplusplus } #endif diff --git a/subsys/net/ip/tcp_private.h b/subsys/net/ip/tcp_private.h index 3c4462292ad..b125331eec2 100644 --- a/subsys/net/ip/tcp_private.h +++ b/subsys/net/ip/tcp_private.h @@ -336,6 +336,7 @@ struct tcp { /* TCP connection */ bool keep_alive : 1; #endif /* CONFIG_NET_TCP_KEEPALIVE */ bool tcp_nodelay : 1; + bool addr_ref_done : 1; }; #define _flags(_fl, _op, _mask, _cond) \ diff --git a/subsys/net/l2/CMakeLists.txt b/subsys/net/l2/CMakeLists.txt index 0d68a4ef791..db3160a7ef0 100644 --- a/subsys/net/l2/CMakeLists.txt +++ b/subsys/net/l2/CMakeLists.txt @@ -1,9 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -if(CONFIG_NET_L2_BT OR CONFIG_NET_L2_BT_SHELL) - add_subdirectory(bluetooth) -endif() - if(CONFIG_NET_L2_VIRTUAL) add_subdirectory(virtual) endif() diff --git a/subsys/net/l2/Kconfig b/subsys/net/l2/Kconfig index 5ac6349df12..abc17725d07 100644 --- a/subsys/net/l2/Kconfig +++ b/subsys/net/l2/Kconfig @@ -14,62 +14,6 @@ if NET_L2_DUMMY source "subsys/net/l2/dummy/Kconfig" endif -config NET_L2_BT - bool "Bluetooth support" - depends on NET_IPV6 - depends on BT - depends on BT_PERIPHERAL - depends on BT_CENTRAL - depends on BT_SMP - depends on BT_L2CAP_DYNAMIC_CHANNEL - select NET_6LO - help - Enable Bluetooth driver that send and receives IPv6 packets, - does header compression on it and writes it to the - Bluetooth stack via L2CAP channel. - -if NET_L2_BT -config NET_L2_BT_ZEP1656 - bool "***Workaround to work with Linux.***" - help - This workaround is necessary to interoperate with Linux up to 4.10 but - it might not be compliant with RFC 7668 as it cause the stack to skip - Neighbor Discovery cache causing the destination link address to be - omitted. For more details why this is needed see: - https://github.com/zephyrproject-rtos/zephyr/issues/3111 - -config NET_L2_BT_SEC_LEVEL - int "Security level of Bluetooth Link" - default 1 - range 1 4 - help - Security level of Bluetooth Link: - Level 1 (BT_SECURITY_L1) = No encryption or authentication required - Level 2 (BT_SECURITY_L2) = Only encryption required - Level 3 (BT_SECURITY_L3) = Encryption and authentication required - Level 4 (BT_SECURITY_L4) = LE Secure Connection required - -module = NET_L2_BT -module-dep = NET_LOG -module-str = Log level for Bluetooth L2 layer -module-help = Enables Bluetooth L2 to output debug messages. -source "subsys/net/Kconfig.template.log_config.net" -endif - -config NET_L2_BT_MGMT - bool "Bluetooth Network Management support" - depends on NET_L2_BT - select NET_MGMT - select NET_MGMT_EVENT - -config NET_L2_BT_SHELL - bool "Bluetooth shell module" - select SHELL - select NET_L2_BT_MGMT - help - This can be used for testing Bluetooth management commands through the - console via a shell module named "net_bt". - source "subsys/net/l2/virtual/Kconfig" source "subsys/net/l2/ethernet/Kconfig" diff --git a/subsys/net/l2/bluetooth/CMakeLists.txt b/subsys/net/l2/bluetooth/CMakeLists.txt deleted file mode 100644 index d76fd3ce003..00000000000 --- a/subsys/net/l2/bluetooth/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -zephyr_library() -zephyr_library_include_directories(${ZEPHYR_BASE}/subsys/net/ip) -zephyr_library_compile_definitions_ifdef( - CONFIG_NEWLIB_LIBC __LINUX_ERRNO_EXTENSIONS__ - ) - -zephyr_library_sources_ifdef(CONFIG_NET_L2_BT bluetooth.c) -zephyr_library_sources_ifdef(CONFIG_NET_L2_BT_SHELL bluetooth_shell.c) diff --git a/subsys/net/l2/bluetooth/bluetooth.c b/subsys/net/l2/bluetooth/bluetooth.c deleted file mode 100644 index 984b02a62de..00000000000 --- a/subsys/net/l2/bluetooth/bluetooth.c +++ /dev/null @@ -1,639 +0,0 @@ -/* - * Copyright (c) 2016 Intel Corporation. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -LOG_MODULE_REGISTER(net_bt, CONFIG_NET_L2_BT_LOG_LEVEL); - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include <6lo.h> - -#include -#include -#include -#include -#include - -#include "net_private.h" -#include "ipv6.h" - -#define BUF_TIMEOUT K_MSEC(50) - -#define L2CAP_IPSP_PSM 0x0023 -#define L2CAP_IPSP_MTU 1280 - -#define CHAN_CONN(_conn) CONTAINER_OF(_conn, struct bt_if_conn, ipsp_chan.chan) - -#if defined(CONFIG_NET_L2_BT_MGMT) -static struct bt_conn *default_conn; -#endif - -#if defined(CONFIG_NET_L2_BT_SHELL) -extern int net_bt_shell_init(void); -#else -#define net_bt_shell_init(...) -#endif - -#if defined(CONFIG_NET_BUF_FIXED_DATA_SIZE) -#define IPSP_FRAG_LEN CONFIG_NET_BUF_DATA_SIZE -#else -#define IPSP_FRAG_LEN L2CAP_IPSP_MTU -#endif /* CONFIG_NET_BUF_FIXED_DATA_SIZE */ - -struct bt_if_conn { - struct net_if *iface; - struct bt_l2cap_le_chan ipsp_chan; - bt_addr_t src; - bt_addr_t dst; -}; - -struct bt_context { - struct bt_if_conn conns[CONFIG_BT_MAX_CONN]; -}; - -static enum net_verdict net_bt_recv(struct net_if *iface, struct net_pkt *pkt) -{ - NET_DBG("iface %p pkt %p len %zu", iface, pkt, net_pkt_get_len(pkt)); - - if (!net_6lo_uncompress(pkt)) { - NET_DBG("Packet decompression failed"); - return NET_DROP; - } - - return NET_CONTINUE; -} - -static struct bt_if_conn *net_bt_get_conn(struct net_if *iface) -{ - struct bt_context *ctxt = net_if_get_device(iface)->data; - int i; - - for (i = 0; i < CONFIG_BT_MAX_CONN; i++) { - if (ctxt->conns[i].iface == iface) { - return &ctxt->conns[i]; - } - } - - return NULL; -} - -static int net_bt_send(struct net_if *iface, struct net_pkt *pkt) -{ - struct bt_if_conn *conn = net_bt_get_conn(iface); - struct net_buf *buffer; - int length; - int ret; - - NET_DBG("iface %p pkt %p len %zu", iface, pkt, net_pkt_get_len(pkt)); - - /* Only accept IPv6 packets */ - if (net_pkt_family(pkt) != AF_INET6) { - return -EINVAL; - } - - ret = net_6lo_compress(pkt, true); - if (ret < 0) { - NET_DBG("Packet compression failed"); - return ret; - } - - length = net_pkt_get_len(pkt); - - net_capture_pkt(iface, pkt); - - /* Detach data fragments for packet */ - buffer = pkt->buffer; - pkt->buffer = NULL; - - ret = bt_l2cap_chan_send(&conn->ipsp_chan.chan, buffer); - if (ret < 0) { - NET_ERR("Unable to send packet: %d", ret); - bt_l2cap_chan_disconnect(&conn->ipsp_chan.chan); - net_buf_unref(buffer); - return ret; - } - - net_pkt_unref(pkt); - - return length; -} - -static int net_bt_enable(struct net_if *iface, bool state) -{ - NET_DBG("iface %p %s", iface, state ? "up" : "down"); - - return 0; -} - -static enum net_l2_flags net_bt_flags(struct net_if *iface) -{ - /* TODO: add NET_L2_MULTICAST_SKIP_JOIN_SOLICIT_NODE once the stack - * supports Address Registration Option for neighbor discovery. - */ - return NET_L2_MULTICAST; -} - -NET_L2_INIT(BLUETOOTH_L2, net_bt_recv, net_bt_send, - net_bt_enable, net_bt_flags); - -static void ipsp_connected(struct bt_l2cap_chan *chan) -{ - struct bt_if_conn *conn = CHAN_CONN(chan); - struct bt_conn_info info; - struct net_linkaddr ll; - struct in6_addr in6; - - if (bt_conn_get_info(chan->conn, &info) < 0) { - NET_ERR("Unable to get connection info"); - bt_l2cap_chan_disconnect(chan); - return; - } - - if (CONFIG_NET_L2_BT_LOG_LEVEL >= LOG_LEVEL_DBG) { - char src[BT_ADDR_LE_STR_LEN]; - char dst[BT_ADDR_LE_STR_LEN]; - - bt_addr_le_to_str(info.le.src, src, sizeof(src)); - bt_addr_le_to_str(info.le.dst, dst, sizeof(dst)); - - NET_DBG("Channel %p Source %s connected to Destination %s", - chan, src, dst); - } - - /* Swap bytes since net APIs expect big endian address */ - sys_memcpy_swap(conn->src.val, info.le.src->a.val, sizeof(conn->src)); - sys_memcpy_swap(conn->dst.val, info.le.dst->a.val, sizeof(conn->dst)); - - net_if_set_link_addr(conn->iface, conn->src.val, sizeof(conn->src.val), - NET_LINK_BLUETOOTH); - - ll.addr = conn->dst.val; - ll.len = sizeof(conn->dst.val); - ll.type = NET_LINK_BLUETOOTH; - - /* Add remote link-local address to the nbr cache to avoid sending ns: - * https://tools.ietf.org/html/rfc7668#section-3.2.3 - * A Bluetooth LE 6LN MUST NOT register its link-local address. - */ - net_ipv6_addr_create_iid(&in6, &ll); - net_ipv6_nbr_add(conn->iface, &in6, &ll, false, - NET_IPV6_NBR_STATE_STATIC); - - /* Leave dormant state (iface goes up if set to admin up) */ - net_if_dormant_off(conn->iface); -} - -static void ipsp_disconnected(struct bt_l2cap_chan *chan) -{ - struct bt_if_conn *conn = CHAN_CONN(chan); - - NET_DBG("Channel %p disconnected", chan); - - /* Enter dormant state (iface goes down) */ - net_if_dormant_on(conn->iface); - -#if defined(CONFIG_NET_L2_BT_MGMT) - if (chan->conn != default_conn) { - return; - } - - bt_conn_unref(default_conn); - default_conn = NULL; -#endif -} - -static int ipsp_recv(struct bt_l2cap_chan *chan, struct net_buf *buf) -{ - struct bt_if_conn *conn = CHAN_CONN(chan); - struct net_pkt *pkt; - - NET_DBG("Incoming data channel %p len %zu", chan, - net_buf_frags_len(buf)); - - /* Get packet for bearer / protocol related data */ - pkt = net_pkt_rx_alloc_on_iface(conn->iface, BUF_TIMEOUT); - if (!pkt) { - return -ENOMEM; - } - - /* Set destination address */ - net_pkt_lladdr_dst(pkt)->addr = conn->src.val; - net_pkt_lladdr_dst(pkt)->len = sizeof(conn->src); - net_pkt_lladdr_dst(pkt)->type = NET_LINK_BLUETOOTH; - - /* Set source address */ - net_pkt_lladdr_src(pkt)->addr = conn->dst.val; - net_pkt_lladdr_src(pkt)->len = sizeof(conn->dst); - net_pkt_lladdr_src(pkt)->type = NET_LINK_BLUETOOTH; - - /* Add data buffer as fragment of RX buffer, take a reference while - * doing so since L2CAP will unref the buffer after return. - */ - net_pkt_append_buffer(pkt, net_buf_ref(buf)); - - if (net_recv_data(conn->iface, pkt) < 0) { - NET_DBG("Packet dropped by NET stack"); - net_pkt_unref(pkt); - } - - return 0; -} - -static struct net_buf *ipsp_alloc_buf(struct bt_l2cap_chan *chan) -{ - NET_DBG("Channel %p requires buffer", chan); - - return net_pkt_get_reserve_rx_data(IPSP_FRAG_LEN, BUF_TIMEOUT); -} - -static const struct bt_l2cap_chan_ops ipsp_ops = { - .alloc_buf = ipsp_alloc_buf, - .recv = ipsp_recv, - .connected = ipsp_connected, - .disconnected = ipsp_disconnected, -}; - -static struct bt_context bt_context_data = { - .conns[0 ... (CONFIG_BT_MAX_CONN - 1)] = { - .iface = NULL, - .ipsp_chan.chan.ops = &ipsp_ops, - .ipsp_chan.rx.mtu = L2CAP_IPSP_MTU, - } -}; - -static void bt_iface_init(struct net_if *iface) -{ - struct bt_context *ctxt = net_if_get_device(iface)->data; - struct bt_if_conn *conn = NULL; - int i; - - NET_DBG("iface %p", iface); - - /* Find unused slot to store the iface */ - for (i = 0; i < CONFIG_BT_MAX_CONN; i++) { - if (!ctxt->conns[i].iface) { - conn = &ctxt->conns[i]; - NET_DBG("[%d] alloc ctxt %p iface %p", i, ctxt, iface); - break; - } - } - - if (!conn) { - NET_ERR("Unable to allocate iface"); - return; - } - - conn->iface = iface; - - net_if_dormant_on(iface); - -#if defined(CONFIG_NET_L2_BT_ZEP1656) - /* Workaround Linux bug, see: - * https://github.com/zephyrproject-rtos/zephyr/issues/3111 - */ - net_if_flag_set(iface, NET_IF_POINTOPOINT); -#endif -} - -static struct net_if_api bt_if_api = { - .init = bt_iface_init, -}; - -static int ipsp_accept(struct bt_conn *conn, struct bt_l2cap_server *server, - struct bt_l2cap_chan **chan) -{ - struct bt_if_conn *if_conn = NULL; - int i; - - NET_DBG("Incoming conn %p", (void *)conn); - - /* Find unused slot to store the iface */ - for (i = 0; i < CONFIG_BT_MAX_CONN; i++) { - if (bt_context_data.conns[i].iface && - !bt_context_data.conns[i].ipsp_chan.chan.conn) { - if_conn = &bt_context_data.conns[i]; - break; - } - } - - if (!if_conn) { - NET_ERR("No channels available"); - return -ENOMEM; - } - - *chan = &if_conn->ipsp_chan.chan; - - return 0; -} - -static struct bt_l2cap_server server = { - .psm = L2CAP_IPSP_PSM, - .sec_level = CONFIG_NET_L2_BT_SEC_LEVEL, - .accept = ipsp_accept, -}; - -#if defined(CONFIG_NET_L2_BT_MGMT) - -#define DEVICE_NAME CONFIG_BT_DEVICE_NAME -#define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1) -#define UNKNOWN_APPEARANCE 0x0000 - -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, BT_UUID_16_ENCODE(BT_UUID_IPSS_VAL)), -}; - -static const struct bt_data sd[] = { - BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN), -}; - -static int bt_advertise(uint32_t mgmt_request, struct net_if *iface, void *data, - size_t len) -{ - if (!strcmp(data, "on")) { - return bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), - sd, ARRAY_SIZE(sd)); - } else if (!strcmp(data, "off")) { - return bt_le_adv_stop(); - } else { - return -EINVAL; - } - - return 0; -} - -static int bt_connect(uint32_t mgmt_request, struct net_if *iface, void *data, - size_t len) -{ - struct bt_if_conn *conn = net_bt_get_conn(iface); - bt_addr_le_t *addr = data; - - if (len != sizeof(*addr)) { - NET_ERR("Invalid address"); - return -EINVAL; - } - - if (conn->ipsp_chan.chan.conn) { - NET_ERR("No channels available"); - return -ENOMEM; - } - - if (default_conn) { - return bt_l2cap_chan_connect(default_conn, - &conn->ipsp_chan.chan, - L2CAP_IPSP_PSM); - } - - return bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, - BT_LE_CONN_PARAM_DEFAULT, &default_conn); -} - -static bool eir_found(uint8_t type, const uint8_t *data, uint8_t data_len, - void *user_data) -{ - int i; - - if (type != BT_DATA_UUID16_SOME && type != BT_DATA_UUID16_ALL) { - return false; - } - - if (data_len % sizeof(uint16_t) != 0U) { - NET_ERR("AD malformed\n"); - return false; - } - - for (i = 0; i < data_len; i += sizeof(uint16_t)) { - const struct bt_uuid *uuid; - uint16_t u16; - - memcpy(&u16, &data[i], sizeof(u16)); - uuid = BT_UUID_DECLARE_16(sys_le16_to_cpu(u16)); - if (bt_uuid_cmp(uuid, BT_UUID_IPSS)) { - continue; - } - - if (CONFIG_NET_L2_BT_LOG_LEVEL >= LOG_LEVEL_DBG) { - bt_addr_le_t *addr = user_data; - char dev[BT_ADDR_LE_STR_LEN]; - - bt_addr_le_to_str(addr, dev, sizeof(dev)); - NET_DBG("[DEVICE]: %s", dev); - } - - /* TODO: Notify device address found */ - net_mgmt_event_notify(NET_EVENT_BT_SCAN_RESULT, - bt_context_data.conns[0].iface); - - return true; - } - - return false; -} - -static bool ad_parse(struct net_buf_simple *ad_buf, - bool (*func)(uint8_t type, const uint8_t *data, - uint8_t data_len, void *user_data), - void *user_data) -{ - while (ad_buf->len > 1) { - uint8_t len = net_buf_simple_pull_u8(ad_buf); - uint8_t type; - - /* Check for early termination */ - if (len == 0U) { - return false; - } - - if (len > ad_buf->len) { - NET_ERR("AD malformed\n"); - return false; - } - - type = net_buf_simple_pull_u8(ad_buf); - - if (func(type, ad_buf->data, len - 1, user_data)) { - return true; - } - - net_buf_simple_pull(ad_buf, len - 1); - } - - return false; -} - -static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type, - struct net_buf_simple *ad_buf) -{ - /* We're only interested in connectable events */ - if (type == BT_GAP_ADV_TYPE_ADV_IND || - type == BT_GAP_ADV_TYPE_ADV_DIRECT_IND) { - ad_parse(ad_buf, eir_found, (void *)addr); - } -} - -static void bt_active_scan(void) -{ - int err; - - err = bt_le_scan_start(BT_LE_SCAN_ACTIVE, device_found); - if (err) { - NET_ERR("Bluetooth set active scan failed (err %d)\n", err); - } -} - -static void bt_passive_scan(void) -{ - int err; - - err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, device_found); - if (err) { - NET_ERR("Bluetooth set passive scan failed (err %d)\n", err); - } -} - -static void bt_scan_off(void) -{ - int err; - - err = bt_le_scan_stop(); - if (err) { - NET_ERR("Stopping scanning failed (err %d)\n", err); - } -} - -static int bt_scan(uint32_t mgmt_request, struct net_if *iface, void *data, - size_t len) -{ - if (!strcmp(data, "on") || !strcmp(data, "active")) { - bt_active_scan(); - } else if (!strcmp(data, "passive")) { - bt_passive_scan(); - } else if (!strcmp("off", data)) { - bt_scan_off(); - } else { - return -EINVAL; - } - - return 0; -} - -static int bt_disconnect(uint32_t mgmt_request, struct net_if *iface, - void *data, size_t len) -{ - struct bt_if_conn *conn = net_bt_get_conn(iface); - - if (!conn->ipsp_chan.chan.conn) { - NET_ERR("Not connected"); - return -ENOTCONN; - } - - /* Release connect reference in case of central/router role */ - if (default_conn) { - bt_conn_unref(default_conn); - default_conn = NULL; - } - - return bt_l2cap_chan_disconnect(&conn->ipsp_chan.chan); -} - -static void connected(struct bt_conn *conn, uint8_t err) -{ - int i; - - if (err) { - if (CONFIG_NET_L2_BT_LOG_LEVEL >= LOG_LEVEL_DBG) { - char addr[BT_ADDR_LE_STR_LEN]; - - bt_addr_le_to_str(bt_conn_get_dst(conn), addr, - sizeof(addr)); - - NET_ERR("Failed to connect to %s (%u)\n", - addr, err); - } - - return; - } - - if (conn != default_conn) { - return; - } - - for (i = 0; i < CONFIG_BT_MAX_CONN; i++) { - struct bt_if_conn *if_conn = &bt_context_data.conns[i]; - - if (if_conn->ipsp_chan.chan.conn == conn) { - bt_l2cap_chan_connect(conn, &if_conn->ipsp_chan.chan, - L2CAP_IPSP_PSM); - break; - } - } -} - -static void disconnected(struct bt_conn *conn, uint8_t reason) -{ - if (conn != default_conn) { - return; - } - - if (CONFIG_NET_L2_BT_LOG_LEVEL >= LOG_LEVEL_DBG) { - char addr[BT_ADDR_LE_STR_LEN]; - - bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); - - NET_DBG("Disconnected: %s (reason 0x%02x)\n", - addr, reason); - } - - bt_conn_unref(default_conn); - default_conn = NULL; -} - -BT_CONN_CB_DEFINE(conn_callbacks) = { - .connected = connected, - .disconnected = disconnected, -}; -#endif /* CONFIG_NET_L2_BT_MGMT */ - -static int net_bt_init(const struct device *dev) -{ - int err; - - NET_DBG("dev %p driver_data %p", dev, dev->data); - - err = bt_l2cap_server_register(&server); - if (err) { - return err; - } - - net_bt_shell_init(); - - return 0; -} - -#if defined(CONFIG_NET_L2_BT_MGMT) -NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_BT_ADVERTISE, bt_advertise); -NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_BT_CONNECT, bt_connect); -NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_BT_SCAN, bt_scan); -NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_BT_DISCONNECT, bt_disconnect); -#endif - -DEVICE_DEFINE(net_bt, "net_bt", net_bt_init, NULL, &bt_context_data, NULL, - POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &bt_if_api); -NET_L2_DATA_INIT(net_bt, 0, NET_L2_GET_CTX_TYPE(BLUETOOTH_L2)); -NET_IF_INIT(net_bt, 0, BLUETOOTH_L2, L2CAP_IPSP_MTU, CONFIG_BT_MAX_CONN); diff --git a/subsys/net/l2/bluetooth/bluetooth_shell.c b/subsys/net/l2/bluetooth/bluetooth_shell.c deleted file mode 100644 index f5f07edd88e..00000000000 --- a/subsys/net/l2/bluetooth/bluetooth_shell.c +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (c) 2017 Intel Corporation. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -LOG_MODULE_REGISTER(net_bt_shell, CONFIG_NET_L2_BT_LOG_LEVEL); - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -#include -#include - -static int shell_cmd_connect(const struct shell *sh, - size_t argc, char *argv[]) -{ - int err; - bt_addr_le_t addr; - struct net_if *iface = net_if_get_default(); - - if (argc < 3) { - shell_help(sh); - return -ENOEXEC; - } - - err = bt_addr_le_from_str(argv[1], argv[2], &addr); - if (err) { - shell_fprintf(sh, SHELL_WARNING, - "Invalid peer address (err %d)\n", err); - return 0; - } - - if (net_mgmt(NET_REQUEST_BT_CONNECT, iface, &addr, sizeof(addr))) { - shell_fprintf(sh, SHELL_WARNING, - "Connection failed\n"); - } else { - shell_fprintf(sh, SHELL_NORMAL, - "Connection pending\n"); - } - - return 0; -} - -static int shell_cmd_scan(const struct shell *sh, - size_t argc, char *argv[]) -{ - struct net_if *iface = net_if_get_default(); - - if (argc < 2) { - shell_help(sh); - return -ENOEXEC; - } - - if (net_mgmt(NET_REQUEST_BT_SCAN, iface, argv[1], strlen(argv[1]))) { - shell_fprintf(sh, SHELL_WARNING, - "Scan failed\n"); - } else { - shell_fprintf(sh, SHELL_NORMAL, - "Scan in progress\n"); - } - - return 0; -} - -static int shell_cmd_disconnect(const struct shell *sh, - size_t argc, char *argv[]) -{ - struct net_if *iface = net_if_get_default(); - - if (net_mgmt(NET_REQUEST_BT_DISCONNECT, iface, NULL, 0)) { - shell_fprintf(sh, SHELL_WARNING, - "Disconnect failed\n"); - } else { - shell_fprintf(sh, SHELL_NORMAL, - "Disconnected\n"); - } - - return 0; -} - -static int shell_cmd_advertise(const struct shell *sh, - size_t argc, char *argv[]) -{ - struct net_if *iface = net_if_get_default(); - - if (argc < 2) { - shell_help(sh); - return -ENOEXEC; - } - - if (net_mgmt(NET_REQUEST_BT_ADVERTISE, iface, argv[1], - strlen(argv[1]))) { - shell_fprintf(sh, SHELL_WARNING, - "Advertise failed\n"); - } else { - shell_fprintf(sh, SHELL_NORMAL, - "Advertise in progress\n"); - } - - return 0; -} - -SHELL_STATIC_SUBCMD_SET_CREATE(bt_commands, - SHELL_CMD(advertise, NULL, - "on/off", - shell_cmd_advertise), - SHELL_CMD(connect, NULL, - " ", - shell_cmd_connect), - SHELL_CMD(scan, NULL, - "", - shell_cmd_scan), - SHELL_CMD(disconnect, NULL, - "", - shell_cmd_disconnect), - SHELL_SUBCMD_SET_END -); - -SHELL_CMD_REGISTER(net_bt, &bt_commands, "Net Bluetooth commands", NULL); - -void net_bt_shell_init(void) -{ -} diff --git a/subsys/net/l2/ethernet/gptp/gptp_md.c b/subsys/net/l2/ethernet/gptp/gptp_md.c index fd0c62182a4..1c4cf53f899 100644 --- a/subsys/net/l2/ethernet/gptp/gptp_md.c +++ b/subsys/net/l2/ethernet/gptp/gptp_md.c @@ -29,11 +29,14 @@ static void gptp_md_sync_prepare(struct net_pkt *pkt, } static void gptp_md_follow_up_prepare(struct net_pkt *pkt, + struct net_pkt *sync, struct gptp_md_sync_info *sync_send, int port_number) { struct gptp_hdr *hdr; struct gptp_follow_up *fup; + uint64_t sync_ts_ns, delay_ns; + struct net_ptp_time *sync_ts = net_pkt_timestamp(sync); hdr = GPTP_HDR(pkt); fup = GPTP_FOLLOW_UP(pkt); @@ -45,6 +48,48 @@ static void gptp_md_follow_up_prepare(struct net_pkt *pkt, hdr->log_msg_interval = sync_send->log_msg_interval; + if (memcmp(GPTP_GLOBAL_DS()->gm_priority.root_system_id.grand_master_id, + GPTP_DEFAULT_DS()->clk_id, GPTP_CLOCK_ID_LEN) == 0 && + GPTP_GLOBAL_DS()->gm_present) { + /* + * Time aware system acting as the Grand Master. + * + * Get preciseOriginTimestamp from previous sync message + * according to IEEE802.1AS 11.4.4.2.1 syncEventEgressTimestamp + */ + fup->prec_orig_ts_secs_high = htons(sync_ts->_sec.high); + fup->prec_orig_ts_secs_low = htonl(sync_ts->_sec.low); + fup->prec_orig_ts_nsecs = htonl(sync_ts->nanosecond); + /* + * Grand master clock should keep correction_field at zero, + * according to IEEE802.1AS Table 11-6 and 10.6.2.2.9 + */ + hdr->correction_field = 0LL; + } else { + /* + * Time aware system acting as a bridge. + */ + fup->prec_orig_ts_secs_high = + htons(sync_send->precise_orig_ts._sec.high); + fup->prec_orig_ts_secs_low = htonl(sync_send->precise_orig_ts._sec.low); + fup->prec_orig_ts_nsecs = htonl(sync_send->precise_orig_ts.nanosecond); + /* + * According to IEEE802.AS 11.1.3 and 11.2.14.2.3, when time aware + * system is operating as a transparent clock also called a bridge, it + * shall compute the sum of link propagation delay and residence time, + * expressed in grand master time base. Then this quantity shall be + * added to last received fup correction field to build value of + * correction field. + */ + sync_ts_ns = sync_ts->second; + sync_ts_ns *= NSEC_PER_SEC; + sync_ts_ns += sync_ts->nanosecond; + delay_ns = sync_ts_ns - sync_send->upstream_tx_time; + + hdr->correction_field = sync_send->follow_up_correction_field + + (int64_t)(sync_send->rate_ratio * delay_ns); + hdr->correction_field = htonll(hdr->correction_field << 16); + } fup->tlv_hdr.type = htons(GPTP_TLV_ORGANIZATION_EXT); fup->tlv_hdr.len = htons(sizeof(struct gptp_follow_up_tlv)); fup->tlv.org_id[0] = GPTP_FUP_TLV_ORG_ID_BYTE_0; @@ -852,6 +897,7 @@ static void gptp_md_sync_send_state_machine(int port) pkt = gptp_prepare_follow_up(port, state->sync_ptr); if (pkt) { gptp_md_follow_up_prepare(pkt, + state->sync_ptr, state->sync_send_ptr, port); gptp_send_follow_up(port, pkt); diff --git a/subsys/net/l2/ethernet/gptp/gptp_messages.c b/subsys/net/l2/ethernet/gptp/gptp_messages.c index d56b679ab7a..7fe558d8a2c 100644 --- a/subsys/net/l2/ethernet/gptp/gptp_messages.c +++ b/subsys/net/l2/ethernet/gptp/gptp_messages.c @@ -16,10 +16,10 @@ LOG_MODULE_DECLARE(net_gptp, CONFIG_NET_GPTP_LOG_LEVEL); #define NET_BUF_TIMEOUT K_MSEC(100) -static struct net_if_timestamp_cb sync_timestamp_cb; -static struct net_if_timestamp_cb pdelay_response_timestamp_cb; -static bool sync_cb_registered; -static bool ts_cb_registered; +static struct net_if_timestamp_cb sync_timestamp_cb[CONFIG_NET_GPTP_NUM_PORTS]; +static struct net_if_timestamp_cb pdelay_response_timestamp_cb[CONFIG_NET_GPTP_NUM_PORTS]; +static bool sync_cb_registered[CONFIG_NET_GPTP_NUM_PORTS]; +static bool ts_cb_registered[CONFIG_NET_GPTP_NUM_PORTS]; static const struct net_eth_addr gptp_multicast_eth_addr = { { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e } }; @@ -98,8 +98,8 @@ static void gptp_sync_timestamp_callback(struct net_pkt *pkt) if (hdr->message_type == GPTP_SYNC_MESSAGE) { state->md_sync_timestamp_avail = true; - net_if_unregister_timestamp_cb(&sync_timestamp_cb); - sync_cb_registered = false; + net_if_unregister_timestamp_cb(&sync_timestamp_cb[port - 1]); + sync_cb_registered[port - 1] = false; /* The pkt was ref'ed in gptp_send_sync() */ net_pkt_unref(pkt); @@ -129,8 +129,8 @@ static void gptp_pdelay_response_timestamp_callback(struct net_pkt *pkt) goto out; } - net_if_unregister_timestamp_cb(&pdelay_response_timestamp_cb); - ts_cb_registered = false; + net_if_unregister_timestamp_cb(&pdelay_response_timestamp_cb[port - 1]); + ts_cb_registered[port - 1] = false; gptp_send_pdelay_follow_up(port, follow_up, net_pkt_timestamp(pkt)); @@ -241,7 +241,6 @@ struct net_pkt *gptp_prepare_follow_up(int port, struct net_pkt *sync) struct gptp_follow_up *fup; struct net_if *iface; struct net_pkt *pkt; - struct net_ptp_time *sync_ts; NET_ASSERT(sync); NET_ASSERT((port >= GPTP_PORT_START) && (port <= GPTP_PORT_END)); @@ -259,7 +258,6 @@ struct net_pkt *gptp_prepare_follow_up(int port, struct net_pkt *sync) hdr = GPTP_HDR(pkt); fup = GPTP_FOLLOW_UP(pkt); sync_hdr = GPTP_HDR(sync); - sync_ts = net_pkt_timestamp(sync); /* * Header configuration. @@ -271,11 +269,6 @@ struct net_pkt *gptp_prepare_follow_up(int port, struct net_pkt *sync) hdr->ptp_version = GPTP_VERSION; hdr->sequence_id = sync_hdr->sequence_id; hdr->domain_number = 0U; - /* - * Grand master clock should keep correction_field at zero, - * according to IEEE802.1AS Table 11-6 and 10.6.2.2.9 - */ - hdr->correction_field = 0LL; hdr->flags.octets[0] = 0U; hdr->flags.octets[1] = GPTP_FLAG_PTP_TIMESCALE; hdr->message_length = htons(sizeof(struct gptp_hdr) + @@ -287,14 +280,6 @@ struct net_pkt *gptp_prepare_follow_up(int port, struct net_pkt *sync) hdr->reserved1 = 0U; hdr->reserved2 = 0U; - /* - * Get preciseOriginTimestamp from previous sync message - * according to IEEE802.1AS 11.4.4.2.1 syncEventEgressTimestamp - */ - fup->prec_orig_ts_secs_high = htons(sync_ts->_sec.high); - fup->prec_orig_ts_secs_low = htonl(sync_ts->_sec.low); - fup->prec_orig_ts_nsecs = htonl(sync_ts->nanosecond); - /* PTP configuration will be set by the MDSyncSend state machine. */ return pkt; @@ -639,13 +624,13 @@ void gptp_handle_pdelay_req(int port, struct net_pkt *pkt) GPTP_STATS_INC(port, rx_pdelay_req_count); - if (ts_cb_registered == true) { + if (ts_cb_registered[port - 1] == true) { NET_WARN("Multiple pdelay requests"); - net_if_unregister_timestamp_cb(&pdelay_response_timestamp_cb); - net_pkt_unref(pdelay_response_timestamp_cb.pkt); + net_if_unregister_timestamp_cb(&pdelay_response_timestamp_cb[port - 1]); + net_pkt_unref(pdelay_response_timestamp_cb[port - 1].pkt); - ts_cb_registered = false; + ts_cb_registered[port - 1] = false; } /* Prepare response and send */ @@ -654,7 +639,7 @@ void gptp_handle_pdelay_req(int port, struct net_pkt *pkt) return; } - net_if_register_timestamp_cb(&pdelay_response_timestamp_cb, + net_if_register_timestamp_cb(&pdelay_response_timestamp_cb[port - 1], reply, net_pkt_iface(pkt), gptp_pdelay_response_timestamp_callback); @@ -665,7 +650,7 @@ void gptp_handle_pdelay_req(int port, struct net_pkt *pkt) */ net_pkt_ref(reply); - ts_cb_registered = true; + ts_cb_registered[port - 1] = true; gptp_send_pdelay_resp(port, reply, net_pkt_timestamp(pkt)); } @@ -821,12 +806,12 @@ void gptp_handle_signaling(int port, struct net_pkt *pkt) void gptp_send_sync(int port, struct net_pkt *pkt) { - if (!sync_cb_registered) { - net_if_register_timestamp_cb(&sync_timestamp_cb, + if (!sync_cb_registered[port - 1]) { + net_if_register_timestamp_cb(&sync_timestamp_cb[port - 1], pkt, net_pkt_iface(pkt), gptp_sync_timestamp_callback); - sync_cb_registered = true; + sync_cb_registered[port - 1] = true; } GPTP_STATS_INC(port, tx_sync_count); diff --git a/subsys/net/l2/ethernet/gptp/gptp_mi.c b/subsys/net/l2/ethernet/gptp/gptp_mi.c index 2e460ce0303..bb5a36cf16b 100644 --- a/subsys/net/l2/ethernet/gptp/gptp_mi.c +++ b/subsys/net/l2/ethernet/gptp/gptp_mi.c @@ -960,12 +960,17 @@ static void gptp_mi_set_ps_sync_cmss(void) sync_info->precise_orig_ts.second = current_time / NSEC_PER_SEC; sync_info->precise_orig_ts.nanosecond = current_time % NSEC_PER_SEC; - /* TODO calculate correction field properly, rate_ratio is also set to - * zero instead of being copied from global_ds as it affects the final - * value of FUP correction field. + /* TODO calculate rate ratio and correction field properly. + * Whenever time aware system is the grand master clock, we currently + * make the following shortcuts: + * - assuming that clock source is the local clock, + * rate_ratio is set to 1.0 instead of being copied from global_ds. + * - considering that precise origin timestamp is directly inherited + * from sync egress timestamp in gptp_md_follow_up_prepare(), + * follow_up_correction_field is set to 0. */ sync_info->follow_up_correction_field = 0; - sync_info->rate_ratio = 0; + sync_info->rate_ratio = 1.0; memcpy(&sync_info->src_port_id.clk_id, GPTP_DEFAULT_DS()->clk_id, @@ -2014,7 +2019,22 @@ void gptp_mi_state_machines(void) gptp_mi_port_role_selection_state_machine(); gptp_mi_clk_master_sync_offset_state_machine(); #if defined(CONFIG_NET_GPTP_GM_CAPABLE) - gptp_mi_clk_master_sync_snd_state_machine(); + /* + * Only call ClockMasterSyncSend state machine in case a Grand Master clock + * is present and is this time aware system. + * This check is not described by IEEE802.1AS. Instead, according to + * 10.2.9.3, the SiteSyncSync state machine shall not take into account + * information from ClockMasterSyncSend in case this time aware system is + * not grand-master capable. Current implementation of ClockMasterSyncSend + * state machine send sync indication to the PortSync entities, instead of + * sending it to the SiteSyncSync entity. And the SiteSyncSync state machine + * does not make sanity check. + */ + if (memcmp(GPTP_GLOBAL_DS()->gm_priority.root_system_id.grand_master_id, + GPTP_DEFAULT_DS()->clk_id, GPTP_CLOCK_ID_LEN) == 0 && + GPTP_GLOBAL_DS()->gm_present) { + gptp_mi_clk_master_sync_snd_state_machine(); + } #endif gptp_mi_clk_master_sync_rcv_state_machine(); } diff --git a/subsys/net/l2/openthread/Kconfig b/subsys/net/l2/openthread/Kconfig index 9673aa7702a..c75af2c5c25 100644 --- a/subsys/net/l2/openthread/Kconfig +++ b/subsys/net/l2/openthread/Kconfig @@ -322,7 +322,7 @@ config OPENTHREAD_MAC_SOFTWARE_CSMA_BACKOFF_ENABLE config OPENTHREAD_CRYPTO_PSA bool "ARM PSA crypto API" - depends on MBEDTLS_PSA_CRYPTO_C || BUILD_WITH_TFM + depends on MBEDTLS_PSA_CRYPTO_CLIENT select OPENTHREAD_PLATFORM_KEY_REF if !OPENTHREAD_COPROCESSOR_RCP imply OPENTHREAD_PLATFORM_KEYS_EXPORTABLE_ENABLE help diff --git a/subsys/net/l2/ppp/ppp_l2.c b/subsys/net/l2/ppp/ppp_l2.c index efbd7b81008..bfe28738f79 100644 --- a/subsys/net/l2/ppp/ppp_l2.c +++ b/subsys/net/l2/ppp/ppp_l2.c @@ -231,7 +231,9 @@ static int ppp_lcp_close(struct ppp_context *ctx) k_sem_reset(&ctx->wait_ppp_link_terminated); ppp_lcp->close(ctx, "L2 Disabled"); - return k_sem_take(&ctx->wait_ppp_link_terminated, K_MSEC(CONFIG_NET_L2_PPP_TIMEOUT)); + return k_sem_take(&ctx->wait_ppp_link_terminated, + K_MSEC(CONFIG_NET_L2_PPP_TIMEOUT * + (1 + CONFIG_NET_L2_PPP_MAX_TERMINATE_REQ_RETRANSMITS))); } static void ppp_lcp_lower_down_async(struct ppp_context *ctx) diff --git a/subsys/net/l2/wifi/CMakeLists.txt b/subsys/net/l2/wifi/CMakeLists.txt index aaf825599f0..c834c5bfc2f 100644 --- a/subsys/net/l2/wifi/CMakeLists.txt +++ b/subsys/net/l2/wifi/CMakeLists.txt @@ -17,5 +17,5 @@ zephyr_library_sources_ifdef(CONFIG_NET_L2_WIFI_UTILS wifi_utils.c) # Linker section placement for wifi_nm_instance iterable structure zephyr_linker_sources_ifdef(CONFIG_WIFI_NM DATA_SECTIONS wifi_nm.ld) if (CONFIG_WIFI_NM) -zephyr_iterable_section(NAME wifi_nm_instance GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) +zephyr_iterable_section(NAME wifi_nm_instance GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) endif() diff --git a/subsys/net/l2/wifi/wifi_nm.ld b/subsys/net/l2/wifi/wifi_nm.ld index 73bc53f881a..2b23e88443e 100644 --- a/subsys/net/l2/wifi/wifi_nm.ld +++ b/subsys/net/l2/wifi/wifi_nm.ld @@ -4,4 +4,4 @@ * SPDX-License-Identifier: Apache-2.0 */ -ITERABLE_SECTION_RAM(wifi_nm_instance, 4) +ITERABLE_SECTION_RAM(wifi_nm_instance, Z_LINK_ITERABLE_SUBALIGN) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 954b6aecc07..ab2637a1271 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -457,6 +457,7 @@ static int __wifi_args_to_params(const struct shell *sh, size_t argc, char *argv {"bssid", required_argument, 0, 'm'}, {"band", required_argument, 0, 'b'}, {"channel", required_argument, 0, 'c'}, + {"timeout", required_argument, 0, 't'}, {"help", no_argument, 0, 'h'}, {0, 0, 0, 0}}; int opt_index = 0; @@ -477,7 +478,8 @@ static int __wifi_args_to_params(const struct shell *sh, size_t argc, char *argv params->security = WIFI_SECURITY_TYPE_NONE; params->mfp = WIFI_MFP_OPTIONAL; - while ((opt = getopt_long(argc, argv, "s:p:k:w:b:c:m:h", long_options, &opt_index)) != -1) { + while ((opt = getopt_long(argc, argv, "s:p:k:w:b:c:m:t:h", + long_options, &opt_index)) != -1) { state = getopt_state_get(); switch (opt) { case 's': @@ -563,6 +565,15 @@ static int __wifi_args_to_params(const struct shell *sh, size_t argc, char *argv ¶ms->bssid[2], ¶ms->bssid[3], ¶ms->bssid[4], ¶ms->bssid[5]); break; + case 't': + if (iface_mode == WIFI_MODE_INFRA) { + params->timeout = strtol(optarg, &endptr, 10); + if (*endptr != '\0') { + PR_ERROR("Invalid timeout: %s\n", optarg); + return -EINVAL; + } + } + break; case 'h': return -ENOEXEC; default: @@ -574,6 +585,16 @@ static int __wifi_args_to_params(const struct shell *sh, size_t argc, char *argv if (params->psk && !secure_connection) { PR_WARNING("Passphrase provided without security configuration\n"); } + + if (!params->ssid) { + PR_ERROR("SSID not provided\n"); + return -EINVAL; + } + + if (iface_mode == WIFI_MODE_AP && params->channel == WIFI_CHANNEL_ANY) { + PR_ERROR("Channel not provided\n"); + return -EINVAL; + } return 0; } @@ -582,6 +603,7 @@ static int cmd_wifi_connect(const struct shell *sh, size_t argc, { struct net_if *iface = net_if_get_first_wifi(); struct wifi_connect_req_params cnx_params = { 0 }; + int ret; context.sh = sh; if (__wifi_args_to_params(sh, argc, argv, &cnx_params, WIFI_MODE_INFRA)) { @@ -590,12 +612,11 @@ static int cmd_wifi_connect(const struct shell *sh, size_t argc, } context.connecting = true; - - if (net_mgmt(NET_REQUEST_WIFI_CONNECT, iface, - &cnx_params, sizeof(struct wifi_connect_req_params))) { - PR_WARNING("Connection request failed\n"); + ret = net_mgmt(NET_REQUEST_WIFI_CONNECT, iface, + &cnx_params, sizeof(struct wifi_connect_req_params)); + if (ret) { + printk("Connection request failed with error: %d\n", ret); context.connecting = false; - return -ENOEXEC; } @@ -621,7 +642,7 @@ static int cmd_wifi_disconnect(const struct shell *sh, size_t argc, if (status == -EALREADY) { PR_INFO("Already disconnected\n"); } else { - PR_WARNING("Disconnect request failed\n"); + PR_WARNING("Disconnect request failed: %d\n", status); return -ENOEXEC; } } else { @@ -1910,6 +1931,7 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, "[-w, --ieee-80211w]: MFP (optional: needs security type to be specified)\n" ": 0:Disable, 1:Optional, 2:Required.\n" "[-m, --bssid]: MAC address of the AP (BSSID).\n" + "[-t, --timeout]: Timeout for the connection attempt (in seconds).\n" "[-h, --help]: Print out the help for the connect command.\n", cmd_wifi_connect, 2, 7), diff --git a/subsys/net/lib/CMakeLists.txt b/subsys/net/lib/CMakeLists.txt index 40795ac5a16..02d43e2190a 100644 --- a/subsys/net/lib/CMakeLists.txt +++ b/subsys/net/lib/CMakeLists.txt @@ -27,7 +27,7 @@ if (CONFIG_DNS_RESOLVER add_subdirectory(dns) endif() -if(CONFIG_HTTP_PARSER_URL OR CONFIG_HTTP_PARSER OR CONFIG_HTTP_CLIENT) +if(CONFIG_HTTP) add_subdirectory(http) endif() diff --git a/subsys/net/lib/coap/coap_client.c b/subsys/net/lib/coap/coap_client.c index 4bdf387a242..96d1584ccb0 100644 --- a/subsys/net/lib/coap/coap_client.c +++ b/subsys/net/lib/coap/coap_client.c @@ -27,6 +27,7 @@ static atomic_t coap_client_recv_active; static int send_request(int sock, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen) { + LOG_HEXDUMP_DBG(buf, len, "Send CoAP Request:"); if (addrlen == 0) { return zsock_sendto(sock, buf, len, flags, NULL, 0); } else { @@ -37,11 +38,17 @@ static int send_request(int sock, const void *buf, size_t len, int flags, static int receive(int sock, void *buf, size_t max_len, int flags, struct sockaddr *src_addr, socklen_t *addrlen) { + ssize_t err; + if (*addrlen == 0) { - return zsock_recvfrom(sock, buf, max_len, flags, NULL, NULL); + err = zsock_recvfrom(sock, buf, max_len, flags, NULL, NULL); } else { - return zsock_recvfrom(sock, buf, max_len, flags, src_addr, addrlen); + err = zsock_recvfrom(sock, buf, max_len, flags, src_addr, addrlen); + } + if (err > 0) { + LOG_HEXDUMP_DBG(buf, err, "Receive CoAP Response:"); } + return err; } static void reset_block_contexts(struct coap_client_internal_request *request) @@ -59,6 +66,7 @@ static void reset_internal_request(struct coap_client_internal_request *request) { request->offset = 0; request->last_id = 0; + request->last_response_id = -1; reset_block_contexts(request); } @@ -282,6 +290,7 @@ int coap_client_req(struct coap_client *client, int sock, const struct sockaddr struct coap_client_internal_request *internal_req = get_free_request(client); if (internal_req == NULL) { + LOG_DBG("No more free requests"); return -EAGAIN; } @@ -320,6 +329,7 @@ int coap_client_req(struct coap_client *client, int sock, const struct sockaddr reset_internal_request(internal_req); if (k_mutex_lock(&client->send_mutex, K_NO_WAIT)) { + LOG_DBG("Could not immediately lock send_mutex"); return -EAGAIN; } @@ -360,6 +370,7 @@ int coap_client_req(struct coap_client *client, int sock, const struct sockaddr } coap_pending_cycle(&internal_req->pending); + internal_req->is_observe = coap_request_is_observe(&internal_req->request); } ret = send_request(sock, internal_req->request.data, internal_req->request.offset, 0, @@ -380,8 +391,13 @@ int coap_client_req(struct coap_client *client, int sock, const struct sockaddr static void report_callback_error(struct coap_client_internal_request *internal_req, int error_code) { if (internal_req->coap_request.cb) { - internal_req->coap_request.cb(error_code, 0, NULL, 0, true, - internal_req->coap_request.user_data); + if (!atomic_set(&internal_req->in_callback, 1)) { + internal_req->coap_request.cb(error_code, 0, NULL, 0, true, + internal_req->coap_request.user_data); + atomic_clear(&internal_req->in_callback); + } else { + LOG_DBG("Cannot call the callback; already in it."); + } } } @@ -400,7 +416,9 @@ static int resend_request(struct coap_client *client, { int ret = 0; - if (internal_req->pending.timeout != 0 && coap_pending_cycle(&internal_req->pending)) { + if (internal_req->request_ongoing && + internal_req->pending.timeout != 0 && + coap_pending_cycle(&internal_req->pending)) { LOG_ERR("Timeout in poll, retrying send"); /* Reset send block context as it was updated in previous init from packet */ @@ -643,6 +661,7 @@ static int handle_response(struct coap_client *client, const struct coap_packet /* CON, NON_CON and piggybacked ACK need to match the token with original request */ uint16_t payload_len; uint8_t response_code = coap_header_get_code(response); + uint16_t response_id = coap_header_get_id(response); const uint8_t *payload = coap_packet_get_payload(response, &payload_len); /* Separate response coming */ @@ -659,6 +678,14 @@ static int handle_response(struct coap_client *client, const struct coap_packet return 1; } + /* MID-based deduplication */ + if (response_id == internal_req->last_response_id) { + LOG_WRN("Duplicate MID, dropping"); + goto fail; + } + + internal_req->last_response_id = response_id; + /* Received echo option */ if (find_echo_option(response, &client->echo_option)) { /* Resend request with echo option */ @@ -765,10 +792,16 @@ static int handle_response(struct coap_client *client, const struct coap_packet /* Call user callback */ if (internal_req->coap_request.cb) { - internal_req->coap_request.cb(response_code, internal_req->offset, payload, - payload_len, last_block, - internal_req->coap_request.user_data); - + if (!atomic_set(&internal_req->in_callback, 1)) { + internal_req->coap_request.cb(response_code, internal_req->offset, payload, + payload_len, last_block, + internal_req->coap_request.user_data); + atomic_clear(&internal_req->in_callback); + } + if (!internal_req->request_ongoing) { + /* User callback must have called coap_client_cancel_requests(). */ + goto fail; + } /* Update the offset for next callback in a blockwise transfer */ if (blockwise_transfer) { internal_req->offset += payload_len; @@ -811,10 +844,33 @@ static int handle_response(struct coap_client *client, const struct coap_packet } fail: client->response_ready = false; - internal_req->request_ongoing = false; + if (ret < 0 || !internal_req->is_observe) { + internal_req->request_ongoing = false; + } return ret; } +void coap_client_cancel_requests(struct coap_client *client) +{ + for (int i = 0; i < ARRAY_SIZE(client->requests); i++) { + if (client->requests[i].request_ongoing == true) { + LOG_DBG("Cancelling request %d", i); + /* Report the request was cancelled. This will be skipped if + * this function was called from the user's callback so we + * do not reenter it. In that case, the user knows their + * request was cancelled anyway. + */ + report_callback_error(&client->requests[i], -ECANCELED); + client->requests[i].request_ongoing = false; + client->requests[i].is_observe = false; + } + } + atomic_clear(&coap_client_recv_active); + + /* Wait until after zsock_poll() can time out and return. */ + k_sleep(K_MSEC(COAP_PERIODIC_TIMEOUT)); +} + void coap_client_recv(void *coap_cl, void *a, void *b) { int ret; diff --git a/subsys/net/lib/config/CMakeLists.txt b/subsys/net/lib/config/CMakeLists.txt index 2de025e2c77..73250973739 100644 --- a/subsys/net/lib/config/CMakeLists.txt +++ b/subsys/net/lib/config/CMakeLists.txt @@ -12,11 +12,6 @@ if(CONFIG_NET_CONFIG_SETTINGS) CONFIG_NET_L2_IEEE802154 ieee802154_settings.c ) - - zephyr_library_sources_ifdef( - CONFIG_NET_L2_BT - bt_settings.c - ) endif() zephyr_library_sources_ifdef(CONFIG_NET_CONFIG_CLOCK_SNTP_INIT init_clock_sntp.c) diff --git a/subsys/net/lib/config/Kconfig b/subsys/net/lib/config/Kconfig index c9ebc9ca3ef..64083eb3fc1 100644 --- a/subsys/net/lib/config/Kconfig +++ b/subsys/net/lib/config/Kconfig @@ -3,6 +3,25 @@ # Copyright (c) 2017 Intel Corporation. # SPDX-License-Identifier: Apache-2.0 +module = NET_CONFIG +module-dep = NET_LOG +module-str = Log level for network config library +module-help = Enables net config library to output debug messages. +source "subsys/net/Kconfig.template.log_config.net" + +menuconfig NET_CONFIG_SETTINGS + bool "Set network settings for applications" + select NET_MGMT + select NET_MGMT_EVENT + help + Allow IP addresses to be set in config file for + networking client/server sample applications, or + some link-layer dedicated settings like the channel. + Beware this is not meant to be used for proper + provisioning but quick sampling/testing. + +if NET_CONFIG_SETTINGS + config NET_CONFIG_AUTO_INIT bool "Init networking support automatically during device startup" default n if USB_DEVICE_NETWORK @@ -12,22 +31,14 @@ config NET_CONFIG_AUTO_INIT initialized when the device is started. If you do not wish to do this, then disable this and call net_config_init() in your application. +if NET_CONFIG_AUTO_INIT + config NET_CONFIG_INIT_PRIO int "Startup priority for the network application init" default 95 - depends on NET_CONFIG_AUTO_INIT - -config NET_CONFIG_INIT_TIMEOUT - int "How long to wait for networking to be ready and available" - default 30 - help - The value is in seconds. If for example IPv4 address from DHCPv4 is not - received within this limit, then the net_config_init() call will fail - during the device startup. config NET_CONFIG_NEED_IPV6 bool "This application wants IPv6 support" - depends on NET_CONFIG_AUTO_INIT select NET_IPV6 help The network application needs IPv6 support to function properly. @@ -36,7 +47,6 @@ config NET_CONFIG_NEED_IPV6 config NET_CONFIG_NEED_IPV6_ROUTER bool "This application wants IPv6 router to exists" - depends on NET_CONFIG_AUTO_INIT depends on NET_IPV6 help The network application needs IPv6 router to exists before continuing. @@ -45,31 +55,21 @@ config NET_CONFIG_NEED_IPV6_ROUTER config NET_CONFIG_NEED_IPV4 bool "This application wants IPv4 support" - depends on NET_CONFIG_AUTO_INIT select NET_IPV4 help The network application needs IPv4 support to function properly. This option makes sure the network application is initialized properly in order to use IPv4. -module = NET_CONFIG -module-dep = NET_LOG -module-str = Log level for network config library -module-help = Enables net config library to output debug messages. -source "subsys/net/Kconfig.template.log_config.net" +endif # NET_CONFIG_AUTO_INIT -menuconfig NET_CONFIG_SETTINGS - bool "Set network settings for applications" - select NET_MGMT - select NET_MGMT_EVENT +config NET_CONFIG_INIT_TIMEOUT + int "How long to wait for networking to be ready and available" + default 30 help - Allow IP addresses to be set in config file for - networking client/server sample applications, or - some link-layer dedicated settings like the channel. - Beware this is not meant to be used for proper - provisioning but quick sampling/testing. - -if NET_CONFIG_SETTINGS + The value is in seconds. If for example IPv4 address from DHCPv4 is not + received within this limit, then the net_config_init() call will fail + during the device startup. config NET_CONFIG_MY_VLAN_ID int "My VLAN identifier" @@ -185,14 +185,6 @@ config NET_CONFIG_IEEE802154_ACK_REQUIRED endif # NET_L2_IEEE802154 || IEEE802154_RAW_MODE -config NET_CONFIG_BT_NODE - bool "Bluetooth node support" - depends on NET_L2_BT - select NET_L2_BT_MGMT - help - Enables application to operate in node mode which requires GATT - service to be registered and start advertising as peripheral. - endif # NET_CONFIG_SETTINGS if NET_DHCPV6 diff --git a/subsys/net/lib/config/bt_settings.c b/subsys/net/lib/config/bt_settings.c deleted file mode 100644 index d7f6afc92c1..00000000000 --- a/subsys/net/lib/config/bt_settings.c +++ /dev/null @@ -1,62 +0,0 @@ -/* IEEE 802.15.4 settings code */ - -/* - * Copyright (c) 2017 Intel Corporation. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -LOG_MODULE_DECLARE(net_config, CONFIG_NET_CONFIG_LOG_LEVEL); - -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -#if defined(CONFIG_NET_CONFIG_BT_NODE) -#define ADV_STR "on" - -BT_GATT_SERVICE_DEFINE(ipss_svc, - /* IP Support Service Declaration */ - BT_GATT_PRIMARY_SERVICE(BT_UUID_IPSS), -); -#endif - -int z_net_config_bt_setup(void) -{ - struct net_if *iface; - const struct device *dev; - int err; - - err = bt_enable(NULL); - if (err < 0 && err != -EALREADY) { - return err; - } - - dev = device_get_binding("net_bt"); - if (!dev) { - return -ENODEV; - } - - iface = net_if_lookup_by_dev(dev); - if (!iface) { - return -EINVAL; - } - -#if defined(CONFIG_NET_CONFIG_BT_NODE) - if (net_mgmt(NET_REQUEST_BT_ADVERTISE, iface, ADV_STR, - sizeof(ADV_STR))) { - return -EINVAL; - } -#endif - - return 0; -} diff --git a/subsys/net/lib/config/bt_settings.h b/subsys/net/lib/config/bt_settings.h deleted file mode 100644 index dc6eb74e38a..00000000000 --- a/subsys/net/lib/config/bt_settings.h +++ /dev/null @@ -1,13 +0,0 @@ -/* IEEE 802.15.4 settings header */ - -/* - * Copyright (c) 2017 Intel Corporation. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#if defined(CONFIG_NET_L2_BT) && defined(CONFIG_NET_CONFIG_SETTINGS) -int z_net_config_bt_setup(void); -#else -#define z_net_config_bt_setup(...) 0 -#endif diff --git a/subsys/net/lib/config/init.c b/subsys/net/lib/config/init.c index 734ca16998c..23ceeff5247 100644 --- a/subsys/net/lib/config/init.c +++ b/subsys/net/lib/config/init.c @@ -29,7 +29,6 @@ LOG_MODULE_REGISTER(net_config, CONFIG_NET_CONFIG_LOG_LEVEL); #include #include "ieee802154_settings.h" -#include "bt_settings.h" extern int net_init_clock_via_sntp(void); @@ -501,14 +500,6 @@ int net_config_init_app(const struct device *dev, const char *app_info) NET_ERR("Cannot setup IEEE 802.15.4 interface (%d)", ret); } -#if defined(CONFIG_NET_IPV6) - /* Bluetooth is only usable if IPv6 is enabled */ - ret = z_net_config_bt_setup(); - if (ret < 0) { - NET_ERR("Cannot setup Bluetooth interface (%d)", ret); - } -#endif - /* Only try to use a network interface that is auto started */ if (iface == NULL) { net_if_foreach(iface_find_cb, &iface); diff --git a/subsys/net/lib/dhcpv4/dhcpv4.c b/subsys/net/lib/dhcpv4/dhcpv4.c index e1db51ebfcd..d0ea25edc49 100644 --- a/subsys/net/lib/dhcpv4/dhcpv4.c +++ b/subsys/net/lib/dhcpv4/dhcpv4.c @@ -1406,7 +1406,7 @@ static void dhcpv4_iface_event_handler(struct net_mgmt_event_callback *cb, if (iface->config.dhcpv4.state == NET_DHCPV4_BOUND) { iface->config.dhcpv4.attempts = 0U; - iface->config.dhcpv4.state = NET_DHCPV4_RENEWING; + iface->config.dhcpv4.state = NET_DHCPV4_INIT; NET_DBG("enter state=%s", net_dhcpv4_state_name( iface->config.dhcpv4.state)); /* Remove any bound address as interface is gone */ diff --git a/subsys/net/lib/dns/Kconfig b/subsys/net/lib/dns/Kconfig index 4503c3e8dc8..9b15408177e 100644 --- a/subsys/net/lib/dns/Kconfig +++ b/subsys/net/lib/dns/Kconfig @@ -4,6 +4,8 @@ config DNS_RESOLVER bool "DNS resolver" depends on NET_NATIVE + select NET_SOCKETS + select NET_SOCKETS_SERVICE select CRC help This option enables the DNS client side support for Zephyr @@ -164,6 +166,8 @@ config MDNS_RESPONDER select NET_IPV6_MLD if NET_IPV6 select NET_MGMT select NET_MGMT_EVENT + select NET_SOCKETS + select NET_SOCKETS_SERVICE depends on NET_HOSTNAME_ENABLE help This option enables the mDNS responder support for Zephyr. @@ -229,6 +233,8 @@ config LLMNR_RESPONDER select NET_IPV6_MLD if NET_IPV6 select NET_MGMT select NET_MGMT_EVENT + select NET_SOCKETS + select NET_SOCKETS_SERVICE depends on NET_HOSTNAME_ENABLE help This option enables the LLMNR responder support for Zephyr. diff --git a/subsys/net/lib/dns/llmnr_responder.c b/subsys/net/lib/dns/llmnr_responder.c index b5442904a74..deb9802c2a6 100644 --- a/subsys/net/lib/dns/llmnr_responder.c +++ b/subsys/net/lib/dns/llmnr_responder.c @@ -6,6 +6,7 @@ /* * Copyright (c) 2018 Intel Corporation + * Copyright (c) 2024 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -23,6 +24,7 @@ LOG_MODULE_REGISTER(net_llmnr_responder, CONFIG_LLMNR_RESPONDER_LOG_LEVEL); #include #include #include +#include #include #include @@ -36,12 +38,12 @@ LOG_MODULE_REGISTER(net_llmnr_responder, CONFIG_LLMNR_RESPONDER_LOG_LEVEL); #define LLMNR_TTL CONFIG_LLMNR_RESPONDER_TTL /* In seconds */ #if defined(CONFIG_NET_IPV4) -static struct net_context *ipv4; +static int ipv4; static struct sockaddr_in local_addr4; #endif #if defined(CONFIG_NET_IPV6) -static struct net_context *ipv6; +static int ipv6; #endif static struct net_mgmt_event_callback mgmt_cb; @@ -54,7 +56,19 @@ static struct net_mgmt_event_callback mgmt_cb; #define DNS_RESOLVER_BUF_CTR (DNS_RESOLVER_MIN_BUF + \ CONFIG_LLMNR_RESOLVER_ADDITIONAL_BUF_CTR) -NET_BUF_POOL_DEFINE(llmnr_dns_msg_pool, DNS_RESOLVER_BUF_CTR, +#if (IS_ENABLED(CONFIG_NET_IPV6) && IS_ENABLED(CONFIG_NET_IPV4)) +#define LLMNR_MAX_POLL 2 +#else +#define LLMNR_MAX_POLL 1 +#endif + +/* Socket polling for each server connection */ +static struct zsock_pollfd fds[LLMNR_MAX_POLL]; + +static void svc_handler(struct k_work *work); +NET_SOCKET_SERVICE_SYNC_DEFINE_STATIC(svc_llmnr, NULL, svc_handler, LLMNR_MAX_POLL); + +NET_BUF_POOL_DEFINE(llmnr_msg_pool, DNS_RESOLVER_BUF_CTR, DNS_RESOLVER_MAX_BUF_SIZE, 0, NULL); #if defined(CONFIG_NET_IPV6) @@ -68,20 +82,14 @@ static void create_ipv6_addr(struct sockaddr_in6 *addr) 0xff02, 0, 0, 0, 0, 0, 0x01, 0x03); } -static void create_ipv6_dst_addr(struct net_pkt *pkt, +static void create_ipv6_dst_addr(struct sockaddr_in6 *src_addr, struct sockaddr_in6 *addr) { - struct net_udp_hdr *udp_hdr, hdr; - - udp_hdr = net_udp_get_hdr(pkt, &hdr); - if (!udp_hdr) { - return; - } - addr->sin6_family = AF_INET6; - addr->sin6_port = udp_hdr->src_port; + addr->sin6_port = src_addr->sin6_port; - net_ipv6_addr_copy_raw((uint8_t *)&addr->sin6_addr, NET_IPV6_HDR(pkt)->src); + net_ipv6_addr_copy_raw((uint8_t *)&addr->sin6_addr, + (uint8_t *)&src_addr->sin6_addr); } #endif @@ -95,21 +103,14 @@ static void create_ipv4_addr(struct sockaddr_in *addr) addr->sin_addr.s_addr = htonl(0xE00000FC); } -static void create_ipv4_dst_addr(struct net_pkt *pkt, +static void create_ipv4_dst_addr(struct sockaddr_in *src_addr, struct sockaddr_in *addr) { - struct net_udp_hdr *udp_hdr, hdr; - - udp_hdr = net_udp_get_hdr(pkt, &hdr); - if (!udp_hdr) { - NET_ERR("could not get UDP header"); - return; - } - addr->sin_family = AF_INET; - addr->sin_port = udp_hdr->src_port; + addr->sin_port = src_addr->sin_port; - net_ipv4_addr_copy_raw((uint8_t *)&addr->sin_addr, NET_IPV4_HDR(pkt)->src); + net_ipv4_addr_copy_raw((uint8_t *)&addr->sin_addr, + (uint8_t *)&src_addr->sin_addr); } #endif @@ -128,33 +129,31 @@ static void llmnr_iface_event_handler(struct net_mgmt_event_callback *cb, } } -static struct net_context *get_ctx(sa_family_t family) +static int get_socket(sa_family_t family) { - struct net_context *ctx; int ret; - ret = net_context_get(family, SOCK_DGRAM, IPPROTO_UDP, &ctx); + ret = zsock_socket(family, SOCK_DGRAM, IPPROTO_UDP); if (ret < 0) { NET_DBG("Cannot get context (%d)", ret); - return NULL; } - return ctx; + return ret; } -static int bind_ctx(struct net_context *ctx, +static int bind_ctx(int sock, struct sockaddr *local_addr, socklen_t addrlen) { int ret; - if (!ctx) { + if (sock < 0) { return -EINVAL; } - ret = net_context_bind(ctx, local_addr, addrlen); + ret = zsock_bind(sock, local_addr, addrlen); if (ret < 0) { - NET_DBG("Cannot bind to LLMNR %s port (%d)", + NET_DBG("Cannot bind to %s %s port (%d)", "LLMNR", local_addr->sa_family == AF_INET ? "IPv4" : "IPv6", ret); return ret; @@ -237,8 +236,7 @@ static int add_answer(struct net_buf *query, uint32_t ttl, return offset + addr_len; } -static int create_answer(struct net_context *ctx, - enum dns_rr_type qtype, +static int create_answer(enum dns_rr_type qtype, struct net_buf *query, uint16_t dns_id, uint16_t addr_len, const uint8_t *addr) @@ -246,7 +244,7 @@ static int create_answer(struct net_context *ctx, /* Prepare the response into the query buffer: move the name * query buffer has to get enough free space: dns_hdr + query + answer */ - if ((query->size - query->len) < (DNS_MSG_HEADER_SIZE + + if ((net_buf_max_len(query) - query->len) < (DNS_MSG_HEADER_SIZE + (DNS_QTYPE_LEN + DNS_QCLASS_LEN) * 2 + DNS_TTL_LEN + DNS_RDLENGTH_LEN + addr_len + query->len)) { @@ -292,10 +290,14 @@ static const uint8_t *get_ipv6_src(struct net_if *iface, struct in6_addr *dst) } #endif +static int set_ttl_hop_limit(int sock, int level, int option, int new_limit) +{ + return zsock_setsockopt(sock, level, option, &new_limit, sizeof(new_limit)); +} + #if defined(CONFIG_NET_IPV4) -static int create_ipv4_answer(struct net_context *ctx, - struct net_pkt *pkt, - union net_ip_header *ip_hdr, +static int create_ipv4_answer(int sock, + struct sockaddr_in *src_addr, enum dns_rr_type qtype, struct net_buf *query, uint16_t dns_id, @@ -305,49 +307,30 @@ static int create_ipv4_answer(struct net_context *ctx, const uint8_t *addr; int addr_len; - create_ipv4_dst_addr(pkt, net_sin(dst)); - *dst_len = sizeof(struct sockaddr_in); - - if (qtype == DNS_RR_TYPE_A) { - /* Select proper address according to destination */ - addr = get_ipv4_src(net_pkt_iface(pkt), - &net_sin(dst)->sin_addr); - if (!addr) { - return -ENOENT; - } + create_ipv4_dst_addr(src_addr, net_sin(dst)); - addr_len = sizeof(struct in_addr); - - } else if (qtype == DNS_RR_TYPE_AAAA) { -#if defined(CONFIG_NET_IPV6) - addr = get_ipv6_src(net_pkt_iface(pkt), - (struct in6_addr *)ip_hdr->ipv6->src); - if (!addr) { - return -ENOENT; - } + *dst_len = sizeof(struct sockaddr_in); - addr_len = sizeof(struct in6_addr); -#else - addr = NULL; - addr_len = 0; -#endif - } else { - return -EINVAL; + /* Select proper address according to destination */ + addr = get_ipv4_src(NULL, &net_sin(dst)->sin_addr); + if (!addr) { + return -ENOENT; } - if (create_answer(ctx, qtype, query, dns_id, addr_len, addr)) { + addr_len = sizeof(struct in_addr); + + if (create_answer(qtype, query, dns_id, addr_len, addr)) { return -ENOMEM; } - net_context_set_ipv4_mcast_ttl(ctx, 255); + (void)set_ttl_hop_limit(sock, IPPROTO_IP, IP_MULTICAST_TTL, 255); return 0; } #endif /* CONFIG_NET_IPV4 */ -static int create_ipv6_answer(struct net_context *ctx, - struct net_pkt *pkt, - union net_ip_header *ip_hdr, +static int create_ipv6_answer(int sock, + struct sockaddr_in6 *src_addr, enum dns_rr_type qtype, struct net_buf *query, uint16_t dns_id, @@ -358,62 +341,50 @@ static int create_ipv6_answer(struct net_context *ctx, const uint8_t *addr; int addr_len; - create_ipv6_dst_addr(pkt, net_sin6(dst)); - *dst_len = sizeof(struct sockaddr_in6); + create_ipv6_dst_addr(src_addr, net_sin6(dst)); - if (qtype == DNS_RR_TYPE_AAAA) { - addr = get_ipv6_src(net_pkt_iface(pkt), - (struct in6_addr *)ip_hdr->ipv6->src); - if (!addr) { - return -ENOENT; - } - - addr_len = sizeof(struct in6_addr); - } else if (qtype == DNS_RR_TYPE_A) { -#if defined(CONFIG_NET_IPV4) - addr = get_ipv4_src(net_pkt_iface(pkt), - (struct in_addr *)ip_hdr->ipv4->src); - if (!addr) { - return -ENOENT; - } + *dst_len = sizeof(struct sockaddr_in6); - addr_len = sizeof(struct in_addr); -#else - addr_len = 0; -#endif - } else { - return -EINVAL; + addr = get_ipv6_src(NULL, &src_addr->sin6_addr); + if (!addr) { + return -ENOENT; } - if (create_answer(ctx, qtype, query, dns_id, addr_len, addr)) { + addr_len = sizeof(struct in6_addr); + + if (create_answer(qtype, query, dns_id, addr_len, addr)) { return -ENOMEM; } - net_context_set_ipv6_mcast_hop_limit(ctx, 255); + (void)set_ttl_hop_limit(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, 255); #endif /* CONFIG_NET_IPV6 */ return 0; } -static int send_response(struct net_context *ctx, struct net_pkt *pkt, - union net_ip_header *ip_hdr, struct net_buf *reply, - enum dns_rr_type qtype, uint16_t dns_id) +static int send_response(int sock, + struct sockaddr *src_addr, + size_t addrlen, + struct net_buf *reply, + enum dns_rr_type qtype, + uint16_t dns_id) { - struct sockaddr dst; socklen_t dst_len; int ret; + COND_CODE_1(IS_ENABLED(CONFIG_NET_IPV6), + (struct sockaddr_in6), (struct sockaddr_in)) dst; - if (IS_ENABLED(CONFIG_NET_IPV4) && - net_pkt_family(pkt) == AF_INET) { - ret = create_ipv4_answer(ctx, pkt, ip_hdr, qtype, reply, - dns_id, &dst, &dst_len); + if (IS_ENABLED(CONFIG_NET_IPV4) && src_addr->sa_family == AF_INET) { + ret = create_ipv4_answer(sock, (struct sockaddr_in *)src_addr, + qtype, reply, dns_id, + (struct sockaddr *)&dst, &dst_len); if (ret < 0) { return ret; } - } else if (IS_ENABLED(CONFIG_NET_IPV6) && - net_pkt_family(pkt) == AF_INET6) { - ret = create_ipv6_answer(ctx, pkt, ip_hdr, qtype, reply, - dns_id, &dst, &dst_len); + } else if (IS_ENABLED(CONFIG_NET_IPV6) && src_addr->sa_family == AF_INET6) { + ret = create_ipv6_answer(sock, (struct sockaddr_in6 *)src_addr, + qtype, reply, dns_id, + (struct sockaddr *)&dst, &dst_len); if (ret < 0) { return ret; } @@ -422,23 +393,24 @@ static int send_response(struct net_context *ctx, struct net_pkt *pkt, return -EPFNOSUPPORT; } - ret = net_context_sendto(ctx, reply->data, reply->len, &dst, - dst_len, NULL, K_NO_WAIT, NULL); + ret = zsock_sendto(sock, reply->data, reply->len, 0, + (struct sockaddr *)&dst, dst_len); if (ret < 0) { - NET_DBG("Cannot send LLMNR reply to %s (%d)", - net_pkt_family(pkt) == AF_INET ? - net_sprint_ipv4_addr(&net_sin(&dst)->sin_addr) : - net_sprint_ipv6_addr(&net_sin6(&dst)->sin6_addr), + NET_DBG("Cannot send %s reply to %s (%d)", "LLMNR", + src_addr->sa_family == AF_INET ? + net_sprint_ipv4_addr(&net_sin((struct sockaddr *)&dst)->sin_addr) : + net_sprint_ipv6_addr(&net_sin6((struct sockaddr *)&dst)->sin6_addr), ret); } return ret; } -static int dns_read(struct net_context *ctx, - struct net_pkt *pkt, - union net_ip_header *ip_hdr, +static int dns_read(int sock, struct net_buf *dns_data, + size_t len, + struct sockaddr *src_addr, + size_t addrlen, struct dns_addrinfo *info) { /* Helper struct to track the dns msg received from the server */ @@ -447,28 +419,23 @@ static int dns_read(struct net_context *ctx, struct net_buf *result; struct dns_msg_t dns_msg; uint16_t dns_id = 0U; + socklen_t optlen; int data_len; int queries; + int family; int ret; - data_len = MIN(net_pkt_remaining_data(pkt), DNS_RESOLVER_MAX_BUF_SIZE); + data_len = MIN(len, DNS_RESOLVER_MAX_BUF_SIZE); /* Store the DNS query name into a temporary net_buf, which will be * eventually used to send a response */ - result = net_buf_alloc(&llmnr_dns_msg_pool, BUF_ALLOC_TIMEOUT); + result = net_buf_alloc(&llmnr_msg_pool, BUF_ALLOC_TIMEOUT); if (!result) { ret = -ENOMEM; goto quit; } - /* TODO: Instead of this temporary copy, just use the net_pkt directly. - */ - ret = net_pkt_read(pkt, dns_data->data, data_len); - if (ret < 0) { - goto quit; - } - dns_msg.msg = dns_data->data; dns_msg.msg_size = data_len; @@ -480,18 +447,21 @@ static int dns_read(struct net_context *ctx, queries = ret; + optlen = sizeof(int); + (void)zsock_getsockopt(sock, SOL_SOCKET, SO_DOMAIN, &family, &optlen); + NET_DBG("Received %d %s from %s (id 0x%04x)", queries, queries > 1 ? "queries" : "query", - net_pkt_family(pkt) == AF_INET ? - net_sprint_ipv4_addr(&ip_hdr->ipv4->src) : - net_sprint_ipv6_addr(&ip_hdr->ipv6->src), + family == AF_INET ? + net_sprint_ipv4_addr(&net_sin(src_addr)->sin_addr) : + net_sprint_ipv6_addr(&net_sin6(src_addr)->sin6_addr), dns_id); do { enum dns_rr_type qtype; enum dns_class qclass; - (void)memset(result->data, 0, result->size); + (void)memset(result->data, 0, net_buf_max_len(result)); result->len = 0U; ret = dns_unpack_query(&dns_msg, result, &qtype, &qclass); @@ -506,9 +476,9 @@ static int dns_read(struct net_context *ctx, /* If the query matches to our hostname, then send reply */ if (!strncasecmp(hostname, result->data + 1, hostname_len) && (result->len - 1) >= hostname_len) { - NET_DBG("LLMNR query to our hostname %s", + NET_DBG("%s query to our hostname %s", "LLMNR", hostname); - ret = send_response(ctx, pkt, ip_hdr, result, qtype, + ret = send_response(sock, src_addr, addrlen, result, qtype, dns_id); if (ret < 0) { NET_DBG("Cannot send response (%d)", ret); @@ -526,43 +496,69 @@ static int dns_read(struct net_context *ctx, return ret; } -static void recv_cb(struct net_context *net_ctx, - struct net_pkt *pkt, - union net_ip_header *ip_hdr, - union net_proto_header *proto_hdr, - int status, - void *user_data) +static int recv_data(struct net_socket_service_event *pev) { - struct net_context *ctx = user_data; + COND_CODE_1(IS_ENABLED(CONFIG_NET_IPV6), + (struct sockaddr_in6), (struct sockaddr_in)) addr; struct net_buf *dns_data = NULL; struct dns_addrinfo info = { 0 }; - int ret; - - ARG_UNUSED(net_ctx); - NET_ASSERT(ctx == net_ctx); - - if (!pkt) { - return; - } - - if (status) { + size_t addrlen = sizeof(addr); + int ret, family, sock_error, len; + socklen_t optlen; + + if ((pev->event.revents & ZSOCK_POLLERR) || + (pev->event.revents & ZSOCK_POLLNVAL)) { + (void)zsock_getsockopt(pev->event.fd, SOL_SOCKET, + SO_DOMAIN, &family, &optlen); + (void)zsock_getsockopt(pev->event.fd, SOL_SOCKET, + SO_ERROR, &sock_error, &optlen); + NET_ERR("Receiver IPv%d socket error (%d)", + family == AF_INET ? 4 : 6, sock_error); + ret = DNS_EAI_SYSTEM; goto quit; } - dns_data = net_buf_alloc(&llmnr_dns_msg_pool, BUF_ALLOC_TIMEOUT); + dns_data = net_buf_alloc(&llmnr_msg_pool, BUF_ALLOC_TIMEOUT); if (!dns_data) { + ret = -ENOENT; goto quit; } - ret = dns_read(ctx, pkt, ip_hdr, dns_data, &info); + ret = zsock_recvfrom(pev->event.fd, dns_data->data, + net_buf_max_len(dns_data), 0, + (struct sockaddr *)&addr, &addrlen); + if (ret < 0) { + ret = -errno; + NET_ERR("recv failed on IPv%d socket (%d)", + family == AF_INET ? 4 : 6, -ret); + goto free_buf; + } + + len = ret; + + ret = dns_read(pev->event.fd, dns_data, len, + (struct sockaddr *)&addr, addrlen, &info); if (ret < 0 && ret != -EINVAL) { - NET_DBG("LLMNR read failed (%d)", ret); + NET_DBG("%s read failed (%d)", "LLMNR", ret); } +free_buf: net_buf_unref(dns_data); quit: - net_pkt_unref(pkt); + return ret; +} + +static void svc_handler(struct k_work *work) +{ + struct net_socket_service_event *pev = + CONTAINER_OF(work, struct net_socket_service_event, work); + int ret; + + ret = recv_data(pev); + if (ret < 0) { + NET_ERR("DNS recv error (%d)", ret); + } } #if defined(CONFIG_NET_IPV6) @@ -573,8 +569,10 @@ static void iface_ipv6_cb(struct net_if *iface, void *user_data) ret = net_ipv6_mld_join(iface, addr); if (ret < 0) { - NET_DBG("Cannot join %s IPv6 multicast group (%d)", - net_sprint_ipv6_addr(addr), ret); + NET_DBG("Cannot join %s IPv6 multicast group to iface %d (%d)", + net_sprint_ipv6_addr(addr), + net_if_get_by_iface(iface), + ret); } } @@ -594,8 +592,8 @@ static void iface_ipv4_cb(struct net_if *iface, void *user_data) ret = net_ipv4_igmp_join(iface, addr, NULL); if (ret < 0) { - NET_DBG("Cannot add IPv4 multicast address to iface %p", - iface); + NET_DBG("Cannot add %s multicast address to iface %d", "IPv4", + net_if_get_by_iface(iface)); } } @@ -611,25 +609,52 @@ static int init_listener(void) { int ret, ok = 0; + ARRAY_FOR_EACH(fds, j) { + fds[j].fd = -1; + } + #if defined(CONFIG_NET_IPV6) { static struct sockaddr_in6 local_addr; setup_ipv6_addr(&local_addr); - ipv6 = get_ctx(AF_INET6); + ipv6 = get_socket(AF_INET6); ret = bind_ctx(ipv6, (struct sockaddr *)&local_addr, sizeof(local_addr)); if (ret < 0) { - net_context_put(ipv6); + zsock_close(ipv6); + goto ipv6_out; + } + + ret = -ENOENT; + + ARRAY_FOR_EACH(fds, j) { + if (fds[j].fd == ipv6) { + ret = 0; + break; + } + + if (fds[j].fd < 0) { + fds[j].fd = ipv6; + fds[j].events = ZSOCK_POLLIN; + ret = 0; + break; + } + } + + if (ret < 0) { + NET_DBG("Cannot set %s to socket (%d)", "polling", ret); + zsock_close(ipv6); goto ipv6_out; } - ret = net_context_recv(ipv6, recv_cb, K_NO_WAIT, ipv6); + ret = net_socket_service_register(&svc_llmnr, fds, ARRAY_SIZE(fds), NULL); if (ret < 0) { - NET_WARN("Cannot receive IPv6 LLMNR data (%d)", ret); - net_context_put(ipv6); + NET_DBG("Cannot register %s %s socket service (%d)", + "IPv6", "LLMNR", ret); + zsock_close(ipv6); } else { ok++; } @@ -641,19 +666,42 @@ static int init_listener(void) { setup_ipv4_addr(&local_addr4); - ipv4 = get_ctx(AF_INET); + ipv4 = get_socket(AF_INET); ret = bind_ctx(ipv4, (struct sockaddr *)&local_addr4, sizeof(local_addr4)); if (ret < 0) { - net_context_put(ipv4); + zsock_close(ipv4); goto ipv4_out; } - ret = net_context_recv(ipv4, recv_cb, K_NO_WAIT, ipv4); + ret = -ENOENT; + + ARRAY_FOR_EACH(fds, j) { + if (fds[j].fd == ipv4) { + ret = 0; + break; + } + + if (fds[j].fd < 0) { + fds[j].fd = ipv4; + fds[j].events = ZSOCK_POLLIN; + ret = 0; + break; + } + } + if (ret < 0) { - NET_WARN("Cannot receive IPv4 LLMNR data (%d)", ret); - net_context_put(ipv4); + NET_DBG("Cannot set %s to socket (%d)", "polling", ret); + zsock_close(ipv4); + goto ipv4_out; + } + + ret = net_socket_service_register(&svc_llmnr, fds, ARRAY_SIZE(fds), NULL); + if (ret < 0) { + NET_DBG("Cannot register %s %s socket service (%d)", + "IPv4", "LLMNR", ret); + zsock_close(ipv4); } else { ok++; } @@ -662,7 +710,7 @@ static int init_listener(void) #endif /* CONFIG_NET_IPV4 */ if (!ok) { - NET_WARN("Cannot start LLMNR responder"); + NET_WARN("Cannot start %s responder", "LLMNR"); } return !ok; @@ -670,7 +718,6 @@ static int init_listener(void) static int llmnr_responder_init(void) { - net_mgmt_init_event_callback(&mgmt_cb, llmnr_iface_event_handler, NET_EVENT_IF_UP); diff --git a/subsys/net/lib/dns/mdns_responder.c b/subsys/net/lib/dns/mdns_responder.c index 893a3692d37..e92db7dd57b 100644 --- a/subsys/net/lib/dns/mdns_responder.c +++ b/subsys/net/lib/dns/mdns_responder.c @@ -7,6 +7,7 @@ /* * Copyright (c) 2017 Intel Corporation * Copyright (c) 2020 Friedt Professional Engineering Services, Inc + * Copyright (c) 2024 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -25,6 +26,7 @@ LOG_MODULE_REGISTER(net_mdns_responder, CONFIG_MDNS_RESPONDER_LOG_LEVEL); #include #include #include +#include #include #include "dns_sd.h" @@ -39,14 +41,14 @@ LOG_MODULE_REGISTER(net_mdns_responder, CONFIG_MDNS_RESPONDER_LOG_LEVEL); #if defined(CONFIG_NET_IPV4) #define MAX_IPV4_IFACE_COUNT CONFIG_NET_IF_MAX_IPV4_COUNT -static struct net_context *ipv4[MAX_IPV4_IFACE_COUNT]; +static int ipv4[MAX_IPV4_IFACE_COUNT]; static struct sockaddr_in local_addr4; #else #define MAX_IPV4_IFACE_COUNT 0 #endif #if defined(CONFIG_NET_IPV6) #define MAX_IPV6_IFACE_COUNT CONFIG_NET_IF_MAX_IPV6_COUNT -static struct net_context *ipv6[MAX_IPV6_IFACE_COUNT]; +static int ipv6[MAX_IPV6_IFACE_COUNT]; #else #define MAX_IPV6_IFACE_COUNT 0 #endif @@ -63,8 +65,20 @@ static size_t external_records_count; #define DNS_RESOLVER_BUF_CTR (DNS_RESOLVER_MIN_BUF + \ CONFIG_MDNS_RESOLVER_ADDITIONAL_BUF_CTR) +#if (IS_ENABLED(CONFIG_NET_IPV6) && IS_ENABLED(CONFIG_NET_IPV4)) +#define MDNS_MAX_POLL (2 * (MAX_IPV4_IFACE_COUNT + MAX_IPV6_IFACE_COUNT)) +#else +#define MDNS_MAX_POLL (1 * (MAX_IPV4_IFACE_COUNT + MAX_IPV6_IFACE_COUNT)) +#endif + +static void svc_handler(struct k_work *work); +NET_SOCKET_SERVICE_SYNC_DEFINE_STATIC(svc_mdns, NULL, svc_handler, MDNS_MAX_POLL); + +/* Socket polling for each server connection */ +static struct zsock_pollfd fds[MDNS_MAX_POLL]; + #ifndef CONFIG_NET_TEST -static int setup_dst_addr(struct net_context *ctx, sa_family_t family, +static int setup_dst_addr(int sock, sa_family_t family, struct sockaddr *dst, socklen_t *dst_len); #endif /* CONFIG_NET_TEST */ @@ -106,17 +120,32 @@ static void mdns_iface_event_handler(struct net_mgmt_event_callback *cb, } } -int setup_dst_addr(struct net_context *ctx, sa_family_t family, +static int set_ttl_hop_limit(int sock, int level, int option, int new_limit) +{ + return zsock_setsockopt(sock, level, option, &new_limit, sizeof(new_limit)); +} + +int setup_dst_addr(int sock, sa_family_t family, struct sockaddr *dst, socklen_t *dst_len) { + int ret; + if (IS_ENABLED(CONFIG_NET_IPV4) && family == AF_INET) { create_ipv4_addr(net_sin(dst)); *dst_len = sizeof(struct sockaddr_in); - net_context_set_ipv4_mcast_ttl(ctx, 255); + + ret = set_ttl_hop_limit(sock, IPPROTO_IP, IP_MULTICAST_TTL, 255); + if (ret < 0) { + NET_DBG("Cannot set %s multicast %s (%d)", "IPv4", "TTL", ret); + } } else if (IS_ENABLED(CONFIG_NET_IPV6) && family == AF_INET6) { create_ipv6_addr(net_sin6(dst)); *dst_len = sizeof(struct sockaddr_in6); - net_context_set_ipv6_mcast_hop_limit(ctx, 255); + + ret = set_ttl_hop_limit(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, 255); + if (ret < 0) { + NET_DBG("Cannot set %s multicast %s (%d)", "IPv6", "hoplimit", ret); + } } else { return -EPFNOSUPPORT; } @@ -124,36 +153,34 @@ int setup_dst_addr(struct net_context *ctx, sa_family_t family, return 0; } -static struct net_context *get_ctx(sa_family_t family) +static int get_socket(sa_family_t family) { - struct net_context *ctx; int ret; - ret = net_context_get(family, SOCK_DGRAM, IPPROTO_UDP, &ctx); + ret = zsock_socket(family, SOCK_DGRAM, IPPROTO_UDP); if (ret < 0) { + ret = -errno; NET_DBG("Cannot get context (%d)", ret); - return NULL; } - return ctx; + return ret; } -static int bind_ctx(struct net_context *ctx, +static int bind_ctx(int sock, struct sockaddr *local_addr, socklen_t addrlen) { int ret; - if (!ctx) { + if (sock < 0) { return -EINVAL; } - ret = net_context_bind(ctx, local_addr, addrlen); + ret = zsock_bind(sock, local_addr, addrlen); if (ret < 0) { - NET_DBG("Cannot bind to mDNS %s port (%d)", + NET_DBG("Cannot bind to %s %s port (%d)", "mDNS", local_addr->sa_family == AF_INET ? "IPv4" : "IPv6", ret); - return ret; } return ret; @@ -230,7 +257,7 @@ static void add_answer(struct net_buf *query, enum dns_rr_type qtype, memcpy(query->data + offset, addr, addr_len); } -static int create_answer(struct net_context *ctx, +static int create_answer(int sock, struct net_buf *query, enum dns_rr_type qtype, uint16_t addr_len, uint8_t *addr) @@ -238,7 +265,7 @@ static int create_answer(struct net_context *ctx, /* Prepare the response into the query buffer: move the name * query buffer has to get enough free space: dns_hdr + answer */ - if ((query->size - query->len) < (DNS_MSG_HEADER_SIZE + + if ((net_buf_max_len(query) - query->len) < (DNS_MSG_HEADER_SIZE + DNS_QTYPE_LEN + DNS_QCLASS_LEN + DNS_TTL_LEN + DNS_RDLENGTH_LEN + addr_len)) { @@ -258,28 +285,37 @@ static int create_answer(struct net_context *ctx, return 0; } -static int send_response(struct net_context *ctx, - struct net_if *iface, +static int send_response(int sock, sa_family_t family, - const void *src_addr, + struct sockaddr *src_addr, + size_t addrlen, struct net_buf *query, enum dns_rr_type qtype) { - struct sockaddr dst; + struct net_if *iface; socklen_t dst_len; int ret; + COND_CODE_1(IS_ENABLED(CONFIG_NET_IPV6), + (struct sockaddr_in6), (struct sockaddr_in)) dst; - ret = setup_dst_addr(ctx, family, &dst, &dst_len); + ret = setup_dst_addr(sock, family, (struct sockaddr *)&dst, &dst_len); if (ret < 0) { NET_DBG("unable to set up the response address"); return ret; } + if (family == AF_INET6) { + iface = net_if_ipv6_select_src_iface(&net_sin6(src_addr)->sin6_addr); + } else { + iface = net_if_ipv4_select_src_iface(&net_sin(src_addr)->sin_addr); + } + if (IS_ENABLED(CONFIG_NET_IPV4) && qtype == DNS_RR_TYPE_A) { const struct in_addr *addr; if (family == AF_INET) { - addr = net_if_ipv4_select_src_addr(iface, (struct in_addr *)src_addr); + addr = net_if_ipv4_select_src_addr(iface, + &net_sin(src_addr)->sin_addr); } else { struct sockaddr_in tmp_addr; @@ -287,7 +323,7 @@ static int send_response(struct net_context *ctx, addr = net_if_ipv4_select_src_addr(iface, &tmp_addr.sin_addr); } - ret = create_answer(ctx, query, qtype, sizeof(struct in_addr), (uint8_t *)addr); + ret = create_answer(sock, query, qtype, sizeof(struct in_addr), (uint8_t *)addr); if (ret != 0) { return ret; } @@ -295,7 +331,8 @@ static int send_response(struct net_context *ctx, const struct in6_addr *addr; if (family == AF_INET6) { - addr = net_if_ipv6_select_src_addr(iface, (struct in6_addr *)src_addr); + addr = net_if_ipv6_select_src_addr(iface, + &net_sin6(src_addr)->sin6_addr); } else { struct sockaddr_in6 tmp_addr; @@ -303,7 +340,7 @@ static int send_response(struct net_context *ctx, addr = net_if_ipv6_select_src_addr(iface, &tmp_addr.sin6_addr); } - ret = create_answer(ctx, query, qtype, sizeof(struct in6_addr), (uint8_t *)addr); + ret = create_answer(sock, query, qtype, sizeof(struct in6_addr), (uint8_t *)addr); if (ret != 0) { return -ENOMEM; } @@ -312,10 +349,10 @@ static int send_response(struct net_context *ctx, return -EINVAL; } - ret = net_context_sendto(ctx, query->data, query->len, &dst, - dst_len, NULL, K_NO_WAIT, NULL); + ret = zsock_sendto(sock, query->data, query->len, 0, + (struct sockaddr *)&dst, dst_len); if (ret < 0) { - NET_DBG("Cannot send mDNS reply (%d)", ret); + NET_DBG("Cannot send %s reply (%d)", "mDNS", ret); } return ret; @@ -334,19 +371,19 @@ static const char *qtype_to_string(int qtype) } } -static void send_sd_response(struct net_context *ctx, - struct net_if *iface, +static void send_sd_response(int sock, sa_family_t family, - const void *src_addr, + struct sockaddr *src_addr, + size_t addrlen, struct dns_msg_t *dns_msg, struct net_buf *result) { + struct net_if *iface; + socklen_t dst_len; int ret; const struct dns_sd_rec *record; /* filter must be zero-initialized for "wildcard" port */ struct dns_sd_rec filter = {0}; - struct sockaddr dst; - socklen_t dst_len; bool service_type_enum = false; const struct in6_addr *addr6 = NULL; const struct in_addr *addr4 = NULL; @@ -364,6 +401,8 @@ static void send_sd_response(struct net_context *ctx, size_t n = ARRAY_SIZE(label); size_t rec_num; size_t ext_rec_num = external_records_count; + COND_CODE_1(IS_ENABLED(CONFIG_NET_IPV6), + (struct sockaddr_in6), (struct sockaddr_in)) dst; BUILD_ASSERT(ARRAY_SIZE(label) == ARRAY_SIZE(size), ""); @@ -376,16 +415,23 @@ static void send_sd_response(struct net_context *ctx, label[2] = proto_buf; label[3] = domain_buf; - ret = setup_dst_addr(ctx, family, &dst, &dst_len); + ret = setup_dst_addr(sock, family, (struct sockaddr *)&dst, &dst_len); if (ret < 0) { NET_DBG("unable to set up the response address"); return; } + if (family == AF_INET6) { + iface = net_if_ipv6_select_src_iface(&net_sin6(src_addr)->sin6_addr); + } else { + iface = net_if_ipv4_select_src_iface(&net_sin(src_addr)->sin_addr); + } + if (IS_ENABLED(CONFIG_NET_IPV4)) { /* Look up the local IPv4 address */ if (family == AF_INET) { - addr4 = net_if_ipv4_select_src_addr(iface, (struct in_addr *)src_addr); + addr4 = net_if_ipv4_select_src_addr(iface, + &net_sin(src_addr)->sin_addr); } else { struct sockaddr_in tmp_addr; @@ -397,7 +443,8 @@ static void send_sd_response(struct net_context *ctx, if (IS_ENABLED(CONFIG_NET_IPV6)) { /* Look up the local IPv6 address */ if (family == AF_INET6) { - addr6 = net_if_ipv6_select_src_addr(iface, (struct in6_addr *)src_addr); + addr6 = net_if_ipv6_select_src_addr(iface, + &net_sin6(src_addr)->sin6_addr); } else { struct sockaddr_in6 tmp_addr; @@ -453,7 +500,7 @@ static void send_sd_response(struct net_context *ctx, /* Construct the response */ if (service_type_enum) { ret = dns_sd_handle_service_type_enum(record, addr4, addr6, - result->data, result->size); + result->data, net_buf_max_len(result)); if (ret < 0) { NET_DBG("dns_sd_handle_service_type_enum() failed (%d)", ret); @@ -461,7 +508,7 @@ static void send_sd_response(struct net_context *ctx, } } else { ret = dns_sd_handle_ptr_query(record, addr4, addr6, - result->data, result->size); + result->data, net_buf_max_len(result)); if (ret < 0) { NET_DBG("dns_sd_handle_ptr_query() failed (%d)", ret); continue; @@ -471,20 +518,21 @@ static void send_sd_response(struct net_context *ctx, result->len = ret; /* Send the response */ - ret = net_context_sendto(ctx, result->data, - result->len, &dst, dst_len, NULL, - K_NO_WAIT, NULL); + ret = zsock_sendto(sock, result->data, result->len, 0, + (struct sockaddr *)&dst, dst_len); if (ret < 0) { - NET_DBG("Cannot send mDNS reply (%d)", ret); + NET_DBG("Cannot send %s reply (%d)", "mDNS", ret); continue; } } } } -static int dns_read(struct net_context *ctx, - struct net_pkt *pkt, +static int dns_read(int sock, struct net_buf *dns_data, + size_t len, + struct sockaddr *src_addr, + size_t addrlen, struct dns_addrinfo *info) { /* Helper struct to track the dns msg received from the server */ @@ -492,12 +540,13 @@ static int dns_read(struct net_context *ctx, int hostname_len = strlen(hostname); struct net_buf *result; struct dns_msg_t dns_msg; - const void *src_addr; + socklen_t optlen; int data_len; int queries; + int family; int ret; - data_len = MIN(net_pkt_remaining_data(pkt), DNS_RESOLVER_MAX_BUF_SIZE); + data_len = MIN(len, DNS_RESOLVER_MAX_BUF_SIZE); /* Store the DNS query name into a temporary net_buf, which will be * eventually used to send a response @@ -508,13 +557,6 @@ static int dns_read(struct net_context *ctx, goto quit; } - /* TODO: Instead of this temporary copy, just use the net_pkt directly. - */ - ret = net_pkt_read(pkt, dns_data->data, data_len); - if (ret < 0) { - goto quit; - } - dns_msg.msg = dns_data->data; dns_msg.msg_size = data_len; @@ -526,12 +568,15 @@ static int dns_read(struct net_context *ctx, queries = ret; - src_addr = net_pkt_family(pkt) == AF_INET - ? (const void *)&NET_IPV4_HDR(pkt)->src : (const void *)&NET_IPV6_HDR(pkt)->src; + optlen = sizeof(int); + (void)zsock_getsockopt(sock, SOL_SOCKET, SO_DOMAIN, &family, &optlen); NET_DBG("Received %d %s from %s", queries, queries > 1 ? "queries" : "query", - net_sprint_addr(net_pkt_family(pkt), src_addr)); + net_sprint_addr(family, + family == AF_INET ? + (const void *)&net_sin(src_addr)->sin_addr : + (const void *)&net_sin6(src_addr)->sin6_addr)); do { enum dns_rr_type qtype; @@ -563,13 +608,13 @@ static int dns_read(struct net_context *ctx, if (!strncasecmp(hostname, result->data + 1, hostname_len) && (result->len - 1) >= hostname_len && &(result->data + 1)[hostname_len] == lquery) { - NET_DBG("mDNS query to our hostname %s.local", + NET_DBG("%s query to our hostname %s.local", "mDNS", hostname); - send_response(ctx, net_pkt_iface(pkt), net_pkt_family(pkt), src_addr, + send_response(sock, family, src_addr, addrlen, result, qtype); } else if (IS_ENABLED(CONFIG_MDNS_RESPONDER_DNS_SD) && qtype == DNS_RR_TYPE_PTR) { - send_sd_response(ctx, net_pkt_iface(pkt), net_pkt_family(pkt), src_addr, + send_sd_response(sock, family, src_addr, addrlen, &dns_msg, result); } @@ -585,45 +630,69 @@ static int dns_read(struct net_context *ctx, return ret; } -static void recv_cb(struct net_context *net_ctx, - struct net_pkt *pkt, - union net_ip_header *ip_hdr, - union net_proto_header *proto_hdr, - int status, - void *user_data) +static int recv_data(struct net_socket_service_event *pev) { - struct net_context *ctx = user_data; + COND_CODE_1(IS_ENABLED(CONFIG_NET_IPV6), + (struct sockaddr_in6), (struct sockaddr_in)) addr; struct net_buf *dns_data = NULL; struct dns_addrinfo info = { 0 }; - int ret; - - ARG_UNUSED(net_ctx); - ARG_UNUSED(ip_hdr); - ARG_UNUSED(proto_hdr); - NET_ASSERT(ctx == net_ctx); - - if (!pkt) { - return; - } - - if (status) { + size_t addrlen = sizeof(addr); + int ret, family, sock_error, len; + socklen_t optlen; + + if ((pev->event.revents & ZSOCK_POLLERR) || + (pev->event.revents & ZSOCK_POLLNVAL)) { + (void)zsock_getsockopt(pev->event.fd, SOL_SOCKET, + SO_DOMAIN, &family, &optlen); + (void)zsock_getsockopt(pev->event.fd, SOL_SOCKET, + SO_ERROR, &sock_error, &optlen); + NET_ERR("Receiver IPv%d socket error (%d)", + family == AF_INET ? 4 : 6, sock_error); + ret = DNS_EAI_SYSTEM; goto quit; } dns_data = net_buf_alloc(&mdns_msg_pool, BUF_ALLOC_TIMEOUT); if (!dns_data) { + ret = -ENOENT; goto quit; } - ret = dns_read(ctx, pkt, dns_data, &info); + ret = zsock_recvfrom(pev->event.fd, dns_data->data, + net_buf_max_len(dns_data), 0, + (struct sockaddr *)&addr, &addrlen); + if (ret < 0) { + ret = -errno; + NET_ERR("recv failed on IPv%d socket (%d)", + family == AF_INET ? 4 : 6, -ret); + goto free_buf; + } + + len = ret; + + ret = dns_read(pev->event.fd, dns_data, len, + (struct sockaddr *)&addr, addrlen, &info); if (ret < 0 && ret != -EINVAL) { - NET_DBG("mDNS read failed (%d)", ret); + NET_DBG("%s read failed (%d)", "mDNS", ret); } +free_buf: net_buf_unref(dns_data); quit: - net_pkt_unref(pkt); + return ret; +} + +static void svc_handler(struct k_work *work) +{ + struct net_socket_service_event *pev = + CONTAINER_OF(work, struct net_socket_service_event, work); + int ret; + + ret = recv_data(pev); + if (ret < 0) { + NET_ERR("DNS recv error (%d)", ret); + } } #if defined(CONFIG_NET_IPV6) @@ -683,14 +752,22 @@ static void setup_ipv4_addr(struct sockaddr_in *local_addr) } #endif /* CONFIG_NET_IPV4 */ +#if defined(CONFIG_NET_INTERFACE_NAME_LEN) +#define INTERFACE_NAME_LEN CONFIG_NET_INTERFACE_NAME_LEN +#else +#define INTERFACE_NAME_LEN 0 +#endif + static int init_listener(void) { - int ret, ok = 0, i; + int ret, ok = 0, i, ifindex; + char name[INTERFACE_NAME_LEN + 1]; + struct ifreq if_req; struct net_if *iface; int iface_count; NET_IFACE_COUNT(&iface_count); - NET_DBG("Setting mDNS listener to %d interface%s", iface_count, + NET_DBG("Setting %s listener to %d interface%s", "mDNS", iface_count, iface_count > 1 ? "s" : ""); if ((iface_count > MAX_IPV6_IFACE_COUNT && MAX_IPV6_IFACE_COUNT > 0) || @@ -701,39 +778,82 @@ static int init_listener(void) MAX_IPV6_IFACE_COUNT), iface_count); } + ARRAY_FOR_EACH(fds, j) { + fds[j].fd = -1; + } + #if defined(CONFIG_NET_IPV6) struct sockaddr_in6 local_addr6; - struct net_context *v6; + int v6; setup_ipv6_addr(&local_addr6); for (i = 0; i < MAX_IPV6_IFACE_COUNT; i++) { - v6 = get_ctx(AF_INET6); - if (v6 == NULL) { - NET_ERR("Cannot get %s context out of %d. Max contexts is %d", + v6 = get_socket(AF_INET6); + if (v6 < 0) { + NET_ERR("Cannot get %s socket out of %d. Max sockets is %d", "IPv6", MAX_IPV6_IFACE_COUNT, CONFIG_NET_MAX_CONTEXTS); continue; } iface = net_if_get_by_index(i + 1); if (iface == NULL) { - net_context_unref(v6); + zsock_close(v6); continue; } - net_context_bind_iface(v6, iface); + ifindex = net_if_get_by_iface(iface); + + ret = net_if_get_name(iface, name, INTERFACE_NAME_LEN); + if (ret < 0) { + NET_DBG("Cannot get interface name for %d (%d)", + ifindex, ret); + } else { + memset(&if_req, 0, sizeof(if_req)); + strncpy(if_req.ifr_name, name, sizeof(if_req.ifr_name)); + + ret = zsock_setsockopt(v6, SOL_SOCKET, SO_BINDTODEVICE, + &if_req, sizeof(if_req)); + if (ret < 0) { + NET_DBG("Cannot bind sock %d to interface %d (%d)", + v6, ifindex, ret); + } + } ret = bind_ctx(v6, (struct sockaddr *)&local_addr6, sizeof(local_addr6)); if (ret < 0) { - net_context_put(v6); + zsock_close(v6); goto ipv6_out; } - ret = net_context_recv(v6, recv_cb, K_NO_WAIT, v6); + ret = -ENOENT; + + ARRAY_FOR_EACH(fds, j) { + if (fds[j].fd == v6) { + ret = 0; + break; + } + + if (fds[j].fd < 0) { + fds[j].fd = v6; + fds[j].events = ZSOCK_POLLIN; + ret = 0; + break; + } + } + + if (ret < 0) { + NET_DBG("Cannot set %s to socket (%d)", "polling", ret); + zsock_close(v6); + continue; + } + + ret = net_socket_service_register(&svc_mdns, fds, ARRAY_SIZE(fds), NULL); if (ret < 0) { - NET_WARN("Cannot receive %s mDNS data (%d)", "IPv6", ret); - net_context_put(v6); + NET_DBG("Cannot register %s %s socket service (%d)", + "IPv6", "mDNS", ret); + zsock_close(v6); } else { ipv6[i] = v6; ok++; @@ -746,37 +866,76 @@ static int init_listener(void) #endif /* CONFIG_NET_IPV6 */ #if defined(CONFIG_NET_IPV4) - struct net_context *v4; + int v4; setup_ipv4_addr(&local_addr4); for (i = 0; i < MAX_IPV4_IFACE_COUNT; i++) { - v4 = get_ctx(AF_INET); - if (v4 == NULL) { - NET_ERR("Cannot get %s context out of %d. Max contexts is %d", + v4 = get_socket(AF_INET); + if (v4 < 0) { + NET_ERR("Cannot get %s socket out of %d. Max sockets is %d", "IPv4", MAX_IPV4_IFACE_COUNT, CONFIG_NET_MAX_CONTEXTS); continue; } iface = net_if_get_by_index(i + 1); if (iface == NULL) { - net_context_unref(v4); + zsock_close(v4); continue; } - net_context_bind_iface(v4, iface); + ifindex = net_if_get_by_iface(iface); + + ret = net_if_get_name(iface, name, INTERFACE_NAME_LEN); + if (ret < 0) { + NET_DBG("Cannot get interface name for %d (%d)", + ifindex, ret); + } else { + memset(&if_req, 0, sizeof(if_req)); + strncpy(if_req.ifr_name, name, sizeof(if_req.ifr_name)); + + ret = zsock_setsockopt(v4, SOL_SOCKET, SO_BINDTODEVICE, + &if_req, sizeof(if_req)); + if (ret < 0) { + NET_DBG("Cannot bind sock %d to interface %d (%d)", + v4, ifindex, ret); + } + } ret = bind_ctx(v4, (struct sockaddr *)&local_addr4, sizeof(local_addr4)); if (ret < 0) { - net_context_put(v4); + zsock_close(v4); goto ipv4_out; } - ret = net_context_recv(v4, recv_cb, K_NO_WAIT, v4); + ret = -ENOENT; + + ARRAY_FOR_EACH(fds, j) { + if (fds[j].fd == v4) { + ret = 0; + break; + } + + if (fds[j].fd < 0) { + fds[j].fd = v4; + fds[j].events = ZSOCK_POLLIN; + ret = 0; + break; + } + } + + if (ret < 0) { + NET_DBG("Cannot set %s to socket (%d)", "polling", ret); + zsock_close(v4); + continue; + } + + ret = net_socket_service_register(&svc_mdns, fds, ARRAY_SIZE(fds), NULL); if (ret < 0) { - NET_WARN("Cannot receive %s mDNS data (%d)", "IPv4", ret); - net_context_put(v4); + NET_DBG("Cannot register %s %s socket service (%d)", + "IPv4", "mDNS", ret); + zsock_close(v4); } else { ipv4[i] = v4; ok++; @@ -786,7 +945,7 @@ static int init_listener(void) #endif /* CONFIG_NET_IPV4 */ if (!ok) { - NET_WARN("Cannot start mDNS responder"); + NET_WARN("Cannot start %s responder", "mDNS"); } return !ok; diff --git a/subsys/net/lib/dns/resolve.c b/subsys/net/lib/dns/resolve.c index 37032f4de45..3e7a22923bc 100644 --- a/subsys/net/lib/dns/resolve.c +++ b/subsys/net/lib/dns/resolve.c @@ -6,6 +6,7 @@ /* * Copyright (c) 2017 Intel Corporation + * Copyright (c) 2024 Nordic Semiconductor * * SPDX-License-Identifier: Apache-2.0 */ @@ -24,6 +25,7 @@ LOG_MODULE_REGISTER(net_dns_resolve, CONFIG_DNS_RESOLVER_LOG_LEVEL); #include #include #include +#include #include "dns_pack.h" #include "dns_internal.h" #include "dns_cache.h" @@ -62,6 +64,11 @@ LOG_MODULE_REGISTER(net_dns_resolve, CONFIG_DNS_RESOLVER_LOG_LEVEL); #define DNS_IPV4_LEN sizeof(struct in_addr) #define DNS_IPV6_LEN sizeof(struct in6_addr) +static void svc_handler(struct k_work *work); +static int init_called; + +NET_SOCKET_SERVICE_SYNC_DEFINE_STATIC(svc, NULL, svc_handler, DNS_RESOLVER_MAX_POLL); + NET_BUF_POOL_DEFINE(dns_msg_pool, DNS_RESOLVER_BUF_CTR, DNS_RESOLVER_MAX_BUF_SIZE, 0, NULL); @@ -78,7 +85,7 @@ static struct dns_resolve_context dns_default_ctx; static int dns_write(struct dns_resolve_context *ctx, int server_idx, int query_idx, - struct net_buf *dns_data, + uint8_t *buf, size_t buf_len, size_t max_len, struct net_buf *dns_qname, int hop_limit); @@ -213,6 +220,14 @@ static int dns_resolve_init_locked(struct dns_resolve_context *ctx, goto fail; } + ARRAY_FOR_EACH(ctx->servers, j) { + ctx->servers[j].sock = -1; + } + + ARRAY_FOR_EACH(ctx->fds, j) { + ctx->fds[j].fd = -1; + } + if (servers) { for (i = 0; idx < SERVER_COUNT && servers[i]; i++) { struct sockaddr *addr = &ctx->servers[idx].dns_server; @@ -283,22 +298,28 @@ static int dns_resolve_init_locked(struct dns_resolve_context *ctx, goto fail; } - ret = net_context_get(ctx->servers[i].dns_server.sa_family, - SOCK_DGRAM, IPPROTO_UDP, - &ctx->servers[i].net_ctx); + ret = zsock_socket(ctx->servers[i].dns_server.sa_family, + SOCK_DGRAM, IPPROTO_UDP); if (ret < 0) { - NET_DBG("Cannot get net_context (%d)", ret); + NET_DBG("Cannot get socket (%d)", ret); goto fail; } - ret = net_context_bind(ctx->servers[i].net_ctx, - local_addr, addr_len); + ctx->servers[i].sock = ret; + + ret = zsock_bind(ctx->servers[i].sock, local_addr, addr_len); if (ret < 0) { NET_DBG("Cannot bind DNS context (%d)", ret); goto fail; } - iface = net_context_get_iface(ctx->servers[i].net_ctx); + if (ctx->servers[i].dns_server.sa_family == AF_INET6) { + iface = net_if_ipv6_select_src_iface( + &net_sin6(&ctx->servers[i].dns_server)->sin6_addr); + } else { + iface = net_if_ipv4_select_src_iface( + &net_sin(&ctx->servers[i].dns_server)->sin_addr); + } if (IS_ENABLED(CONFIG_NET_MGMT_EVENT_INFO)) { net_mgmt_event_notify_with_info( @@ -327,6 +348,7 @@ static int dns_resolve_init_locked(struct dns_resolve_context *ctx, goto fail; } + init_called++; ctx->state = DNS_RESOLVE_CONTEXT_ACTIVE; ctx->buf_timeout = DNS_BUF_TIMEOUT; ret = 0; @@ -689,7 +711,7 @@ int dns_validate_msg(struct dns_resolve_context *ctx, if (dns_cname) { ret = dns_copy_qname(dns_cname->data, &dns_cname->len, - dns_cname->size, + net_buf_max_len(dns_cname), dns_msg, pos); if (ret < 0) { ret = DNS_EAI_SYSTEM; @@ -714,8 +736,7 @@ int dns_validate_msg(struct dns_resolve_context *ctx, /* Must be invoked with context lock held */ static int dns_read(struct dns_resolve_context *ctx, - struct net_pkt *pkt, - struct net_buf *dns_data, + struct net_buf *dns_data, size_t buf_len, uint16_t *dns_id, struct net_buf *dns_cname, uint16_t *query_hash) @@ -726,15 +747,7 @@ static int dns_read(struct dns_resolve_context *ctx, int ret; int query_idx = -1; - data_len = MIN(net_pkt_remaining_data(pkt), DNS_RESOLVER_MAX_BUF_SIZE); - - /* TODO: Instead of this temporary copy, just use the net_pkt directly. - */ - ret = net_pkt_read(pkt, dns_data->data, data_len); - if (ret < 0) { - ret = DNS_EAI_MEMORY; - goto quit; - } + data_len = MIN(buf_len, DNS_RESOLVER_MAX_BUF_SIZE); dns_msg.msg = dns_data->data; dns_msg.msg_size = data_len; @@ -755,8 +768,6 @@ static int dns_read(struct dns_resolve_context *ctx, /* Marks the end of the results */ release_query(&ctx->queries[query_idx]); - net_pkt_unref(pkt); - return 0; finished: @@ -764,26 +775,22 @@ static int dns_read(struct dns_resolve_context *ctx, ctx->queries[query_idx].query, ctx->queries[query_idx].query_type); quit: - net_pkt_unref(pkt); - return ret; } -static void cb_recv(struct net_context *net_ctx, - struct net_pkt *pkt, - union net_ip_header *ip_hdr, - union net_proto_header *proto_hdr, - int status, - void *user_data) +static int recv_data(struct net_socket_service_event *pev) { - struct dns_resolve_context *ctx = user_data; + COND_CODE_1(IS_ENABLED(CONFIG_NET_IPV6), + (struct sockaddr_in6), (struct sockaddr_in)) addr; + struct dns_resolve_context *ctx = pev->user_data; + socklen_t optlen = sizeof(int); + size_t addrlen = sizeof(addr); struct net_buf *dns_cname = NULL; struct net_buf *dns_data = NULL; uint16_t query_hash = 0U; uint16_t dns_id = 0U; - int ret, i; - - ARG_UNUSED(net_ctx); + int family = AF_UNSPEC, sock_error; + int ret = 0, i, len; k_mutex_lock(&ctx->lock, K_FOREVER); @@ -791,24 +798,43 @@ static void cb_recv(struct net_context *net_ctx, goto unlock; } - if (status) { + if ((pev->event.revents & ZSOCK_POLLERR) || + (pev->event.revents & ZSOCK_POLLNVAL)) { + (void)zsock_getsockopt(pev->event.fd, SOL_SOCKET, + SO_DOMAIN, &family, &optlen); + (void)zsock_getsockopt(pev->event.fd, SOL_SOCKET, + SO_ERROR, &sock_error, &optlen); + NET_ERR("Receiver IPv%d socket error (%d)", + family == AF_INET ? 4 : 6, sock_error); ret = DNS_EAI_SYSTEM; - goto quit; + goto unlock; } dns_data = net_buf_alloc(&dns_msg_pool, ctx->buf_timeout); if (!dns_data) { ret = DNS_EAI_MEMORY; - goto quit; + goto free_buf; } dns_cname = net_buf_alloc(&dns_qname_pool, ctx->buf_timeout); if (!dns_cname) { ret = DNS_EAI_MEMORY; - goto quit; + goto free_buf; } - ret = dns_read(ctx, pkt, dns_data, &dns_id, dns_cname, &query_hash); + ret = zsock_recvfrom(pev->event.fd, dns_data->data, + net_buf_max_len(dns_data), 0, + (struct sockaddr *)&addr, &addrlen); + if (ret < 0) { + ret = -errno; + NET_ERR("recv failed on IPv%d socket (%d)", + family == AF_INET ? 4 : 6, -ret); + goto free_buf; + } + + len = ret; + + ret = dns_read(ctx, dns_data, len, &dns_id, dns_cname, &query_hash); if (!ret) { /* We called the callback already in dns_read() if there * was no errors. @@ -827,11 +853,13 @@ static void cb_recv(struct net_context *net_ctx, } for (j = 0; j < SERVER_COUNT; j++) { - if (!ctx->servers[j].net_ctx) { + if (ctx->servers[j].sock < 0) { continue; } - ret = dns_write(ctx, j, i, dns_data, dns_cname, 0); + ret = dns_write(ctx, j, i, dns_data->data, len, + net_buf_max_len(dns_data), + dns_cname, 0); if (ret < 0) { failure++; } @@ -871,29 +899,50 @@ static void cb_recv(struct net_context *net_ctx, unlock: k_mutex_unlock(&ctx->lock); + + return ret; +} + +static void svc_handler(struct k_work *work) +{ + struct net_socket_service_event *pev = + CONTAINER_OF(work, struct net_socket_service_event, work); + int ret; + + ret = recv_data(pev); + if (ret < 0) { + NET_ERR("DNS recv error (%d)", ret); + } +} + +static int set_ttl_hop_limit(int sock, int level, int option, int new_limit) +{ + return zsock_setsockopt(sock, level, option, &new_limit, sizeof(new_limit)); } /* Must be invoked with context lock held */ static int dns_write(struct dns_resolve_context *ctx, int server_idx, int query_idx, - struct net_buf *dns_data, + uint8_t *buf, size_t buf_len, size_t max_len, struct net_buf *dns_qname, int hop_limit) { enum dns_query_type query_type; - struct net_context *net_ctx; struct sockaddr *server; int server_addr_len; - uint16_t dns_id; - int ret; + uint16_t dns_id, len; + int ret, sock, family; - net_ctx = ctx->servers[server_idx].net_ctx; + sock = ctx->servers[server_idx].sock; + family = ctx->servers[server_idx].dns_server.sa_family; server = &ctx->servers[server_idx].dns_server; dns_id = ctx->queries[query_idx].id; query_type = ctx->queries[query_idx].query_type; - ret = dns_msg_pack_query(dns_data->data, &dns_data->len, dns_data->size, + len = buf_len; + + ret = dns_msg_pack_query(buf, &len, (uint16_t)max_len, dns_qname->data, dns_qname->len, dns_id, (enum dns_rr_type)query_type); if (ret < 0) { @@ -904,26 +953,58 @@ static int dns_write(struct dns_resolve_context *ctx, * the dns_qname->len contains the length of \0 */ ctx->queries[query_idx].query_hash = - crc16_ansi(dns_data->data + DNS_MSG_HEADER_SIZE, - dns_qname->len + 2); - - if (IS_ENABLED(CONFIG_NET_IPV6) && - net_context_get_family(net_ctx) == AF_INET6 && - hop_limit > 0) { - net_context_set_ipv6_hop_limit(net_ctx, hop_limit); - } else if (IS_ENABLED(CONFIG_NET_IPV4) && - net_context_get_family(net_ctx) == AF_INET && - hop_limit > 0) { - net_context_set_ipv4_ttl(net_ctx, hop_limit); - } - - ret = net_context_recv(net_ctx, cb_recv, K_NO_WAIT, ctx); - if (ret < 0 && ret != -EALREADY) { - NET_DBG("Could not receive from socket (%d)", ret); + crc16_ansi(buf + DNS_MSG_HEADER_SIZE, dns_qname->len + 2); + + if (hop_limit > 0) { + if (IS_ENABLED(CONFIG_NET_IPV6) && family == AF_INET6) { + ret = set_ttl_hop_limit(sock, IPPROTO_IPV6, + IPV6_UNICAST_HOPS, + hop_limit); + } else if (IS_ENABLED(CONFIG_NET_IPV4) && family == AF_INET) { + ret = set_ttl_hop_limit(sock, IPPROTO_IP, IP_TTL, + hop_limit); + } else { + ret = -ENOTSUP; + } + + if (ret < 0) { + NET_DBG("Cannot set %s to socket (%d)", + family == AF_INET6 ? "hop limit" : + (family == AF_INET ? "TTL" : ""), + ret); + return ret; + } + } + + ret = -ENOENT; + + ARRAY_FOR_EACH(ctx->fds, i) { + if (ctx->fds[i].fd == sock) { + /* There was query to this server already */ + ret = 0; + break; + } + + if (ctx->fds[i].fd < 0) { + ctx->fds[i].fd = sock; + ctx->fds[i].events = ZSOCK_POLLIN; + ret = 0; + break; + } + } + + if (ret < 0) { + NET_DBG("Cannot set %s to socket (%d)", "polling", ret); + return ret; + } + + ret = net_socket_service_register(&svc, ctx->fds, ARRAY_SIZE(ctx->fds), ctx); + if (ret < 0) { + NET_DBG("Cannot register socket service (%d)", ret); return ret; } - if (server->sa_family == AF_INET) { + if (family == AF_INET) { server_addr_len = sizeof(struct sockaddr_in); } else { server_addr_len = sizeof(struct sockaddr_in6); @@ -941,9 +1022,7 @@ static int dns_write(struct dns_resolve_context *ctx, "hash %u", query_idx, server_idx, dns_id, ctx->queries[query_idx].query_hash); - ret = net_context_sendto(net_ctx, dns_data->data, dns_data->len, - server, server_addr_len, NULL, - K_NO_WAIT, NULL); + ret = zsock_sendto(sock, buf, len, 0, server, server_addr_len); if (ret < 0) { NET_DBG("Cannot send query (%d)", ret); return ret; @@ -1028,13 +1107,14 @@ int dns_resolve_cancel_with_name(struct dns_resolve_context *ctx, return -ENOMEM; } - ret = dns_msg_pack_qname(&len, buf->data, buf->size, + ret = dns_msg_pack_qname(&len, buf->data, + net_buf_max_len(buf), query_name); if (ret >= 0) { /* If the query string + \0 + query type (A or AAAA) * does not fit the tmp buf, then bail out */ - if ((len + 2) > buf->size) { + if ((len + 2) > net_buf_max_len(buf)) { net_buf_unref(buf); return -ENOMEM; } @@ -1274,7 +1354,7 @@ int dns_resolve_name(struct dns_resolve_context *ctx, for (j = 0; j < SERVER_COUNT; j++) { hop_limit = 0U; - if (!ctx->servers[j].net_ctx) { + if (ctx->servers[j].sock < 0) { continue; } @@ -1297,7 +1377,10 @@ int dns_resolve_name(struct dns_resolve_context *ctx, hop_limit = 1U; } - ret = dns_write(ctx, j, i, dns_data, dns_qname, hop_limit); + ret = dns_write(ctx, j, i, dns_data->data, + net_buf_max_len(dns_data), + net_buf_max_len(dns_data), + dns_qname, hop_limit); if (ret < 0) { failure++; continue; @@ -1369,25 +1452,45 @@ static int dns_resolve_close_locked(struct dns_resolve_context *ctx) k_mutex_unlock(&ctx->lock); for (i = 0; i < SERVER_COUNT; i++) { - if (ctx->servers[i].net_ctx) { - struct net_if *iface; + struct net_if *iface; - iface = net_context_get_iface(ctx->servers[i].net_ctx); + if (ctx->servers[i].sock < 0) { + continue; + } - if (IS_ENABLED(CONFIG_NET_MGMT_EVENT_INFO)) { - net_mgmt_event_notify_with_info( - NET_EVENT_DNS_SERVER_DEL, - iface, - (void *)&ctx->servers[i].dns_server, - sizeof(struct sockaddr)); - } else { - net_mgmt_event_notify(NET_EVENT_DNS_SERVER_DEL, - iface); - } + if (ctx->servers[i].dns_server.sa_family == AF_INET6) { + iface = net_if_ipv6_select_src_iface( + &net_sin6(&ctx->servers[i].dns_server)->sin6_addr); + } else { + iface = net_if_ipv4_select_src_iface( + &net_sin(&ctx->servers[i].dns_server)->sin_addr); + } - net_context_put(ctx->servers[i].net_ctx); - ctx->servers[i].net_ctx = NULL; + if (IS_ENABLED(CONFIG_NET_MGMT_EVENT_INFO)) { + net_mgmt_event_notify_with_info( + NET_EVENT_DNS_SERVER_DEL, + iface, + (void *)&ctx->servers[i].dns_server, + sizeof(struct sockaddr)); + } else { + net_mgmt_event_notify(NET_EVENT_DNS_SERVER_DEL, + iface); + } + + zsock_close(ctx->servers[i].sock); + + ARRAY_FOR_EACH(ctx->fds, j) { + if (ctx->fds[j].fd == ctx->servers[i].sock) { + ctx->fds[j].fd = -1; + } } + + ctx->servers[i].sock = -1; + } + + if (--init_called <= 0) { + (void)net_socket_service_unregister(&svc); + init_called = 0; } k_mutex_lock(&ctx->lock, K_FOREVER); diff --git a/subsys/net/lib/http/CMakeLists.txt b/subsys/net/lib/http/CMakeLists.txt index 5d9d4a06a32..b30d12b834e 100644 --- a/subsys/net/lib/http/CMakeLists.txt +++ b/subsys/net/lib/http/CMakeLists.txt @@ -11,3 +11,12 @@ zephyr_include_directories(${ZEPHYR_BASE}/subsys/net/ip) zephyr_library_sources_ifdef(CONFIG_HTTP_PARSER http_parser.c) zephyr_library_sources_ifdef(CONFIG_HTTP_PARSER_URL http_parser_url.c) zephyr_library_sources_ifdef(CONFIG_HTTP_CLIENT http_client.c) +zephyr_library_sources_ifdef(CONFIG_HTTP_SERVER http_server_core.c + http_server_http1.c + http_server_http2.c + http_hpack.c + http_huffman.c) +if(CONFIG_HTTP_SERVER AND CONFIG_WEBSOCKET) + zephyr_library_sources(http_server_ws.c) + zephyr_library_link_libraries_ifdef(CONFIG_MBEDTLS mbedTLS) +endif() diff --git a/subsys/net/lib/http/Kconfig b/subsys/net/lib/http/Kconfig index 789e45827c3..9926b9b1d38 100644 --- a/subsys/net/lib/http/Kconfig +++ b/subsys/net/lib/http/Kconfig @@ -23,22 +23,114 @@ config HTTP_PARSER_STRICT This option enables the strict parsing option config HTTP_CLIENT - bool "HTTP client API [EXPERIMENTAL]" + bool "HTTP client API" select HTTP_PARSER select HTTP_PARSER_URL - select EXPERIMENTAL help HTTP client API config HTTP_SERVER bool "HTTP Server [EXPERIMENTAL]" - select WARN_EXPERIMENTAL + select HTTP_PARSER + select HTTP_PARSER_URL + select EXPERIMENTAL + help + HTTP1 and HTTP2 server support. + +if HTTP_SERVER + +config HTTP_SERVER_STACK_SIZE + int "HTTP server thread stack size" + default 3072 + help + HTTP server thread stack size for processing RX/TX events. + +config HTTP_SERVER_NUM_SERVICES + int "Number of HTTP Server Instances" + default 1 + range 1 100 + help + This setting determines the number of http services that the server supports. + +config HTTP_SERVER_MAX_CLIENTS + int "Max number of HTTP/2 clients" + default 3 + range 1 100 + help + This setting determines the maximum number of HTTP/2 clients that the server can handle at once. + +config HTTP_SERVER_MAX_STREAMS + int "Max number of HTTP/2 streams" + default 10 + range 1 100 + help + This setting determines the maximum number of HTTP/2 streams for each client. + +config HTTP_SERVER_CLIENT_BUFFER_SIZE + int "Client Buffer Size" + default 256 + range 64 1024 help - HTTP server support. - Note: this is a work-in-progress + This setting determines the buffer size for each client. + +config HTTP_SERVER_HUFFMAN_DECODE_BUFFER_SIZE + int "Size of the buffer used for decoding Huffman-encoded strings" + default 256 + range 64 1024 + help + Size of the buffer used for decoding Huffman-encoded strings when + processing HPACK compressed headers. This effectively limits the + maximum length of an individual HTTP header supported. + +config HTTP_SERVER_MAX_URL_LENGTH + int "Maximum HTTP URL Length" + default 256 + range 32 2048 + help + This setting determines the maximum length of the HTTP URL that the server can process. + +config HTTP_SERVER_MAX_CONTENT_TYPE_LENGTH + int "Maximum HTTP Content-Type Length" + default 64 + range 1 128 + help + This setting determines the maximum length of the HTTP Content-Length field. + +config HTTP_SERVER_CLIENT_INACTIVITY_TIMEOUT + int "Client inactivity timeout (seconds)" + default 10 + range 1 86400 + help + This timeout specifies maximum time the client may remain inactive + (i. e. not sending or receiving any data) before the server drops the + connection. + +config HTTP_SERVER_WEBSOCKET + bool "Allow upgrading to Websocket connection" + select WEBSOCKET_CLIENT + select WEBSOCKET + help + If this is enabled, then the user can allow the HTTP connection to be + upgraded to a Websocket connection. The user can then define a Websocket + handler that is called after upgrading to handle the Websocket network + traffic. + +endif + +# Hidden option to avoid having multiple individual options that are ORed together +config HTTP + bool + depends on (HTTP_PARSER_URL || HTTP_PARSER || HTTP_CLIENT || HTTP_SERVER) + default y module = NET_HTTP module-dep = NET_LOG module-str = Log level for HTTP client library module-help = Enables HTTP client code to output debug messages. source "subsys/net/Kconfig.template.log_config.net" + +module = NET_HTTP_SERVER +module-dep = NET_LOG +module-str = Log level for HTTP server library +module-help = Enables HTTP server code to output debug messages. +source "subsys/net/Kconfig.template.log_config.net" diff --git a/subsys/net/lib/http/headers/mlog.h b/subsys/net/lib/http/headers/mlog.h new file mode 100644 index 00000000000..e70c67d2cc4 --- /dev/null +++ b/subsys/net/lib/http/headers/mlog.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023, Emna Rekik + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef MLOG_H_ +#define MLOG_H_ + +#include + +#define LOG_MODULE_REGISTER(x, y) + +#define LOG_INF(fmt, args...) printf("I: " fmt "\n", ##args) +#define LOG_ERR(fmt, args...) printf("E: " fmt "\n", ##args) +#define LOG_DBG(fmt, args...) printf("D: " fmt "\n", ##args) + +#endif diff --git a/subsys/net/lib/http/headers/server_internal.h b/subsys/net/lib/http/headers/server_internal.h new file mode 100644 index 00000000000..557cc26d883 --- /dev/null +++ b/subsys/net/lib/http/headers/server_internal.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2023, Emna Rekik + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef HTTP_SERVER_INTERNAL_H_ +#define HTTP_SERVER_INTERNAL_H_ + +#include + +#include +#include +#include +#include +#include + +/* HTTP1/HTTP2 state handling */ +int handle_http_frame_rst_frame(struct http_client_ctx *client); +int handle_http_frame_goaway(struct http_client_ctx *client); +int handle_http_frame_settings(struct http_client_ctx *client); +int handle_http_frame_priority(struct http_client_ctx *client); +int handle_http_frame_continuation(struct http_client_ctx *client); +int handle_http_frame_window_update(struct http_client_ctx *client); +int handle_http_frame_header(struct http_client_ctx *client); +int handle_http_frame_headers(struct http_client_ctx *client); +int handle_http_frame_data(struct http_client_ctx *client); +int handle_http1_request(struct http_client_ctx *client); +int handle_http1_to_http2_upgrade(struct http_client_ctx *client); +int handle_http1_to_websocket_upgrade(struct http_client_ctx *client); +void http_server_release_client(struct http_client_ctx *client); + +int enter_http1_request(struct http_client_ctx *client); +int enter_http2_request(struct http_client_ctx *client); +int enter_http_done_state(struct http_client_ctx *client); + +/* Others */ +struct http_resource_detail *get_resource_detail(const char *path, int *len, bool is_ws); +int http_server_sendall(struct http_client_ctx *client, const void *buf, size_t len); +void http_client_timer_restart(struct http_client_ctx *client); + +/* TODO Could be static, but currently used in tests. */ +int parse_http_frame_header(struct http_client_ctx *client); +const char *get_frame_type_name(enum http_frame_type type); + +#endif /* HTTP_SERVER_INTERNAL_H_ */ diff --git a/subsys/net/lib/http/http_client.c b/subsys/net/lib/http/http_client.c index 0f73ce6e8f8..58ff1389b47 100644 --- a/subsys/net/lib/http/http_client.c +++ b/subsys/net/lib/http/http_client.c @@ -11,7 +11,7 @@ */ #include -LOG_MODULE_REGISTER(net_http, CONFIG_NET_HTTP_LOG_LEVEL); +LOG_MODULE_REGISTER(net_http_client, CONFIG_NET_HTTP_LOG_LEVEL); #include #include diff --git a/subsys/net/lib/http/http_hpack.c b/subsys/net/lib/http/http_hpack.c new file mode 100644 index 00000000000..bfbad52f423 --- /dev/null +++ b/subsys/net/lib/http/http_hpack.c @@ -0,0 +1,631 @@ +/* + * Copyright (c) 2023, Emna Rekik + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include + +#include +#include +#include + +LOG_MODULE_DECLARE(net_http_server, CONFIG_NET_HTTP_SERVER_LOG_LEVEL); + +static inline bool http_hpack_key_is_static(uint32_t key) +{ + return key > HTTP_SERVER_HPACK_INVALID && key <= HTTP_SERVER_HPACK_WWW_AUTHENTICATE; +} + +static inline bool http_hpack_key_is_dynamic(uint32_t key) +{ + return key > HTTP_SERVER_HPACK_WWW_AUTHENTICATE; +} + +struct hpack_table_entry { + const char *name; + const char *value; +}; + +static const struct hpack_table_entry http_hpack_table_static[] = { + [HTTP_SERVER_HPACK_AUTHORITY] = { ":authority", NULL }, + [HTTP_SERVER_HPACK_METHOD_GET] = { ":method", "GET" }, + [HTTP_SERVER_HPACK_METHOD_POST] = { ":method", "POST" }, + [HTTP_SERVER_HPACK_PATH_ROOT] = { ":path", "/" }, + [HTTP_SERVER_HPACK_PATH_INDEX] = { ":path", "/index.html" }, + [HTTP_SERVER_HPACK_SCHEME_HTTP] = { ":scheme", "http" }, + [HTTP_SERVER_HPACK_SCHEME_HTTPS] = { ":scheme", "https" }, + [HTTP_SERVER_HPACK_STATUS_200] = { ":status", "200" }, + [HTTP_SERVER_HPACK_STATUS_204] = { ":status", "204" }, + [HTTP_SERVER_HPACK_STATUS_206] = { ":status", "206" }, + [HTTP_SERVER_HPACK_STATUS_304] = { ":status", "304" }, + [HTTP_SERVER_HPACK_STATUS_400] = { ":status", "400" }, + [HTTP_SERVER_HPACK_STATUS_404] = { ":status", "404" }, + [HTTP_SERVER_HPACK_STATUS_500] = { ":status", "500" }, + [HTTP_SERVER_HPACK_ACCEPT_CHARSET] = { "accept-charset", NULL }, + [HTTP_SERVER_HPACK_ACCEPT_ENCODING] = { "accept-encoding", "gzip, deflate" }, + [HTTP_SERVER_HPACK_ACCEPT_LANGUAGE] = { "accept-language", NULL }, + [HTTP_SERVER_HPACK_ACCEPT_RANGES] = { "accept-ranges", NULL }, + [HTTP_SERVER_HPACK_ACCEPT] = { "accept", NULL }, + [HTTP_SERVER_HPACK_ACCESS_CONTROL_ALLOW_ORIGIN] = { "access-control-allow-origin", NULL }, + [HTTP_SERVER_HPACK_AGE] = { "age", NULL }, + [HTTP_SERVER_HPACK_ALLOW] = { "allow", NULL }, + [HTTP_SERVER_HPACK_AUTHORIZATION] = { "authorization", NULL }, + [HTTP_SERVER_HPACK_CACHE_CONTROL] = { "cache-control", NULL }, + [HTTP_SERVER_HPACK_CONTENT_DISPOSITION] = { "content-disposition", NULL }, + [HTTP_SERVER_HPACK_CONTENT_ENCODING] = { "content-encoding", NULL }, + [HTTP_SERVER_HPACK_CONTENT_LANGUAGE] = { "content-language", NULL }, + [HTTP_SERVER_HPACK_CONTENT_LENGTH] = { "content-length", NULL }, + [HTTP_SERVER_HPACK_CONTENT_LOCATION] = { "content-location", NULL }, + [HTTP_SERVER_HPACK_CONTENT_RANGE] = { "content-range", NULL }, + [HTTP_SERVER_HPACK_CONTENT_TYPE] = { "content-type", NULL }, + [HTTP_SERVER_HPACK_COOKIE] = { "cookie", NULL }, + [HTTP_SERVER_HPACK_DATE] = { "date", NULL }, + [HTTP_SERVER_HPACK_ETAG] = { "etag", NULL }, + [HTTP_SERVER_HPACK_EXPECT] = { "expect", NULL }, + [HTTP_SERVER_HPACK_EXPIRES] = { "expires", NULL }, + [HTTP_SERVER_HPACK_FROM] = { "from", NULL }, + [HTTP_SERVER_HPACK_HOST] = { "host", NULL }, + [HTTP_SERVER_HPACK_IF_MATCH] = { "if-match", NULL }, + [HTTP_SERVER_HPACK_IF_MODIFIED_SINCE] = { "if-modified-since", NULL }, + [HTTP_SERVER_HPACK_IF_NONE_MATCH] = { "if-none-match", NULL }, + [HTTP_SERVER_HPACK_IF_RANGE] = { "if-range", NULL }, + [HTTP_SERVER_HPACK_IF_UNMODIFIED_SINCE] = { "if-unmodified-since", NULL }, + [HTTP_SERVER_HPACK_LAST_MODIFIED] = { "last-modified", NULL }, + [HTTP_SERVER_HPACK_LINK] = { "link", NULL }, + [HTTP_SERVER_HPACK_LOCATION] = { "location", NULL }, + [HTTP_SERVER_HPACK_MAX_FORWARDS] = { "max-forwards", NULL }, + [HTTP_SERVER_HPACK_PROXY_AUTHENTICATE] = { "proxy-authenticate", NULL }, + [HTTP_SERVER_HPACK_PROXY_AUTHORIZATION] = { "proxy-authorization", NULL }, + [HTTP_SERVER_HPACK_RANGE] = { "range", NULL }, + [HTTP_SERVER_HPACK_REFERER] = { "referer", NULL }, + [HTTP_SERVER_HPACK_REFRESH] = { "refresh", NULL }, + [HTTP_SERVER_HPACK_RETRY_AFTER] = { "retry-after", NULL }, + [HTTP_SERVER_HPACK_SERVER] = { "server", NULL }, + [HTTP_SERVER_HPACK_SET_COOKIE] = { "set-cookie", NULL }, + [HTTP_SERVER_HPACK_STRICT_TRANSPORT_SECURITY] = { "strict-transport-security", NULL }, + [HTTP_SERVER_HPACK_TRANSFER_ENCODING] = { "transfer-encoding", NULL }, + [HTTP_SERVER_HPACK_USER_AGENT] = { "user-agent", NULL }, + [HTTP_SERVER_HPACK_VARY] = { "vary", NULL }, + [HTTP_SERVER_HPACK_VIA] = { "via", NULL }, + [HTTP_SERVER_HPACK_WWW_AUTHENTICATE] = { "www-authenticate", NULL }, +}; + +const struct hpack_table_entry *http_hpack_table_get(uint32_t key) +{ + if (!http_hpack_key_is_static(key)) { + return NULL; + } + + return &http_hpack_table_static[key]; +} + +static int http_hpack_find_index(struct http_hpack_header_buf *header, + bool *name_only) +{ + const struct hpack_table_entry *entry; + int candidate = -1; + + for (int i = HTTP_SERVER_HPACK_AUTHORITY; + i <= HTTP_SERVER_HPACK_WWW_AUTHENTICATE; i++) { + entry = &http_hpack_table_static[i]; + + if (entry->name != NULL && + strlen(entry->name) == header->name_len && + memcmp(entry->name, header->name, header->name_len) == 0) { + if (entry->value != NULL && + strlen(entry->value) == header->value_len && + memcmp(entry->value, header->value, header->value_len) == 0) { + /* Got exact match. */ + *name_only = false; + return i; + } + + if (candidate < 0) { + candidate = i; + } + } + } + + if (candidate > 0) { + /* Matched name only. */ + *name_only = true; + return candidate; + } + + return -ENOENT; +} + +#define HPACK_INTEGER_CONTINUATION_FLAG 0x80 +#define HPACK_STRING_HUFFMAN_FLAG 0x80 +#define HPACK_STRING_PREFIX_LEN 7 + +#define HPACK_PREFIX_INDEXED_MASK 0x80 +#define HPACK_PREFIX_INDEXED 0x80 +#define HPACK_PREFIX_LEN_INDEXED 7 + +#define HPACK_PREFIX_LITERAL_INDEXING_MASK 0xC0 +#define HPACK_PREFIX_LITERAL_INDEXING 0x40 +#define HPACK_PREFIX_LEN_LITERAL_INDEXING 6 + +#define HPACK_PREFIX_LITERAL_NO_INDEXING_MASK 0xF0 +#define HPACK_PREFIX_LITERAL_NO_INDEXING 0x00 +#define HPACK_PREFIX_LEN_LITERAL_NO_INDEXING 4 + +#define HPACK_PREFIX_LITERAL_NEVER_INDEXED_MASK 0xF0 +#define HPACK_PREFIX_LITERAL_NEVER_INDEXED 0x10 +#define HPACK_PREFIX_LEN_LITERAL_NEVER_INDEXED 4 + +#define HPACK_PREFIX_DYNAMIC_TABLE_SIZE_MASK 0xE0 +#define HPACK_PREFIX_DYNAMIC_TABLE_SIZE_UPDATE 0x20 +#define HPACK_PREFIX_LEN_DYNAMIC_TABLE_SIZE_UPDATE 5 + +static int hpack_integer_decode(const uint8_t *buf, size_t datalen, + uint8_t n, uint32_t *value) +{ + int len = 0; + uint8_t m = 0; + uint8_t value_mask = (1 << n) - 1; + + NET_ASSERT(n < 8); + + if (datalen == 0) { + return -EAGAIN; + } + + /* Based on RFC7541, ch 5.1. */ + len++; + *value = *buf & value_mask; + if (*value < value_mask) { + return len; + } + + do { + buf++; + len++; + + if (--datalen == 0) { + return -EAGAIN; + } + + if (m > sizeof(uint32_t) * 8) { + /* Can't handle integer that large. */ + return -EBADMSG; + } + + *value += (*buf & ~HPACK_INTEGER_CONTINUATION_FLAG) * (1 << m); + m += 7; + + } while (*buf & HPACK_INTEGER_CONTINUATION_FLAG); + + return len; +} + +enum hpack_string_type { + HPACK_HEADER_NAME, + HPACK_HEADER_VALUE, +}; + +static int hpack_huffman_decode(const uint8_t *encoded_buf, size_t encoded_len, + enum hpack_string_type type, + struct http_hpack_header_buf *header) +{ + uint8_t *buf = header->buf + header->datalen; + size_t buflen = sizeof(header->buf) - header->datalen; + int ret; + + NET_ASSERT(type == HPACK_HEADER_NAME || type == HPACK_HEADER_VALUE); + + ret = http_hpack_huffman_decode(encoded_buf, encoded_len, buf, buflen); + if (ret < 0) { + return ret; + } + + if (type == HPACK_HEADER_NAME) { + header->name = buf; + header->name_len = ret; + } else if (type == HPACK_HEADER_VALUE) { + header->value = buf; + header->value_len = ret; + } + + header->datalen += ret; + + return 0; +} + +static int hpack_string_decode(const uint8_t *buf, size_t datalen, + enum hpack_string_type type, + struct http_hpack_header_buf *header) +{ + uint32_t str_len; + bool huffman; + int len = 0; + int ret; + + NET_ASSERT(type == HPACK_HEADER_NAME || type == HPACK_HEADER_VALUE); + + if (datalen == 0) { + return -EAGAIN; + } + + huffman = *buf & HPACK_STRING_HUFFMAN_FLAG; + + ret = hpack_integer_decode(buf, datalen, HPACK_STRING_PREFIX_LEN, + &str_len); + if (ret < 0) { + return ret; + } + + len += ret; + datalen -= ret; + buf += ret; + + if (str_len > datalen) { + return -EAGAIN; + } + + if (huffman) { + ret = hpack_huffman_decode(buf, str_len, type, header); + if (ret < 0) { + return ret; + } + } else { + if (type == HPACK_HEADER_NAME) { + header->name = buf; + header->name_len = str_len; + } else if (type == HPACK_HEADER_VALUE) { + header->value = buf; + header->value_len = str_len; + } + } + + len += str_len; + + return len; +} + +static int hpack_handle_indexed(const uint8_t *buf, size_t datalen, + struct http_hpack_header_buf *header) +{ + const struct hpack_table_entry *entry; + uint32_t index; + int ret; + + ret = hpack_integer_decode(buf, datalen, HPACK_PREFIX_LEN_INDEXED, + &index); + if (ret < 0) { + return ret; + } + + if (index == 0) { + return -EBADMSG; + } + + entry = http_hpack_table_get(index); + if (entry == NULL) { + return -EBADMSG; + } + + if (entry->name == NULL || entry->value == NULL) { + return -EBADMSG; + } + + header->name = entry->name; + header->name_len = strlen(entry->name); + header->value = entry->value; + header->value_len = strlen(entry->value); + + return ret; +} + +static int hpack_handle_literal(const uint8_t *buf, size_t datalen, + struct http_hpack_header_buf *header, + uint8_t prefix_len) +{ + uint32_t index; + int ret, len; + + header->datalen = 0; + + ret = hpack_integer_decode(buf, datalen, prefix_len, &index); + if (ret < 0) { + return ret; + } + + len = ret; + buf += ret; + datalen -= ret; + + if (index == 0) { + /* Literal name. */ + ret = hpack_string_decode(buf, datalen, HPACK_HEADER_NAME, + header); + if (ret < 0) { + return ret; + } + + len += ret; + buf += ret; + datalen -= ret; + } else { + /* Indexed name. */ + const struct hpack_table_entry *entry; + + entry = http_hpack_table_get(index); + if (entry == NULL) { + return -EBADMSG; + } + + if (entry->name == NULL) { + return -EBADMSG; + } + + header->name = entry->name; + header->name_len = strlen(entry->name); + } + + ret = hpack_string_decode(buf, datalen, HPACK_HEADER_VALUE, header); + if (ret < 0) { + return ret; + } + + len += ret; + + return len; +} + +static int hpack_handle_literal_index(const uint8_t *buf, size_t datalen, + struct http_hpack_header_buf *header) +{ + /* TODO Add dynamic table support, if needed. */ + + return hpack_handle_literal(buf, datalen, header, + HPACK_PREFIX_LEN_LITERAL_INDEXING); +} + +static int hpack_handle_literal_no_index(const uint8_t *buf, size_t datalen, + struct http_hpack_header_buf *header) +{ + return hpack_handle_literal(buf, datalen, header, + HPACK_PREFIX_LEN_LITERAL_NO_INDEXING); +} + +static int hpack_handle_dynamic_size_update(const uint8_t *buf, size_t datalen) +{ + uint32_t max_size; + int ret; + + ret = hpack_integer_decode( + buf, datalen, HPACK_PREFIX_LEN_DYNAMIC_TABLE_SIZE_UPDATE, &max_size); + if (ret < 0) { + return ret; + } + + /* TODO Add dynamic table support, if needed. */ + + return ret; +} + +int http_hpack_decode_header(const uint8_t *buf, size_t datalen, + struct http_hpack_header_buf *header) +{ + uint8_t prefix = *buf; + int ret; + + if (buf == NULL || header == NULL) { + return -EINVAL; + } + + if (datalen == 0) { + return -EAGAIN; + } + + if ((prefix & HPACK_PREFIX_INDEXED_MASK) == HPACK_PREFIX_INDEXED) { + ret = hpack_handle_indexed(buf, datalen, header); + } else if ((prefix & HPACK_PREFIX_LITERAL_INDEXING_MASK) == + HPACK_PREFIX_LITERAL_INDEXING) { + ret = hpack_handle_literal_index(buf, datalen, header); + } else if (((prefix & HPACK_PREFIX_LITERAL_NO_INDEXING_MASK) == + HPACK_PREFIX_LITERAL_NO_INDEXING) || + ((prefix & HPACK_PREFIX_LITERAL_NEVER_INDEXED_MASK) == + HPACK_PREFIX_LITERAL_NEVER_INDEXED)) { + ret = hpack_handle_literal_no_index(buf, datalen, header); + } else if ((prefix & HPACK_PREFIX_DYNAMIC_TABLE_SIZE_MASK) == + HPACK_PREFIX_DYNAMIC_TABLE_SIZE_UPDATE) { + ret = hpack_handle_dynamic_size_update(buf, datalen); + } else { + ret = -EINVAL; + } + + return ret; +} + +static int hpack_integer_encode(uint8_t *buf, size_t buflen, int value, + uint8_t prefix, uint8_t n) +{ + uint8_t limit = (1 << n) - 1; + int len = 0; + + if (buflen == 0) { + return -ENOBUFS; + } + + /* Based on RFC7541, ch 5.1. */ + if (value < limit) { + *buf = prefix | (uint8_t)value; + + return 1; + } + + *buf++ = prefix | limit; + len++; + value -= limit; + + while (value >= 128) { + if (len >= buflen) { + return -ENOBUFS; + } + + *buf = (uint8_t)((value % 128) + 128); + len++; + value /= 128; + } + + if (len >= buflen) { + return -ENOBUFS; + } + + *buf = (uint8_t)value; + len++; + + return len; +} + +static int hpack_string_encode(uint8_t *buf, size_t buflen, + enum hpack_string_type type, + struct http_hpack_header_buf *header) +{ + int ret, len = 0; + const char *str; + size_t str_len; + uint8_t prefix = 0; + + if (type == HPACK_HEADER_NAME) { + str = header->name; + str_len = header->name_len; + } else { + str = header->value; + str_len = header->value_len; + } + + /* Try to encode string into intermediate buffer. */ + ret = http_hpack_huffman_encode(str, str_len, header->buf, + sizeof(header->buf)); + if (ret > 0 && ret < str_len) { + /* Use Huffman encoded string only if smaller than the original. */ + str = header->buf; + str_len = ret; + prefix = HPACK_STRING_HUFFMAN_FLAG; + } + + /* Encode string length. */ + ret = hpack_integer_encode(buf, buflen, str_len, prefix, + HPACK_STRING_PREFIX_LEN); + if (ret < 0) { + return ret; + } + + buf += ret; + buflen -= ret; + len += ret; + + /* Copy string. */ + if (str_len > buflen) { + return -ENOBUFS; + } + + memcpy(buf, str, str_len); + len += str_len; + + return len; +} + +static int hpack_encode_literal(uint8_t *buf, size_t buflen, + struct http_hpack_header_buf *header) +{ + int ret, len = 0; + + ret = hpack_integer_encode(buf, buflen, 0, + HPACK_PREFIX_LITERAL_NEVER_INDEXED, + HPACK_PREFIX_LEN_LITERAL_NEVER_INDEXED); + if (ret < 0) { + return ret; + } + + buf += ret; + buflen -= ret; + len += ret; + + ret = hpack_string_encode(buf, buflen, HPACK_HEADER_NAME, header); + if (ret < 0) { + return ret; + } + + buf += ret; + buflen -= ret; + len += ret; + + ret = hpack_string_encode(buf, buflen, HPACK_HEADER_VALUE, header); + if (ret < 0) { + return ret; + } + + len += ret; + + return len; +} + +static int hpack_encode_literal_value(uint8_t *buf, size_t buflen, int index, + struct http_hpack_header_buf *header) +{ + int ret, len = 0; + + ret = hpack_integer_encode(buf, buflen, index, + HPACK_PREFIX_LITERAL_NEVER_INDEXED, + HPACK_PREFIX_LEN_LITERAL_NEVER_INDEXED); + if (ret < 0) { + return ret; + } + + buf += ret; + buflen -= ret; + len += ret; + + ret = hpack_string_encode(buf, buflen, HPACK_HEADER_VALUE, header); + if (ret < 0) { + return ret; + } + + len += ret; + + return len; +} + +static int hpack_encode_indexed(uint8_t *buf, size_t buflen, int index) +{ + return hpack_integer_encode(buf, buflen, index, HPACK_PREFIX_INDEXED, + HPACK_PREFIX_LEN_INDEXED); +} + +int http_hpack_encode_header(uint8_t *buf, size_t buflen, + struct http_hpack_header_buf *header) +{ + int ret, len = 0; + bool name_only; + + if (buf == NULL || header == NULL || + header->name == NULL || header->name_len == 0 || + header->value == NULL || header->value_len == 0) { + return -EINVAL; + } + + if (buflen == 0) { + return -ENOBUFS; + } + + ret = http_hpack_find_index(header, &name_only); + if (ret < 0) { + /* All literal */ + len = hpack_encode_literal(buf, buflen, header); + } else if (name_only) { + /* Literal value */ + len = hpack_encode_literal_value(buf, buflen, ret, header); + } else { + /* Indexed */ + len = hpack_encode_indexed(buf, buflen, ret); + } + + return len; +} diff --git a/subsys/net/lib/http/http_huffman.c b/subsys/net/lib/http/http_huffman.c new file mode 100644 index 00000000000..6465eee2bc0 --- /dev/null +++ b/subsys/net/lib/http/http_huffman.c @@ -0,0 +1,480 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include + +#include +#include + +LOG_MODULE_DECLARE(net_http_server, CONFIG_NET_HTTP_SERVER_LOG_LEVEL); + +struct decode_elem { + uint8_t bitlen; + uint8_t symbol; + uint8_t code[4]; +}; + +static const struct decode_elem decode_table[] = { + { 5, 48, { 0b00000000, 0b00000000, 0b00000000, 0b00000000 } }, + { 5, 49, { 0b00001000, 0b00000000, 0b00000000, 0b00000000 } }, + { 5, 50, { 0b00010000, 0b00000000, 0b00000000, 0b00000000 } }, + { 5, 97, { 0b00011000, 0b00000000, 0b00000000, 0b00000000 } }, + { 5, 99, { 0b00100000, 0b00000000, 0b00000000, 0b00000000 } }, + { 5, 101, { 0b00101000, 0b00000000, 0b00000000, 0b00000000 } }, + { 5, 105, { 0b00110000, 0b00000000, 0b00000000, 0b00000000 } }, + { 5, 111, { 0b00111000, 0b00000000, 0b00000000, 0b00000000 } }, + { 5, 115, { 0b01000000, 0b00000000, 0b00000000, 0b00000000 } }, + { 5, 116, { 0b01001000, 0b00000000, 0b00000000, 0b00000000 } }, + { 6, 32, { 0b01010000, 0b00000000, 0b00000000, 0b00000000 } }, + { 6, 37, { 0b01010100, 0b00000000, 0b00000000, 0b00000000 } }, + { 6, 45, { 0b01011000, 0b00000000, 0b00000000, 0b00000000 } }, + { 6, 46, { 0b01011100, 0b00000000, 0b00000000, 0b00000000 } }, + { 6, 47, { 0b01100000, 0b00000000, 0b00000000, 0b00000000 } }, + { 6, 51, { 0b01100100, 0b00000000, 0b00000000, 0b00000000 } }, + { 6, 52, { 0b01101000, 0b00000000, 0b00000000, 0b00000000 } }, + { 6, 53, { 0b01101100, 0b00000000, 0b00000000, 0b00000000 } }, + { 6, 54, { 0b01110000, 0b00000000, 0b00000000, 0b00000000 } }, + { 6, 55, { 0b01110100, 0b00000000, 0b00000000, 0b00000000 } }, + { 6, 56, { 0b01111000, 0b00000000, 0b00000000, 0b00000000 } }, + { 6, 57, { 0b01111100, 0b00000000, 0b00000000, 0b00000000 } }, + { 6, 61, { 0b10000000, 0b00000000, 0b00000000, 0b00000000 } }, + { 6, 65, { 0b10000100, 0b00000000, 0b00000000, 0b00000000 } }, + { 6, 95, { 0b10001000, 0b00000000, 0b00000000, 0b00000000 } }, + { 6, 98, { 0b10001100, 0b00000000, 0b00000000, 0b00000000 } }, + { 6, 100, { 0b10010000, 0b00000000, 0b00000000, 0b00000000 } }, + { 6, 102, { 0b10010100, 0b00000000, 0b00000000, 0b00000000 } }, + { 6, 103, { 0b10011000, 0b00000000, 0b00000000, 0b00000000 } }, + { 6, 104, { 0b10011100, 0b00000000, 0b00000000, 0b00000000 } }, + { 6, 108, { 0b10100000, 0b00000000, 0b00000000, 0b00000000 } }, + { 6, 109, { 0b10100100, 0b00000000, 0b00000000, 0b00000000 } }, + { 6, 110, { 0b10101000, 0b00000000, 0b00000000, 0b00000000 } }, + { 6, 112, { 0b10101100, 0b00000000, 0b00000000, 0b00000000 } }, + { 6, 114, { 0b10110000, 0b00000000, 0b00000000, 0b00000000 } }, + { 6, 117, { 0b10110100, 0b00000000, 0b00000000, 0b00000000 } }, + { 7, 58, { 0b10111000, 0b00000000, 0b00000000, 0b00000000 } }, + { 7, 66, { 0b10111010, 0b00000000, 0b00000000, 0b00000000 } }, + { 7, 67, { 0b10111100, 0b00000000, 0b00000000, 0b00000000 } }, + { 7, 68, { 0b10111110, 0b00000000, 0b00000000, 0b00000000 } }, + { 7, 69, { 0b11000000, 0b00000000, 0b00000000, 0b00000000 } }, + { 7, 70, { 0b11000010, 0b00000000, 0b00000000, 0b00000000 } }, + { 7, 71, { 0b11000100, 0b00000000, 0b00000000, 0b00000000 } }, + { 7, 72, { 0b11000110, 0b00000000, 0b00000000, 0b00000000 } }, + { 7, 73, { 0b11001000, 0b00000000, 0b00000000, 0b00000000 } }, + { 7, 74, { 0b11001010, 0b00000000, 0b00000000, 0b00000000 } }, + { 7, 75, { 0b11001100, 0b00000000, 0b00000000, 0b00000000 } }, + { 7, 76, { 0b11001110, 0b00000000, 0b00000000, 0b00000000 } }, + { 7, 77, { 0b11010000, 0b00000000, 0b00000000, 0b00000000 } }, + { 7, 78, { 0b11010010, 0b00000000, 0b00000000, 0b00000000 } }, + { 7, 79, { 0b11010100, 0b00000000, 0b00000000, 0b00000000 } }, + { 7, 80, { 0b11010110, 0b00000000, 0b00000000, 0b00000000 } }, + { 7, 81, { 0b11011000, 0b00000000, 0b00000000, 0b00000000 } }, + { 7, 82, { 0b11011010, 0b00000000, 0b00000000, 0b00000000 } }, + { 7, 83, { 0b11011100, 0b00000000, 0b00000000, 0b00000000 } }, + { 7, 84, { 0b11011110, 0b00000000, 0b00000000, 0b00000000 } }, + { 7, 85, { 0b11100000, 0b00000000, 0b00000000, 0b00000000 } }, + { 7, 86, { 0b11100010, 0b00000000, 0b00000000, 0b00000000 } }, + { 7, 87, { 0b11100100, 0b00000000, 0b00000000, 0b00000000 } }, + { 7, 89, { 0b11100110, 0b00000000, 0b00000000, 0b00000000 } }, + { 7, 106, { 0b11101000, 0b00000000, 0b00000000, 0b00000000 } }, + { 7, 107, { 0b11101010, 0b00000000, 0b00000000, 0b00000000 } }, + { 7, 113, { 0b11101100, 0b00000000, 0b00000000, 0b00000000 } }, + { 7, 118, { 0b11101110, 0b00000000, 0b00000000, 0b00000000 } }, + { 7, 119, { 0b11110000, 0b00000000, 0b00000000, 0b00000000 } }, + { 7, 120, { 0b11110010, 0b00000000, 0b00000000, 0b00000000 } }, + { 7, 121, { 0b11110100, 0b00000000, 0b00000000, 0b00000000 } }, + { 7, 122, { 0b11110110, 0b00000000, 0b00000000, 0b00000000 } }, + { 8, 38, { 0b11111000, 0b00000000, 0b00000000, 0b00000000 } }, + { 8, 42, { 0b11111001, 0b00000000, 0b00000000, 0b00000000 } }, + { 8, 44, { 0b11111010, 0b00000000, 0b00000000, 0b00000000 } }, + { 8, 59, { 0b11111011, 0b00000000, 0b00000000, 0b00000000 } }, + { 8, 88, { 0b11111100, 0b00000000, 0b00000000, 0b00000000 } }, + { 8, 90, { 0b11111101, 0b00000000, 0b00000000, 0b00000000 } }, + { 10, 33, { 0b11111110, 0b00000000, 0b00000000, 0b00000000 } }, + { 10, 34, { 0b11111110, 0b01000000, 0b00000000, 0b00000000 } }, + { 10, 40, { 0b11111110, 0b10000000, 0b00000000, 0b00000000 } }, + { 10, 41, { 0b11111110, 0b11000000, 0b00000000, 0b00000000 } }, + { 10, 63, { 0b11111111, 0b00000000, 0b00000000, 0b00000000 } }, + { 11, 39, { 0b11111111, 0b01000000, 0b00000000, 0b00000000 } }, + { 11, 43, { 0b11111111, 0b01100000, 0b00000000, 0b00000000 } }, + { 11, 124, { 0b11111111, 0b10000000, 0b00000000, 0b00000000 } }, + { 12, 35, { 0b11111111, 0b10100000, 0b00000000, 0b00000000 } }, + { 12, 62, { 0b11111111, 0b10110000, 0b00000000, 0b00000000 } }, + { 13, 0, { 0b11111111, 0b11000000, 0b00000000, 0b00000000 } }, + { 13, 36, { 0b11111111, 0b11001000, 0b00000000, 0b00000000 } }, + { 13, 64, { 0b11111111, 0b11010000, 0b00000000, 0b00000000 } }, + { 13, 91, { 0b11111111, 0b11011000, 0b00000000, 0b00000000 } }, + { 13, 93, { 0b11111111, 0b11100000, 0b00000000, 0b00000000 } }, + { 13, 126, { 0b11111111, 0b11101000, 0b00000000, 0b00000000 } }, + { 14, 94, { 0b11111111, 0b11110000, 0b00000000, 0b00000000 } }, + { 14, 125, { 0b11111111, 0b11110100, 0b00000000, 0b00000000 } }, + { 15, 60, { 0b11111111, 0b11111000, 0b00000000, 0b00000000 } }, + { 15, 96, { 0b11111111, 0b11111010, 0b00000000, 0b00000000 } }, + { 15, 123, { 0b11111111, 0b11111100, 0b00000000, 0b00000000 } }, + { 19, 92, { 0b11111111, 0b11111110, 0b00000000, 0b00000000 } }, + { 19, 195, { 0b11111111, 0b11111110, 0b00100000, 0b00000000 } }, + { 19, 208, { 0b11111111, 0b11111110, 0b01000000, 0b00000000 } }, + { 20, 128, { 0b11111111, 0b11111110, 0b01100000, 0b00000000 } }, + { 20, 130, { 0b11111111, 0b11111110, 0b01110000, 0b00000000 } }, + { 20, 131, { 0b11111111, 0b11111110, 0b10000000, 0b00000000 } }, + { 20, 162, { 0b11111111, 0b11111110, 0b10010000, 0b00000000 } }, + { 20, 184, { 0b11111111, 0b11111110, 0b10100000, 0b00000000 } }, + { 20, 194, { 0b11111111, 0b11111110, 0b10110000, 0b00000000 } }, + { 20, 224, { 0b11111111, 0b11111110, 0b11000000, 0b00000000 } }, + { 20, 226, { 0b11111111, 0b11111110, 0b11010000, 0b00000000 } }, + { 21, 153, { 0b11111111, 0b11111110, 0b11100000, 0b00000000 } }, + { 21, 161, { 0b11111111, 0b11111110, 0b11101000, 0b00000000 } }, + { 21, 167, { 0b11111111, 0b11111110, 0b11110000, 0b00000000 } }, + { 21, 172, { 0b11111111, 0b11111110, 0b11111000, 0b00000000 } }, + { 21, 176, { 0b11111111, 0b11111111, 0b00000000, 0b00000000 } }, + { 21, 177, { 0b11111111, 0b11111111, 0b00001000, 0b00000000 } }, + { 21, 179, { 0b11111111, 0b11111111, 0b00010000, 0b00000000 } }, + { 21, 209, { 0b11111111, 0b11111111, 0b00011000, 0b00000000 } }, + { 21, 216, { 0b11111111, 0b11111111, 0b00100000, 0b00000000 } }, + { 21, 217, { 0b11111111, 0b11111111, 0b00101000, 0b00000000 } }, + { 21, 227, { 0b11111111, 0b11111111, 0b00110000, 0b00000000 } }, + { 21, 229, { 0b11111111, 0b11111111, 0b00111000, 0b00000000 } }, + { 21, 230, { 0b11111111, 0b11111111, 0b01000000, 0b00000000 } }, + { 22, 129, { 0b11111111, 0b11111111, 0b01001000, 0b00000000 } }, + { 22, 132, { 0b11111111, 0b11111111, 0b01001100, 0b00000000 } }, + { 22, 133, { 0b11111111, 0b11111111, 0b01010000, 0b00000000 } }, + { 22, 134, { 0b11111111, 0b11111111, 0b01010100, 0b00000000 } }, + { 22, 136, { 0b11111111, 0b11111111, 0b01011000, 0b00000000 } }, + { 22, 146, { 0b11111111, 0b11111111, 0b01011100, 0b00000000 } }, + { 22, 154, { 0b11111111, 0b11111111, 0b01100000, 0b00000000 } }, + { 22, 156, { 0b11111111, 0b11111111, 0b01100100, 0b00000000 } }, + { 22, 160, { 0b11111111, 0b11111111, 0b01101000, 0b00000000 } }, + { 22, 163, { 0b11111111, 0b11111111, 0b01101100, 0b00000000 } }, + { 22, 164, { 0b11111111, 0b11111111, 0b01110000, 0b00000000 } }, + { 22, 169, { 0b11111111, 0b11111111, 0b01110100, 0b00000000 } }, + { 22, 170, { 0b11111111, 0b11111111, 0b01111000, 0b00000000 } }, + { 22, 173, { 0b11111111, 0b11111111, 0b01111100, 0b00000000 } }, + { 22, 178, { 0b11111111, 0b11111111, 0b10000000, 0b00000000 } }, + { 22, 181, { 0b11111111, 0b11111111, 0b10000100, 0b00000000 } }, + { 22, 185, { 0b11111111, 0b11111111, 0b10001000, 0b00000000 } }, + { 22, 186, { 0b11111111, 0b11111111, 0b10001100, 0b00000000 } }, + { 22, 187, { 0b11111111, 0b11111111, 0b10010000, 0b00000000 } }, + { 22, 189, { 0b11111111, 0b11111111, 0b10010100, 0b00000000 } }, + { 22, 190, { 0b11111111, 0b11111111, 0b10011000, 0b00000000 } }, + { 22, 196, { 0b11111111, 0b11111111, 0b10011100, 0b00000000 } }, + { 22, 198, { 0b11111111, 0b11111111, 0b10100000, 0b00000000 } }, + { 22, 228, { 0b11111111, 0b11111111, 0b10100100, 0b00000000 } }, + { 22, 232, { 0b11111111, 0b11111111, 0b10101000, 0b00000000 } }, + { 22, 233, { 0b11111111, 0b11111111, 0b10101100, 0b00000000 } }, + { 23, 1, { 0b11111111, 0b11111111, 0b10110000, 0b00000000 } }, + { 23, 135, { 0b11111111, 0b11111111, 0b10110010, 0b00000000 } }, + { 23, 137, { 0b11111111, 0b11111111, 0b10110100, 0b00000000 } }, + { 23, 138, { 0b11111111, 0b11111111, 0b10110110, 0b00000000 } }, + { 23, 139, { 0b11111111, 0b11111111, 0b10111000, 0b00000000 } }, + { 23, 140, { 0b11111111, 0b11111111, 0b10111010, 0b00000000 } }, + { 23, 141, { 0b11111111, 0b11111111, 0b10111100, 0b00000000 } }, + { 23, 143, { 0b11111111, 0b11111111, 0b10111110, 0b00000000 } }, + { 23, 147, { 0b11111111, 0b11111111, 0b11000000, 0b00000000 } }, + { 23, 149, { 0b11111111, 0b11111111, 0b11000010, 0b00000000 } }, + { 23, 150, { 0b11111111, 0b11111111, 0b11000100, 0b00000000 } }, + { 23, 151, { 0b11111111, 0b11111111, 0b11000110, 0b00000000 } }, + { 23, 152, { 0b11111111, 0b11111111, 0b11001000, 0b00000000 } }, + { 23, 155, { 0b11111111, 0b11111111, 0b11001010, 0b00000000 } }, + { 23, 157, { 0b11111111, 0b11111111, 0b11001100, 0b00000000 } }, + { 23, 158, { 0b11111111, 0b11111111, 0b11001110, 0b00000000 } }, + { 23, 165, { 0b11111111, 0b11111111, 0b11010000, 0b00000000 } }, + { 23, 166, { 0b11111111, 0b11111111, 0b11010010, 0b00000000 } }, + { 23, 168, { 0b11111111, 0b11111111, 0b11010100, 0b00000000 } }, + { 23, 174, { 0b11111111, 0b11111111, 0b11010110, 0b00000000 } }, + { 23, 175, { 0b11111111, 0b11111111, 0b11011000, 0b00000000 } }, + { 23, 180, { 0b11111111, 0b11111111, 0b11011010, 0b00000000 } }, + { 23, 182, { 0b11111111, 0b11111111, 0b11011100, 0b00000000 } }, + { 23, 183, { 0b11111111, 0b11111111, 0b11011110, 0b00000000 } }, + { 23, 188, { 0b11111111, 0b11111111, 0b11100000, 0b00000000 } }, + { 23, 191, { 0b11111111, 0b11111111, 0b11100010, 0b00000000 } }, + { 23, 197, { 0b11111111, 0b11111111, 0b11100100, 0b00000000 } }, + { 23, 231, { 0b11111111, 0b11111111, 0b11100110, 0b00000000 } }, + { 23, 239, { 0b11111111, 0b11111111, 0b11101000, 0b00000000 } }, + { 24, 9, { 0b11111111, 0b11111111, 0b11101010, 0b00000000 } }, + { 24, 142, { 0b11111111, 0b11111111, 0b11101011, 0b00000000 } }, + { 24, 144, { 0b11111111, 0b11111111, 0b11101100, 0b00000000 } }, + { 24, 145, { 0b11111111, 0b11111111, 0b11101101, 0b00000000 } }, + { 24, 148, { 0b11111111, 0b11111111, 0b11101110, 0b00000000 } }, + { 24, 159, { 0b11111111, 0b11111111, 0b11101111, 0b00000000 } }, + { 24, 171, { 0b11111111, 0b11111111, 0b11110000, 0b00000000 } }, + { 24, 206, { 0b11111111, 0b11111111, 0b11110001, 0b00000000 } }, + { 24, 215, { 0b11111111, 0b11111111, 0b11110010, 0b00000000 } }, + { 24, 225, { 0b11111111, 0b11111111, 0b11110011, 0b00000000 } }, + { 24, 236, { 0b11111111, 0b11111111, 0b11110100, 0b00000000 } }, + { 24, 237, { 0b11111111, 0b11111111, 0b11110101, 0b00000000 } }, + { 25, 199, { 0b11111111, 0b11111111, 0b11110110, 0b00000000 } }, + { 25, 207, { 0b11111111, 0b11111111, 0b11110110, 0b10000000 } }, + { 25, 234, { 0b11111111, 0b11111111, 0b11110111, 0b00000000 } }, + { 25, 235, { 0b11111111, 0b11111111, 0b11110111, 0b10000000 } }, + { 26, 192, { 0b11111111, 0b11111111, 0b11111000, 0b00000000 } }, + { 26, 193, { 0b11111111, 0b11111111, 0b11111000, 0b01000000 } }, + { 26, 200, { 0b11111111, 0b11111111, 0b11111000, 0b10000000 } }, + { 26, 201, { 0b11111111, 0b11111111, 0b11111000, 0b11000000 } }, + { 26, 202, { 0b11111111, 0b11111111, 0b11111001, 0b00000000 } }, + { 26, 205, { 0b11111111, 0b11111111, 0b11111001, 0b01000000 } }, + { 26, 210, { 0b11111111, 0b11111111, 0b11111001, 0b10000000 } }, + { 26, 213, { 0b11111111, 0b11111111, 0b11111001, 0b11000000 } }, + { 26, 218, { 0b11111111, 0b11111111, 0b11111010, 0b00000000 } }, + { 26, 219, { 0b11111111, 0b11111111, 0b11111010, 0b01000000 } }, + { 26, 238, { 0b11111111, 0b11111111, 0b11111010, 0b10000000 } }, + { 26, 240, { 0b11111111, 0b11111111, 0b11111010, 0b11000000 } }, + { 26, 242, { 0b11111111, 0b11111111, 0b11111011, 0b00000000 } }, + { 26, 243, { 0b11111111, 0b11111111, 0b11111011, 0b01000000 } }, + { 26, 255, { 0b11111111, 0b11111111, 0b11111011, 0b10000000 } }, + { 27, 203, { 0b11111111, 0b11111111, 0b11111011, 0b11000000 } }, + { 27, 204, { 0b11111111, 0b11111111, 0b11111011, 0b11100000 } }, + { 27, 211, { 0b11111111, 0b11111111, 0b11111100, 0b00000000 } }, + { 27, 212, { 0b11111111, 0b11111111, 0b11111100, 0b00100000 } }, + { 27, 214, { 0b11111111, 0b11111111, 0b11111100, 0b01000000 } }, + { 27, 221, { 0b11111111, 0b11111111, 0b11111100, 0b01100000 } }, + { 27, 222, { 0b11111111, 0b11111111, 0b11111100, 0b10000000 } }, + { 27, 223, { 0b11111111, 0b11111111, 0b11111100, 0b10100000 } }, + { 27, 241, { 0b11111111, 0b11111111, 0b11111100, 0b11000000 } }, + { 27, 244, { 0b11111111, 0b11111111, 0b11111100, 0b11100000 } }, + { 27, 245, { 0b11111111, 0b11111111, 0b11111101, 0b00000000 } }, + { 27, 246, { 0b11111111, 0b11111111, 0b11111101, 0b00100000 } }, + { 27, 247, { 0b11111111, 0b11111111, 0b11111101, 0b01000000 } }, + { 27, 248, { 0b11111111, 0b11111111, 0b11111101, 0b01100000 } }, + { 27, 250, { 0b11111111, 0b11111111, 0b11111101, 0b10000000 } }, + { 27, 251, { 0b11111111, 0b11111111, 0b11111101, 0b10100000 } }, + { 27, 252, { 0b11111111, 0b11111111, 0b11111101, 0b11000000 } }, + { 27, 253, { 0b11111111, 0b11111111, 0b11111101, 0b11100000 } }, + { 27, 254, { 0b11111111, 0b11111111, 0b11111110, 0b00000000 } }, + { 28, 2, { 0b11111111, 0b11111111, 0b11111110, 0b00100000 } }, + { 28, 3, { 0b11111111, 0b11111111, 0b11111110, 0b00110000 } }, + { 28, 4, { 0b11111111, 0b11111111, 0b11111110, 0b01000000 } }, + { 28, 5, { 0b11111111, 0b11111111, 0b11111110, 0b01010000 } }, + { 28, 6, { 0b11111111, 0b11111111, 0b11111110, 0b01100000 } }, + { 28, 7, { 0b11111111, 0b11111111, 0b11111110, 0b01110000 } }, + { 28, 8, { 0b11111111, 0b11111111, 0b11111110, 0b10000000 } }, + { 28, 11, { 0b11111111, 0b11111111, 0b11111110, 0b10010000 } }, + { 28, 12, { 0b11111111, 0b11111111, 0b11111110, 0b10100000 } }, + { 28, 14, { 0b11111111, 0b11111111, 0b11111110, 0b10110000 } }, + { 28, 15, { 0b11111111, 0b11111111, 0b11111110, 0b11000000 } }, + { 28, 16, { 0b11111111, 0b11111111, 0b11111110, 0b11010000 } }, + { 28, 17, { 0b11111111, 0b11111111, 0b11111110, 0b11100000 } }, + { 28, 18, { 0b11111111, 0b11111111, 0b11111110, 0b11110000 } }, + { 28, 19, { 0b11111111, 0b11111111, 0b11111111, 0b00000000 } }, + { 28, 20, { 0b11111111, 0b11111111, 0b11111111, 0b00010000 } }, + { 28, 21, { 0b11111111, 0b11111111, 0b11111111, 0b00100000 } }, + { 28, 23, { 0b11111111, 0b11111111, 0b11111111, 0b00110000 } }, + { 28, 24, { 0b11111111, 0b11111111, 0b11111111, 0b01000000 } }, + { 28, 25, { 0b11111111, 0b11111111, 0b11111111, 0b01010000 } }, + { 28, 26, { 0b11111111, 0b11111111, 0b11111111, 0b01100000 } }, + { 28, 27, { 0b11111111, 0b11111111, 0b11111111, 0b01110000 } }, + { 28, 28, { 0b11111111, 0b11111111, 0b11111111, 0b10000000 } }, + { 28, 29, { 0b11111111, 0b11111111, 0b11111111, 0b10010000 } }, + { 28, 30, { 0b11111111, 0b11111111, 0b11111111, 0b10100000 } }, + { 28, 31, { 0b11111111, 0b11111111, 0b11111111, 0b10110000 } }, + { 28, 127, { 0b11111111, 0b11111111, 0b11111111, 0b11000000 } }, + { 28, 220, { 0b11111111, 0b11111111, 0b11111111, 0b11010000 } }, + { 28, 249, { 0b11111111, 0b11111111, 0b11111111, 0b11100000 } }, + { 30, 10, { 0b11111111, 0b11111111, 0b11111111, 0b11110000 } }, + { 30, 13, { 0b11111111, 0b11111111, 0b11111111, 0b11110100 } }, + { 30, 22, { 0b11111111, 0b11111111, 0b11111111, 0b11111000 } }, +}; + +static const struct decode_elem eos = { + 30, 0, { 0b11111111, 0b11111111, 0b11111111, 0b11111100 } +}; + +#define UINT32_BITLEN 32 + +#define MSB_MASK(len) (UINT32_MAX << (UINT32_BITLEN - len)) +#define LSB_MASK(len) ((1UL << len) - 1UL) + +static bool huffman_bits_compare(uint32_t bits, const struct decode_elem *entry) +{ + uint32_t mask = MSB_MASK(entry->bitlen); + uint32_t code = sys_get_be32(entry->code); + + if (code == (bits & mask)) { + return true; + } + + return false; +} + +static const struct decode_elem *huffman_decode_bits(uint32_t bits) +{ + for (int i = 0; i < ARRAY_SIZE(decode_table); i++) { + if (huffman_bits_compare(bits, &decode_table[i])) { + return &decode_table[i]; + } + } + + if (huffman_bits_compare(bits, &eos)) { + return &eos; + } + + return NULL; +} + +static const struct decode_elem *huffman_find_entry(uint8_t symbol) +{ + for (int i = 0; i < ARRAY_SIZE(decode_table); i++) { + if (decode_table[i].symbol == symbol) { + return &decode_table[i]; + } + } + + return NULL; +} + +#define MAX_PADDING_LEN 7 + +int http_hpack_huffman_decode(const uint8_t *encoded_buf, size_t encoded_len, + uint8_t *buf, size_t buflen) +{ + size_t encoded_bits_len = encoded_len * 8; + uint8_t bits_needed = UINT32_BITLEN; + const struct decode_elem *decoded; + uint8_t bits_in_byte_left = 8; + size_t decoded_len = 0; + uint32_t bits = 0; + + if (encoded_buf == NULL || buf == NULL || encoded_len == 0) { + return -EINVAL; + } + + while (encoded_bits_len > 0) { + /* Refill the bits variable */ + while (bits_needed > 0) { + if (encoded_len > 0) { + if (bits_in_byte_left <= bits_needed) { + /* Consume rest of the byte */ + bits <<= bits_in_byte_left; + bits |= *encoded_buf & + LSB_MASK(bits_in_byte_left); + bits_needed -= bits_in_byte_left; + bits_in_byte_left = 0; + } else { + /* Consume part of the byte */ + bits <<= bits_needed; + bits |= (*encoded_buf >> + (bits_in_byte_left - bits_needed)) & + LSB_MASK(bits_needed); + bits_in_byte_left -= bits_needed; + bits_needed = 0; + } + } else { + /* Pad with ones */ + bits <<= bits_needed; + bits |= LSB_MASK(bits_needed); + bits_needed = 0; + } + + /* Move to next encoded byte */ + if (bits_in_byte_left == 0) { + encoded_buf++; + encoded_len--; + bits_in_byte_left = 8; + } + } + + /* Pass to decoder */ + decoded = huffman_decode_bits(bits); + if (decoded == NULL) { + LOG_ERR("No symbol found"); + return -EBADMSG; + } + + if (decoded == &eos) { + if (encoded_bits_len > MAX_PADDING_LEN) { + LOG_ERR("eos reached prematurely"); + return -EBADMSG; + } + + break; + } + + if (encoded_bits_len < decoded->bitlen) { + LOG_ERR("Invalid symbol used for padding"); + return -EBADMSG; + } + + /* Remove consumed bits from bits variable. */ + bits_needed += decoded->bitlen; + encoded_bits_len -= decoded->bitlen; + + /* Store decoded symbol */ + if (buflen == 0) { + LOG_ERR("Not enough buffer to decode string"); + return -ENOBUFS; + } + + *buf = decoded->symbol; + buf++; + buflen--; + decoded_len++; + } + + return decoded_len; +} + +int http_hpack_huffman_encode(const uint8_t *str, size_t str_len, + uint8_t *buf, size_t buflen) +{ + const struct decode_elem *entry; + size_t buflen_bits = buflen * 8; + uint8_t bit_offset = 0; + int len = 0; + + if (str == NULL || buf == NULL || str_len == 0) { + return -EINVAL; + } + + while (str_len > 0) { + uint32_t code; + uint8_t bitlen; + + entry = huffman_find_entry(*str); + if (entry == NULL) { + return -EINVAL; + } + + if (entry->bitlen > buflen_bits) { + return -ENOBUFS; + } + + bitlen = entry->bitlen; + code = sys_get_be32(entry->code); + + while (bitlen > 0) { + uint8_t to_copy = MIN(8 - bit_offset, bitlen); + uint8_t byte = (uint8_t)((code & MSB_MASK(to_copy)) >> + (24 + bit_offset)); + + /* This is way suboptimal */ + if (bit_offset == 0) { + *buf = byte; + } else { + *buf |= byte; + } + + code <<= to_copy; + bitlen -= to_copy; + bit_offset = (bit_offset + to_copy) % 8; + + if (bit_offset == 0) { + buf++; + len++; + } + } + + buflen_bits -= entry->bitlen; + str_len--; + str++; + } + + /* Pad with ones. */ + if (bit_offset > 0) { + *buf |= LSB_MASK((8 - bit_offset)); + len++; + } + + return len; +} diff --git a/subsys/net/lib/http/http_server_core.c b/subsys/net/lib/http/http_server_core.c new file mode 100644 index 00000000000..e0402259faf --- /dev/null +++ b/subsys/net/lib/http/http_server_core.c @@ -0,0 +1,754 @@ +/* + * Copyright (c) 2023, Emna Rekik + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(net_http_server, CONFIG_NET_HTTP_SERVER_LOG_LEVEL); + +#include "../../ip/net_private.h" +#include "headers/server_internal.h" + +#if defined(CONFIG_NET_TC_THREAD_COOPERATIVE) +/* Lowest priority cooperative thread */ +#define THREAD_PRIORITY K_PRIO_COOP(CONFIG_NUM_COOP_PRIORITIES - 1) +#else +#define THREAD_PRIORITY K_PRIO_PREEMPT(CONFIG_NUM_PREEMPT_PRIORITIES - 1) +#endif + +#define INVALID_SOCK -1 +#define INACTIVITY_TIMEOUT K_SECONDS(CONFIG_HTTP_SERVER_CLIENT_INACTIVITY_TIMEOUT) + +#define HTTP_SERVER_MAX_SERVICES CONFIG_HTTP_SERVER_NUM_SERVICES +#define HTTP_SERVER_MAX_CLIENTS CONFIG_HTTP_SERVER_MAX_CLIENTS +#define HTTP_SERVER_SOCK_COUNT (1 + HTTP_SERVER_MAX_SERVICES + HTTP_SERVER_MAX_CLIENTS) + +struct http_server_ctx { + int num_clients; + int listen_fds; /* max value of 1 + MAX_SERVICES */ + + /* First pollfd is eventfd that can be used to stop the server, + * then we have the server listen sockets, + * and then the accepted sockets. + */ + struct zsock_pollfd fds[HTTP_SERVER_SOCK_COUNT]; + struct http_client_ctx clients[HTTP_SERVER_MAX_CLIENTS]; +}; + +static struct http_server_ctx server_ctx; +static K_SEM_DEFINE(server_start, 0, 1); +static bool server_running; + +int http_server_init(struct http_server_ctx *ctx) +{ + int proto; + int failed = 0, count = 0; + int svc_count; + socklen_t len; + int fd, af, i; + struct sockaddr_storage addr_storage; + const union { + struct sockaddr *addr; + struct sockaddr_in *addr4; + struct sockaddr_in6 *addr6; + } addr = { + .addr = (struct sockaddr *)&addr_storage + }; + + HTTP_SERVICE_COUNT(&svc_count); + + /* Initialize fds */ + memset(ctx->fds, 0, sizeof(ctx->fds)); + memset(ctx->clients, 0, sizeof(ctx->clients)); + + for (i = 0; i < ARRAY_SIZE(ctx->fds); i++) { + ctx->fds[i].fd = INVALID_SOCK; + } + + /* Create an eventfd that can be used to trigger events during polling */ + fd = eventfd(0, 0); + if (fd < 0) { + fd = -errno; + LOG_ERR("eventfd failed (%d)", fd); + return fd; + } + + ctx->fds[count].fd = fd; + ctx->fds[count].events = ZSOCK_POLLIN; + count++; + + HTTP_SERVICE_FOREACH(svc) { + /* set the default address (in6addr_any / INADDR_ANY are all 0) */ + memset(&addr_storage, 0, sizeof(struct sockaddr_storage)); + + /* Set up the server address struct according to address family */ + if (IS_ENABLED(CONFIG_NET_IPV6) && + zsock_inet_pton(AF_INET6, svc->host, &addr.addr6->sin6_addr) == 1) { + af = AF_INET6; + len = sizeof(*addr.addr6); + + addr.addr6->sin6_family = AF_INET6; + addr.addr6->sin6_port = htons(*svc->port); + } else if (IS_ENABLED(CONFIG_NET_IPV4) && + zsock_inet_pton(AF_INET, svc->host, &addr.addr4->sin_addr) == 1) { + af = AF_INET; + len = sizeof(*addr.addr4); + + addr.addr4->sin_family = AF_INET; + addr.addr4->sin_port = htons(*svc->port); + } else if (IS_ENABLED(CONFIG_NET_IPV6)) { + /* prefer IPv6 if both IPv6 and IPv4 are supported */ + af = AF_INET6; + len = sizeof(*addr.addr6); + + addr.addr6->sin6_family = AF_INET6; + addr.addr6->sin6_port = htons(*svc->port); + } else if (IS_ENABLED(CONFIG_NET_IPV4)) { + af = AF_INET; + len = sizeof(*addr.addr4); + + addr.addr4->sin_family = AF_INET; + addr.addr4->sin_port = htons(*svc->port); + } else { + LOG_ERR("Neither IPv4 nor IPv6 is enabled"); + failed++; + break; + } + + /* Create a socket */ + if (COND_CODE_1(CONFIG_NET_SOCKETS_SOCKOPT_TLS, + (svc->sec_tag_list != NULL), + (0))) { + proto = IPPROTO_TLS_1_2; + } else { + proto = IPPROTO_TCP; + } + + fd = zsock_socket(af, SOCK_STREAM, proto); + if (fd < 0) { + LOG_ERR("socket: %d", errno); + failed++; + continue; + } + +#if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS) + if (svc->sec_tag_list != NULL) { + if (zsock_setsockopt(fd, SOL_TLS, TLS_SEC_TAG_LIST, + svc->sec_tag_list, + svc->sec_tag_list_size) < 0) { + LOG_ERR("setsockopt: %d", errno); + zsock_close(fd); + continue; + } + + if (zsock_setsockopt(fd, SOL_TLS, TLS_HOSTNAME, "localhost", + sizeof("localhost")) < 0) { + LOG_ERR("setsockopt: %d", errno); + zsock_close(fd); + continue; + } + } +#endif + + if (zsock_setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &(int){1}, + sizeof(int)) < 0) { + LOG_ERR("setsockopt: %d", errno); + zsock_close(fd); + continue; + } + + if (zsock_bind(fd, addr.addr, len) < 0) { + LOG_ERR("bind: %d", errno); + failed++; + zsock_close(fd); + continue; + } + + if (*svc->port == 0) { + /* ephemeral port - read back the port number */ + len = sizeof(addr_storage); + if (zsock_getsockname(fd, addr.addr, &len) < 0) { + LOG_ERR("getsockname: %d", errno); + zsock_close(fd); + continue; + } + + *svc->port = ntohs(addr.addr4->sin_port); + } + + if (zsock_listen(fd, HTTP_SERVER_MAX_CLIENTS) < 0) { + LOG_ERR("listen: %d", errno); + failed++; + zsock_close(fd); + continue; + } + + LOG_DBG("Initialized HTTP Service %s:%u", svc->host, *svc->port); + + ctx->fds[count].fd = fd; + ctx->fds[count].events = ZSOCK_POLLIN; + count++; + } + + if (failed >= svc_count) { + LOG_ERR("All services failed (%d)", failed); + return -ESRCH; + } + + ctx->listen_fds = count; + ctx->num_clients = 0; + + return 0; +} + +static int accept_new_client(int server_fd) +{ + int new_socket; + socklen_t addrlen; + struct sockaddr_storage sa; + + memset(&sa, 0, sizeof(sa)); + addrlen = sizeof(sa); + + new_socket = zsock_accept(server_fd, (struct sockaddr *)&sa, &addrlen); + if (new_socket < 0) { + new_socket = -errno; + LOG_DBG("[%d] accept failed (%d)", server_fd, new_socket); + return new_socket; + } + + LOG_DBG("New client from %s:%d", + net_sprint_addr(sa.ss_family, &net_sin((struct sockaddr *)&sa)->sin_addr), + ntohs(net_sin((struct sockaddr *)&sa)->sin_port)); + + return new_socket; +} + +static int close_all_sockets(struct http_server_ctx *ctx) +{ + zsock_close(ctx->fds[0].fd); /* close eventfd */ + ctx->fds[0].fd = -1; + + for (int i = 1; i < ARRAY_SIZE(ctx->fds); i++) { + if (ctx->fds[i].fd < 0) { + continue; + } + + zsock_close(ctx->fds[i].fd); + ctx->fds[i].fd = -1; + } + + return 0; +} + +static void client_release_resources(struct http_client_ctx *client) +{ + struct http_resource_detail *detail; + struct http_resource_detail_dynamic *dynamic_detail; + + HTTP_SERVICE_FOREACH(service) { + HTTP_SERVICE_FOREACH_RESOURCE(service, resource) { + detail = resource->detail; + + if (detail->type != HTTP_RESOURCE_TYPE_DYNAMIC) { + continue; + } + + dynamic_detail = (struct http_resource_detail_dynamic *)detail; + + if (dynamic_detail->holder != client) { + continue; + } + + /* If the client still holds the resource at this point, + * it means the transaction was not complete. Release + * the resource and notify application. + */ + dynamic_detail->holder = NULL; + + if (dynamic_detail->cb == NULL) { + continue; + } + + dynamic_detail->cb(client, HTTP_SERVER_DATA_ABORTED, + NULL, 0, dynamic_detail->user_data); + } + } +} + +void http_server_release_client(struct http_client_ctx *client) +{ + int i; + struct k_work_sync sync; + + __ASSERT_NO_MSG(IS_ARRAY_ELEMENT(server_ctx.clients, client)); + + k_work_cancel_delayable_sync(&client->inactivity_timer, &sync); + client_release_resources(client); + + server_ctx.num_clients--; + + for (i = server_ctx.listen_fds; i < ARRAY_SIZE(server_ctx.fds); i++) { + if (server_ctx.fds[i].fd == client->fd) { + server_ctx.fds[i].fd = INVALID_SOCK; + break; + } + } + + memset(client, 0, sizeof(struct http_client_ctx)); + client->fd = INVALID_SOCK; +} + +static void close_client_connection(struct http_client_ctx *client) +{ + int fd = client->fd; + + http_server_release_client(client); + + (void)zsock_close(fd); +} + +static void client_timeout(struct k_work *work) +{ + struct k_work_delayable *dwork = k_work_delayable_from_work(work); + struct http_client_ctx *client = + CONTAINER_OF(dwork, struct http_client_ctx, inactivity_timer); + + LOG_DBG("Client %p timeout", client); + + /* Shutdown the socket. This will be detected by poll() and a proper + * cleanup will proceed. + */ + (void)zsock_shutdown(client->fd, ZSOCK_SHUT_RD); +} + +void http_client_timer_restart(struct http_client_ctx *client) +{ + __ASSERT_NO_MSG(IS_ARRAY_ELEMENT(server_ctx.clients, client)); + + k_work_reschedule(&client->inactivity_timer, INACTIVITY_TIMEOUT); +} + +static void init_client_ctx(struct http_client_ctx *client, int new_socket) +{ + client->fd = new_socket; + client->data_len = 0; + client->server_state = HTTP_SERVER_PREFACE_STATE; + client->has_upgrade_header = false; + client->preface_sent = false; + client->window_size = HTTP_SERVER_INITIAL_WINDOW_SIZE; + + memset(client->buffer, 0, sizeof(client->buffer)); + memset(client->url_buffer, 0, sizeof(client->url_buffer)); + k_work_init_delayable(&client->inactivity_timer, client_timeout); + http_client_timer_restart(client); + + ARRAY_FOR_EACH(client->streams, i) { + client->streams[i].stream_state = HTTP_SERVER_STREAM_IDLE; + client->streams[i].stream_id = 0; + } +} + +static int handle_http_preface(struct http_client_ctx *client) +{ + LOG_DBG("HTTP_SERVER_PREFACE_STATE."); + + if (client->data_len < sizeof(HTTP2_PREFACE) - 1) { + /* We don't have full preface yet, get more data. */ + return -EAGAIN; + } + + if (strncmp(client->cursor, HTTP2_PREFACE, sizeof(HTTP2_PREFACE) - 1) != 0) { + return enter_http1_request(client); + } + + return enter_http2_request(client); +} + +static int handle_http_done(struct http_client_ctx *client) +{ + LOG_DBG("HTTP_SERVER_DONE_STATE"); + + close_client_connection(client); + + return -EAGAIN; +} + +int enter_http_done_state(struct http_client_ctx *client) +{ + close_client_connection(client); + + client->server_state = HTTP_SERVER_DONE_STATE; + + return -EAGAIN; +} + +static int handle_http_request(struct http_client_ctx *client) +{ + int ret = -EINVAL; + + client->cursor = client->buffer; + + do { + switch (client->server_state) { + case HTTP_SERVER_FRAME_DATA_STATE: + ret = handle_http_frame_data(client); + break; + case HTTP_SERVER_PREFACE_STATE: + ret = handle_http_preface(client); + break; + case HTTP_SERVER_REQUEST_STATE: + ret = handle_http1_request(client); + break; + case HTTP_SERVER_FRAME_HEADER_STATE: + ret = handle_http_frame_header(client); + break; + case HTTP_SERVER_FRAME_HEADERS_STATE: + ret = handle_http_frame_headers(client); + break; + case HTTP_SERVER_FRAME_CONTINUATION_STATE: + ret = handle_http_frame_continuation(client); + break; + case HTTP_SERVER_FRAME_SETTINGS_STATE: + ret = handle_http_frame_settings(client); + break; + case HTTP_SERVER_FRAME_WINDOW_UPDATE_STATE: + ret = handle_http_frame_window_update(client); + break; + case HTTP_SERVER_FRAME_RST_STREAM_STATE: + ret = handle_http_frame_rst_frame(client); + break; + case HTTP_SERVER_FRAME_GOAWAY_STATE: + ret = handle_http_frame_goaway(client); + break; + case HTTP_SERVER_FRAME_PRIORITY_STATE: + ret = handle_http_frame_priority(client); + break; + case HTTP_SERVER_DONE_STATE: + ret = handle_http_done(client); + break; + default: + ret = handle_http_done(client); + break; + } + } while (ret >= 0 && client->data_len > 0); + + if (ret < 0 && ret != -EAGAIN) { + return ret; + } + + if (client->data_len > 0) { + /* Move any remaining data in the buffer. */ + memmove(client->buffer, client->cursor, client->data_len); + } + + return 0; +} + +static int http_server_run(struct http_server_ctx *ctx) +{ + struct http_client_ctx *client; + eventfd_t value; + bool found_slot; + int new_socket; + int ret, i, j; + int sock_error; + socklen_t optlen = sizeof(int); + + value = 0; + + while (1) { + ret = zsock_poll(ctx->fds, HTTP_SERVER_SOCK_COUNT, -1); + if (ret < 0) { + ret = -errno; + LOG_DBG("poll failed (%d)", ret); + return ret; + } + + if (ret == 0) { + /* should not happen because timeout is -1 */ + break; + } + + if (ret == 1 && ctx->fds[0].revents) { + eventfd_read(ctx->fds[0].fd, &value); + LOG_DBG("Received stop event. exiting .."); + goto closing; + } + + for (i = 1; i < ARRAY_SIZE(ctx->fds); i++) { + if (ctx->fds[i].fd < 0) { + continue; + } + + if (ctx->fds[i].revents & ZSOCK_POLLHUP) { + if (i >= ctx->listen_fds) { + LOG_DBG("Client #%d has disconnected", + i - ctx->listen_fds); + + client = &ctx->clients[i - ctx->listen_fds]; + close_client_connection(client); + } + + continue; + } + + if (ctx->fds[i].revents & ZSOCK_POLLERR) { + (void)zsock_getsockopt(ctx->fds[i].fd, SOL_SOCKET, + SO_ERROR, &sock_error, &optlen); + LOG_DBG("Error on fd %d %d", ctx->fds[i].fd, sock_error); + + if (i >= ctx->listen_fds) { + client = &ctx->clients[i - ctx->listen_fds]; + close_client_connection(client); + continue; + } + + /* Listening socket error, abort. */ + LOG_ERR("Listening socket error, aborting."); + return -sock_error; + + } + + if (!(ctx->fds[i].revents & ZSOCK_POLLIN)) { + continue; + } + + /* First check if we have something to accept */ + if (i < ctx->listen_fds) { + new_socket = accept_new_client(ctx->fds[i].fd); + if (new_socket < 0) { + ret = -errno; + LOG_DBG("accept: %d", ret); + continue; + } + + found_slot = false; + + for (j = ctx->listen_fds; j < ARRAY_SIZE(ctx->fds); j++) { + if (ctx->fds[j].fd != INVALID_SOCK) { + continue; + } + + ctx->fds[j].fd = new_socket; + ctx->fds[j].events = ZSOCK_POLLIN; + ctx->fds[j].revents = 0; + + ctx->num_clients++; + + LOG_DBG("Init client #%d", j - ctx->listen_fds); + + init_client_ctx(&ctx->clients[j - ctx->listen_fds], + new_socket); + found_slot = true; + break; + } + + if (!found_slot) { + LOG_DBG("No free slot found."); + zsock_close(new_socket); + } + + continue; + } + + /* Client sock */ + client = &ctx->clients[i - ctx->listen_fds]; + + ret = zsock_recv(client->fd, client->buffer + client->data_len, + sizeof(client->buffer) - client->data_len, 0); + if (ret <= 0) { + if (ret == 0) { + LOG_DBG("Connection closed by peer for client #%d", + i - ctx->listen_fds); + } else { + ret = -errno; + LOG_DBG("ERROR reading from socket (%d)", ret); + } + + close_client_connection(client); + continue; + } + + client->data_len += ret; + + http_client_timer_restart(client); + + ret = handle_http_request(client); + if (ret < 0 && ret != -EAGAIN) { + if (ret == -ENOTCONN) { + LOG_DBG("Client closed connection while handling request"); + } else { + LOG_ERR("HTTP request handling error (%d)", ret); + } + close_client_connection(client); + } else if (client->data_len == sizeof(client->buffer)) { + /* If the RX buffer is still full after parsing, + * it means we won't be able to handle this request + * with the current buffer size. + */ + LOG_ERR("RX buffer too small to handle request"); + close_client_connection(client); + } + } + } + + return 0; + +closing: + /* Close all client connections and the server socket */ + return close_all_sockets(ctx); +} + +/* Compare two strings where the terminator is either "\0" or "?" */ +static int compare_strings(const char *s1, const char *s2) +{ + while ((*s1 && *s2) && (*s1 == *s2) && (*s1 != '?')) { + s1++; + s2++; + } + + /* Check if both strings have reached their terminators or '?' */ + if ((*s1 == '\0' || *s1 == '?') && (*s2 == '\0' || *s2 == '?')) { + return 0; /* Strings are equal */ + } + + return 1; /* Strings are not equal */ +} + +static bool skip_this(struct http_resource_desc *resource, bool is_websocket) +{ + struct http_resource_detail *detail; + + detail = (struct http_resource_detail *)resource->detail; + + if (is_websocket) { + if (detail->type != HTTP_RESOURCE_TYPE_WEBSOCKET) { + return true; + } + } else { + if (detail->type == HTTP_RESOURCE_TYPE_WEBSOCKET) { + return true; + } + } + + return false; +} + +struct http_resource_detail *get_resource_detail(const char *path, + int *path_len, + bool is_websocket) +{ + HTTP_SERVICE_FOREACH(service) { + HTTP_SERVICE_FOREACH_RESOURCE(service, resource) { + if (skip_this(resource, is_websocket)) { + continue; + } + + if (compare_strings(path, resource->resource) == 0) { + NET_DBG("Got match for %s", resource->resource); + + *path_len = strlen(resource->resource); + return resource->detail; + } + } + } + + NET_DBG("No match for %s", path); + + return NULL; +} + +int http_server_sendall(struct http_client_ctx *client, const void *buf, size_t len) +{ + while (len) { + ssize_t out_len = zsock_send(client->fd, buf, len, 0); + + if (out_len < 0) { + return -errno; + } + + buf = (const char *)buf + out_len; + len -= out_len; + + http_client_timer_restart(client); + } + + return 0; +} + +int http_server_start(void) +{ + if (server_running) { + LOG_DBG("HTTP server already started"); + return -EALREADY; + } + + server_running = true; + k_sem_give(&server_start); + + LOG_DBG("Starting HTTP server"); + + return 0; +} + +int http_server_stop(void) +{ + if (!server_running) { + LOG_DBG("HTTP server already stopped"); + return -EALREADY; + } + + server_running = false; + k_sem_reset(&server_start); + eventfd_write(server_ctx.fds[0].fd, 1); + + LOG_DBG("Stopping HTTP server"); + + return 0; +} + +static void http_server_thread(void *p1, void *p2, void *p3) +{ + int ret; + + ARG_UNUSED(p1); + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + while (true) { + k_sem_take(&server_start, K_FOREVER); + + while (server_running) { + ret = http_server_init(&server_ctx); + if (ret < 0) { + LOG_ERR("Failed to initialize HTTP2 server"); + return; + } + + ret = http_server_run(&server_ctx); + if (server_running) { + LOG_INF("Re-starting server (%d)", ret); + } + } + } +} + +K_THREAD_DEFINE(http_server_tid, CONFIG_HTTP_SERVER_STACK_SIZE, + http_server_thread, NULL, NULL, NULL, THREAD_PRIORITY, 0, 0); diff --git a/subsys/net/lib/http/http_server_http1.c b/subsys/net/lib/http/http_server_http1.c new file mode 100644 index 00000000000..d718c37bc35 --- /dev/null +++ b/subsys/net/lib/http/http_server_http1.c @@ -0,0 +1,638 @@ +/* + * Copyright (c) 2023, Emna Rekik + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +LOG_MODULE_DECLARE(net_http_server, CONFIG_NET_HTTP_SERVER_LOG_LEVEL); + +#include "headers/server_internal.h" + +#define TEMP_BUF_LEN 64 + +static const char final_chunk[] = "0\r\n\r\n"; +static const char *crlf = &final_chunk[3]; + +static int handle_http1_static_resource( + struct http_resource_detail_static *static_detail, + struct http_client_ctx *client) +{ +#define RESPONSE_TEMPLATE \ + "HTTP/1.1 200 OK\r\n" \ + "%s%s\r\n" \ + "Content-Length: %d\r\n" + + /* Add couple of bytes to total response */ + char http_response[sizeof(RESPONSE_TEMPLATE) + + sizeof("Content-Encoding: 01234567890123456789\r\n") + + sizeof("Content-Type: \r\n") + HTTP_SERVER_MAX_CONTENT_TYPE_LEN + + sizeof("xxxx") + + sizeof("\r\n")]; + const char *data; + int len; + int ret; + + if (static_detail->common.bitmask_of_supported_http_methods & BIT(HTTP_GET)) { + data = static_detail->static_data; + len = static_detail->static_data_len; + + if (static_detail->common.content_encoding != NULL && + static_detail->common.content_encoding[0] != '\0') { + snprintk(http_response, sizeof(http_response), + RESPONSE_TEMPLATE "Content-Encoding: %s\r\n\r\n", + "Content-Type: ", + static_detail->common.content_type == NULL ? + "text/html" : static_detail->common.content_type, + len, static_detail->common.content_encoding); + } else { + snprintk(http_response, sizeof(http_response), + RESPONSE_TEMPLATE "\r\n", + "Content-Type: ", + static_detail->common.content_type == NULL ? + "text/html" : static_detail->common.content_type, + len); + } + + ret = http_server_sendall(client, http_response, + strlen(http_response)); + if (ret < 0) { + return ret; + } + + ret = http_server_sendall(client, data, len); + if (ret < 0) { + return ret; + } + } + + return 0; +} + +#define RESPONSE_TEMPLATE_CHUNKED \ + "HTTP/1.1 200 OK\r\n" \ + "%s%s\r\n" \ + "Transfer-Encoding: chunked\r\n\r\n" + +#define RESPONSE_TEMPLATE_DYNAMIC \ + "HTTP/1.1 200 OK\r\n" \ + "%s%s\r\n\r\n" + +#define SEND_RESPONSE(_template, _content_type) ({ \ + char http_response[sizeof(_template) + \ + sizeof("Content-Type: \r\n") + \ + HTTP_SERVER_MAX_CONTENT_TYPE_LEN + \ + sizeof("xxxx") + \ + sizeof("\r\n")]; \ + snprintk(http_response, sizeof(http_response), \ + _template "\r\n", \ + "Content-Type: ", \ + _content_type == NULL ? \ + "text/html" : _content_type); \ + ret = http_server_sendall(client, http_response, \ + strnlen(http_response, \ + sizeof(_template) - 1)); \ + ret; }) + +static int dynamic_get_req(struct http_resource_detail_dynamic *dynamic_detail, + struct http_client_ctx *client) +{ + /* offset tells from where the GET params start */ + int ret, remaining, offset = dynamic_detail->common.path_len; + char *ptr; + char tmp[TEMP_BUF_LEN]; + + ret = SEND_RESPONSE(RESPONSE_TEMPLATE_CHUNKED, + dynamic_detail->common.content_type); + if (ret < 0) { + return ret; + } + + remaining = strlen(&client->url_buffer[dynamic_detail->common.path_len]); + + /* Pass URL to the client */ + while (1) { + int copy_len, send_len; + enum http_data_status status; + + ptr = &client->url_buffer[offset]; + copy_len = MIN(remaining, dynamic_detail->data_buffer_len); + + memcpy(dynamic_detail->data_buffer, ptr, copy_len); + + if (copy_len == remaining) { + status = HTTP_SERVER_DATA_FINAL; + } else { + status = HTTP_SERVER_DATA_MORE; + } + + send_len = dynamic_detail->cb(client, status, + dynamic_detail->data_buffer, + copy_len, dynamic_detail->user_data); + if (send_len > 0) { + ret = snprintk(tmp, sizeof(tmp), "%x\r\n", send_len); + ret = http_server_sendall(client, tmp, ret); + if (ret < 0) { + return ret; + } + + ret = http_server_sendall(client, + dynamic_detail->data_buffer, + send_len); + if (ret < 0) { + return ret; + } + + (void)http_server_sendall(client, crlf, 2); + + offset += copy_len; + remaining -= copy_len; + + continue; + } + + break; + } + + dynamic_detail->holder = NULL; + + ret = http_server_sendall(client, final_chunk, + sizeof(final_chunk) - 1); + if (ret < 0) { + return ret; + } + + return 0; +} + +static int dynamic_post_req(struct http_resource_detail_dynamic *dynamic_detail, + struct http_client_ctx *client) +{ + /* offset tells from where the POST params start */ + char *start = client->cursor; + int ret, remaining = client->data_len, offset = 0; + int copy_len; + char *ptr; + char tmp[TEMP_BUF_LEN]; + + if (start == NULL) { + return -ENOENT; + } + + if (!client->headers_sent) { + ret = SEND_RESPONSE(RESPONSE_TEMPLATE_CHUNKED, + dynamic_detail->common.content_type); + if (ret < 0) { + return ret; + } + client->headers_sent = true; + } + + copy_len = MIN(remaining, dynamic_detail->data_buffer_len); + while (copy_len > 0) { + enum http_data_status status; + int send_len; + + ptr = &start[offset]; + + memcpy(dynamic_detail->data_buffer, ptr, copy_len); + + if (copy_len == remaining && + client->parser_state == HTTP1_MESSAGE_COMPLETE_STATE) { + status = HTTP_SERVER_DATA_FINAL; + } else { + status = HTTP_SERVER_DATA_MORE; + } + + send_len = dynamic_detail->cb(client, status, + dynamic_detail->data_buffer, + copy_len, dynamic_detail->user_data); + if (send_len > 0) { + ret = snprintk(tmp, sizeof(tmp), "%x\r\n", send_len); + ret = http_server_sendall(client, tmp, ret); + if (ret < 0) { + return ret; + } + + ret = http_server_sendall(client, + dynamic_detail->data_buffer, + send_len); + if (ret < 0) { + return ret; + } + + (void)http_server_sendall(client, crlf, 2); + + offset += copy_len; + remaining -= copy_len; + } + + copy_len = MIN(remaining, dynamic_detail->data_buffer_len); + } + + if (client->parser_state == HTTP1_MESSAGE_COMPLETE_STATE) { + ret = http_server_sendall(client, final_chunk, + sizeof(final_chunk) - 1); + if (ret < 0) { + return ret; + } + + dynamic_detail->holder = NULL; + } + + return 0; +} + +static int handle_http1_dynamic_resource( + struct http_resource_detail_dynamic *dynamic_detail, + struct http_client_ctx *client) +{ + uint32_t user_method; + int ret; + + if (dynamic_detail->cb == NULL) { + return -ESRCH; + } + + user_method = dynamic_detail->common.bitmask_of_supported_http_methods; + + if (!(BIT(client->method) & user_method)) { + return -ENOPROTOOPT; + } + + if (dynamic_detail->holder != NULL && dynamic_detail->holder != client) { + static const char conflict_response[] = + "HTTP/1.1 409 Conflict\r\n\r\n"; + + ret = http_server_sendall(client, conflict_response, + sizeof(conflict_response) - 1); + if (ret < 0) { + LOG_DBG("Cannot write to socket (%d)", ret); + return ret; + } + + return enter_http_done_state(client); + } + + dynamic_detail->holder = client; + + switch (client->method) { + case HTTP_HEAD: + if (user_method & BIT(HTTP_HEAD)) { + ret = SEND_RESPONSE(RESPONSE_TEMPLATE_DYNAMIC, + dynamic_detail->common.content_type); + if (ret < 0) { + return ret; + } + + dynamic_detail->holder = NULL; + + return 0; + } + + case HTTP_GET: + /* For GET request, we do not pass any data to the app but let the app + * send data to the peer. + */ + if (user_method & BIT(HTTP_GET)) { + return dynamic_get_req(dynamic_detail, client); + } + + goto not_supported; + + case HTTP_POST: + if (user_method & BIT(HTTP_POST)) { + return dynamic_post_req(dynamic_detail, client); + } + + goto not_supported; + +not_supported: + default: + LOG_DBG("HTTP method %s (%d) not supported.", + http_method_str(client->method), + client->method); + + return -ENOTSUP; + } + + return 0; +} + +static int on_header_field(struct http_parser *parser, const char *at, + size_t length) +{ + struct http_client_ctx *ctx = CONTAINER_OF(parser, + struct http_client_ctx, + parser); + size_t offset = strnlen(ctx->header_buffer, sizeof(ctx->header_buffer)); + + if (offset + length > sizeof(ctx->header_buffer) - 1U) { + LOG_DBG("Header %s too long (by %zu bytes)", "field", + offset + length - sizeof(ctx->header_buffer) - 1U); + ctx->header_buffer[0] = '\0'; + } else { + memcpy(ctx->header_buffer + offset, at, length); + offset += length; + ctx->header_buffer[offset] = '\0'; + + if (parser->state == s_header_value_discard_ws) { + /* This means that the header field is fully parsed, + * and we can use it directly. + */ + if (strncasecmp(ctx->header_buffer, "Upgrade", + sizeof("Upgrade") - 1) == 0) { + ctx->has_upgrade_header = true; + } else if (strncasecmp(ctx->header_buffer, + "Sec-WebSocket-Key", + sizeof("Sec-WebSocket-Key") - 1) == 0) { + ctx->websocket_sec_key_next = true; + } + + ctx->header_buffer[0] = '\0'; + } + } + + ctx->parser_state = HTTP1_RECEIVING_HEADER_STATE; + + return 0; +} + +static int on_header_value(struct http_parser *parser, + const char *at, size_t length) +{ + struct http_client_ctx *ctx = CONTAINER_OF(parser, + struct http_client_ctx, + parser); + size_t offset = strnlen(ctx->header_buffer, sizeof(ctx->header_buffer)); + + if (offset + length > sizeof(ctx->header_buffer) - 1U) { + LOG_DBG("Header %s too long (by %zu bytes)", "value", + offset + length - sizeof(ctx->header_buffer) - 1U); + ctx->header_buffer[0] = '\0'; + } else { + memcpy(ctx->header_buffer + offset, at, length); + offset += length; + ctx->header_buffer[offset] = '\0'; + + if (parser->state == s_header_almost_done) { + if (ctx->has_upgrade_header) { + if (strncasecmp(ctx->header_buffer, "h2c", + sizeof("h2c") - 1) == 0) { + ctx->http2_upgrade = true; + } else if (strncasecmp(ctx->header_buffer, + "websocket", + sizeof("websocket") - 1) == 0) { + ctx->websocket_upgrade = true; + } + + ctx->has_upgrade_header = false; + } + + if (ctx->websocket_sec_key_next) { +#if defined(CONFIG_WEBSOCKET) + strncpy(ctx->ws_sec_key, ctx->header_buffer, + MIN(sizeof(ctx->ws_sec_key), offset)); +#endif + ctx->websocket_sec_key_next = false; + } + + ctx->header_buffer[0] = '\0'; + } + } + + return 0; +} + +static int on_headers_complete(struct http_parser *parser) +{ + struct http_client_ctx *ctx = CONTAINER_OF(parser, + struct http_client_ctx, + parser); + + ctx->parser_state = HTTP1_RECEIVED_HEADER_STATE; + + return 0; +} + +static int on_url(struct http_parser *parser, const char *at, size_t length) +{ + struct http_client_ctx *ctx = CONTAINER_OF(parser, + struct http_client_ctx, + parser); + size_t offset = strlen(ctx->url_buffer); + + ctx->parser_state = HTTP1_WAITING_HEADER_STATE; + + if (offset + length > sizeof(ctx->url_buffer) - 1) { + LOG_DBG("URL too long to handle"); + return -EMSGSIZE; + } + + memcpy(ctx->url_buffer + offset, at, length); + offset += length; + ctx->url_buffer[offset] = '\0'; + + return 0; +} + +static int on_body(struct http_parser *parser, const char *at, size_t length) +{ + struct http_client_ctx *ctx = CONTAINER_OF(parser, + struct http_client_ctx, + parser); + + ctx->parser_state = HTTP1_RECEIVING_DATA_STATE; + + ctx->http1_frag_data_len += length; + + return 0; +} + +static int on_message_complete(struct http_parser *parser) +{ + struct http_client_ctx *ctx = CONTAINER_OF(parser, + struct http_client_ctx, + parser); + + ctx->parser_state = HTTP1_MESSAGE_COMPLETE_STATE; + + return 0; +} + +int enter_http1_request(struct http_client_ctx *client) +{ + client->server_state = HTTP_SERVER_REQUEST_STATE; + + http_parser_init(&client->parser, HTTP_REQUEST); + http_parser_settings_init(&client->parser_settings); + + client->parser_settings.on_header_field = on_header_field; + client->parser_settings.on_header_value = on_header_value; + client->parser_settings.on_headers_complete = on_headers_complete; + client->parser_settings.on_url = on_url; + client->parser_settings.on_body = on_body; + client->parser_settings.on_message_complete = on_message_complete; + client->parser_state = HTTP1_INIT_HEADER_STATE; + + memset(client->header_buffer, 0, sizeof(client->header_buffer)); + + return 0; +} + +int handle_http1_request(struct http_client_ctx *client) +{ + int ret, path_len = 0; + struct http_resource_detail *detail; + bool skip_headers = (client->parser_state < HTTP1_RECEIVING_DATA_STATE); + size_t parsed; + + LOG_DBG("HTTP_SERVER_REQUEST"); + + client->http1_frag_data_len = 0; + + parsed = http_parser_execute(&client->parser, &client->parser_settings, + client->cursor, client->data_len); + + if (parsed > client->data_len) { + LOG_ERR("HTTP/1 parser error, too much data consumed"); + return -EBADMSG; + } + + if (client->parser.http_errno != HPE_OK) { + LOG_ERR("HTTP/1 parsing error, %d", client->parser.http_errno); + return -EBADMSG; + } + + if (client->parser_state < HTTP1_RECEIVED_HEADER_STATE) { + client->cursor += parsed; + client->data_len -= parsed; + + return 0; + } + + client->method = client->parser.method; + client->has_upgrade_header = client->parser.upgrade; + + if (skip_headers) { + LOG_DBG("Requested URL: %s", client->url_buffer); + + size_t frag_headers_len; + + if (parsed < client->http1_frag_data_len) { + return -EBADMSG; + } + + frag_headers_len = parsed - client->http1_frag_data_len; + parsed -= frag_headers_len; + + client->cursor += frag_headers_len; + client->data_len -= frag_headers_len; + } + + if (client->has_upgrade_header) { + static const char upgrade_required[] = + "HTTP/1.1 426 Upgrade required\r\n" + "Upgrade: "; + static const char upgrade_msg[] = + "Content-Length: 13\r\n\r\n" + "Wrong upgrade"; + const char *needed_upgrade = "h2c\r\n"; + + if (client->websocket_upgrade) { + if (IS_ENABLED(CONFIG_HTTP_SERVER_WEBSOCKET)) { + detail = get_resource_detail(client->url_buffer, + &path_len, true); + if (detail == NULL) { + goto not_found; + } + + client->current_detail = detail; + return handle_http1_to_websocket_upgrade(client); + } + + goto upgrade_not_found; + } + + if (client->http2_upgrade) { + return handle_http1_to_http2_upgrade(client); + } + +upgrade_not_found: + ret = http_server_sendall(client, upgrade_required, + sizeof(upgrade_required) - 1); + if (ret < 0) { + LOG_DBG("Cannot write to socket (%d)", ret); + return ret; + } + + ret = http_server_sendall(client, needed_upgrade, + strlen(needed_upgrade)); + if (ret < 0) { + LOG_DBG("Cannot write to socket (%d)", ret); + return ret; + } + + ret = http_server_sendall(client, upgrade_msg, + sizeof(upgrade_msg) - 1); + if (ret < 0) { + LOG_DBG("Cannot write to socket (%d)", ret); + return ret; + } + } + + detail = get_resource_detail(client->url_buffer, &path_len, false); + if (detail != NULL) { + detail->path_len = path_len; + + if (detail->type == HTTP_RESOURCE_TYPE_STATIC) { + ret = handle_http1_static_resource( + (struct http_resource_detail_static *)detail, + client); + if (ret < 0) { + return ret; + } + } else if (detail->type == HTTP_RESOURCE_TYPE_DYNAMIC) { + ret = handle_http1_dynamic_resource( + (struct http_resource_detail_dynamic *)detail, + client); + if (ret < 0) { + return ret; + } + } + } else { +not_found: ; /* Add extra semicolon to make clang to compile when using label */ + static const char not_found_response[] = + "HTTP/1.1 404 Not Found\r\n" + "Content-Length: 9\r\n\r\n" + "Not Found"; + + ret = http_server_sendall(client, not_found_response, + sizeof(not_found_response) - 1); + if (ret < 0) { + LOG_DBG("Cannot write to socket (%d)", ret); + return ret; + } + } + + client->cursor += parsed; + client->data_len -= parsed; + + if (client->parser_state == HTTP1_MESSAGE_COMPLETE_STATE) { + LOG_DBG("Connection closed client %p", client); + enter_http_done_state(client); + } + + return 0; +} diff --git a/subsys/net/lib/http/http_server_http2.c b/subsys/net/lib/http/http_server_http2.c new file mode 100644 index 00000000000..b455340bf38 --- /dev/null +++ b/subsys/net/lib/http/http_server_http2.c @@ -0,0 +1,1252 @@ +/* + * Copyright (c) 2023, Emna Rekik + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +LOG_MODULE_DECLARE(net_http_server, CONFIG_NET_HTTP_SERVER_LOG_LEVEL); + +#include "headers/server_internal.h" + +static const char content_404[] = { +#ifdef INCLUDE_HTML_CONTENT +#include "not_found_page.html.gz.inc" +#endif +}; + +static bool settings_ack_flag(unsigned char flags) +{ + return (flags & HTTP_SERVER_FLAG_SETTINGS_ACK) != 0; +} + +/* Disabled for now to avoid warning, as temporarily not used. */ +static bool end_headers_flag(unsigned char flags) +{ + return (flags & HTTP_SERVER_FLAG_END_HEADERS) != 0; +} + +static bool end_stream_flag(unsigned char flags) +{ + return (flags & HTTP_SERVER_FLAG_END_STREAM) != 0; +} + +static void print_http_frames(struct http_client_ctx *client) +{ +#if defined(PRINT_COLOR) + const char *bold = "\033[1m"; + const char *reset = "\033[0m"; + const char *green = "\033[32m"; + const char *blue = "\033[34m"; +#else + const char *bold = ""; + const char *reset = ""; + const char *green = ""; + const char *blue = ""; +#endif + + struct http_frame *frame = &client->current_frame; + int payload_received_length; + + LOG_DBG("%s=====================================%s", green, reset); + LOG_DBG("%sReceived %s Frame :%s", bold, get_frame_type_name(frame->type), reset); + LOG_DBG(" %sLength:%s %u", blue, reset, frame->length); + LOG_DBG(" %sType:%s %u (%s)", blue, reset, frame->type, get_frame_type_name(frame->type)); + LOG_DBG(" %sFlags:%s %u", blue, reset, frame->flags); + LOG_DBG(" %sStream Identifier:%s %u", blue, reset, frame->stream_identifier); + + if (client->data_len > frame->length) { + payload_received_length = frame->length; + } else { + payload_received_length = client->data_len; + } + + LOG_HEXDUMP_DBG(frame->payload, payload_received_length, "Payload"); + LOG_DBG("%s=====================================%s", green, reset); +} + +static struct http_stream_ctx *find_http_stream_context( + struct http_client_ctx *client, uint32_t stream_id) +{ + ARRAY_FOR_EACH(client->streams, i) { + if (client->streams[i].stream_id == stream_id) { + return &client->streams[i]; + } + } + + return NULL; +} + +static struct http_stream_ctx *allocate_http_stream_context( + struct http_client_ctx *client, uint32_t stream_id) +{ + ARRAY_FOR_EACH(client->streams, i) { + if (client->streams[i].stream_state == HTTP_SERVER_STREAM_IDLE) { + client->streams[i].stream_id = stream_id; + client->streams[i].stream_state = HTTP_SERVER_STREAM_OPEN; + client->streams[i].window_size = + HTTP_SERVER_INITIAL_WINDOW_SIZE; + return &client->streams[i]; + } + } + + return NULL; +} + +static void release_http_stream_context(struct http_client_ctx *client, + uint32_t stream_id) +{ + ARRAY_FOR_EACH(client->streams, i) { + if (client->streams[i].stream_id == stream_id) { + client->streams[i].stream_id = 0; + client->streams[i].stream_state = HTTP_SERVER_STREAM_IDLE; + break; + } + } +} + +static int add_header_field(struct http_client_ctx *client, uint8_t **buf, + size_t *buflen, const char *name, const char *value) +{ + int ret; + + client->header_field.name = name; + client->header_field.name_len = strlen(name); + client->header_field.value = value; + client->header_field.value_len = strlen(value); + + ret = http_hpack_encode_header(*buf, *buflen, &client->header_field); + if (ret < 0) { + return ret; + } + + *buf += ret; + *buflen -= ret; + + return 0; +} + +static void encode_frame_header(uint8_t *buf, uint32_t payload_len, + enum http_frame_type frame_type, + uint8_t flags, uint32_t stream_id) +{ + sys_put_be24(payload_len, &buf[HTTP_SERVER_FRAME_LENGTH_OFFSET]); + buf[HTTP_SERVER_FRAME_TYPE_OFFSET] = frame_type; + buf[HTTP_SERVER_FRAME_FLAGS_OFFSET] = flags; + sys_put_be32(stream_id, &buf[HTTP_SERVER_FRAME_STREAM_ID_OFFSET]); +} + +static int send_headers_frame(struct http_client_ctx *client, + enum http_status status, uint32_t stream_id, + struct http_resource_detail *detail_common, + uint8_t flags) +{ + uint8_t headers_frame[64]; + uint8_t status_str[4]; + uint8_t *buf = headers_frame + HTTP_SERVER_FRAME_HEADER_SIZE; + size_t buflen = sizeof(headers_frame) - HTTP_SERVER_FRAME_HEADER_SIZE; + size_t payload_len; + int ret; + + ret = snprintf(status_str, sizeof(status_str), "%d", status); + if (ret > sizeof(status_str) - 1) { + return -EINVAL; + } + + ret = add_header_field(client, &buf, &buflen, ":status", status_str); + if (ret < 0) { + return ret; + } + + if (detail_common && detail_common->content_encoding != NULL) { + ret = add_header_field(client, &buf, &buflen, "content-encoding", + "gzip"); + if (ret < 0) { + return ret; + } + } + + if (detail_common && detail_common->content_type != NULL) { + ret = add_header_field(client, &buf, &buflen, "content-type", + detail_common->content_type); + if (ret < 0) { + return ret; + } + } + + payload_len = sizeof(headers_frame) - buflen - HTTP_SERVER_FRAME_HEADER_SIZE; + flags |= HTTP_SERVER_FLAG_END_HEADERS; + + encode_frame_header(headers_frame, payload_len, HTTP_SERVER_HEADERS_FRAME, + flags, stream_id); + + ret = http_server_sendall(client, headers_frame, + payload_len + HTTP_SERVER_FRAME_HEADER_SIZE); + if (ret < 0) { + LOG_DBG("Cannot write to socket (%d)", ret); + return ret; + } + + return 0; +} + +static int send_data_frame(struct http_client_ctx *client, const char *payload, + size_t length, uint32_t stream_id, uint8_t flags) +{ + uint8_t frame_header[HTTP_SERVER_FRAME_HEADER_SIZE]; + int ret; + + encode_frame_header(frame_header, length, HTTP_SERVER_DATA_FRAME, + end_stream_flag(flags) ? + HTTP_SERVER_FLAG_END_STREAM : 0, + stream_id); + + ret = http_server_sendall(client, frame_header, sizeof(frame_header)); + if (ret < 0) { + LOG_DBG("Cannot write to socket (%d)", ret); + } else { + if (payload != NULL && length > 0) { + ret = http_server_sendall(client, payload, length); + if (ret < 0) { + LOG_DBG("Cannot write to socket (%d)", ret); + } + } + } + + return ret; +} + +int send_settings_frame(struct http_client_ctx *client, bool ack) +{ + uint8_t settings_frame[HTTP_SERVER_FRAME_HEADER_SIZE + + 2 * sizeof(struct http_settings_field)]; + struct http_settings_field *setting; + size_t len; + int ret; + + if (ack) { + encode_frame_header(settings_frame, 0, + HTTP_SERVER_SETTINGS_FRAME, + HTTP_SERVER_FLAG_SETTINGS_ACK, 0); + len = HTTP_SERVER_FRAME_HEADER_SIZE; + } else { + encode_frame_header(settings_frame, + 2 * sizeof(struct http_settings_field), + HTTP_SERVER_SETTINGS_FRAME, 0, 0); + + setting = (struct http_settings_field *) + (settings_frame + HTTP_SERVER_FRAME_HEADER_SIZE); + UNALIGNED_PUT(htons(HTTP_SETTINGS_HEADER_TABLE_SIZE), + &setting->id); + UNALIGNED_PUT(0, &setting->value); + + setting++; + UNALIGNED_PUT(htons(HTTP_SETTINGS_MAX_CONCURRENT_STREAMS), + &setting->id); + UNALIGNED_PUT(htonl(CONFIG_HTTP_SERVER_MAX_STREAMS), + &setting->value); + + len = HTTP_SERVER_FRAME_HEADER_SIZE + + 2 * sizeof(struct http_settings_field); + } + + ret = http_server_sendall(client, settings_frame, len); + if (ret < 0) { + LOG_DBG("Cannot write to socket (%d)", ret); + return ret; + } + + return 0; +} + +int send_window_update_frame(struct http_client_ctx *client, + struct http_stream_ctx *stream) +{ + uint8_t window_update_frame[HTTP_SERVER_FRAME_HEADER_SIZE + + sizeof(uint32_t)]; + uint32_t window_update; + uint32_t stream_id; + int ret; + + if (stream != NULL) { + window_update = HTTP_SERVER_INITIAL_WINDOW_SIZE - stream->window_size; + stream->window_size = HTTP_SERVER_INITIAL_WINDOW_SIZE; + stream_id = stream->stream_id; + } else { + window_update = HTTP_SERVER_INITIAL_WINDOW_SIZE - client->window_size; + client->window_size = HTTP_SERVER_INITIAL_WINDOW_SIZE; + stream_id = 0; + } + + encode_frame_header(window_update_frame, sizeof(uint32_t), + HTTP_SERVER_WINDOW_UPDATE_FRAME, + 0, stream_id); + sys_put_be32(window_update, + window_update_frame + HTTP_SERVER_FRAME_HEADER_SIZE); + + ret = http_server_sendall(client, window_update_frame, + sizeof(window_update_frame)); + if (ret < 0) { + LOG_DBG("Cannot write to socket (%d)", ret); + return ret; + } + + return 0; +} + +static int send_http2_404(struct http_client_ctx *client, + struct http_frame *frame) +{ + int ret; + + ret = send_headers_frame(client, HTTP_404_NOT_FOUND, + frame->stream_identifier, NULL, 0); + if (ret < 0) { + LOG_DBG("Cannot write to socket (%d)", ret); + return ret; + } + + ret = send_data_frame(client, content_404, sizeof(content_404), + frame->stream_identifier, + HTTP_SERVER_FLAG_END_STREAM); + if (ret < 0) { + LOG_DBG("Cannot write to socket (%d)", ret); + } + + return ret; +} + +static int send_http2_409(struct http_client_ctx *client, + struct http_frame *frame) +{ + int ret; + + ret = send_headers_frame(client, HTTP_409_CONFLICT, + frame->stream_identifier, NULL, + HTTP_SERVER_FLAG_END_STREAM); + if (ret < 0) { + LOG_DBG("Cannot write to socket (%d)", ret); + } + + return ret; +} + +static int handle_http2_static_resource( + struct http_resource_detail_static *static_detail, + struct http_frame *frame, struct http_client_ctx *client) +{ + const char *content_200; + size_t content_len; + int ret; + + if (!(static_detail->common.bitmask_of_supported_http_methods & BIT(HTTP_GET))) { + return -ENOTSUP; + } + + content_200 = static_detail->static_data; + content_len = static_detail->static_data_len; + + ret = send_headers_frame(client, HTTP_200_OK, frame->stream_identifier, + &static_detail->common, 0); + if (ret < 0) { + LOG_DBG("Cannot write to socket (%d)", ret); + goto out; + } + + ret = send_data_frame(client, content_200, content_len, + frame->stream_identifier, + HTTP_SERVER_FLAG_END_STREAM); + if (ret < 0) { + LOG_DBG("Cannot write to socket (%d)", ret); + goto out; + } + +out: + return ret; +} + +static int dynamic_get_req_v2(struct http_resource_detail_dynamic *dynamic_detail, + struct http_client_ctx *client) +{ + struct http_frame *frame = &client->current_frame; + int ret, remaining, offset = dynamic_detail->common.path_len; + char *ptr; + + ret = send_headers_frame(client, HTTP_200_OK, frame->stream_identifier, + &dynamic_detail->common, 0); + if (ret < 0) { + LOG_DBG("Cannot write to socket (%d)", ret); + return ret; + } + + remaining = strlen(&client->url_buffer[dynamic_detail->common.path_len]); + + /* Pass URL to the client */ + while (1) { + int copy_len, send_len; + enum http_data_status status; + + ptr = &client->url_buffer[offset]; + copy_len = MIN(remaining, dynamic_detail->data_buffer_len); + + if (copy_len > 0) { + memcpy(dynamic_detail->data_buffer, ptr, copy_len); + } + + if (copy_len == remaining) { + status = HTTP_SERVER_DATA_FINAL; + } else { + status = HTTP_SERVER_DATA_MORE; + } + + send_len = dynamic_detail->cb(client, status, + dynamic_detail->data_buffer, + copy_len, + dynamic_detail->user_data); + if (send_len > 0) { + ret = send_data_frame(client, + dynamic_detail->data_buffer, + send_len, + frame->stream_identifier, + 0); + if (ret < 0) { + break; + } + + offset += copy_len; + remaining -= copy_len; + + continue; + } + + ret = send_data_frame(client, NULL, 0, + frame->stream_identifier, + HTTP_SERVER_FLAG_END_STREAM); + if (ret < 0) { + LOG_DBG("Cannot send last frame (%d)", ret); + } + + dynamic_detail->holder = NULL; + + break; + } + + return ret; +} + +static int dynamic_post_req_v2(struct http_resource_detail_dynamic *dynamic_detail, + struct http_client_ctx *client) +{ + struct http_frame *frame = &client->current_frame; + size_t data_len; + int copy_len; + int ret = 0; + + if (dynamic_detail == NULL) { + return -ENOENT; + } + + data_len = MIN(frame->length, client->data_len); + copy_len = MIN(data_len, dynamic_detail->data_buffer_len); + + while (copy_len > 0) { + enum http_data_status status; + int send_len; + + /* Read all the user data and pass it to application. After + * passing all the data, if application returns 0, it means + * that there is no more data to send to client. + */ + memcpy(dynamic_detail->data_buffer, client->cursor, copy_len); + data_len -= copy_len; + client->cursor += copy_len; + client->data_len -= copy_len; + frame->length -= copy_len; + + if (frame->length == 0 && end_stream_flag(frame->flags)) { + status = HTTP_SERVER_DATA_FINAL; + } else { + status = HTTP_SERVER_DATA_MORE; + } + + send_len = dynamic_detail->cb(client, status, + dynamic_detail->data_buffer, + copy_len, + dynamic_detail->user_data); + if (send_len > 0) { + uint8_t flags = 0; + + if (!client->headers_sent) { + ret = send_headers_frame( + client, HTTP_200_OK, frame->stream_identifier, + &dynamic_detail->common, 0); + if (ret < 0) { + LOG_DBG("Cannot write to socket (%d)", ret); + return ret; + } + + client->headers_sent = true; + } + + /* In case no more data is available, that was the last + * callback call, so we can include END_STREAM flag. + */ + if (frame->length == 0 && end_stream_flag(frame->flags)) { + flags = HTTP_SERVER_FLAG_END_STREAM; + } + + ret = send_data_frame(client, + dynamic_detail->data_buffer, + send_len, + frame->stream_identifier, + flags); + if (ret < 0) { + LOG_DBG("Cannot send data frame (%d)", ret); + return ret; + } + } + + copy_len = MIN(data_len, dynamic_detail->data_buffer_len); + }; + + if (frame->length == 0 && end_stream_flag(frame->flags)) { + if (!client->headers_sent) { + /* The callback did not report any data to send, therefore send + * headers frame now, including END_STREAM flag. + */ + ret = send_headers_frame( + client, HTTP_200_OK, frame->stream_identifier, + &dynamic_detail->common, + HTTP_SERVER_FLAG_END_STREAM); + if (ret < 0) { + LOG_DBG("Cannot write to socket (%d)", ret); + return ret; + } + + client->headers_sent = true; + } + + dynamic_detail->holder = NULL; + } + + + return ret; +} + +static int handle_http2_dynamic_resource( + struct http_resource_detail_dynamic *dynamic_detail, + struct http_frame *frame, struct http_client_ctx *client) +{ + uint32_t user_method; + int ret; + + if (dynamic_detail->cb == NULL) { + return -ESRCH; + } + + user_method = dynamic_detail->common.bitmask_of_supported_http_methods; + + if (!(BIT(client->method) & user_method)) { + return -ENOPROTOOPT; + } + + if (dynamic_detail->holder != NULL && dynamic_detail->holder != client) { + ret = send_http2_409(client, frame); + if (ret < 0) { + return ret; + } + + return enter_http_done_state(client); + } + + dynamic_detail->holder = client; + + switch (client->method) { + case HTTP_GET: + if (user_method & BIT(HTTP_GET)) { + return dynamic_get_req_v2(dynamic_detail, client); + } + + goto not_supported; + + case HTTP_POST: + /* The data will come in DATA frames. Remember the detail ptr + * which needs to be known when passing data to application. + */ + if (user_method & BIT(HTTP_POST)) { + client->current_detail = + (struct http_resource_detail *)dynamic_detail; + break; + } + + goto not_supported; + +not_supported: + default: + LOG_DBG("HTTP method %s (%d) not supported.", + http_method_str(client->method), + client->method); + + return -ENOTSUP; + } + + return 0; +} + +int enter_http2_request(struct http_client_ctx *client) +{ + int ret; + + client->server_state = HTTP_SERVER_FRAME_HEADER_STATE; + client->data_len -= sizeof(HTTP2_PREFACE) - 1; + client->cursor += sizeof(HTTP2_PREFACE) - 1; + + /* HTTP/2 client preface received, send server preface + * (settings frame). + */ + if (!client->preface_sent) { + ret = send_settings_frame(client, false); + if (ret < 0) { + return ret; + } + + client->preface_sent = true; + } + + return 0; +} + +static int enter_http_frame_settings_state(struct http_client_ctx *client) +{ + client->server_state = HTTP_SERVER_FRAME_SETTINGS_STATE; + + return 0; +} + +static int enter_http_frame_data_state(struct http_client_ctx *client) +{ + struct http_frame *frame = &client->current_frame; + struct http_stream_ctx *stream; + + if (frame->stream_identifier == 0) { + LOG_DBG("Stream ID 0 is forbidden for data frames."); + return -EBADMSG; + } + + stream = find_http_stream_context(client, frame->stream_identifier); + if (stream == NULL) { + LOG_DBG("No stream context found for ID %d", + frame->stream_identifier); + return -EBADMSG; + } + + if (stream->stream_state != HTTP_SERVER_STREAM_OPEN && + stream->stream_state != HTTP_SERVER_STREAM_HALF_CLOSED_REMOTE) { + LOG_DBG("Stream ID %d in a wrong state %d", stream->stream_id, + stream->stream_state); + return -EBADMSG; + } + + stream->window_size -= frame->length; + client->window_size -= frame->length; + client->server_state = HTTP_SERVER_FRAME_DATA_STATE; + + return 0; +} + +static int enter_http_frame_headers_state(struct http_client_ctx *client) +{ + struct http_frame *frame = &client->current_frame; + struct http_stream_ctx *stream; + + stream = find_http_stream_context(client, frame->stream_identifier); + if (!stream) { + LOG_DBG("|| stream ID || %d", frame->stream_identifier); + + stream = allocate_http_stream_context(client, frame->stream_identifier); + if (!stream) { + LOG_DBG("No available stream slots. Connection closed."); + + return -ENOMEM; + } + } + + client->server_state = HTTP_SERVER_FRAME_HEADERS_STATE; + + return 0; +} + +static int enter_http_frame_continuation_state(struct http_client_ctx *client) +{ + client->server_state = HTTP_SERVER_FRAME_CONTINUATION_STATE; + + return 0; +} + +static int enter_http_frame_window_update_state(struct http_client_ctx *client) +{ + client->server_state = HTTP_SERVER_FRAME_WINDOW_UPDATE_STATE; + + return 0; +} + +static int enter_http_frame_priority_state(struct http_client_ctx *client) +{ + client->server_state = HTTP_SERVER_FRAME_PRIORITY_STATE; + + return 0; +} + +static int enter_http_frame_rst_stream_state(struct http_client_ctx *client) +{ + client->server_state = HTTP_SERVER_FRAME_RST_STREAM_STATE; + + return 0; +} + +static int enter_http_frame_goaway_state(struct http_client_ctx *client) +{ + client->server_state = HTTP_SERVER_FRAME_GOAWAY_STATE; + + return 0; +} + +int handle_http_frame_header(struct http_client_ctx *client) +{ + int bytes_consumed; + int parse_result; + + LOG_DBG("HTTP_SERVER_FRAME_HEADER"); + + parse_result = parse_http_frame_header(client); + if (parse_result == 0) { + return -EAGAIN; + } else if (parse_result < 0) { + return parse_result; + } + + bytes_consumed = HTTP_SERVER_FRAME_HEADER_SIZE; + + client->cursor += bytes_consumed; + client->data_len -= bytes_consumed; + + switch (client->current_frame.type) { + case HTTP_SERVER_DATA_FRAME: + return enter_http_frame_data_state(client); + case HTTP_SERVER_HEADERS_FRAME: + return enter_http_frame_headers_state(client); + case HTTP_SERVER_CONTINUATION_FRAME: + return enter_http_frame_continuation_state(client); + case HTTP_SERVER_SETTINGS_FRAME: + return enter_http_frame_settings_state(client); + case HTTP_SERVER_WINDOW_UPDATE_FRAME: + return enter_http_frame_window_update_state(client); + case HTTP_SERVER_RST_STREAM_FRAME: + return enter_http_frame_rst_stream_state(client); + case HTTP_SERVER_GOAWAY_FRAME: + return enter_http_frame_goaway_state(client); + case HTTP_SERVER_PRIORITY_FRAME: + return enter_http_frame_priority_state(client); + default: + return enter_http_done_state(client); + } + + return 0; +} + +/* This feature is theoretically obsoleted in RFC9113, but curl for instance + * still uses it, so implement as described in RFC7540. + */ +int handle_http1_to_http2_upgrade(struct http_client_ctx *client) +{ + static const char switching_protocols[] = + "HTTP/1.1 101 Switching Protocols\r\n" + "Connection: Upgrade\r\n" + "Upgrade: h2c\r\n" + "\r\n"; + struct http_frame *frame = &client->current_frame; + struct http_resource_detail *detail; + int path_len; + int ret; + + /* Create an artificial Data frame, so that we can proceed with HTTP2 + * processing. The HTTP/1.1 request that is sent prior to upgrade is + * assigned a stream identifier of 1. + */ + frame->stream_identifier = 1; + frame->type = HTTP_SERVER_DATA_FRAME; + frame->length = client->http1_frag_data_len; + if (client->parser_state == HTTP1_MESSAGE_COMPLETE_STATE) { + frame->flags = HTTP_SERVER_FLAG_END_STREAM; + } else { + frame->flags = 0; + } + + if (!client->preface_sent) { + ret = http_server_sendall(client, switching_protocols, + sizeof(switching_protocols) - 1); + if (ret < 0) { + goto error; + } + + /* The first HTTP/2 frame sent by the server MUST be a server connection + * preface. + */ + ret = send_settings_frame(client, false); + if (ret < 0) { + goto error; + } + + client->preface_sent = true; + } + + detail = get_resource_detail(client->url_buffer, &path_len, false); + if (detail != NULL) { + detail->path_len = path_len; + + if (detail->type == HTTP_RESOURCE_TYPE_STATIC) { + ret = handle_http2_static_resource( + (struct http_resource_detail_static *)detail, + frame, client); + if (ret < 0) { + goto error; + } + } else if (detail->type == HTTP_RESOURCE_TYPE_DYNAMIC) { + ret = handle_http2_dynamic_resource( + (struct http_resource_detail_dynamic *)detail, + frame, client); + if (ret < 0) { + goto error; + } + + if (client->method == HTTP_POST) { + ret = dynamic_post_req_v2( + (struct http_resource_detail_dynamic *)detail, + client); + if (ret < 0) { + goto error; + } + } + + } + } else { + ret = send_http2_404(client, frame); + if (ret < 0) { + goto error; + } + } + + /* Only after the complete HTTP1 payload has been processed, switch + * to HTTP2. + */ + if (client->parser_state == HTTP1_MESSAGE_COMPLETE_STATE) { + client->current_detail = NULL; + client->server_state = HTTP_SERVER_PREFACE_STATE; + client->cursor += client->data_len; + client->data_len = 0; + } + + return 0; + +error: + return ret; +} + +int handle_http_frame_data(struct http_client_ctx *client) +{ + struct http_frame *frame = &client->current_frame; + int ret; + + LOG_DBG("HTTP_SERVER_FRAME_DATA_STATE"); + + print_http_frames(client); + + if (client->current_detail == NULL) { + /* There is no handler */ + LOG_DBG("No dynamic handler found."); + (void)send_http2_404(client, frame); + return -ENOENT; + } + + ret = dynamic_post_req_v2( + (struct http_resource_detail_dynamic *)client->current_detail, + client); + if (ret < 0 && ret == -ENOENT) { + ret = send_http2_404(client, frame); + } + + if (ret < 0) { + return ret; + } + + if (frame->length == 0) { + struct http_stream_ctx *stream = + find_http_stream_context(client, frame->stream_identifier); + + if (stream == NULL) { + LOG_DBG("No stream context found for ID %d", + frame->stream_identifier); + return -EBADMSG; + } + + ret = send_window_update_frame(client, stream); + if (ret < 0) { + return ret; + } + + ret = send_window_update_frame(client, NULL); + if (ret < 0) { + return ret; + } + + /* Whole frame consumed, expect next one. */ + client->server_state = HTTP_SERVER_FRAME_HEADER_STATE; + + if (end_stream_flag(frame->flags)) { + client->current_detail = NULL; + release_http_stream_context(client, frame->stream_identifier); + } + } + + return 0; +} + +static int process_header(struct http_client_ctx *client, + struct http_hpack_header_buf *header) +{ + if (header->name_len == (sizeof(":method") - 1) && + memcmp(header->name, ":method", header->name_len) == 0) { + /* TODO Improve string to method conversion */ + if (header->value_len == (sizeof("GET") - 1) && + memcmp(header->value, "GET", header->value_len) == 0) { + client->method = HTTP_GET; + } else if (header->value_len == (sizeof("POST") - 1) && + memcmp(header->value, "POST", header->value_len) == 0) { + client->method = HTTP_POST; + } else { + /* Unknown method */ + return -EBADMSG; + } + } else if (header->name_len == (sizeof(":path") - 1) && + memcmp(header->name, ":path", header->name_len) == 0) { + if (header->value_len > sizeof(client->url_buffer) - 1) { + /* URL too long to handle */ + return -ENOBUFS; + } + + memcpy(client->url_buffer, header->value, header->value_len); + client->url_buffer[header->value_len] = '\0'; + } else if (header->name_len == (sizeof("content-type") - 1) && + memcmp(header->name, "content-type", header->name_len) == 0) { + if (header->value_len > sizeof(client->content_type) - 1) { + /* Content-type too long to handle */ + return -ENOBUFS; + } + + memcpy(client->content_type, header->value, header->value_len); + client->content_type[header->value_len] = '\0'; + } else if (header->name_len == (sizeof("content-length") - 1) && + memcmp(header->name, "content-length", header->name_len) == 0) { + char len_str[16] = { 0 }; + char *endptr; + unsigned long len; + + memcpy(len_str, header->value, MIN(sizeof(len_str), header->value_len)); + len_str[sizeof(len_str) - 1] = '\0'; + + len = strtoul(len_str, &endptr, 10); + if (*endptr != '\0') { + return -EINVAL; + } + + client->content_len = (size_t)len; + } else { + /* Just ignore for now. */ + LOG_DBG("Ignoring field %.*s", (int)header->name_len, header->name); + } + + return 0; +} + +int handle_http_frame_headers(struct http_client_ctx *client) +{ + struct http_frame *frame = &client->current_frame; + struct http_resource_detail *detail; + int ret, path_len; + + LOG_DBG("HTTP_SERVER_FRAME_HEADERS"); + + print_http_frames(client); + + while (frame->length > 0) { + struct http_hpack_header_buf *header = &client->header_field; + + ret = http_hpack_decode_header(client->cursor, client->data_len, + header); + if (ret <= 0) { + ret = (ret == 0) ? -EBADMSG : ret; + return ret; + } + + if (ret > frame->length) { + LOG_ERR("Protocol error, frame length exceeded"); + return -EBADMSG; + } + + frame->length -= ret; + client->cursor += ret; + client->data_len -= ret; + + LOG_DBG("Parsed header: %.*s %.*s", (int)header->name_len, + header->name, (int)header->value_len, header->value); + + ret = process_header(client, header); + if (ret < 0) { + return ret; + } + } + + if (!end_headers_flag(frame->flags)) { + /* More headers to come in the continuation frame. */ + client->server_state = HTTP_SERVER_FRAME_HEADER_STATE; + + /* TODO Implement continuation frame processing. */ + + return 0; + } + + detail = get_resource_detail(client->url_buffer, &path_len, false); + if (detail != NULL) { + detail->path_len = path_len; + + if (detail->type == HTTP_RESOURCE_TYPE_STATIC) { + ret = handle_http2_static_resource( + (struct http_resource_detail_static *)detail, + frame, client); + if (ret < 0) { + return ret; + } + } else if (detail->type == HTTP_RESOURCE_TYPE_DYNAMIC) { + ret = handle_http2_dynamic_resource( + (struct http_resource_detail_dynamic *)detail, + frame, client); + if (ret < 0) { + return ret; + } + } + + } else { + ret = send_http2_404(client, frame); + if (ret < 0) { + return ret; + } + } + + if (end_stream_flag(frame->flags)) { + release_http_stream_context(client, frame->stream_identifier); + } + + client->server_state = HTTP_SERVER_FRAME_HEADER_STATE; + + return 0; +} + +int handle_http_frame_priority(struct http_client_ctx *client) +{ + struct http_frame *frame = &client->current_frame; + int bytes_consumed; + + LOG_DBG("HTTP_SERVER_FRAME_PRIORITY_STATE"); + + print_http_frames(client); + + if (client->data_len < frame->length) { + return -EAGAIN; + } + + bytes_consumed = client->current_frame.length; + client->data_len -= bytes_consumed; + client->cursor += bytes_consumed; + + client->server_state = HTTP_SERVER_FRAME_HEADER_STATE; + + return 0; +} + +int handle_http_frame_rst_frame(struct http_client_ctx *client) +{ + struct http_frame *frame = &client->current_frame; + int bytes_consumed; + + LOG_DBG("FRAME_RST_STREAM"); + + print_http_frames(client); + + if (client->data_len < frame->length) { + return -EAGAIN; + } + + bytes_consumed = client->current_frame.length; + client->data_len -= bytes_consumed; + client->cursor += bytes_consumed; + + client->server_state = HTTP_SERVER_FRAME_HEADER_STATE; + + return 0; +} + +int handle_http_frame_settings(struct http_client_ctx *client) +{ + struct http_frame *frame = &client->current_frame; + int bytes_consumed; + + LOG_DBG("HTTP_SERVER_FRAME_SETTINGS"); + + print_http_frames(client); + + if (client->data_len < frame->length) { + return -EAGAIN; + } + + bytes_consumed = client->current_frame.length; + client->data_len -= bytes_consumed; + client->cursor += bytes_consumed; + + if (!settings_ack_flag(frame->flags)) { + int ret; + + ret = send_settings_frame(client, true); + if (ret < 0) { + LOG_DBG("Cannot write to socket (%d)", ret); + return ret; + } + } + + client->server_state = HTTP_SERVER_FRAME_HEADER_STATE; + + return 0; +} + +int handle_http_frame_goaway(struct http_client_ctx *client) +{ + struct http_frame *frame = &client->current_frame; + int bytes_consumed; + + LOG_DBG("HTTP_SERVER_FRAME_GOAWAY"); + + print_http_frames(client); + + if (client->data_len < frame->length) { + return -EAGAIN; + } + + bytes_consumed = client->current_frame.length; + client->data_len -= bytes_consumed; + client->cursor += bytes_consumed; + + enter_http_done_state(client); + + return 0; +} + +int handle_http_frame_window_update(struct http_client_ctx *client) +{ + struct http_frame *frame = &client->current_frame; + int bytes_consumed; + + LOG_DBG("HTTP_SERVER_FRAME_WINDOW_UPDATE"); + + print_http_frames(client); + + /* TODO Implement flow control, for now just ignore. */ + + if (client->data_len < frame->length) { + return -EAGAIN; + } + + bytes_consumed = client->current_frame.length; + client->data_len -= bytes_consumed; + client->cursor += bytes_consumed; + + client->server_state = HTTP_SERVER_FRAME_HEADER_STATE; + + return 0; +} + +int handle_http_frame_continuation(struct http_client_ctx *client) +{ + LOG_DBG("HTTP_SERVER_FRAME_CONTINUATION_STATE"); + client->server_state = HTTP_SERVER_FRAME_HEADERS_STATE; + + return 0; +} + +const char *get_frame_type_name(enum http_frame_type type) +{ + switch (type) { + case HTTP_SERVER_DATA_FRAME: + return "DATA"; + case HTTP_SERVER_HEADERS_FRAME: + return "HEADERS"; + case HTTP_SERVER_PRIORITY_FRAME: + return "PRIORITY"; + case HTTP_SERVER_RST_STREAM_FRAME: + return "RST_STREAM"; + case HTTP_SERVER_SETTINGS_FRAME: + return "SETTINGS"; + case HTTP_SERVER_PUSH_PROMISE_FRAME: + return "PUSH_PROMISE"; + case HTTP_SERVER_PING_FRAME: + return "PING"; + case HTTP_SERVER_GOAWAY_FRAME: + return "GOAWAY"; + case HTTP_SERVER_WINDOW_UPDATE_FRAME: + return "WINDOW_UPDATE"; + case HTTP_SERVER_CONTINUATION_FRAME: + return "CONTINUATION"; + default: + return "UNKNOWN"; + } +} + +int parse_http_frame_header(struct http_client_ctx *client) +{ + unsigned char *buffer = client->cursor; + unsigned long buffer_len = client->data_len; + struct http_frame *frame = &client->current_frame; + + frame->length = 0; + frame->stream_identifier = 0; + + if (buffer_len < HTTP_SERVER_FRAME_HEADER_SIZE) { + return 0; + } + + frame->length = (buffer[HTTP_SERVER_FRAME_LENGTH_OFFSET] << 16) | + (buffer[HTTP_SERVER_FRAME_LENGTH_OFFSET + 1] << 8) | + buffer[HTTP_SERVER_FRAME_LENGTH_OFFSET + 2]; + frame->type = buffer[HTTP_SERVER_FRAME_TYPE_OFFSET]; + frame->flags = buffer[HTTP_SERVER_FRAME_FLAGS_OFFSET]; + frame->stream_identifier = (buffer[HTTP_SERVER_FRAME_STREAM_ID_OFFSET] << 24) | + (buffer[HTTP_SERVER_FRAME_STREAM_ID_OFFSET + 1] << 16) | + (buffer[HTTP_SERVER_FRAME_STREAM_ID_OFFSET + 2] << 8) | + buffer[HTTP_SERVER_FRAME_STREAM_ID_OFFSET + 3]; + frame->stream_identifier &= 0x7FFFFFFF; + frame->payload = buffer + HTTP_SERVER_FRAME_HEADER_SIZE; + + LOG_DBG("Frame len %d type 0x%02x flags 0x%02x id %d", + frame->length, frame->type, frame->flags, frame->stream_identifier); + + return 1; +} diff --git a/subsys/net/lib/http/http_server_ws.c b/subsys/net/lib/http/http_server_ws.c new file mode 100644 index 00000000000..593a73526d7 --- /dev/null +++ b/subsys/net/lib/http/http_server_ws.c @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +LOG_MODULE_DECLARE(net_http_server, CONFIG_NET_HTTP_SERVER_LOG_LEVEL); + +#include "headers/server_internal.h" + +#if !defined(ZEPHYR_USER_AGENT) +#define ZEPHYR_USER_AGENT "Zephyr" +#endif + +/* From RFC 6455 chapter 4.2.2 */ +#define WS_MAGIC "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" + +/* Handle upgrade from HTTP/1.1 to Websocket, see RFC 6455 + */ +int handle_http1_to_websocket_upgrade(struct http_client_ctx *client) +{ + static const char switching_protocols[] = + "HTTP/1.1 101 Switching Protocols\r\n" + "Connection: Upgrade\r\n" + "Upgrade: websocket\r\n" + "Sec-WebSocket-Accept: "; + char key_accept[HTTP_SERVER_WS_MAX_SEC_KEY_LEN + sizeof(WS_MAGIC)]; + char accept[20]; + char tmp[64]; + size_t key_len; + size_t olen; + int ret; + + key_len = MIN(sizeof(key_accept) - 1, sizeof(client->ws_sec_key)); + strncpy(key_accept, client->ws_sec_key, key_len); + key_len = strlen(key_accept); + + olen = MIN(sizeof(key_accept) - 1 - key_len, sizeof(WS_MAGIC) - 1); + strncpy(key_accept + key_len, WS_MAGIC, olen); + + mbedtls_sha1(key_accept, olen + key_len, accept); + + ret = base64_encode(tmp, sizeof(tmp) - 1, &olen, accept, sizeof(accept)); + if (ret) { + if (ret == -ENOMEM) { + NET_DBG("[%p] Too short buffer olen %zd", client, olen); + } + + goto error; + } + + ret = http_server_sendall(client, switching_protocols, + sizeof(switching_protocols) - 1); + if (ret < 0) { + NET_DBG("Cannot write to socket (%d)", ret); + goto error; + } + + ret = http_server_sendall(client, tmp, strlen(tmp)); + if (ret < 0) { + NET_DBG("Cannot write to socket (%d)", ret); + goto error; + } + + ret = snprintk(tmp, sizeof(tmp), "\r\nUser-Agent: %s\r\n\r\n", + ZEPHYR_USER_AGENT); + if (ret < 0 || ret >= sizeof(tmp)) { + goto error; + } + + ret = http_server_sendall(client, tmp, strlen(tmp)); + if (ret < 0) { + NET_DBG("Cannot write to socket (%d)", ret); + goto error; + } + + /* Only after the complete HTTP1 payload has been processed, switch + * to Websocket. + */ + if (client->parser_state == HTTP1_MESSAGE_COMPLETE_STATE) { + struct http_resource_detail_websocket *ws_detail; + int ws_sock; + + ws_detail = (struct http_resource_detail_websocket *)client->current_detail; + + ret = ws_sock = websocket_register(client->fd, + ws_detail->data_buffer, + ws_detail->data_buffer_len); + if (ret < 0) { + NET_DBG("Cannot register websocket (%d)", ret); + goto error; + } + + http_server_release_client(client); + + ret = ws_detail->cb(ws_sock, ws_detail->user_data); + if (ret < 0) { + NET_DBG("WS connection failed (%d)", ret); + zsock_close(ws_sock); + goto error; + } + } + + return 0; + +error: + return ret; +} diff --git a/subsys/net/lib/lwm2m/Kconfig b/subsys/net/lib/lwm2m/Kconfig index 33a093308df..4fdd7228f70 100644 --- a/subsys/net/lib/lwm2m/Kconfig +++ b/subsys/net/lib/lwm2m/Kconfig @@ -134,6 +134,14 @@ config LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP help Enabling this setting allows the RD client to support bootstrap mode. +config LWM2M_ENGINE_ALWAYS_REPORT_OBJ_VERSION + bool "LwM2M engine always report object version" + help + According to LwM2M specification v1.0 and v1.1, non-core object versions other than 1.0 + 'must' be provided, while all other versions 'may' be provided. With specification v1.2, + a client 'can always attach Object Version Information'. Enable this configuration to + always report all object versions. + choice prompt "Socket handling at idle state" @@ -515,6 +523,7 @@ config LWM2M_SECONDS_TO_UPDATE_EARLY config LWM2M_SHELL bool "LwM2M shell utilities" select SHELL + select CRC help Activate shell module that provides LwM2M commands like send to the console. diff --git a/subsys/net/lib/lwm2m/ipso_buzzer.c b/subsys/net/lib/lwm2m/ipso_buzzer.c index f679d7e4a60..c44df2c5431 100644 --- a/subsys/net/lib/lwm2m/ipso_buzzer.c +++ b/subsys/net/lib/lwm2m/ipso_buzzer.c @@ -144,10 +144,10 @@ static int stop_buzzer(struct ipso_buzzer_data *buzzer, bool cancel) return 0; } -static int onoff_post_write_cb(uint16_t obj_inst_id, - uint16_t res_id, uint16_t res_inst_id, - uint8_t *data, uint16_t data_len, - bool last_block, size_t total_size) +static int onoff_post_write_cb(uint16_t obj_inst_id, uint16_t res_id, + uint16_t res_inst_id, uint8_t *data, + uint16_t data_len, bool last_block, + size_t total_size, size_t offset) { int i; diff --git a/subsys/net/lib/lwm2m/ipso_current_sensor.c b/subsys/net/lib/lwm2m/ipso_current_sensor.c index 1268b7da56d..bfe713a1cbe 100644 --- a/subsys/net/lib/lwm2m/ipso_current_sensor.c +++ b/subsys/net/lib/lwm2m/ipso_current_sensor.c @@ -112,7 +112,7 @@ static int reset_min_max_measured_values_cb(uint16_t obj_inst_id, static int sensor_value_write_cb(uint16_t obj_inst_id, uint16_t res_id, uint16_t res_inst_id, uint8_t *data, uint16_t data_len, bool last_block, - size_t total_size) + size_t total_size, size_t offset) { int i; diff --git a/subsys/net/lib/lwm2m/ipso_filling_sensor.c b/subsys/net/lib/lwm2m/ipso_filling_sensor.c index 96944e0c16a..9fae4cfeb25 100644 --- a/subsys/net/lib/lwm2m/ipso_filling_sensor.c +++ b/subsys/net/lib/lwm2m/ipso_filling_sensor.c @@ -121,7 +121,7 @@ static void update(uint16_t obj_inst_id, uint16_t res_id, int index) static int update_cb(uint16_t obj_inst_id, uint16_t res_id, uint16_t res_inst_id, uint8_t *data, uint16_t data_len, - bool last_block, size_t total_size) + bool last_block, size_t total_size, size_t offset) { int i; diff --git a/subsys/net/lib/lwm2m/ipso_generic_sensor.c b/subsys/net/lib/lwm2m/ipso_generic_sensor.c index 05a1afc9806..2b5381d564c 100644 --- a/subsys/net/lib/lwm2m/ipso_generic_sensor.c +++ b/subsys/net/lib/lwm2m/ipso_generic_sensor.c @@ -121,7 +121,7 @@ static int reset_min_max_measured_values_cb(uint16_t obj_inst_id, static int sensor_value_write_cb(uint16_t obj_inst_id, uint16_t res_id, uint16_t res_inst_id, uint8_t *data, uint16_t data_len, bool last_block, - size_t total_size) + size_t total_size, size_t offset) { int i; diff --git a/subsys/net/lib/lwm2m/ipso_humidity_sensor.c b/subsys/net/lib/lwm2m/ipso_humidity_sensor.c index b2d147060a0..85bb2335c2e 100644 --- a/subsys/net/lib/lwm2m/ipso_humidity_sensor.c +++ b/subsys/net/lib/lwm2m/ipso_humidity_sensor.c @@ -107,7 +107,7 @@ static int reset_min_max_measured_values_cb(uint16_t obj_inst_id, static int sensor_value_write_cb(uint16_t obj_inst_id, uint16_t res_id, uint16_t res_inst_id, uint8_t *data, uint16_t data_len, bool last_block, - size_t total_size) + size_t total_size, size_t offset) { int i; diff --git a/subsys/net/lib/lwm2m/ipso_light_control.c b/subsys/net/lib/lwm2m/ipso_light_control.c index b7f727ff4a4..883dece531d 100644 --- a/subsys/net/lib/lwm2m/ipso_light_control.c +++ b/subsys/net/lib/lwm2m/ipso_light_control.c @@ -78,8 +78,7 @@ static void *on_time_read_cb(uint16_t obj_inst_id, uint16_t res_id, uint16_t res } if (on_off_value[i]) { - on_time_value[i] = (k_uptime_get() / MSEC_PER_SEC) - - on_time_offset[i]; + on_time_value[i] = k_uptime_seconds() - on_time_offset[i]; } *data_len = sizeof(on_time_value[i]); @@ -89,10 +88,10 @@ static void *on_time_read_cb(uint16_t obj_inst_id, uint16_t res_id, uint16_t res return NULL; } -static int on_time_post_write_cb(uint16_t obj_inst_id, - uint16_t res_id, uint16_t res_inst_id, - uint8_t *data, uint16_t data_len, - bool last_block, size_t total_size) +static int on_time_post_write_cb(uint16_t obj_inst_id, uint16_t res_id, + uint16_t res_inst_id, uint8_t *data, + uint16_t data_len, bool last_block, + size_t total_size, size_t offset) { int i; @@ -109,8 +108,7 @@ static int on_time_post_write_cb(uint16_t obj_inst_id, } if (counter == 0) { - on_time_offset[i] = - (int32_t)(k_uptime_get() / MSEC_PER_SEC); + on_time_offset[i] = k_uptime_seconds(); } return 0; diff --git a/subsys/net/lib/lwm2m/ipso_onoff_switch.c b/subsys/net/lib/lwm2m/ipso_onoff_switch.c index 3da496b2ca1..da1cf464d83 100644 --- a/subsys/net/lib/lwm2m/ipso_onoff_switch.c +++ b/subsys/net/lib/lwm2m/ipso_onoff_switch.c @@ -87,10 +87,10 @@ static int get_switch_index(uint16_t obj_inst_id) return ret; } -static int state_post_write_cb(uint16_t obj_inst_id, - uint16_t res_id, uint16_t res_inst_id, - uint8_t *data, uint16_t data_len, - bool last_block, size_t total_size) +static int state_post_write_cb(uint16_t obj_inst_id, uint16_t res_id, + uint16_t res_inst_id, uint8_t *data, + uint16_t data_len, bool last_block, + size_t total_size, size_t offset) { int i; @@ -157,10 +157,10 @@ static void *off_time_read_cb(uint16_t obj_inst_id, return &switch_data[i].off_time_sec; } -static int time_post_write_cb(uint16_t obj_inst_id, - uint16_t res_id, uint16_t res_inst_id, - uint8_t *data, uint16_t data_len, - bool last_block, size_t total_size) +static int time_post_write_cb(uint16_t obj_inst_id, uint16_t res_id, + uint16_t res_inst_id, uint8_t *data, + uint16_t data_len, bool last_block, + size_t total_size, size_t offset) { int i = get_switch_index(obj_inst_id); diff --git a/subsys/net/lib/lwm2m/ipso_pressure_sensor.c b/subsys/net/lib/lwm2m/ipso_pressure_sensor.c index 7dca2ed3956..f6b59591d7d 100644 --- a/subsys/net/lib/lwm2m/ipso_pressure_sensor.c +++ b/subsys/net/lib/lwm2m/ipso_pressure_sensor.c @@ -108,7 +108,7 @@ static int reset_min_max_measured_values_cb(uint16_t obj_inst_id, static int sensor_value_write_cb(uint16_t obj_inst_id, uint16_t res_id, uint16_t res_inst_id, uint8_t *data, uint16_t data_len, bool last_block, - size_t total_size) + size_t total_size, size_t offset) { int i; diff --git a/subsys/net/lib/lwm2m/ipso_push_button.c b/subsys/net/lib/lwm2m/ipso_push_button.c index 07782a86756..475363a75ef 100644 --- a/subsys/net/lib/lwm2m/ipso_push_button.c +++ b/subsys/net/lib/lwm2m/ipso_push_button.c @@ -82,10 +82,10 @@ static int get_button_index(uint16_t obj_inst_id) return ret; } -static int state_post_write_cb(uint16_t obj_inst_id, - uint16_t res_id, uint16_t res_inst_id, - uint8_t *data, uint16_t data_len, - bool last_block, size_t total_size) +static int state_post_write_cb(uint16_t obj_inst_id, uint16_t res_id, + uint16_t res_inst_id, uint8_t *data, + uint16_t data_len, bool last_block, + size_t total_size, size_t offset) { int i; diff --git a/subsys/net/lib/lwm2m/ipso_temp_sensor.c b/subsys/net/lib/lwm2m/ipso_temp_sensor.c index ba843db0ebd..6d258b9d5fb 100644 --- a/subsys/net/lib/lwm2m/ipso_temp_sensor.c +++ b/subsys/net/lib/lwm2m/ipso_temp_sensor.c @@ -107,10 +107,10 @@ static int reset_min_max_measured_values_cb(uint16_t obj_inst_id, return -ENOENT; } -static int sensor_value_write_cb(uint16_t obj_inst_id, - uint16_t res_id, uint16_t res_inst_id, - uint8_t *data, uint16_t data_len, - bool last_block, size_t total_size) +static int sensor_value_write_cb(uint16_t obj_inst_id, uint16_t res_id, + uint16_t res_inst_id, uint8_t *data, + uint16_t data_len, bool last_block, + size_t total_size, size_t offset) { int i; diff --git a/subsys/net/lib/lwm2m/ipso_timer.c b/subsys/net/lib/lwm2m/ipso_timer.c index 833002e56c4..cf4798d7456 100644 --- a/subsys/net/lib/lwm2m/ipso_timer.c +++ b/subsys/net/lib/lwm2m/ipso_timer.c @@ -200,9 +200,10 @@ static void *cumulative_time_read_cb(uint16_t obj_inst_id, } static int cumulative_time_post_write_cb(uint16_t obj_inst_id, - uint16_t res_id, uint16_t res_inst_id, - uint8_t *data, uint16_t data_len, - bool last_block, size_t total_size) + uint16_t res_id, + uint16_t res_inst_id, uint8_t *data, + uint16_t data_len, bool last_block, + size_t total_size, size_t offset) { int i; @@ -215,10 +216,10 @@ static int cumulative_time_post_write_cb(uint16_t obj_inst_id, return 0; } -static int enabled_post_write_cb(uint16_t obj_inst_id, - uint16_t res_id, uint16_t res_inst_id, - uint8_t *data, uint16_t data_len, - bool last_block, size_t total_size) +static int enabled_post_write_cb(uint16_t obj_inst_id, uint16_t res_id, + uint16_t res_inst_id, uint8_t *data, + uint16_t data_len, bool last_block, + size_t total_size, size_t offset) { int i; @@ -236,9 +237,10 @@ static int enabled_post_write_cb(uint16_t obj_inst_id, } static int trigger_counter_post_write_cb(uint16_t obj_inst_id, - uint16_t res_id, uint16_t res_inst_id, - uint8_t *data, uint16_t data_len, - bool last_block, size_t total_size) + uint16_t res_id, + uint16_t res_inst_id, uint8_t *data, + uint16_t data_len, bool last_block, + size_t total_size, size_t offset) { int i; diff --git a/subsys/net/lib/lwm2m/ipso_voltage_sensor.c b/subsys/net/lib/lwm2m/ipso_voltage_sensor.c index ec1274d07ff..87fb1b83761 100644 --- a/subsys/net/lib/lwm2m/ipso_voltage_sensor.c +++ b/subsys/net/lib/lwm2m/ipso_voltage_sensor.c @@ -113,7 +113,7 @@ static int reset_min_max_measured_values_cb(uint16_t obj_inst_id, static int sensor_value_write_cb(uint16_t obj_inst_id, uint16_t res_id, uint16_t res_inst_id, uint8_t *data, uint16_t data_len, bool last_block, - size_t total_size) + size_t total_size, size_t offset) { int i; diff --git a/subsys/net/lib/lwm2m/iterables.ld b/subsys/net/lib/lwm2m/iterables.ld index 83ce9070ef0..dd487f95263 100644 --- a/subsys/net/lib/lwm2m/iterables.ld +++ b/subsys/net/lib/lwm2m/iterables.ld @@ -1 +1 @@ -ITERABLE_SECTION_ROM(lwm2m_init_func, 4) +ITERABLE_SECTION_ROM(lwm2m_init_func, Z_LINK_ITERABLE_SUBALIGN) diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index db7906da4cf..50165c1436f 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -681,8 +681,8 @@ static int socket_recv_message(struct lwm2m_ctx *client_ctx) static struct sockaddr from_addr; from_addr_len = sizeof(from_addr); - len = zsock_recvfrom(client_ctx->sock_fd, in_buf, sizeof(in_buf) - 1, 0, &from_addr, - &from_addr_len); + len = zsock_recvfrom(client_ctx->sock_fd, in_buf, sizeof(in_buf) - 1, ZSOCK_MSG_DONTWAIT, + &from_addr, &from_addr_len); if (len < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK) { diff --git a/subsys/net/lib/lwm2m/lwm2m_message_handling.c b/subsys/net/lib/lwm2m/lwm2m_message_handling.c index 5cc82f165c5..41165ef4063 100644 --- a/subsys/net/lib/lwm2m/lwm2m_message_handling.c +++ b/subsys/net/lib/lwm2m/lwm2m_message_handling.c @@ -103,7 +103,8 @@ sys_slist_t *lwm2m_engine_obj_inst_list(void); static int handle_request(struct coap_packet *request, struct lwm2m_message *msg); #if defined(CONFIG_LWM2M_COAP_BLOCK_TRANSFER) -STATIC int build_msg_block_for_send(struct lwm2m_message *msg, uint16_t block_num); +STATIC int build_msg_block_for_send(struct lwm2m_message *msg, uint16_t block_num, + enum coap_block_size block_size); struct coap_block_context *lwm2m_output_block_context(void); #endif @@ -111,24 +112,7 @@ struct coap_block_context *lwm2m_output_block_context(void); enum coap_block_size lwm2m_default_block_size(void) { - switch (CONFIG_LWM2M_COAP_BLOCK_SIZE) { - case 16: - return COAP_BLOCK_16; - case 32: - return COAP_BLOCK_32; - case 64: - return COAP_BLOCK_64; - case 128: - return COAP_BLOCK_128; - case 256: - return COAP_BLOCK_256; - case 512: - return COAP_BLOCK_512; - case 1024: - return COAP_BLOCK_1024; - } - - return COAP_BLOCK_256; + return coap_bytes_to_block_size(CONFIG_LWM2M_COAP_BLOCK_SIZE); } void lwm2m_clear_block_contexts(void) @@ -277,11 +261,12 @@ static inline void release_body_encode_buffer(uint8_t **buffer) } } -STATIC int build_msg_block_for_send(struct lwm2m_message *msg, uint16_t block_num) +STATIC int build_msg_block_for_send(struct lwm2m_message *msg, uint16_t block_num, + enum coap_block_size block_size) { int ret; uint16_t payload_size; - const uint16_t block_size_bytes = coap_block_size_to_bytes(lwm2m_default_block_size()); + const uint16_t block_size_bytes = coap_block_size_to_bytes(block_size); uint16_t complete_payload_len; const uint8_t *complete_payload = coap_packet_get_payload(&msg->body_encode_buffer, &complete_payload_len); @@ -350,7 +335,7 @@ STATIC int build_msg_block_for_send(struct lwm2m_message *msg, uint16_t block_nu LOG_ERR("coap packet init error: no output block context available"); return ret; } - ret = coap_block_transfer_init(msg->out.block_ctx, lwm2m_default_block_size(), + ret = coap_block_transfer_init(msg->out.block_ctx, block_size, complete_payload_len); if (ret < 0) { return ret; @@ -362,6 +347,7 @@ STATIC int build_msg_block_for_send(struct lwm2m_message *msg, uint16_t block_nu } else { /* update block context */ msg->out.block_ctx->current = block_num * block_size_bytes; + msg->out.block_ctx->block_size = block_size; } ret = coap_append_descriptive_block_option(&msg->cpkt, msg->out.block_ctx); @@ -427,7 +413,7 @@ STATIC int prepare_msg_for_send(struct lwm2m_message *msg) (const uint8_t *)&hash, sizeof(hash)); } - ret = build_msg_block_for_send(msg, 0); + ret = build_msg_block_for_send(msg, 0, lwm2m_default_block_size()); if (ret != 0) { return ret; } @@ -687,32 +673,33 @@ int lwm2m_init_message(struct lwm2m_message *msg) int lwm2m_send_message_async(struct lwm2m_message *msg) { - int ret = 0; #if defined(CONFIG_LWM2M_COAP_BLOCK_TRANSFER) /* check if body encode buffer is in use => packet is not yet prepared for send */ if (msg->body_encode_buffer.data == msg->cpkt.data) { - ret = prepare_msg_for_send(msg); + int ret = prepare_msg_for_send(msg); + if (ret) { lwm2m_reset_message(msg, true); return ret; } } #endif -#if defined(CONFIG_LWM2M_QUEUE_MODE_ENABLED) - ret = lwm2m_rd_client_connection_resume(msg->ctx); - if (ret) { - lwm2m_reset_message(msg, true); - return ret; + if (IS_ENABLED(CONFIG_LWM2M_QUEUE_MODE_ENABLED)) { + int ret = lwm2m_rd_client_connection_resume(msg->ctx); + + if (ret && ret != -EPERM) { + lwm2m_reset_message(msg, true); + return ret; + } } -#endif sys_slist_append(&msg->ctx->pending_sends, &msg->node); if (IS_ENABLED(CONFIG_LWM2M_QUEUE_MODE_ENABLED)) { engine_update_tx_time(); } lwm2m_engine_wake_up(); - return ret; + return 0; } int lwm2m_information_interface_send(struct lwm2m_message *msg) @@ -997,7 +984,8 @@ static int lwm2m_write_handler_opaque(struct lwm2m_engine_obj_inst *obj_inst, if (res->validate_cb) { ret = res->validate_cb(obj_inst->obj_inst_id, res->res_id, res_inst->res_inst_id, write_buf, len, - last_pkt_block && last_block, opaque_ctx.len); + last_pkt_block && last_block, opaque_ctx.len, + msg->in.block_ctx->ctx.current); if (ret < 0) { /* -EEXIST will generate Bad Request LWM2M response. */ return -EEXIST; @@ -1008,13 +996,17 @@ static int lwm2m_write_handler_opaque(struct lwm2m_engine_obj_inst *obj_inst, #endif /* CONFIG_LWM2M_ENGINE_VALIDATION_BUFFER_SIZE > 0 */ if (res->post_write_cb) { - ret = res->post_write_cb(obj_inst->obj_inst_id, res->res_id, - res_inst->res_inst_id, data_ptr, len, - last_pkt_block && last_block, opaque_ctx.len); + ret = res->post_write_cb( + obj_inst->obj_inst_id, res->res_id, res_inst->res_inst_id, data_ptr, + len, last_pkt_block && last_block, opaque_ctx.len, + (msg->in.block_ctx ? msg->in.block_ctx->ctx.current : 0)); if (ret < 0) { return ret; } } + if (msg->in.block_ctx) { + msg->in.block_ctx->ctx.current += len; + } } if (msg->in.block_ctx != NULL) { @@ -1039,6 +1031,7 @@ int lwm2m_write_handler(struct lwm2m_engine_obj_inst *obj_inst, struct lwm2m_eng bool last_block = true; void *write_buf; size_t write_buf_len; + size_t offset = 0; if (!obj_inst || !res || !res_inst || !obj_field || !msg) { return -EINVAL; @@ -1058,19 +1051,26 @@ int lwm2m_write_handler(struct lwm2m_engine_obj_inst *obj_inst, struct lwm2m_eng res_inst->res_inst_id, &data_len); } - if (res->post_write_cb -#if CONFIG_LWM2M_ENGINE_VALIDATION_BUFFER_SIZE > 0 - || res->validate_cb -#endif - ) { - if (msg->in.block_ctx != NULL) { - /* Get block_ctx for total_size (might be zero) */ - total_size = msg->in.block_ctx->ctx.total_size; - LOG_DBG("BLOCK1: total:%zu current:%zu" - " last:%u", - msg->in.block_ctx->ctx.total_size, msg->in.block_ctx->ctx.current, - msg->in.block_ctx->last_block); + if (msg->in.block_ctx != NULL) { + /* Get block_ctx for total_size (might be zero) */ + total_size = msg->in.block_ctx->ctx.total_size; + offset = msg->in.block_ctx->ctx.current; + + LOG_DBG("BLOCK1: total:%zu current:%zu" + " last:%u", + msg->in.block_ctx->ctx.total_size, msg->in.block_ctx->ctx.current, + msg->in.block_ctx->last_block); + } + + /* Only when post_write callback is set, we allow larger content than our + * buffer sizes. The post-write callback handles assembling of the data + */ + if (!res->post_write_cb) { + if ((offset > 0 && offset >= data_len) || total_size > data_len) { + return -ENOMEM; } + data_len -= offset; + data_ptr = (uint8_t *)data_ptr + offset; } #if CONFIG_LWM2M_ENGINE_VALIDATION_BUFFER_SIZE > 0 @@ -1213,11 +1213,12 @@ int lwm2m_write_handler(struct lwm2m_engine_obj_inst *obj_inst, struct lwm2m_eng } if (obj_field->data_type != LWM2M_RES_TYPE_OPAQUE) { + #if CONFIG_LWM2M_ENGINE_VALIDATION_BUFFER_SIZE > 0 if (res->validate_cb) { ret = res->validate_cb(obj_inst->obj_inst_id, res->res_id, res_inst->res_inst_id, write_buf, len, last_block, - total_size); + total_size, offset); if (ret < 0) { /* -EEXIST will generate Bad Request LWM2M response. */ return -EEXIST; @@ -1240,7 +1241,7 @@ int lwm2m_write_handler(struct lwm2m_engine_obj_inst *obj_inst, struct lwm2m_eng if (res->post_write_cb) { ret = res->post_write_cb(obj_inst->obj_inst_id, res->res_id, res_inst->res_inst_id, data_ptr, len, last_block, - total_size); + total_size, offset); } } @@ -2100,12 +2101,12 @@ static int parse_write_op(struct lwm2m_message *msg, uint16_t format) block_ctx->last_block = last_block; - /* Initial block sent by the server might be larger than - * our block size therefore it is needed to take this - * into account when calculating next expected block - * number. + /* Initial block sent by the server might be larger or smaller than + * our block size, therefore it is needed to take this into account + * when calculating next expected block number. */ - block_ctx->expected += GET_BLOCK_SIZE(block_opt) - block_ctx->ctx.block_size + 1; + block_ctx->expected += + 1 << MAX(0, GET_BLOCK_SIZE(block_opt) - block_ctx->ctx.block_size); } r = do_write_op(msg, format); @@ -2649,6 +2650,7 @@ static void handle_ongoing_block2_tx(struct lwm2m_message *msg, struct coap_pack #if defined(CONFIG_LWM2M_COAP_BLOCK_TRANSFER) int r; uint8_t block; + enum coap_block_size block_size; r = coap_get_block2_option(cpkt, &block); if (r < 0) { @@ -2656,9 +2658,10 @@ static void handle_ongoing_block2_tx(struct lwm2m_message *msg, struct coap_pack return; } + block_size = coap_bytes_to_block_size(r); msg->in.in_cpkt = cpkt; - r = build_msg_block_for_send(msg, block); + r = build_msg_block_for_send(msg, block, block_size); if (r < 0) { clear_ongoing_block2_tx(); LOG_ERR("Unable to build next block of lwm2m message! r=%d", r); @@ -2745,6 +2748,8 @@ void lwm2m_udp_receive(struct lwm2m_ctx *client_ctx, uint8_t *buf, uint16_t buf_ return; } + enum coap_block_size block_size = coap_bytes_to_block_size(r); + if (r != CONFIG_LWM2M_COAP_BLOCK_SIZE) { LOG_WRN("Server requests different block size: ignore"); } @@ -2756,7 +2761,7 @@ void lwm2m_udp_receive(struct lwm2m_ctx *client_ctx, uint8_t *buf, uint16_t buf_ } last_block_num = msg->out.block_ctx->current / - coap_block_size_to_bytes(msg->out.block_ctx->block_size); + coap_block_size_to_bytes(block_size); if (last_block_num > block_num) { LOG_INF("Block already sent: ignore"); return; @@ -2765,7 +2770,7 @@ void lwm2m_udp_receive(struct lwm2m_ctx *client_ctx, uint8_t *buf, uint16_t buf_ return; } - r = build_msg_block_for_send(msg, block_num + 1); + r = build_msg_block_for_send(msg, block_num + 1, block_size); if (r < 0) { lwm2m_reset_message(msg, true); LOG_ERR("Unable to build next block of lwm2m message!"); diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_access_control.c b/subsys/net/lib/lwm2m/lwm2m_obj_access_control.c index e5eb8c56efb..287be88f726 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_access_control.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_access_control.c @@ -335,8 +335,10 @@ static void add_existing_objects(void) } } -static int write_validate_cb(uint16_t obj_inst_id, uint16_t res_id, uint16_t res_inst_id, - uint8_t *data, uint16_t data_len, bool last_block, size_t total_size) +static int write_validate_cb(uint16_t obj_inst_id, uint16_t res_id, + uint16_t res_inst_id, uint8_t *data, + uint16_t data_len, bool last_block, + size_t total_size, size_t offset) { /* validates and removes acl instances for non-existing servers */ diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_device.c b/subsys/net/lib/lwm2m/lwm2m_obj_device.c index 30b3beaca66..208423eb04a 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_device.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_device.c @@ -176,7 +176,7 @@ static int reset_error_list_cb(uint16_t obj_inst_id, static void *current_time_read_cb(uint16_t obj_inst_id, uint16_t res_id, uint16_t res_inst_id, size_t *data_len) { - time_temp = time_offset + (k_uptime_get() / 1000); + time_temp = time_offset + k_uptime_seconds(); *data_len = sizeof(time_temp); return &time_temp; @@ -190,15 +190,15 @@ static void *current_time_pre_write_cb(uint16_t obj_inst_id, uint16_t res_id, } static int current_time_post_write_cb(uint16_t obj_inst_id, uint16_t res_id, - uint16_t res_inst_id, - uint8_t *data, uint16_t data_len, - bool last_block, size_t total_size) + uint16_t res_inst_id, uint8_t *data, + uint16_t data_len, bool last_block, + size_t total_size, size_t offset) { if (data_len == 4U) { - time_offset = *(uint32_t *)data - (uint32_t)(k_uptime_get() / 1000); + time_offset = *(uint32_t *)data - k_uptime_seconds(); return 0; } else if (data_len == 8U) { - time_offset = *(time_t *)data - (time_t)(k_uptime_get() / 1000); + time_offset = *(time_t *)data - (time_t)k_uptime_seconds(); return 0; } diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_firmware.c b/subsys/net/lib/lwm2m/lwm2m_obj_firmware.c index ad313163548..1ba3789f1cf 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_firmware.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_firmware.c @@ -235,8 +235,9 @@ void lwm2m_firmware_set_update_result(uint8_t result) } static int package_write_cb(uint16_t obj_inst_id, uint16_t res_id, - uint16_t res_inst_id, uint8_t *data, uint16_t data_len, - bool last_block, size_t total_size) + uint16_t res_inst_id, uint8_t *data, + uint16_t data_len, bool last_block, + size_t total_size, size_t offset) { uint8_t state; int ret = 0; @@ -270,7 +271,7 @@ static int package_write_cb(uint16_t obj_inst_id, uint16_t res_id, write_callback = lwm2m_firmware_get_write_cb_inst(obj_inst_id); if (write_callback) { ret = write_callback(obj_inst_id, res_id, res_inst_id, data, data_len, last_block, - total_size); + total_size, offset); } if (ret >= 0) { @@ -298,8 +299,9 @@ static int package_write_cb(uint16_t obj_inst_id, uint16_t res_id, } static int package_uri_write_cb(uint16_t obj_inst_id, uint16_t res_id, - uint16_t res_inst_id, uint8_t *data, uint16_t data_len, - bool last_block, size_t total_size) + uint16_t res_inst_id, uint8_t *data, + uint16_t data_len, bool last_block, + size_t total_size, size_t offset) { LOG_DBG("PACKAGE_URI WRITE: %s", package_uri[obj_inst_id]); diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_gateway.c b/subsys/net/lib/lwm2m/lwm2m_obj_gateway.c index 106ef951653..fb82fe6c3f5 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_gateway.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_gateway.c @@ -61,9 +61,10 @@ static struct lwm2m_engine_res res[MAX_INSTANCE_COUNT][GATEWAY_MAX_ID]; static struct lwm2m_engine_res_inst res_inst[MAX_INSTANCE_COUNT][RESOURCE_INSTANCE_COUNT]; lwm2m_engine_gateway_msg_cb gateway_msg_cb[MAX_INSTANCE_COUNT]; -static int prefix_validation_cb(uint16_t obj_inst_id, uint16_t res_id, uint16_t res_inst_id, - uint8_t *data, uint16_t data_len, bool last_block, - size_t total_size) +static int prefix_validation_cb(uint16_t obj_inst_id, uint16_t res_id, + uint16_t res_inst_id, uint8_t *data, + uint16_t data_len, bool last_block, + size_t total_size, size_t offset) { int i; int length; diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_server.c b/subsys/net/lib/lwm2m/lwm2m_obj_server.c index a7d3e541bbe..9c1dfc0ca1d 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_server.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_server.c @@ -146,7 +146,7 @@ bool lwm2m_server_get_mute_send(uint16_t obj_inst_id) static int lifetime_write_cb(uint16_t obj_inst_id, uint16_t res_id, uint16_t res_inst_id, uint8_t *data, uint16_t data_len, bool last_block, - size_t total_size) + size_t total_size, size_t offset) { ARG_UNUSED(obj_inst_id); ARG_UNUSED(res_id); diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_swmgmt.c b/subsys/net/lib/lwm2m/lwm2m_obj_swmgmt.c index f1466be6c87..69dfd5c1f8c 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_swmgmt.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_swmgmt.c @@ -187,9 +187,10 @@ static int callback_execute_not_defined(uint16_t obj_inst_id, uint8_t *args, uin return -EINVAL; } -static int callback_write_not_defined(uint16_t obj_inst_id, uint16_t res_id, uint16_t res_inst_id, - uint8_t *data, uint16_t data_len, bool last_block, - size_t total_size) +static int callback_write_not_defined(uint16_t obj_inst_id, uint16_t res_id, + uint16_t res_inst_id, uint8_t *data, + uint16_t data_len, bool last_block, + size_t total_size, size_t offset) { LOG_ERR("Callback not defined for inst %u", obj_inst_id); return -EINVAL; @@ -558,8 +559,10 @@ static int deactivate_cb(uint16_t obj_inst_id, uint8_t *args, uint16_t args_len) return handle_event(instance, EVENT_DEACTIVATE); } -static int package_write_cb(uint16_t obj_inst_id, uint16_t res_id, uint16_t res_inst_id, - uint8_t *data, uint16_t data_len, bool last_block, size_t total_size) +static int package_write_cb(uint16_t obj_inst_id, uint16_t res_id, + uint16_t res_inst_id, uint8_t *data, + uint16_t data_len, bool last_block, + size_t total_size, size_t offset) { int ret = -EINVAL; struct lwm2m_swmgmt_data *instance = NULL; @@ -643,9 +646,10 @@ static void set_update_result(uint16_t obj_inst_id, int error_code) } } -static int package_uri_write_cb(uint16_t obj_inst_id, uint16_t res_id, uint16_t res_inst_id, - uint8_t *data, uint16_t data_len, bool last_block, - size_t total_size) +static int package_uri_write_cb(uint16_t obj_inst_id, uint16_t res_id, + uint16_t res_inst_id, uint8_t *data, + uint16_t data_len, bool last_block, + size_t total_size, size_t offset) { #ifdef CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_SUPPORT int error_code; diff --git a/subsys/net/lib/lwm2m/lwm2m_pull_context.c b/subsys/net/lib/lwm2m/lwm2m_pull_context.c index e1eac08554f..c4c782d538f 100644 --- a/subsys/net/lib/lwm2m/lwm2m_pull_context.c +++ b/subsys/net/lib/lwm2m/lwm2m_pull_context.c @@ -303,6 +303,8 @@ static int do_firmware_transfer_reply_cb(const struct coap_packet *response, } if (context.write_cb) { + size_t offset = context.block_ctx.current; + /* flush incoming data to write_cb */ while (payload_len > 0) { len = (payload_len > write_buflen) ? write_buflen : payload_len; @@ -317,7 +319,8 @@ static int do_firmware_transfer_reply_cb(const struct coap_packet *response, ret = context.write_cb(context.obj_inst_id, 0, 0, write_buf, len, last_block && (payload_len == 0U), - context.block_ctx.total_size); + context.block_ctx.total_size, offset); + offset += len; if (ret < 0) { goto error; } diff --git a/subsys/net/lib/lwm2m/lwm2m_registry.c b/subsys/net/lib/lwm2m/lwm2m_registry.c index 725ef91210e..54bda0a0ca1 100644 --- a/subsys/net/lib/lwm2m/lwm2m_registry.c +++ b/subsys/net/lib/lwm2m/lwm2m_registry.c @@ -668,7 +668,7 @@ static int lwm2m_engine_set(const struct lwm2m_obj_path *path, const void *value #if CONFIG_LWM2M_ENGINE_VALIDATION_BUFFER_SIZE > 0 if (res->validate_cb) { ret = res->validate_cb(obj_inst->obj_inst_id, res->res_id, res_inst->res_inst_id, - (uint8_t *)value, len, false, 0); + (uint8_t *)value, len, false, 0, 0); if (ret < 0) { k_mutex_unlock(®istry_lock); return -EINVAL; @@ -774,7 +774,7 @@ static int lwm2m_engine_set(const struct lwm2m_obj_path *path, const void *value if (res->post_write_cb) { ret = res->post_write_cb(obj_inst->obj_inst_id, res->res_id, res_inst->res_inst_id, - data_ptr, len, false, 0); + data_ptr, len, false, 0, 0); } if (changed && LWM2M_HAS_PERM(obj_field, LWM2M_PERM_R)) { @@ -2010,6 +2010,10 @@ struct lwm2m_engine_res_inst *lwm2m_engine_get_res_inst(const struct lwm2m_obj_p bool lwm2m_engine_shall_report_obj_version(const struct lwm2m_engine_obj *obj) { + if (IS_ENABLED(CONFIG_LWM2M_ENGINE_ALWAYS_REPORT_OBJ_VERSION)) { + return true; + } + /* For non-core objects, report version other than 1.0 */ if (!obj->is_core) { return obj->version_major != 1 || obj->version_minor != 0; diff --git a/subsys/net/lib/lwm2m/lwm2m_senml_cbor.patch b/subsys/net/lib/lwm2m/lwm2m_senml_cbor.patch index 41bb3f0a5d4..20b64f91f4a 100644 --- a/subsys/net/lib/lwm2m/lwm2m_senml_cbor.patch +++ b/subsys/net/lib/lwm2m/lwm2m_senml_cbor.patch @@ -1,5 +1,5 @@ diff --git a/subsys/net/lib/lwm2m/lwm2m_senml_cbor_decode.c b/subsys/net/lib/lwm2m/lwm2m_senml_cbor_decode.c -index c12f477cce..f41b81275d 100644 +index 8b136cccf0b..ca935f9f60a 100644 --- a/subsys/net/lib/lwm2m/lwm2m_senml_cbor_decode.c +++ b/subsys/net/lib/lwm2m/lwm2m_senml_cbor_decode.c @@ -4,7 +4,7 @@ @@ -41,7 +41,7 @@ index c12f477cce..f41b81275d 100644 if (!tmp_result) { zcbor_trace_file(state); diff --git a/subsys/net/lib/lwm2m/lwm2m_senml_cbor_decode.h b/subsys/net/lib/lwm2m/lwm2m_senml_cbor_decode.h -index a36f8782c6..b913fb78e9 100644 +index 8060c2cd932..7316e8fb2c6 100644 --- a/subsys/net/lib/lwm2m/lwm2m_senml_cbor_decode.h +++ b/subsys/net/lib/lwm2m/lwm2m_senml_cbor_decode.h @@ -4,7 +4,7 @@ @@ -66,7 +66,7 @@ index a36f8782c6..b913fb78e9 100644 const uint8_t *payload, size_t payload_len, struct lwm2m_senml *result, diff --git a/subsys/net/lib/lwm2m/lwm2m_senml_cbor_encode.c b/subsys/net/lib/lwm2m/lwm2m_senml_cbor_encode.c -index 94926c531f..5521917853 100644 +index d63baab5bcb..cbeef1b4e18 100644 --- a/subsys/net/lib/lwm2m/lwm2m_senml_cbor_encode.c +++ b/subsys/net/lib/lwm2m/lwm2m_senml_cbor_encode.c @@ -4,7 +4,7 @@ @@ -114,7 +114,7 @@ index 94926c531f..5521917853 100644 if (!tmp_result) { zcbor_trace_file(state); diff --git a/subsys/net/lib/lwm2m/lwm2m_senml_cbor_encode.h b/subsys/net/lib/lwm2m/lwm2m_senml_cbor_encode.h -index df2f0ac6a1..8fa1eedb2b 100644 +index 8bfba2d834e..fe644015f63 100644 --- a/subsys/net/lib/lwm2m/lwm2m_senml_cbor_encode.h +++ b/subsys/net/lib/lwm2m/lwm2m_senml_cbor_encode.h @@ -4,7 +4,7 @@ @@ -139,7 +139,7 @@ index df2f0ac6a1..8fa1eedb2b 100644 uint8_t *payload, size_t payload_len, const struct lwm2m_senml *input, diff --git a/subsys/net/lib/lwm2m/lwm2m_senml_cbor_types.h b/subsys/net/lib/lwm2m/lwm2m_senml_cbor_types.h -index 77649036ef..f0a2958072 100644 +index ad1d0bef58d..662329d1680 100644 --- a/subsys/net/lib/lwm2m/lwm2m_senml_cbor_types.h +++ b/subsys/net/lib/lwm2m/lwm2m_senml_cbor_types.h @@ -4,7 +4,7 @@ @@ -151,7 +151,7 @@ index 77649036ef..f0a2958072 100644 * Generated with a --default-max-qty of 99 */ -@@ -20,14 +20,18 @@ +@@ -20,14 +20,17 @@ extern "C" { #endif @@ -163,7 +163,6 @@ index 77649036ef..f0a2958072 100644 - * See `zcbor --help` for more information about --default-max-qty - */ -#define DEFAULT_MAX_QTY 99 -+ +enum lwm2m_senml_cbor_key { + lwm2m_senml_cbor_key_bn = -2, + lwm2m_senml_cbor_key_bt = -3, @@ -178,7 +177,26 @@ index 77649036ef..f0a2958072 100644 struct record_bn { struct zcbor_string record_bn; -@@ -118,7 +122,7 @@ struct record { +@@ -104,21 +107,21 @@ struct record_key_value_pair_m { + + struct record { + struct record_bn record_bn; +- bool record_bn_present; + struct record_bt record_bt; +- bool record_bt_present; + struct record_n record_n; +- bool record_n_present; + struct record_t record_t; +- bool record_t_present; + struct record_union_r record_union; +- bool record_union_present; + struct record_key_value_pair_m record_key_value_pair_m[5]; + size_t record_key_value_pair_m_count; ++ bool record_bn_present; ++ bool record_bt_present; ++ bool record_n_present; ++ bool record_t_present; ++ bool record_union_present; }; struct lwm2m_senml { diff --git a/subsys/net/lib/lwm2m/lwm2m_senml_cbor_types.h b/subsys/net/lib/lwm2m/lwm2m_senml_cbor_types.h index dbb5a368551..662329d1680 100644 --- a/subsys/net/lib/lwm2m/lwm2m_senml_cbor_types.h +++ b/subsys/net/lib/lwm2m/lwm2m_senml_cbor_types.h @@ -107,17 +107,17 @@ struct record_key_value_pair_m { struct record { struct record_bn record_bn; - bool record_bn_present; struct record_bt record_bt; - bool record_bt_present; struct record_n record_n; - bool record_n_present; struct record_t record_t; - bool record_t_present; struct record_union_r record_union; - bool record_union_present; struct record_key_value_pair_m record_key_value_pair_m[5]; size_t record_key_value_pair_m_count; + bool record_bn_present; + bool record_bt_present; + bool record_n_present; + bool record_t_present; + bool record_union_present; }; struct lwm2m_senml { diff --git a/subsys/net/lib/lwm2m/lwm2m_shell.c b/subsys/net/lib/lwm2m/lwm2m_shell.c index 5f4d3e20269..153423f6402 100644 --- a/subsys/net/lib/lwm2m/lwm2m_shell.c +++ b/subsys/net/lib/lwm2m/lwm2m_shell.c @@ -17,6 +17,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #include #include #include +#include #include #include @@ -31,7 +32,8 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); "-uX\tRead value as uintX_t\n" \ "-sX\tRead value as intX_t\n" \ "-f \tRead value as float\n" \ - "-t \tRead value as time_t\n" + "-t \tRead value as time_t\n" \ + "-crc32\tCalculate CRC32 of the content\n" #define LWM2M_HELP_WRITE "write PATH [OPTIONS] VALUE\nWrite into LwM2M resource\n" \ "-s \tWrite value as string (default)\n" \ "-b \tWrite value as bool\n" \ @@ -180,6 +182,19 @@ static int cmd_read(const struct shell *sh, size_t argc, char **argv) goto out; } shell_hexdump(sh, buff, buff_len); + } else if (strcmp(dtype, "-crc32") == 0) { + const char *buff; + uint16_t buff_len = 0; + + ret = lwm2m_get_res_buf(&path, (void **)&buff, + NULL, &buff_len, NULL); + if (ret != 0) { + goto out; + } + + uint32_t crc = crc32_ieee(buff, buff_len); + + shell_print(sh, "%u", crc); } else if (strcmp(dtype, "-s") == 0) { const char *buff; uint16_t buff_len = 0; diff --git a/subsys/net/lib/shell/CMakeLists.txt b/subsys/net/lib/shell/CMakeLists.txt index 5cfb5c269b4..ea310b5fc71 100644 --- a/subsys/net/lib/shell/CMakeLists.txt +++ b/subsys/net/lib/shell/CMakeLists.txt @@ -14,6 +14,7 @@ zephyr_library_sources(dhcpv4.c) zephyr_library_sources(dns.c) zephyr_library_sources(events.c) zephyr_library_sources(gptp.c) +zephyr_library_sources(http.c) zephyr_library_sources(iface.c) zephyr_library_sources(ipv4.c) zephyr_library_sources(ipv6.c) diff --git a/subsys/net/lib/shell/events.c b/subsys/net/lib/shell/events.c index 44037a76f3f..f7814982130 100644 --- a/subsys/net/lib/shell/events.c +++ b/subsys/net/lib/shell/events.c @@ -98,6 +98,12 @@ static char *get_l3_desc(struct event_msg *msg, info = net_addr_ntop(AF_INET6, msg->data, extra_info, extra_info_len); break; + case NET_EVENT_IPV6_ADDR_DEPRECATED: + *desc = "IPv6 address"; + *desc2 = "deprecated"; + info = net_addr_ntop(AF_INET6, msg->data, extra_info, + extra_info_len); + break; case NET_EVENT_IPV6_ADDR_DEL: *desc = "IPv6 address"; *desc2 = "del"; @@ -188,6 +194,26 @@ static char *get_l3_desc(struct event_msg *msg, info = net_addr_ntop(AF_INET6, msg->data, extra_info, extra_info_len); break; + case NET_EVENT_IPV6_PE_ENABLED: + *desc = "IPv6 PE"; + *desc2 = "enabled"; + break; + case NET_EVENT_IPV6_PE_DISABLED: + *desc = "IPv6 PE"; + *desc2 = "disabled"; + break; + case NET_EVENT_IPV6_PE_FILTER_ADD: + *desc = "IPv6 PE filter"; + *desc2 = "add"; + info = net_addr_ntop(AF_INET6, msg->data, extra_info, + extra_info_len); + break; + case NET_EVENT_IPV6_PE_FILTER_DEL: + *desc = "IPv6 PE filter"; + *desc2 = "del"; + info = net_addr_ntop(AF_INET6, msg->data, extra_info, + extra_info_len); + break; case NET_EVENT_IPV4_ADDR_ADD: *desc = "IPv4 address"; *desc2 = "add"; diff --git a/subsys/net/lib/shell/http.c b/subsys/net/lib/shell/http.c new file mode 100644 index 00000000000..72c7b61506f --- /dev/null +++ b/subsys/net/lib/shell/http.c @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +LOG_MODULE_DECLARE(net_shell); + +#include "net_shell_private.h" +#include +#include +#include +#include + +#define IS_BIT_SET(val, bit) (((val >> bit) & (0x1)) != 0) + +static int cmd_net_http(const struct shell *sh, size_t argc, char *argv[]) +{ +#if defined(CONFIG_HTTP_SERVER) + int res_count = 0, serv_count = 0; + + PR("%-15s\t%-12s\n", + "Host:Port", "Concurrent/Backlog"); + PR("\tResource type\tMethods\t\tEndpoint\n"); + + HTTP_SERVICE_FOREACH(svc) { + PR("\n"); + PR("%s:%d\t%zu/%zu\n", + svc->host == NULL || svc->host[0] == '\0' ? + "" : svc->host, svc->port ? *svc->port : 0, + svc->concurrent, svc->backlog); + + HTTP_SERVICE_FOREACH_RESOURCE(svc, res) { + struct http_resource_detail *detail = res->detail; + const char *detail_type = ""; + int method_count = 0; + bool print_comma; + + switch (detail->type) { + case HTTP_RESOURCE_TYPE_STATIC: + detail_type = "static"; + break; + case HTTP_RESOURCE_TYPE_DYNAMIC: + detail_type = "dynamic"; + break; + case HTTP_RESOURCE_TYPE_WEBSOCKET: + detail_type = "websocket"; + break; + } + + PR("\t%12s\t", detail_type); + + print_comma = false; + + for (int i = 0; i < NUM_BITS(uint32_t); i++) { + if (IS_BIT_SET(detail->bitmask_of_supported_http_methods, i)) { + PR("%s%s", print_comma ? "," : "", http_method_str(i)); + print_comma = true; + method_count++; + } + } + + if (method_count < 2) { + /* make columns line up better */ + PR("\t"); + } + + PR("\t%s\n", res->resource); + res_count++; + } + + serv_count++; + } + + if (res_count == 0 && serv_count == 0) { + PR("No HTTP services and resources found.\n"); + } else { + PR("\n%d service%sand %d resource%sfound.\n", + serv_count, serv_count > 1 ? "s " : " ", + res_count, res_count > 1 ? "s " : " "); + } + +#else /* CONFIG_HTTP_SERVER */ + ARG_UNUSED(argc); + ARG_UNUSED(argv); + + PR_INFO("Set %s to enable %s support.\n", + "CONFIG_HTTP_SERVER", + "HTTP information"); +#endif + + return 0; +} + +SHELL_SUBCMD_ADD((net), http, NULL, + "Show HTTP services.", + cmd_net_http, 1, 0); diff --git a/subsys/net/lib/shell/iface.c b/subsys/net/lib/shell/iface.c index ac3980c6213..00c681784ed 100644 --- a/subsys/net/lib/shell/iface.c +++ b/subsys/net/lib/shell/iface.c @@ -321,12 +321,13 @@ static void iface_cb(struct net_if *iface, void *user_data) continue; } - PR("\t%s %s %s%s%s\n", + PR("\t%s %s %s%s%s%s\n", net_sprint_ipv6_addr(&unicast->address.in6_addr), addrtype2str(unicast->addr_type), addrstate2str(unicast->addr_state), unicast->is_infinite ? " infinite" : "", - unicast->is_mesh_local ? " meshlocal" : ""); + unicast->is_mesh_local ? " meshlocal" : "", + unicast->is_temporary ? " temporary" : ""); count++; } @@ -385,6 +386,12 @@ static void iface_cb(struct net_if *iface, void *user_data) skip_ipv6: +#if defined(CONFIG_NET_IPV6_PE) + PR("IPv6 privacy extension : %s (preferring %s addresses)\n", + iface->pe_enabled ? "enabled" : "disabled", + iface->pe_prefer_public ? "public" : "temporary"); +#endif + if (ipv6) { PR("IPv6 hop limit : %d\n", ipv6->hop_limit); @@ -404,9 +411,6 @@ static void iface_cb(struct net_if *iface, void *user_data) if ( #if defined(CONFIG_NET_L2_IEEE802154) (net_if_l2(iface) == &NET_L2_GET_NAME(IEEE802154)) || -#endif -#if defined(CONFIG_NET_L2_BT) - (net_if_l2(iface) == &NET_L2_GET_NAME(BLUETOOTH)) || #endif 0) { PR_WARNING("%s not %s for this interface.\n", "IPv4", diff --git a/subsys/net/lib/shell/ipv4.c b/subsys/net/lib/shell/ipv4.c index cc2e7e30d70..2e6d4ccf7d6 100644 --- a/subsys/net/lib/shell/ipv4.c +++ b/subsys/net/lib/shell/ipv4.c @@ -32,7 +32,7 @@ static void ip_address_lifetime_cb(struct net_if *iface, void *user_data) return; } - PR("Type \tState \tLifetime (sec)\tAddress\n"); + PR("Type \tState \tRef\tAddress\n"); ARRAY_FOR_EACH(ipv4->unicast, i) { if (!ipv4->unicast[i].ipv4.is_used || @@ -40,13 +40,14 @@ static void ip_address_lifetime_cb(struct net_if *iface, void *user_data) continue; } - PR("%s \t%s \t%12s/%12s\n", - addrtype2str(ipv4->unicast[i].ipv4.addr_type), - addrstate2str(ipv4->unicast[i].ipv4.addr_state), - net_sprint_ipv4_addr( - &ipv4->unicast[i].ipv4.address.in_addr), - net_sprint_ipv4_addr( - &ipv4->unicast[i].netmask)); + PR("%s \t%s \t%ld\t%s/%s\n", + addrtype2str(ipv4->unicast[i].ipv4.addr_type), + addrstate2str(ipv4->unicast[i].ipv4.addr_state), + atomic_get(&ipv4->unicast[i].ipv4.atomic_ref), + net_sprint_ipv4_addr( + &ipv4->unicast[i].ipv4.address.in_addr), + net_sprint_ipv4_addr( + &ipv4->unicast[i].netmask)); } } #endif /* CONFIG_NET_NATIVE_IPV4 */ diff --git a/subsys/net/lib/shell/ipv6.c b/subsys/net/lib/shell/ipv6.c index 12f4ce66565..b9a9252f1ac 100644 --- a/subsys/net/lib/shell/ipv6.c +++ b/subsys/net/lib/shell/ipv6.c @@ -56,6 +56,28 @@ void ipv6_frag_cb(struct net_ipv6_reassembly *reass, void *user_data) #if defined(CONFIG_NET_NATIVE_IPV6) +#if defined(CONFIG_NET_IPV6_PE) +static void ipv6_pe_filter_cb(struct in6_addr *prefix, bool is_denylist, + void *user_data) +{ + struct net_shell_user_data *data = user_data; + const struct shell *sh = data->sh; + int *count = data->user_data; + char ipaddr[INET6_ADDRSTRLEN + 1]; + + net_addr_ntop(AF_INET6, prefix, ipaddr, sizeof(ipaddr) - 1); + + if (*count == 0) { + PR("IPv6 privacy extension %s list filters :\n", + is_denylist ? "deny" : "allow"); + } + + PR("[%d] %s/64\n", *count, ipaddr); + + (*count)++; +} +#endif /* CONFIG_NET_IPV6_PE */ + static void address_lifetime_cb(struct net_if *iface, void *user_data) { struct net_shell_user_data *data = user_data; @@ -74,12 +96,12 @@ static void address_lifetime_cb(struct net_if *iface, void *user_data) return; } - PR("Type \tState \tLifetime (sec)\tAddress\n"); + PR("Type \tState \tLifetime (sec)\tRef\tAddress\n"); ARRAY_FOR_EACH(ipv6->unicast, i) { struct net_if_ipv6_prefix *prefix; char remaining_str[sizeof("01234567890")]; - uint64_t remaining; + uint32_t remaining; uint8_t prefix_len; if (!ipv6->unicast[i].is_used || @@ -103,16 +125,16 @@ static void address_lifetime_cb(struct net_if *iface, void *user_data) "infinite"); } else { snprintk(remaining_str, sizeof(remaining_str) - 1, - "%u", (uint32_t)(remaining / 1000U)); + "%u", remaining); } - PR("%s \t%s\t%s \t%s/%d\n", - addrtype2str(ipv6->unicast[i].addr_type), - addrstate2str(ipv6->unicast[i].addr_state), - remaining_str, - net_sprint_ipv6_addr( - &ipv6->unicast[i].address.in6_addr), - prefix_len); + PR("%s \t%s\t%14s\t%ld\t%s/%d%s\n", + addrtype2str(ipv6->unicast[i].addr_type), + addrstate2str(ipv6->unicast[i].addr_state), + remaining_str, atomic_get(&ipv6->unicast[i].atomic_ref), + net_sprint_ipv6_addr(&ipv6->unicast[i].address.in6_addr), + prefix_len, + ipv6->unicast[i].is_temporary ? " (temporary)" : ""); } } #endif /* CONFIG_NET_NATIVE_IPV6 */ @@ -160,6 +182,15 @@ static int cmd_net_ipv6(const struct shell *sh, size_t argc, char *argv[]) "disabled"); } + PR("Privacy extension support : %s\n", + IS_ENABLED(CONFIG_NET_IPV6_PE) ? "enabled" : "disabled"); + +#if defined(CONFIG_NET_IPV6_PE) + PR("Max number of IPv6 privacy extension filters " + " : %d\n", + CONFIG_NET_IPV6_PE_FILTER_PREFIX_COUNT); +#endif + PR("Max number of IPv6 network interfaces " "in the system : %d\n", CONFIG_NET_IF_MAX_IPV6_COUNT); @@ -178,7 +209,8 @@ static int cmd_net_ipv6(const struct shell *sh, size_t argc, char *argv[]) /* Print information about address lifetime */ net_if_foreach(address_lifetime_cb, &user_data); -#endif + +#endif /* CONFIG_NET_NATIVE_IPV6 */ return 0; } @@ -292,6 +324,119 @@ static int cmd_net_ip6_del(const struct shell *sh, size_t argc, char *argv[]) return 0; } +static int cmd_net_ip6_pe(const struct shell *sh, size_t argc, char *argv[]) +{ +#if defined(CONFIG_NET_NATIVE_IPV6) +#if CONFIG_NET_IPV6_PE_FILTER_PREFIX_COUNT > 0 + bool do_allowlisting = true; + struct in6_addr prefix; + bool do_add; + int arg = 1; + int ret; + + if (argc == 0) { + PR_ERROR("Correct usage: net ipv6 pe [add | del] [allow | deny] []\n"); + return -EINVAL; + } + + if (argc == 1) { + struct net_shell_user_data user_data; + int count = 0; + + user_data.sh = sh; + user_data.user_data = &count; + + count = net_ipv6_pe_filter_foreach(ipv6_pe_filter_cb, &user_data); + if (count == 0) { + PR("No privacy extension filters found."); + } + + return 0; + } + + if (strcmp(argv[arg], "add") == 0) { + arg++; + do_add = true; + } else if (strcmp(argv[arg], "del") == 0) { + arg++; + do_add = false; + } else { + PR("Unknown sub-option \"%s\"\n", argv[arg]); + return 0; + } + + if (!argv[arg]) { + PR("No sub-options given. See \"help net ipv6\" " + "command for details.\n"); + return 0; + } + + if (strcmp(argv[arg], "allow") == 0) { + arg++; + } else if (strcmp(argv[arg], "deny") == 0) { + arg++; + do_allowlisting = false; + } + + if (!argv[arg]) { + PR("No sub-options given. See \"help net ipv6\" " + "command for details.\n"); + return 0; + } + + ret = net_addr_pton(AF_INET6, argv[arg], &prefix); + if (ret < 0) { + PR("Invalid prefix \"%s\"\n", argv[arg]); + if (strstr(argv[arg], "/")) { + PR("Do not add the prefix length.\n"); + } + + return 0; + } + + if (do_add) { + ret = net_ipv6_pe_add_filter(&prefix, !do_allowlisting); + } else { + ret = net_ipv6_pe_del_filter(&prefix); + } + + if (ret < 0) { + if (ret == -EALREADY) { + PR("Filter %s already in %s list\n", + net_sprint_ipv6_addr(&prefix), + do_allowlisting ? "allow" : "deny"); + } else if (ret == -ENOENT) { + PR("No such filter %s found\n", + net_sprint_ipv6_addr(&prefix)); + } else { + PR("Cannot %s %s %sfilter (%d)\n", + do_add ? "add" : "delete", + argv[arg], + do_add ? + (do_allowlisting ? "allowlist " : + "denylist ") : "", + ret); + } + + return 0; + } + + PR("%s %s%sfilter for %s\n", + do_add ? "Added" : "Deleted", + do_add ? (do_allowlisting ? "allow" : "deny") : "", + do_add ? " list " : "", + argv[arg]); +#else + PR("IPv6 privacy extension filter support is disabled.\n"); + PR("Set CONFIG_NET_IPV6_PE_FILTER_PREFIX_COUNT > 0 to enable it.\n"); +#endif +#else /* CONFIG_NET_NATIVE_IPV6 */ + PR_INFO("Set %s and %s to enable native %s support.\n", + "CONFIG_NET_NATIVE", "CONFIG_NET_IPV6", "IPv6"); +#endif /* CONFIG_NET_NATIVE_IPV6 */ + return 0; +} + SHELL_STATIC_SUBCMD_SET_CREATE(net_cmd_ip6, SHELL_CMD(add, NULL, "'net ipv6 add
' adds the address to the interface.", @@ -299,6 +444,15 @@ SHELL_STATIC_SUBCMD_SET_CREATE(net_cmd_ip6, SHELL_CMD(del, NULL, "'net ipv6 del
' deletes the address from the interface.", cmd_net_ip6_del), + SHELL_CMD(pe, NULL, + "net ipv6 pe add [allow|deny] \n" + "Add IPv6 address to filter list. The allow/deny " + "parameter tells if this is allow listed (accepted) or " + "deny listed (declined) prefix. Default is to allow list " + "the prefix.\n" + "ipv6 pe del \n" + "Delete IPv6 address from filter list.", + cmd_net_ip6_pe), SHELL_SUBCMD_SET_END ); diff --git a/subsys/net/lib/shell/net_shell.c b/subsys/net/lib/shell/net_shell.c index 9f932cb1bc4..1ba64041d1e 100644 --- a/subsys/net/lib/shell/net_shell.c +++ b/subsys/net/lib/shell/net_shell.c @@ -202,16 +202,6 @@ const char *iface2str(struct net_if *iface, const char **extra) } #endif -#ifdef CONFIG_NET_L2_BT - if (net_if_l2(iface) == &NET_L2_GET_NAME(BLUETOOTH)) { - if (extra) { - *extra = "========="; - } - - return "Bluetooth"; - } -#endif - #ifdef CONFIG_NET_OFFLOAD if (net_if_is_ip_offloaded(iface)) { if (extra) { diff --git a/subsys/net/lib/shell/route.c b/subsys/net/lib/shell/route.c index 035b56f6dfc..9e84860b1e2 100644 --- a/subsys/net/lib/shell/route.c +++ b/subsys/net/lib/shell/route.c @@ -93,30 +93,20 @@ static void route_mcast_cb(struct net_route_entry_mcast *entry, { struct net_shell_user_data *data = user_data; const struct shell *sh = data->sh; - struct net_if *iface = data->user_data; - const char *extra; - if (entry->iface != iface) { - return; - } - - PR("IPv6 multicast route %p for interface %d (%p) (%s)\n", entry, - net_if_get_by_iface(iface), iface, iface2str(iface, &extra)); - PR("===========================================================" - "%s\n", extra); + PR("IPv6 multicast route (%p)\n", entry); + PR("=================================\n"); PR("IPv6 group : %s\n", net_sprint_ipv6_addr(&entry->group)); PR("IPv6 group len : %d\n", entry->prefix_len); PR("Lifetime : %u\n", entry->lifetime); -} -static void iface_per_mcast_route_cb(struct net_if *iface, void *user_data) -{ - struct net_shell_user_data *data = user_data; - - data->user_data = iface; - - net_route_mcast_foreach(route_mcast_cb, NULL, data); + for (int i = 0; i < CONFIG_NET_MCAST_ROUTE_MAX_IFACES; ++i) { + if (entry->ifaces[i]) { + PR("Interface : %d (%p) %s\n", net_if_get_by_iface(entry->ifaces[i]), + entry->ifaces[i], iface2str(entry->ifaces[i], NULL)); + } + } } #endif /* CONFIG_NET_ROUTE_MCAST */ @@ -234,7 +224,7 @@ static int cmd_net_route(const struct shell *sh, size_t argc, char *argv[]) #endif #if defined(CONFIG_NET_ROUTE_MCAST) - net_if_foreach(iface_per_mcast_route_cb, &user_data); + net_route_mcast_foreach(route_mcast_cb, NULL, &user_data); #endif #endif return 0; diff --git a/subsys/net/lib/shell/websocket.c b/subsys/net/lib/shell/websocket.c index 56e705199e3..7e760024f7e 100644 --- a/subsys/net/lib/shell/websocket.c +++ b/subsys/net/lib/shell/websocket.c @@ -37,16 +37,16 @@ static void websocket_context_cb(struct websocket_context *context, } if ((*count) == 0) { - PR(" websocket/net_ctx\tIface " - "Local \tRemote\n"); + PR(" websocket/net_ctx \tIface\t" + "%-16s\t%-16s\n", "Local", "Remote"); } get_addresses(net_ctx, addr_local, sizeof(addr_local), addr_remote, sizeof(addr_remote)); - PR("[%2d] %p/%p\t%p %16s\t%16s\n", + PR("[%2d] %p/%p\t%d\t%-16s\t%-16s\n", (*count) + 1, context, net_ctx, - net_context_get_iface(net_ctx), + net_if_get_by_iface(net_context_get_iface(net_ctx)), addr_local, addr_remote); (*count)++; diff --git a/subsys/net/lib/sockets/Kconfig b/subsys/net/lib/sockets/Kconfig index 8f7996a93bd..b93369e62ce 100644 --- a/subsys/net/lib/sockets/Kconfig +++ b/subsys/net/lib/sockets/Kconfig @@ -147,10 +147,9 @@ config NET_SOCKETS_SERVICE_INIT_PRIO depends on NET_SOCKETS_SERVICE config NET_SOCKETS_SOCKOPT_TLS - bool "TCP TLS socket option support [EXPERIMENTAL]" + bool "TCP TLS socket option support" imply TLS_CREDENTIALS select MBEDTLS if NET_NATIVE - select EXPERIMENTAL help Enable TLS socket option support which automatically establishes a TLS connection to the remote host. @@ -180,10 +179,9 @@ config NET_SOCKETS_TLS_SET_MAX_FRAGMENT_LENGTH the maximum supported receive record length. config NET_SOCKETS_ENABLE_DTLS - bool "DTLS socket support [EXPERIMENTAL]" + bool "DTLS socket support" depends on NET_SOCKETS_SOCKOPT_TLS select MBEDTLS_DTLS if NET_NATIVE - select EXPERIMENTAL help Enable DTLS socket support. By default only TLS over TCP is supported. diff --git a/subsys/net/lib/sockets/sockets.c b/subsys/net/lib/sockets/sockets.c index e153cd173bb..e75c0b0203f 100644 --- a/subsys/net/lib/sockets/sockets.c +++ b/subsys/net/lib/sockets/sockets.c @@ -89,8 +89,8 @@ static inline void *get_sock_vtable(int sock, #endif /* CONFIG_USERSPACE */ if (ctx == NULL) { - NET_ERR("invalid access on sock %d by thread %p", sock, - _current); + NET_DBG("Invalid access on sock %d by thread %p (%s)", sock, + _current, k_thread_name_get(_current)); } return ctx; @@ -2692,6 +2692,22 @@ int zsock_getsockopt_ctx(struct net_context *ctx, int level, int optname, break; + case IPV6_ADDR_PREFERENCES: + if (IS_ENABLED(CONFIG_NET_IPV6)) { + ret = net_context_get_option(ctx, + NET_OPT_ADDR_PREFERENCES, + optval, + optlen); + if (ret < 0) { + errno = -ret; + return -1; + } + + return 0; + } + + break; + case IPV6_TCLASS: if (IS_ENABLED(CONFIG_NET_CONTEXT_DSCP_ECN)) { ret = net_context_get_option(ctx, @@ -3276,6 +3292,22 @@ int zsock_setsockopt_ctx(struct net_context *ctx, int level, int optname, break; + case IPV6_ADDR_PREFERENCES: + if (IS_ENABLED(CONFIG_NET_IPV6)) { + ret = net_context_set_option(ctx, + NET_OPT_ADDR_PREFERENCES, + optval, + optlen); + if (ret < 0) { + errno = -ret; + return -1; + } + + return 0; + } + + break; + case IPV6_TCLASS: if (IS_ENABLED(CONFIG_NET_CONTEXT_DSCP_ECN)) { ret = net_context_set_option(ctx, @@ -3452,6 +3484,7 @@ int zsock_getsockname_ctx(struct net_context *ctx, struct sockaddr *addr, socklen_t *addrlen) { socklen_t newlen = 0; + int ret; if (IS_ENABLED(CONFIG_NET_IPV4) && ctx->local.family == AF_INET) { struct sockaddr_in addr4 = { 0 }; @@ -3460,27 +3493,33 @@ int zsock_getsockname_ctx(struct net_context *ctx, struct sockaddr *addr, SET_ERRNO(-EINVAL); } - addr4.sin_family = AF_INET; - addr4.sin_port = net_sin_ptr(&ctx->local)->sin_port; - memcpy(&addr4.sin_addr, net_sin_ptr(&ctx->local)->sin_addr, - sizeof(struct in_addr)); newlen = sizeof(struct sockaddr_in); + ret = net_context_get_local_addr(ctx, + (struct sockaddr *)&addr4, + &newlen); + if (ret < 0) { + SET_ERRNO(-ret); + } + memcpy(addr, &addr4, MIN(*addrlen, newlen)); - } else if (IS_ENABLED(CONFIG_NET_IPV6) && - ctx->local.family == AF_INET6) { + + } else if (IS_ENABLED(CONFIG_NET_IPV6) && ctx->local.family == AF_INET6) { struct sockaddr_in6 addr6 = { 0 }; if (net_sin6_ptr(&ctx->local)->sin6_addr == NULL) { SET_ERRNO(-EINVAL); } - addr6.sin6_family = AF_INET6; - addr6.sin6_port = net_sin6_ptr(&ctx->local)->sin6_port; - memcpy(&addr6.sin6_addr, net_sin6_ptr(&ctx->local)->sin6_addr, - sizeof(struct in6_addr)); newlen = sizeof(struct sockaddr_in6); + ret = net_context_get_local_addr(ctx, + (struct sockaddr *)&addr6, + &newlen); + if (ret < 0) { + SET_ERRNO(-ret); + } + memcpy(addr, &addr6, MIN(*addrlen, newlen)); } else { SET_ERRNO(-EINVAL); diff --git a/subsys/net/lib/sockets/sockets_misc.c b/subsys/net/lib/sockets/sockets_misc.c index fb3750e110a..f16bfc8e962 100644 --- a/subsys/net/lib/sockets/sockets_misc.c +++ b/subsys/net/lib/sockets/sockets_misc.c @@ -6,6 +6,7 @@ #include #include +#include #include int z_impl_zsock_gethostname(char *buf, size_t len) diff --git a/subsys/net/lib/sockets/sockets_service.c b/subsys/net/lib/sockets/sockets_service.c index ad5c07de601..6e034d57ea5 100644 --- a/subsys/net/lib/sockets/sockets_service.c +++ b/subsys/net/lib/sockets/sockets_service.c @@ -8,6 +8,7 @@ LOG_MODULE_REGISTER(net_sock_svc, CONFIG_NET_SOCKETS_LOG_LEVEL); #include +#include #include #include @@ -179,6 +180,7 @@ static int trigger_work(struct zsock_pollfd *pev) static void socket_service_thread(void) { int ret, i, fd, count = 0; + int error_count = 0; eventfd_t value; STRUCT_SECTION_COUNT(net_socket_service_desc, &ret); @@ -252,11 +254,25 @@ static void socket_service_thread(void) } if (ret > 0 && ctx.events[0].revents) { + if ((ctx.events[0].revents & ZSOCK_POLLNVAL) || + (ctx.events[0].revents & ZSOCK_POLLERR)) { + /* Ignore eventfd errors and turn eventfd + * support off if we get too many errors + */ + if (++error_count > 2) { + ctx.events[0].fd = -1; + } + + continue; + } + eventfd_read(ctx.events[0].fd, &value); NET_DBG("Received restart event."); goto restart; } + error_count = 0; + for (i = 1; i < (count + 1); i++) { if (ctx.events[i].fd < 0) { continue; diff --git a/subsys/net/lib/sockets/sockets_tls.c b/subsys/net/lib/sockets/sockets_tls.c index 4d7fadce47b..185324de97e 100644 --- a/subsys/net/lib/sockets/sockets_tls.c +++ b/subsys/net/lib/sockets/sockets_tls.c @@ -655,6 +655,7 @@ static int tls_session_get(const struct sockaddr *peer_addr, /* Discard corrupted session data. */ mbedtls_free(entry->session); entry->session = NULL; + NET_ERR("Failed to load TLS session %d", ret); return -EIO; } @@ -762,6 +763,8 @@ static int wait(int sock, int timeout, int event) if (zsock_getsockopt(fds.fd, SOL_SOCKET, SO_ERROR, &optval, &optlen) == 0) { + NET_ERR("TLS underlying socket poll error %d", + -optval); return -optval; } @@ -2313,6 +2316,8 @@ static ssize_t send_tls(struct tls_context *ctx, const void *buf, break; } } else { + NET_ERR("TLS send error: -%x", -ret); + /* MbedTLS API documentation requires session to * be reset in other error cases */ @@ -2622,6 +2627,7 @@ static ssize_t recv_tls(struct tls_context *ctx, void *buf, continue; } } else { + NET_ERR("TLS recv error: -%x", -ret); ret = -EIO; } @@ -2792,6 +2798,8 @@ static ssize_t recvfrom_dtls_client(struct tls_context *ctx, void *buf, break; default: + NET_ERR("DTLS client recv error: -%x", -ret); + /* MbedTLS API documentation requires session to * be reset in other error cases */ @@ -2893,6 +2901,8 @@ static ssize_t recvfrom_dtls_server(struct tls_context *ctx, void *buf, break; default: + NET_ERR("DTLS server recv error: -%x", -ret); + ret = tls_mbedtls_reset(ctx); if (ret != 0) { ctx->error = ENOMEM; @@ -3090,6 +3100,8 @@ static int ztls_socket_data_check(struct tls_context *ctx) return 0; } + NET_ERR("TLS data check error: -%x", -ret); + /* MbedTLS API documentation requires session to * be reset in other error cases */ diff --git a/subsys/net/lib/tls_credentials/Kconfig b/subsys/net/lib/tls_credentials/Kconfig index 58ec0949d47..760a3ce6757 100644 --- a/subsys/net/lib/tls_credentials/Kconfig +++ b/subsys/net/lib/tls_credentials/Kconfig @@ -28,6 +28,7 @@ config TLS_CREDENTIALS_BACKEND_VOLATILE config TLS_CREDENTIALS_BACKEND_PROTECTED_STORAGE bool "TLS credentials management protected storage backend" depends on BUILD_WITH_TFM + select PSA_WANT_ALG_SHA_256 help TLS credentials management backend using the Protected Storage API to store credentials with integrity check against physical diff --git a/subsys/net/lib/tls_credentials/tls_credentials_digest_raw.c b/subsys/net/lib/tls_credentials/tls_credentials_digest_raw.c index 2013c5d52fb..6752f8dd506 100644 --- a/subsys/net/lib/tls_credentials/tls_credentials_digest_raw.c +++ b/subsys/net/lib/tls_credentials/tls_credentials_digest_raw.c @@ -16,48 +16,9 @@ #include "tls_internal.h" #include "tls_credentials_digest_raw.h" -/* Grab mbedTLS headers if they are available so that we can check whether SHA256 is supported */ +#if defined(CONFIG_PSA_WANT_ALG_SHA_256) && defined(CONFIG_BASE64) -#if defined(CONFIG_MBEDTLS) -#if !defined(CONFIG_MBEDTLS_CFG_FILE) -#include "mbedtls/config.h" -#else -#include CONFIG_MBEDTLS_CFG_FILE -#endif /* CONFIG_MBEDTLS_CFG_FILE */ -#endif /* CONFIG_MBEDTLS */ - -#if defined(CONFIG_TINYCRYPT_SHA256) && defined(CONFIG_BASE64) - -#include -#include - -int credential_digest_raw(struct tls_credential *credential, void *dest, size_t *len) -{ - int err = 0; - size_t written = 0; - struct tc_sha256_state_struct sha_state; - uint8_t digest_buf[TC_SHA256_DIGEST_SIZE]; - - /* Compute digest. */ - (void)tc_sha256_init(&sha_state); - (void)tc_sha256_update(&sha_state, credential->buf, credential->len); - (void)tc_sha256_final(digest_buf, &sha_state); - - /* Attempt to encode digest to destination. - * Will return -ENOMEM if there is not enough space in the destination buffer. - */ - err = base64_encode(dest, *len, &written, digest_buf, sizeof(digest_buf)); - *len = err ? 0 : written; - - /* Clean up. */ - memset(&sha_state, 0, sizeof(sha_state)); - memset(digest_buf, 0, sizeof(digest_buf)); - return err; -} - -#elif defined(MBEDTLS_SHA256_C) && defined(CONFIG_BASE64) - -#include +#include #include int credential_digest_raw(struct tls_credential *credential, void *dest, size_t *len) @@ -65,9 +26,15 @@ int credential_digest_raw(struct tls_credential *credential, void *dest, size_t int err = 0; size_t written = 0; uint8_t digest_buf[32]; + size_t digest_len; + psa_status_t status; - /* Compute digest. The '0' indicates to mbedtls to use SHA256 instead of 224. */ - mbedtls_sha256(credential->buf, credential->len, digest_buf, 0); + /* Compute digest. */ + status = psa_hash_compute(PSA_ALG_SHA_256, credential->buf, credential->len, + digest_buf, sizeof(digest_buf), &digest_len); + if (status != PSA_SUCCESS) { + return -EIO; + } /* Attempt to encode digest to destination. * Will return -ENOMEM if there is not enough space in the destination buffer. diff --git a/subsys/net/lib/websocket/Kconfig b/subsys/net/lib/websocket/Kconfig index adfcdc169d9..20f6ca6b1fe 100644 --- a/subsys/net/lib/websocket/Kconfig +++ b/subsys/net/lib/websocket/Kconfig @@ -1,7 +1,7 @@ # Copyright (c) 2019 Intel Corporation # SPDX-License-Identifier: Apache-2.0 -menuconfig WEBSOCKET_CLIENT +config WEBSOCKET_CLIENT bool "Websocket client support [EXPERIMENTAL]" select NET_SOCKETS select HTTP_PARSER @@ -14,6 +14,12 @@ menuconfig WEBSOCKET_CLIENT help Enable Websocket client library. +config WEBSOCKET + bool + default y if WEBSOCKET_CLIENT + help + Helper symbol for generic Websocket support. + if WEBSOCKET_CLIENT config WEBSOCKET_MAX_CONTEXTS diff --git a/subsys/net/lib/websocket/websocket.c b/subsys/net/lib/websocket/websocket.c index 8f463285c25..c7b896ecb8a 100644 --- a/subsys/net/lib/websocket/websocket.c +++ b/subsys/net/lib/websocket/websocket.c @@ -393,6 +393,8 @@ int websocket_connect(int sock, struct websocket_request *wreq, /* Init parser FSM */ ctx->parser_state = WEBSOCKET_PARSER_STATE_OPCODE; + (void)sock_obj_core_alloc_find(ctx->real_sock, fd, SOCK_STREAM); + return fd; out: @@ -422,9 +424,11 @@ static int websocket_interal_disconnect(struct websocket_context *ctx) ret = websocket_send_msg(ctx->sock, NULL, 0, WEBSOCKET_OPCODE_CLOSE, true, true, SYS_FOREVER_MS); if (ret < 0) { - NET_ERR("[%p] Failed to send close message (err %d).", ctx, ret); + NET_DBG("[%p] Failed to send close message (err %d).", ctx, ret); } + (void)sock_obj_core_dealloc(ctx->sock); + websocket_context_unref(ctx); return ret; @@ -437,10 +441,15 @@ static int websocket_close_vmeth(void *obj) ret = websocket_interal_disconnect(ctx); if (ret < 0) { - NET_DBG("[%p] Cannot close (%d)", obj, ret); + /* Ignore error if we are not connected */ + if (ret != -ENOTCONN) { + NET_DBG("[%p] Cannot close (%d)", obj, ret); - errno = -ret; - return -1; + errno = -ret; + return -1; + } + + ret = 0; } return ret; @@ -1050,6 +1059,8 @@ static int websocket_send(struct websocket_context *ctx, const uint8_t *buf, NET_DBG("[%p] Sent %d bytes", ctx, ret); + sock_obj_core_update_send_stats(ctx->sock, ret); + return ret; } @@ -1078,6 +1089,8 @@ static int websocket_recv(struct websocket_context *ctx, uint8_t *buf, NET_DBG("[%p] Received %d bytes", ctx, ret); + sock_obj_core_update_recv_stats(ctx->sock, ret); + return ret; } @@ -1127,6 +1140,111 @@ static ssize_t websocket_recvfrom_ctx(void *obj, void *buf, size_t max_len, return (ssize_t)websocket_recv(ctx, buf, max_len, timeout); } +int websocket_register(int sock, uint8_t *recv_buf, size_t recv_buf_len) +{ + struct websocket_context *ctx; + int ret, fd; + + if (sock < 0) { + return -EINVAL; + } + + ctx = websocket_find(sock); + if (ctx) { + NET_DBG("[%p] Websocket for sock %d already exists!", ctx, sock); + return -EEXIST; + } + + ctx = websocket_get(); + if (!ctx) { + return -ENOENT; + } + + ctx->real_sock = sock; + ctx->recv_buf.buf = recv_buf; + ctx->recv_buf.size = recv_buf_len; + + fd = z_reserve_fd(); + if (fd < 0) { + ret = -ENOSPC; + goto out; + } + + ctx->sock = fd; + z_finalize_fd(fd, ctx, + (const struct fd_op_vtable *)&websocket_fd_op_vtable); + + NET_DBG("[%p] WS connection to peer established (fd %d)", ctx, fd); + + ctx->recv_buf.count = 0; + ctx->parser_state = WEBSOCKET_PARSER_STATE_OPCODE; + + (void)sock_obj_core_alloc_find(ctx->real_sock, fd, SOCK_STREAM); + + return fd; + +out: + if (fd >= 0) { + (void)zsock_close(fd); + } + + websocket_context_unref(ctx); + + return ret; +} + +static struct websocket_context *websocket_search(int sock) +{ + struct websocket_context *ctx = NULL; + int i; + + k_sem_take(&contexts_lock, K_FOREVER); + + for (i = 0; i < ARRAY_SIZE(contexts); i++) { + if (!websocket_context_is_used(&contexts[i])) { + continue; + } + + if (contexts[i].sock != sock) { + continue; + } + + ctx = &contexts[i]; + break; + } + + k_sem_give(&contexts_lock); + + return ctx; +} + +int websocket_unregister(int sock) +{ + struct websocket_context *ctx; + + if (sock < 0) { + return -EINVAL; + } + + ctx = websocket_search(sock); + if (ctx == NULL) { + NET_DBG("[%p] Real socket for websocket sock %d not found!", ctx, sock); + return -ENOENT; + } + + if (ctx->real_sock < 0) { + return -EALREADY; + } + + (void)zsock_close(sock); + (void)zsock_close(ctx->real_sock); + + ctx->real_sock = -1; + ctx->sock = -1; + + return 0; +} + static const struct socket_op_vtable websocket_fd_op_vtable = { .fd_vtable = { .read = websocket_read_vmeth, diff --git a/subsys/net/lib/zperf/zperf_common.c b/subsys/net/lib/zperf/zperf_common.c index 3c39008965c..61a49bde39a 100644 --- a/subsys/net/lib/zperf/zperf_common.c +++ b/subsys/net/lib/zperf/zperf_common.c @@ -110,7 +110,7 @@ int zperf_get_ipv4_addr(char *host, struct in_addr *addr) } int zperf_prepare_upload_sock(const struct sockaddr *peer_addr, uint8_t tos, - int priority, int proto) + int priority, int tcp_nodelay, int proto) { socklen_t addrlen = peer_addr->sa_family == AF_INET6 ? sizeof(struct sockaddr_in6) : @@ -189,6 +189,14 @@ int zperf_prepare_upload_sock(const struct sockaddr *peer_addr, uint8_t tos, } } + if (proto == IPPROTO_TCP && tcp_nodelay && + zsock_setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, + &tcp_nodelay, + sizeof(tcp_nodelay)) != 0) { + NET_WARN("Failed to set IPPROTO_TCP - TCP_NODELAY socket option."); + return -EINVAL; + } + ret = zsock_connect(sock, peer_addr, addrlen); if (ret < 0) { NET_ERR("Connect failed (%d)", errno); diff --git a/subsys/net/lib/zperf/zperf_internal.h b/subsys/net/lib/zperf/zperf_internal.h index 84506743002..a798edd8537 100644 --- a/subsys/net/lib/zperf/zperf_internal.h +++ b/subsys/net/lib/zperf/zperf_internal.h @@ -43,6 +43,14 @@ #define DEF_PORT 5001 #define DEF_PORT_STR STRINGIFY(DEF_PORT) +/* Upload defaults */ +#define DEF_DURATION_SECONDS 1 +#define DEF_DURATION_SECONDS_STR STRINGIFY(DEF_DURATION_SECONDS) +#define DEF_PACKET_SIZE 256 +#define DEF_PACKET_SIZE_STR STRINGIFY(DEF_PACKET_SIZE) +#define DEF_RATE_KBPS 10 +#define DEF_RATE_KBPS_STR STRINGIFY(DEF_RATE_KBPS) + #define ZPERF_VERSION "1.1" struct zperf_udp_datagram { @@ -96,7 +104,7 @@ struct sockaddr_in *zperf_get_sin(void); extern void connect_ap(char *ssid); int zperf_prepare_upload_sock(const struct sockaddr *peer_addr, uint8_t tos, - int priority, int proto); + int priority, int tcp_nodelay, int proto); uint32_t zperf_packet_duration(uint32_t packet_size, uint32_t rate_in_kbps); diff --git a/subsys/net/lib/zperf/zperf_shell.c b/subsys/net/lib/zperf/zperf_shell.c index 2bd37a476d1..97d9e1e9140 100644 --- a/subsys/net/lib/zperf/zperf_shell.c +++ b/subsys/net/lib/zperf/zperf_shell.c @@ -361,6 +361,9 @@ static void udp_session_cb(enum zperf_status status, case ZPERF_SESSION_ERROR: shell_fprintf(sh, SHELL_ERROR, "UDP session error.\n"); break; + + default: + break; } } @@ -476,7 +479,7 @@ static void shell_udp_upload_print_stats(const struct shell *sh, struct zperf_results *results) { if (IS_ENABLED(CONFIG_NET_UDP)) { - unsigned int rate_in_kbps, client_rate_in_kbps; + uint64_t rate_in_kbps, client_rate_in_kbps; shell_fprintf(sh, SHELL_NORMAL, "-\nUpload completed!\n"); @@ -540,7 +543,7 @@ static void shell_tcp_upload_print_stats(const struct shell *sh, struct zperf_results *results) { if (IS_ENABLED(CONFIG_NET_TCP)) { - unsigned int client_rate_in_kbps; + uint64_t client_rate_in_kbps; shell_fprintf(sh, SHELL_NORMAL, "-\nUpload completed!\n"); @@ -569,6 +572,37 @@ static void shell_tcp_upload_print_stats(const struct shell *sh, } } +static void shell_tcp_upload_print_periodic(const struct shell *sh, + struct zperf_results *results) +{ + if (IS_ENABLED(CONFIG_NET_TCP)) { + uint64_t client_rate_in_kbps; + + if (results->client_time_in_us != 0U) { + client_rate_in_kbps = (uint32_t) + (((uint64_t)results->nb_packets_sent * + (uint64_t)results->packet_size * (uint64_t)8 * + (uint64_t)USEC_PER_SEC) / + (results->client_time_in_us * 1000U)); + } else { + client_rate_in_kbps = 0U; + } + + shell_fprintf(sh, SHELL_NORMAL, "Duration: "); + print_number_64(sh, results->client_time_in_us, + TIME_US, TIME_US_UNIT); + shell_fprintf(sh, SHELL_NORMAL, " | "); + shell_fprintf(sh, SHELL_NORMAL, "Packets: %6u | ", + results->nb_packets_sent); + shell_fprintf(sh, SHELL_NORMAL, + "Errors: %6u | ", + results->nb_packets_errors); + shell_fprintf(sh, SHELL_NORMAL, "Rate: "); + print_number(sh, client_rate_in_kbps, KBPS, KBPS_UNIT); + shell_fprintf(sh, SHELL_NORMAL, "\n"); + } +} + static void udp_upload_cb(enum zperf_status status, struct zperf_results *result, void *user_data) @@ -587,6 +621,9 @@ static void udp_upload_cb(enum zperf_status status, case ZPERF_SESSION_ERROR: shell_fprintf(sh, SHELL_ERROR, "UDP upload failed\n"); break; + + default: + break; } } @@ -600,6 +637,10 @@ static void tcp_upload_cb(enum zperf_status status, case ZPERF_SESSION_STARTED: break; + case ZPERF_SESSION_PERIODIC_RESULT: + shell_tcp_upload_print_periodic(sh, result); + break; + case ZPERF_SESSION_FINISHED: { shell_tcp_upload_print_stats(sh, result); break; @@ -644,7 +685,8 @@ static void send_ping(const struct shell *sh, return; } - memcpy(&dest_addr.sin6_addr, addr, sizeof(struct in6_addr)); + dest_addr.sin6_family = AF_INET6; + net_ipv6_addr_copy_raw((uint8_t *)&dest_addr.sin6_addr, (uint8_t *)addr); k_sem_init(&sem_wait, 0, 1); @@ -724,8 +766,8 @@ static int execute_upload(const struct shell *sh, shell_udp_upload_print_stats(sh, &results); } } else { - if (!IS_ENABLED(CONFIG_NET_UDP)) { - shell_fprintf(sh, SHELL_INFO, + if (is_udp && !IS_ENABLED(CONFIG_NET_UDP)) { + shell_fprintf(sh, SHELL_WARNING, "UDP not supported\n"); } } @@ -750,8 +792,8 @@ static int execute_upload(const struct shell *sh, shell_tcp_upload_print_stats(sh, &results); } } else { - if (!IS_ENABLED(CONFIG_NET_TCP)) { - shell_fprintf(sh, SHELL_INFO, + if (!is_udp && !IS_ENABLED(CONFIG_NET_TCP)) { + shell_fprintf(sh, SHELL_WARNING, "TCP not supported\n"); } } @@ -866,6 +908,24 @@ static int shell_cmd_upload(const struct shell *sh, size_t argc, opt_cnt += 2; break; + case 'i': + int seconds = parse_arg(&i, argc, argv); + + if (is_udp) { + shell_fprintf(sh, SHELL_WARNING, + "UDP does not support -i option\n"); + return -ENOEXEC; + } + if (seconds < 0 || seconds > UINT16_MAX) { + shell_fprintf(sh, SHELL_WARNING, + "Parse error: %s\n", argv[i]); + return -ENOEXEC; + } + + param.options.report_interval_ms = seconds * MSEC_PER_SEC; + opt_cnt += 2; + break; + default: shell_fprintf(sh, SHELL_WARNING, "Unrecognized argument: %s\n", argv[i]); @@ -916,7 +976,7 @@ static int shell_cmd_upload(const struct shell *sh, size_t argc, return -ENOEXEC; } - shell_fprintf(sh, SHELL_WARNING, "Connecting to %s\n", + shell_fprintf(sh, SHELL_NORMAL, "Connecting to %s\n", net_sprint_ipv6_addr(&ipv6.sin6_addr)); memcpy(¶m.peer_addr, &ipv6, sizeof(ipv6)); @@ -974,20 +1034,24 @@ static int shell_cmd_upload(const struct shell *sh, size_t argc, param.duration_ms = MSEC_PER_SEC * strtoul(argv[start + 3], NULL, 10); } else { - param.duration_ms = MSEC_PER_SEC * 1; + param.duration_ms = MSEC_PER_SEC * DEF_DURATION_SECONDS; } if (argc > 4) { param.packet_size = parse_number(argv[start + 4], K, K_UNIT); } else { - param.packet_size = 256U; + param.packet_size = DEF_PACKET_SIZE; } if (argc > 5) { param.rate_kbps = (parse_number(argv[start + 5], K, K_UNIT) + 999) / 1000; + if (!is_udp) { + shell_fprintf(sh, SHELL_WARNING, + "TCP upload will ignore argument\n"); + } } else { - param.rate_kbps = 10U; + param.rate_kbps = DEF_RATE_KBPS; } return execute_upload(sh, ¶m, is_udp, async); @@ -1077,6 +1141,24 @@ static int shell_cmd_upload2(const struct shell *sh, size_t argc, opt_cnt += 2; break; + case 'i': + int seconds = parse_arg(&i, argc, argv); + + if (is_udp) { + shell_fprintf(sh, SHELL_WARNING, + "UDP does not support -i option\n"); + return -ENOEXEC; + } + if (seconds < 0 || seconds > UINT16_MAX) { + shell_fprintf(sh, SHELL_WARNING, + "Parse error: %s\n", argv[i]); + return -ENOEXEC; + } + + param.options.report_interval_ms = seconds * MSEC_PER_SEC; + opt_cnt += 2; + break; + default: shell_fprintf(sh, SHELL_WARNING, "Unrecognized argument: %s\n", argv[i]); @@ -1138,20 +1220,24 @@ static int shell_cmd_upload2(const struct shell *sh, size_t argc, param.duration_ms = MSEC_PER_SEC * strtoul(argv[start + 2], NULL, 10); } else { - param.duration_ms = MSEC_PER_SEC * 1; + param.duration_ms = MSEC_PER_SEC * DEF_DURATION_SECONDS; } if (argc > 3) { param.packet_size = parse_number(argv[start + 3], K, K_UNIT); } else { - param.packet_size = 256U; + param.packet_size = DEF_PACKET_SIZE; } if (argc > 4) { param.rate_kbps = (parse_number(argv[start + 4], K, K_UNIT) + 999) / 1000; + if (!is_udp) { + shell_fprintf(sh, SHELL_WARNING, + "TCP upload will ignore argument\n"); + } } else { - param.rate_kbps = 10U; + param.rate_kbps = DEF_RATE_KBPS; } return execute_upload(sh, ¶m, is_udp, async); @@ -1242,6 +1328,9 @@ static void tcp_session_cb(enum zperf_status status, case ZPERF_SESSION_ERROR: shell_fprintf(sh, SHELL_ERROR, "TCP session error.\n"); break; + + default: + break; } } @@ -1374,12 +1463,15 @@ SHELL_STATIC_SUBCMD_SET_CREATE(zperf_cmd_tcp, " command options (optional): [-S tos -a]\n" " IP destination\n" " port destination\n" - " of the test in seconds\n" - " Size of the packet in byte or kilobyte " - "(with suffix K)\n" + " of the test in seconds " + "(default " DEF_DURATION_SECONDS_STR ")\n" + " in byte or kilobyte " + "(with suffix K) " + "(default " DEF_PACKET_SIZE_STR ")\n" "Available options:\n" "-S tos: Specify IPv4/6 type of service\n" "-a: Asynchronous call (shell will not block for the upload)\n" + "-i sec: Periodic reporting interval in seconds (async only)\n" "-n: Disable Nagle's algorithm\n" #ifdef CONFIG_NET_CONTEXT_PRIORITY "-p: Specify custom packet priority\n" @@ -1388,21 +1480,24 @@ SHELL_STATIC_SUBCMD_SET_CREATE(zperf_cmd_tcp, "Example: tcp upload 2001:db8::2\n", cmd_tcp_upload), SHELL_CMD(upload2, NULL, - "[] v6|v4 [K] [K|M]\n" + "[] v6|v4 [K]\n" " command options (optional): [-S tos -a]\n" ": Use either IPv6 or IPv4\n" - " Duration of the test in seconds\n" - " Size of the packet in byte or kilobyte " - "(with suffix K)\n" + " of the test in seconds " + "(default " DEF_DURATION_SECONDS_STR ")\n" + " in byte or kilobyte " + "(with suffix K) " + "(default " DEF_PACKET_SIZE_STR ")\n" "Available options:\n" "-S tos: Specify IPv4/6 type of service\n" "-a: Asynchronous call (shell will not block for the upload)\n" + "-i sec: Periodic reporting interval in seconds (async only)\n" + "-n: Disable Nagle's algorithm\n" #ifdef CONFIG_NET_CONTEXT_PRIORITY "-p: Specify custom packet priority\n" #endif /* CONFIG_NET_CONTEXT_PRIORITY */ "Example: tcp upload2 v6 1 1K\n" "Example: tcp upload2 v4\n" - "-n: Disable Nagle's algorithm\n" #if defined(CONFIG_NET_IPV6) && defined(MY_IP6ADDR_SET) "Default IPv6 address is " MY_IP6ADDR ", destination [" DST_IP6ADDR "]:" DEF_PORT_STR "\n" @@ -1433,10 +1528,13 @@ SHELL_STATIC_SUBCMD_SET_CREATE(zperf_cmd_udp, " command options (optional): [-S tos -a]\n" " IP destination\n" " port destination\n" - " of the test in seconds\n" - " Size of the packet in byte or kilobyte " - "(with suffix K)\n" - " Baudrate in kilobyte or megabyte\n" + " of the test in seconds " + "(default " DEF_DURATION_SECONDS_STR ")\n" + " in byte or kilobyte " + "(with suffix K) " + "(default " DEF_PACKET_SIZE_STR ")\n" + " in kilobyte or megabyte " + "(default " DEF_RATE_KBPS_STR "K)\n" "Available options:\n" "-S tos: Specify IPv4/6 type of service\n" "-a: Asynchronous call (shell will not block for the upload)\n" @@ -1451,10 +1549,13 @@ SHELL_STATIC_SUBCMD_SET_CREATE(zperf_cmd_udp, "[] v6|v4 [ [K] [K|M]]\n" " command options (optional): [-S tos -a]\n" ": Use either IPv6 or IPv4\n" - " Duration of the test in seconds\n" - " Size of the packet in byte or kilobyte " - "(with suffix K)\n" - " Baudrate in kilobyte or megabyte\n" + " of the test in seconds " + "(default " DEF_DURATION_SECONDS_STR ")\n" + " in byte or kilobyte " + "(with suffix K) " + "(default " DEF_PACKET_SIZE_STR ")\n" + " in kilobyte or megabyte " + "(default " DEF_RATE_KBPS_STR "K)\n" "Available options:\n" "-S tos: Specify IPv4/6 type of service\n" "-a: Asynchronous call (shell will not block for the upload)\n" diff --git a/subsys/net/lib/zperf/zperf_tcp_uploader.c b/subsys/net/lib/zperf/zperf_tcp_uploader.c index 7958f80b373..6b3fe458347 100644 --- a/subsys/net/lib/zperf/zperf_tcp_uploader.c +++ b/subsys/net/lib/zperf/zperf_tcp_uploader.c @@ -133,19 +133,12 @@ int zperf_tcp_upload(const struct zperf_upload_params *param, } sock = zperf_prepare_upload_sock(¶m->peer_addr, param->options.tos, - param->options.priority, IPPROTO_TCP); + param->options.priority, param->options.tcp_nodelay, + IPPROTO_TCP); if (sock < 0) { return sock; } - if (param->options.tcp_nodelay && - zsock_setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, - ¶m->options.tcp_nodelay, - sizeof(param->options.tcp_nodelay)) != 0) { - NET_WARN("Failed to set IPPROTO_TCP - TCP_NODELAY socket option."); - return -EINVAL; - } - ret = tcp_upload(sock, param->duration_ms, param->packet_size, result); zsock_close(sock); @@ -157,20 +150,72 @@ static void tcp_upload_async_work(struct k_work *work) { struct zperf_async_upload_context *upload_ctx = CONTAINER_OF(work, struct zperf_async_upload_context, work); - struct zperf_results result; + struct zperf_results result = { 0 }; int ret; + struct zperf_upload_params param = upload_ctx->param; + int sock; upload_ctx->callback(ZPERF_SESSION_STARTED, NULL, upload_ctx->user_data); - ret = zperf_tcp_upload(&upload_ctx->param, &result); - if (ret < 0) { + sock = zperf_prepare_upload_sock(¶m.peer_addr, param.options.tos, + param.options.priority, param.options.tcp_nodelay, + IPPROTO_TCP); + + if (sock < 0) { upload_ctx->callback(ZPERF_SESSION_ERROR, NULL, upload_ctx->user_data); + return; + } + + if (param.options.report_interval_ms > 0) { + uint32_t report_interval = param.options.report_interval_ms; + uint32_t duration = param.duration_ms; + + /* Compute how many upload rounds will be executed and the duration + * of the last round when total duration isn't divisible by interval + */ + uint32_t rounds = (duration + report_interval - 1) / report_interval; + uint32_t last_round_duration = duration - ((rounds - 1) * report_interval); + + struct zperf_results periodic_result; + + for (; rounds > 0; rounds--) { + uint32_t round_duration; + + if (rounds == 1) { + round_duration = last_round_duration; + } else { + round_duration = report_interval; + } + ret = tcp_upload(sock, round_duration, param.packet_size, &periodic_result); + if (ret < 0) { + upload_ctx->callback(ZPERF_SESSION_ERROR, NULL, + upload_ctx->user_data); + return; + } + upload_ctx->callback(ZPERF_SESSION_PERIODIC_RESULT, &periodic_result, + upload_ctx->user_data); + + result.nb_packets_sent += periodic_result.nb_packets_sent; + result.client_time_in_us += periodic_result.client_time_in_us; + result.nb_packets_errors += periodic_result.nb_packets_errors; + } + + result.packet_size = periodic_result.packet_size; + } else { - upload_ctx->callback(ZPERF_SESSION_FINISHED, &result, - upload_ctx->user_data); + ret = tcp_upload(sock, param.duration_ms, param.packet_size, &result); + if (ret < 0) { + upload_ctx->callback(ZPERF_SESSION_ERROR, NULL, + upload_ctx->user_data); + return; + } } + + upload_ctx->callback(ZPERF_SESSION_FINISHED, &result, + upload_ctx->user_data); + zsock_close(sock); } int zperf_tcp_upload_async(const struct zperf_upload_params *param, diff --git a/subsys/net/lib/zperf/zperf_udp_uploader.c b/subsys/net/lib/zperf/zperf_udp_uploader.c index 548a0a55f10..daf2cf21d01 100644 --- a/subsys/net/lib/zperf/zperf_udp_uploader.c +++ b/subsys/net/lib/zperf/zperf_udp_uploader.c @@ -305,7 +305,7 @@ int zperf_udp_upload(const struct zperf_upload_params *param, } sock = zperf_prepare_upload_sock(¶m->peer_addr, param->options.tos, - param->options.priority, IPPROTO_UDP); + param->options.priority, 0, IPPROTO_UDP); if (sock < 0) { return sock; } diff --git a/subsys/pm/CMakeLists.txt b/subsys/pm/CMakeLists.txt index 1ddc7861a72..a9aba72caca 100644 --- a/subsys/pm/CMakeLists.txt +++ b/subsys/pm/CMakeLists.txt @@ -7,3 +7,4 @@ endif() zephyr_sources_ifdef(CONFIG_PM_DEVICE device.c) zephyr_sources_ifdef(CONFIG_PM_DEVICE_RUNTIME device_runtime.c) +zephyr_sources_ifdef(CONFIG_PM_DEVICE_SHELL pm_shell.c) diff --git a/subsys/pm/Kconfig b/subsys/pm/Kconfig index aeffe8c60ec..eda7569c917 100644 --- a/subsys/pm/Kconfig +++ b/subsys/pm/Kconfig @@ -37,6 +37,13 @@ config PM_S2RAM help This option enables suspend-to-RAM (S2RAM). +config PM_S2RAM_CUSTOM_MARKING + bool "Use custom marking functions" + depends on PM_S2RAM + help + By default a magic word in RAM is used to mark entering suspend-to-RAM. Enabling + this option allows custom implementation of functions which handles the marking. + config PM_NEED_ALL_DEVICES_IDLE bool "System Low Power Mode Needs All Devices Idle" depends on PM_DEVICE && !SMP @@ -122,6 +129,13 @@ config PM_DEVICE_RUNTIME_EXCLUSIVE On system suspend / resume do not trigger the Device PM hooks but only rely on Runtime PM to manage the devices power states. +config PM_DEVICE_SHELL + bool "Device Power Management shell" + depends on SHELL + help + Enable the device power management shell, for triggering device power + management events through the shell interface. + endif # PM_DEVICE endmenu diff --git a/subsys/pm/device_runtime.c b/subsys/pm/device_runtime.c index 533caddd503..d574f0356c9 100644 --- a/subsys/pm/device_runtime.c +++ b/subsys/pm/device_runtime.c @@ -422,6 +422,11 @@ int pm_device_runtime_enable(const struct device *dev) goto end; } + if (pm_device_is_busy(dev)) { + ret = -EBUSY; + goto end; + } + if (atomic_test_bit(&dev->pm_base->flags, PM_DEVICE_FLAG_ISR_SAFE)) { ret = runtime_enable_sync(dev); goto end; @@ -555,3 +560,28 @@ bool pm_device_runtime_is_enabled(const struct device *dev) return pm && atomic_test_bit(&pm->flags, PM_DEVICE_FLAG_RUNTIME_ENABLED); } + +int pm_device_runtime_usage(const struct device *dev) +{ + struct pm_device *pm = dev->pm; + uint32_t usage; + + if (!pm_device_runtime_is_enabled(dev)) { + return -ENOTSUP; + } + + if (atomic_test_bit(&dev->pm_base->flags, PM_DEVICE_FLAG_ISR_SAFE)) { + struct pm_device_isr *pm_sync = dev->pm_isr; + k_spinlock_key_t k = k_spin_lock(&pm_sync->lock); + + usage = pm_sync->base.usage; + + k_spin_unlock(&pm_sync->lock, k); + } else { + (void)k_sem_take(&pm->lock, K_FOREVER); + usage = pm->base.usage; + k_sem_give(&pm->lock); + } + + return usage; +} diff --git a/subsys/pm/pm.c b/subsys/pm/pm.c index d81072c3a5b..bb586073fcb 100644 --- a/subsys/pm/pm.c +++ b/subsys/pm/pm.c @@ -210,7 +210,8 @@ bool pm_system_suspend(int32_t ticks) } #endif - if (ticks != K_TICKS_FOREVER) { + if ((z_cpus_pm_state[id].exit_latency_us != 0) && + (ticks != K_TICKS_FOREVER)) { /* * We need to set the timer to interrupt a little bit early to * accommodate the time required by the CPU to fully wake up. diff --git a/subsys/pm/pm_shell.c b/subsys/pm/pm_shell.c new file mode 100644 index 00000000000..f656cf4426c --- /dev/null +++ b/subsys/pm/pm_shell.c @@ -0,0 +1,179 @@ +/* + * Copyright 2024 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +static bool pm_device_filter(const struct device *dev) +{ + return dev->pm != NULL; +} + +static void device_name_get(size_t idx, struct shell_static_entry *entry) +{ + const struct device *dev = shell_device_filter(idx, pm_device_filter); + + 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); + +static int pm_cmd_suspend(const struct shell *sh, size_t argc, char *argv[]) +{ + const struct device *dev; + int ret; + + dev = device_get_binding(argv[1]); + if (dev == NULL) { + shell_error(sh, "Invalid device: %s", argv[1]); + return -ENODEV; + } + + if (pm_device_runtime_is_enabled(dev)) { + shell_error(sh, "Device %s uses runtime PM, use the runtime functions instead", + dev->name); + return -EINVAL; + } + + ret = pm_device_action_run(dev, PM_DEVICE_ACTION_SUSPEND); + if (ret < 0) { + shell_error(sh, "Device %s error: %d", "suspend", ret); + return ret; + } + + return 0; +} + +static int pm_cmd_resume(const struct shell *sh, size_t argc, char *argv[]) +{ + const struct device *dev; + int ret; + + dev = device_get_binding(argv[1]); + if (dev == NULL) { + shell_error(sh, "Invalid device: %s", argv[1]); + return -ENODEV; + } + + if (pm_device_runtime_is_enabled(dev)) { + shell_error(sh, "Device %s uses runtime PM, use the runtime functions instead", + dev->name); + return -EINVAL; + } + + ret = pm_device_action_run(dev, PM_DEVICE_ACTION_RESUME); + if (ret < 0) { + shell_error(sh, "Device %s error: %d", "resume", ret); + return ret; + } + + return 0; +} + +#if defined(CONFIG_PM_DEVICE_RUNTIME) +static int pm_cmd_runtime_get(const struct shell *sh, size_t argc, char *argv[]) +{ + const struct device *dev; + int ret; + + dev = device_get_binding(argv[1]); + if (dev == NULL) { + shell_error(sh, "Invalid device: %s", argv[1]); + return -ENODEV; + } + + if (!pm_device_runtime_is_enabled(dev)) { + shell_error(sh, "Device %s is not using runtime PM", dev->name); + return -EINVAL; + } + + ret = pm_device_runtime_get(dev); + if (ret < 0) { + shell_error(sh, "Device %s error: %d", "runtime get", ret); + return ret; + } + + return 0; +} + +static int pm_cmd_runtime_put(const struct shell *sh, size_t argc, char *argv[]) +{ + const struct device *dev; + int ret; + + dev = device_get_binding(argv[1]); + if (dev == NULL) { + shell_error(sh, "Invalid device: %s", argv[1]); + return -ENODEV; + } + + if (!pm_device_runtime_is_enabled(dev)) { + shell_error(sh, "Device %s is not using runtime PM", dev->name); + return -EINVAL; + } + + ret = pm_device_runtime_put(dev); + if (ret < 0) { + shell_error(sh, "Device %s error: %d", "runtime put", ret); + return ret; + } + + return 0; +} + +static int pm_cmd_runtime_put_async(const struct shell *sh, size_t argc, char *argv[]) +{ + const struct device *dev; + int ret; + + dev = device_get_binding(argv[1]); + if (dev == NULL) { + shell_error(sh, "Invalid device: %s", argv[1]); + return -ENODEV; + } + + if (!pm_device_runtime_is_enabled(dev)) { + shell_error(sh, "Device %s is not using runtime PM", dev->name); + return -EINVAL; + } + + ret = pm_device_runtime_put_async(dev, K_NO_WAIT); + if (ret < 0) { + shell_error(sh, "Device %s error: %d", "runtime put async", ret); + return ret; + } + + return 0; +} +#endif /* CONFIG_PM_DEVICE_RUNTIME */ + +SHELL_STATIC_SUBCMD_SET_CREATE( + sub_pm_cmds, + SHELL_CMD_ARG(suspend, &dsub_device_name, + "Call the PM suspend action on a device", + pm_cmd_suspend, 2, 0), + SHELL_CMD_ARG(resume, &dsub_device_name, + "Call the PM resume action on a device", + pm_cmd_resume, 2, 0), +#if defined(CONFIG_PM_DEVICE_RUNTIME) + SHELL_CMD_ARG(runtime-get, &dsub_device_name, + "Call the PM runtime get on a device", + pm_cmd_runtime_get, 2, 0), + SHELL_CMD_ARG(runtime-put, &dsub_device_name, + "Call the PM runtime put on a device", + pm_cmd_runtime_put, 2, 0), + SHELL_CMD_ARG(runtime-put-async, &dsub_device_name, + "Call the PM runtime put async on a device", + pm_cmd_runtime_put_async, 2, 0), +#endif /* CONFIG_PM_DEVICE_RUNTIME */ + SHELL_SUBCMD_SET_END); + +SHELL_CMD_REGISTER(pm, &sub_pm_cmds, "PM commands", NULL); diff --git a/subsys/pm/policy.c b/subsys/pm/policy.c index fa44a7069f7..9b5570136bc 100644 --- a/subsys/pm/policy.c +++ b/subsys/pm/policy.c @@ -113,7 +113,7 @@ static void update_next_event(uint32_t cyc) * the comparison. */ if (cyc_evt < cyc) { - cyc_evt += UINT32_MAX + 1U; + cyc_evt += (uint64_t)UINT32_MAX + 1U; } if ((new_next_event_cyc < 0) || @@ -124,7 +124,7 @@ static void update_next_event(uint32_t cyc) /* undo padding for events in the [0, cyc) range */ if (new_next_event_cyc > UINT32_MAX) { - new_next_event_cyc -= UINT32_MAX + 1U; + new_next_event_cyc -= (uint64_t)UINT32_MAX + 1U; } next_event_cyc = new_next_event_cyc; diff --git a/subsys/sd/sd_ops.c b/subsys/sd/sd_ops.c index 7d4ebf11dd3..54f5b1a360f 100644 --- a/subsys/sd/sd_ops.c +++ b/subsys/sd/sd_ops.c @@ -1,5 +1,5 @@ /* - * Copyright 2022 NXP + * Copyright 2022,2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -535,7 +535,6 @@ static int card_read(struct sd_card *card, uint8_t *rbuf, uint32_t start_block, ret = sdmmc_wait_ready(card); if (ret) { LOG_ERR("Card did not return to ready state"); - k_mutex_unlock(&card->lock); return -ETIMEDOUT; } return 0; @@ -774,6 +773,13 @@ int card_write_blocks(struct sd_card *card, const uint8_t *wbuf, uint32_t start_ /* IO Control handler for SD MMC */ int card_ioctl(struct sd_card *card, uint8_t cmd, void *buf) { + int ret; + + ret = k_mutex_lock(&card->lock, K_MSEC(CONFIG_SD_DATA_TIMEOUT)); + if (ret) { + LOG_WRN("Could not get SD card mutex"); + return ret; + } switch (cmd) { case DISK_IOCTL_GET_SECTOR_COUNT: (*(uint32_t *)buf) = card->block_count; @@ -787,9 +793,10 @@ int card_ioctl(struct sd_card *card, uint8_t cmd, void *buf) * Note that SD stack does not support enabling caching, so * cache flush is not required here */ - return sdmmc_wait_ready(card); + ret = sdmmc_wait_ready(card); default: - return -ENOTSUP; + ret = -ENOTSUP; } - return 0; + k_mutex_unlock(&card->lock); + return ret; } diff --git a/subsys/sd/sdio.c b/subsys/sd/sdio.c index 64c813b1090..a81403c5f82 100644 --- a/subsys/sd/sdio.c +++ b/subsys/sd/sdio.c @@ -450,23 +450,23 @@ static int sdio_set_bus_width(struct sd_card *card, enum sdhc_bus_width width) static inline void sdio_select_bus_speed(struct sd_card *card) { if (card->host_props.host_caps.sdr104_support && - (card->cccr_flags & SDIO_SUPPORT_SDR104) && - (card->host_props.f_max >= SD_CLOCK_208MHZ)) { + (card->cccr_flags & SDIO_SUPPORT_SDR104)) { card->card_speed = SD_TIMING_SDR104; + card->switch_caps.uhs_max_dtr = UHS_SDR104_MAX_DTR; } else if (card->host_props.host_caps.ddr50_support && - (card->cccr_flags & SDIO_SUPPORT_DDR50) && - (card->host_props.f_max >= SD_CLOCK_50MHZ)) { + (card->cccr_flags & SDIO_SUPPORT_DDR50)) { card->card_speed = SD_TIMING_DDR50; + card->switch_caps.uhs_max_dtr = UHS_DDR50_MAX_DTR; } else if (card->host_props.host_caps.sdr50_support && - (card->cccr_flags & SDIO_SUPPORT_SDR50) && - (card->host_props.f_max >= SD_CLOCK_100MHZ)) { + (card->cccr_flags & SDIO_SUPPORT_SDR50)) { card->card_speed = SD_TIMING_SDR50; + card->switch_caps.uhs_max_dtr = UHS_SDR50_MAX_DTR; } else if (card->host_props.host_caps.high_spd_support && - (card->switch_caps.bus_speed & SDIO_SUPPORT_HS) && - (card->host_props.f_max >= SD_CLOCK_50MHZ)) { - card->card_speed = SD_TIMING_SDR25; + (card->cccr_flags & SDIO_SUPPORT_HS)) { + card->card_speed = SD_TIMING_HIGH_SPEED; + card->switch_caps.hs_max_dtr = HS_MAX_DTR; } else { - card->card_speed = SD_TIMING_SDR12; + card->card_speed = SD_TIMING_DEFAULT; } } @@ -474,34 +474,35 @@ static inline void sdio_select_bus_speed(struct sd_card *card) static int sdio_set_bus_speed(struct sd_card *card) { int ret, timing, retries = CONFIG_SD_RETRY_COUNT; + uint32_t bus_clock; uint8_t speed_reg, target_speed; switch (card->card_speed) { /* Set bus clock speed */ case SD_TIMING_SDR104: - card->switch_caps.uhs_max_dtr = SD_CLOCK_208MHZ; + bus_clock = MIN(card->host_props.f_max, card->switch_caps.uhs_max_dtr); target_speed = SDIO_CCCR_SPEED_SDR104; timing = SDHC_TIMING_SDR104; break; case SD_TIMING_DDR50: - card->switch_caps.uhs_max_dtr = SD_CLOCK_50MHZ; + bus_clock = MIN(card->host_props.f_max, card->switch_caps.uhs_max_dtr); target_speed = SDIO_CCCR_SPEED_DDR50; timing = SDHC_TIMING_DDR50; break; case SD_TIMING_SDR50: - card->switch_caps.uhs_max_dtr = SD_CLOCK_100MHZ; + bus_clock = MIN(card->host_props.f_max, card->switch_caps.uhs_max_dtr); target_speed = SDIO_CCCR_SPEED_SDR50; timing = SDHC_TIMING_SDR50; break; - case SD_TIMING_SDR25: - card->switch_caps.uhs_max_dtr = SD_CLOCK_50MHZ; + case SD_TIMING_HIGH_SPEED: + bus_clock = MIN(card->host_props.f_max, card->switch_caps.hs_max_dtr); target_speed = SDIO_CCCR_SPEED_SDR25; - timing = SDHC_TIMING_SDR25; + timing = SDHC_TIMING_HS; break; - case SD_TIMING_SDR12: - card->switch_caps.uhs_max_dtr = SD_CLOCK_25MHZ; + case SD_TIMING_DEFAULT: + bus_clock = MIN(card->host_props.f_max, MHZ(25)); target_speed = SDIO_CCCR_SPEED_SDR12; - timing = SDHC_TIMING_SDR12; + timing = SDHC_TIMING_LEGACY; break; default: /* No need to change bus speed */ @@ -530,7 +531,7 @@ static int sdio_set_bus_speed(struct sd_card *card) } else { /* Set card bus clock and timing */ card->bus_io.timing = timing; - card->bus_io.clock = card->switch_caps.uhs_max_dtr; + card->bus_io.clock = bus_clock; LOG_DBG("Setting bus clock to: %d", card->bus_io.clock); ret = sdhc_set_io(card->sdhc, &card->bus_io); if (ret) { diff --git a/subsys/sd/sdmmc.c b/subsys/sd/sdmmc.c index 5b9854cc95b..ed7acaf439b 100644 --- a/subsys/sd/sdmmc.c +++ b/subsys/sd/sdmmc.c @@ -332,8 +332,25 @@ static int sdmmc_read_switch(struct sd_card *card) * Bit n being set in support bit field indicates support for function * number n on the card. (So 0x3 indicates support for functions 0 and 1) */ + /* Determine HS speed support, if any */ if (status[13] & HIGH_SPEED_BUS_SPEED) { card->switch_caps.hs_max_dtr = HS_MAX_DTR; + } else { + card->switch_caps.hs_max_dtr = HS_UNSUPPORTED; + } + /* Determine UHS speed support, if any */ + if (status[13] & UHS_SDR104_BUS_SPEED) { + card->switch_caps.uhs_max_dtr = UHS_SDR104_MAX_DTR; + } else if (status[13] & UHS_DDR50_BUS_SPEED) { + card->switch_caps.uhs_max_dtr = UHS_DDR50_MAX_DTR; + } else if (status[13] & UHS_SDR50_BUS_SPEED) { + card->switch_caps.uhs_max_dtr = UHS_SDR50_MAX_DTR; + } else if (status[13] & UHS_SDR25_BUS_SPEED) { + card->switch_caps.uhs_max_dtr = UHS_SDR25_MAX_DTR; + } else if (status[13] & UHS_SDR12_BUS_SPEED) { + card->switch_caps.uhs_max_dtr = UHS_SDR12_MAX_DTR; + } else { + card->switch_caps.uhs_max_dtr = UHS_UNSUPPORTED; } if (card->sd_version >= SD_SPEC_VER3_0) { card->switch_caps.bus_speed = status[13]; @@ -349,22 +366,31 @@ static inline void sdmmc_select_bus_speed(struct sd_card *card) * Note that function support is defined using bitfields, but function * selection is defined using values 0x0-0xF. */ - if (card->host_props.host_caps.sdr104_support && - (card->switch_caps.bus_speed & UHS_SDR104_BUS_SPEED) && - (card->host_props.f_max >= SD_CLOCK_208MHZ)) { - card->card_speed = SD_TIMING_SDR104; - } else if (card->host_props.host_caps.ddr50_support && - (card->switch_caps.bus_speed & UHS_DDR50_BUS_SPEED) && - (card->host_props.f_max >= SD_CLOCK_50MHZ)) { - card->card_speed = SD_TIMING_DDR50; - } else if (card->host_props.host_caps.sdr50_support && - (card->switch_caps.bus_speed & UHS_SDR50_BUS_SPEED) && - (card->host_props.f_max >= SD_CLOCK_100MHZ)) { - card->card_speed = SD_TIMING_SDR50; - } else if (card->host_props.host_caps.high_spd_support && - (card->switch_caps.bus_speed & UHS_SDR12_BUS_SPEED) && - (card->host_props.f_max >= SD_CLOCK_25MHZ)) { - card->card_speed = SD_TIMING_SDR12; + if ((card->flags & SD_1800MV_FLAG) && sdmmc_host_uhs(&card->host_props) && + !(card->host_props.is_spi) && IS_ENABLED(CONFIG_SD_UHS_PROTOCOL)) { + /* Select UHS mode timing */ + if (card->host_props.host_caps.sdr104_support && + (card->switch_caps.bus_speed & UHS_SDR104_BUS_SPEED)) { + card->card_speed = SD_TIMING_SDR104; + } else if (card->host_props.host_caps.ddr50_support && + (card->switch_caps.bus_speed & UHS_DDR50_BUS_SPEED)) { + card->card_speed = SD_TIMING_DDR50; + } else if (card->host_props.host_caps.sdr50_support && + (card->switch_caps.bus_speed & UHS_SDR50_BUS_SPEED)) { + card->card_speed = SD_TIMING_SDR50; + } else if (card->switch_caps.bus_speed & UHS_SDR12_BUS_SPEED) { + card->card_speed = SD_TIMING_SDR25; + } else { + card->card_speed = SD_TIMING_SDR12; + } + } else { + /* Select HS mode timing */ + if (card->host_props.host_caps.high_spd_support && + (card->switch_caps.bus_speed & HIGH_SPEED_BUS_SPEED)) { + card->card_speed = SD_TIMING_HIGH_SPEED; + } else { + card->card_speed = SD_TIMING_DEFAULT; + } } } @@ -432,34 +458,52 @@ static int sdmmc_set_current_limit(struct sd_card *card) static int sdmmc_set_bus_speed(struct sd_card *card) { int ret; - int timing = 0; uint8_t *status = card->card_buffer; + enum sdhc_timing_mode timing; + uint32_t card_clock; - switch (card->card_speed) { - /* Set bus clock speed */ - case SD_TIMING_SDR104: - card->switch_caps.uhs_max_dtr = SD_CLOCK_208MHZ; - timing = SDHC_TIMING_SDR104; - break; - case SD_TIMING_DDR50: - card->switch_caps.uhs_max_dtr = SD_CLOCK_50MHZ; - timing = SDHC_TIMING_DDR50; - break; - case SD_TIMING_SDR50: - card->switch_caps.uhs_max_dtr = SD_CLOCK_100MHZ; - timing = SDHC_TIMING_SDR50; - break; - case SD_TIMING_SDR25: - card->switch_caps.uhs_max_dtr = SD_CLOCK_50MHZ; - timing = SDHC_TIMING_SDR25; - break; - case SD_TIMING_SDR12: - card->switch_caps.uhs_max_dtr = SD_CLOCK_25MHZ; - timing = SDHC_TIMING_SDR12; - break; - default: - /* No need to change bus speed */ - return 0; + /* Set card clock and host timing. Since the card's maximum clock + * was calculated within sdmmc_read_switch(), we can safely use the + * minimum between that clock and the host's highest clock supported. + */ + if ((card->flags & SD_1800MV_FLAG) && sdmmc_host_uhs(&card->host_props) && + !(card->host_props.is_spi) && IS_ENABLED(CONFIG_SD_UHS_PROTOCOL)) { + /* UHS mode */ + card_clock = MIN(card->host_props.f_max, card->switch_caps.uhs_max_dtr); + switch (card->card_speed) { + case SD_TIMING_SDR104: + timing = SDHC_TIMING_SDR104; + break; + case SD_TIMING_DDR50: + timing = SDHC_TIMING_DDR50; + break; + case SD_TIMING_SDR50: + timing = SDHC_TIMING_SDR50; + break; + case SD_TIMING_SDR25: + timing = SDHC_TIMING_SDR25; + break; + case SD_TIMING_SDR12: + timing = SDHC_TIMING_SDR12; + break; + default: + /* No need to change bus speed */ + return 0; + } + } else { + /* High speed/default mode */ + card_clock = MIN(card->host_props.f_max, card->switch_caps.hs_max_dtr); + switch (card->card_speed) { + case SD_TIMING_HIGH_SPEED: + timing = SDHC_TIMING_HS; + break; + case SD_TIMING_DEFAULT: + timing = SDHC_TIMING_LEGACY; + break; + default: + /* No need to change bus speed */ + return 0; + } } /* Switch bus speed */ @@ -473,7 +517,7 @@ static int sdmmc_set_bus_speed(struct sd_card *card) } else { /* Change host bus speed */ card->bus_io.timing = timing; - card->bus_io.clock = card->switch_caps.uhs_max_dtr; + card->bus_io.clock = card_clock; LOG_DBG("Setting bus clock to: %d", card->bus_io.clock); ret = sdhc_set_io(card->sdhc, &card->bus_io); if (ret) { @@ -533,12 +577,15 @@ static int sdmmc_init_hs(struct sd_card *card) { int ret; - if ((!card->host_props.host_caps.high_spd_support) || (card->sd_version < SD_SPEC_VER1_1) || - (card->switch_caps.hs_max_dtr == 0)) { + if ((!card->host_props.host_caps.high_spd_support) || + (card->sd_version < SD_SPEC_VER1_1) || + (card->switch_caps.hs_max_dtr == HS_UNSUPPORTED)) { /* No high speed support. Leave card untouched */ return 0; } - card->card_speed = SD_TIMING_SDR25; + /* Select bus speed for card depending on host and card capability*/ + sdmmc_select_bus_speed(card); + /* Apply selected bus speed */ ret = sdmmc_set_bus_speed(card); if (ret) { LOG_ERR("Failed to switch card to HS mode"); diff --git a/subsys/settings/src/settings_store.c b/subsys/settings/src/settings_store.c index d47b24f064b..b697f993d94 100644 --- a/subsys/settings/src/settings_store.c +++ b/subsys/settings/src/settings_store.c @@ -116,6 +116,11 @@ int settings_delete(const char *name) } int settings_save(void) +{ + return settings_save_subtree(NULL); +} + +int settings_save_subtree(const char *subtree) { struct settings_store *cs; int rc; @@ -132,6 +137,9 @@ int settings_save(void) rc = 0; STRUCT_SECTION_FOREACH(settings_handler_static, ch) { + if (subtree && !settings_name_steq(ch->name, subtree, NULL)) { + continue; + } if (ch->h_export) { rc2 = ch->h_export(settings_save_one); if (!rc) { @@ -143,6 +151,9 @@ int settings_save(void) #if defined(CONFIG_SETTINGS_DYNAMIC_HANDLERS) struct settings_handler *ch; SYS_SLIST_FOR_EACH_CONTAINER(&settings_handlers, ch, node) { + if (subtree && !settings_name_steq(ch->name, subtree, NULL)) { + continue; + } if (ch->h_export) { rc2 = ch->h_export(settings_save_one); if (!rc) { diff --git a/subsys/shell/Kconfig b/subsys/shell/Kconfig index 5921a56bb49..c9907839959 100644 --- a/subsys/shell/Kconfig +++ b/subsys/shell/Kconfig @@ -297,6 +297,14 @@ config SHELL_CMDS_RETURN_VALUE This option enables the retval command. It is used to retrieve the return value from the most recently executed command. +config SHELL_CUSTOM_HEADER + bool "Include Custom Shell Header" + help + When enabled, a custom application provided header, named + "zephyr_custom_shell.h", is included at the end of shell.h. This enables + extension of the shell APIs at the macro level. Please use cautiously! + The internal shell API may change in future releases. + source "subsys/shell/modules/Kconfig" endif # SHELL diff --git a/subsys/shell/backends/Kconfig.backends b/subsys/shell/backends/Kconfig.backends index a78c9247365..e1924872361 100644 --- a/subsys/shell/backends/Kconfig.backends +++ b/subsys/shell/backends/Kconfig.backends @@ -28,8 +28,7 @@ if SHELL_BACKEND_SERIAL config SHELL_BACKEND_SERIAL_INIT_PRIORITY int "Initialization priority" - default 55 if ACPI - default 0 + default APPLICATION_INIT_PRIORITY range 0 99 help Initialization priority for UART backend. This must be bigger than diff --git a/subsys/shell/modules/device_service.c b/subsys/shell/modules/device_service.c index fec4b25f6b9..f702651cfd4 100644 --- a/subsys/shell/modules/device_service.c +++ b/subsys/shell/modules/device_service.c @@ -64,6 +64,7 @@ static int cmd_device_list(const struct shell *sh, char buf[20]; const char *name = get_device_name(dev, buf, sizeof(buf)); const char *state = "READY"; + int usage; shell_fprintf(sh, SHELL_NORMAL, "- %s", name); if (!device_is_ready(dev)) { @@ -79,7 +80,13 @@ static int cmd_device_list(const struct shell *sh, #endif /* CONFIG_PM_DEVICE */ } - shell_fprintf(sh, SHELL_NORMAL, " (%s)\n", state); + usage = pm_device_runtime_usage(dev); + if (usage >= 0) { + shell_fprintf(sh, SHELL_NORMAL, " (%s, usage=%d)\n", state, usage); + } else { + shell_fprintf(sh, SHELL_NORMAL, " (%s)\n", state); + } + #ifdef CONFIG_DEVICE_DEPS if (!k_is_user_context()) { struct cmd_device_list_visitor_context ctx = { diff --git a/subsys/shell/modules/devmem_service.c b/subsys/shell/modules/devmem_service.c index e5a7a06f35b..8b649e8093b 100644 --- a/subsys/shell/modules/devmem_service.c +++ b/subsys/shell/modules/devmem_service.c @@ -19,6 +19,10 @@ #include #include +#ifndef CONFIG_NATIVE_LIBC +extern void getopt_init(void); +#endif + static inline bool is_ascii(uint8_t data) { return (data >= 0x30 && data <= 0x39) || (data >= 0x61 && data <= 0x66) || @@ -101,6 +105,9 @@ static int cmd_dump(const struct shell *sh, size_t argc, char **argv) mem_addr_t addr = -1; optind = 1; +#ifndef CONFIG_NATIVE_LIBC + getopt_init(); +#endif while ((rv = getopt(argc, argv, "a:s:w:")) != -1) { switch (rv) { case 'a': @@ -349,7 +356,7 @@ SHELL_STATIC_SUBCMD_SET_CREATE(sub_devmem, SHELL_CMD_ARG(dump, NULL, "Usage:\n" "devmem dump -a
-s [-w ]\n", - cmd_dump, 4, 6), + cmd_dump, 5, 2), SHELL_CMD_ARG(load, NULL, "Usage:\n" "devmem load [options] [address]\n" diff --git a/subsys/shell/shell.c b/subsys/shell/shell.c index 1bd8de70d02..29f9d856d5f 100644 --- a/subsys/shell/shell.c +++ b/subsys/shell/shell.c @@ -1548,7 +1548,7 @@ void shell_vfprintf(const struct shell *sh, enum shell_vt100_color color, /* This function mustn't be used from shell context to avoid deadlock. * However it can be used in shell command handlers. */ -void shell_fprintf(const struct shell *sh, enum shell_vt100_color color, +void shell_fprintf_impl(const struct shell *sh, enum shell_vt100_color color, const char *fmt, ...) { va_list args; diff --git a/subsys/shell/shell_utils.c b/subsys/shell/shell_utils.c index bd7523e4705..00d3315d0ce 100644 --- a/subsys/shell/shell_utils.c +++ b/subsys/shell/shell_utils.c @@ -496,8 +496,9 @@ void z_shell_cmd_trim(const struct shell *sh) sh->ctx->cmd_buff_pos = sh->ctx->cmd_buff_len; } -const struct device *shell_device_lookup(size_t idx, - const char *prefix) +static const struct device *shell_device_internal(size_t idx, + const char *prefix, + shell_device_filter_t filter) { size_t match_idx = 0; const struct device *dev; @@ -510,7 +511,8 @@ const struct device *shell_device_lookup(size_t idx, && (strlen(dev->name) != 0) && ((prefix == NULL) || (strncmp(prefix, dev->name, - strlen(prefix)) == 0))) { + strlen(prefix)) == 0)) + && (filter == NULL || filter(dev))) { if (match_idx == idx) { return dev; } @@ -522,6 +524,18 @@ const struct device *shell_device_lookup(size_t idx, return NULL; } +const struct device *shell_device_filter(size_t idx, + shell_device_filter_t filter) +{ + return shell_device_internal(idx, NULL, filter); +} + +const struct device *shell_device_lookup(size_t idx, + const char *prefix) +{ + return shell_device_internal(idx, prefix, NULL); +} + long shell_strtol(const char *str, int base, int *err) { long val; diff --git a/subsys/sip_svc/sip_svc_data.ld b/subsys/sip_svc/sip_svc_data.ld index 02516ee1e52..3b993d0c8e0 100644 --- a/subsys/sip_svc/sip_svc_data.ld +++ b/subsys/sip_svc/sip_svc_data.ld @@ -1,3 +1,3 @@ #include -ITERABLE_SECTION_RAM(sip_svc_controller, 4) +ITERABLE_SECTION_RAM(sip_svc_controller, Z_LINK_ITERABLE_SUBALIGN) diff --git a/subsys/testsuite/boards/unit_testing/unit_testing/Kconfig.defconfig b/subsys/testsuite/boards/unit_testing/unit_testing/Kconfig.defconfig index 939f1c97e71..38c6d4b3019 100644 --- a/subsys/testsuite/boards/unit_testing/unit_testing/Kconfig.defconfig +++ b/subsys/testsuite/boards/unit_testing/unit_testing/Kconfig.defconfig @@ -6,3 +6,8 @@ choice BT_HCI_BUS_TYPE default BT_NO_DRIVER endchoice + +# Controller HCI support requires e.g. devicetree, which isn't available +# for unit tests. +config BT_CTLR_HCI + default n diff --git a/subsys/testsuite/include/zephyr/interrupt_util.h b/subsys/testsuite/include/zephyr/interrupt_util.h index 0bccd53cc51..a3653618d97 100644 --- a/subsys/testsuite/include/zephyr/interrupt_util.h +++ b/subsys/testsuite/include/zephyr/interrupt_util.h @@ -166,7 +166,7 @@ static inline void trigger_irq(int irq) } #elif defined(CONFIG_RISCV) -#if defined(CONFIG_NUCLEI_ECLIC) +#if defined(CONFIG_NUCLEI_ECLIC) || defined(CONFIG_NRFX_CLIC) void riscv_clic_irq_set_pending(uint32_t irq); static inline void trigger_irq(int irq) { diff --git a/subsys/testsuite/ztest/include/zephyr/offsets.h b/subsys/testsuite/ztest/include/zephyr/offsets.h deleted file mode 100644 index 7c7c8ee57a6..00000000000 --- a/subsys/testsuite/ztest/include/zephyr/offsets.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ -#ifndef __GEN_OFFSETS_H__ -#define __GEN_OFFSETS_H__ - -/* - * This file is a fake replacement for - * $build_dir/zephyr/include/generated/offsets.h - * - * The unittest infrastructure does not know how to generate - * offsets.h, so until this is supported we fake it with this - * file. This allows us to test source files that include offsets.h, - * but don't actually use anything from it when unit testing. - */ - -#endif diff --git a/subsys/testsuite/ztest/include/zephyr/syscall_list.h b/subsys/testsuite/ztest/include/zephyr/syscall_list.h deleted file mode 100644 index 1cfdde31e13..00000000000 --- a/subsys/testsuite/ztest/include/zephyr/syscall_list.h +++ /dev/null @@ -1,3 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ diff --git a/subsys/testsuite/ztest/include/zephyr/syscall_macros.h b/subsys/testsuite/ztest/include/zephyr/syscall_macros.h deleted file mode 100644 index 1cfdde31e13..00000000000 --- a/subsys/testsuite/ztest/include/zephyr/syscall_macros.h +++ /dev/null @@ -1,3 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ diff --git a/subsys/testsuite/ztest/include/zephyr/syscalls/kernel.h b/subsys/testsuite/ztest/include/zephyr/syscalls/kernel.h deleted file mode 100644 index 1cfdde31e13..00000000000 --- a/subsys/testsuite/ztest/include/zephyr/syscalls/kernel.h +++ /dev/null @@ -1,3 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ diff --git a/subsys/testsuite/ztest/include/zephyr/syscalls/kobject.h b/subsys/testsuite/ztest/include/zephyr/syscalls/kobject.h deleted file mode 100644 index 49281301178..00000000000 --- a/subsys/testsuite/ztest/include/zephyr/syscalls/kobject.h +++ /dev/null @@ -1,5 +0,0 @@ -/* - * Copyright (c) 2020 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ diff --git a/subsys/testsuite/ztest/include/zephyr/syscalls/log_core.h b/subsys/testsuite/ztest/include/zephyr/syscalls/log_core.h deleted file mode 100644 index ff9e44d289f..00000000000 --- a/subsys/testsuite/ztest/include/zephyr/syscalls/log_core.h +++ /dev/null @@ -1,5 +0,0 @@ -/* - * Copyright (c) 2019 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ diff --git a/subsys/testsuite/ztest/include/zephyr/syscalls/log_ctrl.h b/subsys/testsuite/ztest/include/zephyr/syscalls/log_ctrl.h deleted file mode 100644 index ff9e44d289f..00000000000 --- a/subsys/testsuite/ztest/include/zephyr/syscalls/log_ctrl.h +++ /dev/null @@ -1,5 +0,0 @@ -/* - * Copyright (c) 2019 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ diff --git a/subsys/testsuite/ztest/include/zephyr/syscalls/log_msg.h b/subsys/testsuite/ztest/include/zephyr/syscalls/log_msg.h deleted file mode 100644 index bb6a719084b..00000000000 --- a/subsys/testsuite/ztest/include/zephyr/syscalls/log_msg.h +++ /dev/null @@ -1,5 +0,0 @@ -/* - * Copyright (c) 2021 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ diff --git a/subsys/testsuite/ztest/include/zephyr/syscalls/sys_clock.h b/subsys/testsuite/ztest/include/zephyr/syscalls/sys_clock.h deleted file mode 100644 index 1cfdde31e13..00000000000 --- a/subsys/testsuite/ztest/include/zephyr/syscalls/sys_clock.h +++ /dev/null @@ -1,3 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ diff --git a/subsys/testsuite/ztest/include/zephyr/ztress.h b/subsys/testsuite/ztest/include/zephyr/ztress.h index ce349d480d4..63c17dfc564 100644 --- a/subsys/testsuite/ztest/include/zephyr/ztress.h +++ b/subsys/testsuite/ztest/include/zephyr/ztress.h @@ -154,7 +154,7 @@ struct ztress_context_data { #define Z_ZTRESS_TIMER_IDX(idx, data) \ ((GET_ARG_N(1, __DEBRACKET data)) == ZTRESS_ID_K_TIMER ? idx : 0) -/** @intenal Macro validates that @ref ZTRESS_TIMER context is not used except for +/** @internal Macro validates that @ref ZTRESS_TIMER context is not used except for * the first item in the list of contexts. */ #define Z_ZTRESS_TIMER_CONTEXT_VALIDATE(...) \ diff --git a/subsys/testsuite/ztest/include/zephyr/arch/cpu.h b/subsys/testsuite/ztest/unittest/include/zephyr/arch/cpu.h similarity index 100% rename from subsys/testsuite/ztest/include/zephyr/arch/cpu.h rename to subsys/testsuite/ztest/unittest/include/zephyr/arch/cpu.h diff --git a/subsys/tracing/tracing_backend_ram.c b/subsys/tracing/tracing_backend_ram.c index 2f8219784ec..20cd06706eb 100644 --- a/subsys/tracing/tracing_backend_ram.c +++ b/subsys/tracing/tracing_backend_ram.c @@ -35,6 +35,8 @@ static void tracing_backend_ram_output( static void tracing_backend_ram_init(void) { memset(ram_tracing, 0, CONFIG_RAM_TRACING_BUFFER_SIZE); + pos = 0; + buffer_full = false; } const struct tracing_backend_api tracing_backend_ram_api = { diff --git a/subsys/usb/device/bos.c b/subsys/usb/device/bos.c index 57abfff9cac..4b7feb22513 100644 --- a/subsys/usb/device/bos.c +++ b/subsys/usb/device/bos.c @@ -7,15 +7,18 @@ #include LOG_MODULE_REGISTER(usb_bos, CONFIG_USB_DEVICE_LOG_LEVEL); -#include +#include +#include #include - #include extern const uint8_t __usb_bos_desc_start[]; extern const uint8_t __usb_bos_desc_end[]; +#define USB_DEVICE_BOS_DESC_DEFINE_HDR \ + static __in_section(usb, bos_desc_area, 0) __aligned(1) __used + USB_DEVICE_BOS_DESC_DEFINE_HDR struct usb_bos_descriptor bos_hdr = { .bLength = sizeof(struct usb_bos_descriptor), .bDescriptorType = USB_DESC_BOS, @@ -38,8 +41,10 @@ void usb_bos_fix_total_length(void) bos_hdr.wTotalLength = usb_bos_get_length(); } -void usb_bos_register_cap(struct usb_bos_platform_descriptor *desc) +void usb_bos_register_cap(void *desc) { + ARG_UNUSED(desc); + /* Has effect only on first register */ bos_hdr.wTotalLength = usb_bos_get_length(); diff --git a/subsys/usb/device/bos_desc.h b/subsys/usb/device/bos_desc.h new file mode 100644 index 00000000000..711b1a78ebd --- /dev/null +++ b/subsys/usb/device/bos_desc.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2018 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_USB_DEVICE_BOS_DESC_H_ +#define ZEPHYR_INCLUDE_USB_DEVICE_BOS_DESC_H_ + +#include +#include + +size_t usb_bos_get_length(void); + +void usb_bos_fix_total_length(void); + +const void *usb_bos_get_header(void); + +#if defined(CONFIG_USB_DEVICE_BOS) +int usb_handle_bos(struct usb_setup_packet *setup, int32_t *len, uint8_t **data); +#else +#define usb_handle_bos(x, y, z) -ENOTSUP +#endif + +#endif /* ZEPHYR_INCLUDE_USB_DEVICE_BOS_DESC_H_ */ diff --git a/subsys/usb/device/usb_descriptor.c b/subsys/usb/device/usb_descriptor.c index 7c2ac37d94a..325989dc7fd 100644 --- a/subsys/usb/device/usb_descriptor.c +++ b/subsys/usb/device/usb_descriptor.c @@ -56,7 +56,7 @@ USBD_DEVICE_DESCR_DEFINE(primary) struct common_descriptor common_desc = { .bLength = sizeof(struct usb_device_descriptor), .bDescriptorType = USB_DESC_DEVICE, #ifdef CONFIG_USB_DEVICE_BOS - .bcdUSB = sys_cpu_to_le16(USB_SRN_2_1), + .bcdUSB = sys_cpu_to_le16(USB_SRN_2_0_1), #else .bcdUSB = sys_cpu_to_le16(USB_SRN_2_0), #endif @@ -505,12 +505,18 @@ static int usb_fix_descriptor(struct usb_desc_header *head) uint8_t *usb_get_device_descriptor(void) { + static bool initialized; + LOG_DBG("__usb_descriptor_start %p", __usb_descriptor_start); LOG_DBG("__usb_descriptor_end %p", __usb_descriptor_end); - if (usb_fix_descriptor(__usb_descriptor_start)) { - LOG_ERR("Failed to fixup USB descriptor"); - return NULL; + if (!initialized) { + if (usb_fix_descriptor(__usb_descriptor_start)) { + LOG_ERR("Failed to fixup USB descriptor"); + return NULL; + } + + initialized = true; } return (uint8_t *) __usb_descriptor_start; diff --git a/subsys/usb/device/usb_device.c b/subsys/usb/device/usb_device.c index aeb4df1a3f0..a3670a16804 100644 --- a/subsys/usb/device/usb_device.c +++ b/subsys/usb/device/usb_device.c @@ -59,6 +59,7 @@ #include #include +#include #include #include #include @@ -1595,7 +1596,7 @@ int usb_enable(usb_dc_status_callback status_cb) { int ret; struct usb_dc_ep_cfg_data ep0_cfg; - struct usb_device_descriptor *dev_desc = (void *)usb_dev.descriptors; + struct usb_device_descriptor *dev_desc; /* Prevent from calling usb_enable form different context. * This should only be called once. @@ -1609,12 +1610,27 @@ int usb_enable(usb_dc_status_callback status_cb) goto out; } + /* + * If usb_dev.descriptors is equal to NULL (usb_dev has static + * specifier), then usb_get_device_descriptor() and usb_set_config() + * are likely not called yet. If so, set the configuration here. + */ + if (usb_dev.descriptors == NULL) { + usb_set_config(usb_get_device_descriptor()); + if (usb_dev.descriptors == NULL) { + LOG_ERR("Failed to configure USB device stack"); + ret = -1; + goto out; + } + } + /* Enable VBUS if needed */ ret = usb_vbus_set(true); if (ret < 0) { goto out; } + dev_desc = (void *)usb_dev.descriptors; usb_dev.user_status_callback = status_cb; usb_register_status_callback(forward_status_cb); usb_dc_set_status_callback(forward_status_cb); @@ -1693,32 +1709,11 @@ int usb_enable(usb_dc_status_callback status_cb) return ret; } -/* - * This function configures the USB device stack based on USB descriptor and - * usb_cfg_data. - */ +#if defined(CONFIG_USB_DEVICE_INITIALIZE_AT_BOOT) static int usb_device_init(void) { - uint8_t *device_descriptor; - - if (usb_dev.enabled == true) { - return -EALREADY; - } - - /* register device descriptor */ - device_descriptor = usb_get_device_descriptor(); - if (!device_descriptor) { - LOG_ERR("Failed to configure USB device stack"); - return -1; - } - - usb_set_config(device_descriptor); - - if (IS_ENABLED(CONFIG_USB_DEVICE_INITIALIZE_AT_BOOT)) { - return usb_enable(NULL); - } - - return 0; + return usb_enable(NULL); } SYS_INIT(usb_device_init, POST_KERNEL, CONFIG_APPLICATION_INIT_PRIORITY); +#endif diff --git a/subsys/usb/device_next/CMakeLists.txt b/subsys/usb/device_next/CMakeLists.txt index 281c2286328..0c6c9b24269 100644 --- a/subsys/usb/device_next/CMakeLists.txt +++ b/subsys/usb/device_next/CMakeLists.txt @@ -62,4 +62,10 @@ zephyr_library_sources_ifdef( class/usbd_uac2.c ) +zephyr_library_sources_ifdef( + CONFIG_USBD_HID_SUPPORT + class/usbd_hid.c + class/usbd_hid_api.c +) + zephyr_linker_sources(DATA_SECTIONS usbd_data.ld) diff --git a/subsys/usb/device_next/Kconfig b/subsys/usb/device_next/Kconfig index 7d783422ec3..a38823db71a 100644 --- a/subsys/usb/device_next/Kconfig +++ b/subsys/usb/device_next/Kconfig @@ -6,7 +6,7 @@ menuconfig USB_DEVICE_STACK_NEXT bool "New USB device stack [EXPERIMENTAL]" select EXPERIMENTAL select UDC_DRIVER - select HWINFO + imply HWINFO help New experimental USB device stack. @@ -47,6 +47,14 @@ config USBD_MSG_SLAB_COUNT help Maximum number of USB device notification messages that can be queued. +config USBD_MSG_WORK_DELAY + int "USB device notification messages work delay" + range 1 100 + default 1 + help + Message work may need to be delayed because the device stack is not + yet ready to publish the message. The delay unit is milliseconds. + rsource "class/Kconfig" endif # USB_DEVICE_STACK_NEXT diff --git a/subsys/usb/device_next/class/Kconfig b/subsys/usb/device_next/class/Kconfig index 19fe3cceb8c..42e489e9f4d 100644 --- a/subsys/usb/device_next/class/Kconfig +++ b/subsys/usb/device_next/class/Kconfig @@ -8,3 +8,4 @@ rsource "Kconfig.cdc_ecm" rsource "Kconfig.bt" rsource "Kconfig.msc" rsource "Kconfig.uac2" +rsource "Kconfig.hid" diff --git a/subsys/usb/device_next/class/Kconfig.hid b/subsys/usb/device_next/class/Kconfig.hid new file mode 100644 index 00000000000..8e3133a1dde --- /dev/null +++ b/subsys/usb/device_next/class/Kconfig.hid @@ -0,0 +1,37 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +menuconfig USBD_HID_SUPPORT + bool "USB Human Interface Device support" + default y + depends on DT_HAS_ZEPHYR_HID_DEVICE_ENABLED + help + Enables USB Human Interface Device support. + +if USBD_HID_SUPPORT + +config USBD_HID_IN_BUF_COUNT + int "Number of buffers in the IN pool" + range 1 256 + default 2 + help + Number of buffers in the IN pool per HID instance. + +config USBD_HID_OUT_BUF_COUNT + int "Number of buffers in the OUT pool" + range 1 256 + default 2 + help + Number of buffers in the OUT pool per HID instance. + +config USBD_HID_INIT_PRIORITY + int "HID device init priority" + default KERNEL_INIT_PRIORITY_DEVICE + help + HID device initialization priority + +module = USBD_HID +module-str = usbd hid +source "subsys/logging/Kconfig.template.log_config" + +endif # USBD_HID_SUPPORT diff --git a/subsys/usb/device_next/class/bt_hci.c b/subsys/usb/device_next/class/bt_hci.c index 8772ffeaf03..7c1c727d8b8 100644 --- a/subsys/usb/device_next/class/bt_hci.c +++ b/subsys/usb/device_next/class/bt_hci.c @@ -53,7 +53,8 @@ LOG_MODULE_REGISTER(bt_hci, CONFIG_USBD_BT_HCI_LOG_LEVEL); #define BT_HCI_EP_VOICE_OUT 0x03 #define BT_HCI_EP_MPS_EVENTS 16 -#define BT_HCI_EP_MPS_ACL_DATA 0 /* Get maximum supported */ +#define BT_HCI_EP_FS_MPS_ACL_DATA 64 +#define BT_HCI_EP_HS_MPS_ACL_DATA 512 #define BT_HCI_EP_MPS_VOICE 9 #define BT_HCI_EP_INTERVAL_EVENTS 1 @@ -81,20 +82,6 @@ static struct k_thread rx_thread_data; static K_KERNEL_STACK_DEFINE(tx_thread_stack, CONFIG_USBD_BT_HCI_TX_STACK_SIZE); static struct k_thread tx_thread_data; -struct bt_hci_data { - struct net_buf *acl_buf; - uint16_t acl_len; - struct k_sem sync_sem; - atomic_t state; -}; - -/* - * Make supported device request visible for the stack - * bRequest 0x00 and bRequest 0xE0. - */ -static const struct usbd_cctx_vendor_req bt_hci_vregs = - USBD_VENDOR_REQ(0x00, 0xe0); - /* * We do not support voice channels and we do not implement * isochronous endpoints handling, these are only available to match @@ -107,6 +94,8 @@ struct usbd_bt_hci_desc { struct usb_ep_descriptor if0_int_ep; struct usb_ep_descriptor if0_in_ep; struct usb_ep_descriptor if0_out_ep; + struct usb_ep_descriptor if0_hs_in_ep; + struct usb_ep_descriptor if0_hs_out_ep; struct usb_if_descriptor if1_0; struct usb_ep_descriptor if1_0_iso_in_ep; @@ -116,34 +105,57 @@ struct usbd_bt_hci_desc { struct usb_ep_descriptor if1_1_iso_out_ep; struct usb_desc_header nil_desc; -} __packed; +}; + +struct bt_hci_data { + struct net_buf *acl_buf; + struct usbd_bt_hci_desc *const desc; + const struct usb_desc_header **const fs_desc; + const struct usb_desc_header **const hs_desc; + uint16_t acl_len; + struct k_sem sync_sem; + atomic_t state; +}; + +/* + * Make supported device request visible for the stack + * bRequest 0x00 and bRequest 0xE0. + */ +static const struct usbd_cctx_vendor_req bt_hci_vregs = + USBD_VENDOR_REQ(0x00, 0xe0); -static uint8_t bt_hci_get_int_in(struct usbd_class_node *const c_nd) +static uint8_t bt_hci_get_int_in(struct usbd_class_data *const c_data) { - struct usbd_bt_hci_desc *desc = c_nd->data->desc; + struct bt_hci_data *data = usbd_class_get_private(c_data); + struct usbd_bt_hci_desc *desc = data->desc; return desc->if0_int_ep.bEndpointAddress; } -static uint8_t bt_hci_get_bulk_in(struct usbd_class_node *const c_nd) +static uint8_t bt_hci_get_bulk_in(struct usbd_class_data *const c_data) { - struct usbd_bt_hci_desc *desc = c_nd->data->desc; + struct usbd_contex *uds_ctx = usbd_class_get_ctx(c_data); + struct bt_hci_data *data = usbd_class_get_private(c_data); + struct usbd_bt_hci_desc *desc = data->desc; + + if (usbd_bus_speed(uds_ctx) == USBD_SPEED_HS) { + return desc->if0_hs_in_ep.bEndpointAddress; + } return desc->if0_in_ep.bEndpointAddress; } -static uint8_t bt_hci_get_bulk_out(struct usbd_class_node *const c_nd) +static uint8_t bt_hci_get_bulk_out(struct usbd_class_data *const c_data) { - struct usbd_bt_hci_desc *desc = c_nd->data->desc; + struct usbd_contex *uds_ctx = usbd_class_get_ctx(c_data); + struct bt_hci_data *data = usbd_class_get_private(c_data); + struct usbd_bt_hci_desc *desc = data->desc; - return desc->if0_out_ep.bEndpointAddress; -} - -static void bt_hci_update_iad(struct usbd_class_node *const c_nd) -{ - struct usbd_bt_hci_desc *desc = c_nd->data->desc; + if (usbd_bus_speed(uds_ctx) == USBD_SPEED_HS) { + return desc->if0_hs_out_ep.bEndpointAddress; + } - desc->iad.bFirstInterface = desc->if0.bInterfaceNumber; + return desc->if0_out_ep.bEndpointAddress; } struct net_buf *bt_hci_buf_alloc(const uint8_t ep) @@ -163,10 +175,10 @@ struct net_buf *bt_hci_buf_alloc(const uint8_t ep) return buf; } -static void bt_hci_tx_sync_in(struct usbd_class_node *const c_nd, +static void bt_hci_tx_sync_in(struct usbd_class_data *const c_data, struct net_buf *const bt_buf, const uint8_t ep) { - struct bt_hci_data *hci_data = c_nd->data->priv; + struct bt_hci_data *hci_data = usbd_class_get_private(c_data); struct net_buf *buf; buf = bt_hci_buf_alloc(ep); @@ -176,14 +188,14 @@ static void bt_hci_tx_sync_in(struct usbd_class_node *const c_nd, } net_buf_add_mem(buf, bt_buf->data, bt_buf->len); - usbd_ep_enqueue(c_nd, buf); + usbd_ep_enqueue(c_data, buf); k_sem_take(&hci_data->sync_sem, K_FOREVER); net_buf_unref(buf); } static void bt_hci_tx_thread(void *p1, void *p2, void *p3) { - struct usbd_class_node *const c_nd = p1; + struct usbd_class_data *const c_data = p1; ARG_UNUSED(p2); ARG_UNUSED(p3); @@ -196,10 +208,10 @@ static void bt_hci_tx_thread(void *p1, void *p2, void *p3) switch (bt_buf_get_type(bt_buf)) { case BT_BUF_EVT: - ep = bt_hci_get_int_in(c_nd); + ep = bt_hci_get_int_in(c_data); break; case BT_BUF_ACL_IN: - ep = bt_hci_get_bulk_in(c_nd); + ep = bt_hci_get_bulk_in(c_data); break; default: LOG_ERR("Unknown type %u", bt_buf_get_type(bt_buf)); @@ -207,7 +219,7 @@ static void bt_hci_tx_thread(void *p1, void *p2, void *p3) } - bt_hci_tx_sync_in(c_nd, bt_buf, ep); + bt_hci_tx_sync_in(c_data, bt_buf, ep); net_buf_unref(bt_buf); } } @@ -229,9 +241,9 @@ static void bt_hci_rx_thread(void *a, void *b, void *c) } } -static int bt_hci_acl_out_start(struct usbd_class_node *const c_nd) +static int bt_hci_acl_out_start(struct usbd_class_data *const c_data) { - struct bt_hci_data *hci_data = c_nd->data->priv; + struct bt_hci_data *hci_data = usbd_class_get_private(c_data); struct net_buf *buf; uint8_t ep; int ret; @@ -244,13 +256,13 @@ static int bt_hci_acl_out_start(struct usbd_class_node *const c_nd) return -EBUSY; } - ep = bt_hci_get_bulk_out(c_nd); + ep = bt_hci_get_bulk_out(c_data); buf = bt_hci_buf_alloc(ep); if (buf == NULL) { return -ENOMEM; } - ret = usbd_ep_enqueue(c_nd, buf); + ret = usbd_ep_enqueue(c_data, buf); if (ret) { LOG_ERR("Failed to enqueue net_buf for 0x%02x", ep); net_buf_unref(buf); @@ -298,10 +310,10 @@ static uint16_t hci_pkt_get_len(struct net_buf *const buf, return (size < hdr_len) ? 0 : len; } -static int bt_hci_acl_out_cb(struct usbd_class_node *const c_nd, +static int bt_hci_acl_out_cb(struct usbd_class_data *const c_data, struct net_buf *const buf, const int err) { - struct bt_hci_data *hci_data = c_nd->data->priv; + struct bt_hci_data *hci_data = usbd_class_get_private(c_data); if (err) { goto restart_out_transfer; @@ -352,24 +364,24 @@ static int bt_hci_acl_out_cb(struct usbd_class_node *const c_nd, net_buf_unref(buf); atomic_clear_bit(&hci_data->state, BT_HCI_ACL_RX_ENGAGED); - return bt_hci_acl_out_start(c_nd); + return bt_hci_acl_out_start(c_data); } -static int bt_hci_request(struct usbd_class_node *const c_nd, +static int bt_hci_request(struct usbd_class_data *const c_data, struct net_buf *buf, int err) { - struct usbd_contex *uds_ctx = c_nd->data->uds_ctx; - struct bt_hci_data *hci_data = c_nd->data->priv; + struct usbd_contex *uds_ctx = usbd_class_get_ctx(c_data); + struct bt_hci_data *hci_data = usbd_class_get_private(c_data); struct udc_buf_info *bi; bi = udc_get_buf_info(buf); - if (bi->ep == bt_hci_get_bulk_out(c_nd)) { - return bt_hci_acl_out_cb(c_nd, buf, err); + if (bi->ep == bt_hci_get_bulk_out(c_data)) { + return bt_hci_acl_out_cb(c_data, buf, err); } - if (bi->ep == bt_hci_get_bulk_in(c_nd) || - bi->ep == bt_hci_get_int_in(c_nd)) { + if (bi->ep == bt_hci_get_bulk_in(c_data) || + bi->ep == bt_hci_get_int_in(c_data)) { k_sem_give(&hci_data->sync_sem); return 0; @@ -378,34 +390,34 @@ static int bt_hci_request(struct usbd_class_node *const c_nd, return usbd_ep_buf_free(uds_ctx, buf); } -static void bt_hci_update(struct usbd_class_node *const c_nd, +static void bt_hci_update(struct usbd_class_data *const c_data, uint8_t iface, uint8_t alternate) { LOG_DBG("New configuration, interface %u alternate %u", iface, alternate); } -static void bt_hci_enable(struct usbd_class_node *const c_nd) +static void bt_hci_enable(struct usbd_class_data *const c_data) { - struct bt_hci_data *hci_data = c_nd->data->priv; + struct bt_hci_data *hci_data = usbd_class_get_private(c_data); atomic_set_bit(&hci_data->state, BT_HCI_CLASS_ENABLED); LOG_INF("Configuration enabled"); - if (bt_hci_acl_out_start(c_nd)) { + if (bt_hci_acl_out_start(c_data)) { LOG_ERR("Failed to start ACL OUT transfer"); } } -static void bt_hci_disable(struct usbd_class_node *const c_nd) +static void bt_hci_disable(struct usbd_class_data *const c_data) { - struct bt_hci_data *hci_data = c_nd->data->priv; + struct bt_hci_data *hci_data = usbd_class_get_private(c_data); atomic_clear_bit(&hci_data->state, BT_HCI_CLASS_ENABLED); LOG_INF("Configuration disabled"); } -static int bt_hci_ctd(struct usbd_class_node *const c_nd, +static int bt_hci_ctd(struct usbd_class_data *const c_data, const struct usb_setup_packet *const setup, const struct net_buf *const buf) { @@ -433,10 +445,25 @@ static int bt_hci_ctd(struct usbd_class_node *const c_nd, return 0; } -static int bt_hci_init(struct usbd_class_node *const c_nd) +static void *bt_hci_get_desc(struct usbd_class_data *const c_data, + const enum usbd_speed speed) +{ + struct bt_hci_data *data = usbd_class_get_private(c_data); + + if (speed == USBD_SPEED_HS) { + return data->hs_desc; + } + + return data->fs_desc; +} + +static int bt_hci_init(struct usbd_class_data *const c_data) { - bt_hci_update_iad(c_nd); + struct bt_hci_data *data = usbd_class_get_private(c_data); + struct usbd_bt_hci_desc *desc = data->desc; + + desc->iad.bFirstInterface = desc->if0.bInterfaceNumber; return 0; } @@ -447,6 +474,7 @@ static struct usbd_class_api bt_hci_api = { .enable = bt_hci_enable, .disable = bt_hci_disable, .control_to_dev = bt_hci_ctd, + .get_desc = bt_hci_get_desc, .init = bt_hci_init, }; @@ -489,7 +517,7 @@ static struct usbd_bt_hci_desc bt_hci_desc_##n = { \ .bDescriptorType = USB_DESC_ENDPOINT, \ .bEndpointAddress = BT_HCI_EP_ACL_DATA_IN, \ .bmAttributes = USB_EP_TYPE_BULK, \ - .wMaxPacketSize = sys_cpu_to_le16(BT_HCI_EP_MPS_ACL_DATA), \ + .wMaxPacketSize = sys_cpu_to_le16(BT_HCI_EP_FS_MPS_ACL_DATA), \ .bInterval = 0, \ }, \ \ @@ -498,10 +526,27 @@ static struct usbd_bt_hci_desc bt_hci_desc_##n = { \ .bDescriptorType = USB_DESC_ENDPOINT, \ .bEndpointAddress = BT_HCI_EP_ACL_DATA_OUT, \ .bmAttributes = USB_EP_TYPE_BULK, \ - .wMaxPacketSize = sys_cpu_to_le16(BT_HCI_EP_MPS_ACL_DATA), \ + .wMaxPacketSize = sys_cpu_to_le16(BT_HCI_EP_FS_MPS_ACL_DATA), \ .bInterval = 0, \ }, \ \ + .if0_hs_in_ep = { \ + .bLength = sizeof(struct usb_ep_descriptor), \ + .bDescriptorType = USB_DESC_ENDPOINT, \ + .bEndpointAddress = BT_HCI_EP_ACL_DATA_IN, \ + .bmAttributes = USB_EP_TYPE_BULK, \ + .wMaxPacketSize = sys_cpu_to_le16(BT_HCI_EP_HS_MPS_ACL_DATA), \ + .bInterval = 0, \ + }, \ + \ + .if0_hs_out_ep = { \ + .bLength = sizeof(struct usb_ep_descriptor), \ + .bDescriptorType = USB_DESC_ENDPOINT, \ + .bEndpointAddress = BT_HCI_EP_ACL_DATA_OUT, \ + .bmAttributes = USB_EP_TYPE_BULK, \ + .wMaxPacketSize = sys_cpu_to_le16(BT_HCI_EP_HS_MPS_ACL_DATA), \ + .bInterval = 0, \ + }, \ .if1_0 = { \ .bLength = sizeof(struct usb_if_descriptor), \ .bDescriptorType = USB_DESC_INTERFACE, \ @@ -566,20 +611,48 @@ static struct usbd_bt_hci_desc bt_hci_desc_##n = { \ .bLength = 0, \ .bDescriptorType = 0, \ }, \ +}; \ + \ +const static struct usb_desc_header *bt_hci_fs_desc_##n[] = { \ + (struct usb_desc_header *) &bt_hci_desc_##n.iad, \ + (struct usb_desc_header *) &bt_hci_desc_##n.if0, \ + (struct usb_desc_header *) &bt_hci_desc_##n.if0_int_ep, \ + (struct usb_desc_header *) &bt_hci_desc_##n.if0_in_ep, \ + (struct usb_desc_header *) &bt_hci_desc_##n.if0_out_ep, \ + (struct usb_desc_header *) &bt_hci_desc_##n.if1_0, \ + (struct usb_desc_header *) &bt_hci_desc_##n.if1_0_iso_in_ep, \ + (struct usb_desc_header *) &bt_hci_desc_##n.if1_0_iso_out_ep, \ + (struct usb_desc_header *) &bt_hci_desc_##n.if1_1, \ + (struct usb_desc_header *) &bt_hci_desc_##n.if1_1_iso_in_ep, \ + (struct usb_desc_header *) &bt_hci_desc_##n.if1_1_iso_out_ep, \ + (struct usb_desc_header *) &bt_hci_desc_##n.nil_desc, \ +}; \ + \ +const static struct usb_desc_header *bt_hci_hs_desc_##n[] = { \ + (struct usb_desc_header *) &bt_hci_desc_##n.iad, \ + (struct usb_desc_header *) &bt_hci_desc_##n.if0, \ + (struct usb_desc_header *) &bt_hci_desc_##n.if0_int_ep, \ + (struct usb_desc_header *) &bt_hci_desc_##n.if0_hs_in_ep, \ + (struct usb_desc_header *) &bt_hci_desc_##n.if0_hs_out_ep, \ + (struct usb_desc_header *) &bt_hci_desc_##n.if1_0, \ + (struct usb_desc_header *) &bt_hci_desc_##n.if1_0_iso_in_ep, \ + (struct usb_desc_header *) &bt_hci_desc_##n.if1_0_iso_out_ep, \ + (struct usb_desc_header *) &bt_hci_desc_##n.if1_1, \ + (struct usb_desc_header *) &bt_hci_desc_##n.if1_1_iso_in_ep, \ + (struct usb_desc_header *) &bt_hci_desc_##n.if1_1_iso_out_ep, \ + (struct usb_desc_header *) &bt_hci_desc_##n.nil_desc, \ }; #define BT_HCI_CLASS_DATA_DEFINE(n) \ static struct bt_hci_data bt_hci_data_##n = { \ .sync_sem = Z_SEM_INITIALIZER(bt_hci_data_##n.sync_sem, 0, 1), \ + .desc = &bt_hci_desc_##n, \ + .fs_desc = bt_hci_fs_desc_##n, \ + .hs_desc = bt_hci_hs_desc_##n, \ }; \ \ - static struct usbd_class_data bt_hci_class_##n = { \ - .desc = (struct usb_desc_header *)&bt_hci_desc_##n, \ - .priv = &bt_hci_data_##n, \ - .v_reqs = &bt_hci_vregs, \ - }; \ - \ - USBD_DEFINE_CLASS(bt_hci_##n, &bt_hci_api, &bt_hci_class_##n); + USBD_DEFINE_CLASS(bt_hci_##n, &bt_hci_api, \ + &bt_hci_data_##n, &bt_hci_vregs); /* * Bluetooth subsystem does not support multiple HCI instances, diff --git a/subsys/usb/device_next/class/loopback.c b/subsys/usb/device_next/class/loopback.c index d6d60243ab2..edddb867f55 100644 --- a/subsys/usb/device_next/class/loopback.c +++ b/subsys/usb/device_next/class/loopback.c @@ -22,197 +22,47 @@ static uint8_t lb_buf[1024]; #define LB_VENDOR_REQ_OUT 0x5b #define LB_VENDOR_REQ_IN 0x5c +#define LB_ISO_EP_MPS 256 +#define LB_ISO_EP_INTERVAL 1 + /* Make supported vendor request visible for the device stack */ static const struct usbd_cctx_vendor_req lb_vregs = USBD_VENDOR_REQ(LB_VENDOR_REQ_OUT, LB_VENDOR_REQ_IN); struct loopback_desc { + struct usb_association_descriptor iad; struct usb_if_descriptor if0; struct usb_ep_descriptor if0_out_ep; struct usb_ep_descriptor if0_in_ep; - struct usb_ep_descriptor if0_int_out_ep; - struct usb_ep_descriptor if0_int_in_ep; - struct usb_ep_descriptor if0_iso_out_ep; - struct usb_ep_descriptor if0_iso_in_ep; + struct usb_ep_descriptor if0_hs_out_ep; + struct usb_ep_descriptor if0_hs_in_ep; struct usb_if_descriptor if1; - struct usb_if_descriptor if2; - struct usb_ep_descriptor if2_out_ep; - struct usb_ep_descriptor if2_in_ep; - struct usb_if_descriptor if3; - struct usb_ep_descriptor if3_out_ep; - struct usb_ep_descriptor if3_in_ep; + struct usb_ep_descriptor if1_int_out_ep; + struct usb_ep_descriptor if1_int_in_ep; + struct usb_if_descriptor if2_0; + struct usb_ep_descriptor if2_0_iso_in_ep; + struct usb_ep_descriptor if2_0_iso_out_ep; + struct usb_if_descriptor if2_1; + struct usb_ep_descriptor if2_1_iso_in_ep; + struct usb_ep_descriptor if2_1_iso_out_ep; struct usb_desc_header nil_desc; -} __packed; - -#define DEFINE_LOOPBACK_DESCRIPTOR(x, _) \ -static struct loopback_desc lb_desc_##x = { \ - /* Interface descriptor 0 */ \ - .if0 = { \ - .bLength = sizeof(struct usb_if_descriptor), \ - .bDescriptorType = USB_DESC_INTERFACE, \ - .bInterfaceNumber = 0, \ - .bAlternateSetting = 0, \ - .bNumEndpoints = 6, \ - .bInterfaceClass = USB_BCC_VENDOR, \ - .bInterfaceSubClass = 0, \ - .bInterfaceProtocol = 0, \ - .iInterface = 0, \ - }, \ - \ - /* Data Endpoint OUT */ \ - .if0_out_ep = { \ - .bLength = sizeof(struct usb_ep_descriptor), \ - .bDescriptorType = USB_DESC_ENDPOINT, \ - .bEndpointAddress = 0x01, \ - .bmAttributes = USB_EP_TYPE_BULK, \ - .wMaxPacketSize = 0, \ - .bInterval = 0x00, \ - }, \ - \ - /* Data Endpoint IN */ \ - .if0_in_ep = { \ - .bLength = sizeof(struct usb_ep_descriptor), \ - .bDescriptorType = USB_DESC_ENDPOINT, \ - .bEndpointAddress = 0x81, \ - .bmAttributes = USB_EP_TYPE_BULK, \ - .wMaxPacketSize = 0, \ - .bInterval = 0x00, \ - }, \ - \ - /* Interface Endpoint OUT */ \ - .if0_int_out_ep = { \ - .bLength = sizeof(struct usb_ep_descriptor), \ - .bDescriptorType = USB_DESC_ENDPOINT, \ - .bEndpointAddress = 0x03, \ - .bmAttributes = USB_EP_TYPE_INTERRUPT, \ - .wMaxPacketSize = 0, \ - .bInterval = 0x01, \ - }, \ - \ - /* Interrupt Endpoint IN */ \ - .if0_int_in_ep = { \ - .bLength = sizeof(struct usb_ep_descriptor), \ - .bDescriptorType = USB_DESC_ENDPOINT, \ - .bEndpointAddress = 0x83, \ - .bmAttributes = USB_EP_TYPE_INTERRUPT, \ - .wMaxPacketSize = 0, \ - .bInterval = 0x01, \ - }, \ - \ - /* Endpoint ISO OUT */ \ - .if0_iso_out_ep = { \ - .bLength = sizeof(struct usb_ep_descriptor), \ - .bDescriptorType = USB_DESC_ENDPOINT, \ - .bEndpointAddress = 0x03, \ - .bmAttributes = USB_EP_TYPE_ISO, \ - .wMaxPacketSize = 0, \ - .bInterval = 0x01, \ - }, \ - \ - /* Endpoint ISO IN */ \ - .if0_iso_in_ep = { \ - .bLength = sizeof(struct usb_ep_descriptor), \ - .bDescriptorType = USB_DESC_ENDPOINT, \ - .bEndpointAddress = 0x83, \ - .bmAttributes = USB_EP_TYPE_ISO, \ - .wMaxPacketSize = 0, \ - .bInterval = 0x01, \ - }, \ - \ - /* Interface descriptor 1, no endpoints */ \ - .if1 = { \ - .bLength = sizeof(struct usb_if_descriptor), \ - .bDescriptorType = USB_DESC_INTERFACE, \ - .bInterfaceNumber = 1, \ - .bAlternateSetting = 0, \ - .bNumEndpoints = 0, \ - .bInterfaceClass = USB_BCC_VENDOR, \ - .bInterfaceSubClass = 0, \ - .bInterfaceProtocol = 0, \ - .iInterface = 0, \ - }, \ - \ - /* Interface descriptor 1 */ \ - .if2 = { \ - .bLength = sizeof(struct usb_if_descriptor), \ - .bDescriptorType = USB_DESC_INTERFACE, \ - .bInterfaceNumber = 1, \ - .bAlternateSetting = 1, \ - .bNumEndpoints = 2, \ - .bInterfaceClass = USB_BCC_VENDOR, \ - .bInterfaceSubClass = 0, \ - .bInterfaceProtocol = 0, \ - .iInterface = 0, \ - }, \ - \ - /* Data Endpoint OUT */ \ - .if2_out_ep = { \ - .bLength = sizeof(struct usb_ep_descriptor), \ - .bDescriptorType = USB_DESC_ENDPOINT, \ - .bEndpointAddress = 0x02, \ - .bmAttributes = USB_EP_TYPE_BULK, \ - .wMaxPacketSize = 32, \ - .bInterval = 0x00, \ - }, \ - \ - /* Data Endpoint IN */ \ - .if2_in_ep = { \ - .bLength = sizeof(struct usb_ep_descriptor), \ - .bDescriptorType = USB_DESC_ENDPOINT, \ - .bEndpointAddress = 0x82, \ - .bmAttributes = USB_EP_TYPE_BULK, \ - .wMaxPacketSize = 32, \ - .bInterval = 0x00, \ - }, \ - \ - /* Interface descriptor 1 */ \ - .if3 = { \ - .bLength = sizeof(struct usb_if_descriptor), \ - .bDescriptorType = USB_DESC_INTERFACE, \ - .bInterfaceNumber = 1, \ - .bAlternateSetting = 2, \ - .bNumEndpoints = 2, \ - .bInterfaceClass = USB_BCC_VENDOR, \ - .bInterfaceSubClass = 0, \ - .bInterfaceProtocol = 0, \ - .iInterface = 0, \ - }, \ - \ - /* Data Endpoint OUT, get wMaxPacketSize from UDC */ \ - .if3_out_ep = { \ - .bLength = sizeof(struct usb_ep_descriptor), \ - .bDescriptorType = USB_DESC_ENDPOINT, \ - .bEndpointAddress = 0x02, \ - .bmAttributes = USB_EP_TYPE_BULK, \ - .wMaxPacketSize = 0, \ - .bInterval = 0x00, \ - }, \ - \ - /* Data Endpoint IN, get wMaxPacketSize from UDC */ \ - .if3_in_ep = { \ - .bLength = sizeof(struct usb_ep_descriptor), \ - .bDescriptorType = USB_DESC_ENDPOINT, \ - .bEndpointAddress = 0x82, \ - .bmAttributes = USB_EP_TYPE_BULK, \ - .wMaxPacketSize = 0, \ - .bInterval = 0x00, \ - }, \ - \ - /* Termination descriptor */ \ - .nil_desc = { \ - .bLength = 0, \ - .bDescriptorType = 0, \ - }, \ -}; \ - -static void lb_update(struct usbd_class_node *c_nd, +}; + +struct lb_data { + struct loopback_desc *const desc; + const struct usb_desc_header **const fs_desc; + const struct usb_desc_header **const hs_desc; + atomic_t state; +}; + +static void lb_update(struct usbd_class_data *c_data, uint8_t iface, uint8_t alternate) { LOG_DBG("Instance %p, interface %u alternate %u changed", - c_nd, iface, alternate); + c_data, iface, alternate); } -static int lb_control_to_host(struct usbd_class_node *c_nd, +static int lb_control_to_host(struct usbd_class_data *c_data, const struct usb_setup_packet *const setup, struct net_buf *const buf) { @@ -237,7 +87,7 @@ static int lb_control_to_host(struct usbd_class_node *c_nd, return 0; } -static int lb_control_to_dev(struct usbd_class_node *c_nd, +static int lb_control_to_dev(struct usbd_class_data *c_data, const struct usb_setup_packet *const setup, const struct net_buf *const buf) { @@ -259,21 +109,38 @@ static int lb_control_to_dev(struct usbd_class_node *c_nd, return 0; } -static int lb_request_handler(struct usbd_class_node *c_nd, +static int lb_request_handler(struct usbd_class_data *c_data, struct net_buf *buf, int err) { + struct usbd_contex *uds_ctx = usbd_class_get_ctx(c_data); struct udc_buf_info *bi = NULL; bi = (struct udc_buf_info *)net_buf_user_data(buf); - LOG_DBG("%p -> ep 0x%02x, len %u, err %d", c_nd, bi->ep, buf->len, err); - usbd_ep_buf_free(c_nd->data->uds_ctx, buf); + LOG_DBG("%p -> ep 0x%02x, len %u, err %d", c_data, bi->ep, buf->len, err); - return 0; + return usbd_ep_buf_free(uds_ctx, buf); } -static int lb_init(struct usbd_class_node *c_nd) +static void *lb_get_desc(struct usbd_class_data *const c_data, + const enum usbd_speed speed) { - LOG_DBG("Init class instance %p", c_nd); + struct lb_data *data = usbd_class_get_private(c_data); + + if (speed == USBD_SPEED_HS) { + return data->hs_desc; + } + + return data->fs_desc; +} + +static int lb_init(struct usbd_class_data *c_data) +{ + struct lb_data *data = usbd_class_get_private(c_data); + struct loopback_desc *desc = data->desc; + + desc->iad.bFirstInterface = desc->if0.bInterfaceNumber; + + LOG_DBG("Init class instance %p", c_data); return 0; } @@ -283,16 +150,219 @@ struct usbd_class_api lb_api = { .control_to_host = lb_control_to_host, .control_to_dev = lb_control_to_dev, .request = lb_request_handler, + .get_desc = lb_get_desc, .init = lb_init, }; -#define DEFINE_LOOPBACK_CLASS_DATA(x, _) \ - static struct usbd_class_data lb_class_##x = { \ - .desc = (struct usb_desc_header *)&lb_desc_##x, \ - .v_reqs = &lb_vregs, \ - }; \ - \ - USBD_DEFINE_CLASS(loopback_##x, &lb_api, &lb_class_##x); +#define DEFINE_LOOPBACK_DESCRIPTOR(x, _) \ +static struct loopback_desc lb_desc_##x = { \ + .iad = { \ + .bLength = sizeof(struct usb_association_descriptor), \ + .bDescriptorType = USB_DESC_INTERFACE_ASSOC, \ + .bFirstInterface = 0, \ + .bInterfaceCount = 3, \ + .bFunctionClass = USB_BCC_VENDOR, \ + .bFunctionSubClass = 0, \ + .bFunctionProtocol = 0, \ + .iFunction = 0, \ + }, \ + \ + /* Interface descriptor 0 */ \ + .if0 = { \ + .bLength = sizeof(struct usb_if_descriptor), \ + .bDescriptorType = USB_DESC_INTERFACE, \ + .bInterfaceNumber = 0, \ + .bAlternateSetting = 0, \ + .bNumEndpoints = 2, \ + .bInterfaceClass = USB_BCC_VENDOR, \ + .bInterfaceSubClass = 0, \ + .bInterfaceProtocol = 0, \ + .iInterface = 0, \ + }, \ + \ + /* Data Endpoint OUT */ \ + .if0_out_ep = { \ + .bLength = sizeof(struct usb_ep_descriptor), \ + .bDescriptorType = USB_DESC_ENDPOINT, \ + .bEndpointAddress = 0x01, \ + .bmAttributes = USB_EP_TYPE_BULK, \ + .wMaxPacketSize = sys_cpu_to_le16(64U), \ + .bInterval = 0x00, \ + }, \ + \ + /* Data Endpoint IN */ \ + .if0_in_ep = { \ + .bLength = sizeof(struct usb_ep_descriptor), \ + .bDescriptorType = USB_DESC_ENDPOINT, \ + .bEndpointAddress = 0x81, \ + .bmAttributes = USB_EP_TYPE_BULK, \ + .wMaxPacketSize = sys_cpu_to_le16(64U), \ + .bInterval = 0x00, \ + }, \ + \ + /* Data Endpoint OUT */ \ + .if0_hs_out_ep = { \ + .bLength = sizeof(struct usb_ep_descriptor), \ + .bDescriptorType = USB_DESC_ENDPOINT, \ + .bEndpointAddress = 0x01, \ + .bmAttributes = USB_EP_TYPE_BULK, \ + .wMaxPacketSize = sys_cpu_to_le16(512), \ + .bInterval = 0x00, \ + }, \ + \ + /* Data Endpoint IN */ \ + .if0_hs_in_ep = { \ + .bLength = sizeof(struct usb_ep_descriptor), \ + .bDescriptorType = USB_DESC_ENDPOINT, \ + .bEndpointAddress = 0x81, \ + .bmAttributes = USB_EP_TYPE_BULK, \ + .wMaxPacketSize = sys_cpu_to_le16(512), \ + .bInterval = 0x00, \ + }, \ + \ + /* Interface descriptor 1 */ \ + .if1 = { \ + .bLength = sizeof(struct usb_if_descriptor), \ + .bDescriptorType = USB_DESC_INTERFACE, \ + .bInterfaceNumber = 1, \ + .bAlternateSetting = 0, \ + .bNumEndpoints = 2, \ + .bInterfaceClass = USB_BCC_VENDOR, \ + .bInterfaceSubClass = 0, \ + .bInterfaceProtocol = 0, \ + .iInterface = 0, \ + }, \ + \ + /* Interface Interrupt Endpoint OUT */ \ + .if1_int_out_ep = { \ + .bLength = sizeof(struct usb_ep_descriptor), \ + .bDescriptorType = USB_DESC_ENDPOINT, \ + .bEndpointAddress = 0x02, \ + .bmAttributes = USB_EP_TYPE_INTERRUPT, \ + .wMaxPacketSize = sys_cpu_to_le16(64), \ + .bInterval = 0x01, \ + }, \ + \ + /* Interrupt Interrupt Endpoint IN */ \ + .if1_int_in_ep = { \ + .bLength = sizeof(struct usb_ep_descriptor), \ + .bDescriptorType = USB_DESC_ENDPOINT, \ + .bEndpointAddress = 0x82, \ + .bmAttributes = USB_EP_TYPE_INTERRUPT, \ + .wMaxPacketSize = sys_cpu_to_le16(64), \ + .bInterval = 0x01, \ + }, \ + \ + .if2_0 = { \ + .bLength = sizeof(struct usb_if_descriptor), \ + .bDescriptorType = USB_DESC_INTERFACE, \ + .bInterfaceNumber = 2, \ + .bAlternateSetting = 0, \ + .bNumEndpoints = 2, \ + .bInterfaceClass = USB_BCC_VENDOR, \ + .bInterfaceSubClass = 0, \ + .bInterfaceProtocol = 0, \ + .iInterface = 0, \ + }, \ + \ + .if2_0_iso_in_ep = { \ + .bLength = sizeof(struct usb_ep_descriptor), \ + .bDescriptorType = USB_DESC_ENDPOINT, \ + .bEndpointAddress = 0x83, \ + .bmAttributes = USB_EP_TYPE_ISO, \ + .wMaxPacketSize = 0, \ + .bInterval = LB_ISO_EP_INTERVAL, \ + }, \ + \ + .if2_0_iso_out_ep = { \ + .bLength = sizeof(struct usb_ep_descriptor), \ + .bDescriptorType = USB_DESC_ENDPOINT, \ + .bEndpointAddress = 0x03, \ + .bmAttributes = USB_EP_TYPE_ISO, \ + .wMaxPacketSize = 0, \ + .bInterval = LB_ISO_EP_INTERVAL, \ + }, \ + \ + .if2_1 = { \ + .bLength = sizeof(struct usb_if_descriptor), \ + .bDescriptorType = USB_DESC_INTERFACE, \ + .bInterfaceNumber = 2, \ + .bAlternateSetting = 1, \ + .bNumEndpoints = 2, \ + .bInterfaceClass = USB_BCC_VENDOR, \ + .bInterfaceSubClass = 0, \ + .bInterfaceProtocol = 0, \ + .iInterface = 0, \ + }, \ + \ + .if2_1_iso_in_ep = { \ + .bLength = sizeof(struct usb_ep_descriptor), \ + .bDescriptorType = USB_DESC_ENDPOINT, \ + .bEndpointAddress = 0x83, \ + .bmAttributes = USB_EP_TYPE_ISO, \ + .wMaxPacketSize = sys_cpu_to_le16(LB_ISO_EP_MPS), \ + .bInterval = LB_ISO_EP_INTERVAL, \ + }, \ + \ + .if2_1_iso_out_ep = { \ + .bLength = sizeof(struct usb_ep_descriptor), \ + .bDescriptorType = USB_DESC_ENDPOINT, \ + .bEndpointAddress = 0x03, \ + .bmAttributes = USB_EP_TYPE_ISO, \ + .wMaxPacketSize = sys_cpu_to_le16(LB_ISO_EP_MPS), \ + .bInterval = LB_ISO_EP_INTERVAL, \ + }, \ + \ + /* Termination descriptor */ \ + .nil_desc = { \ + .bLength = 0, \ + .bDescriptorType = 0, \ + }, \ +}; \ + \ +const static struct usb_desc_header *lb_fs_desc_##x[] = { \ + (struct usb_desc_header *) &lb_desc_##x.iad, \ + (struct usb_desc_header *) &lb_desc_##x.if0, \ + (struct usb_desc_header *) &lb_desc_##x.if0_in_ep, \ + (struct usb_desc_header *) &lb_desc_##x.if0_out_ep, \ + (struct usb_desc_header *) &lb_desc_##x.if1, \ + (struct usb_desc_header *) &lb_desc_##x.if1_int_in_ep, \ + (struct usb_desc_header *) &lb_desc_##x.if1_int_out_ep, \ + (struct usb_desc_header *) &lb_desc_##x.if2_0, \ + (struct usb_desc_header *) &lb_desc_##x.if2_0_iso_in_ep, \ + (struct usb_desc_header *) &lb_desc_##x.if2_0_iso_out_ep, \ + (struct usb_desc_header *) &lb_desc_##x.if2_1, \ + (struct usb_desc_header *) &lb_desc_##x.if2_1_iso_in_ep, \ + (struct usb_desc_header *) &lb_desc_##x.if2_1_iso_out_ep, \ + (struct usb_desc_header *) &lb_desc_##x.nil_desc, \ +}; \ + \ +const static struct usb_desc_header *lb_hs_desc_##x[] = { \ + (struct usb_desc_header *) &lb_desc_##x.iad, \ + (struct usb_desc_header *) &lb_desc_##x.if0, \ + (struct usb_desc_header *) &lb_desc_##x.if0_hs_in_ep, \ + (struct usb_desc_header *) &lb_desc_##x.if0_hs_out_ep, \ + (struct usb_desc_header *) &lb_desc_##x.if1, \ + (struct usb_desc_header *) &lb_desc_##x.if1_int_in_ep, \ + (struct usb_desc_header *) &lb_desc_##x.if1_int_out_ep, \ + (struct usb_desc_header *) &lb_desc_##x.if2_0, \ + (struct usb_desc_header *) &lb_desc_##x.if2_0_iso_in_ep, \ + (struct usb_desc_header *) &lb_desc_##x.if2_0_iso_out_ep, \ + (struct usb_desc_header *) &lb_desc_##x.if2_1, \ + (struct usb_desc_header *) &lb_desc_##x.if2_1_iso_in_ep, \ + (struct usb_desc_header *) &lb_desc_##x.if2_1_iso_out_ep, \ + (struct usb_desc_header *) &lb_desc_##x.nil_desc, \ +}; + + +#define DEFINE_LOOPBACK_CLASS_DATA(x, _) \ + static struct lb_data lb_data_##x = { \ + .desc = &lb_desc_##x, \ + .fs_desc = lb_fs_desc_##x, \ + .hs_desc = lb_hs_desc_##x, \ + }; \ + \ + USBD_DEFINE_CLASS(loopback_##x, &lb_api, &lb_data_##x, &lb_vregs); LISTIFY(CONFIG_USBD_LOOPBACK_INSTANCES_COUNT, DEFINE_LOOPBACK_DESCRIPTOR, ()) LISTIFY(CONFIG_USBD_LOOPBACK_INSTANCES_COUNT, DEFINE_LOOPBACK_CLASS_DATA, ()) diff --git a/subsys/usb/device_next/class/usbd_cdc_acm.c b/subsys/usb/device_next/class/usbd_cdc_acm.c index 58544322a0a..838550f18dd 100644 --- a/subsys/usb/device_next/class/usbd_cdc_acm.c +++ b/subsys/usb/device_next/class/usbd_cdc_acm.c @@ -21,6 +21,14 @@ #include "usbd_msg.h" #include +#if DT_NODE_HAS_COMPAT(DT_CHOSEN(zephyr_console), zephyr_cdc_acm_uart) \ + && defined(CONFIG_USBD_CDC_ACM_LOG_LEVEL) \ + && CONFIG_USBD_CDC_ACM_LOG_LEVEL != LOG_LEVEL_NONE +/* Prevent endless recursive logging loop and warn user about it */ +#warning "USB_CDC_ACM_LOG_LEVEL forced to LOG_LEVEL_NONE" +#undef CONFIG_USBD_CDC_ACM_LOG_LEVEL +#define CONFIG_USBD_CDC_ACM_LOG_LEVEL LOG_LEVEL_NONE +#endif LOG_MODULE_REGISTER(usbd_cdc_acm, CONFIG_USBD_CDC_ACM_LOG_LEVEL); NET_BUF_POOL_FIXED_DEFINE(cdc_acm_ep_pool, @@ -28,9 +36,10 @@ NET_BUF_POOL_FIXED_DEFINE(cdc_acm_ep_pool, 512, sizeof(struct udc_buf_info), NULL); #define CDC_ACM_DEFAULT_LINECODING {sys_cpu_to_le32(115200), 0, 0, 8} -#define CDC_ACM_DEFAULT_BULK_EP_MPS 0 #define CDC_ACM_DEFAULT_INT_EP_MPS 16 -#define CDC_ACM_DEFAULT_INT_INTERVAL 0x0A +#define CDC_ACM_INTERVAL_DEFAULT 10000UL +#define CDC_ACM_FS_INT_EP_INTERVAL USB_FS_INT_EP_INTERVAL(10000U) +#define CDC_ACM_HS_INT_EP_INTERVAL USB_HS_INT_EP_INTERVAL(10000U) #define CDC_ACM_CLASS_ENABLED 0 #define CDC_ACM_CLASS_SUSPENDED 1 @@ -49,9 +58,32 @@ struct cdc_acm_uart_fifo { bool altered; }; +struct usbd_cdc_acm_desc { + struct usb_association_descriptor iad; + struct usb_if_descriptor if0; + struct cdc_header_descriptor if0_header; + struct cdc_cm_descriptor if0_cm; + struct cdc_acm_descriptor if0_acm; + struct cdc_union_descriptor if0_union; + struct usb_ep_descriptor if0_int_ep; + struct usb_ep_descriptor if0_hs_int_ep; + + struct usb_if_descriptor if1; + struct usb_ep_descriptor if1_in_ep; + struct usb_ep_descriptor if1_out_ep; + struct usb_ep_descriptor if1_hs_in_ep; + struct usb_ep_descriptor if1_hs_out_ep; + + struct usb_desc_header nil_desc; +}; + struct cdc_acm_uart_data { /* Pointer to the associated USBD class node */ - struct usbd_class_node *c_nd; + struct usbd_class_data *c_data; + /* Pointer to the class interface descriptors */ + struct usbd_cdc_acm_desc *const desc; + const struct usb_desc_header **const fs_desc; + const struct usb_desc_header **const hs_desc; /* Line Coding Structure */ struct cdc_acm_line_coding line_coding; /* SetControlLineState bitmap */ @@ -80,22 +112,6 @@ struct cdc_acm_uart_data { struct k_sem notif_sem; }; -struct usbd_cdc_acm_desc { - struct usb_association_descriptor iad_cdc; - struct usb_if_descriptor if0; - struct cdc_header_descriptor if0_header; - struct cdc_cm_descriptor if0_cm; - struct cdc_acm_descriptor if0_acm; - struct cdc_union_descriptor if0_union; - struct usb_ep_descriptor if0_int_ep; - - struct usb_if_descriptor if1; - struct usb_ep_descriptor if1_in_ep; - struct usb_ep_descriptor if1_out_ep; - - struct usb_desc_header nil_desc; -} __packed; - static void cdc_acm_irq_rx_enable(const struct device *dev); struct net_buf *cdc_acm_buf_alloc(const uint8_t ep) @@ -125,39 +141,64 @@ static ALWAYS_INLINE bool check_wq_ctx(const struct device *dev) return k_current_get() == k_work_queue_thread_get(&cdc_acm_work_q); } -static uint8_t cdc_acm_get_int_in(struct usbd_class_node *const c_nd) +static uint8_t cdc_acm_get_int_in(struct usbd_class_data *const c_data) { - struct usbd_cdc_acm_desc *desc = c_nd->data->desc; + struct usbd_contex *uds_ctx = usbd_class_get_ctx(c_data); + const struct device *dev = usbd_class_get_private(c_data); + struct cdc_acm_uart_data *data = dev->data; + struct usbd_cdc_acm_desc *desc = data->desc; + + if (usbd_bus_speed(uds_ctx) == USBD_SPEED_HS) { + return desc->if0_hs_int_ep.bEndpointAddress; + } return desc->if0_int_ep.bEndpointAddress; } -static uint8_t cdc_acm_get_bulk_in(struct usbd_class_node *const c_nd) +static uint8_t cdc_acm_get_bulk_in(struct usbd_class_data *const c_data) { - struct usbd_cdc_acm_desc *desc = c_nd->data->desc; + struct usbd_contex *uds_ctx = usbd_class_get_ctx(c_data); + const struct device *dev = usbd_class_get_private(c_data); + struct cdc_acm_uart_data *data = dev->data; + struct usbd_cdc_acm_desc *desc = data->desc; + + if (usbd_bus_speed(uds_ctx) == USBD_SPEED_HS) { + return desc->if1_hs_in_ep.bEndpointAddress; + } return desc->if1_in_ep.bEndpointAddress; } -static uint8_t cdc_acm_get_bulk_out(struct usbd_class_node *const c_nd) +static uint8_t cdc_acm_get_bulk_out(struct usbd_class_data *const c_data) { - struct usbd_cdc_acm_desc *desc = c_nd->data->desc; + struct usbd_contex *uds_ctx = usbd_class_get_ctx(c_data); + const struct device *dev = usbd_class_get_private(c_data); + struct cdc_acm_uart_data *data = dev->data; + struct usbd_cdc_acm_desc *desc = data->desc; + + if (usbd_bus_speed(uds_ctx) == USBD_SPEED_HS) { + return desc->if1_hs_out_ep.bEndpointAddress; + } return desc->if1_out_ep.bEndpointAddress; } -static size_t cdc_acm_get_bulk_mps(struct usbd_class_node *const c_nd) +static size_t cdc_acm_get_bulk_mps(struct usbd_class_data *const c_data) { - struct usbd_cdc_acm_desc *desc = c_nd->data->desc; + struct usbd_contex *uds_ctx = usbd_class_get_ctx(c_data); + + if (usbd_bus_speed(uds_ctx) == USBD_SPEED_HS) { + return 512U; + } - return desc->if1_out_ep.wMaxPacketSize; + return 64U; } -static int usbd_cdc_acm_request(struct usbd_class_node *const c_nd, +static int usbd_cdc_acm_request(struct usbd_class_data *const c_data, struct net_buf *buf, int err) { - struct usbd_contex *uds_ctx = c_nd->data->uds_ctx; - const struct device *dev = c_nd->data->priv; + struct usbd_contex *uds_ctx = usbd_class_get_ctx(c_data); + const struct device *dev = usbd_class_get_private(c_data); struct cdc_acm_uart_data *data = dev->data; struct udc_buf_info *bi; @@ -171,14 +212,14 @@ static int usbd_cdc_acm_request(struct usbd_class_node *const c_nd, bi->ep, buf->len); } - if (bi->ep == cdc_acm_get_bulk_out(c_nd)) { + if (bi->ep == cdc_acm_get_bulk_out(c_data)) { atomic_clear_bit(&data->state, CDC_ACM_RX_FIFO_BUSY); } goto ep_request_error; } - if (bi->ep == cdc_acm_get_bulk_out(c_nd)) { + if (bi->ep == cdc_acm_get_bulk_out(c_data)) { /* RX transfer completion */ size_t done; @@ -192,14 +233,14 @@ static int usbd_cdc_acm_request(struct usbd_class_node *const c_nd, cdc_acm_work_submit(&data->rx_fifo_work); } - if (bi->ep == cdc_acm_get_bulk_in(c_nd)) { + if (bi->ep == cdc_acm_get_bulk_in(c_data)) { /* TX transfer completion */ if (data->cb) { cdc_acm_work_submit(&data->irq_cb_work); } } - if (bi->ep == cdc_acm_get_int_in(c_nd)) { + if (bi->ep == cdc_acm_get_int_in(c_data)) { k_sem_give(&data->notif_sem); } @@ -207,16 +248,16 @@ static int usbd_cdc_acm_request(struct usbd_class_node *const c_nd, return usbd_ep_buf_free(uds_ctx, buf); } -static void usbd_cdc_acm_update(struct usbd_class_node *const c_nd, +static void usbd_cdc_acm_update(struct usbd_class_data *const c_data, uint8_t iface, uint8_t alternate) { LOG_DBG("New configuration, interface %u alternate %u", iface, alternate); } -static void usbd_cdc_acm_enable(struct usbd_class_node *const c_nd) +static void usbd_cdc_acm_enable(struct usbd_class_data *const c_data) { - const struct device *dev = c_nd->data->priv; + const struct device *dev = usbd_class_get_private(c_data); struct cdc_acm_uart_data *data = dev->data; atomic_set_bit(&data->state, CDC_ACM_CLASS_ENABLED); @@ -231,9 +272,9 @@ static void usbd_cdc_acm_enable(struct usbd_class_node *const c_nd) } } -static void usbd_cdc_acm_disable(struct usbd_class_node *const c_nd) +static void usbd_cdc_acm_disable(struct usbd_class_data *const c_data) { - const struct device *dev = c_nd->data->priv; + const struct device *dev = usbd_class_get_private(c_data); struct cdc_acm_uart_data *data = dev->data; atomic_clear_bit(&data->state, CDC_ACM_CLASS_ENABLED); @@ -241,23 +282,36 @@ static void usbd_cdc_acm_disable(struct usbd_class_node *const c_nd) LOG_INF("Configuration disabled"); } -static void usbd_cdc_acm_suspended(struct usbd_class_node *const c_nd) +static void usbd_cdc_acm_suspended(struct usbd_class_data *const c_data) { - const struct device *dev = c_nd->data->priv; + const struct device *dev = usbd_class_get_private(c_data); struct cdc_acm_uart_data *data = dev->data; /* FIXME: filter stray suspended events earlier */ atomic_set_bit(&data->state, CDC_ACM_CLASS_SUSPENDED); } -static void usbd_cdc_acm_resumed(struct usbd_class_node *const c_nd) +static void usbd_cdc_acm_resumed(struct usbd_class_data *const c_data) { - const struct device *dev = c_nd->data->priv; + const struct device *dev = usbd_class_get_private(c_data); struct cdc_acm_uart_data *data = dev->data; atomic_clear_bit(&data->state, CDC_ACM_CLASS_SUSPENDED); } +static void *usbd_cdc_acm_get_desc(struct usbd_class_data *const c_data, + const enum usbd_speed speed) +{ + const struct device *dev = usbd_class_get_private(c_data); + struct cdc_acm_uart_data *data = dev->data; + + if (speed == USBD_SPEED_HS) { + return data->hs_desc; + } + + return data->fs_desc; +} + static void cdc_acm_update_uart_cfg(struct cdc_acm_uart_data *const data) { struct uart_config *const cfg = &data->uart_cfg; @@ -330,11 +384,11 @@ static void cdc_acm_update_linestate(struct cdc_acm_uart_data *const data) } } -static int usbd_cdc_acm_cth(struct usbd_class_node *const c_nd, +static int usbd_cdc_acm_cth(struct usbd_class_data *const c_data, const struct usb_setup_packet *const setup, struct net_buf *const buf) { - const struct device *dev = c_nd->data->priv; + const struct device *dev = usbd_class_get_private(c_data); struct cdc_acm_uart_data *data = dev->data; size_t min_len; @@ -357,12 +411,12 @@ static int usbd_cdc_acm_cth(struct usbd_class_node *const c_nd, return 0; } -static int usbd_cdc_acm_ctd(struct usbd_class_node *const c_nd, +static int usbd_cdc_acm_ctd(struct usbd_class_data *const c_data, const struct usb_setup_packet *const setup, const struct net_buf *const buf) { - struct usbd_contex *uds_ctx = c_nd->data->uds_ctx; - const struct device *dev = c_nd->data->priv; + struct usbd_contex *uds_ctx = usbd_class_get_ctx(c_data); + const struct device *dev = usbd_class_get_private(c_data); struct cdc_acm_uart_data *data = dev->data; size_t len; @@ -396,11 +450,13 @@ static int usbd_cdc_acm_ctd(struct usbd_class_node *const c_nd, return 0; } -static int usbd_cdc_acm_init(struct usbd_class_node *const c_nd) +static int usbd_cdc_acm_init(struct usbd_class_data *const c_data) { - struct usbd_cdc_acm_desc *desc = c_nd->data->desc; + const struct device *dev = usbd_class_get_private(c_data); + struct cdc_acm_uart_data *data = dev->data; + struct usbd_cdc_acm_desc *desc = data->desc; - desc->iad_cdc.bFirstInterface = desc->if0.bInterfaceNumber; + desc->iad.bFirstInterface = desc->if0.bInterfaceNumber; desc->if0_union.bControlInterface = desc->if0.bInterfaceNumber; desc->if0_union.bSubordinateInterface0 = desc->if1.bInterfaceNumber; @@ -419,7 +475,7 @@ static int cdc_acm_send_notification(const struct device *dev, .data = sys_cpu_to_le16(serial_state), }; struct cdc_acm_uart_data *data = dev->data; - struct usbd_class_node *c_nd = data->c_nd; + struct usbd_class_data *c_data = data->c_data; struct net_buf *buf; uint8_t ep; int ret; @@ -434,14 +490,14 @@ static int cdc_acm_send_notification(const struct device *dev, return -EACCES; } - ep = cdc_acm_get_int_in(c_nd); - buf = usbd_ep_buf_alloc(c_nd, ep, sizeof(struct cdc_acm_notification)); + ep = cdc_acm_get_int_in(c_data); + buf = usbd_ep_buf_alloc(c_data, ep, sizeof(struct cdc_acm_notification)); if (buf == NULL) { return -ENOMEM; } net_buf_add_mem(buf, ¬ification, sizeof(struct cdc_acm_notification)); - ret = usbd_ep_enqueue(c_nd, buf); + ret = usbd_ep_enqueue(c_data, buf); /* FIXME: support for sync transfers */ k_sem_take(&data->notif_sem, K_FOREVER); @@ -454,13 +510,13 @@ static int cdc_acm_send_notification(const struct device *dev, static void cdc_acm_tx_fifo_handler(struct k_work *work) { struct cdc_acm_uart_data *data; - struct usbd_class_node *c_nd; + struct usbd_class_data *c_data; struct net_buf *buf; size_t len; int ret; data = CONTAINER_OF(work, struct cdc_acm_uart_data, tx_fifo_work); - c_nd = data->c_nd; + c_data = data->c_data; if (!atomic_test_bit(&data->state, CDC_ACM_CLASS_ENABLED)) { LOG_DBG("USB configuration is not enabled"); @@ -477,7 +533,7 @@ static void cdc_acm_tx_fifo_handler(struct k_work *work) return; } - buf = cdc_acm_buf_alloc(cdc_acm_get_bulk_in(c_nd)); + buf = cdc_acm_buf_alloc(cdc_acm_get_bulk_in(c_data)); if (buf == NULL) { cdc_acm_work_submit(&data->tx_fifo_work); goto tx_fifo_handler_exit; @@ -486,7 +542,7 @@ static void cdc_acm_tx_fifo_handler(struct k_work *work) len = ring_buf_get(data->tx_fifo.rb, buf->data, buf->size); net_buf_add(buf, len); - ret = usbd_ep_enqueue(c_nd, buf); + ret = usbd_ep_enqueue(c_data, buf); if (ret) { LOG_ERR("Failed to enqueue"); net_buf_unref(buf); @@ -507,13 +563,13 @@ static void cdc_acm_tx_fifo_handler(struct k_work *work) static void cdc_acm_rx_fifo_handler(struct k_work *work) { struct cdc_acm_uart_data *data; - struct usbd_class_node *c_nd; + struct usbd_class_data *c_data; struct net_buf *buf; uint8_t ep; int ret; data = CONTAINER_OF(work, struct cdc_acm_uart_data, rx_fifo_work); - c_nd = data->c_nd; + c_data = data->c_data; if (!atomic_test_bit(&data->state, CDC_ACM_CLASS_ENABLED) || atomic_test_bit(&data->state, CDC_ACM_CLASS_SUSPENDED)) { @@ -521,7 +577,7 @@ static void cdc_acm_rx_fifo_handler(struct k_work *work) return; } - if (ring_buf_space_get(data->rx_fifo.rb) < cdc_acm_get_bulk_mps(c_nd)) { + if (ring_buf_space_get(data->rx_fifo.rb) < cdc_acm_get_bulk_mps(c_data)) { LOG_INF("RX buffer to small, throttle"); return; } @@ -531,13 +587,13 @@ static void cdc_acm_rx_fifo_handler(struct k_work *work) return; } - ep = cdc_acm_get_bulk_out(c_nd); + ep = cdc_acm_get_bulk_out(c_data); buf = cdc_acm_buf_alloc(ep); if (buf == NULL) { return; } - ret = usbd_ep_enqueue(c_nd, buf); + ret = usbd_ep_enqueue(c_data, buf); if (ret) { LOG_ERR("Failed to enqueue net_buf for 0x%02x", ep); net_buf_unref(buf); @@ -727,10 +783,10 @@ static int cdc_acm_irq_update(const struct device *dev) static void cdc_acm_irq_cb_handler(struct k_work *work) { struct cdc_acm_uart_data *data; - struct usbd_class_node *c_nd; + struct usbd_class_data *c_data; data = CONTAINER_OF(work, struct cdc_acm_uart_data, irq_cb_work); - c_nd = data->c_nd; + c_data = data->c_data; if (data->cb == NULL) { LOG_ERR("IRQ callback is not set"); @@ -750,7 +806,7 @@ static void cdc_acm_irq_cb_handler(struct k_work *work) if (atomic_test_bit(&data->state, CDC_ACM_IRQ_RX_ENABLED) || atomic_test_bit(&data->state, CDC_ACM_IRQ_TX_ENABLED)) { - data->cb(c_nd->data->priv, data->cb_data); + data->cb(usbd_class_get_private(c_data), data->cb_data); } if (data->rx_fifo.altered) { @@ -996,11 +1052,12 @@ struct usbd_class_api usbd_cdc_acm_api = { .control_to_host = usbd_cdc_acm_cth, .control_to_dev = usbd_cdc_acm_ctd, .init = usbd_cdc_acm_init, + .get_desc = usbd_cdc_acm_get_desc, }; #define CDC_ACM_DEFINE_DESCRIPTOR(n) \ static struct usbd_cdc_acm_desc cdc_acm_desc_##n = { \ - .iad_cdc = { \ + .iad = { \ .bLength = sizeof(struct usb_association_descriptor), \ .bDescriptorType = USB_DESC_INTERFACE_ASSOC, \ .bFirstInterface = 0, \ @@ -1060,7 +1117,16 @@ static struct usbd_cdc_acm_desc cdc_acm_desc_##n = { \ .bEndpointAddress = 0x81, \ .bmAttributes = USB_EP_TYPE_INTERRUPT, \ .wMaxPacketSize = sys_cpu_to_le16(CDC_ACM_DEFAULT_INT_EP_MPS), \ - .bInterval = CDC_ACM_DEFAULT_INT_INTERVAL, \ + .bInterval = CDC_ACM_FS_INT_EP_INTERVAL, \ + }, \ + \ + .if0_hs_int_ep = { \ + .bLength = sizeof(struct usb_ep_descriptor), \ + .bDescriptorType = USB_DESC_ENDPOINT, \ + .bEndpointAddress = 0x81, \ + .bmAttributes = USB_EP_TYPE_INTERRUPT, \ + .wMaxPacketSize = sys_cpu_to_le16(CDC_ACM_DEFAULT_INT_EP_MPS), \ + .bInterval = CDC_ACM_HS_INT_EP_INTERVAL, \ }, \ \ .if1 = { \ @@ -1080,7 +1146,7 @@ static struct usbd_cdc_acm_desc cdc_acm_desc_##n = { \ .bDescriptorType = USB_DESC_ENDPOINT, \ .bEndpointAddress = 0x82, \ .bmAttributes = USB_EP_TYPE_BULK, \ - .wMaxPacketSize = sys_cpu_to_le16(CDC_ACM_DEFAULT_BULK_EP_MPS), \ + .wMaxPacketSize = sys_cpu_to_le16(64U), \ .bInterval = 0, \ }, \ \ @@ -1089,7 +1155,25 @@ static struct usbd_cdc_acm_desc cdc_acm_desc_##n = { \ .bDescriptorType = USB_DESC_ENDPOINT, \ .bEndpointAddress = 0x01, \ .bmAttributes = USB_EP_TYPE_BULK, \ - .wMaxPacketSize = sys_cpu_to_le16(CDC_ACM_DEFAULT_BULK_EP_MPS), \ + .wMaxPacketSize = sys_cpu_to_le16(64U), \ + .bInterval = 0, \ + }, \ + \ + .if1_hs_in_ep = { \ + .bLength = sizeof(struct usb_ep_descriptor), \ + .bDescriptorType = USB_DESC_ENDPOINT, \ + .bEndpointAddress = 0x82, \ + .bmAttributes = USB_EP_TYPE_BULK, \ + .wMaxPacketSize = sys_cpu_to_le16(512U), \ + .bInterval = 0, \ + }, \ + \ + .if1_hs_out_ep = { \ + .bLength = sizeof(struct usb_ep_descriptor), \ + .bDescriptorType = USB_DESC_ENDPOINT, \ + .bEndpointAddress = 0x01, \ + .bmAttributes = USB_EP_TYPE_BULK, \ + .wMaxPacketSize = sys_cpu_to_le16(512U), \ .bInterval = 0, \ }, \ \ @@ -1097,6 +1181,34 @@ static struct usbd_cdc_acm_desc cdc_acm_desc_##n = { \ .bLength = 0, \ .bDescriptorType = 0, \ }, \ +}; \ + \ +const static struct usb_desc_header *cdc_acm_fs_desc_##n[] = { \ + (struct usb_desc_header *) &cdc_acm_desc_##n.iad, \ + (struct usb_desc_header *) &cdc_acm_desc_##n.if0, \ + (struct usb_desc_header *) &cdc_acm_desc_##n.if0_header, \ + (struct usb_desc_header *) &cdc_acm_desc_##n.if0_cm, \ + (struct usb_desc_header *) &cdc_acm_desc_##n.if0_acm, \ + (struct usb_desc_header *) &cdc_acm_desc_##n.if0_union, \ + (struct usb_desc_header *) &cdc_acm_desc_##n.if0_int_ep, \ + (struct usb_desc_header *) &cdc_acm_desc_##n.if1, \ + (struct usb_desc_header *) &cdc_acm_desc_##n.if1_in_ep, \ + (struct usb_desc_header *) &cdc_acm_desc_##n.if1_out_ep, \ + (struct usb_desc_header *) &cdc_acm_desc_##n.nil_desc, \ +}; \ + \ +const static struct usb_desc_header *cdc_acm_hs_desc_##n[] = { \ + (struct usb_desc_header *) &cdc_acm_desc_##n.iad, \ + (struct usb_desc_header *) &cdc_acm_desc_##n.if0, \ + (struct usb_desc_header *) &cdc_acm_desc_##n.if0_header, \ + (struct usb_desc_header *) &cdc_acm_desc_##n.if0_cm, \ + (struct usb_desc_header *) &cdc_acm_desc_##n.if0_acm, \ + (struct usb_desc_header *) &cdc_acm_desc_##n.if0_union, \ + (struct usb_desc_header *) &cdc_acm_desc_##n.if0_hs_int_ep, \ + (struct usb_desc_header *) &cdc_acm_desc_##n.if1, \ + (struct usb_desc_header *) &cdc_acm_desc_##n.if1_hs_in_ep, \ + (struct usb_desc_header *) &cdc_acm_desc_##n.if1_hs_out_ep, \ + (struct usb_desc_header *) &cdc_acm_desc_##n.nil_desc, \ } #define USBD_CDC_ACM_DT_DEVICE_DEFINE(n) \ @@ -1106,26 +1218,22 @@ static struct usbd_cdc_acm_desc cdc_acm_desc_##n = { \ \ CDC_ACM_DEFINE_DESCRIPTOR(n); \ \ - static struct usbd_class_data usbd_cdc_acm_data_##n; \ - \ USBD_DEFINE_CLASS(cdc_acm_##n, \ &usbd_cdc_acm_api, \ - &usbd_cdc_acm_data_##n); \ + (void *)DEVICE_DT_GET(DT_DRV_INST(n)), NULL); \ \ RING_BUF_DECLARE(cdc_acm_rb_rx_##n, DT_INST_PROP(n, tx_fifo_size)); \ RING_BUF_DECLARE(cdc_acm_rb_tx_##n, DT_INST_PROP(n, tx_fifo_size)); \ \ static struct cdc_acm_uart_data uart_data_##n = { \ .line_coding = CDC_ACM_DEFAULT_LINECODING, \ - .c_nd = &cdc_acm_##n, \ + .c_data = &cdc_acm_##n, \ .rx_fifo.rb = &cdc_acm_rb_rx_##n, \ .tx_fifo.rb = &cdc_acm_rb_tx_##n, \ .notif_sem = Z_SEM_INITIALIZER(uart_data_##n.notif_sem, 0, 1), \ - }; \ - \ - static struct usbd_class_data usbd_cdc_acm_data_##n = { \ - .desc = (struct usb_desc_header *)&cdc_acm_desc_##n, \ - .priv = (void *)DEVICE_DT_GET(DT_DRV_INST(n)), \ + .desc = &cdc_acm_desc_##n, \ + .fs_desc = cdc_acm_fs_desc_##n, \ + .hs_desc = cdc_acm_hs_desc_##n, \ }; \ \ DEVICE_DT_INST_DEFINE(n, usbd_cdc_acm_preinit, NULL, \ diff --git a/subsys/usb/device_next/class/usbd_cdc_ecm.c b/subsys/usb/device_next/class/usbd_cdc_ecm.c index 6f7200c40a9..7b3305bf343 100644 --- a/subsys/usb/device_next/class/usbd_cdc_ecm.c +++ b/subsys/usb/device_next/class/usbd_cdc_ecm.c @@ -20,9 +20,10 @@ #include LOG_MODULE_REGISTER(cdc_ecm, CONFIG_USBD_CDC_ECM_LOG_LEVEL); -#define CDC_ECM_EP_MPS_BULK 0 #define CDC_ECM_EP_MPS_INT 16 -#define CDC_ECM_EP_INTERVAL_INT 0x0A +#define CDC_ECM_INTERVAL_DEFAULT 10000UL +#define CDC_ECM_FS_INT_EP_INTERVAL USB_FS_INT_EP_INTERVAL(10000U) +#define CDC_ECM_HS_INT_EP_INTERVAL USB_HS_INT_EP_INTERVAL(10000U) enum { CDC_ECM_IFACE_UP, @@ -51,18 +52,11 @@ struct cdc_ecm_notification { uint16_t wLength; } __packed; -struct cdc_ecm_eth_data { - struct usbd_class_node *c_nd; - struct usbd_desc_node *const mac_desc_nd; - - struct net_if *iface; - uint8_t mac_addr[6]; - - struct k_sem sync_sem; - struct k_sem notif_sem; - atomic_t state; -}; - +/* + * Collection of descriptors used to assemble specific function descriptors. + * This structure is used by CDC ECM implementation to update and fetch + * properties at runtime. We currently support full and high speed. + */ struct usbd_cdc_ecm_desc { struct usb_association_descriptor iad; @@ -71,40 +65,90 @@ struct usbd_cdc_ecm_desc { struct cdc_union_descriptor if0_union; struct cdc_ecm_descriptor if0_ecm; struct usb_ep_descriptor if0_int_ep; + struct usb_ep_descriptor if0_hs_int_ep; struct usb_if_descriptor if1_0; struct usb_if_descriptor if1_1; struct usb_ep_descriptor if1_1_in_ep; struct usb_ep_descriptor if1_1_out_ep; + struct usb_ep_descriptor if1_1_hs_in_ep; + struct usb_ep_descriptor if1_1_hs_out_ep; struct usb_desc_header nil_desc; -} __packed; +}; + +struct cdc_ecm_eth_data { + struct usbd_class_data *c_data; + struct usbd_desc_node *const mac_desc_data; + struct usbd_cdc_ecm_desc *const desc; + const struct usb_desc_header **const fs_desc; + const struct usb_desc_header **const hs_desc; + + struct net_if *iface; + uint8_t mac_addr[6]; + + struct k_sem sync_sem; + struct k_sem notif_sem; + atomic_t state; +}; -static uint8_t cdc_ecm_get_ctrl_if(struct usbd_class_node *const c_nd) +static uint8_t cdc_ecm_get_ctrl_if(struct cdc_ecm_eth_data *const data) { - struct usbd_cdc_ecm_desc *desc = c_nd->data->desc; + struct usbd_cdc_ecm_desc *desc = data->desc; return desc->if0.bInterfaceNumber; } -static uint8_t cdc_ecm_get_int_in(struct usbd_class_node *const c_nd) +static uint8_t cdc_ecm_get_int_in(struct usbd_class_data *const c_data) { - struct usbd_cdc_ecm_desc *desc = c_nd->data->desc; + struct usbd_contex *uds_ctx = usbd_class_get_ctx(c_data); + const struct device *dev = usbd_class_get_private(c_data); + struct cdc_ecm_eth_data *data = dev->data; + struct usbd_cdc_ecm_desc *desc = data->desc; + + if (usbd_bus_speed(uds_ctx) == USBD_SPEED_HS) { + return desc->if0_hs_int_ep.bEndpointAddress; + } return desc->if0_int_ep.bEndpointAddress; } -static uint8_t cdc_ecm_get_bulk_in(struct usbd_class_node *const c_nd) +static uint8_t cdc_ecm_get_bulk_in(struct usbd_class_data *const c_data) { - struct usbd_cdc_ecm_desc *desc = c_nd->data->desc; + struct usbd_contex *uds_ctx = usbd_class_get_ctx(c_data); + const struct device *dev = usbd_class_get_private(c_data); + struct cdc_ecm_eth_data *data = dev->data; + struct usbd_cdc_ecm_desc *desc = data->desc; + + if (usbd_bus_speed(uds_ctx) == USBD_SPEED_HS) { + return desc->if1_1_hs_in_ep.bEndpointAddress; + } return desc->if1_1_in_ep.bEndpointAddress; } -static uint8_t cdc_ecm_get_bulk_out(struct usbd_class_node *const c_nd) +static uint16_t cdc_ecm_get_bulk_in_mps(struct usbd_class_data *const c_data) { - struct usbd_cdc_ecm_desc *desc = c_nd->data->desc; + struct usbd_contex *uds_ctx = usbd_class_get_ctx(c_data); + + if (usbd_bus_speed(uds_ctx) == USBD_SPEED_HS) { + return 512U; + } + + return 64U; +} + +static uint8_t cdc_ecm_get_bulk_out(struct usbd_class_data *const c_data) +{ + struct usbd_contex *uds_ctx = usbd_class_get_ctx(c_data); + const struct device *dev = usbd_class_get_private(c_data); + struct cdc_ecm_eth_data *data = dev->data; + struct usbd_cdc_ecm_desc *desc = data->desc; + + if (usbd_bus_speed(uds_ctx) == USBD_SPEED_HS) { + return desc->if1_1_hs_out_ep.bEndpointAddress; + } return desc->if1_1_out_ep.bEndpointAddress; } @@ -155,9 +199,9 @@ static size_t ecm_eth_size(void *const ecm_pkt, const size_t len) return sizeof(struct net_eth_hdr) + ip_len; } -static int cdc_ecm_out_start(struct usbd_class_node *const c_nd) +static int cdc_ecm_out_start(struct usbd_class_data *const c_data) { - const struct device *dev = c_nd->data->priv; + const struct device *dev = usbd_class_get_private(c_data); struct cdc_ecm_eth_data *data = dev->data; struct net_buf *buf; uint8_t ep; @@ -171,13 +215,13 @@ static int cdc_ecm_out_start(struct usbd_class_node *const c_nd) return -EBUSY; } - ep = cdc_ecm_get_bulk_out(c_nd); + ep = cdc_ecm_get_bulk_out(c_data); buf = cdc_ecm_buf_alloc(ep); if (buf == NULL) { return -ENOMEM; } - ret = usbd_ep_enqueue(c_nd, buf); + ret = usbd_ep_enqueue(c_data, buf); if (ret) { LOG_ERR("Failed to enqueue net_buf for 0x%02x", ep); net_buf_unref(buf); @@ -186,10 +230,10 @@ static int cdc_ecm_out_start(struct usbd_class_node *const c_nd) return ret; } -static int cdc_ecm_acl_out_cb(struct usbd_class_node *const c_nd, +static int cdc_ecm_acl_out_cb(struct usbd_class_data *const c_data, struct net_buf *const buf, const int err) { - const struct device *dev = c_nd->data->priv; + const struct device *dev = usbd_class_get_private(c_data); struct cdc_ecm_eth_data *data = dev->data; struct net_pkt *pkt; @@ -233,30 +277,30 @@ static int cdc_ecm_acl_out_cb(struct usbd_class_node *const c_nd, net_buf_unref(buf); atomic_clear_bit(&data->state, CDC_ECM_OUT_ENGAGED); - return cdc_ecm_out_start(c_nd); + return cdc_ecm_out_start(c_data); } -static int usbd_cdc_ecm_request(struct usbd_class_node *const c_nd, +static int usbd_cdc_ecm_request(struct usbd_class_data *const c_data, struct net_buf *buf, int err) { - struct usbd_contex *uds_ctx = c_nd->data->uds_ctx; - const struct device *dev = c_nd->data->priv; + struct usbd_contex *uds_ctx = usbd_class_get_ctx(c_data); + const struct device *dev = usbd_class_get_private(c_data); struct cdc_ecm_eth_data *data = dev->data; struct udc_buf_info *bi; bi = udc_get_buf_info(buf); - if (bi->ep == cdc_ecm_get_bulk_out(c_nd)) { - return cdc_ecm_acl_out_cb(c_nd, buf, err); + if (bi->ep == cdc_ecm_get_bulk_out(c_data)) { + return cdc_ecm_acl_out_cb(c_data, buf, err); } - if (bi->ep == cdc_ecm_get_bulk_in(c_nd)) { + if (bi->ep == cdc_ecm_get_bulk_in(c_data)) { k_sem_give(&data->sync_sem); return 0; } - if (bi->ep == cdc_ecm_get_int_in(c_nd)) { + if (bi->ep == cdc_ecm_get_int_in(c_data)) { k_sem_give(&data->notif_sem); return 0; @@ -269,7 +313,7 @@ static int cdc_ecm_send_notification(const struct device *dev, const bool connected) { struct cdc_ecm_eth_data *data = dev->data; - struct usbd_class_node *c_nd = data->c_nd; + struct usbd_class_data *c_data = data->c_data; struct cdc_ecm_notification notification = { .RequestType = { .direction = USB_REQTYPE_DIR_TO_HOST, @@ -278,7 +322,7 @@ static int cdc_ecm_send_notification(const struct device *dev, }, .bNotificationType = USB_CDC_NETWORK_CONNECTION, .wValue = sys_cpu_to_le16((uint16_t)connected), - .wIndex = sys_cpu_to_le16(cdc_ecm_get_ctrl_if(c_nd)), + .wIndex = sys_cpu_to_le16(cdc_ecm_get_ctrl_if(data)), .wLength = 0, }; struct net_buf *buf; @@ -295,14 +339,14 @@ static int cdc_ecm_send_notification(const struct device *dev, return 0; } - ep = cdc_ecm_get_int_in(c_nd); - buf = usbd_ep_buf_alloc(c_nd, ep, sizeof(struct cdc_ecm_notification)); + ep = cdc_ecm_get_int_in(c_data); + buf = usbd_ep_buf_alloc(c_data, ep, sizeof(struct cdc_ecm_notification)); if (buf == NULL) { return -ENOMEM; } net_buf_add_mem(buf, ¬ification, sizeof(struct cdc_ecm_notification)); - ret = usbd_ep_enqueue(c_nd, buf); + ret = usbd_ep_enqueue(c_data, buf); if (ret) { LOG_ERR("Failed to enqueue net_buf for 0x%02x", ep); net_buf_unref(buf); @@ -315,13 +359,13 @@ static int cdc_ecm_send_notification(const struct device *dev, return 0; } -static void usbd_cdc_ecm_update(struct usbd_class_node *const c_nd, +static void usbd_cdc_ecm_update(struct usbd_class_data *const c_data, const uint8_t iface, const uint8_t alternate) { - struct usbd_cdc_ecm_desc *desc = c_nd->data->desc; - const uint8_t data_iface = desc->if1_1.bInterfaceNumber; - const struct device *dev = c_nd->data->priv; + const struct device *dev = usbd_class_get_private(c_data); struct cdc_ecm_eth_data *data = dev->data; + struct usbd_cdc_ecm_desc *desc = data->desc; + const uint8_t data_iface = desc->if1_1.bInterfaceNumber; LOG_INF("New configuration, interface %u alternate %u", iface, alternate); @@ -332,25 +376,25 @@ static void usbd_cdc_ecm_update(struct usbd_class_node *const c_nd, if (data_iface == iface && alternate == 1) { net_if_carrier_on(data->iface); - if (cdc_ecm_out_start(c_nd)) { + if (cdc_ecm_out_start(c_data)) { LOG_ERR("Failed to start OUT transfer"); } } } -static void usbd_cdc_ecm_enable(struct usbd_class_node *const c_nd) +static void usbd_cdc_ecm_enable(struct usbd_class_data *const c_data) { - const struct device *dev = c_nd->data->priv; + const struct device *dev = usbd_class_get_private(c_data); struct cdc_ecm_eth_data *data = dev->data; atomic_set_bit(&data->state, CDC_ECM_CLASS_ENABLED); - LOG_INF("Configuration enabled"); + LOG_DBG("Configuration enabled"); } -static void usbd_cdc_ecm_disable(struct usbd_class_node *const c_nd) +static void usbd_cdc_ecm_disable(struct usbd_class_data *const c_data) { - const struct device *dev = c_nd->data->priv; + const struct device *dev = usbd_class_get_private(c_data); struct cdc_ecm_eth_data *data = dev->data; if (atomic_test_and_clear_bit(&data->state, CDC_ECM_CLASS_ENABLED)) { @@ -361,23 +405,23 @@ static void usbd_cdc_ecm_disable(struct usbd_class_node *const c_nd) LOG_INF("Configuration disabled"); } -static void usbd_cdc_ecm_suspended(struct usbd_class_node *const c_nd) +static void usbd_cdc_ecm_suspended(struct usbd_class_data *const c_data) { - const struct device *dev = c_nd->data->priv; + const struct device *dev = usbd_class_get_private(c_data); struct cdc_ecm_eth_data *data = dev->data; atomic_set_bit(&data->state, CDC_ECM_CLASS_SUSPENDED); } -static void usbd_cdc_ecm_resumed(struct usbd_class_node *const c_nd) +static void usbd_cdc_ecm_resumed(struct usbd_class_data *const c_data) { - const struct device *dev = c_nd->data->priv; + const struct device *dev = usbd_class_get_private(c_data); struct cdc_ecm_eth_data *data = dev->data; atomic_clear_bit(&data->state, CDC_ECM_CLASS_SUSPENDED); } -static int usbd_cdc_ecm_ctd(struct usbd_class_node *const c_nd, +static int usbd_cdc_ecm_ctd(struct usbd_class_data *const c_data, const struct usb_setup_packet *const setup, const struct net_buf *const buf) { @@ -396,12 +440,13 @@ static int usbd_cdc_ecm_ctd(struct usbd_class_node *const c_nd, return 0; } -static int usbd_cdc_ecm_init(struct usbd_class_node *const c_nd) +static int usbd_cdc_ecm_init(struct usbd_class_data *const c_data) { - struct usbd_cdc_ecm_desc *desc = c_nd->data->desc; - const uint8_t if_num = desc->if0.bInterfaceNumber; - const struct device *dev = c_nd->data->priv; + struct usbd_contex *uds_ctx = usbd_class_get_ctx(c_data); + const struct device *dev = usbd_class_get_private(c_data); struct cdc_ecm_eth_data *const data = dev->data; + struct usbd_cdc_ecm_desc *desc = data->desc; + const uint8_t if_num = desc->if0.bInterfaceNumber; /* Update relevant b*Interface fields */ desc->iad.bFirstInterface = if_num; @@ -409,32 +454,44 @@ static int usbd_cdc_ecm_init(struct usbd_class_node *const c_nd) desc->if0_union.bSubordinateInterface0 = if_num + 1; LOG_DBG("CDC ECM class initialized"); - if (usbd_add_descriptor(c_nd->data->uds_ctx, data->mac_desc_nd)) { + if (usbd_add_descriptor(uds_ctx, data->mac_desc_data)) { LOG_ERR("Failed to add iMACAddress string descriptor"); } else { - desc->if0_ecm.iMACAddress = data->mac_desc_nd->idx; + desc->if0_ecm.iMACAddress = usbd_str_desc_get_idx(data->mac_desc_data); } return 0; } -static void usbd_cdc_ecm_shutdown(struct usbd_class_node *const c_nd) +static void usbd_cdc_ecm_shutdown(struct usbd_class_data *const c_data) { - struct usbd_cdc_ecm_desc *desc = c_nd->data->desc; - const struct device *dev = c_nd->data->priv; + const struct device *dev = usbd_class_get_private(c_data); struct cdc_ecm_eth_data *const data = dev->data; + struct usbd_cdc_ecm_desc *desc = data->desc; desc->if0_ecm.iMACAddress = 0; - sys_dlist_remove(&data->mac_desc_nd->node); + sys_dlist_remove(&data->mac_desc_data->node); +} + +static void *usbd_cdc_ecm_get_desc(struct usbd_class_data *const c_data, + const enum usbd_speed speed) +{ + const struct device *dev = usbd_class_get_private(c_data); + struct cdc_ecm_eth_data *const data = dev->data; + + if (speed == USBD_SPEED_HS) { + return data->hs_desc; + } + + return data->fs_desc; } static int cdc_ecm_send(const struct device *dev, struct net_pkt *const pkt) { struct cdc_ecm_eth_data *const data = dev->data; - struct usbd_class_node *c_nd = data->c_nd; + struct usbd_class_data *c_data = data->c_data; size_t len = net_pkt_get_len(pkt); struct net_buf *buf; - uint16_t bulk_mps; if (len > NET_ETH_MAX_FRAME_SIZE) { LOG_WRN("Trying to send too large packet, drop"); @@ -447,7 +504,7 @@ static int cdc_ecm_send(const struct device *dev, struct net_pkt *const pkt) return -EACCES; } - buf = cdc_ecm_buf_alloc(cdc_ecm_get_bulk_in(c_nd)); + buf = cdc_ecm_buf_alloc(cdc_ecm_get_bulk_in(c_data)); if (buf == NULL) { LOG_ERR("Failed to allocate buffer"); return -ENOMEM; @@ -462,21 +519,11 @@ static int cdc_ecm_send(const struct device *dev, struct net_pkt *const pkt) net_buf_add(buf, len); - /* - * REVISE: It should be more abstract and - * not pull UDC stuff in the class code. - */ - if (udc_device_speed(c_nd->data->uds_ctx->dev) == UDC_BUS_SPEED_FS) { - bulk_mps = 64; - } else { - bulk_mps = 512; - } - - if (!(buf->len % bulk_mps)) { + if (!(buf->len % cdc_ecm_get_bulk_in_mps(c_data))) { udc_ep_buf_set_zlp(buf); } - usbd_ep_enqueue(c_nd, buf); + usbd_ep_enqueue(c_data, buf); k_sem_take(&data->sync_sem, K_FOREVER); net_buf_unref(buf); @@ -580,6 +627,7 @@ static struct usbd_class_api usbd_cdc_ecm_api = { .control_to_dev = usbd_cdc_ecm_ctd, .init = usbd_cdc_ecm_init, .shutdown = usbd_cdc_ecm_shutdown, + .get_desc = usbd_cdc_ecm_get_desc, }; static const struct ethernet_api cdc_ecm_eth_api = { @@ -649,7 +697,16 @@ static struct usbd_cdc_ecm_desc cdc_ecm_desc_##n = { \ .bEndpointAddress = 0x81, \ .bmAttributes = USB_EP_TYPE_INTERRUPT, \ .wMaxPacketSize = sys_cpu_to_le16(CDC_ECM_EP_MPS_INT), \ - .bInterval = CDC_ECM_EP_INTERVAL_INT, \ + .bInterval = CDC_ECM_FS_INT_EP_INTERVAL, \ + }, \ + \ + .if0_hs_int_ep = { \ + .bLength = sizeof(struct usb_ep_descriptor), \ + .bDescriptorType = USB_DESC_ENDPOINT, \ + .bEndpointAddress = 0x81, \ + .bmAttributes = USB_EP_TYPE_INTERRUPT, \ + .wMaxPacketSize = sys_cpu_to_le16(CDC_ECM_EP_MPS_INT), \ + .bInterval = CDC_ECM_HS_INT_EP_INTERVAL, \ }, \ \ .if1_0 = { \ @@ -681,7 +738,7 @@ static struct usbd_cdc_ecm_desc cdc_ecm_desc_##n = { \ .bDescriptorType = USB_DESC_ENDPOINT, \ .bEndpointAddress = 0x82, \ .bmAttributes = USB_EP_TYPE_BULK, \ - .wMaxPacketSize = sys_cpu_to_le16(CDC_ECM_EP_MPS_BULK), \ + .wMaxPacketSize = sys_cpu_to_le16(64U), \ .bInterval = 0, \ }, \ \ @@ -690,7 +747,25 @@ static struct usbd_cdc_ecm_desc cdc_ecm_desc_##n = { \ .bDescriptorType = USB_DESC_ENDPOINT, \ .bEndpointAddress = 0x01, \ .bmAttributes = USB_EP_TYPE_BULK, \ - .wMaxPacketSize = sys_cpu_to_le16(CDC_ECM_EP_MPS_BULK), \ + .wMaxPacketSize = sys_cpu_to_le16(64U), \ + .bInterval = 0, \ + }, \ + \ + .if1_1_hs_in_ep = { \ + .bLength = sizeof(struct usb_ep_descriptor), \ + .bDescriptorType = USB_DESC_ENDPOINT, \ + .bEndpointAddress = 0x82, \ + .bmAttributes = USB_EP_TYPE_BULK, \ + .wMaxPacketSize = sys_cpu_to_le16(512U), \ + .bInterval = 0, \ + }, \ + \ + .if1_1_hs_out_ep = { \ + .bLength = sizeof(struct usb_ep_descriptor), \ + .bDescriptorType = USB_DESC_ENDPOINT, \ + .bEndpointAddress = 0x01, \ + .bmAttributes = USB_EP_TYPE_BULK, \ + .wMaxPacketSize = sys_cpu_to_le16(512U), \ .bInterval = 0, \ }, \ \ @@ -698,31 +773,55 @@ static struct usbd_cdc_ecm_desc cdc_ecm_desc_##n = { \ .bLength = 0, \ .bDescriptorType = 0, \ }, \ -} +}; \ + \ + const static struct usb_desc_header *cdc_ecm_fs_desc_##n[] = { \ + (struct usb_desc_header *) &cdc_ecm_desc_##n.iad, \ + (struct usb_desc_header *) &cdc_ecm_desc_##n.if0, \ + (struct usb_desc_header *) &cdc_ecm_desc_##n.if0_header, \ + (struct usb_desc_header *) &cdc_ecm_desc_##n.if0_union, \ + (struct usb_desc_header *) &cdc_ecm_desc_##n.if0_ecm, \ + (struct usb_desc_header *) &cdc_ecm_desc_##n.if0_int_ep, \ + (struct usb_desc_header *) &cdc_ecm_desc_##n.if1_0, \ + (struct usb_desc_header *) &cdc_ecm_desc_##n.if1_1, \ + (struct usb_desc_header *) &cdc_ecm_desc_##n.if1_1_in_ep, \ + (struct usb_desc_header *) &cdc_ecm_desc_##n.if1_1_out_ep, \ + (struct usb_desc_header *) &cdc_ecm_desc_##n.nil_desc, \ + }; \ + \ + const static struct usb_desc_header *cdc_ecm_hs_desc_##n[] = { \ + (struct usb_desc_header *) &cdc_ecm_desc_##n.iad, \ + (struct usb_desc_header *) &cdc_ecm_desc_##n.if0, \ + (struct usb_desc_header *) &cdc_ecm_desc_##n.if0_header, \ + (struct usb_desc_header *) &cdc_ecm_desc_##n.if0_union, \ + (struct usb_desc_header *) &cdc_ecm_desc_##n.if0_ecm, \ + (struct usb_desc_header *) &cdc_ecm_desc_##n.if0_hs_int_ep, \ + (struct usb_desc_header *) &cdc_ecm_desc_##n.if1_0, \ + (struct usb_desc_header *) &cdc_ecm_desc_##n.if1_1, \ + (struct usb_desc_header *) &cdc_ecm_desc_##n.if1_1_hs_in_ep, \ + (struct usb_desc_header *) &cdc_ecm_desc_##n.if1_1_hs_out_ep, \ + (struct usb_desc_header *) &cdc_ecm_desc_##n.nil_desc, \ + } #define USBD_CDC_ECM_DT_DEVICE_DEFINE(n) \ CDC_ECM_DEFINE_DESCRIPTOR(n); \ - USBD_DESC_STRING_DEFINE(mac_desc_nd_##n, \ + USBD_DESC_STRING_DEFINE(mac_desc_data_##n, \ DT_INST_PROP(n, remote_mac_address), \ USBD_DUT_STRING_INTERFACE); \ \ - static struct usbd_class_data usbd_cdc_ecm_data_##n; \ - \ USBD_DEFINE_CLASS(cdc_ecm_##n, \ &usbd_cdc_ecm_api, \ - &usbd_cdc_ecm_data_##n); \ + (void *)DEVICE_DT_GET(DT_DRV_INST(n)), NULL); \ \ static struct cdc_ecm_eth_data eth_data_##n = { \ - .c_nd = &cdc_ecm_##n, \ + .c_data = &cdc_ecm_##n, \ .mac_addr = DT_INST_PROP_OR(n, local_mac_address, {0}), \ .sync_sem = Z_SEM_INITIALIZER(eth_data_##n.sync_sem, 0, 1), \ .notif_sem = Z_SEM_INITIALIZER(eth_data_##n.notif_sem, 0, 1), \ - .mac_desc_nd = &mac_desc_nd_##n, \ - }; \ - \ - static struct usbd_class_data usbd_cdc_ecm_data_##n = { \ - .desc = (struct usb_desc_header *)&cdc_ecm_desc_##n, \ - .priv = (void *)DEVICE_DT_GET(DT_DRV_INST(n)), \ + .mac_desc_data = &mac_desc_data_##n, \ + .desc = &cdc_ecm_desc_##n, \ + .fs_desc = cdc_ecm_fs_desc_##n, \ + .hs_desc = cdc_ecm_hs_desc_##n, \ }; \ \ ETH_NET_DEVICE_DT_INST_DEFINE(n, usbd_cdc_ecm_preinit, NULL, \ diff --git a/subsys/usb/device_next/class/usbd_hid.c b/subsys/usb/device_next/class/usbd_hid.c new file mode 100644 index 00000000000..befdc9db9cc --- /dev/null +++ b/subsys/usb/device_next/class/usbd_hid.c @@ -0,0 +1,744 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT zephyr_hid_device + +#include "usbd_hid_internal.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(usbd_hid, CONFIG_USBD_HID_LOG_LEVEL); + +#define HID_GET_IDLE_DURATION(wValue) ((wValue) >> 8) +#define HID_GET_IDLE_ID(wValue) (wValue) +#define HID_GET_REPORT_TYPE(wValue) ((wValue) >> 8) +#define HID_GET_REPORT_ID(wValue) (wValue) + +#define HID_SUBORDINATE_DESC_NUM 1 + +struct subordinate_info { + uint8_t bDescriptorType; + uint16_t wDescriptorLength; +} __packed; + +/* See HID spec. 6.2 Class-Specific Descriptors */ +struct hid_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t bcdHID; + uint8_t bCountryCode; + uint8_t bNumDescriptors; + /* At least report subordinate descriptor is required. */ + struct subordinate_info sub[HID_SUBORDINATE_DESC_NUM]; +} __packed; + +struct usbd_hid_descriptor { + struct usb_if_descriptor if0; + struct hid_descriptor hid; + struct usb_ep_descriptor in_ep; + struct usb_ep_descriptor hs_in_ep; + struct usb_ep_descriptor out_ep; + struct usb_ep_descriptor hs_out_ep; + + struct usb_if_descriptor if0_1; + struct usb_ep_descriptor alt_hs_in_ep; + struct usb_ep_descriptor alt_hs_out_ep; +}; + +enum { + HID_DEV_CLASS_ENABLED, +}; + +struct hid_device_data { + struct usbd_hid_descriptor *const desc; + struct usbd_class_data *c_data; + struct net_buf_pool *const pool_out; + struct net_buf_pool *const pool_in; + const struct hid_device_ops *ops; + const uint8_t *rdesc; + size_t rsize; + const struct usb_desc_header **const fs_desc; + const struct usb_desc_header **const hs_desc; + atomic_t state; + struct k_sem in_sem; + struct k_work output_work; + uint8_t idle_rate; + uint8_t protocol; +}; + +static inline uint8_t hid_get_in_ep(struct usbd_class_data *const c_data) +{ + const struct device *dev = usbd_class_get_private(c_data); + struct hid_device_data *ddata = dev->data; + struct usbd_hid_descriptor *desc = ddata->desc; + + return desc->in_ep.bEndpointAddress; +} + +static inline uint8_t hid_get_out_ep(struct usbd_class_data *const c_data) +{ + const struct device *dev = usbd_class_get_private(c_data); + struct hid_device_data *ddata = dev->data; + struct usbd_hid_descriptor *desc = ddata->desc; + + return desc->out_ep.bEndpointAddress; +} + +static int usbd_hid_request(struct usbd_class_data *const c_data, + struct net_buf *const buf, const int err) +{ + struct usbd_contex *uds_ctx = usbd_class_get_ctx(c_data); + const struct device *dev = usbd_class_get_private(c_data); + struct hid_device_data *ddata = dev->data; + const struct hid_device_ops *ops = ddata->ops; + struct udc_buf_info *bi; + + bi = udc_get_buf_info(buf); + + if (bi->ep == hid_get_out_ep(c_data)) { + if (ops->output_report != NULL) { + if (err == 0) { + ops->output_report(dev, buf->len, buf->data); + } + + k_work_submit(&ddata->output_work); + } + } + + if (bi->ep == hid_get_in_ep(c_data)) { + if (ops->input_report_done != NULL) { + ops->input_report_done(dev); + } else { + k_sem_give(&ddata->in_sem); + } + } + + return usbd_ep_buf_free(uds_ctx, buf); +} + +static int handle_set_idle(const struct device *dev, + const struct usb_setup_packet *const setup) +{ + const uint32_t duration = HID_GET_IDLE_DURATION(setup->wValue); + const uint8_t id = HID_GET_IDLE_ID(setup->wValue); + struct hid_device_data *const ddata = dev->data; + const struct hid_device_ops *ops = ddata->ops; + + if (id == 0U) { + /* Only the common idle rate is stored. */ + ddata->idle_rate = duration; + } + + if (ops->set_idle != NULL) { + ops->set_idle(dev, id, duration * 4UL); + } else { + errno = -ENOTSUP; + } + + LOG_DBG("Set Idle, Report ID %u Duration %u", id, duration); + + return 0; +} + +static int handle_get_idle(const struct device *dev, + const struct usb_setup_packet *const setup, + struct net_buf *const buf) +{ + const uint8_t id = HID_GET_IDLE_ID(setup->wValue); + struct hid_device_data *const ddata = dev->data; + const struct hid_device_ops *ops = ddata->ops; + uint32_t duration; + + if (setup->wLength != 1U) { + errno = -ENOTSUP; + return 0; + } + + /* + * There is no Get Idle callback in the leagacy API, do not issue a + * protocol error if no callback is provided but ID is 0. + */ + if (id != 0U && ops->get_idle == NULL) { + errno = -ENOTSUP; + return 0; + } + + if (id == 0U) { + /* Only the common idle rate is stored. */ + duration = ddata->idle_rate; + } else { + duration = ops->get_idle(dev, id) / 4UL; + } + + LOG_DBG("Get Idle, Report ID %u Duration %u", id, duration); + net_buf_add_u8(buf, duration); + + return 0; +} + +static int handle_set_report(const struct device *dev, + const struct usb_setup_packet *const setup, + const struct net_buf *const buf) +{ + const uint8_t type = HID_GET_REPORT_TYPE(setup->wValue); + const uint8_t id = HID_GET_REPORT_ID(setup->wValue); + struct hid_device_data *const ddata = dev->data; + const struct hid_device_ops *ops = ddata->ops; + + if (ops->set_report == NULL) { + errno = -ENOTSUP; + LOG_DBG("Set Report not supported"); + return 0; + } + + switch (type) { + case HID_REPORT_TYPE_INPUT: + LOG_DBG("Set Report, Input Report ID %u", id); + errno = ops->set_report(dev, type, id, buf->len, buf->data); + break; + case HID_REPORT_TYPE_OUTPUT: + LOG_DBG("Set Report, Output Report ID %u", id); + errno = ops->set_report(dev, type, id, buf->len, buf->data); + break; + case HID_REPORT_TYPE_FEATURE: + LOG_DBG("Set Report, Feature Report ID %u", id); + errno = ops->set_report(dev, type, id, buf->len, buf->data); + break; + default: + errno = -ENOTSUP; + break; + } + + return 0; +} + +static int handle_get_report(const struct device *dev, + const struct usb_setup_packet *const setup, + struct net_buf *const buf) +{ + const uint8_t type = HID_GET_REPORT_TYPE(setup->wValue); + const uint8_t id = HID_GET_REPORT_ID(setup->wValue); + struct hid_device_data *const ddata = dev->data; + const struct hid_device_ops *ops = ddata->ops; + + switch (type) { + case HID_REPORT_TYPE_INPUT: + LOG_DBG("Get Report, Input Report ID %u", id); + errno = ops->get_report(dev, type, id, net_buf_tailroom(buf), buf->data); + break; + case HID_REPORT_TYPE_OUTPUT: + LOG_DBG("Get Report, Output Report ID %u", id); + errno = ops->get_report(dev, type, id, net_buf_tailroom(buf), buf->data); + break; + case HID_REPORT_TYPE_FEATURE: + LOG_DBG("Get Report, Feature Report ID %u", id); + errno = ops->get_report(dev, type, id, net_buf_tailroom(buf), buf->data); + break; + default: + errno = -ENOTSUP; + break; + } + + return 0; +} + +static int handle_set_protocol(const struct device *dev, + const struct usb_setup_packet *const setup) +{ + struct hid_device_data *const ddata = dev->data; + struct usbd_hid_descriptor *const desc = ddata->desc; + const struct hid_device_ops *const ops = ddata->ops; + const uint16_t protocol = setup->wValue; + + if (protocol > HID_PROTOCOL_REPORT) { + /* Can only be 0 (Boot Protocol) or 1 (Report Protocol). */ + errno = -ENOTSUP; + return 0; + } + + if (desc->if0.bInterfaceSubClass == 0) { + /* + * The device does not support the boot protocol and we will + * not notify it. + */ + errno = -ENOTSUP; + return 0; + } + + LOG_DBG("Set Protocol: %s", protocol ? "Report" : "Boot"); + + if (ddata->protocol != protocol) { + ddata->protocol = protocol; + + if (ops->set_protocol) { + ops->set_protocol(dev, protocol); + } + } + + return 0; +} + +static int handle_get_protocol(const struct device *dev, + const struct usb_setup_packet *const setup, + struct net_buf *const buf) +{ + struct hid_device_data *const ddata = dev->data; + struct usbd_hid_descriptor *const desc = ddata->desc; + + if (setup->wValue != 0 || setup->wLength != 1) { + errno = -ENOTSUP; + return 0; + } + + if (desc->if0.bInterfaceSubClass == 0) { + /* The device does not support the boot protocol */ + errno = -ENOTSUP; + return 0; + } + + LOG_DBG("Get Protocol: %s", ddata->protocol ? "Report" : "Boot"); + net_buf_add_u8(buf, ddata->protocol); + + return 0; +} + +static int handle_get_descriptor(const struct device *dev, + const struct usb_setup_packet *const setup, + struct net_buf *const buf) +{ + struct hid_device_data *const ddata = dev->data; + uint8_t desc_type = USB_GET_DESCRIPTOR_TYPE(setup->wValue); + uint8_t desc_idx = USB_GET_DESCRIPTOR_INDEX(setup->wValue); + struct usbd_hid_descriptor *const desc = ddata->desc; + + switch (desc_type) { + case USB_DESC_HID_REPORT: + LOG_DBG("Get descriptor report"); + net_buf_add_mem(buf, ddata->rdesc, MIN(ddata->rsize, setup->wLength)); + break; + case USB_DESC_HID: + LOG_DBG("Get descriptor HID"); + net_buf_add_mem(buf, &desc->hid, MIN(desc->hid.bLength, setup->wLength)); + break; + case USB_DESC_HID_PHYSICAL: + LOG_DBG("Get descriptor physical %u", desc_idx); + errno = -ENOTSUP; + break; + default: + errno = -ENOTSUP; + break; + } + + return 0; +} + +static int usbd_hid_ctd(struct usbd_class_data *const c_data, + const struct usb_setup_packet *const setup, + const struct net_buf *const buf) +{ + const struct device *dev = usbd_class_get_private(c_data); + int ret = 0; + + switch (setup->bRequest) { + case USB_HID_SET_IDLE: + ret = handle_set_idle(dev, setup); + break; + case USB_HID_SET_REPORT: + ret = handle_set_report(dev, setup, buf); + break; + case USB_HID_SET_PROTOCOL: + ret = handle_set_protocol(dev, setup); + break; + default: + errno = -ENOTSUP; + break; + } + + return ret; +} + +static int usbd_hid_cth(struct usbd_class_data *const c_data, + const struct usb_setup_packet *const setup, + struct net_buf *const buf) +{ + const struct device *dev = usbd_class_get_private(c_data); + int ret = 0; + + switch (setup->bRequest) { + case USB_HID_GET_IDLE: + ret = handle_get_idle(dev, setup, buf); + break; + case USB_HID_GET_REPORT: + ret = handle_get_report(dev, setup, buf); + break; + case USB_HID_GET_PROTOCOL: + ret = handle_get_protocol(dev, setup, buf); + break; + case USB_SREQ_GET_DESCRIPTOR: + ret = handle_get_descriptor(dev, setup, buf); + break; + default: + errno = -ENOTSUP; + break; + } + + return ret; +} + +static void usbd_hid_sof(struct usbd_class_data *const c_data) +{ + const struct device *dev = usbd_class_get_private(c_data); + struct hid_device_data *ddata = dev->data; + const struct hid_device_ops *const ops = ddata->ops; + + if (ops->sof) { + ops->sof(dev); + } +} + +static void usbd_hid_enable(struct usbd_class_data *const c_data) +{ + const struct device *dev = usbd_class_get_private(c_data); + struct hid_device_data *ddata = dev->data; + const struct hid_device_ops *const ops = ddata->ops; + struct usbd_hid_descriptor *const desc = ddata->desc; + + atomic_set_bit(&ddata->state, HID_DEV_CLASS_ENABLED); + ddata->protocol = HID_PROTOCOL_REPORT; + if (ops->iface_ready) { + ops->iface_ready(dev, true); + } + + if (desc->out_ep.bLength != 0U) { + k_work_submit(&ddata->output_work); + } + + LOG_DBG("Configuration enabled"); +} + +static void usbd_hid_disable(struct usbd_class_data *const c_data) +{ + const struct device *dev = usbd_class_get_private(c_data); + struct hid_device_data *ddata = dev->data; + const struct hid_device_ops *const ops = ddata->ops; + + atomic_clear_bit(&ddata->state, HID_DEV_CLASS_ENABLED); + if (ops->iface_ready) { + ops->iface_ready(dev, false); + } + + LOG_DBG("Configuration disabled"); +} + +static void usbd_hid_suspended(struct usbd_class_data *const c_data) +{ + const struct device *dev = usbd_class_get_private(c_data); + + LOG_DBG("Configuration suspended, device %s", dev->name); +} + +static void usbd_hid_resumed(struct usbd_class_data *const c_data) +{ + const struct device *dev = usbd_class_get_private(c_data); + + LOG_DBG("Configuration resumed, device %s", dev->name); +} + +static void *usbd_hid_get_desc(struct usbd_class_data *const c_data, + const enum usbd_speed speed) +{ + const struct device *dev = usbd_class_get_private(c_data); + struct hid_device_data *ddata = dev->data; + + if (speed == USBD_SPEED_HS) { + return ddata->hs_desc; + } + + return ddata->fs_desc; +} + +static int usbd_hid_init(struct usbd_class_data *const c_data) +{ + LOG_DBG("HID class %s init", c_data->name); + + return 0; +} + +static void usbd_hid_shutdown(struct usbd_class_data *const c_data) +{ + LOG_DBG("HID class %s shutdown", c_data->name); +} + +static struct net_buf *hid_buf_alloc_ext(struct hid_device_data *const ddata, + const uint16_t size, void *const data, + const uint8_t ep) +{ + struct net_buf *buf = NULL; + struct udc_buf_info *bi; + + buf = net_buf_alloc_with_data(ddata->pool_in, data, size, K_NO_WAIT); + if (!buf) { + return NULL; + } + + bi = udc_get_buf_info(buf); + memset(bi, 0, sizeof(struct udc_buf_info)); + bi->ep = ep; + + return buf; +} + +static struct net_buf *hid_buf_alloc(struct hid_device_data *const ddata, + const uint8_t ep) +{ + struct net_buf *buf = NULL; + struct udc_buf_info *bi; + + buf = net_buf_alloc(ddata->pool_out, K_NO_WAIT); + if (!buf) { + return NULL; + } + + bi = udc_get_buf_info(buf); + memset(bi, 0, sizeof(struct udc_buf_info)); + bi->ep = ep; + + return buf; +} + +static void hid_dev_output_handler(struct k_work *work) +{ + struct hid_device_data *ddata = CONTAINER_OF(work, + struct hid_device_data, + output_work); + struct usbd_class_data *c_data = ddata->c_data; + struct net_buf *buf; + + if (!atomic_test_bit(&ddata->state, HID_DEV_CLASS_ENABLED)) { + return; + } + + buf = hid_buf_alloc(ddata, hid_get_out_ep(c_data)); + if (buf == NULL) { + LOG_ERR("Failed to allocate buffer"); + return; + } + + if (usbd_ep_enqueue(c_data, buf)) { + net_buf_unref(buf); + LOG_ERR("Failed to enqueue buffer"); + } +} + +static int hid_dev_submit_report(const struct device *dev, + const uint16_t size, const uint8_t *const report) +{ + struct hid_device_data *const ddata = dev->data; + const struct hid_device_ops *ops = ddata->ops; + struct usbd_class_data *c_data = ddata->c_data; + struct net_buf *buf; + int ret; + + __ASSERT(IS_ALIGNED(report, sizeof(void *)), "Report buffer is not aligned"); + + if (!atomic_test_bit(&ddata->state, HID_DEV_CLASS_ENABLED)) { + return -EACCES; + } + + buf = hid_buf_alloc_ext(ddata, size, (void *)report, hid_get_in_ep(c_data)); + if (buf == NULL) { + LOG_ERR("Failed to allocate net_buf"); + return -ENOMEM; + } + + ret = usbd_ep_enqueue(c_data, buf); + if (ret) { + net_buf_unref(buf); + return ret; + } + + if (ops->input_report_done == NULL) { + k_sem_take(&ddata->in_sem, K_FOREVER); + } + + return 0; +} + +static int hid_dev_register(const struct device *dev, + const uint8_t *const rdesc, const uint16_t rsize, + const struct hid_device_ops *const ops) +{ + struct hid_device_data *const ddata = dev->data; + struct usbd_hid_descriptor *const desc = ddata->desc; + + if (atomic_test_bit(&ddata->state, HID_DEV_CLASS_ENABLED)) { + return -EALREADY; + } + + /* Get Report is required for all HID device types. */ + if (ops == NULL || ops->get_report == NULL) { + LOG_ERR("get_report callback is missing"); + return -EINVAL; + } + + /* Set Report is required when an output report is declared. */ + if (desc->out_ep.bLength && ops->set_report == NULL) { + LOG_ERR("set_report callback is missing"); + return -EINVAL; + } + + /* + * Get/Set Protocol are required when device supports boot interface. + * Get Protocol is handled internally, no callback is required. + */ + if (desc->if0.bInterfaceSubClass && ops->set_protocol == NULL) { + LOG_ERR("set_protocol callback is missing"); + return -EINVAL; + } + + ddata->rdesc = rdesc; + ddata->rsize = rsize; + ddata->ops = ops; + + sys_put_le16(ddata->rsize, (uint8_t *)&(desc->hid.sub[0].wDescriptorLength)); + + return 0; +} + +static int hid_device_init(const struct device *dev) +{ + struct hid_device_data *const ddata = dev->data; + + k_work_init(&ddata->output_work, hid_dev_output_handler); + LOG_DBG("HID device %s init", dev->name); + + return 0; +} + +struct usbd_class_api usbd_hid_api = { + .request = usbd_hid_request, + .update = NULL, + .sof = usbd_hid_sof, + .enable = usbd_hid_enable, + .disable = usbd_hid_disable, + .suspended = usbd_hid_suspended, + .resumed = usbd_hid_resumed, + .control_to_dev = usbd_hid_ctd, + .control_to_host = usbd_hid_cth, + .get_desc = usbd_hid_get_desc, + .init = usbd_hid_init, + .shutdown = usbd_hid_shutdown, +}; + +static const struct hid_device_driver_api hid_device_api = { + .submit_report = hid_dev_submit_report, + .dev_register = hid_dev_register, +}; + +#include "usbd_hid_macros.h" + +#define USBD_HID_INTERFACE_SIMPLE_DEFINE(n) \ + static struct usbd_hid_descriptor hid_desc_##n = { \ + .if0 = HID_INTERFACE_DEFINE(n, 0), \ + .hid = HID_DESCRIPTOR_DEFINE(n), \ + .in_ep = HID_IN_EP_DEFINE(n, false, true), \ + .hs_in_ep = HID_IN_EP_DEFINE(n, true, true), \ + .out_ep = HID_OUT_EP_DEFINE_OR_ZERO(n, false, true), \ + .hs_out_ep = HID_OUT_EP_DEFINE_OR_ZERO(n, true, true), \ + }; \ + \ + const static struct usb_desc_header *hid_fs_desc_##n[] = { \ + (struct usb_desc_header *) &hid_desc_##n.if0, \ + (struct usb_desc_header *) &hid_desc_##n.hid, \ + (struct usb_desc_header *) &hid_desc_##n.in_ep, \ + (struct usb_desc_header *) &hid_desc_##n.out_ep, \ + NULL, \ + }; \ + \ + const static struct usb_desc_header *hid_hs_desc_##n[] = { \ + (struct usb_desc_header *) &hid_desc_##n.if0, \ + (struct usb_desc_header *) &hid_desc_##n.hid, \ + (struct usb_desc_header *) &hid_desc_##n.hs_in_ep, \ + (struct usb_desc_header *) &hid_desc_##n.hs_out_ep, \ + NULL, \ + } + +#define USBD_HID_INTERFACE_ALTERNATE_DEFINE(n) \ + static struct usbd_hid_descriptor hid_desc_##n = { \ + .if0 = HID_INTERFACE_DEFINE(n, 0), \ + .hid = HID_DESCRIPTOR_DEFINE(n), \ + .in_ep = HID_IN_EP_DEFINE(n, false, false), \ + .hs_in_ep = HID_IN_EP_DEFINE(n, true, false), \ + .out_ep = HID_OUT_EP_DEFINE_OR_ZERO(n, false, false), \ + .hs_out_ep = HID_OUT_EP_DEFINE_OR_ZERO(n, true, false), \ + .if0_1 = HID_INTERFACE_DEFINE(n, 1), \ + .alt_hs_in_ep = HID_IN_EP_DEFINE(n, true, true), \ + .alt_hs_out_ep = HID_OUT_EP_DEFINE_OR_ZERO(n, true, true), \ + }; \ + \ + const static struct usb_desc_header *hid_fs_desc_##n[] = { \ + (struct usb_desc_header *) &hid_desc_##n.if0, \ + (struct usb_desc_header *) &hid_desc_##n.hid, \ + (struct usb_desc_header *) &hid_desc_##n.in_ep, \ + (struct usb_desc_header *) &hid_desc_##n.out_ep, \ + NULL, \ + }; \ + \ + const static struct usb_desc_header *hid_hs_desc_##n[] = { \ + (struct usb_desc_header *) &hid_desc_##n.if0, \ + (struct usb_desc_header *) &hid_desc_##n.hid, \ + (struct usb_desc_header *) &hid_desc_##n.hs_in_ep, \ + COND_CODE_1(DT_INST_NODE_HAS_PROP(n, out_report_size), \ + ((struct usb_desc_header *) &hid_desc_##n.hs_out_ep,), ()) \ + (struct usb_desc_header *)&hid_desc_##n.if0_1, \ + (struct usb_desc_header *) &hid_desc_##n.hid, \ + (struct usb_desc_header *) &hid_desc_##n.alt_hs_in_ep, \ + COND_CODE_1(DT_INST_NODE_HAS_PROP(n, out_report_size), \ + ((struct usb_desc_header *) &hid_desc_##n.alt_hs_out_ep,), ()) \ + NULL, \ + } + +#define USBD_HID_INTERFACE_DEFINE(n) \ + COND_CODE_1(HID_ALL_MPS_LESS_65(n), \ + (USBD_HID_INTERFACE_SIMPLE_DEFINE(n)), \ + (USBD_HID_INTERFACE_ALTERNATE_DEFINE(n))) + +#define USBD_HID_INSTANCE_DEFINE(n) \ + NET_BUF_POOL_DEFINE(hid_buf_pool_in_##n, \ + CONFIG_USBD_HID_IN_BUF_COUNT, 0, \ + sizeof(struct udc_buf_info), NULL); \ + \ + HID_OUT_POOL_DEFINE(n); \ + USBD_HID_INTERFACE_DEFINE(n); \ + \ + USBD_DEFINE_CLASS(hid_##n, \ + &usbd_hid_api, \ + (void *)DEVICE_DT_GET(DT_DRV_INST(n)), NULL); \ + \ + static struct hid_device_data hid_data_##n = { \ + .desc = &hid_desc_##n, \ + .c_data = &hid_##n, \ + .pool_in = &hid_buf_pool_in_##n, \ + .pool_out = HID_OUT_POOL_ADDR(n), \ + .in_sem = Z_SEM_INITIALIZER(hid_data_##n.in_sem, 0, 1), \ + .fs_desc = hid_fs_desc_##n, \ + .hs_desc = hid_hs_desc_##n, \ + }; \ + \ + DEVICE_DT_INST_DEFINE(n, hid_device_init, NULL, \ + &hid_data_##n, NULL, \ + POST_KERNEL, CONFIG_USBD_HID_INIT_PRIORITY, \ + &hid_device_api); + +DT_INST_FOREACH_STATUS_OKAY(USBD_HID_INSTANCE_DEFINE); diff --git a/subsys/usb/device_next/class/usbd_hid_api.c b/subsys/usb/device_next/class/usbd_hid_api.c new file mode 100644 index 00000000000..17b0efc1fbb --- /dev/null +++ b/subsys/usb/device_next/class/usbd_hid_api.c @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "usbd_hid_internal.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(hid_api, CONFIG_USBD_HID_LOG_LEVEL); + +int hid_device_submit_report(const struct device *dev, + const uint16_t size, const uint8_t *const report) +{ + const struct hid_device_driver_api *api = dev->api; + + return api->submit_report(dev, size, report); +} + +int hid_device_register(const struct device *dev, + const uint8_t *const rdesc, const uint16_t rsize, + const struct hid_device_ops *const ops) +{ + const struct hid_device_driver_api *api = dev->api; + + return api->dev_register(dev, rdesc, rsize, ops); +} + +/* Legacy HID API wrapper below */ + +struct legacy_wrapper { + const struct device *dev; + const struct hid_ops *legacy_ops; + struct hid_device_ops *ops; +}; + +static struct hid_device_ops wrapper_ops; + +#define DT_DRV_COMPAT zephyr_hid_device + +#define USBD_HID_WRAPPER_DEFINE(n) \ + { \ + .dev = DEVICE_DT_GET(DT_DRV_INST(n)), \ + .ops = &wrapper_ops, \ + }, + +static struct legacy_wrapper wrappers[] = { + DT_INST_FOREACH_STATUS_OKAY(USBD_HID_WRAPPER_DEFINE) +}; + +static const struct hid_ops *get_legacy_ops(const struct device *dev) +{ + for (unsigned int i = 0; i < ARRAY_SIZE(wrappers); i++) { + if (wrappers[i].dev == dev) { + return wrappers[i].legacy_ops; + } + } + + return NULL; +} + +int wrapper_get_report(const struct device *dev, + const uint8_t type, const uint8_t id, + const uint16_t len, uint8_t *const buf) +{ + const struct hid_ops *legacy_ops = get_legacy_ops(dev); + struct usb_setup_packet setup = { + .bmRequestType = 0, + .bRequest = 0, + .wValue = (type << 8) | id, + .wIndex = 0, + .wLength = len, + }; + uint8_t *d = buf; + int l = len; + + if (legacy_ops != NULL && legacy_ops->get_report != NULL) { + return legacy_ops->get_report(dev, &setup, &l, &d); + } + + return -ENOTSUP; +} + +int wrapper_set_report(const struct device *dev, + const uint8_t type, const uint8_t id, + const uint16_t len, const uint8_t *const buf) +{ + const struct hid_ops *legacy_ops = get_legacy_ops(dev); + struct usb_setup_packet setup = { + .bmRequestType = 0, + .bRequest = 0, + .wValue = (type << 8) | id, + .wIndex = 0, + .wLength = len, + }; + uint8_t *d = (void *)buf; + int l = len; + + if (legacy_ops != NULL && legacy_ops->set_report != NULL) { + return legacy_ops->set_report(dev, &setup, &l, &d); + } + + return -ENOTSUP; +} + +void wrapper_set_idle(const struct device *dev, + const uint8_t id, const uint32_t duration) +{ + if (id != 0U) { + LOG_ERR("Set Idle for %s ID %u duration %u cannot be propagated", + dev->name, id, duration); + } +} + +void wrapper_set_protocol(const struct device *dev, const uint8_t proto) +{ + const struct hid_ops *legacy_ops = get_legacy_ops(dev); + + if (legacy_ops != NULL && legacy_ops->protocol_change != NULL) { + legacy_ops->protocol_change(dev, proto); + } +} + +void wrapper_input_report_done(const struct device *dev) +{ + const struct hid_ops *legacy_ops = get_legacy_ops(dev); + + if (legacy_ops != NULL && legacy_ops->int_in_ready != NULL) { + legacy_ops->int_in_ready(dev); + } +} + +void wrapper_output_report(const struct device *dev, + const uint16_t len, const uint8_t *const buf) +{ + ARG_UNUSED(dev); + ARG_UNUSED(len); + ARG_UNUSED(buf); + + __ASSERT(false, "Output report callback is not supported"); +} + +static struct hid_device_ops wrapper_ops = { + .get_report = wrapper_get_report, + .set_report = wrapper_set_report, + .set_idle = wrapper_set_idle, + .set_protocol = wrapper_set_protocol, + .input_report_done = wrapper_input_report_done, + .output_report = wrapper_output_report, +}; + +int hid_int_ep_write(const struct device *dev, + const uint8_t *data, uint32_t data_len, uint32_t *bytes_ret) +{ + int ret; + + ret = hid_device_submit_report(dev, data_len, data); + if (bytes_ret != NULL) { + *bytes_ret = ret == 0 ? data_len : 0; + } + + return ret; +} + +int hid_int_ep_read(const struct device *dev, + uint8_t *data, uint32_t max_data_len, uint32_t *ret_bytes) +{ + ARG_UNUSED(dev); + ARG_UNUSED(data); + ARG_UNUSED(max_data_len); + ARG_UNUSED(ret_bytes); + + LOG_ERR("Not supported"); + + return -ENOTSUP; +} + +int usb_hid_set_proto_code(const struct device *dev, uint8_t proto_code) +{ + ARG_UNUSED(dev); + ARG_UNUSED(proto_code); + + LOG_WRN("Protocol code is set using DT property protocol-code"); + + return 0; +} + +int usb_hid_init(const struct device *dev) +{ + LOG_DBG("It does nothing for dev %s", dev->name); + + return 0; +} + +void usb_hid_register_device(const struct device *dev, + const uint8_t *desc, size_t size, + const struct hid_ops *ops) +{ + for (unsigned int i = 0; i < ARRAY_SIZE(wrappers); i++) { + if (wrappers[i].dev == dev) { + wrappers[i].legacy_ops = ops; + if (hid_device_register(dev, desc, size, wrappers[i].ops)) { + LOG_ERR("Failed to register HID device"); + } + } + } + +} diff --git a/subsys/usb/device_next/class/usbd_hid_internal.h b/subsys/usb/device_next/class/usbd_hid_internal.h new file mode 100644 index 00000000000..d049b0c22a3 --- /dev/null +++ b/subsys/usb/device_next/class/usbd_hid_internal.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +/* + * HID device driver API, we can keep internally as long as it is only used in + * USB. + */ + +struct hid_device_driver_api { + int (*enable_output)(const struct device *dev, const bool enable); + int (*submit_report)(const struct device *dev, + const uint16_t size, const uint8_t *const report); + int (*dev_register)(const struct device *dev, + const uint8_t *const rdesc, const uint16_t rsize, + const struct hid_device_ops *const ops); +}; diff --git a/subsys/usb/device_next/class/usbd_hid_macros.h b/subsys/usb/device_next/class/usbd_hid_macros.h new file mode 100644 index 00000000000..c00a18b227a --- /dev/null +++ b/subsys/usb/device_next/class/usbd_hid_macros.h @@ -0,0 +1,1169 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * The macros in this file are not for public use, but only for HID driver + * instantiation. + */ + +#include +#include + +#ifndef ZEPHYR_USB_DEVICE_CLASS_HID_MACROS_H_ +#define ZEPHYR_USB_DEVICE_CLASS_HID_MACROS_H_ + +/* + * This long list of definitions is used in HID_MPS_LESS_65 macro to determine + * whether an endpoint MPS is equal to or less than 64 bytes. + */ +#define HID_MPS_LESS_65_0 1 +#define HID_MPS_LESS_65_1 1 +#define HID_MPS_LESS_65_2 1 +#define HID_MPS_LESS_65_3 1 +#define HID_MPS_LESS_65_4 1 +#define HID_MPS_LESS_65_5 1 +#define HID_MPS_LESS_65_6 1 +#define HID_MPS_LESS_65_7 1 +#define HID_MPS_LESS_65_8 1 +#define HID_MPS_LESS_65_9 1 +#define HID_MPS_LESS_65_10 1 +#define HID_MPS_LESS_65_11 1 +#define HID_MPS_LESS_65_12 1 +#define HID_MPS_LESS_65_13 1 +#define HID_MPS_LESS_65_14 1 +#define HID_MPS_LESS_65_15 1 +#define HID_MPS_LESS_65_16 1 +#define HID_MPS_LESS_65_17 1 +#define HID_MPS_LESS_65_18 1 +#define HID_MPS_LESS_65_19 1 +#define HID_MPS_LESS_65_20 1 +#define HID_MPS_LESS_65_21 1 +#define HID_MPS_LESS_65_22 1 +#define HID_MPS_LESS_65_23 1 +#define HID_MPS_LESS_65_24 1 +#define HID_MPS_LESS_65_25 1 +#define HID_MPS_LESS_65_26 1 +#define HID_MPS_LESS_65_27 1 +#define HID_MPS_LESS_65_28 1 +#define HID_MPS_LESS_65_29 1 +#define HID_MPS_LESS_65_30 1 +#define HID_MPS_LESS_65_31 1 +#define HID_MPS_LESS_65_32 1 +#define HID_MPS_LESS_65_33 1 +#define HID_MPS_LESS_65_34 1 +#define HID_MPS_LESS_65_35 1 +#define HID_MPS_LESS_65_36 1 +#define HID_MPS_LESS_65_37 1 +#define HID_MPS_LESS_65_38 1 +#define HID_MPS_LESS_65_39 1 +#define HID_MPS_LESS_65_40 1 +#define HID_MPS_LESS_65_41 1 +#define HID_MPS_LESS_65_42 1 +#define HID_MPS_LESS_65_43 1 +#define HID_MPS_LESS_65_44 1 +#define HID_MPS_LESS_65_45 1 +#define HID_MPS_LESS_65_46 1 +#define HID_MPS_LESS_65_47 1 +#define HID_MPS_LESS_65_48 1 +#define HID_MPS_LESS_65_49 1 +#define HID_MPS_LESS_65_50 1 +#define HID_MPS_LESS_65_51 1 +#define HID_MPS_LESS_65_52 1 +#define HID_MPS_LESS_65_53 1 +#define HID_MPS_LESS_65_54 1 +#define HID_MPS_LESS_65_55 1 +#define HID_MPS_LESS_65_56 1 +#define HID_MPS_LESS_65_57 1 +#define HID_MPS_LESS_65_58 1 +#define HID_MPS_LESS_65_59 1 +#define HID_MPS_LESS_65_60 1 +#define HID_MPS_LESS_65_61 1 +#define HID_MPS_LESS_65_62 1 +#define HID_MPS_LESS_65_63 1 +#define HID_MPS_LESS_65_64 1 +#define HID_MPS_LESS_65_65 0 +#define HID_MPS_LESS_65_66 0 +#define HID_MPS_LESS_65_67 0 +#define HID_MPS_LESS_65_68 0 +#define HID_MPS_LESS_65_69 0 +#define HID_MPS_LESS_65_70 0 +#define HID_MPS_LESS_65_71 0 +#define HID_MPS_LESS_65_72 0 +#define HID_MPS_LESS_65_73 0 +#define HID_MPS_LESS_65_74 0 +#define HID_MPS_LESS_65_75 0 +#define HID_MPS_LESS_65_76 0 +#define HID_MPS_LESS_65_77 0 +#define HID_MPS_LESS_65_78 0 +#define HID_MPS_LESS_65_79 0 +#define HID_MPS_LESS_65_80 0 +#define HID_MPS_LESS_65_81 0 +#define HID_MPS_LESS_65_82 0 +#define HID_MPS_LESS_65_83 0 +#define HID_MPS_LESS_65_84 0 +#define HID_MPS_LESS_65_85 0 +#define HID_MPS_LESS_65_86 0 +#define HID_MPS_LESS_65_87 0 +#define HID_MPS_LESS_65_88 0 +#define HID_MPS_LESS_65_89 0 +#define HID_MPS_LESS_65_90 0 +#define HID_MPS_LESS_65_91 0 +#define HID_MPS_LESS_65_92 0 +#define HID_MPS_LESS_65_93 0 +#define HID_MPS_LESS_65_94 0 +#define HID_MPS_LESS_65_95 0 +#define HID_MPS_LESS_65_96 0 +#define HID_MPS_LESS_65_97 0 +#define HID_MPS_LESS_65_98 0 +#define HID_MPS_LESS_65_99 0 +#define HID_MPS_LESS_65_100 0 +#define HID_MPS_LESS_65_101 0 +#define HID_MPS_LESS_65_102 0 +#define HID_MPS_LESS_65_103 0 +#define HID_MPS_LESS_65_104 0 +#define HID_MPS_LESS_65_105 0 +#define HID_MPS_LESS_65_106 0 +#define HID_MPS_LESS_65_107 0 +#define HID_MPS_LESS_65_108 0 +#define HID_MPS_LESS_65_109 0 +#define HID_MPS_LESS_65_110 0 +#define HID_MPS_LESS_65_111 0 +#define HID_MPS_LESS_65_112 0 +#define HID_MPS_LESS_65_113 0 +#define HID_MPS_LESS_65_114 0 +#define HID_MPS_LESS_65_115 0 +#define HID_MPS_LESS_65_116 0 +#define HID_MPS_LESS_65_117 0 +#define HID_MPS_LESS_65_118 0 +#define HID_MPS_LESS_65_119 0 +#define HID_MPS_LESS_65_120 0 +#define HID_MPS_LESS_65_121 0 +#define HID_MPS_LESS_65_122 0 +#define HID_MPS_LESS_65_123 0 +#define HID_MPS_LESS_65_124 0 +#define HID_MPS_LESS_65_125 0 +#define HID_MPS_LESS_65_126 0 +#define HID_MPS_LESS_65_127 0 +#define HID_MPS_LESS_65_128 0 +#define HID_MPS_LESS_65_129 0 +#define HID_MPS_LESS_65_130 0 +#define HID_MPS_LESS_65_131 0 +#define HID_MPS_LESS_65_132 0 +#define HID_MPS_LESS_65_133 0 +#define HID_MPS_LESS_65_134 0 +#define HID_MPS_LESS_65_135 0 +#define HID_MPS_LESS_65_136 0 +#define HID_MPS_LESS_65_137 0 +#define HID_MPS_LESS_65_138 0 +#define HID_MPS_LESS_65_139 0 +#define HID_MPS_LESS_65_140 0 +#define HID_MPS_LESS_65_141 0 +#define HID_MPS_LESS_65_142 0 +#define HID_MPS_LESS_65_143 0 +#define HID_MPS_LESS_65_144 0 +#define HID_MPS_LESS_65_145 0 +#define HID_MPS_LESS_65_146 0 +#define HID_MPS_LESS_65_147 0 +#define HID_MPS_LESS_65_148 0 +#define HID_MPS_LESS_65_149 0 +#define HID_MPS_LESS_65_150 0 +#define HID_MPS_LESS_65_151 0 +#define HID_MPS_LESS_65_152 0 +#define HID_MPS_LESS_65_153 0 +#define HID_MPS_LESS_65_154 0 +#define HID_MPS_LESS_65_155 0 +#define HID_MPS_LESS_65_156 0 +#define HID_MPS_LESS_65_157 0 +#define HID_MPS_LESS_65_158 0 +#define HID_MPS_LESS_65_159 0 +#define HID_MPS_LESS_65_160 0 +#define HID_MPS_LESS_65_161 0 +#define HID_MPS_LESS_65_162 0 +#define HID_MPS_LESS_65_163 0 +#define HID_MPS_LESS_65_164 0 +#define HID_MPS_LESS_65_165 0 +#define HID_MPS_LESS_65_166 0 +#define HID_MPS_LESS_65_167 0 +#define HID_MPS_LESS_65_168 0 +#define HID_MPS_LESS_65_169 0 +#define HID_MPS_LESS_65_170 0 +#define HID_MPS_LESS_65_171 0 +#define HID_MPS_LESS_65_172 0 +#define HID_MPS_LESS_65_173 0 +#define HID_MPS_LESS_65_174 0 +#define HID_MPS_LESS_65_175 0 +#define HID_MPS_LESS_65_176 0 +#define HID_MPS_LESS_65_177 0 +#define HID_MPS_LESS_65_178 0 +#define HID_MPS_LESS_65_179 0 +#define HID_MPS_LESS_65_180 0 +#define HID_MPS_LESS_65_181 0 +#define HID_MPS_LESS_65_182 0 +#define HID_MPS_LESS_65_183 0 +#define HID_MPS_LESS_65_184 0 +#define HID_MPS_LESS_65_185 0 +#define HID_MPS_LESS_65_186 0 +#define HID_MPS_LESS_65_187 0 +#define HID_MPS_LESS_65_188 0 +#define HID_MPS_LESS_65_189 0 +#define HID_MPS_LESS_65_190 0 +#define HID_MPS_LESS_65_191 0 +#define HID_MPS_LESS_65_192 0 +#define HID_MPS_LESS_65_193 0 +#define HID_MPS_LESS_65_194 0 +#define HID_MPS_LESS_65_195 0 +#define HID_MPS_LESS_65_196 0 +#define HID_MPS_LESS_65_197 0 +#define HID_MPS_LESS_65_198 0 +#define HID_MPS_LESS_65_199 0 +#define HID_MPS_LESS_65_200 0 +#define HID_MPS_LESS_65_201 0 +#define HID_MPS_LESS_65_202 0 +#define HID_MPS_LESS_65_203 0 +#define HID_MPS_LESS_65_204 0 +#define HID_MPS_LESS_65_205 0 +#define HID_MPS_LESS_65_206 0 +#define HID_MPS_LESS_65_207 0 +#define HID_MPS_LESS_65_208 0 +#define HID_MPS_LESS_65_209 0 +#define HID_MPS_LESS_65_210 0 +#define HID_MPS_LESS_65_211 0 +#define HID_MPS_LESS_65_212 0 +#define HID_MPS_LESS_65_213 0 +#define HID_MPS_LESS_65_214 0 +#define HID_MPS_LESS_65_215 0 +#define HID_MPS_LESS_65_216 0 +#define HID_MPS_LESS_65_217 0 +#define HID_MPS_LESS_65_218 0 +#define HID_MPS_LESS_65_219 0 +#define HID_MPS_LESS_65_220 0 +#define HID_MPS_LESS_65_221 0 +#define HID_MPS_LESS_65_222 0 +#define HID_MPS_LESS_65_223 0 +#define HID_MPS_LESS_65_224 0 +#define HID_MPS_LESS_65_225 0 +#define HID_MPS_LESS_65_226 0 +#define HID_MPS_LESS_65_227 0 +#define HID_MPS_LESS_65_228 0 +#define HID_MPS_LESS_65_229 0 +#define HID_MPS_LESS_65_230 0 +#define HID_MPS_LESS_65_231 0 +#define HID_MPS_LESS_65_232 0 +#define HID_MPS_LESS_65_233 0 +#define HID_MPS_LESS_65_234 0 +#define HID_MPS_LESS_65_235 0 +#define HID_MPS_LESS_65_236 0 +#define HID_MPS_LESS_65_237 0 +#define HID_MPS_LESS_65_238 0 +#define HID_MPS_LESS_65_239 0 +#define HID_MPS_LESS_65_240 0 +#define HID_MPS_LESS_65_241 0 +#define HID_MPS_LESS_65_242 0 +#define HID_MPS_LESS_65_243 0 +#define HID_MPS_LESS_65_244 0 +#define HID_MPS_LESS_65_245 0 +#define HID_MPS_LESS_65_246 0 +#define HID_MPS_LESS_65_247 0 +#define HID_MPS_LESS_65_248 0 +#define HID_MPS_LESS_65_249 0 +#define HID_MPS_LESS_65_250 0 +#define HID_MPS_LESS_65_251 0 +#define HID_MPS_LESS_65_252 0 +#define HID_MPS_LESS_65_253 0 +#define HID_MPS_LESS_65_254 0 +#define HID_MPS_LESS_65_255 0 +#define HID_MPS_LESS_65_256 0 +#define HID_MPS_LESS_65_257 0 +#define HID_MPS_LESS_65_258 0 +#define HID_MPS_LESS_65_259 0 +#define HID_MPS_LESS_65_260 0 +#define HID_MPS_LESS_65_261 0 +#define HID_MPS_LESS_65_262 0 +#define HID_MPS_LESS_65_263 0 +#define HID_MPS_LESS_65_264 0 +#define HID_MPS_LESS_65_265 0 +#define HID_MPS_LESS_65_266 0 +#define HID_MPS_LESS_65_267 0 +#define HID_MPS_LESS_65_268 0 +#define HID_MPS_LESS_65_269 0 +#define HID_MPS_LESS_65_270 0 +#define HID_MPS_LESS_65_271 0 +#define HID_MPS_LESS_65_272 0 +#define HID_MPS_LESS_65_273 0 +#define HID_MPS_LESS_65_274 0 +#define HID_MPS_LESS_65_275 0 +#define HID_MPS_LESS_65_276 0 +#define HID_MPS_LESS_65_277 0 +#define HID_MPS_LESS_65_278 0 +#define HID_MPS_LESS_65_279 0 +#define HID_MPS_LESS_65_280 0 +#define HID_MPS_LESS_65_281 0 +#define HID_MPS_LESS_65_282 0 +#define HID_MPS_LESS_65_283 0 +#define HID_MPS_LESS_65_284 0 +#define HID_MPS_LESS_65_285 0 +#define HID_MPS_LESS_65_286 0 +#define HID_MPS_LESS_65_287 0 +#define HID_MPS_LESS_65_288 0 +#define HID_MPS_LESS_65_289 0 +#define HID_MPS_LESS_65_290 0 +#define HID_MPS_LESS_65_291 0 +#define HID_MPS_LESS_65_292 0 +#define HID_MPS_LESS_65_293 0 +#define HID_MPS_LESS_65_294 0 +#define HID_MPS_LESS_65_295 0 +#define HID_MPS_LESS_65_296 0 +#define HID_MPS_LESS_65_297 0 +#define HID_MPS_LESS_65_298 0 +#define HID_MPS_LESS_65_299 0 +#define HID_MPS_LESS_65_300 0 +#define HID_MPS_LESS_65_301 0 +#define HID_MPS_LESS_65_302 0 +#define HID_MPS_LESS_65_303 0 +#define HID_MPS_LESS_65_304 0 +#define HID_MPS_LESS_65_305 0 +#define HID_MPS_LESS_65_306 0 +#define HID_MPS_LESS_65_307 0 +#define HID_MPS_LESS_65_308 0 +#define HID_MPS_LESS_65_309 0 +#define HID_MPS_LESS_65_310 0 +#define HID_MPS_LESS_65_311 0 +#define HID_MPS_LESS_65_312 0 +#define HID_MPS_LESS_65_313 0 +#define HID_MPS_LESS_65_314 0 +#define HID_MPS_LESS_65_315 0 +#define HID_MPS_LESS_65_316 0 +#define HID_MPS_LESS_65_317 0 +#define HID_MPS_LESS_65_318 0 +#define HID_MPS_LESS_65_319 0 +#define HID_MPS_LESS_65_320 0 +#define HID_MPS_LESS_65_321 0 +#define HID_MPS_LESS_65_322 0 +#define HID_MPS_LESS_65_323 0 +#define HID_MPS_LESS_65_324 0 +#define HID_MPS_LESS_65_325 0 +#define HID_MPS_LESS_65_326 0 +#define HID_MPS_LESS_65_327 0 +#define HID_MPS_LESS_65_328 0 +#define HID_MPS_LESS_65_329 0 +#define HID_MPS_LESS_65_330 0 +#define HID_MPS_LESS_65_331 0 +#define HID_MPS_LESS_65_332 0 +#define HID_MPS_LESS_65_333 0 +#define HID_MPS_LESS_65_334 0 +#define HID_MPS_LESS_65_335 0 +#define HID_MPS_LESS_65_336 0 +#define HID_MPS_LESS_65_337 0 +#define HID_MPS_LESS_65_338 0 +#define HID_MPS_LESS_65_339 0 +#define HID_MPS_LESS_65_340 0 +#define HID_MPS_LESS_65_341 0 +#define HID_MPS_LESS_65_342 0 +#define HID_MPS_LESS_65_343 0 +#define HID_MPS_LESS_65_344 0 +#define HID_MPS_LESS_65_345 0 +#define HID_MPS_LESS_65_346 0 +#define HID_MPS_LESS_65_347 0 +#define HID_MPS_LESS_65_348 0 +#define HID_MPS_LESS_65_349 0 +#define HID_MPS_LESS_65_350 0 +#define HID_MPS_LESS_65_351 0 +#define HID_MPS_LESS_65_352 0 +#define HID_MPS_LESS_65_353 0 +#define HID_MPS_LESS_65_354 0 +#define HID_MPS_LESS_65_355 0 +#define HID_MPS_LESS_65_356 0 +#define HID_MPS_LESS_65_357 0 +#define HID_MPS_LESS_65_358 0 +#define HID_MPS_LESS_65_359 0 +#define HID_MPS_LESS_65_360 0 +#define HID_MPS_LESS_65_361 0 +#define HID_MPS_LESS_65_362 0 +#define HID_MPS_LESS_65_363 0 +#define HID_MPS_LESS_65_364 0 +#define HID_MPS_LESS_65_365 0 +#define HID_MPS_LESS_65_366 0 +#define HID_MPS_LESS_65_367 0 +#define HID_MPS_LESS_65_368 0 +#define HID_MPS_LESS_65_369 0 +#define HID_MPS_LESS_65_370 0 +#define HID_MPS_LESS_65_371 0 +#define HID_MPS_LESS_65_372 0 +#define HID_MPS_LESS_65_373 0 +#define HID_MPS_LESS_65_374 0 +#define HID_MPS_LESS_65_375 0 +#define HID_MPS_LESS_65_376 0 +#define HID_MPS_LESS_65_377 0 +#define HID_MPS_LESS_65_378 0 +#define HID_MPS_LESS_65_379 0 +#define HID_MPS_LESS_65_380 0 +#define HID_MPS_LESS_65_381 0 +#define HID_MPS_LESS_65_382 0 +#define HID_MPS_LESS_65_383 0 +#define HID_MPS_LESS_65_384 0 +#define HID_MPS_LESS_65_385 0 +#define HID_MPS_LESS_65_386 0 +#define HID_MPS_LESS_65_387 0 +#define HID_MPS_LESS_65_388 0 +#define HID_MPS_LESS_65_389 0 +#define HID_MPS_LESS_65_390 0 +#define HID_MPS_LESS_65_391 0 +#define HID_MPS_LESS_65_392 0 +#define HID_MPS_LESS_65_393 0 +#define HID_MPS_LESS_65_394 0 +#define HID_MPS_LESS_65_395 0 +#define HID_MPS_LESS_65_396 0 +#define HID_MPS_LESS_65_397 0 +#define HID_MPS_LESS_65_398 0 +#define HID_MPS_LESS_65_399 0 +#define HID_MPS_LESS_65_400 0 +#define HID_MPS_LESS_65_401 0 +#define HID_MPS_LESS_65_402 0 +#define HID_MPS_LESS_65_403 0 +#define HID_MPS_LESS_65_404 0 +#define HID_MPS_LESS_65_405 0 +#define HID_MPS_LESS_65_406 0 +#define HID_MPS_LESS_65_407 0 +#define HID_MPS_LESS_65_408 0 +#define HID_MPS_LESS_65_409 0 +#define HID_MPS_LESS_65_410 0 +#define HID_MPS_LESS_65_411 0 +#define HID_MPS_LESS_65_412 0 +#define HID_MPS_LESS_65_413 0 +#define HID_MPS_LESS_65_414 0 +#define HID_MPS_LESS_65_415 0 +#define HID_MPS_LESS_65_416 0 +#define HID_MPS_LESS_65_417 0 +#define HID_MPS_LESS_65_418 0 +#define HID_MPS_LESS_65_419 0 +#define HID_MPS_LESS_65_420 0 +#define HID_MPS_LESS_65_421 0 +#define HID_MPS_LESS_65_422 0 +#define HID_MPS_LESS_65_423 0 +#define HID_MPS_LESS_65_424 0 +#define HID_MPS_LESS_65_425 0 +#define HID_MPS_LESS_65_426 0 +#define HID_MPS_LESS_65_427 0 +#define HID_MPS_LESS_65_428 0 +#define HID_MPS_LESS_65_429 0 +#define HID_MPS_LESS_65_430 0 +#define HID_MPS_LESS_65_431 0 +#define HID_MPS_LESS_65_432 0 +#define HID_MPS_LESS_65_433 0 +#define HID_MPS_LESS_65_434 0 +#define HID_MPS_LESS_65_435 0 +#define HID_MPS_LESS_65_436 0 +#define HID_MPS_LESS_65_437 0 +#define HID_MPS_LESS_65_438 0 +#define HID_MPS_LESS_65_439 0 +#define HID_MPS_LESS_65_440 0 +#define HID_MPS_LESS_65_441 0 +#define HID_MPS_LESS_65_442 0 +#define HID_MPS_LESS_65_443 0 +#define HID_MPS_LESS_65_444 0 +#define HID_MPS_LESS_65_445 0 +#define HID_MPS_LESS_65_446 0 +#define HID_MPS_LESS_65_447 0 +#define HID_MPS_LESS_65_448 0 +#define HID_MPS_LESS_65_449 0 +#define HID_MPS_LESS_65_450 0 +#define HID_MPS_LESS_65_451 0 +#define HID_MPS_LESS_65_452 0 +#define HID_MPS_LESS_65_453 0 +#define HID_MPS_LESS_65_454 0 +#define HID_MPS_LESS_65_455 0 +#define HID_MPS_LESS_65_456 0 +#define HID_MPS_LESS_65_457 0 +#define HID_MPS_LESS_65_458 0 +#define HID_MPS_LESS_65_459 0 +#define HID_MPS_LESS_65_460 0 +#define HID_MPS_LESS_65_461 0 +#define HID_MPS_LESS_65_462 0 +#define HID_MPS_LESS_65_463 0 +#define HID_MPS_LESS_65_464 0 +#define HID_MPS_LESS_65_465 0 +#define HID_MPS_LESS_65_466 0 +#define HID_MPS_LESS_65_467 0 +#define HID_MPS_LESS_65_468 0 +#define HID_MPS_LESS_65_469 0 +#define HID_MPS_LESS_65_470 0 +#define HID_MPS_LESS_65_471 0 +#define HID_MPS_LESS_65_472 0 +#define HID_MPS_LESS_65_473 0 +#define HID_MPS_LESS_65_474 0 +#define HID_MPS_LESS_65_475 0 +#define HID_MPS_LESS_65_476 0 +#define HID_MPS_LESS_65_477 0 +#define HID_MPS_LESS_65_478 0 +#define HID_MPS_LESS_65_479 0 +#define HID_MPS_LESS_65_480 0 +#define HID_MPS_LESS_65_481 0 +#define HID_MPS_LESS_65_482 0 +#define HID_MPS_LESS_65_483 0 +#define HID_MPS_LESS_65_484 0 +#define HID_MPS_LESS_65_485 0 +#define HID_MPS_LESS_65_486 0 +#define HID_MPS_LESS_65_487 0 +#define HID_MPS_LESS_65_488 0 +#define HID_MPS_LESS_65_489 0 +#define HID_MPS_LESS_65_490 0 +#define HID_MPS_LESS_65_491 0 +#define HID_MPS_LESS_65_492 0 +#define HID_MPS_LESS_65_493 0 +#define HID_MPS_LESS_65_494 0 +#define HID_MPS_LESS_65_495 0 +#define HID_MPS_LESS_65_496 0 +#define HID_MPS_LESS_65_497 0 +#define HID_MPS_LESS_65_498 0 +#define HID_MPS_LESS_65_499 0 +#define HID_MPS_LESS_65_500 0 +#define HID_MPS_LESS_65_501 0 +#define HID_MPS_LESS_65_502 0 +#define HID_MPS_LESS_65_503 0 +#define HID_MPS_LESS_65_504 0 +#define HID_MPS_LESS_65_505 0 +#define HID_MPS_LESS_65_506 0 +#define HID_MPS_LESS_65_507 0 +#define HID_MPS_LESS_65_508 0 +#define HID_MPS_LESS_65_509 0 +#define HID_MPS_LESS_65_510 0 +#define HID_MPS_LESS_65_511 0 +#define HID_MPS_LESS_65_512 0 +#define HID_MPS_LESS_65_513 0 +#define HID_MPS_LESS_65_514 0 +#define HID_MPS_LESS_65_515 0 +#define HID_MPS_LESS_65_516 0 +#define HID_MPS_LESS_65_517 0 +#define HID_MPS_LESS_65_518 0 +#define HID_MPS_LESS_65_519 0 +#define HID_MPS_LESS_65_520 0 +#define HID_MPS_LESS_65_521 0 +#define HID_MPS_LESS_65_522 0 +#define HID_MPS_LESS_65_523 0 +#define HID_MPS_LESS_65_524 0 +#define HID_MPS_LESS_65_525 0 +#define HID_MPS_LESS_65_526 0 +#define HID_MPS_LESS_65_527 0 +#define HID_MPS_LESS_65_528 0 +#define HID_MPS_LESS_65_529 0 +#define HID_MPS_LESS_65_530 0 +#define HID_MPS_LESS_65_531 0 +#define HID_MPS_LESS_65_532 0 +#define HID_MPS_LESS_65_533 0 +#define HID_MPS_LESS_65_534 0 +#define HID_MPS_LESS_65_535 0 +#define HID_MPS_LESS_65_536 0 +#define HID_MPS_LESS_65_537 0 +#define HID_MPS_LESS_65_538 0 +#define HID_MPS_LESS_65_539 0 +#define HID_MPS_LESS_65_540 0 +#define HID_MPS_LESS_65_541 0 +#define HID_MPS_LESS_65_542 0 +#define HID_MPS_LESS_65_543 0 +#define HID_MPS_LESS_65_544 0 +#define HID_MPS_LESS_65_545 0 +#define HID_MPS_LESS_65_546 0 +#define HID_MPS_LESS_65_547 0 +#define HID_MPS_LESS_65_548 0 +#define HID_MPS_LESS_65_549 0 +#define HID_MPS_LESS_65_550 0 +#define HID_MPS_LESS_65_551 0 +#define HID_MPS_LESS_65_552 0 +#define HID_MPS_LESS_65_553 0 +#define HID_MPS_LESS_65_554 0 +#define HID_MPS_LESS_65_555 0 +#define HID_MPS_LESS_65_556 0 +#define HID_MPS_LESS_65_557 0 +#define HID_MPS_LESS_65_558 0 +#define HID_MPS_LESS_65_559 0 +#define HID_MPS_LESS_65_560 0 +#define HID_MPS_LESS_65_561 0 +#define HID_MPS_LESS_65_562 0 +#define HID_MPS_LESS_65_563 0 +#define HID_MPS_LESS_65_564 0 +#define HID_MPS_LESS_65_565 0 +#define HID_MPS_LESS_65_566 0 +#define HID_MPS_LESS_65_567 0 +#define HID_MPS_LESS_65_568 0 +#define HID_MPS_LESS_65_569 0 +#define HID_MPS_LESS_65_570 0 +#define HID_MPS_LESS_65_571 0 +#define HID_MPS_LESS_65_572 0 +#define HID_MPS_LESS_65_573 0 +#define HID_MPS_LESS_65_574 0 +#define HID_MPS_LESS_65_575 0 +#define HID_MPS_LESS_65_576 0 +#define HID_MPS_LESS_65_577 0 +#define HID_MPS_LESS_65_578 0 +#define HID_MPS_LESS_65_579 0 +#define HID_MPS_LESS_65_580 0 +#define HID_MPS_LESS_65_581 0 +#define HID_MPS_LESS_65_582 0 +#define HID_MPS_LESS_65_583 0 +#define HID_MPS_LESS_65_584 0 +#define HID_MPS_LESS_65_585 0 +#define HID_MPS_LESS_65_586 0 +#define HID_MPS_LESS_65_587 0 +#define HID_MPS_LESS_65_588 0 +#define HID_MPS_LESS_65_589 0 +#define HID_MPS_LESS_65_590 0 +#define HID_MPS_LESS_65_591 0 +#define HID_MPS_LESS_65_592 0 +#define HID_MPS_LESS_65_593 0 +#define HID_MPS_LESS_65_594 0 +#define HID_MPS_LESS_65_595 0 +#define HID_MPS_LESS_65_596 0 +#define HID_MPS_LESS_65_597 0 +#define HID_MPS_LESS_65_598 0 +#define HID_MPS_LESS_65_599 0 +#define HID_MPS_LESS_65_600 0 +#define HID_MPS_LESS_65_601 0 +#define HID_MPS_LESS_65_602 0 +#define HID_MPS_LESS_65_603 0 +#define HID_MPS_LESS_65_604 0 +#define HID_MPS_LESS_65_605 0 +#define HID_MPS_LESS_65_606 0 +#define HID_MPS_LESS_65_607 0 +#define HID_MPS_LESS_65_608 0 +#define HID_MPS_LESS_65_609 0 +#define HID_MPS_LESS_65_610 0 +#define HID_MPS_LESS_65_611 0 +#define HID_MPS_LESS_65_612 0 +#define HID_MPS_LESS_65_613 0 +#define HID_MPS_LESS_65_614 0 +#define HID_MPS_LESS_65_615 0 +#define HID_MPS_LESS_65_616 0 +#define HID_MPS_LESS_65_617 0 +#define HID_MPS_LESS_65_618 0 +#define HID_MPS_LESS_65_619 0 +#define HID_MPS_LESS_65_620 0 +#define HID_MPS_LESS_65_621 0 +#define HID_MPS_LESS_65_622 0 +#define HID_MPS_LESS_65_623 0 +#define HID_MPS_LESS_65_624 0 +#define HID_MPS_LESS_65_625 0 +#define HID_MPS_LESS_65_626 0 +#define HID_MPS_LESS_65_627 0 +#define HID_MPS_LESS_65_628 0 +#define HID_MPS_LESS_65_629 0 +#define HID_MPS_LESS_65_630 0 +#define HID_MPS_LESS_65_631 0 +#define HID_MPS_LESS_65_632 0 +#define HID_MPS_LESS_65_633 0 +#define HID_MPS_LESS_65_634 0 +#define HID_MPS_LESS_65_635 0 +#define HID_MPS_LESS_65_636 0 +#define HID_MPS_LESS_65_637 0 +#define HID_MPS_LESS_65_638 0 +#define HID_MPS_LESS_65_639 0 +#define HID_MPS_LESS_65_640 0 +#define HID_MPS_LESS_65_641 0 +#define HID_MPS_LESS_65_642 0 +#define HID_MPS_LESS_65_643 0 +#define HID_MPS_LESS_65_644 0 +#define HID_MPS_LESS_65_645 0 +#define HID_MPS_LESS_65_646 0 +#define HID_MPS_LESS_65_647 0 +#define HID_MPS_LESS_65_648 0 +#define HID_MPS_LESS_65_649 0 +#define HID_MPS_LESS_65_650 0 +#define HID_MPS_LESS_65_651 0 +#define HID_MPS_LESS_65_652 0 +#define HID_MPS_LESS_65_653 0 +#define HID_MPS_LESS_65_654 0 +#define HID_MPS_LESS_65_655 0 +#define HID_MPS_LESS_65_656 0 +#define HID_MPS_LESS_65_657 0 +#define HID_MPS_LESS_65_658 0 +#define HID_MPS_LESS_65_659 0 +#define HID_MPS_LESS_65_660 0 +#define HID_MPS_LESS_65_661 0 +#define HID_MPS_LESS_65_662 0 +#define HID_MPS_LESS_65_663 0 +#define HID_MPS_LESS_65_664 0 +#define HID_MPS_LESS_65_665 0 +#define HID_MPS_LESS_65_666 0 +#define HID_MPS_LESS_65_667 0 +#define HID_MPS_LESS_65_668 0 +#define HID_MPS_LESS_65_669 0 +#define HID_MPS_LESS_65_670 0 +#define HID_MPS_LESS_65_671 0 +#define HID_MPS_LESS_65_672 0 +#define HID_MPS_LESS_65_673 0 +#define HID_MPS_LESS_65_674 0 +#define HID_MPS_LESS_65_675 0 +#define HID_MPS_LESS_65_676 0 +#define HID_MPS_LESS_65_677 0 +#define HID_MPS_LESS_65_678 0 +#define HID_MPS_LESS_65_679 0 +#define HID_MPS_LESS_65_680 0 +#define HID_MPS_LESS_65_681 0 +#define HID_MPS_LESS_65_682 0 +#define HID_MPS_LESS_65_683 0 +#define HID_MPS_LESS_65_684 0 +#define HID_MPS_LESS_65_685 0 +#define HID_MPS_LESS_65_686 0 +#define HID_MPS_LESS_65_687 0 +#define HID_MPS_LESS_65_688 0 +#define HID_MPS_LESS_65_689 0 +#define HID_MPS_LESS_65_690 0 +#define HID_MPS_LESS_65_691 0 +#define HID_MPS_LESS_65_692 0 +#define HID_MPS_LESS_65_693 0 +#define HID_MPS_LESS_65_694 0 +#define HID_MPS_LESS_65_695 0 +#define HID_MPS_LESS_65_696 0 +#define HID_MPS_LESS_65_697 0 +#define HID_MPS_LESS_65_698 0 +#define HID_MPS_LESS_65_699 0 +#define HID_MPS_LESS_65_700 0 +#define HID_MPS_LESS_65_701 0 +#define HID_MPS_LESS_65_702 0 +#define HID_MPS_LESS_65_703 0 +#define HID_MPS_LESS_65_704 0 +#define HID_MPS_LESS_65_705 0 +#define HID_MPS_LESS_65_706 0 +#define HID_MPS_LESS_65_707 0 +#define HID_MPS_LESS_65_708 0 +#define HID_MPS_LESS_65_709 0 +#define HID_MPS_LESS_65_710 0 +#define HID_MPS_LESS_65_711 0 +#define HID_MPS_LESS_65_712 0 +#define HID_MPS_LESS_65_713 0 +#define HID_MPS_LESS_65_714 0 +#define HID_MPS_LESS_65_715 0 +#define HID_MPS_LESS_65_716 0 +#define HID_MPS_LESS_65_717 0 +#define HID_MPS_LESS_65_718 0 +#define HID_MPS_LESS_65_719 0 +#define HID_MPS_LESS_65_720 0 +#define HID_MPS_LESS_65_721 0 +#define HID_MPS_LESS_65_722 0 +#define HID_MPS_LESS_65_723 0 +#define HID_MPS_LESS_65_724 0 +#define HID_MPS_LESS_65_725 0 +#define HID_MPS_LESS_65_726 0 +#define HID_MPS_LESS_65_727 0 +#define HID_MPS_LESS_65_728 0 +#define HID_MPS_LESS_65_729 0 +#define HID_MPS_LESS_65_730 0 +#define HID_MPS_LESS_65_731 0 +#define HID_MPS_LESS_65_732 0 +#define HID_MPS_LESS_65_733 0 +#define HID_MPS_LESS_65_734 0 +#define HID_MPS_LESS_65_735 0 +#define HID_MPS_LESS_65_736 0 +#define HID_MPS_LESS_65_737 0 +#define HID_MPS_LESS_65_738 0 +#define HID_MPS_LESS_65_739 0 +#define HID_MPS_LESS_65_740 0 +#define HID_MPS_LESS_65_741 0 +#define HID_MPS_LESS_65_742 0 +#define HID_MPS_LESS_65_743 0 +#define HID_MPS_LESS_65_744 0 +#define HID_MPS_LESS_65_745 0 +#define HID_MPS_LESS_65_746 0 +#define HID_MPS_LESS_65_747 0 +#define HID_MPS_LESS_65_748 0 +#define HID_MPS_LESS_65_749 0 +#define HID_MPS_LESS_65_750 0 +#define HID_MPS_LESS_65_751 0 +#define HID_MPS_LESS_65_752 0 +#define HID_MPS_LESS_65_753 0 +#define HID_MPS_LESS_65_754 0 +#define HID_MPS_LESS_65_755 0 +#define HID_MPS_LESS_65_756 0 +#define HID_MPS_LESS_65_757 0 +#define HID_MPS_LESS_65_758 0 +#define HID_MPS_LESS_65_759 0 +#define HID_MPS_LESS_65_760 0 +#define HID_MPS_LESS_65_761 0 +#define HID_MPS_LESS_65_762 0 +#define HID_MPS_LESS_65_763 0 +#define HID_MPS_LESS_65_764 0 +#define HID_MPS_LESS_65_765 0 +#define HID_MPS_LESS_65_766 0 +#define HID_MPS_LESS_65_767 0 +#define HID_MPS_LESS_65_768 0 +#define HID_MPS_LESS_65_769 0 +#define HID_MPS_LESS_65_770 0 +#define HID_MPS_LESS_65_771 0 +#define HID_MPS_LESS_65_772 0 +#define HID_MPS_LESS_65_773 0 +#define HID_MPS_LESS_65_774 0 +#define HID_MPS_LESS_65_775 0 +#define HID_MPS_LESS_65_776 0 +#define HID_MPS_LESS_65_777 0 +#define HID_MPS_LESS_65_778 0 +#define HID_MPS_LESS_65_779 0 +#define HID_MPS_LESS_65_780 0 +#define HID_MPS_LESS_65_781 0 +#define HID_MPS_LESS_65_782 0 +#define HID_MPS_LESS_65_783 0 +#define HID_MPS_LESS_65_784 0 +#define HID_MPS_LESS_65_785 0 +#define HID_MPS_LESS_65_786 0 +#define HID_MPS_LESS_65_787 0 +#define HID_MPS_LESS_65_788 0 +#define HID_MPS_LESS_65_789 0 +#define HID_MPS_LESS_65_790 0 +#define HID_MPS_LESS_65_791 0 +#define HID_MPS_LESS_65_792 0 +#define HID_MPS_LESS_65_793 0 +#define HID_MPS_LESS_65_794 0 +#define HID_MPS_LESS_65_795 0 +#define HID_MPS_LESS_65_796 0 +#define HID_MPS_LESS_65_797 0 +#define HID_MPS_LESS_65_798 0 +#define HID_MPS_LESS_65_799 0 +#define HID_MPS_LESS_65_800 0 +#define HID_MPS_LESS_65_801 0 +#define HID_MPS_LESS_65_802 0 +#define HID_MPS_LESS_65_803 0 +#define HID_MPS_LESS_65_804 0 +#define HID_MPS_LESS_65_805 0 +#define HID_MPS_LESS_65_806 0 +#define HID_MPS_LESS_65_807 0 +#define HID_MPS_LESS_65_808 0 +#define HID_MPS_LESS_65_809 0 +#define HID_MPS_LESS_65_810 0 +#define HID_MPS_LESS_65_811 0 +#define HID_MPS_LESS_65_812 0 +#define HID_MPS_LESS_65_813 0 +#define HID_MPS_LESS_65_814 0 +#define HID_MPS_LESS_65_815 0 +#define HID_MPS_LESS_65_816 0 +#define HID_MPS_LESS_65_817 0 +#define HID_MPS_LESS_65_818 0 +#define HID_MPS_LESS_65_819 0 +#define HID_MPS_LESS_65_820 0 +#define HID_MPS_LESS_65_821 0 +#define HID_MPS_LESS_65_822 0 +#define HID_MPS_LESS_65_823 0 +#define HID_MPS_LESS_65_824 0 +#define HID_MPS_LESS_65_825 0 +#define HID_MPS_LESS_65_826 0 +#define HID_MPS_LESS_65_827 0 +#define HID_MPS_LESS_65_828 0 +#define HID_MPS_LESS_65_829 0 +#define HID_MPS_LESS_65_830 0 +#define HID_MPS_LESS_65_831 0 +#define HID_MPS_LESS_65_832 0 +#define HID_MPS_LESS_65_833 0 +#define HID_MPS_LESS_65_834 0 +#define HID_MPS_LESS_65_835 0 +#define HID_MPS_LESS_65_836 0 +#define HID_MPS_LESS_65_837 0 +#define HID_MPS_LESS_65_838 0 +#define HID_MPS_LESS_65_839 0 +#define HID_MPS_LESS_65_840 0 +#define HID_MPS_LESS_65_841 0 +#define HID_MPS_LESS_65_842 0 +#define HID_MPS_LESS_65_843 0 +#define HID_MPS_LESS_65_844 0 +#define HID_MPS_LESS_65_845 0 +#define HID_MPS_LESS_65_846 0 +#define HID_MPS_LESS_65_847 0 +#define HID_MPS_LESS_65_848 0 +#define HID_MPS_LESS_65_849 0 +#define HID_MPS_LESS_65_850 0 +#define HID_MPS_LESS_65_851 0 +#define HID_MPS_LESS_65_852 0 +#define HID_MPS_LESS_65_853 0 +#define HID_MPS_LESS_65_854 0 +#define HID_MPS_LESS_65_855 0 +#define HID_MPS_LESS_65_856 0 +#define HID_MPS_LESS_65_857 0 +#define HID_MPS_LESS_65_858 0 +#define HID_MPS_LESS_65_859 0 +#define HID_MPS_LESS_65_860 0 +#define HID_MPS_LESS_65_861 0 +#define HID_MPS_LESS_65_862 0 +#define HID_MPS_LESS_65_863 0 +#define HID_MPS_LESS_65_864 0 +#define HID_MPS_LESS_65_865 0 +#define HID_MPS_LESS_65_866 0 +#define HID_MPS_LESS_65_867 0 +#define HID_MPS_LESS_65_868 0 +#define HID_MPS_LESS_65_869 0 +#define HID_MPS_LESS_65_870 0 +#define HID_MPS_LESS_65_871 0 +#define HID_MPS_LESS_65_872 0 +#define HID_MPS_LESS_65_873 0 +#define HID_MPS_LESS_65_874 0 +#define HID_MPS_LESS_65_875 0 +#define HID_MPS_LESS_65_876 0 +#define HID_MPS_LESS_65_877 0 +#define HID_MPS_LESS_65_878 0 +#define HID_MPS_LESS_65_879 0 +#define HID_MPS_LESS_65_880 0 +#define HID_MPS_LESS_65_881 0 +#define HID_MPS_LESS_65_882 0 +#define HID_MPS_LESS_65_883 0 +#define HID_MPS_LESS_65_884 0 +#define HID_MPS_LESS_65_885 0 +#define HID_MPS_LESS_65_886 0 +#define HID_MPS_LESS_65_887 0 +#define HID_MPS_LESS_65_888 0 +#define HID_MPS_LESS_65_889 0 +#define HID_MPS_LESS_65_890 0 +#define HID_MPS_LESS_65_891 0 +#define HID_MPS_LESS_65_892 0 +#define HID_MPS_LESS_65_893 0 +#define HID_MPS_LESS_65_894 0 +#define HID_MPS_LESS_65_895 0 +#define HID_MPS_LESS_65_896 0 +#define HID_MPS_LESS_65_897 0 +#define HID_MPS_LESS_65_898 0 +#define HID_MPS_LESS_65_899 0 +#define HID_MPS_LESS_65_900 0 +#define HID_MPS_LESS_65_901 0 +#define HID_MPS_LESS_65_902 0 +#define HID_MPS_LESS_65_903 0 +#define HID_MPS_LESS_65_904 0 +#define HID_MPS_LESS_65_905 0 +#define HID_MPS_LESS_65_906 0 +#define HID_MPS_LESS_65_907 0 +#define HID_MPS_LESS_65_908 0 +#define HID_MPS_LESS_65_909 0 +#define HID_MPS_LESS_65_910 0 +#define HID_MPS_LESS_65_911 0 +#define HID_MPS_LESS_65_912 0 +#define HID_MPS_LESS_65_913 0 +#define HID_MPS_LESS_65_914 0 +#define HID_MPS_LESS_65_915 0 +#define HID_MPS_LESS_65_916 0 +#define HID_MPS_LESS_65_917 0 +#define HID_MPS_LESS_65_918 0 +#define HID_MPS_LESS_65_919 0 +#define HID_MPS_LESS_65_920 0 +#define HID_MPS_LESS_65_921 0 +#define HID_MPS_LESS_65_922 0 +#define HID_MPS_LESS_65_923 0 +#define HID_MPS_LESS_65_924 0 +#define HID_MPS_LESS_65_925 0 +#define HID_MPS_LESS_65_926 0 +#define HID_MPS_LESS_65_927 0 +#define HID_MPS_LESS_65_928 0 +#define HID_MPS_LESS_65_929 0 +#define HID_MPS_LESS_65_930 0 +#define HID_MPS_LESS_65_931 0 +#define HID_MPS_LESS_65_932 0 +#define HID_MPS_LESS_65_933 0 +#define HID_MPS_LESS_65_934 0 +#define HID_MPS_LESS_65_935 0 +#define HID_MPS_LESS_65_936 0 +#define HID_MPS_LESS_65_937 0 +#define HID_MPS_LESS_65_938 0 +#define HID_MPS_LESS_65_939 0 +#define HID_MPS_LESS_65_940 0 +#define HID_MPS_LESS_65_941 0 +#define HID_MPS_LESS_65_942 0 +#define HID_MPS_LESS_65_943 0 +#define HID_MPS_LESS_65_944 0 +#define HID_MPS_LESS_65_945 0 +#define HID_MPS_LESS_65_946 0 +#define HID_MPS_LESS_65_947 0 +#define HID_MPS_LESS_65_948 0 +#define HID_MPS_LESS_65_949 0 +#define HID_MPS_LESS_65_950 0 +#define HID_MPS_LESS_65_951 0 +#define HID_MPS_LESS_65_952 0 +#define HID_MPS_LESS_65_953 0 +#define HID_MPS_LESS_65_954 0 +#define HID_MPS_LESS_65_955 0 +#define HID_MPS_LESS_65_956 0 +#define HID_MPS_LESS_65_957 0 +#define HID_MPS_LESS_65_958 0 +#define HID_MPS_LESS_65_959 0 +#define HID_MPS_LESS_65_960 0 +#define HID_MPS_LESS_65_961 0 +#define HID_MPS_LESS_65_962 0 +#define HID_MPS_LESS_65_963 0 +#define HID_MPS_LESS_65_964 0 +#define HID_MPS_LESS_65_965 0 +#define HID_MPS_LESS_65_966 0 +#define HID_MPS_LESS_65_967 0 +#define HID_MPS_LESS_65_968 0 +#define HID_MPS_LESS_65_969 0 +#define HID_MPS_LESS_65_970 0 +#define HID_MPS_LESS_65_971 0 +#define HID_MPS_LESS_65_972 0 +#define HID_MPS_LESS_65_973 0 +#define HID_MPS_LESS_65_974 0 +#define HID_MPS_LESS_65_975 0 +#define HID_MPS_LESS_65_976 0 +#define HID_MPS_LESS_65_977 0 +#define HID_MPS_LESS_65_978 0 +#define HID_MPS_LESS_65_979 0 +#define HID_MPS_LESS_65_980 0 +#define HID_MPS_LESS_65_981 0 +#define HID_MPS_LESS_65_982 0 +#define HID_MPS_LESS_65_983 0 +#define HID_MPS_LESS_65_984 0 +#define HID_MPS_LESS_65_985 0 +#define HID_MPS_LESS_65_986 0 +#define HID_MPS_LESS_65_987 0 +#define HID_MPS_LESS_65_988 0 +#define HID_MPS_LESS_65_989 0 +#define HID_MPS_LESS_65_990 0 +#define HID_MPS_LESS_65_991 0 +#define HID_MPS_LESS_65_992 0 +#define HID_MPS_LESS_65_993 0 +#define HID_MPS_LESS_65_994 0 +#define HID_MPS_LESS_65_995 0 +#define HID_MPS_LESS_65_996 0 +#define HID_MPS_LESS_65_997 0 +#define HID_MPS_LESS_65_998 0 +#define HID_MPS_LESS_65_999 0 +#define HID_MPS_LESS_65_1000 0 +#define HID_MPS_LESS_65_1001 0 +#define HID_MPS_LESS_65_1002 0 +#define HID_MPS_LESS_65_1003 0 +#define HID_MPS_LESS_65_1004 0 +#define HID_MPS_LESS_65_1005 0 +#define HID_MPS_LESS_65_1006 0 +#define HID_MPS_LESS_65_1007 0 +#define HID_MPS_LESS_65_1008 0 +#define HID_MPS_LESS_65_1009 0 +#define HID_MPS_LESS_65_1010 0 +#define HID_MPS_LESS_65_1011 0 +#define HID_MPS_LESS_65_1012 0 +#define HID_MPS_LESS_65_1013 0 +#define HID_MPS_LESS_65_1014 0 +#define HID_MPS_LESS_65_1015 0 +#define HID_MPS_LESS_65_1016 0 +#define HID_MPS_LESS_65_1017 0 +#define HID_MPS_LESS_65_1018 0 +#define HID_MPS_LESS_65_1019 0 +#define HID_MPS_LESS_65_1020 0 +#define HID_MPS_LESS_65_1021 0 +#define HID_MPS_LESS_65_1022 0 +#define HID_MPS_LESS_65_1023 0 +#define HID_MPS_LESS_65_1024 0 + +#define HID_MPS_LESS_65(x) UTIL_PRIMITIVE_CAT(HID_MPS_LESS_65_, x) + +/* + * If all the endpoint MPS are less than 65 bytes, we do not need to define and + * configure an alternate interface. + */ +#define HID_ALL_MPS_LESS_65(n) \ + UTIL_AND(HID_MPS_LESS_65(DT_INST_PROP(n, out_report_size)), \ + HID_MPS_LESS_65(DT_INST_PROP(n, in_report_size))) + +/* Get IN endpoint polling rate based on the desired speed. */ +#define HID_IN_EP_INTERVAL(n, hs) \ + COND_CODE_1(hs, \ + (USB_HS_INT_EP_INTERVAL(DT_INST_PROP(n, in_polling_rate))), \ + (USB_FS_INT_EP_INTERVAL(DT_INST_PROP(n, in_polling_rate)))) + +/* Get OUT endpoint polling rate based on the desired speed. */ +#define HID_OUT_EP_INTERVAL(n, hs) \ + COND_CODE_1(hs, \ + (USB_HS_INT_EP_INTERVAL(DT_INST_PROP(n, out_polling_rate))),\ + (USB_FS_INT_EP_INTERVAL(DT_INST_PROP(n, out_polling_rate)))) + +/* Get the number of endpoints, which can be either 1 or 2 */ +#define HID_NUM_ENDPOINTS(n) \ + COND_CODE_1(DT_INST_NODE_HAS_PROP(n, out_report_size), (2), (1)) + +/* + * Either the device does not support a boot protocol, or it supports the + * keyboard or mouse boot protocol. + */ +#define HID_INTERFACE_PROTOCOL(n) DT_INST_ENUM_IDX_OR(n, protocol_code, 0) + +/* bInterfaceSubClass must be set to 1 if a boot device protocol is supported */ +#define HID_INTERFACE_SUBCLASS(n) \ + COND_CODE_0(HID_INTERFACE_PROTOCOL(n), (0), (1)) + +#define HID_INTERFACE_DEFINE(n, alt) \ + { \ + .bLength = sizeof(struct usb_if_descriptor), \ + .bDescriptorType = USB_DESC_INTERFACE, \ + .bInterfaceNumber = 0, \ + .bAlternateSetting = alt, \ + .bNumEndpoints = HID_NUM_ENDPOINTS(n), \ + .bInterfaceClass = USB_BCC_HID, \ + .bInterfaceSubClass = HID_INTERFACE_SUBCLASS(n), \ + .bInterfaceProtocol = HID_INTERFACE_PROTOCOL(n), \ + .iInterface = 0, \ + } + +#define HID_DESCRIPTOR_DEFINE(n) \ + { \ + .bLength = sizeof(struct hid_descriptor), \ + .bDescriptorType = USB_DESC_HID, \ + .bcdHID = sys_cpu_to_le16(USB_HID_VERSION), \ + .bCountryCode = 0, \ + .bNumDescriptors = HID_SUBORDINATE_DESC_NUM, \ + .sub[0] = { \ + .bDescriptorType = USB_DESC_HID_REPORT, \ + .wDescriptorLength = 0, \ + }, \ + } \ + +/* + * OUT endpoint MPS for either default or alternate interface. + * MPS for the default interface is always limited to 64 bytes. + */ +#define HID_OUT_EP_MPS(n, alt) \ + COND_CODE_1(alt, \ + (sys_cpu_to_le16(DT_INST_PROP(n, out_report_size))), \ + (sys_cpu_to_le16(MIN(DT_INST_PROP(n, out_report_size), 64U)))) + +/* + * IN endpoint MPS for either default or alternate interface. + * MPS for the default interface is always limited to 64 bytes. + */ +#define HID_IN_EP_MPS(n, alt) \ + COND_CODE_1(alt, \ + (sys_cpu_to_le16(DT_INST_PROP(n, in_report_size))), \ + (sys_cpu_to_le16(MIN(DT_INST_PROP(n, in_report_size), 64U)))) + +#define HID_OUT_EP_DEFINE(n, hs, alt) \ + { \ + .bLength = sizeof(struct usb_ep_descriptor), \ + .bDescriptorType = USB_DESC_ENDPOINT, \ + .bEndpointAddress = 0x01, \ + .bmAttributes = USB_EP_TYPE_INTERRUPT, \ + .wMaxPacketSize = HID_OUT_EP_MPS(n, alt), \ + .bInterval = HID_OUT_EP_INTERVAL(n, hs), \ + } + +#define HID_IN_EP_DEFINE(n, hs, alt) \ + { \ + .bLength = sizeof(struct usb_ep_descriptor), \ + .bDescriptorType = USB_DESC_ENDPOINT, \ + .bEndpointAddress = 0x81, \ + .bmAttributes = USB_EP_TYPE_INTERRUPT, \ + .wMaxPacketSize = HID_IN_EP_MPS(n, alt), \ + .bInterval = HID_IN_EP_INTERVAL(n, hs), \ + } + +/* + * Both the optional OUT endpoint and the associated pool are only defined if + * there is an out-report-size property. + */ +#define HID_OUT_EP_DEFINE_OR_ZERO(n, hs, alt) \ + COND_CODE_1(DT_INST_NODE_HAS_PROP(n, out_report_size), \ + (HID_OUT_EP_DEFINE(n, hs, alt)), \ + ({0})) + +#define HID_OUT_POOL_DEFINE(n) \ + COND_CODE_1(DT_INST_NODE_HAS_PROP(n, out_report_size), \ + (NET_BUF_POOL_DEFINE(hid_buf_pool_out_##n, \ + CONFIG_USBD_HID_OUT_BUF_COUNT, \ + DT_INST_PROP(n, out_report_size), \ + sizeof(struct udc_buf_info), NULL)), \ + ()) + +#define HID_OUT_POOL_ADDR(n) \ + COND_CODE_1(DT_INST_NODE_HAS_PROP(n, out_report_size), \ + (&hid_buf_pool_out_##n), (NULL)) + +#endif /* ZEPHYR_USB_DEVICE_CLASS_HID_MACROS_H_ */ diff --git a/subsys/usb/device_next/class/usbd_msc.c b/subsys/usb/device_next/class/usbd_msc.c index 5e61fc29b46..1cf23170b1a 100644 --- a/subsys/usb/device_next/class/usbd_msc.c +++ b/subsys/usb/device_next/class/usbd_msc.c @@ -60,14 +60,6 @@ struct CSW { /* Single instance is likely enough because it can support multiple LUNs */ #define MSC_NUM_INSTANCES CONFIG_USBD_MSC_INSTANCES_COUNT -/* TODO: Bulk wMaxPacketSize is ultimately determined by connection speed - * and can be 8/16/32/64 on Full-Speed and 512 on High-Speed. USBD handler - * will update the value based on first connected speed which is wrong, - * because it has to be set to valid value at connected speed on every - * connection. - */ -#define MSC_DEFAULT_BULK_EP_MPS 0 - /* Can be 64 if device is not High-Speed capable */ #define MSC_BUF_SIZE 512 @@ -76,7 +68,7 @@ NET_BUF_POOL_FIXED_DEFINE(msc_ep_pool, sizeof(struct udc_buf_info), NULL); struct msc_event { - struct usbd_class_node *node; + struct usbd_class_data *c_data; /* NULL to request Bulk-Only Mass Storage Reset * Otherwise must point to previously enqueued endpoint buffer */ @@ -95,8 +87,10 @@ struct msc_bot_desc { struct usb_if_descriptor if0; struct usb_ep_descriptor if0_in_ep; struct usb_ep_descriptor if0_out_ep; + struct usb_ep_descriptor if0_hs_in_ep; + struct usb_ep_descriptor if0_hs_out_ep; struct usb_desc_header nil_desc; -} __packed; +}; enum { MSC_CLASS_ENABLED, @@ -117,7 +111,10 @@ enum msc_bot_state { }; struct msc_bot_ctx { - struct usbd_class_node *class_node; + struct usbd_class_data *class_node; + struct msc_bot_desc *const desc; + const struct usb_desc_header **const fs_desc; + const struct usb_desc_header **const hs_desc; atomic_t bits; enum msc_bot_state state; uint8_t registered_luns; @@ -147,23 +144,35 @@ static struct net_buf *msc_buf_alloc(const uint8_t ep) return buf; } -static uint8_t msc_get_bulk_in(struct usbd_class_node *const node) +static uint8_t msc_get_bulk_in(struct usbd_class_data *const c_data) { - struct msc_bot_desc *desc = node->data->desc; + struct usbd_contex *uds_ctx = usbd_class_get_ctx(c_data); + struct msc_bot_ctx *ctx = usbd_class_get_private(c_data); + struct msc_bot_desc *desc = ctx->desc; + + if (usbd_bus_speed(uds_ctx) == USBD_SPEED_HS) { + return desc->if0_hs_in_ep.bEndpointAddress; + } return desc->if0_in_ep.bEndpointAddress; } -static uint8_t msc_get_bulk_out(struct usbd_class_node *const node) +static uint8_t msc_get_bulk_out(struct usbd_class_data *const c_data) { - struct msc_bot_desc *desc = node->data->desc; + struct usbd_contex *uds_ctx = usbd_class_get_ctx(c_data); + struct msc_bot_ctx *ctx = usbd_class_get_private(c_data); + struct msc_bot_desc *desc = ctx->desc; + + if (usbd_bus_speed(uds_ctx) == USBD_SPEED_HS) { + return desc->if0_hs_out_ep.bEndpointAddress; + } return desc->if0_out_ep.bEndpointAddress; } -static void msc_queue_bulk_out_ep(struct usbd_class_node *const node) +static void msc_queue_bulk_out_ep(struct usbd_class_data *const c_data) { - struct msc_bot_ctx *ctx = node->data->priv; + struct msc_bot_ctx *ctx = usbd_class_get_private(c_data); struct net_buf *buf; uint8_t ep; int ret; @@ -174,14 +183,14 @@ static void msc_queue_bulk_out_ep(struct usbd_class_node *const node) } LOG_DBG("Queuing OUT"); - ep = msc_get_bulk_out(node); + ep = msc_get_bulk_out(c_data); buf = msc_buf_alloc(ep); /* The pool is large enough to support all allocations. Failing alloc * indicates either a memory leak or logic error. */ __ASSERT_NO_MSG(buf); - ret = usbd_ep_enqueue(node, buf); + ret = usbd_ep_enqueue(c_data, buf); if (ret) { LOG_ERR("Failed to enqueue net_buf for 0x%02x", ep); net_buf_unref(buf); @@ -189,25 +198,25 @@ static void msc_queue_bulk_out_ep(struct usbd_class_node *const node) } } -static void msc_stall_bulk_out_ep(struct usbd_class_node *const node) +static void msc_stall_bulk_out_ep(struct usbd_class_data *const c_data) { uint8_t ep; - ep = msc_get_bulk_out(node); - usbd_ep_set_halt(node->data->uds_ctx, ep); + ep = msc_get_bulk_out(c_data); + usbd_ep_set_halt(usbd_class_get_ctx(c_data), ep); } -static void msc_stall_bulk_in_ep(struct usbd_class_node *const node) +static void msc_stall_bulk_in_ep(struct usbd_class_data *const c_data) { uint8_t ep; - ep = msc_get_bulk_in(node); - usbd_ep_set_halt(node->data->uds_ctx, ep); + ep = msc_get_bulk_in(c_data); + usbd_ep_set_halt(usbd_class_get_ctx(c_data), ep); } -static void msc_reset_handler(struct usbd_class_node *node) +static void msc_reset_handler(struct usbd_class_data *c_data) { - struct msc_bot_ctx *ctx = node->data->priv; + struct msc_bot_ctx *ctx = usbd_class_get_private(c_data); int i; LOG_INF("Bulk-Only Mass Storage Reset"); @@ -554,11 +563,11 @@ static void msc_send_csw(struct msc_bot_ctx *ctx) ctx->state = MSC_BBB_WAIT_FOR_CSW_SENT; } -static void usbd_msc_handle_request(struct usbd_class_node *node, +static void usbd_msc_handle_request(struct usbd_class_data *c_data, struct net_buf *buf, int err) { - struct usbd_contex *uds_ctx = node->data->uds_ctx; - struct msc_bot_ctx *ctx = node->data->priv; + struct usbd_contex *uds_ctx = usbd_class_get_ctx(c_data); + struct msc_bot_ctx *ctx = usbd_class_get_private(c_data); struct udc_buf_info *bi; bi = udc_get_buf_info(buf); @@ -574,16 +583,16 @@ static void usbd_msc_handle_request(struct usbd_class_node *node, goto ep_request_error; } - if (bi->ep == msc_get_bulk_out(node)) { + if (bi->ep == msc_get_bulk_out(c_data)) { msc_handle_bulk_out(ctx, buf->data, buf->len); - } else if (bi->ep == msc_get_bulk_in(node)) { + } else if (bi->ep == msc_get_bulk_in(c_data)) { msc_handle_bulk_in(ctx, buf->data, buf->len); } ep_request_error: - if (bi->ep == msc_get_bulk_out(node)) { + if (bi->ep == msc_get_bulk_out(c_data)) { atomic_clear_bit(&ctx->bits, MSC_BULK_OUT_QUEUED); - } else if (bi->ep == msc_get_bulk_in(node)) { + } else if (bi->ep == msc_get_bulk_in(c_data)) { atomic_clear_bit(&ctx->bits, MSC_BULK_IN_QUEUED); } usbd_ep_buf_free(uds_ctx, buf); @@ -600,11 +609,11 @@ static void usbd_msc_thread(void *arg1, void *arg2, void *arg3) while (1) { k_msgq_get(&msc_msgq, &evt, K_FOREVER); - ctx = evt.node->data->priv; + ctx = usbd_class_get_private(evt.c_data); if (evt.buf == NULL) { - msc_reset_handler(evt.node); + msc_reset_handler(evt.c_data); } else { - usbd_msc_handle_request(evt.node, evt.buf, evt.err); + usbd_msc_handle_request(evt.c_data, evt.buf, evt.err); } if (!atomic_test_bit(&ctx->bits, MSC_CLASS_ENABLED)) { @@ -615,7 +624,7 @@ static void usbd_msc_thread(void *arg1, void *arg2, void *arg3) case MSC_BBB_EXPECT_CBW: case MSC_BBB_PROCESS_WRITE: /* Ensure we can accept next OUT packet */ - msc_queue_bulk_out_ep(evt.node); + msc_queue_bulk_out_ep(evt.c_data); break; default: break; @@ -635,17 +644,17 @@ static void usbd_msc_thread(void *arg1, void *arg2, void *arg3) if (ctx->state == MSC_BBB_PROCESS_READ) { msc_process_read(ctx); } else if (ctx->state == MSC_BBB_PROCESS_WRITE) { - msc_queue_bulk_out_ep(evt.node); + msc_queue_bulk_out_ep(evt.c_data); } else if (ctx->state == MSC_BBB_SEND_CSW) { msc_send_csw(ctx); } } } -static void msc_bot_schedule_reset(struct usbd_class_node *node) +static void msc_bot_schedule_reset(struct usbd_class_data *c_data) { struct msc_event request = { - .node = node, + .c_data = c_data, .buf = NULL, /* Bulk-Only Mass Storage Reset */ }; @@ -653,30 +662,30 @@ static void msc_bot_schedule_reset(struct usbd_class_node *node) } /* Feature endpoint halt state handler */ -static void msc_bot_feature_halt(struct usbd_class_node *const node, +static void msc_bot_feature_halt(struct usbd_class_data *const c_data, const uint8_t ep, const bool halted) { - struct msc_bot_ctx *ctx = node->data->priv; + struct msc_bot_ctx *ctx = usbd_class_get_private(c_data); - if (ep == msc_get_bulk_in(node) && !halted && + if (ep == msc_get_bulk_in(c_data) && !halted && atomic_test_bit(&ctx->bits, MSC_BULK_IN_WEDGED)) { /* Endpoint shall remain halted until Reset Recovery */ - usbd_ep_set_halt(node->data->uds_ctx, ep); - } else if (ep == msc_get_bulk_out(node) && !halted && + usbd_ep_set_halt(usbd_class_get_ctx(c_data), ep); + } else if (ep == msc_get_bulk_out(c_data) && !halted && atomic_test_bit(&ctx->bits, MSC_BULK_OUT_WEDGED)) { /* Endpoint shall remain halted until Reset Recovery */ - usbd_ep_set_halt(node->data->uds_ctx, ep); + usbd_ep_set_halt(usbd_class_get_ctx(c_data), ep); } } /* USB control request handler to device */ -static int msc_bot_control_to_dev(struct usbd_class_node *const node, +static int msc_bot_control_to_dev(struct usbd_class_data *const c_data, const struct usb_setup_packet *const setup, const struct net_buf *const buf) { if (setup->bRequest == BULK_ONLY_MASS_STORAGE_RESET && setup->wValue == 0 && setup->wLength == 0) { - msc_bot_schedule_reset(node); + msc_bot_schedule_reset(c_data); } else { errno = -ENOTSUP; } @@ -685,11 +694,11 @@ static int msc_bot_control_to_dev(struct usbd_class_node *const node, } /* USB control request handler to host */ -static int msc_bot_control_to_host(struct usbd_class_node *const node, +static int msc_bot_control_to_host(struct usbd_class_data *const c_data, const struct usb_setup_packet *const setup, struct net_buf *const buf) { - struct msc_bot_ctx *ctx = node->data->priv; + struct msc_bot_ctx *ctx = usbd_class_get_private(c_data); uint8_t max_lun; if (setup->bRequest == GET_MAX_LUN && @@ -708,11 +717,11 @@ static int msc_bot_control_to_host(struct usbd_class_node *const node, } /* Endpoint request completion event handler */ -static int msc_bot_request_handler(struct usbd_class_node *const node, +static int msc_bot_request_handler(struct usbd_class_data *const c_data, struct net_buf *buf, int err) { struct msc_event request = { - .node = node, + .c_data = c_data, .buf = buf, .err = err, }; @@ -724,30 +733,42 @@ static int msc_bot_request_handler(struct usbd_class_node *const node, } /* Class associated configuration is selected */ -static void msc_bot_enable(struct usbd_class_node *const node) +static void msc_bot_enable(struct usbd_class_data *const c_data) { - struct msc_bot_ctx *ctx = node->data->priv; + struct msc_bot_ctx *ctx = usbd_class_get_private(c_data); LOG_INF("Enable"); atomic_set_bit(&ctx->bits, MSC_CLASS_ENABLED); - msc_bot_schedule_reset(node); + msc_bot_schedule_reset(c_data); } /* Class associated configuration is disabled */ -static void msc_bot_disable(struct usbd_class_node *const node) +static void msc_bot_disable(struct usbd_class_data *const c_data) { - struct msc_bot_ctx *ctx = node->data->priv; + struct msc_bot_ctx *ctx = usbd_class_get_private(c_data); LOG_INF("Disable"); atomic_clear_bit(&ctx->bits, MSC_CLASS_ENABLED); } +static void *msc_bot_get_desc(struct usbd_class_data *const c_data, + const enum usbd_speed speed) +{ + struct msc_bot_ctx *ctx = usbd_class_get_private(c_data); + + if (speed == USBD_SPEED_HS) { + return ctx->hs_desc; + } + + return ctx->fs_desc; +} + /* Initialization of the class implementation */ -static int msc_bot_init(struct usbd_class_node *const node) +static int msc_bot_init(struct usbd_class_data *const c_data) { - struct msc_bot_ctx *ctx = node->data->priv; + struct msc_bot_ctx *ctx = usbd_class_get_private(c_data); - ctx->class_node = node; + ctx->class_node = c_data; ctx->state = MSC_BBB_EXPECT_CBW; ctx->registered_luns = 0; @@ -782,7 +803,7 @@ static struct msc_bot_desc msc_bot_desc_##n = { \ .bDescriptorType = USB_DESC_ENDPOINT, \ .bEndpointAddress = 0x81, \ .bmAttributes = USB_EP_TYPE_BULK, \ - .wMaxPacketSize = sys_cpu_to_le16(MSC_DEFAULT_BULK_EP_MPS), \ + .wMaxPacketSize = sys_cpu_to_le16(64U), \ .bInterval = 0, \ }, \ .if0_out_ep = { \ @@ -790,7 +811,23 @@ static struct msc_bot_desc msc_bot_desc_##n = { \ .bDescriptorType = USB_DESC_ENDPOINT, \ .bEndpointAddress = 0x01, \ .bmAttributes = USB_EP_TYPE_BULK, \ - .wMaxPacketSize = sys_cpu_to_le16(MSC_DEFAULT_BULK_EP_MPS), \ + .wMaxPacketSize = sys_cpu_to_le16(64U), \ + .bInterval = 0, \ + }, \ + .if0_hs_in_ep = { \ + .bLength = sizeof(struct usb_ep_descriptor), \ + .bDescriptorType = USB_DESC_ENDPOINT, \ + .bEndpointAddress = 0x81, \ + .bmAttributes = USB_EP_TYPE_BULK, \ + .wMaxPacketSize = sys_cpu_to_le16(512U), \ + .bInterval = 0, \ + }, \ + .if0_hs_out_ep = { \ + .bLength = sizeof(struct usb_ep_descriptor), \ + .bDescriptorType = USB_DESC_ENDPOINT, \ + .bEndpointAddress = 0x01, \ + .bmAttributes = USB_EP_TYPE_BULK, \ + .wMaxPacketSize = sys_cpu_to_le16(512U), \ .bInterval = 0, \ }, \ \ @@ -798,8 +835,23 @@ static struct msc_bot_desc msc_bot_desc_##n = { \ .bLength = 0, \ .bDescriptorType = 0, \ }, \ +}; \ + \ +const static struct usb_desc_header *msc_bot_fs_desc_##n[] = { \ + (struct usb_desc_header *) &msc_bot_desc_##n.if0, \ + (struct usb_desc_header *) &msc_bot_desc_##n.if0_in_ep, \ + (struct usb_desc_header *) &msc_bot_desc_##n.if0_out_ep, \ + (struct usb_desc_header *) &msc_bot_desc_##n.nil_desc, \ +}; \ + \ +const static struct usb_desc_header *msc_bot_hs_desc_##n[] = { \ + (struct usb_desc_header *) &msc_bot_desc_##n.if0, \ + (struct usb_desc_header *) &msc_bot_desc_##n.if0_hs_in_ep, \ + (struct usb_desc_header *) &msc_bot_desc_##n.if0_hs_out_ep, \ + (struct usb_desc_header *) &msc_bot_desc_##n.nil_desc, \ }; + struct usbd_class_api msc_bot_api = { .feature_halt = msc_bot_feature_halt, .control_to_dev = msc_bot_control_to_dev, @@ -807,18 +859,19 @@ struct usbd_class_api msc_bot_api = { .request = msc_bot_request_handler, .enable = msc_bot_enable, .disable = msc_bot_disable, + .get_desc = msc_bot_get_desc, .init = msc_bot_init, }; #define DEFINE_MSC_BOT_CLASS_DATA(x, _) \ - static struct msc_bot_ctx msc_bot_ctx_##x; \ - static struct usbd_class_data msc_bot_class_##x = { \ - .desc = (struct usb_desc_header *)&msc_bot_desc_##x, \ - .v_reqs = &msc_bot_vregs, \ - .priv = &msc_bot_ctx_##x, \ + static struct msc_bot_ctx msc_bot_ctx_##x = { \ + .desc = &msc_bot_desc_##x, \ + .fs_desc = msc_bot_fs_desc_##x, \ + .hs_desc = msc_bot_hs_desc_##x, \ }; \ \ - USBD_DEFINE_CLASS(msc_##x, &msc_bot_api, &msc_bot_class_##x); + USBD_DEFINE_CLASS(msc_##x, &msc_bot_api, &msc_bot_ctx_##x, \ + &msc_bot_vregs); LISTIFY(MSC_NUM_INSTANCES, DEFINE_MSC_BOT_DESCRIPTOR, ()) LISTIFY(MSC_NUM_INSTANCES, DEFINE_MSC_BOT_CLASS_DATA, ()) diff --git a/subsys/usb/device_next/class/usbd_msc.ld b/subsys/usb/device_next/class/usbd_msc.ld index bf06af14dfc..9c0195ddf6a 100644 --- a/subsys/usb/device_next/class/usbd_msc.ld +++ b/subsys/usb/device_next/class/usbd_msc.ld @@ -1,3 +1,3 @@ #include -ITERABLE_SECTION_ROM(usbd_msc_lun, 4) +ITERABLE_SECTION_ROM(usbd_msc_lun, Z_LINK_ITERABLE_SUBALIGN) diff --git a/subsys/usb/device_next/class/usbd_uac2.c b/subsys/usb/device_next/class/usbd_uac2.c index b04ac2e7f14..f69da75e336 100644 --- a/subsys/usb/device_next/class/usbd_uac2.c +++ b/subsys/usb/device_next/class/usbd_uac2.c @@ -68,7 +68,7 @@ typedef enum { ENTITY_TYPE_OUTPUT_TERMINAL, } entity_type_t; -static size_t clock_frequencies(struct usbd_class_node *const node, +static size_t clock_frequencies(struct usbd_class_data *const c_data, const uint8_t id, const uint32_t **frequencies); /* UAC2 device runtime data */ @@ -85,27 +85,28 @@ struct uac2_ctx { /* UAC2 device constant data */ struct uac2_cfg { - struct usbd_class_node *const node; + struct usbd_class_data *const c_data; + const struct usb_desc_header **descriptors; /* Entity 1 type is at entity_types[0] */ const entity_type_t *entity_types; - /* Array of offsets to data endpoint bEndpointAddress in descriptors. - * First AudioStreaming interface is at ep_offsets[0]. Offset is 0 if + /* Array of indexes to data endpoint descriptor in descriptors set. + * First AudioStreaming interface is at ep_indexes[0]. Index is 0 if * the interface is external interface (Type IV), i.e. no endpoint. */ - const uint16_t *ep_offsets; - /* Same as ep_offsets, but for explicit feedback endpoints. */ - const uint16_t *fb_offsets; + const uint16_t *ep_indexes; + /* Same as ep_indexes, but for explicit feedback endpoints. */ + const uint16_t *fb_indexes; /* First AudioStreaming interface Terminal ID is at as_terminals[0]. */ const uint8_t *as_terminals; - /* Number of interfaces (ep_offsets, fb_offset and as_terminals size) */ + /* Number of interfaces (ep_indexes, fb_indexes and as_terminals size) */ uint8_t num_ifaces; /* Number of entities (entity_type array size) */ uint8_t num_entities; }; -static entity_type_t id_type(struct usbd_class_node *const node, uint8_t id) +static entity_type_t id_type(struct usbd_class_data *const c_data, uint8_t id) { - const struct device *dev = node->data->priv; + const struct device *dev = usbd_class_get_private(c_data); const struct uac2_cfg *cfg = dev->config; if ((id - 1) < cfg->num_entities) { @@ -116,56 +117,54 @@ static entity_type_t id_type(struct usbd_class_node *const node, uint8_t id) } static const struct usb_ep_descriptor * -get_as_data_ep(struct usbd_class_node *const node, int as_idx) +get_as_data_ep(struct usbd_class_data *const c_data, int as_idx) { - const struct device *dev = node->data->priv; + const struct device *dev = usbd_class_get_private(c_data); const struct uac2_cfg *cfg = dev->config; - const uint8_t *desc = node->data->desc; + const struct usb_desc_header *desc = NULL; - if ((as_idx < cfg->num_ifaces) && cfg->ep_offsets[as_idx]) { - return CONTAINER_OF(&desc[cfg->ep_offsets[as_idx]], - const struct usb_ep_descriptor, - bEndpointAddress); + if ((as_idx < cfg->num_ifaces) && cfg->ep_indexes[as_idx]) { + desc = cfg->descriptors[cfg->ep_indexes[as_idx]]; } - return NULL; + return (const struct usb_ep_descriptor *)desc; } static const struct usb_ep_descriptor * -get_as_feedback_ep(struct usbd_class_node *const node, int as_idx) +get_as_feedback_ep(struct usbd_class_data *const c_data, int as_idx) { - const struct device *dev = node->data->priv; + const struct device *dev = usbd_class_get_private(c_data); const struct uac2_cfg *cfg = dev->config; - const uint8_t *desc = node->data->desc; + const struct usb_desc_header *desc = NULL; - if ((as_idx < cfg->num_ifaces) && cfg->fb_offsets[as_idx]) { - return CONTAINER_OF(&desc[cfg->fb_offsets[as_idx]], - const struct usb_ep_descriptor, - bEndpointAddress); + if ((as_idx < cfg->num_ifaces) && cfg->fb_indexes[as_idx]) { + desc = cfg->descriptors[cfg->fb_indexes[as_idx]]; } - return NULL; + return (const struct usb_ep_descriptor *)desc; } static int ep_to_as_interface(const struct device *dev, uint8_t ep, bool *fb) { const struct uac2_cfg *cfg = dev->config; - const uint8_t *desc = cfg->node->data->desc; + const struct usb_ep_descriptor *desc; for (int i = 0; i < cfg->num_ifaces; i++) { - if (!cfg->ep_offsets[i]) { + if (!cfg->ep_indexes[i]) { /* If there is no data endpoint there cannot be feedback * endpoint. Simply skip external interfaces. */ continue; } - if (ep == desc[cfg->ep_offsets[i]]) { + desc = get_as_data_ep(cfg->c_data, i); + if (desc && (ep == desc->bEndpointAddress)) { *fb = false; return i; } - if (cfg->fb_offsets[i] && (ep == desc[cfg->fb_offsets[i]])) { + desc = get_as_feedback_ep(cfg->c_data, i); + if (desc && (ep == desc->bEndpointAddress)) { *fb = true; return i; } @@ -226,15 +225,16 @@ int usbd_uac2_send(const struct device *dev, uint8_t terminal, void *data, uint16_t size) { const struct uac2_cfg *cfg = dev->config; - const uint8_t *desc = cfg->node->data->desc; struct uac2_ctx *ctx = dev->data; struct net_buf *buf; + const struct usb_ep_descriptor *desc; uint8_t ep = 0; int as_idx = terminal_to_as_interface(dev, terminal); int ret; - if ((as_idx >= 0) && cfg->ep_offsets[as_idx]) { - ep = desc[cfg->ep_offsets[as_idx]]; + desc = get_as_data_ep(cfg->c_data, as_idx); + if (desc) { + ep = desc->bEndpointAddress; } if (!ep) { @@ -264,7 +264,7 @@ int usbd_uac2_send(const struct device *dev, uint8_t terminal, return -ENOMEM; } - ret = usbd_ep_enqueue(cfg->node, buf); + ret = usbd_ep_enqueue(cfg->c_data, buf); if (ret) { LOG_ERR("Failed to enqueue net_buf for 0x%02x", ep); net_buf_unref(buf); @@ -275,10 +275,10 @@ int usbd_uac2_send(const struct device *dev, uint8_t terminal, return ret; } -static void schedule_iso_out_read(struct usbd_class_node *const node, +static void schedule_iso_out_read(struct usbd_class_data *const c_data, uint8_t ep, uint16_t mps, uint8_t terminal) { - struct device *dev = node->data->priv; + const struct device *dev = usbd_class_get_private(c_data); const struct uac2_cfg *cfg = dev->config; struct uac2_ctx *ctx = dev->data; struct net_buf *buf; @@ -324,7 +324,7 @@ static void schedule_iso_out_read(struct usbd_class_node *const node, return; } - ret = usbd_ep_enqueue(node, buf); + ret = usbd_ep_enqueue(c_data, buf); if (ret) { LOG_ERR("Failed to enqueue net_buf for 0x%02x", ep); net_buf_unref(buf); @@ -332,10 +332,11 @@ static void schedule_iso_out_read(struct usbd_class_node *const node, } } -static void write_explicit_feedback(struct usbd_class_node *const node, +static void write_explicit_feedback(struct usbd_class_data *const c_data, uint8_t ep, uint8_t terminal) { - struct device *dev = node->data->priv; + const struct device *dev = usbd_class_get_private(c_data); + struct usbd_contex *uds_ctx = usbd_class_get_ctx(c_data); struct uac2_ctx *ctx = dev->data; struct net_buf *buf; struct udc_buf_info *bi; @@ -359,13 +360,13 @@ static void write_explicit_feedback(struct usbd_class_node *const node, * class instances for high-speed and full-speed (because high-speed * allows more sampling rates and/or bit depths)? */ - if (udc_device_speed(node->data->uds_ctx->dev) == UDC_BUS_SPEED_FS) { + if (usbd_bus_speed(uds_ctx) == USBD_SPEED_FS) { net_buf_add_le24(buf, fb_value); } else { net_buf_add_le32(buf, fb_value); } - ret = usbd_ep_enqueue(node, buf); + ret = usbd_ep_enqueue(c_data, buf); if (ret) { LOG_ERR("Failed to enqueue net_buf for 0x%02x", ep); net_buf_unref(buf); @@ -374,10 +375,11 @@ static void write_explicit_feedback(struct usbd_class_node *const node, } } -void uac2_update(struct usbd_class_node *const node, +void uac2_update(struct usbd_class_data *const c_data, uint8_t iface, uint8_t alternate) { - struct device *dev = node->data->priv; + const struct device *dev = usbd_class_get_private(c_data); + struct usbd_contex *uds_ctx = usbd_class_get_ctx(c_data); const struct uac2_cfg *cfg = dev->config; struct uac2_ctx *ctx = dev->data; const struct usb_association_descriptor *iad; @@ -387,7 +389,7 @@ void uac2_update(struct usbd_class_node *const node, LOG_DBG("iface %d alt %d", iface, alternate); - iad = (const struct usb_association_descriptor *)node->data->desc; + iad = (const struct usb_association_descriptor *)cfg->descriptors[0]; /* AudioControl interface (bFirstInterface) doesn't have alternate * configurations, therefore the iface must be AudioStreaming. @@ -399,7 +401,7 @@ void uac2_update(struct usbd_class_node *const node, /* Audio class is forbidden on Low-Speed, therefore the only possibility * for not using microframes is when device operates at Full-Speed. */ - if (udc_device_speed(node->data->uds_ctx->dev) == UDC_BUS_SPEED_FS) { + if (usbd_bus_speed(uds_ctx) == USBD_SPEED_FS) { microframes = false; } else { microframes = true; @@ -419,20 +421,20 @@ void uac2_update(struct usbd_class_node *const node, atomic_set_bit(&ctx->as_active, as_idx); - data_ep = get_as_data_ep(node, as_idx); + data_ep = get_as_data_ep(c_data, as_idx); /* External interfaces (i.e. NULL data_ep) do not have alternate * configuration and therefore data_ep must be valid here. */ __ASSERT_NO_MSG(data_ep); if (USB_EP_DIR_IS_OUT(data_ep->bEndpointAddress)) { - schedule_iso_out_read(node, data_ep->bEndpointAddress, + schedule_iso_out_read(c_data, data_ep->bEndpointAddress, sys_le16_to_cpu(data_ep->wMaxPacketSize), cfg->as_terminals[as_idx]); - fb_ep = get_as_feedback_ep(node, as_idx); + fb_ep = get_as_feedback_ep(c_data, as_idx); if (fb_ep) { - write_explicit_feedback(node, fb_ep->bEndpointAddress, + write_explicit_feedback(c_data, fb_ep->bEndpointAddress, cfg->as_terminals[as_idx]); } } @@ -492,7 +494,7 @@ static void layout3_range_response(struct net_buf *const buf, uint16_t length, } } -static int get_clock_source_request(struct usbd_class_node *const node, +static int get_clock_source_request(struct usbd_class_data *const c_data, const struct usb_setup_packet *const setup, struct net_buf *const buf) { @@ -507,7 +509,7 @@ static int get_clock_source_request(struct usbd_class_node *const node, return 0; } - count = clock_frequencies(node, CONTROL_ENTITY_ID(setup), &frequencies); + count = clock_frequencies(c_data, CONTROL_ENTITY_ID(setup), &frequencies); if (CONTROL_SELECTOR(setup) == CS_SAM_FREQ_CONTROL) { if (CONTROL_ATTRIBUTE(setup) == CUR) { @@ -534,7 +536,7 @@ static int get_clock_source_request(struct usbd_class_node *const node, return 0; } -static int uac2_control_to_host(struct usbd_class_node *const node, +static int uac2_control_to_host(struct usbd_class_data *const c_data, const struct usb_setup_packet *const setup, struct net_buf *const buf) { @@ -547,9 +549,9 @@ static int uac2_control_to_host(struct usbd_class_node *const node, } if (setup->bmRequestType == GET_CLASS_REQUEST_TYPE) { - entity_type = id_type(node, CONTROL_ENTITY_ID(setup)); + entity_type = id_type(c_data, CONTROL_ENTITY_ID(setup)); if (entity_type == ENTITY_TYPE_CLOCK_SOURCE) { - return get_clock_source_request(node, setup, buf); + return get_clock_source_request(c_data, setup, buf); } } @@ -557,13 +559,13 @@ static int uac2_control_to_host(struct usbd_class_node *const node, return 0; } -static int uac2_request(struct usbd_class_node *const node, struct net_buf *buf, +static int uac2_request(struct usbd_class_data *const c_data, struct net_buf *buf, int err) { - struct device *dev = node->data->priv; + const struct device *dev = usbd_class_get_private(c_data); const struct uac2_cfg *cfg = dev->config; struct uac2_ctx *ctx = dev->data; - struct usbd_contex *uds_ctx = node->data->uds_ctx; + struct usbd_contex *uds_ctx = usbd_class_get_ctx(c_data); struct udc_buf_info *bi; uint8_t ep, terminal; uint16_t mps; @@ -607,18 +609,18 @@ static int uac2_request(struct usbd_class_node *const node, struct net_buf *buf, /* Reschedule the read or explicit feedback write */ if (USB_EP_DIR_IS_OUT(ep)) { - schedule_iso_out_read(node, ep, mps, terminal); + schedule_iso_out_read(c_data, ep, mps, terminal); } return 0; } -static void uac2_sof(struct usbd_class_node *const node) +static void uac2_sof(struct usbd_class_data *const c_data) { - struct device *dev = node->data->priv; + const struct device *dev = usbd_class_get_private(c_data); const struct usb_ep_descriptor *data_ep; + const struct usb_ep_descriptor *feedback_ep; const struct uac2_cfg *cfg = dev->config; - const uint8_t *desc = node->data->desc; struct uac2_ctx *ctx = dev->data; int as_idx; @@ -629,15 +631,16 @@ static void uac2_sof(struct usbd_class_node *const node) * won't be pending only if there was buffer underrun, i.e. the * application failed to supply receive buffer. */ - data_ep = get_as_data_ep(node, as_idx); + data_ep = get_as_data_ep(c_data, as_idx); if (data_ep && USB_EP_DIR_IS_OUT(data_ep->bEndpointAddress)) { - schedule_iso_out_read(node, data_ep->bEndpointAddress, + schedule_iso_out_read(c_data, data_ep->bEndpointAddress, sys_le16_to_cpu(data_ep->wMaxPacketSize), cfg->as_terminals[as_idx]); } /* Skip interfaces without explicit feedback endpoint */ - if (cfg->fb_offsets[as_idx] == 0) { + feedback_ep = get_as_feedback_ep(c_data, as_idx); + if (feedback_ep == NULL) { continue; } @@ -658,14 +661,27 @@ static void uac2_sof(struct usbd_class_node *const node) * previous SOF is "gone" even if USB host did not attempt to * read it). */ - write_explicit_feedback(node, desc[cfg->fb_offsets[as_idx]], + write_explicit_feedback(c_data, feedback_ep->bEndpointAddress, cfg->as_terminals[as_idx]); } } -static int uac2_init(struct usbd_class_node *const node) +static void *uac2_get_desc(struct usbd_class_data *const c_data, + const enum usbd_speed speed) { - struct device *dev = node->data->priv; + struct device *dev = usbd_class_get_private(c_data); + const struct uac2_cfg *cfg = dev->config; + + if (speed == USBD_SPEED_FS) { + return cfg->descriptors; + } + + return NULL; +} + +static int uac2_init(struct usbd_class_data *const c_data) +{ + const struct device *dev = usbd_class_get_private(c_data); struct uac2_ctx *ctx = dev->data; if (ctx->ops == NULL) { @@ -681,6 +697,7 @@ struct usbd_class_api uac2_api = { .control_to_host = uac2_control_to_host, .request = uac2_request, .sof = uac2_sof, + .get_desc = uac2_get_desc, .init = uac2_init, }; @@ -698,15 +715,15 @@ struct usbd_class_api uac2_api = { ENTITY_TYPE_INVALID \ )) \ , /* Comma here causes unknown types to fail at compile time */ -#define DEFINE_AS_EP_OFFSETS(node) \ +#define DEFINE_AS_EP_INDEXES(node) \ IF_ENABLED(DT_NODE_HAS_COMPAT(node, zephyr_uac2_audio_streaming), ( \ COND_CODE_1(AS_HAS_ISOCHRONOUS_DATA_ENDPOINT(node), \ - (UAC2_DESCRIPTOR_AS_DATA_EP_OFFSET(node),), (0,)) \ + (UAC2_DESCRIPTOR_AS_DATA_EP_INDEX(node),), (0,)) \ )) -#define DEFINE_AS_FB_OFFSETS(node) \ +#define DEFINE_AS_FB_INDEXES(node) \ IF_ENABLED(DT_NODE_HAS_COMPAT(node, zephyr_uac2_audio_streaming), ( \ COND_CODE_1(AS_HAS_EXPLICIT_FEEDBACK_ENDPOINT(node), \ - (UAC2_DESCRIPTOR_AS_FEEDBACK_EP_OFFSET(node),), (0,)) \ + (UAC2_DESCRIPTOR_AS_FEEDBACK_EP_INDEX(node),), (0,)) \ )) #define DEFINE_AS_TERMINALS(node) \ IF_ENABLED(DT_NODE_HAS_COMPAT(node, zephyr_uac2_audio_streaming), ( \ @@ -725,11 +742,11 @@ struct usbd_class_api uac2_api = { static const entity_type_t entity_types_##i[] = { \ DT_INST_FOREACH_CHILD_STATUS_OKAY(i, DEFINE_ENTITY_TYPES) \ }; \ - static const uint16_t ep_offsets_##i[] = { \ - DT_INST_FOREACH_CHILD_STATUS_OKAY(i, DEFINE_AS_EP_OFFSETS) \ + static const uint16_t ep_indexes_##i[] = { \ + DT_INST_FOREACH_CHILD_STATUS_OKAY(i, DEFINE_AS_EP_INDEXES) \ }; \ - static const uint16_t fb_offsets_##i[] = { \ - DT_INST_FOREACH_CHILD_STATUS_OKAY(i, DEFINE_AS_FB_OFFSETS) \ + static const uint16_t fb_indexes_##i[] = { \ + DT_INST_FOREACH_CHILD_STATUS_OKAY(i, DEFINE_AS_FB_INDEXES) \ }; \ static const uint8_t as_terminals_##i[] = { \ DT_INST_FOREACH_CHILD_STATUS_OKAY(i, DEFINE_AS_TERMINALS) \ @@ -739,26 +756,24 @@ struct usbd_class_api uac2_api = { #define DEFINE_UAC2_CLASS_DATA(inst) \ DT_INST_FOREACH_CHILD(inst, VALIDATE_NODE) \ static struct uac2_ctx uac2_ctx_##inst; \ - static uint8_t uac2_descriptor_##inst[] = { \ - UAC2_DESCRIPTORS(DT_DRV_INST(inst)) \ - 0x00, 0x00 /* terminator required by USBD stack */ \ - }; \ - static struct usbd_class_data uac2_class_##inst = { \ - .desc = (struct usb_desc_header *)uac2_descriptor_##inst, \ - .priv = (void *)DEVICE_DT_GET(DT_DRV_INST(inst)), \ + UAC2_DESCRIPTOR_ARRAYS(DT_DRV_INST(inst)) \ + static const struct usb_desc_header *uac2_descriptors_##inst[] = { \ + UAC2_DESCRIPTOR_PTRS(DT_DRV_INST(inst)) \ }; \ - USBD_DEFINE_CLASS(uac2_##inst, &uac2_api, &uac2_class_##inst); \ + USBD_DEFINE_CLASS(uac2_##inst, &uac2_api, \ + (void *)DEVICE_DT_GET(DT_DRV_INST(inst)), NULL); \ DEFINE_LOOKUP_TABLES(inst) \ static const struct uac2_cfg uac2_cfg_##inst = { \ - .node = &uac2_##inst, \ + .c_data = &uac2_##inst, \ + .descriptors = uac2_descriptors_##inst, \ .entity_types = entity_types_##inst, \ - .ep_offsets = ep_offsets_##inst, \ - .fb_offsets = fb_offsets_##inst, \ + .ep_indexes = ep_indexes_##inst, \ + .fb_indexes = fb_indexes_##inst, \ .as_terminals = as_terminals_##inst, \ - .num_ifaces = ARRAY_SIZE(ep_offsets_##inst), \ + .num_ifaces = ARRAY_SIZE(ep_indexes_##inst), \ .num_entities = ARRAY_SIZE(entity_types_##inst), \ }; \ - BUILD_ASSERT(ARRAY_SIZE(ep_offsets_##inst) <= 32, \ + BUILD_ASSERT(ARRAY_SIZE(ep_indexes_##inst) <= 32, \ "UAC2 implementation supports up to 32 AS interfaces"); \ BUILD_ASSERT(ARRAY_SIZE(entity_types_##inst) <= 255, \ "UAC2 supports up to 255 entities"); \ @@ -768,10 +783,10 @@ struct usbd_class_api uac2_api = { NULL); DT_INST_FOREACH_STATUS_OKAY(DEFINE_UAC2_CLASS_DATA) -static size_t clock_frequencies(struct usbd_class_node *const node, +static size_t clock_frequencies(struct usbd_class_data *const c_data, const uint8_t id, const uint32_t **frequencies) { - const struct device *dev = node->data->priv; + const struct device *dev = usbd_class_get_private(c_data); size_t count; #define GET_FREQUENCY_TABLE(node, i) \ diff --git a/subsys/usb/device_next/class/usbd_uac2_macros.h b/subsys/usb/device_next/class/usbd_uac2_macros.h index 743ecaf2900..58716214b56 100644 --- a/subsys/usb/device_next/class/usbd_uac2_macros.h +++ b/subsys/usb/device_next/class/usbd_uac2_macros.h @@ -111,6 +111,9 @@ /* Automatically assign Entity IDs based on entities order in devicetree */ #define ENTITY_ID(e) UTIL_INC(DT_NODE_CHILD_IDX(e)) +/* Name of uint8_t array holding descriptor data */ +#define DESCRIPTOR_NAME(prefix, node) uac2_## prefix ## _ ## node + /* Connected Entity ID or 0 if property is not defined. Rely on devicetree * "required: true" to fail compilation if mandatory handle (e.g. clock source) * is absent. @@ -285,7 +288,21 @@ OUTPUT_TERMINAL_DESCRIPTOR(entity) \ )) +#define ENTITY_HEADER_ARRAYS(entity) \ + IF_ENABLED(UTIL_NOT(IS_EMPTY(ENTITY_HEADER(entity))), ( \ + static uint8_t DESCRIPTOR_NAME(ac_entity, entity)[] = { \ + ENTITY_HEADER(entity) \ + }; \ + )) + +#define ENTITY_HEADER_PTRS(entity) \ + IF_ENABLED(UTIL_NOT(IS_EMPTY(ENTITY_HEADER(entity))), ( \ + (struct usb_desc_header *) &DESCRIPTOR_NAME(ac_entity, entity), \ + )) + #define ENTITY_HEADERS(node) DT_FOREACH_CHILD(node, ENTITY_HEADER) +#define ENTITY_HEADERS_ARRAYS(node) DT_FOREACH_CHILD(node, ENTITY_HEADER_ARRAYS) +#define ENTITY_HEADERS_PTRS(node) DT_FOREACH_CHILD(node, ENTITY_HEADER_PTRS) #define ENTITY_HEADERS_LENGTH(node) sizeof((uint8_t []){ENTITY_HEADERS(node)}) #define AUDIO_STREAMING_CONTROLS(node) \ @@ -365,6 +382,18 @@ AUDIO_STREAMING_GENERAL_DESCRIPTOR(node) \ AUDIO_STREAMING_FORMAT_TYPE_DESCRIPTOR(node) +#define AUDIO_STREAMING_INTERFACE_DESCRIPTORS_ARRAYS(node) \ + static uint8_t DESCRIPTOR_NAME(as_general_desc, node)[] = { \ + AUDIO_STREAMING_GENERAL_DESCRIPTOR(node) \ + }; \ + static uint8_t DESCRIPTOR_NAME(as_format_desc, node)[] = { \ + AUDIO_STREAMING_FORMAT_TYPE_DESCRIPTOR(node) \ + }; + +#define AUDIO_STREAMING_INTERFACE_DESCRIPTORS_PTRS(node) \ + (struct usb_desc_header *) &DESCRIPTOR_NAME(as_general_desc, node), \ + (struct usb_desc_header *) &DESCRIPTOR_NAME(as_format_desc, node), + /* 4.7.2 Class-Specific AC Interface Descriptor */ #define AC_INTERFACE_HEADER_DESCRIPTOR(node) \ 0x09, /* bLength */ \ @@ -375,6 +404,14 @@ U16_LE(9 + ENTITY_HEADERS_LENGTH(node)), /* wTotalLength */ \ 0x00, /* bmControls */ \ +#define AC_INTERFACE_HEADER_DESCRIPTOR_ARRAY(node) \ + static uint8_t DESCRIPTOR_NAME(ac_header, node)[] = { \ + AC_INTERFACE_HEADER_DESCRIPTOR(node) \ + }; + +#define AC_INTERFACE_HEADER_DESCRIPTOR_PTR(node) \ + (struct usb_desc_header *) &DESCRIPTOR_NAME(ac_header, node), + #define IS_AUDIOSTREAMING_INTERFACE(node) \ DT_NODE_HAS_COMPAT(node, zephyr_uac2_audio_streaming) @@ -393,6 +430,14 @@ AF_VERSION_02_00, /* bFunctionProtocol */ \ 0x00, /* iFunction */ +#define UAC2_INTERFACE_ASSOCIATION_DESCRIPTOR_ARRAY(node) \ + static uint8_t DESCRIPTOR_NAME(iad, node)[] = { \ + UAC2_INTERFACE_ASSOCIATION_DESCRIPTOR(node) \ + }; + +#define UAC2_INTERFACE_ASSOCIATION_DESCRIPTOR_PTR(node) \ + (struct usb_desc_header *) &DESCRIPTOR_NAME(iad, node), + /* 4.7.1 Standard AC Interface Descriptor */ #define AC_INTERFACE_DESCRIPTOR(node) \ 0x09, /* bLength */ \ @@ -405,6 +450,14 @@ IP_VERSION_02_00, /* bInterfaceProtocol */\ 0x00, /* iInterface */ +#define AC_INTERFACE_DESCRIPTOR_ARRAY(node) \ + static uint8_t DESCRIPTOR_NAME(ac_interface, node)[] = { \ + AC_INTERFACE_DESCRIPTOR(node) \ + }; + +#define AC_INTERFACE_DESCRIPTOR_PTR(node) \ + (struct usb_desc_header *) &DESCRIPTOR_NAME(ac_interface, node), + /* 4.8.2.1 Standard AC Interrupt Endpoint Descriptor */ #define AC_ENDPOINT_DESCRIPTOR(node) \ 0x07, /* bLength */ \ @@ -414,6 +467,14 @@ 0x06, /* wMaxPacketSize */ \ 0x01, /* bInterval */ \ +#define AC_ENDPOINT_DESCRIPTOR_ARRAY(node) \ + static uint8_t DESCRIPTOR_NAME(ac_endpoint, node)[] = { \ + AC_ENDPOINT_DESCRIPTOR(node) \ + }; + +#define AC_ENDPOINT_DESCRIPTOR_PTR(node) \ + (struct usb_desc_header *) &DESCRIPTOR_NAME(ac_endpoint, node), + #define FIND_AUDIOSTREAMING(node, fn, ...) \ IF_ENABLED(DT_NODE_HAS_COMPAT(node, zephyr_uac2_audio_streaming), ( \ fn(node, __VA_ARGS__))) @@ -487,6 +548,14 @@ IP_VERSION_02_00, /* bInterfaceProtocol */\ 0x00, /* iInterface */ +#define AS_INTERFACE_DESCRIPTOR_ARRAY(node, alternate, numendpoints) \ + static uint8_t DESCRIPTOR_NAME(as_if_alt##alternate, node)[] = { \ + AS_INTERFACE_DESCRIPTOR(node, alternate, numendpoints) \ + }; + +#define AS_INTERFACE_DESCRIPTOR_PTR(node, alternate) \ + (struct usb_desc_header *) &DESCRIPTOR_NAME(as_if_alt##alternate, node), + #define COUNT_AS_OUT_ENDPOINTS_BEFORE_IDX(node, idx) \ + AS_IS_USB_ISO_OUT(node) * (DT_NODE_CHILD_IDX(node) < idx) @@ -569,6 +638,18 @@ STANDARD_AS_ISOCHRONOUS_DATA_ENDPOINT_DESCRIPTOR(node) \ CLASS_SPECIFIC_AS_ISOCHRONOUS_DATA_ENDPOINT_DESCRIPTOR(node) +#define AS_ISOCHRONOUS_DATA_ENDPOINT_DESCRIPTORS_ARRAYS(node) \ + static uint8_t DESCRIPTOR_NAME(std_data_ep, node)[] = { \ + STANDARD_AS_ISOCHRONOUS_DATA_ENDPOINT_DESCRIPTOR(node) \ + }; \ + static uint8_t DESCRIPTOR_NAME(cs_data_ep, node)[] = { \ + CLASS_SPECIFIC_AS_ISOCHRONOUS_DATA_ENDPOINT_DESCRIPTOR(node) \ + }; + +#define AS_ISOCHRONOUS_DATA_ENDPOINT_DESCRIPTORS_PTRS(node) \ + (struct usb_desc_header *) &DESCRIPTOR_NAME(std_data_ep, node), \ + (struct usb_desc_header *) &DESCRIPTOR_NAME(cs_data_ep, node), + #define AS_EXPLICIT_FEEDBACK_ENDPOINT_DESCRIPTOR(node) \ 0x07, /* bLength */ \ USB_DESC_ENDPOINT, /* bDescriptorType */ \ @@ -577,6 +658,14 @@ U16_LE(0x03), /* FIXME: 4 on High-Speed*/ /* wMaxPacketSize */ \ 0x01, /* TODO: adjust to P 5.12.4.2 Feedback */ /* bInterval */ +#define AS_EXPLICIT_FEEDBACK_ENDPOINT_DESCRIPTOR_ARRAY(node) \ + static uint8_t DESCRIPTOR_NAME(feedback_ep, node)[] = { \ + AS_EXPLICIT_FEEDBACK_ENDPOINT_DESCRIPTOR(node) \ + }; + +#define AS_EXPLICIT_FEEDBACK_ENDPOINT_DESCRIPTOR_PTR(node) \ + (struct usb_desc_header *) &DESCRIPTOR_NAME(feedback_ep, node), + #define AS_DESCRIPTORS(node) \ AS_INTERFACE_DESCRIPTOR(node, 0, 0) \ IF_ENABLED(AS_HAS_ISOCHRONOUS_DATA_ENDPOINT(node), ( \ @@ -589,10 +678,41 @@ AS_EXPLICIT_FEEDBACK_ENDPOINT_DESCRIPTOR(node))) \ )) +#define AS_DESCRIPTORS_ARRAYS(node) \ + AS_INTERFACE_DESCRIPTOR_ARRAY(node, 0, 0) \ + IF_ENABLED(AS_HAS_ISOCHRONOUS_DATA_ENDPOINT(node), ( \ + AS_INTERFACE_DESCRIPTOR_ARRAY(node, 1, \ + AS_INTERFACE_NUM_ENDPOINTS(node)))) \ + AUDIO_STREAMING_INTERFACE_DESCRIPTORS_ARRAYS(node) \ + IF_ENABLED(AS_HAS_ISOCHRONOUS_DATA_ENDPOINT(node), ( \ + AS_ISOCHRONOUS_DATA_ENDPOINT_DESCRIPTORS_ARRAYS(node) \ + IF_ENABLED(AS_HAS_EXPLICIT_FEEDBACK_ENDPOINT(node), ( \ + AS_EXPLICIT_FEEDBACK_ENDPOINT_DESCRIPTOR_ARRAY(node))) \ + )) + +#define AS_DESCRIPTORS_PTRS(node) \ + AS_INTERFACE_DESCRIPTOR_PTR(node, 0) \ + IF_ENABLED(AS_HAS_ISOCHRONOUS_DATA_ENDPOINT(node), ( \ + AS_INTERFACE_DESCRIPTOR_PTR(node, 1))) \ + AUDIO_STREAMING_INTERFACE_DESCRIPTORS_PTRS(node) \ + IF_ENABLED(AS_HAS_ISOCHRONOUS_DATA_ENDPOINT(node), ( \ + AS_ISOCHRONOUS_DATA_ENDPOINT_DESCRIPTORS_PTRS(node) \ + IF_ENABLED(AS_HAS_EXPLICIT_FEEDBACK_ENDPOINT(node), ( \ + AS_EXPLICIT_FEEDBACK_ENDPOINT_DESCRIPTOR_PTR(node))) \ + )) + #define AS_DESCRIPTORS_IF_AUDIOSTREAMING(node) \ IF_ENABLED(DT_NODE_HAS_COMPAT(node, zephyr_uac2_audio_streaming), ( \ AS_DESCRIPTORS(node))) +#define AS_DESCRIPTORS_ARRAYS_IF_AUDIOSTREAMING(node) \ + IF_ENABLED(DT_NODE_HAS_COMPAT(node, zephyr_uac2_audio_streaming), ( \ + AS_DESCRIPTORS_ARRAYS(node))) + +#define AS_DESCRIPTORS_PTRS_IF_AUDIOSTREAMING(node) \ + IF_ENABLED(DT_NODE_HAS_COMPAT(node, zephyr_uac2_audio_streaming), ( \ + AS_DESCRIPTORS_PTRS(node))) + #define UAC2_AUDIO_CONTROL_DESCRIPTORS(node) \ AC_INTERFACE_DESCRIPTOR(node) \ AC_INTERFACE_HEADER_DESCRIPTOR(node) \ @@ -600,6 +720,31 @@ IF_ENABLED(DT_PROP(node, interrupt_endpoint), ( \ AC_ENDPOINT_DESCRIPTOR(node))) +#define UAC2_AUDIO_CONTROL_DESCRIPTOR_ARRAYS(node) \ + AC_INTERFACE_DESCRIPTOR_ARRAY(node) \ + AC_INTERFACE_HEADER_DESCRIPTOR_ARRAY(node) \ + ENTITY_HEADERS_ARRAYS(node) \ + IF_ENABLED(DT_PROP(node, interrupt_endpoint), ( \ + AC_ENDPOINT_DESCRIPTOR_ARRAY(node))) + +#define UAC2_AUDIO_CONTROL_DESCRIPTOR_PTRS(node) \ + AC_INTERFACE_DESCRIPTOR_PTR(node) \ + AC_INTERFACE_HEADER_DESCRIPTOR_PTR(node) \ + ENTITY_HEADERS_PTRS(node) \ + IF_ENABLED(DT_PROP(node, interrupt_endpoint), ( \ + AC_ENDPOINT_DESCRIPTOR_PTR(node))) + +#define UAC2_DESCRIPTOR_ARRAYS(node) \ + UAC2_INTERFACE_ASSOCIATION_DESCRIPTOR_ARRAY(node) \ + UAC2_AUDIO_CONTROL_DESCRIPTOR_ARRAYS(node) \ + DT_FOREACH_CHILD(node, AS_DESCRIPTORS_ARRAYS_IF_AUDIOSTREAMING) + +#define UAC2_DESCRIPTOR_PTRS(node) \ + UAC2_INTERFACE_ASSOCIATION_DESCRIPTOR_PTR(node) \ + UAC2_AUDIO_CONTROL_DESCRIPTOR_PTRS(node) \ + DT_FOREACH_CHILD(node, AS_DESCRIPTORS_PTRS_IF_AUDIOSTREAMING) \ + NULL + #define UAC2_DESCRIPTORS(node) \ UAC2_INTERFACE_ASSOCIATION_DESCRIPTOR(node) \ UAC2_AUDIO_CONTROL_DESCRIPTORS(node) \ @@ -651,6 +796,52 @@ - AS_EXPLICIT_FEEDBACK_ENDPOINT_DESCRIPTOR_SIZE(node) \ + offsetof(struct usb_ep_descriptor, bEndpointAddress) +/* Helper macros to determine endpoint descriptor offset within descriptor set */ +#define COUNT_PTRS(...) sizeof((struct usb_desc_header *[]){__VA_ARGS__}) \ + / sizeof(struct usb_desc_header *) + +#define COUNT_AS_DESCRIPTORS_UP_TO_IDX(node, idx) \ + (COUNT_PTRS(AS_DESCRIPTORS_PTRS_IF_AUDIOSTREAMING(node))) * \ + (DT_NODE_CHILD_IDX(node) <= idx) + +#define UAC2_DESCRIPTOR_AS_DESC_END_COUNT(node) \ + (COUNT_PTRS( \ + UAC2_INTERFACE_ASSOCIATION_DESCRIPTOR_PTR(DT_PARENT(node)) \ + UAC2_AUDIO_CONTROL_DESCRIPTOR_PTRS(DT_PARENT(node)) \ + )) + DT_FOREACH_CHILD_SEP_VARGS(DT_PARENT(node), \ + COUNT_AS_DESCRIPTORS_UP_TO_IDX, (+), \ + DT_NODE_CHILD_IDX(node)) + +#define AS_ISOCHRONOUS_DATA_ENDPOINT_DESCRIPTORS_COUNT(node) \ + COUNT_PTRS(AS_ISOCHRONOUS_DATA_ENDPOINT_DESCRIPTORS_PTRS(node)) + +#define AS_EXPLICIT_FEEDBACK_ENDPOINT_DESCRIPTOR_COUNT(node) \ + COND_CODE_1(AS_HAS_EXPLICIT_FEEDBACK_ENDPOINT(node), \ + (COUNT_PTRS( \ + AS_EXPLICIT_FEEDBACK_ENDPOINT_DESCRIPTOR_PTR(node) \ + )), (0)) + +/* Return index inside UAC2_DESCRIPTOR_PTRS(DT_PARENT(node)) poiting to data + * endpoint descriptor belonging to given AudioStreaming interface node. + * + * It is programmer error to call this macro with node other than AudioStreaming + * or when AS_HAS_ISOCHRONOUS_DATA_ENDPOINT(node) is 0. + */ +#define UAC2_DESCRIPTOR_AS_DATA_EP_INDEX(node) \ + UAC2_DESCRIPTOR_AS_DESC_END_COUNT(node) \ + - AS_EXPLICIT_FEEDBACK_ENDPOINT_DESCRIPTOR_COUNT(node) \ + - AS_ISOCHRONOUS_DATA_ENDPOINT_DESCRIPTORS_COUNT(node) + +/* Return index inside UAC2_DESCRIPTOR_PTRS(DT_PARENT(node)) poiting to feedback + * endpoint descriptor belonging to given AudioStreaming interface node. + * + * It is programmer error to call this macro with node other than AudioStreaming + * or when AS_HAS_EXPLICIT_FEEDBACK_ENDPOINT(node) is 0. + */ +#define UAC2_DESCRIPTOR_AS_FEEDBACK_EP_INDEX(node) \ + UAC2_DESCRIPTOR_AS_DESC_END_COUNT(node) \ + - AS_EXPLICIT_FEEDBACK_ENDPOINT_DESCRIPTOR_COUNT(node) + /* Helper macros to validate USB Audio Class 2 devicetree entries. * Macros above do rely on the assumptions checked below. */ diff --git a/subsys/usb/device_next/usbd_ch9.c b/subsys/usb/device_next/usbd_ch9.c index d7b1fccfc2e..2b6897e5567 100644 --- a/subsys/usb/device_next/usbd_ch9.c +++ b/subsys/usb/device_next/usbd_ch9.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "usbd_device.h" #include "usbd_desc.h" @@ -28,6 +29,9 @@ LOG_MODULE_REGISTER(usbd_ch9, CONFIG_USBD_LOG_LEVEL); #define SF_TEST_MODE_SELECTOR(wIndex) ((uint8_t)((wIndex) >> 8)) #define SF_TEST_LOWER_BYTE(wIndex) ((uint8_t)(wIndex)) +static int nonstd_request(struct usbd_contex *const uds_ctx, + struct net_buf *const dbuf); + static bool reqtype_is_to_host(const struct usb_setup_packet *const setup) { return setup->wLength && USB_REQTYPE_GET_DIR(setup->bmRequestType); @@ -122,6 +126,7 @@ static int sreq_set_address(struct usbd_contex *const uds_ctx) static int sreq_set_configuration(struct usbd_contex *const uds_ctx) { struct usb_setup_packet *setup = usbd_get_setup_pkt(uds_ctx); + const enum usbd_speed speed = usbd_bus_speed(uds_ctx); int ret; LOG_INF("Set Configuration Request value %u", setup->wValue); @@ -142,7 +147,7 @@ static int sreq_set_configuration(struct usbd_contex *const uds_ctx) return 0; } - if (setup->wValue && !usbd_config_exist(uds_ctx, setup->wValue)) { + if (setup->wValue && !usbd_config_exist(uds_ctx, speed, setup->wValue)) { errno = -EPERM; return 0; } @@ -211,7 +216,7 @@ static void sreq_feature_halt_notify(struct usbd_contex *const uds_ctx, struct usbd_class_node *c_nd = usbd_class_get_by_ep(uds_ctx, ep); if (c_nd != NULL) { - usbd_class_feature_halt(c_nd, ep, halted); + usbd_class_feature_halt(c_nd->c_data, ep, halted); } } @@ -440,33 +445,78 @@ static int sreq_get_status(struct usbd_contex *const uds_ctx, return 0; } +/* + * This function handles configuration and USB2.0 other-speed-configuration + * descriptor type requests. + */ static int sreq_get_desc_cfg(struct usbd_contex *const uds_ctx, struct net_buf *const buf, - const uint8_t idx) + const uint8_t idx, + const bool other_cfg) { struct usb_setup_packet *setup = usbd_get_setup_pkt(uds_ctx); + enum usbd_speed speed = usbd_bus_speed(uds_ctx); + struct usb_cfg_descriptor other_desc; struct usb_cfg_descriptor *cfg_desc; struct usbd_config_node *cfg_nd; + enum usbd_speed get_desc_speed; struct usbd_class_node *c_nd; uint16_t len; - cfg_nd = usbd_config_get(uds_ctx, idx + 1); + /* + * If the other-speed-configuration-descriptor is requested and the + * controller does not support high speed, respond with an error. + */ + if (other_cfg && usbd_caps_speed(uds_ctx) != USBD_SPEED_HS) { + errno = -ENOTSUP; + return 0; + } + + if (other_cfg) { + if (speed == USBD_SPEED_FS) { + get_desc_speed = USBD_SPEED_HS; + } else { + get_desc_speed = USBD_SPEED_FS; + } + } else { + get_desc_speed = speed; + } + + cfg_nd = usbd_config_get(uds_ctx, get_desc_speed, idx + 1); if (cfg_nd == NULL) { LOG_ERR("Configuration descriptor %u not found", idx + 1); errno = -ENOTSUP; return 0; } - cfg_desc = cfg_nd->desc; - len = MIN(setup->wLength, net_buf_tailroom(buf)); - net_buf_add_mem(buf, cfg_desc, MIN(len, cfg_desc->bLength)); + if (other_cfg) { + /* Copy the configuration descriptor and update the type */ + memcpy(&other_desc, cfg_nd->desc, sizeof(other_desc)); + other_desc.bDescriptorType = USB_DESC_OTHER_SPEED; + cfg_desc = &other_desc; + } else { + cfg_desc = cfg_nd->desc; + } + + net_buf_add_mem(buf, cfg_desc, MIN(net_buf_tailroom(buf), cfg_desc->bLength)); SYS_SLIST_FOR_EACH_CONTAINER(&cfg_nd->class_list, c_nd, node) { - struct usb_desc_header *head = c_nd->data->desc; - size_t desc_len = usbd_class_desc_len(c_nd); + struct usb_desc_header **dhp; - len = MIN(setup->wLength, net_buf_tailroom(buf)); - net_buf_add_mem(buf, head, MIN(len, desc_len)); + dhp = usbd_class_get_desc(c_nd->c_data, get_desc_speed); + if (dhp == NULL) { + continue; + } + + while (*dhp != NULL && (*dhp)->bLength != 0) { + len = MIN(net_buf_tailroom(buf), (*dhp)->bLength); + net_buf_add_mem(buf, *dhp, len); + dhp++; + } + } + + if (buf->len > setup->wLength) { + net_buf_remove_mem(buf, buf->len - setup->wLength); } LOG_DBG("Get Configuration descriptor %u, len %u", idx, buf->len); @@ -474,27 +524,246 @@ static int sreq_get_desc_cfg(struct usbd_contex *const uds_ctx, return 0; } -static int sreq_get_desc(struct usbd_contex *const uds_ctx, - struct net_buf *const buf, - const uint8_t type, const uint8_t idx) +#define USBD_HWID_SN_MAX 32U + +/* Generate valid USB device serial number from hwid */ +static ssize_t get_sn_from_hwid(uint8_t sn[static USBD_HWID_SN_MAX]) +{ + static const char hex[] = "0123456789ABCDEF"; + uint8_t hwid[USBD_HWID_SN_MAX / 2U]; + ssize_t hwid_len = -ENOSYS; + + if (IS_ENABLED(CONFIG_HWINFO)) { + hwid_len = hwinfo_get_device_id(hwid, sizeof(hwid)); + } + + if (hwid_len < 0) { + if (hwid_len == -ENOSYS) { + LOG_ERR("HWINFO not implemented or enabled"); + } + + return hwid_len; + } + + for (ssize_t i = 0; i < hwid_len; i++) { + sn[i * 2] = hex[hwid[i] >> 4]; + sn[i * 2 + 1] = hex[hwid[i] & 0xF]; + } + + return hwid_len * 2; +} + +/* Copy and convert ASCII-7 string descriptor to UTF16-LE */ +static void string_ascii7_to_utf16le(struct usbd_desc_node *const dn, + struct net_buf *const buf, const uint16_t wLength) +{ + uint8_t hwid_sn[USBD_HWID_SN_MAX]; + struct usb_desc_header head = { + .bDescriptorType = dn->bDescriptorType, + }; + uint8_t *ascii7_str; + size_t len; + size_t i; + + if (dn->str.utype == USBD_DUT_STRING_SERIAL_NUMBER && dn->str.use_hwinfo) { + ssize_t hwid_len = get_sn_from_hwid(hwid_sn); + + if (hwid_len < 0) { + errno = -ENOTSUP; + return; + } + + head.bLength = sizeof(head) + hwid_len * 2; + ascii7_str = hwid_sn; + } else { + head.bLength = dn->bLength, + ascii7_str = (uint8_t *)dn->ptr; + } + + LOG_DBG("wLength %u, bLength %u, tailroom %u", + wLength, head.bLength, net_buf_tailroom(buf)); + + len = MIN(net_buf_tailroom(buf), MIN(head.bLength, wLength)); + + /* Add bLength and bDescriptorType */ + net_buf_add_mem(buf, &head, MIN(len, sizeof(head))); + len -= MIN(len, sizeof(head)); + + for (i = 0; i < len / 2; i++) { + __ASSERT(ascii7_str[i] > 0x1F && ascii7_str[i] < 0x7F, + "Only printable ascii-7 characters are allowed in USB " + "string descriptors"); + net_buf_add_le16(buf, ascii7_str[i]); + } + + if (len & 1) { + net_buf_add_u8(buf, ascii7_str[i]); + } +} + +static int sreq_get_desc_dev(struct usbd_contex *const uds_ctx, + struct net_buf *const buf) { struct usb_setup_packet *setup = usbd_get_setup_pkt(uds_ctx); struct usb_desc_header *head; size_t len; - if (type == USB_DESC_DEVICE) { - head = uds_ctx->desc; + len = MIN(setup->wLength, net_buf_tailroom(buf)); + + switch (usbd_bus_speed(uds_ctx)) { + case USBD_SPEED_FS: + head = uds_ctx->fs_desc; + break; + case USBD_SPEED_HS: + head = uds_ctx->hs_desc; + break; + default: + errno = -ENOTSUP; + return 0; + } + + net_buf_add_mem(buf, head, MIN(len, head->bLength)); + + return 0; +} + +static int sreq_get_desc_str(struct usbd_contex *const uds_ctx, + struct net_buf *const buf, const uint8_t idx) +{ + struct usb_setup_packet *setup = usbd_get_setup_pkt(uds_ctx); + struct usbd_desc_node *d_nd; + size_t len; + + /* Get string descriptor */ + d_nd = usbd_get_descriptor(uds_ctx, USB_DESC_STRING, idx); + if (d_nd == NULL) { + errno = -ENOTSUP; + return 0; + } + + if (usbd_str_desc_get_idx(d_nd) == 0U) { + /* Language ID string descriptor */ + struct usb_string_descriptor langid = { + .bLength = d_nd->bLength, + .bDescriptorType = d_nd->bDescriptorType, + .bString = *(uint16_t *)d_nd->ptr, + }; + + len = MIN(setup->wLength, net_buf_tailroom(buf)); + net_buf_add_mem(buf, &langid, MIN(len, langid.bLength)); } else { - head = usbd_get_descriptor(uds_ctx, type, idx); + /* String descriptors in ASCII7 format */ + string_ascii7_to_utf16le(d_nd, buf, setup->wLength); } - if (head == NULL) { + return 0; +} + +static int sreq_get_dev_qualifier(struct usbd_contex *const uds_ctx, + struct net_buf *const buf) +{ + struct usb_setup_packet *setup = usbd_get_setup_pkt(uds_ctx); + /* At Full-Speed we want High-Speed descriptor and vice versa */ + struct usb_device_descriptor *d_desc = + usbd_bus_speed(uds_ctx) == USBD_SPEED_FS ? + uds_ctx->hs_desc : uds_ctx->fs_desc; + struct usb_device_qualifier_descriptor q_desc = { + .bLength = sizeof(struct usb_device_qualifier_descriptor), + .bDescriptorType = USB_DESC_DEVICE_QUALIFIER, + .bcdUSB = d_desc->bcdUSB, + .bDeviceClass = d_desc->bDeviceClass, + .bDeviceSubClass = d_desc->bDeviceSubClass, + .bDeviceProtocol = d_desc->bDeviceProtocol, + .bMaxPacketSize0 = d_desc->bMaxPacketSize0, + .bNumConfigurations = d_desc->bNumConfigurations, + .bReserved = 0U, + }; + size_t len; + + /* + * If the Device Qualifier descriptor is requested and the controller + * does not support high speed, respond with an error. + */ + if (usbd_caps_speed(uds_ctx) != USBD_SPEED_HS) { errno = -ENOTSUP; return 0; } + LOG_DBG("Get Device Qualifier"); len = MIN(setup->wLength, net_buf_tailroom(buf)); - net_buf_add_mem(buf, head, MIN(len, head->bLength)); + net_buf_add_mem(buf, &q_desc, MIN(len, q_desc.bLength)); + + return 0; +} + +static void desc_fill_bos_root(struct usbd_contex *const uds_ctx, + struct usb_bos_descriptor *const root) +{ + struct usbd_desc_node *desc_nd; + + root->bLength = sizeof(struct usb_bos_descriptor); + root->bDescriptorType = USB_DESC_BOS; + root->wTotalLength = root->bLength; + + SYS_DLIST_FOR_EACH_CONTAINER(&uds_ctx->descriptors, desc_nd, node) { + if (desc_nd->bDescriptorType == USB_DESC_BOS) { + root->wTotalLength += desc_nd->bLength; + root->bNumDeviceCaps++; + } + } +} + +static int sreq_get_desc_bos(struct usbd_contex *const uds_ctx, + struct net_buf *const buf) +{ + struct usb_setup_packet *setup = usbd_get_setup_pkt(uds_ctx); + struct usb_device_descriptor *dev_dsc; + struct usb_bos_descriptor bos; + struct usbd_desc_node *desc_nd; + size_t len; + + switch (usbd_bus_speed(uds_ctx)) { + case USBD_SPEED_FS: + dev_dsc = uds_ctx->fs_desc; + break; + case USBD_SPEED_HS: + dev_dsc = uds_ctx->hs_desc; + break; + default: + errno = -ENOTSUP; + return 0; + } + + if (sys_le16_to_cpu(dev_dsc->bcdUSB) < 0x0201U) { + errno = -ENOTSUP; + return 0; + } + + desc_fill_bos_root(uds_ctx, &bos); + len = MIN(net_buf_tailroom(buf), MIN(setup->wLength, bos.wTotalLength)); + + LOG_DBG("wLength %u, bLength %u, wTotalLength %u, tailroom %u", + setup->wLength, bos.bLength, bos.wTotalLength, net_buf_tailroom(buf)); + + net_buf_add_mem(buf, &bos, MIN(len, bos.bLength)); + + len -= MIN(len, sizeof(bos)); + if (len == 0) { + return 0; + } + + SYS_DLIST_FOR_EACH_CONTAINER(&uds_ctx->descriptors, desc_nd, node) { + if (desc_nd->bDescriptorType == USB_DESC_BOS) { + LOG_DBG("bLength %u, len %u, tailroom %u", + desc_nd->bLength, len, net_buf_tailroom(buf)); + net_buf_add_mem(buf, desc_nd->ptr, MIN(len, desc_nd->bLength)); + + len -= MIN(len, desc_nd->bLength); + if (len == 0) { + break; + } + } + } return 0; } @@ -509,16 +778,31 @@ static int sreq_get_descriptor(struct usbd_contex *const uds_ctx, LOG_DBG("Get Descriptor request type %u index %u", desc_type, desc_idx); + if (setup->RequestType.recipient != USB_REQTYPE_RECIPIENT_DEVICE) { + /* + * If the recipient is not the device then it is probably a + * class specific request where wIndex is the interface + * number or endpoint and not the language ID. e.g. HID + * Class Get Descriptor request. + */ + return nonstd_request(uds_ctx, buf); + } + switch (desc_type) { case USB_DESC_DEVICE: - return sreq_get_desc(uds_ctx, buf, USB_DESC_DEVICE, 0); + return sreq_get_desc_dev(uds_ctx, buf); case USB_DESC_CONFIGURATION: - return sreq_get_desc_cfg(uds_ctx, buf, desc_idx); + return sreq_get_desc_cfg(uds_ctx, buf, desc_idx, false); + case USB_DESC_OTHER_SPEED: + return sreq_get_desc_cfg(uds_ctx, buf, desc_idx, true); case USB_DESC_STRING: - return sreq_get_desc(uds_ctx, buf, USB_DESC_STRING, desc_idx); + return sreq_get_desc_str(uds_ctx, buf, desc_idx); + case USB_DESC_DEVICE_QUALIFIER: + return sreq_get_dev_qualifier(uds_ctx, buf); + case USB_DESC_BOS: + return sreq_get_desc_bos(uds_ctx, buf); case USB_DESC_INTERFACE: case USB_DESC_ENDPOINT: - case USB_DESC_OTHER_SPEED: default: break; } @@ -651,9 +935,9 @@ static int nonstd_request(struct usbd_contex *const uds_ctx, if (c_nd != NULL) { if (reqtype_is_to_device(setup)) { - ret = usbd_class_control_to_dev(c_nd, setup, dbuf); + ret = usbd_class_control_to_dev(c_nd->c_data, setup, dbuf); } else { - ret = usbd_class_control_to_host(c_nd, setup, dbuf); + ret = usbd_class_control_to_host(c_nd->c_data, setup, dbuf); } } else { errno = -ENOTSUP; diff --git a/subsys/usb/device_next/usbd_class.c b/subsys/usb/device_next/usbd_class.c index 64610fa3d53..4217019b514 100644 --- a/subsys/usb/device_next/usbd_class.c +++ b/subsys/usb/device_next/usbd_class.c @@ -24,22 +24,20 @@ #endif LOG_MODULE_REGISTER(usbd_class, CONFIG_USBD_LOG_LEVEL); -size_t usbd_class_desc_len(struct usbd_class_node *const c_nd) +size_t usbd_class_desc_len(struct usbd_class_data *const c_data, + const enum usbd_speed speed) { - struct usbd_class_data *data = c_nd->data; - struct usb_desc_header *dh; - uint8_t *ptr; + struct usb_desc_header **dhp; size_t len = 0; - if (data->desc != NULL) { - dh = data->desc; - ptr = (uint8_t *)dh; - - while (dh->bLength != 0) { - len += dh->bLength; - ptr += dh->bLength; - dh = (struct usb_desc_header *)ptr; - } + dhp = usbd_class_get_desc(c_data, speed); + /* + * If the desired descriptor is available, count to the last element, + * which must be a pointer to a nil descriptor. + */ + while (dhp != NULL && (*dhp != NULL) && (*dhp)->bLength != 0U) { + len += (*dhp)->bLength; + dhp++; } return len; @@ -47,19 +45,20 @@ size_t usbd_class_desc_len(struct usbd_class_node *const c_nd) struct usbd_class_node * usbd_class_get_by_config(struct usbd_contex *const uds_ctx, + const enum usbd_speed speed, const uint8_t cnum, const uint8_t inum) { struct usbd_class_node *c_nd; struct usbd_config_node *cfg_nd; - cfg_nd = usbd_config_get(uds_ctx, cnum); + cfg_nd = usbd_config_get(uds_ctx, speed, cnum); if (cfg_nd == NULL) { return NULL; } SYS_SLIST_FOR_EACH_CONTAINER(&cfg_nd->class_list, c_nd, node) { - if (c_nd->data->iface_bm & BIT(inum)) { + if (c_nd->iface_bm & BIT(inum)) { return c_nd; } } @@ -80,7 +79,7 @@ usbd_class_get_by_iface(struct usbd_contex *const uds_ctx, } SYS_SLIST_FOR_EACH_CONTAINER(&cfg_nd->class_list, c_nd, node) { - if (c_nd->data->iface_bm & BIT(inum)) { + if (c_nd->iface_bm & BIT(inum)) { return c_nd; } } @@ -96,9 +95,9 @@ static bool xfer_owner_exist(struct usbd_contex *const uds_ctx, struct usbd_class_node *c_nd; SYS_SLIST_FOR_EACH_CONTAINER(&cfg_nd->class_list, c_nd, node) { - if (bi->owner == c_nd) { - uint32_t ep_active = c_nd->data->ep_active; - uint32_t ep_assigned = c_nd->data->ep_assigned; + if (bi->owner == c_nd->c_data) { + uint32_t ep_active = c_nd->ep_active; + uint32_t ep_assigned = c_nd->ep_assigned; if (!usbd_ep_bm_is_set(&ep_active, bi->ep)) { LOG_DBG("ep 0x%02x is not active", bi->ep); @@ -126,18 +125,12 @@ int usbd_class_handle_xfer(struct usbd_contex *const uds_ctx, if (usbd_state_is_configured(uds_ctx)) { cfg_nd = usbd_config_get_current(uds_ctx); - if (xfer_owner_exist(uds_ctx, cfg_nd, buf)) { - return usbd_class_request(bi->owner, buf, err); - } - } - - SYS_SLIST_FOR_EACH_CONTAINER(&uds_ctx->configs, cfg_nd, node) { - if (xfer_owner_exist(uds_ctx, cfg_nd, buf)) { - return usbd_class_request(bi->owner, buf, err); + if (!xfer_owner_exist(uds_ctx, cfg_nd, buf)) { + LOG_DBG("Class request without owner"); } + } else { + LOG_DBG("Class request on not configured device"); } - - return -ENODATA; } return usbd_class_request(bi->owner, buf, err); @@ -149,6 +142,7 @@ usbd_class_get_by_ep(struct usbd_contex *const uds_ctx, { struct usbd_class_node *c_nd; struct usbd_config_node *cfg_nd; + enum usbd_speed speed; uint8_t ep_idx = USB_EP_GET_IDX(ep); uint8_t cfg; uint32_t ep_bm; @@ -165,13 +159,14 @@ usbd_class_get_by_ep(struct usbd_contex *const uds_ctx, } cfg = usbd_get_config_value(uds_ctx); - cfg_nd = usbd_config_get(uds_ctx, cfg); + speed = usbd_bus_speed(uds_ctx); + cfg_nd = usbd_config_get(uds_ctx, speed, cfg); if (cfg_nd == NULL) { return NULL; } SYS_SLIST_FOR_EACH_CONTAINER(&cfg_nd->class_list, c_nd, node) { - if (c_nd->data->ep_assigned & ep_bm) { + if (c_nd->ep_assigned & ep_bm) { return c_nd; } } @@ -192,16 +187,16 @@ usbd_class_get_by_req(struct usbd_contex *const uds_ctx, } SYS_SLIST_FOR_EACH_CONTAINER(&cfg_nd->class_list, c_nd, node) { - if (c_nd->data->v_reqs == NULL) { + if (c_nd->c_data->v_reqs == NULL) { continue; } - for (int i = 0; i < c_nd->data->v_reqs->len; i++) { + for (int i = 0; i < c_nd->c_data->v_reqs->len; i++) { /* * First instance always wins. * There is no other way to determine the recipient. */ - if (c_nd->data->v_reqs->reqs[i] == request) { + if (c_nd->c_data->v_reqs->reqs[i] == request) { return c_nd; } } @@ -210,11 +205,22 @@ usbd_class_get_by_req(struct usbd_contex *const uds_ctx, return NULL; } -static struct usbd_class_node *usbd_class_node_get(const char *name) +static struct usbd_class_node * +usbd_class_node_get(const char *name, const enum usbd_speed speed) { - STRUCT_SECTION_FOREACH(usbd_class_node, c_nd) { - if (strcmp(name, c_nd->name) == 0) { - return c_nd; + if (speed == USBD_SPEED_FS) { + STRUCT_SECTION_FOREACH_ALTERNATE(usbd_class_fs, + usbd_class_node, c_nd) { + if (strcmp(name, c_nd->c_data->name) == 0) { + return c_nd; + } + } + } else if (speed == USBD_SPEED_HS) { + STRUCT_SECTION_FOREACH_ALTERNATE(usbd_class_hs, + usbd_class_node, c_nd) { + if (strcmp(name, c_nd->c_data->name) == 0) { + return c_nd; + } } } @@ -225,11 +231,12 @@ static struct usbd_class_node *usbd_class_node_get(const char *name) static int usbd_class_append(struct usbd_contex *const uds_ctx, struct usbd_class_node *const c_nd, + const enum usbd_speed speed, const uint8_t cfg) { struct usbd_config_node *cfg_nd; - cfg_nd = usbd_config_get(uds_ctx, cfg); + cfg_nd = usbd_config_get(uds_ctx, speed, cfg); if (cfg_nd == NULL) { return -ENODATA; } @@ -241,11 +248,12 @@ static int usbd_class_append(struct usbd_contex *const uds_ctx, static int usbd_class_remove(struct usbd_contex *const uds_ctx, struct usbd_class_node *const c_nd, + const enum usbd_speed speed, const uint8_t cfg) { struct usbd_config_node *cfg_nd; - cfg_nd = usbd_config_get(uds_ctx, cfg); + cfg_nd = usbd_config_get(uds_ctx, speed, cfg); if (cfg_nd == NULL) { return -ENODATA; } @@ -258,21 +266,22 @@ static int usbd_class_remove(struct usbd_contex *const uds_ctx, } int usbd_class_remove_all(struct usbd_contex *const uds_ctx, + const enum usbd_speed speed, const uint8_t cfg) { struct usbd_config_node *cfg_nd; struct usbd_class_node *c_nd; sys_snode_t *node; - cfg_nd = usbd_config_get(uds_ctx, cfg); + cfg_nd = usbd_config_get(uds_ctx, speed, cfg); if (cfg_nd == NULL) { return -ENODATA; } while ((node = sys_slist_get(&cfg_nd->class_list))) { c_nd = CONTAINER_OF(node, struct usbd_class_node, node); - atomic_clear_bit(&c_nd->data->state, USBD_CCTX_REGISTERED); - usbd_class_shutdown(c_nd); + atomic_clear_bit(&c_nd->state, USBD_CCTX_REGISTERED); + usbd_class_shutdown(c_nd->c_data); LOG_DBG("Remove class node %p from configuration %u", c_nd, cfg); } @@ -285,13 +294,13 @@ int usbd_class_remove_all(struct usbd_contex *const uds_ctx, int usbd_register_class(struct usbd_contex *const uds_ctx, const char *name, - const uint8_t cfg) + const enum usbd_speed speed, const uint8_t cfg) { struct usbd_class_node *c_nd; - struct usbd_class_data *data; + struct usbd_class_data *c_data; int ret; - c_nd = usbd_class_node_get(name); + c_nd = usbd_class_node_get(name, speed); if (c_nd == NULL) { return -ENODEV; } @@ -304,25 +313,26 @@ int usbd_register_class(struct usbd_contex *const uds_ctx, goto register_class_error; } - data = c_nd->data; - if (data->desc == NULL) { - ret = -EINVAL; - goto register_class_error; - } - + c_data = c_nd->c_data; /* TODO: does it still need to be atomic ? */ - if (atomic_test_bit(&data->state, USBD_CCTX_REGISTERED)) { + if (atomic_test_bit(&c_nd->state, USBD_CCTX_REGISTERED)) { LOG_WRN("Class instance already registered"); ret = -EBUSY; goto register_class_error; } - ret = usbd_class_append(uds_ctx, c_nd, cfg); + if ((c_data->uds_ctx != NULL) && (c_data->uds_ctx != uds_ctx)) { + LOG_ERR("Class registered to other context at different speed"); + ret = -EBUSY; + goto register_class_error; + } + + ret = usbd_class_append(uds_ctx, c_nd, speed, cfg); if (ret == 0) { /* Initialize pointer back to the device struct */ - atomic_set_bit(&data->state, USBD_CCTX_REGISTERED); - data->uds_ctx = uds_ctx; + atomic_set_bit(&c_nd->state, USBD_CCTX_REGISTERED); + c_data->uds_ctx = uds_ctx; } register_class_error: @@ -332,13 +342,14 @@ int usbd_register_class(struct usbd_contex *const uds_ctx, int usbd_unregister_class(struct usbd_contex *const uds_ctx, const char *name, - const uint8_t cfg) + const enum usbd_speed speed, const uint8_t cfg) { struct usbd_class_node *c_nd; - struct usbd_class_data *data; + struct usbd_class_data *c_data; + bool can_release_data = true; int ret; - c_nd = usbd_class_node_get(name); + c_nd = usbd_class_node_get(name, speed); if (c_nd == NULL) { return -ENODEV; } @@ -351,19 +362,45 @@ int usbd_unregister_class(struct usbd_contex *const uds_ctx, goto unregister_class_error; } - data = c_nd->data; + c_data = c_nd->c_data; /* TODO: does it still need to be atomic ? */ - if (!atomic_test_bit(&data->state, USBD_CCTX_REGISTERED)) { + if (!atomic_test_bit(&c_nd->state, USBD_CCTX_REGISTERED)) { LOG_WRN("Class instance not registered"); ret = -EBUSY; goto unregister_class_error; } - ret = usbd_class_remove(uds_ctx, c_nd, cfg); + /* TODO: The use of atomic here does not make this code thread safe. + * The atomic should be changed to something else. + */ + if (speed == USBD_SPEED_HS) { + STRUCT_SECTION_FOREACH_ALTERNATE(usbd_class_fs, + usbd_class_node, i) { + if ((i->c_data == c_nd->c_data) && + atomic_test_bit(&i->state, USBD_CCTX_REGISTERED)) { + can_release_data = false; + break; + } + } + } else { + STRUCT_SECTION_FOREACH_ALTERNATE(usbd_class_hs, + usbd_class_node, i) { + if ((i->c_data == c_nd->c_data) && + atomic_test_bit(&i->state, USBD_CCTX_REGISTERED)) { + can_release_data = false; + break; + } + } + } + + ret = usbd_class_remove(uds_ctx, c_nd, speed, cfg); if (ret == 0) { - atomic_clear_bit(&data->state, USBD_CCTX_REGISTERED); - usbd_class_shutdown(c_nd); - data->uds_ctx = NULL; + atomic_clear_bit(&c_nd->state, USBD_CCTX_REGISTERED); + usbd_class_shutdown(c_nd->c_data); + + if (can_release_data) { + c_data->uds_ctx = NULL; + } } unregister_class_error: diff --git a/subsys/usb/device_next/usbd_class.h b/subsys/usb/device_next/usbd_class.h index 63a32ed5727..e89470cb0e0 100644 --- a/subsys/usb/device_next/usbd_class.h +++ b/subsys/usb/device_next/usbd_class.h @@ -23,19 +23,19 @@ int usbd_class_handle_xfer(struct usbd_contex *const uds_ctx, const int err); /** - * @brief Calculate the length of the class descriptor + * @brief Calculate the length of the class function descriptor * - * Calculate the length of the class instance descriptor. - * The descriptor must be terminated by a usb_desc_header structure - * set to {bLength = 0, bDescriptorType = 0,}. + * Calculate the length of the class instance function descriptor. * Calculated length does not include any string descriptors that may be * used by the class instance. * - * @param[in] node Pointer to a class node + * @param[in] c_data Pointer to a class data + * @param[in] speed Speed-dependent descriptor selector * * @return Length of the class descriptor */ -size_t usbd_class_desc_len(struct usbd_class_node *node); +size_t usbd_class_desc_len(struct usbd_class_data *const c_data, + const enum usbd_speed speed); /** * @brief Get class context by bInterfaceNumber value @@ -45,7 +45,7 @@ size_t usbd_class_desc_len(struct usbd_class_node *node); * @param[in] uds_ctx Pointer to device context * @param[in] inum Interface number * - * @return Class node pointer or NULL + * @return Class c_nd pointer or NULL */ struct usbd_class_node *usbd_class_get_by_iface(struct usbd_contex *uds_ctx, uint8_t i_n); @@ -54,12 +54,14 @@ struct usbd_class_node *usbd_class_get_by_iface(struct usbd_contex *uds_ctx, * @brief Get class context by configuration and interface number * * @param[in] uds_ctx Pointer to device context + * @param[in] speed Speed the configuration number refers to * @param[in] cnum Configuration number * @param[in] inum Interface number * - * @return Class node pointer or NULL + * @return Class c_nd pointer or NULL */ struct usbd_class_node *usbd_class_get_by_config(struct usbd_contex *uds_ctx, + const enum usbd_speed speed, uint8_t cnum, uint8_t inum); @@ -71,7 +73,7 @@ struct usbd_class_node *usbd_class_get_by_config(struct usbd_contex *uds_ctx, * @param[in] uds_ctx Pointer to device context * @param[in] ep Endpoint address * - * @return Class node pointer or NULL + * @return Class c_nd pointer or NULL */ struct usbd_class_node *usbd_class_get_by_ep(struct usbd_contex *uds_ctx, uint8_t ep); @@ -88,7 +90,7 @@ struct usbd_class_node *usbd_class_get_by_ep(struct usbd_contex *uds_ctx, * @param[in] uds_ctx Pointer to device context * @param[in] request bRequest value * - * @return Class node pointer or NULL + * @return Class c_nd pointer or NULL */ struct usbd_class_node *usbd_class_get_by_req(struct usbd_contex *uds_ctx, uint8_t request); @@ -97,11 +99,13 @@ struct usbd_class_node *usbd_class_get_by_req(struct usbd_contex *uds_ctx, * @brief Remove all registered class instances from a configuration * * @param[in] uds_ctx Pointer to device context + * @param[in] speed Speed the configuration number applies to * @param[in] cfg Configuration number (bConfigurationValue) * * @return 0 on success, other values on fail. */ int usbd_class_remove_all(struct usbd_contex *const uds_ctx, + const enum usbd_speed speed, const uint8_t cfg); #endif /* ZEPHYR_INCLUDE_USBD_CLASS_H */ diff --git a/subsys/usb/device_next/usbd_class_api.h b/subsys/usb/device_next/usbd_class_api.h index 375fee06bd6..88207ccc39c 100644 --- a/subsys/usb/device_next/usbd_class_api.h +++ b/subsys/usb/device_next/usbd_class_api.h @@ -22,18 +22,18 @@ * This is the event handler for all endpoint accommodated * by a class instance. * - * @param[in] node Pointer to USB device class node + * @param[in] c_data Pointer to USB device class data * @param[in] buf Control Request Data buffer * @param[in] err Result of the transfer. 0 if the transfer was successful. */ -static inline int usbd_class_request(struct usbd_class_node *const node, +static inline int usbd_class_request(struct usbd_class_data *const c_data, struct net_buf *const buf, int err) { - const struct usbd_class_api *api = node->api; + const struct usbd_class_api *api = c_data->api; if (api->request != NULL) { - return api->request(node, buf, err); + return api->request(c_data, buf, err); } return -ENOTSUP; @@ -53,20 +53,20 @@ static inline int usbd_class_request(struct usbd_class_node *const node, * * The execution of the handler must not block. * - * @param[in] node Pointer to USB device class node + * @param[in] c_data Pointer to USB device class data * @param[in] setup Pointer to USB Setup Packet * @param[in] buf Control Request Data buffer * * @return 0 on success, other values on fail. */ -static inline int usbd_class_control_to_host(struct usbd_class_node *const node, +static inline int usbd_class_control_to_host(struct usbd_class_data *const c_data, struct usb_setup_packet *const setup, struct net_buf *const buf) { - const struct usbd_class_api *api = node->api; + const struct usbd_class_api *api = c_data->api; if (api->control_to_host != NULL) { - return api->control_to_host(node, setup, buf); + return api->control_to_host(c_data, setup, buf); } errno = -ENOTSUP; @@ -86,20 +86,20 @@ static inline int usbd_class_control_to_host(struct usbd_class_node *const node, * * The execution of the handler must not block. * - * @param[in] node Pointer to USB device class node + * @param[in] c_data Pointer to USB device class data * @param[in] setup Pointer to USB Setup Packet * @param[in] buf Control Request Data buffer * * @return 0 on success, other values on fail. */ -static inline int usbd_class_control_to_dev(struct usbd_class_node *const node, +static inline int usbd_class_control_to_dev(struct usbd_class_data *const c_data, struct usb_setup_packet *const setup, struct net_buf *const buf) { - const struct usbd_class_api *api = node->api; + const struct usbd_class_api *api = c_data->api; if (api->control_to_dev != NULL) { - return api->control_to_dev(node, setup, buf); + return api->control_to_dev(c_data, setup, buf); } errno = -ENOTSUP; @@ -115,19 +115,19 @@ static inline int usbd_class_control_to_dev(struct usbd_class_node *const node, * * The execution of the handler must not block. * - * @param[in] node Pointer to USB device class node + * @param[in] c_data Pointer to USB device class data * @param[in] ep Endpoint * @param[in] halted True if the endpoint has been halted and false if * the endpoint halt has been cleared by a Feature request. */ -static inline void usbd_class_feature_halt(struct usbd_class_node *const node, +static inline void usbd_class_feature_halt(struct usbd_class_data *const c_data, const uint8_t ep, const bool halted) { - const struct usbd_class_api *api = node->api; + const struct usbd_class_api *api = c_data->api; if (api->feature_halt != NULL) { - api->feature_halt(node, ep, halted); + api->feature_halt(c_data, ep, halted); } } @@ -140,32 +140,33 @@ static inline void usbd_class_feature_halt(struct usbd_class_node *const node, * * The execution of the handler must not block. * - * @param[in] node Pointer to USB device class node + * @param[in] c_data Pointer to USB device class data * @param[in] iface Interface * @param[in] alternate Alternate setting */ -static inline void usbd_class_update(struct usbd_class_node *const node, +static inline void usbd_class_update(struct usbd_class_data *const c_data, const uint8_t iface, const uint8_t alternate) { - const struct usbd_class_api *api = node->api; + const struct usbd_class_api *api = c_data->api; if (api->update != NULL) { - api->update(node, iface, alternate); + api->update(c_data, iface, alternate); } } + /** * @brief USB suspended handler * - * @param[in] node Pointer to USB device class node + * @param[in] c_data Pointer to USB device class data */ -static inline void usbd_class_suspended(struct usbd_class_node *const node) +static inline void usbd_class_suspended(struct usbd_class_data *const c_data) { - const struct usbd_class_api *api = node->api; + const struct usbd_class_api *api = c_data->api; if (api->suspended != NULL) { - api->suspended(node); + api->suspended(c_data); } } @@ -173,14 +174,14 @@ static inline void usbd_class_suspended(struct usbd_class_node *const node) /** * @brief USB resumed handler * - * @param[in] node Pointer to USB device class node + * @param[in] c_data Pointer to USB device class data */ -static inline void usbd_class_resumed(struct usbd_class_node *const node) +static inline void usbd_class_resumed(struct usbd_class_data *const c_data) { - const struct usbd_class_api *api = node->api; + const struct usbd_class_api *api = c_data->api; if (api->resumed != NULL) { - api->resumed(node); + api->resumed(c_data); } } @@ -189,14 +190,14 @@ static inline void usbd_class_resumed(struct usbd_class_node *const node) * * @note The execution of the handler must not block. * - * @param[in] node Pointer to USB device class node + * @param[in] c_data Pointer to USB device class data */ -static inline void usbd_class_sof(struct usbd_class_node *const node) +static inline void usbd_class_sof(struct usbd_class_data *const c_data) { - const struct usbd_class_api *api = node->api; + const struct usbd_class_api *api = c_data->api; if (api->sof != NULL) { - api->sof(node); + api->sof(c_data); } } @@ -205,14 +206,14 @@ static inline void usbd_class_sof(struct usbd_class_node *const node) * * @note The execution of the handler must not block. * - * @param[in] node Pointer to USB device class node + * @param[in] c_data Pointer to USB device class data */ -static inline void usbd_class_enable(struct usbd_class_node *const node) +static inline void usbd_class_enable(struct usbd_class_data *const c_data) { - const struct usbd_class_api *api = node->api; + const struct usbd_class_api *api = c_data->api; if (api->enable != NULL) { - api->enable(node); + api->enable(c_data); } } @@ -221,14 +222,14 @@ static inline void usbd_class_enable(struct usbd_class_node *const node) * * @note The execution of the handler must not block. * - * @param[in] node Pointer to USB device class node + * @param[in] c_data Pointer to USB device class data */ -static inline void usbd_class_disable(struct usbd_class_node *const node) +static inline void usbd_class_disable(struct usbd_class_data *const c_data) { - const struct usbd_class_api *api = node->api; + const struct usbd_class_api *api = c_data->api; if (api->disable != NULL) { - api->disable(node); + api->disable(c_data); } } @@ -243,16 +244,16 @@ static inline void usbd_class_disable(struct usbd_class_node *const node) * * @note If this call fails the core will terminate stack initialization. * - * @param[in] node Pointer to USB device class node + * @param[in] c_data Pointer to USB device class data * * @return 0 on success, other values on fail. */ -static inline int usbd_class_init(struct usbd_class_node *const node) +static inline int usbd_class_init(struct usbd_class_data *const c_data) { - const struct usbd_class_api *api = node->api; + const struct usbd_class_api *api = c_data->api; if (api->init != NULL) { - return api->init(node); + return api->init(c_data); } return -ENOTSUP; @@ -265,15 +266,36 @@ static inline int usbd_class_init(struct usbd_class_node *const node) * * @note The execution of the handler must not block. * - * @param[in] node Pointer to USB device class node + * @param[in] c_data Pointer to USB device class data */ -static inline void usbd_class_shutdown(struct usbd_class_node *const node) +static inline void usbd_class_shutdown(struct usbd_class_data *const c_data) { - const struct usbd_class_api *api = node->api; + const struct usbd_class_api *api = c_data->api; if (api->shutdown != NULL) { - api->shutdown(node); + api->shutdown(c_data); } } +/** + * @brief Get function descriptor + * + * @param[in] c_data Pointer to USB device class data + * @param[in] speed For which speed descriptor is requested. + * + * @return Array of struct usb_desc_header pointers with a last element + * pointing to a nil descriptor on success, NULL if not available. + */ +static inline void *usbd_class_get_desc(struct usbd_class_data *const c_data, + const enum usbd_speed speed) +{ + const struct usbd_class_api *api = c_data->api; + + if (api->get_desc != NULL) { + return api->get_desc(c_data, speed); + } + + return NULL; +} + #endif /* ZEPHYR_INCLUDE_USBD_CLASS_API_H */ diff --git a/subsys/usb/device_next/usbd_config.c b/subsys/usb/device_next/usbd_config.c index 5ac859a5e3a..6162c4c1461 100644 --- a/subsys/usb/device_next/usbd_config.c +++ b/subsys/usb/device_next/usbd_config.c @@ -16,12 +16,26 @@ #include LOG_MODULE_REGISTER(usbd_cfg, CONFIG_USBD_LOG_LEVEL); +static sys_slist_t *usbd_configs(struct usbd_contex *uds_ctx, + const enum usbd_speed speed) +{ + switch (speed) { + case USBD_SPEED_FS: + return &uds_ctx->fs_configs; + case USBD_SPEED_HS: + return &uds_ctx->hs_configs; + default: + return NULL; + } +} + struct usbd_config_node *usbd_config_get(struct usbd_contex *const uds_ctx, + const enum usbd_speed speed, const uint8_t cfg) { struct usbd_config_node *cfg_nd; - SYS_SLIST_FOR_EACH_CONTAINER(&uds_ctx->configs, cfg_nd, node) { + SYS_SLIST_FOR_EACH_CONTAINER(usbd_configs(uds_ctx, speed), cfg_nd, node) { if (usbd_config_get_value(cfg_nd) == cfg) { return cfg_nd; } @@ -38,7 +52,8 @@ usbd_config_get_current(struct usbd_contex *const uds_ctx) return NULL; } - return usbd_config_get(uds_ctx, usbd_get_config_value(uds_ctx)); + return usbd_config_get(uds_ctx, usbd_bus_speed(uds_ctx), + usbd_get_config_value(uds_ctx)); } static void usbd_config_classes_enable(struct usbd_config_node *const cfg_nd, @@ -48,9 +63,9 @@ static void usbd_config_classes_enable(struct usbd_config_node *const cfg_nd, SYS_SLIST_FOR_EACH_CONTAINER(&cfg_nd->class_list, c_nd, node) { if (enable) { - usbd_class_enable(c_nd); + usbd_class_enable(c_nd->c_data); } else { - usbd_class_disable(c_nd); + usbd_class_disable(c_nd->c_data); } } } @@ -78,11 +93,12 @@ static int usbd_config_reset(struct usbd_contex *const uds_ctx) } bool usbd_config_exist(struct usbd_contex *const uds_ctx, + const enum usbd_speed speed, const uint8_t cfg) { struct usbd_config_node *config; - config = usbd_config_get(uds_ctx, cfg); + config = usbd_config_get(uds_ctx, speed, cfg); return (config != NULL) ? true : false; } @@ -91,6 +107,7 @@ int usbd_config_set(struct usbd_contex *const uds_ctx, const uint8_t new_cfg) { struct usbd_config_node *cfg_nd; + const enum usbd_speed speed = usbd_bus_speed(uds_ctx); int ret; if (usbd_get_config_value(uds_ctx) != 0) { @@ -106,12 +123,12 @@ int usbd_config_set(struct usbd_contex *const uds_ctx, return 0; } - cfg_nd = usbd_config_get(uds_ctx, new_cfg); + cfg_nd = usbd_config_get(uds_ctx, speed, new_cfg); if (cfg_nd == NULL) { return -ENODATA; } - ret = usbd_interface_default(uds_ctx, cfg_nd); + ret = usbd_interface_default(uds_ctx, speed, cfg_nd); if (ret) { return ret; } @@ -127,6 +144,7 @@ int usbd_config_set(struct usbd_contex *const uds_ctx, */ int usbd_config_attrib_rwup(struct usbd_contex *const uds_ctx, + const enum usbd_speed speed, const uint8_t cfg, const bool enable) { struct usbd_config_node *cfg_nd; @@ -148,7 +166,7 @@ int usbd_config_attrib_rwup(struct usbd_contex *const uds_ctx, goto attrib_rwup_exit; } - cfg_nd = usbd_config_get(uds_ctx, cfg); + cfg_nd = usbd_config_get(uds_ctx, speed, cfg); if (cfg_nd == NULL) { LOG_INF("Configuration %u not found", cfg); ret = -ENODATA; @@ -168,6 +186,7 @@ int usbd_config_attrib_rwup(struct usbd_contex *const uds_ctx, } int usbd_config_attrib_self(struct usbd_contex *const uds_ctx, + const enum usbd_speed speed, const uint8_t cfg, const bool enable) { struct usbd_config_node *cfg_nd; @@ -181,7 +200,7 @@ int usbd_config_attrib_self(struct usbd_contex *const uds_ctx, goto attrib_self_exit; } - cfg_nd = usbd_config_get(uds_ctx, cfg); + cfg_nd = usbd_config_get(uds_ctx, speed, cfg); if (cfg_nd == NULL) { LOG_INF("Configuration %u not found", cfg); ret = -ENODATA; @@ -201,6 +220,7 @@ int usbd_config_attrib_self(struct usbd_contex *const uds_ctx, } int usbd_config_maxpower(struct usbd_contex *const uds_ctx, + const enum usbd_speed speed, const uint8_t cfg, const uint8_t power) { struct usbd_config_node *cfg_nd; @@ -214,7 +234,7 @@ int usbd_config_maxpower(struct usbd_contex *const uds_ctx, goto maxpower_exit; } - cfg_nd = usbd_config_get(uds_ctx, cfg); + cfg_nd = usbd_config_get(uds_ctx, speed, cfg); if (cfg_nd == NULL) { LOG_INF("Configuration %u not found", cfg); ret = -ENODATA; @@ -230,9 +250,12 @@ int usbd_config_maxpower(struct usbd_contex *const uds_ctx, } int usbd_add_configuration(struct usbd_contex *const uds_ctx, + const enum usbd_speed speed, struct usbd_config_node *const cfg_nd) { struct usb_cfg_descriptor *desc = cfg_nd->desc; + sys_slist_t *configs; + sys_snode_t *node; int ret = 0; usbd_device_lock(uds_ctx); @@ -243,6 +266,13 @@ int usbd_add_configuration(struct usbd_contex *const uds_ctx, goto add_configuration_exit; } + if (speed == USBD_SPEED_HS && + usbd_caps_speed(uds_ctx) == USBD_SPEED_FS) { + LOG_ERR("Controller doesn't support HS"); + ret = -ENOTSUP; + goto add_configuration_exit; + } + if (desc->bmAttributes & USB_SCD_REMOTE_WAKEUP) { struct udc_device_caps caps = udc_caps(uds_ctx->dev); @@ -253,15 +283,43 @@ int usbd_add_configuration(struct usbd_contex *const uds_ctx, } } - if (sys_slist_find_and_remove(&uds_ctx->configs, &cfg_nd->node)) { + configs = usbd_configs(uds_ctx, speed); + switch (speed) { + case USBD_SPEED_HS: + SYS_SLIST_FOR_EACH_NODE(&uds_ctx->fs_configs, node) { + if (node == &cfg_nd->node) { + LOG_ERR("HS config already on FS list"); + ret = -EINVAL; + goto add_configuration_exit; + } + } + break; + case USBD_SPEED_FS: + SYS_SLIST_FOR_EACH_NODE(&uds_ctx->hs_configs, node) { + if (node == &cfg_nd->node) { + LOG_ERR("FS config already on HS list"); + ret = -EINVAL; + goto add_configuration_exit; + } + } + break; + default: + LOG_ERR("Unsupported configuration speed"); + ret = -ENOTSUP; + goto add_configuration_exit; + } + + if (sys_slist_find_and_remove(configs, &cfg_nd->node)) { LOG_WRN("Configuration %u re-inserted", usbd_config_get_value(cfg_nd)); } else { - usbd_config_set_value(cfg_nd, usbd_get_num_configs(uds_ctx) + 1); - usbd_set_num_configs(uds_ctx, usbd_get_num_configs(uds_ctx) + 1); + uint8_t num = usbd_get_num_configs(uds_ctx, speed) + 1; + + usbd_config_set_value(cfg_nd, num); + usbd_set_num_configs(uds_ctx, speed, num); } - sys_slist_append(&uds_ctx->configs, &cfg_nd->node); + sys_slist_append(configs, &cfg_nd->node); usbd_device_unlock(uds_ctx); diff --git a/subsys/usb/device_next/usbd_config.h b/subsys/usb/device_next/usbd_config.h index b3e8794ee6c..f042446f4a1 100644 --- a/subsys/usb/device_next/usbd_config.h +++ b/subsys/usb/device_next/usbd_config.h @@ -42,11 +42,13 @@ static inline void usbd_config_set_value(const struct usbd_config_node *const cf * Get configuration node with desired configuration number. * * @param[in] ctx Pointer to USB device support context + * @param[in] speed Speed the configuration number applies to * @param[in] cfg Configuration number (bConfigurationValue) * * @return pointer to configuration node or NULL if does not exist */ struct usbd_config_node *usbd_config_get(struct usbd_contex *uds_ctx, + const enum usbd_speed speed, uint8_t cfg); /** @@ -64,11 +66,13 @@ struct usbd_config_node *usbd_config_get_current(struct usbd_contex *uds_ctx); * @brief Check whether a configuration exist * * @param[in] ctx Pointer to USB device support context + * @param[in] speed Speed at which the configuration should be checked * @param[in] cfg Configuration number (bConfigurationValue) * * @return True if a configuration exist. */ bool usbd_config_exist(struct usbd_contex *const uds_ctx, + const enum usbd_speed speed, const uint8_t cfg); /** diff --git a/subsys/usb/device_next/usbd_core.c b/subsys/usb/device_next/usbd_core.c index bab37f39ed9..40999b0f7e4 100644 --- a/subsys/usb/device_next/usbd_core.c +++ b/subsys/usb/device_next/usbd_core.c @@ -78,13 +78,13 @@ static void usbd_class_bcast_event(struct usbd_contex *const uds_ctx, SYS_SLIST_FOR_EACH_CONTAINER(&cfg_nd->class_list, c_nd, node) { switch (event->type) { case UDC_EVT_SUSPEND: - usbd_class_suspended(c_nd); + usbd_class_suspended(c_nd->c_data); break; case UDC_EVT_RESUME: - usbd_class_resumed(c_nd); + usbd_class_resumed(c_nd->c_data); break; case UDC_EVT_SOF: - usbd_class_sof(c_nd); + usbd_class_sof(c_nd->c_data); break; default: break; @@ -94,6 +94,7 @@ static void usbd_class_bcast_event(struct usbd_contex *const uds_ctx, static int event_handler_bus_reset(struct usbd_contex *const uds_ctx) { + enum udc_bus_speed udc_speed; int ret; usbd_status_suspended(uds_ctx, false); @@ -114,7 +115,16 @@ static int event_handler_bus_reset(struct usbd_contex *const uds_ctx) LOG_ERR("Failed to dequeue control IN"); } - LOG_INF("Actual device speed %d", udc_device_speed(uds_ctx->dev)); + LOG_INF("Actual device speed %u", udc_device_speed(uds_ctx->dev)); + udc_speed = udc_device_speed(uds_ctx->dev); + switch (udc_speed) { + case UDC_BUS_SPEED_HS: + uds_ctx->status.speed = USBD_SPEED_HS; + break; + default: + uds_ctx->status.speed = USBD_SPEED_FS; + } + uds_ctx->ch9_data.state = USBD_STATE_DEFAULT; return 0; @@ -183,8 +193,7 @@ static void usbd_thread(void *p1, void *p2, void *p3) k_msgq_get(&usbd_msgq, &event, K_FOREVER); STRUCT_SECTION_FOREACH(usbd_contex, uds_ctx) { - if (uds_ctx->dev == event.dev && - usbd_is_initialized(uds_ctx)) { + if (uds_ctx->dev == event.dev) { usbd_event_handler(uds_ctx, &event); } } @@ -217,10 +226,19 @@ int usbd_device_shutdown_core(struct usbd_contex *const uds_ctx) struct usbd_config_node *cfg_nd; int ret; - SYS_SLIST_FOR_EACH_CONTAINER(&uds_ctx->configs, cfg_nd, node) { + SYS_SLIST_FOR_EACH_CONTAINER(&uds_ctx->hs_configs, cfg_nd, node) { + uint8_t cfg_value = usbd_config_get_value(cfg_nd); + + ret = usbd_class_remove_all(uds_ctx, USBD_SPEED_HS, cfg_value); + if (ret) { + LOG_ERR("Failed to cleanup registered classes, %d", ret); + } + } + + SYS_SLIST_FOR_EACH_CONTAINER(&uds_ctx->fs_configs, cfg_nd, node) { uint8_t cfg_value = usbd_config_get_value(cfg_nd); - ret = usbd_class_remove_all(uds_ctx, cfg_value); + ret = usbd_class_remove_all(uds_ctx, USBD_SPEED_FS, cfg_value); if (ret) { LOG_ERR("Failed to cleanup registered classes, %d", ret); } @@ -244,10 +262,14 @@ static int usbd_pre_init(void) k_thread_name_set(&usbd_thread_data, "usbd"); - LOG_DBG("Available USB class nodes:"); - STRUCT_SECTION_FOREACH(usbd_class_node, node) { - atomic_set(&node->data->state, 0); - LOG_DBG("\t%p, name %s", node, node->name); + LOG_DBG("Available USB class iterators:"); + STRUCT_SECTION_FOREACH_ALTERNATE(usbd_class_fs, usbd_class_node, c_nd) { + atomic_set(&c_nd->state, 0); + LOG_DBG("\t%p->%p, name %s", c_nd, c_nd->c_data, c_nd->c_data->name); + } + STRUCT_SECTION_FOREACH_ALTERNATE(usbd_class_hs, usbd_class_node, c_nd) { + atomic_set(&c_nd->state, 0); + LOG_DBG("\t%p->%p, name %s", c_nd, c_nd->c_data, c_nd->c_data->name); } return 0; diff --git a/subsys/usb/device_next/usbd_data.ld b/subsys/usb/device_next/usbd_data.ld index 78c09d0f383..40382031422 100644 --- a/subsys/usb/device_next/usbd_data.ld +++ b/subsys/usb/device_next/usbd_data.ld @@ -1,4 +1,5 @@ #include -ITERABLE_SECTION_RAM(usbd_contex, 4) -ITERABLE_SECTION_RAM(usbd_class_node, 4) +ITERABLE_SECTION_RAM(usbd_contex, Z_LINK_ITERABLE_SUBALIGN) +ITERABLE_SECTION_RAM(usbd_class_fs, Z_LINK_ITERABLE_SUBALIGN) +ITERABLE_SECTION_RAM(usbd_class_hs, Z_LINK_ITERABLE_SUBALIGN) diff --git a/subsys/usb/device_next/usbd_desc.c b/subsys/usb/device_next/usbd_desc.c index 825d1b910a0..ecc8e57259a 100644 --- a/subsys/usb/device_next/usbd_desc.c +++ b/subsys/usb/device_next/usbd_desc.c @@ -9,7 +9,6 @@ #include #include #include -#include #include "usbd_desc.h" #include "usbd_device.h" @@ -17,100 +16,10 @@ #include LOG_MODULE_REGISTER(usbd_desc, CONFIG_USBD_LOG_LEVEL); -/* - * The last index of the initializer_string without null character is: - * ascii_idx_max = bLength / 2 - 2 - * Use this macro to determine the last index of ASCII7 string. - */ -#define USB_BSTRING_ASCII_IDX_MAX(n) (n / 2 - 2) - -/* - * The last index of the bString is: - * utf16le_idx_max = sizeof(initializer_string) * 2 - 2 - 1 - * utf16le_idx_max = bLength - 2 - 1 - * Use this macro to determine the last index of UTF16LE string. - */ -#define USB_BSTRING_UTF16LE_IDX_MAX(n) (n - 3) - -/** - * @brief Transform ASCII-7 string descriptor to UTF16-LE - * - * This function transforms ASCII-7 string descriptor - * into a UTF16-LE. - * - * @param[in] dn Pointer to descriptor node - */ -static void usbd_ascii7_to_utf16le(struct usbd_desc_node *const dn) -{ - struct usb_string_descriptor *desc = dn->desc; - int idx_max = USB_BSTRING_UTF16LE_IDX_MAX(desc->bLength); - int ascii_idx_max = USB_BSTRING_ASCII_IDX_MAX(desc->bLength); - uint8_t *buf = (uint8_t *)&desc->bString; - - LOG_DBG("idx_max %d, ascii_idx_max %d, buf %p", - idx_max, ascii_idx_max, buf); - - for (int i = idx_max; i >= 0; i -= 2) { - LOG_DBG("char %c : %x, idx %d -> %d", - buf[ascii_idx_max], - buf[ascii_idx_max], - ascii_idx_max, i); - __ASSERT(buf[ascii_idx_max] > 0x1F && buf[ascii_idx_max] < 0x7F, - "Only printable ascii-7 characters are allowed in USB " - "string descriptors"); - buf[i] = 0U; - buf[i - 1] = buf[ascii_idx_max--]; - } - - dn->utf16le = true; -} - -/** - * @brief Get common USB descriptor - * - * Get descriptor from internal descriptor list. - * - * @param[in] dn Pointer to descriptor node - * - * @return 0 on success, other values on fail. - */ -static int usbd_get_sn_from_hwid(struct usbd_desc_node *const dn) -{ - static const char hex[] = "0123456789ABCDEF"; - struct usb_string_descriptor *desc = dn->desc; - uint8_t *desc_data = (uint8_t *)&desc->bString; - uint8_t hwid[16]; - ssize_t hwid_len; - ssize_t min_len; - - hwid_len = hwinfo_get_device_id(hwid, sizeof(hwid)); - if (hwid_len < 0) { - if (hwid_len == -ENOSYS) { - LOG_WRN("hwinfo not implemented"); - return 0; - } - - return hwid_len; - } - - min_len = MIN(hwid_len, desc->bLength / 2); - for (size_t i = 0; i < min_len; i++) { - desc_data[i * 2] = hex[hwid[i] >> 4]; - desc_data[i * 2 + 1] = hex[hwid[i] & 0xF]; - } - - LOG_HEXDUMP_DBG(&desc->bString, desc->bLength, "SerialNumber"); - - return 0; -} - static inline bool desc_type_equal(const struct usbd_desc_node *const a, const struct usbd_desc_node *const b) { - const struct usb_desc_header *const head_a = a->desc; - const struct usb_desc_header *const head_b = b->desc; - - return head_a->bDescriptorType == head_b->bDescriptorType; + return a->bDescriptorType == b->bDescriptorType; } /* @@ -137,50 +46,56 @@ static int desc_add_and_update_idx(struct usbd_contex *const uds_ctx, if (next_nd == NULL) { /* Last node of the same bDescriptorType or tail */ - new_nd->idx = tmp_nd->idx + 1; + new_nd->str.idx = tmp_nd->str.idx + 1; sys_dlist_append(&uds_ctx->descriptors, &new_nd->node); - LOG_DBG("Add %u behind %u", new_nd->idx, tmp_nd->idx); + LOG_DBG("Add %u behind %u", new_nd->str.idx, tmp_nd->str.idx); return 0; } if (!desc_type_equal(next_nd, new_nd)) { /* Last node of the same bDescriptorType */ - new_nd->idx = tmp_nd->idx + 1; + new_nd->str.idx = tmp_nd->str.idx + 1; sys_dlist_insert(&next_nd->node, &new_nd->node); - LOG_DBG("Add %u before %u", new_nd->idx, next_nd->idx); + LOG_DBG("Add %u before %u", new_nd->str.idx, next_nd->str.idx); return 0; } - if (tmp_nd->idx != (next_nd->idx - 1)) { + if (tmp_nd->str.idx != (next_nd->str.idx - 1)) { /* Add between nodes of the same bDescriptorType */ - new_nd->idx = tmp_nd->idx + 1; + new_nd->str.idx = tmp_nd->str.idx + 1; sys_dlist_insert(&next_nd->node, &new_nd->node); LOG_DBG("Add %u between %u and %u", - tmp_nd->idx, next_nd->idx, new_nd->idx); + tmp_nd->str.idx, next_nd->str.idx, new_nd->str.idx); return 0; } } /* If there are none of same bDescriptorType, node idx is set to 0. */ - new_nd->idx = 0; + new_nd->str.idx = 0; sys_dlist_append(&uds_ctx->descriptors, &new_nd->node); - LOG_DBG("Added first descriptor node (usage type %u)", new_nd->utype); + LOG_DBG("Added first descriptor node (usage type %u)", new_nd->str.utype); return 0; } -void *usbd_get_descriptor(struct usbd_contex *const uds_ctx, - const uint8_t type, const uint8_t idx) +struct usbd_desc_node *usbd_get_descriptor(struct usbd_contex *const uds_ctx, + const uint8_t type, const uint8_t idx) { - struct usbd_desc_node *tmp; - struct usb_desc_header *dh; + struct usbd_desc_node *desc_nd; + + SYS_DLIST_FOR_EACH_CONTAINER(&uds_ctx->descriptors, desc_nd, node) { + if (desc_nd->bDescriptorType == type) { + if (desc_nd->bDescriptorType == USB_DESC_STRING) { + if (desc_nd->str.idx == idx) { + return desc_nd; + } + } - SYS_DLIST_FOR_EACH_CONTAINER(&uds_ctx->descriptors, tmp, node) { - dh = tmp->desc; - if (tmp->idx == idx && dh->bDescriptorType == type) { - return tmp->desc; + if (desc_nd->bDescriptorType == USB_DESC_BOS) { + return desc_nd; + } } } @@ -203,13 +118,14 @@ int usbd_desc_remove_all(struct usbd_contex *const uds_ctx) int usbd_add_descriptor(struct usbd_contex *const uds_ctx, struct usbd_desc_node *const desc_nd) { - struct usb_device_descriptor *dev_desc = uds_ctx->desc; - struct usb_desc_header *head; + struct usb_device_descriptor *hs_desc, *fs_desc; int ret = 0; usbd_device_lock(uds_ctx); - if (dev_desc == NULL || usbd_is_initialized(uds_ctx)) { + hs_desc = uds_ctx->hs_desc; + fs_desc = uds_ctx->fs_desc; + if (!fs_desc || !hs_desc || usbd_is_initialized(uds_ctx)) { ret = -EPERM; goto add_descriptor_error; } @@ -220,46 +136,63 @@ int usbd_add_descriptor(struct usbd_contex *const uds_ctx, sys_dlist_init(&uds_ctx->descriptors); } - head = desc_nd->desc; if (sys_dnode_is_linked(&desc_nd->node)) { ret = -EALREADY; goto add_descriptor_error; } - ret = desc_add_and_update_idx(uds_ctx, desc_nd); - if (ret) { - ret = -EINVAL; - goto add_descriptor_error; + if (desc_nd->bDescriptorType == USB_DESC_BOS) { + sys_dlist_append(&uds_ctx->descriptors, &desc_nd->node); } - if (head->bDescriptorType == USB_DESC_STRING) { - switch (desc_nd->utype) { + if (desc_nd->bDescriptorType == USB_DESC_STRING) { + ret = desc_add_and_update_idx(uds_ctx, desc_nd); + if (ret) { + ret = -EINVAL; + goto add_descriptor_error; + } + + switch (desc_nd->str.utype) { case USBD_DUT_STRING_LANG: break; case USBD_DUT_STRING_MANUFACTURER: - dev_desc->iManufacturer = desc_nd->idx; + hs_desc->iManufacturer = desc_nd->str.idx; + fs_desc->iManufacturer = desc_nd->str.idx; break; case USBD_DUT_STRING_PRODUCT: - dev_desc->iProduct = desc_nd->idx; + hs_desc->iProduct = desc_nd->str.idx; + fs_desc->iProduct = desc_nd->str.idx; break; case USBD_DUT_STRING_SERIAL_NUMBER: - if (!desc_nd->custom_sn) { - ret = usbd_get_sn_from_hwid(desc_nd); - desc_nd->utf16le = false; - } - - dev_desc->iSerialNumber = desc_nd->idx; + hs_desc->iSerialNumber = desc_nd->str.idx; + fs_desc->iSerialNumber = desc_nd->str.idx; break; default: break; } - - if (desc_nd->idx && !desc_nd->utf16le) { - usbd_ascii7_to_utf16le(desc_nd); - } } add_descriptor_error: usbd_device_unlock(uds_ctx); return ret; } + +uint8_t usbd_str_desc_get_idx(const struct usbd_desc_node *const desc_nd) +{ + if (sys_dnode_is_linked(&desc_nd->node)) { + return desc_nd->str.idx; + } + + return 0; +} + +void usbd_remove_descriptor(struct usbd_desc_node *const desc_nd) +{ + if (sys_dnode_is_linked(&desc_nd->node)) { + sys_dlist_remove(&desc_nd->node); + + if (desc_nd->bDescriptorType == USB_DESC_STRING) { + desc_nd->str.idx = 0U; + } + } +} diff --git a/subsys/usb/device_next/usbd_desc.h b/subsys/usb/device_next/usbd_desc.h index 0b3702206d2..623e92e90c4 100644 --- a/subsys/usb/device_next/usbd_desc.h +++ b/subsys/usb/device_next/usbd_desc.h @@ -10,18 +10,18 @@ #include /** - * @brief Get common USB descriptor + * @brief Get USB descriptor node * - * Get descriptor from internal descriptor list. + * Get descriptor node from internal descriptor list. * * @param[in] ctx Pointer to USB device support context * @param[in] type Descriptor type (bDescriptorType) * @param[in] idx Descriptor index * - * @return pointer to descriptor or NULL if not found. + * @return pointer to descriptor node or NULL if not found. */ -void *usbd_get_descriptor(struct usbd_contex *uds_ctx, - const uint8_t type, const uint8_t idx); +struct usbd_desc_node *usbd_get_descriptor(struct usbd_contex *const uds_ctx, + const uint8_t type, const uint8_t idx); /** * @brief Remove all descriptors from an USB device context diff --git a/subsys/usb/device_next/usbd_device.c b/subsys/usb/device_next/usbd_device.c index 319c73fce2b..9057e439040 100644 --- a/subsys/usb/device_next/usbd_device.c +++ b/subsys/usb/device_next/usbd_device.c @@ -20,10 +20,42 @@ LOG_MODULE_REGISTER(usbd_dev, CONFIG_USBD_LOG_LEVEL); * All the functions below are part of public USB device support API. */ +enum usbd_speed usbd_bus_speed(const struct usbd_contex *const uds_ctx) +{ + return uds_ctx->status.speed; +} + +enum usbd_speed usbd_caps_speed(const struct usbd_contex *const uds_ctx) +{ + struct udc_device_caps caps = udc_caps(uds_ctx->dev); + + /* For now, either high speed is supported or not. */ + if (caps.hs) { + return USBD_SPEED_HS; + } + + return USBD_SPEED_FS; +} + +static struct usb_device_descriptor * +get_device_descriptor(struct usbd_contex *const uds_ctx, + const enum usbd_speed speed) +{ + switch (speed) { + case USBD_SPEED_FS: + return uds_ctx->fs_desc; + case USBD_SPEED_HS: + return uds_ctx->hs_desc; + default: + __ASSERT(false, "Not supported speed"); + return NULL; + } +} + int usbd_device_set_bcd(struct usbd_contex *const uds_ctx, - const uint16_t bcd) + const enum usbd_speed speed, const uint16_t bcd) { - struct usb_device_descriptor *desc = uds_ctx->desc; + struct usb_device_descriptor *desc; int ret = 0; usbd_device_lock(uds_ctx); @@ -33,6 +65,7 @@ int usbd_device_set_bcd(struct usbd_contex *const uds_ctx, goto set_bcd_exit; } + desc = get_device_descriptor(uds_ctx, speed); desc->bcdUSB = sys_cpu_to_le16(bcd); set_bcd_exit: @@ -43,7 +76,7 @@ int usbd_device_set_bcd(struct usbd_contex *const uds_ctx, int usbd_device_set_vid(struct usbd_contex *const uds_ctx, const uint16_t vid) { - struct usb_device_descriptor *desc = uds_ctx->desc; + struct usb_device_descriptor *fs_desc, *hs_desc; int ret = 0; usbd_device_lock(uds_ctx); @@ -53,7 +86,11 @@ int usbd_device_set_vid(struct usbd_contex *const uds_ctx, goto set_vid_exit; } - desc->idVendor = sys_cpu_to_le16(vid); + fs_desc = get_device_descriptor(uds_ctx, USBD_SPEED_FS); + fs_desc->idVendor = sys_cpu_to_le16(vid); + + hs_desc = get_device_descriptor(uds_ctx, USBD_SPEED_HS); + hs_desc->idVendor = sys_cpu_to_le16(vid); set_vid_exit: usbd_device_unlock(uds_ctx); @@ -63,7 +100,7 @@ int usbd_device_set_vid(struct usbd_contex *const uds_ctx, int usbd_device_set_pid(struct usbd_contex *const uds_ctx, const uint16_t pid) { - struct usb_device_descriptor *desc = uds_ctx->desc; + struct usb_device_descriptor *fs_desc, *hs_desc; int ret = 0; usbd_device_lock(uds_ctx); @@ -73,7 +110,11 @@ int usbd_device_set_pid(struct usbd_contex *const uds_ctx, goto set_pid_exit; } - desc->idProduct = sys_cpu_to_le16(pid); + fs_desc = get_device_descriptor(uds_ctx, USBD_SPEED_FS); + fs_desc->idProduct = sys_cpu_to_le16(pid); + + hs_desc = get_device_descriptor(uds_ctx, USBD_SPEED_HS); + hs_desc->idProduct = sys_cpu_to_le16(pid); set_pid_exit: usbd_device_unlock(uds_ctx); @@ -81,10 +122,11 @@ int usbd_device_set_pid(struct usbd_contex *const uds_ctx, } int usbd_device_set_code_triple(struct usbd_contex *const uds_ctx, + const enum usbd_speed speed, const uint8_t base_class, const uint8_t subclass, const uint8_t protocol) { - struct usb_device_descriptor *desc = uds_ctx->desc; + struct usb_device_descriptor *desc; int ret = 0; usbd_device_lock(uds_ctx); @@ -94,6 +136,7 @@ int usbd_device_set_code_triple(struct usbd_contex *const uds_ctx, goto set_code_triple_exit; } + desc = get_device_descriptor(uds_ctx, speed); desc->bDeviceClass = base_class; desc->bDeviceSubClass = subclass; desc->bDeviceProtocol = protocol; @@ -139,6 +182,11 @@ int usbd_init(struct usbd_contex *const uds_ctx) { int ret; + /* + * Lock the scheduler to ensure that the context is not preempted + * before it is fully initialized. + */ + k_sched_lock(); usbd_device_lock(uds_ctx); if (uds_ctx->dev == NULL) { @@ -168,6 +216,8 @@ int usbd_init(struct usbd_contex *const uds_ctx) init_exit: usbd_device_unlock(uds_ctx); + k_sched_unlock(); + return ret; } @@ -253,3 +303,10 @@ int usbd_shutdown(struct usbd_contex *const uds_ctx) return 0; } + +bool usbd_can_detect_vbus(struct usbd_contex *const uds_ctx) +{ + const struct udc_device_caps caps = udc_caps(uds_ctx->dev); + + return caps.can_detect_vbus; +} diff --git a/subsys/usb/device_next/usbd_device.h b/subsys/usb/device_next/usbd_device.h index 083420da2e3..f125345fb4e 100644 --- a/subsys/usb/device_next/usbd_device.h +++ b/subsys/usb/device_next/usbd_device.h @@ -7,18 +7,29 @@ #ifndef ZEPHYR_INCLUDE_USBD_DEVICE_H #define ZEPHYR_INCLUDE_USBD_DEVICE_H +#include #include /** * @brief Get device descriptor bNumConfigurations value * * @param[in] uds_ctx Pointer to a device context + * @param[in] speed Speed for which the bNumConfigurations should be returned * * @return bNumConfigurations value */ -static inline uint8_t usbd_get_num_configs(const struct usbd_contex *const uds_ctx) +static inline uint8_t usbd_get_num_configs(const struct usbd_contex *const uds_ctx, + const enum usbd_speed speed) { - struct usb_device_descriptor *desc = uds_ctx->desc; + struct usb_device_descriptor *desc; + + if (speed == USBD_SPEED_FS) { + desc = uds_ctx->fs_desc; + } else if (speed == USBD_SPEED_HS) { + desc = uds_ctx->hs_desc; + } else { + return 0; + } return desc->bNumConfigurations; } @@ -28,12 +39,22 @@ static inline uint8_t usbd_get_num_configs(const struct usbd_contex *const uds_c * @brief Set device descriptor bNumConfigurations value * * @param[in] uds_ctx Pointer to a device context + * @param[in] speed Speed for which the bNumConfigurations should be set * @param[in] value new bNumConfigurations value */ static inline void usbd_set_num_configs(struct usbd_contex *const uds_ctx, + const enum usbd_speed speed, const uint8_t value) { - struct usb_device_descriptor *desc = uds_ctx->desc; + struct usb_device_descriptor *desc; + + if (speed == USBD_SPEED_FS) { + desc = uds_ctx->fs_desc; + } else if (speed == USBD_SPEED_HS) { + desc = uds_ctx->hs_desc; + } else { + return; + } desc->bNumConfigurations = value; } diff --git a/subsys/usb/device_next/usbd_endpoint.c b/subsys/usb/device_next/usbd_endpoint.c index d57507d8566..fa68313ce8d 100644 --- a/subsys/usb/device_next/usbd_endpoint.c +++ b/subsys/usb/device_next/usbd_endpoint.c @@ -86,17 +86,6 @@ static void usbd_ep_ctrl_set_zlp(struct usbd_contex *const uds_ctx, * All the functions below are part of public USB device support API. */ -struct net_buf *usbd_ep_ctrl_buf_alloc(struct usbd_contex *const uds_ctx, - const uint8_t ep, const size_t size) -{ - if (USB_EP_GET_IDX(ep)) { - /* Not a control endpoint */ - return NULL; - } - - return udc_ep_buf_alloc(uds_ctx->dev, ep, size); -} - int usbd_ep_ctrl_enqueue(struct usbd_contex *const uds_ctx, struct net_buf *const buf) { @@ -120,18 +109,18 @@ int usbd_ep_ctrl_enqueue(struct usbd_contex *const uds_ctx, return udc_ep_enqueue(uds_ctx->dev, buf); } -struct net_buf *usbd_ep_buf_alloc(const struct usbd_class_node *const c_nd, +struct net_buf *usbd_ep_buf_alloc(const struct usbd_class_data *const c_data, const uint8_t ep, const size_t size) { - struct usbd_contex *uds_ctx = c_nd->data->uds_ctx; + struct usbd_contex *uds_ctx = usbd_class_get_ctx(c_data); return udc_ep_buf_alloc(uds_ctx->dev, ep, size); } -int usbd_ep_enqueue(const struct usbd_class_node *const c_nd, +int usbd_ep_enqueue(const struct usbd_class_data *const c_data, struct net_buf *const buf) { - struct usbd_contex *uds_ctx = c_nd->data->uds_ctx; + struct usbd_contex *uds_ctx = usbd_class_get_ctx(c_data); struct udc_buf_info *bi = udc_get_buf_info(buf); if (USB_EP_DIR_IS_IN(bi->ep)) { @@ -140,7 +129,7 @@ int usbd_ep_enqueue(const struct usbd_class_node *const c_nd, } } - bi->owner = (void *)c_nd; + bi->owner = (void *)c_data; return udc_ep_enqueue(uds_ctx->dev, buf); } diff --git a/subsys/usb/device_next/usbd_init.c b/subsys/usb/device_next/usbd_init.c index 98980785f6d..ad0245a4c17 100644 --- a/subsys/usb/device_next/usbd_init.c +++ b/subsys/usb/device_next/usbd_init.c @@ -109,32 +109,38 @@ static int unassign_eps(struct usbd_contex *const uds_ctx, * USB device configuration. */ static int init_configuration_inst(struct usbd_contex *const uds_ctx, - struct usbd_class_data *const data, + const enum usbd_speed speed, + struct usbd_class_node *const c_nd, uint32_t *const config_ep_bm, uint8_t *const nif) { - struct usb_desc_header *dh = data->desc; - uint8_t *ptr = (uint8_t *)dh; + struct usb_desc_header **dhp; struct usb_if_descriptor *ifd = NULL; struct usb_ep_descriptor *ed; uint32_t class_ep_bm = 0; uint8_t tmp_nif; int ret; + LOG_DBG("Initializing configuration for %u speed", speed); + dhp = usbd_class_get_desc(c_nd->c_data, speed); + if (dhp == NULL) { + return 0; + } + tmp_nif = *nif; - data->iface_bm = 0U; - data->ep_active = 0U; + c_nd->iface_bm = 0U; + c_nd->ep_active = 0U; - while (dh->bLength != 0) { + while (*dhp != NULL && (*dhp)->bLength != 0) { - if (dh->bDescriptorType == USB_DESC_INTERFACE) { - ifd = (struct usb_if_descriptor *)ptr; + if ((*dhp)->bDescriptorType == USB_DESC_INTERFACE) { + ifd = (struct usb_if_descriptor *)(*dhp); - data->ep_active |= class_ep_bm; + c_nd->ep_active |= class_ep_bm; if (ifd->bAlternateSetting == 0) { ifd->bInterfaceNumber = tmp_nif; - data->iface_bm |= BIT(tmp_nif); + c_nd->iface_bm |= BIT(tmp_nif); tmp_nif++; } else { ifd->bInterfaceNumber = tmp_nif - 1; @@ -152,20 +158,19 @@ static int init_configuration_inst(struct usbd_contex *const uds_ctx, ifd->bInterfaceNumber, ifd->bAlternateSetting); } - if (dh->bDescriptorType == USB_DESC_ENDPOINT) { - ed = (struct usb_ep_descriptor *)ptr; + if ((*dhp)->bDescriptorType == USB_DESC_ENDPOINT) { + ed = (struct usb_ep_descriptor *)(*dhp); ret = assign_ep_addr(uds_ctx->dev, ed, config_ep_bm, &class_ep_bm); if (ret) { return ret; } - LOG_INF("\tep 0x%02x interface ep-bm 0x%08x", - ed->bEndpointAddress, class_ep_bm); + LOG_INF("\tep 0x%02x mps %u interface ep-bm 0x%08x", + ed->bEndpointAddress, ed->wMaxPacketSize, class_ep_bm); } - ptr += dh->bLength; - dh = (struct usb_desc_header *)ptr; + dhp++; } if (tmp_nif <= *nif) { @@ -173,10 +178,10 @@ static int init_configuration_inst(struct usbd_contex *const uds_ctx, } *nif = tmp_nif; - data->ep_active |= class_ep_bm; + c_nd->ep_active |= class_ep_bm; LOG_INF("Instance iface-bm 0x%08x ep-bm 0x%08x", - data->iface_bm, data->ep_active); + c_nd->iface_bm, c_nd->ep_active); return 0; } @@ -187,6 +192,7 @@ static int init_configuration_inst(struct usbd_contex *const uds_ctx, * Iterate on a list of all classes in a configuration */ static int init_configuration(struct usbd_contex *const uds_ctx, + const enum usbd_speed speed, struct usbd_config_node *const cfg_nd) { struct usb_cfg_descriptor *cfg_desc = cfg_nd->desc; @@ -198,22 +204,22 @@ static int init_configuration(struct usbd_contex *const uds_ctx, SYS_SLIST_FOR_EACH_CONTAINER(&cfg_nd->class_list, c_nd, node) { - ret = init_configuration_inst(uds_ctx, c_nd->data, + ret = init_configuration_inst(uds_ctx, speed, c_nd, &config_ep_bm, &nif); if (ret != 0) { LOG_ERR("Failed to assign endpoint addresses"); return ret; } - ret = usbd_class_init(c_nd); + ret = usbd_class_init(c_nd->c_data); if (ret != 0) { LOG_ERR("Failed to initialize class instance"); return ret; } LOG_INF("Init class node %p, descriptor length %zu", - c_nd, usbd_class_desc_len(c_nd)); - cfg_len += usbd_class_desc_len(c_nd); + c_nd->c_data, usbd_class_desc_len(c_nd->c_data, speed)); + cfg_len += usbd_class_desc_len(c_nd->c_data, speed); } /* Update wTotalLength and bNumInterfaces of configuration descriptor */ @@ -227,8 +233,8 @@ static int init_configuration(struct usbd_contex *const uds_ctx, /* Finally reset configuration's endpoint assignment */ SYS_SLIST_FOR_EACH_CONTAINER(&cfg_nd->class_list, c_nd, node) { - c_nd->data->ep_assigned = c_nd->data->ep_active; - ret = unassign_eps(uds_ctx, &config_ep_bm, &c_nd->data->ep_active); + c_nd->ep_assigned = c_nd->ep_active; + ret = unassign_eps(uds_ctx, &config_ep_bm, &c_nd->ep_active); if (ret != 0) { return ret; } @@ -237,10 +243,10 @@ static int init_configuration(struct usbd_contex *const uds_ctx, return 0; } -static void usbd_init_update_mps0(struct usbd_contex *const uds_ctx) +static void usbd_init_update_fs_mps0(struct usbd_contex *const uds_ctx) { struct udc_device_caps caps = udc_caps(uds_ctx->dev); - struct usb_device_descriptor *desc = uds_ctx->desc; + struct usb_device_descriptor *desc = uds_ctx->fs_desc; switch (caps.mps0) { case UDC_MPS0_8: @@ -262,20 +268,34 @@ int usbd_init_configurations(struct usbd_contex *const uds_ctx) { struct usbd_config_node *cfg_nd; - usbd_init_update_mps0(uds_ctx); + usbd_init_update_fs_mps0(uds_ctx); + + SYS_SLIST_FOR_EACH_CONTAINER(&uds_ctx->hs_configs, cfg_nd, node) { + int ret; + + ret = init_configuration(uds_ctx, USBD_SPEED_HS, cfg_nd); + if (ret) { + LOG_ERR("Failed to init HS configuration %u", + usbd_config_get_value(cfg_nd)); + return ret; + } + + LOG_INF("HS bNumConfigurations %u", + usbd_get_num_configs(uds_ctx, USBD_SPEED_HS)); + } - SYS_SLIST_FOR_EACH_CONTAINER(&uds_ctx->configs, cfg_nd, node) { + SYS_SLIST_FOR_EACH_CONTAINER(&uds_ctx->fs_configs, cfg_nd, node) { int ret; - ret = init_configuration(uds_ctx, cfg_nd); + ret = init_configuration(uds_ctx, USBD_SPEED_FS, cfg_nd); if (ret) { - LOG_ERR("Failed to init configuration %u", + LOG_ERR("Failed to init FS configuration %u", usbd_config_get_value(cfg_nd)); return ret; } - LOG_INF("bNumConfigurations %u", - usbd_get_num_configs(uds_ctx)); + LOG_INF("FS bNumConfigurations %u", + usbd_get_num_configs(uds_ctx, USBD_SPEED_FS)); } return 0; diff --git a/subsys/usb/device_next/usbd_interface.c b/subsys/usb/device_next/usbd_interface.c index b9308e080a4..1e49a259d1e 100644 --- a/subsys/usb/device_next/usbd_interface.c +++ b/subsys/usb/device_next/usbd_interface.c @@ -28,7 +28,7 @@ static int handle_ep_op(struct usbd_contex *const uds_ctx, uint32_t *const ep_bm) { const uint8_t ep = ed->bEndpointAddress; - int ret; + int ret = -ENOTSUP; switch (op) { case EP_OP_TEST: @@ -51,25 +51,26 @@ static int handle_ep_op(struct usbd_contex *const uds_ctx, } static int usbd_interface_modify(struct usbd_contex *const uds_ctx, - struct usbd_class_node *const node, + struct usbd_class_node *const c_nd, const enum ep_op op, const uint8_t iface, const uint8_t alt) { - struct usb_desc_header *dh; + struct usb_desc_header **dhp; bool found_iface = false; - uint8_t *ptr; int ret; - dh = node->data->desc; - ptr = (uint8_t *)dh; + dhp = usbd_class_get_desc(c_nd->c_data, usbd_bus_speed(uds_ctx)); + if (dhp == NULL) { + return -EINVAL; + } - while (dh->bLength != 0) { + while (*dhp != NULL && (*dhp)->bLength != 0) { struct usb_if_descriptor *ifd; struct usb_ep_descriptor *ed; - if (dh->bDescriptorType == USB_DESC_INTERFACE) { - ifd = (struct usb_if_descriptor *)ptr; + if ((*dhp)->bDescriptorType == USB_DESC_INTERFACE) { + ifd = (struct usb_if_descriptor *)(*dhp); if (found_iface) { break; @@ -78,7 +79,7 @@ static int usbd_interface_modify(struct usbd_contex *const uds_ctx, if (ifd->bInterfaceNumber == iface && ifd->bAlternateSetting == alt) { found_iface = true; - LOG_DBG("Found interface %u %p", iface, node); + LOG_DBG("Found interface %u %p", iface, c_nd); if (ifd->bNumEndpoints == 0) { LOG_INF("No endpoints, skip interface"); break; @@ -86,20 +87,19 @@ static int usbd_interface_modify(struct usbd_contex *const uds_ctx, } } - if (dh->bDescriptorType == USB_DESC_ENDPOINT && found_iface) { - ed = (struct usb_ep_descriptor *)ptr; - ret = handle_ep_op(uds_ctx, op, ed, &node->data->ep_active); + if ((*dhp)->bDescriptorType == USB_DESC_ENDPOINT && found_iface) { + ed = (struct usb_ep_descriptor *)(*dhp); + ret = handle_ep_op(uds_ctx, op, ed, &c_nd->ep_active); if (ret) { return ret; } LOG_INF("Modify interface %u ep 0x%02x by op %u ep_bm %x", iface, ed->bEndpointAddress, - op, node->data->ep_active); + op, c_nd->ep_active); } - ptr += dh->bLength; - dh = (struct usb_desc_header *)ptr; + dhp++; } /* TODO: rollback ep_bm on error? */ @@ -113,7 +113,7 @@ int usbd_interface_shutdown(struct usbd_contex *const uds_ctx, struct usbd_class_node *c_nd; SYS_SLIST_FOR_EACH_CONTAINER(&cfg_nd->class_list, c_nd, node) { - uint32_t *ep_bm = &c_nd->data->ep_active; + uint32_t *ep_bm = &c_nd->ep_active; for (int idx = 1; idx < 16 && *ep_bm; idx++) { uint8_t ep_in = USB_EP_DIR_IN | idx; @@ -140,6 +140,7 @@ int usbd_interface_shutdown(struct usbd_contex *const uds_ctx, } int usbd_interface_default(struct usbd_contex *const uds_ctx, + const enum usbd_speed speed, struct usbd_config_node *const cfg_nd) { struct usb_cfg_descriptor *desc = cfg_nd->desc; @@ -150,7 +151,7 @@ int usbd_interface_default(struct usbd_contex *const uds_ctx, struct usbd_class_node *class; int ret; - class = usbd_class_get_by_config(uds_ctx, new_cfg, i); + class = usbd_class_get_by_config(uds_ctx, speed, new_cfg, i); if (class == NULL) { return -ENODATA; } @@ -206,7 +207,7 @@ int usbd_interface_set(struct usbd_contex *const uds_ctx, return ret; } - usbd_class_update(class, iface, alt); + usbd_class_update(class->c_data, iface, alt); usbd_set_alt_value(uds_ctx, iface, alt); return 0; diff --git a/subsys/usb/device_next/usbd_interface.h b/subsys/usb/device_next/usbd_interface.h index e3355545057..bbeaf6f26f7 100644 --- a/subsys/usb/device_next/usbd_interface.h +++ b/subsys/usb/device_next/usbd_interface.h @@ -26,11 +26,13 @@ int usbd_interface_shutdown(struct usbd_contex *const uds_ctx, * @note Used only for configuration change. * * @param[in] uds_ctx Pointer to USB device support context + * @param[in] speed Configuration speed * @param[in] cfg_nd Pointer to configuration node * * @return 0 on success, other values on fail. */ int usbd_interface_default(struct usbd_contex *const uds_ctx, + const enum usbd_speed speed, struct usbd_config_node *const cfg_nd); /** diff --git a/subsys/usb/device_next/usbd_msg.c b/subsys/usb/device_next/usbd_msg.c index b9afb534fa1..b70b85928f4 100644 --- a/subsys/usb/device_next/usbd_msg.c +++ b/subsys/usb/device_next/usbd_msg.c @@ -6,8 +6,8 @@ #include #include -#include #include +#include #include #include "usbd_device.h" @@ -16,8 +16,9 @@ LOG_MODULE_REGISTER(usbd_msg, CONFIG_USBD_LOG_LEVEL); static void msg_work_handler(struct k_work *work); -static K_WORK_DEFINE(msg_work, msg_work_handler); -K_FIFO_DEFINE(msg_queue); +static K_WORK_DELAYABLE_DEFINE(msg_work, msg_work_handler); +static struct k_spinlock ml_lock; +static sys_slist_t msg_list; struct usbd_msg_pkt { sys_snode_t node; @@ -32,6 +33,7 @@ static inline void usbd_msg_pub(struct usbd_contex *const ctx, const struct usbd_msg msg) { struct usbd_msg_pkt *m_pkt; + k_spinlock_key_t key; if (k_mem_slab_alloc(&usbd_msg_slab, (void **)&m_pkt, K_NO_WAIT)) { LOG_DBG("Failed to allocate message memory"); @@ -41,24 +43,47 @@ static inline void usbd_msg_pub(struct usbd_contex *const ctx, m_pkt->ctx = ctx; m_pkt->msg = msg; - k_fifo_put(&msg_queue, m_pkt); - if (k_work_submit(&msg_work) < 0) { - __ASSERT(false, "Failed to submit work"); + key = k_spin_lock(&ml_lock); + sys_slist_append(&msg_list, &m_pkt->node); + k_spin_unlock(&ml_lock, key); + + if (k_work_schedule(&msg_work, K_NO_WAIT) < 0) { + __ASSERT(false, "Failed to schedule work"); } } static void msg_work_handler(struct k_work *work) { + struct k_work_delayable *dwork = k_work_delayable_from_work(work); struct usbd_msg_pkt *m_pkt; + k_spinlock_key_t key; + sys_snode_t *node; + + key = k_spin_lock(&ml_lock); + node = sys_slist_peek_head(&msg_list); + k_spin_unlock(&ml_lock, key); + + __ASSERT(node != NULL, "slist appears to be empty"); + m_pkt = SYS_SLIST_CONTAINER(node, m_pkt, node); + + if (!usbd_is_initialized(m_pkt->ctx)) { + LOG_DBG("USB device support is not yet initialized"); + (void)k_work_reschedule(dwork, K_MSEC(CONFIG_USBD_MSG_WORK_DELAY)); + return; + } + + key = k_spin_lock(&ml_lock); + node = sys_slist_get(&msg_list); + k_spin_unlock(&ml_lock, key); - m_pkt = k_fifo_get(&msg_queue, K_NO_WAIT); - if (m_pkt != NULL) { - m_pkt->ctx->msg_cb(&m_pkt->msg); + if (node != NULL) { + m_pkt = SYS_SLIST_CONTAINER(node, m_pkt, node); + m_pkt->ctx->msg_cb(m_pkt->ctx, &m_pkt->msg); k_mem_slab_free(&usbd_msg_slab, (void *)m_pkt); } - if (!k_fifo_is_empty(&msg_queue)) { - (void)k_work_submit(work); + if (!sys_slist_is_empty(&msg_list)) { + (void)k_work_schedule(dwork, K_NO_WAIT); } } diff --git a/subsys/usb/device_next/usbd_shell.c b/subsys/usb/device_next/usbd_shell.c index 22c903bb858..86e571177d7 100644 --- a/subsys/usb/device_next/usbd_shell.c +++ b/subsys/usb/device_next/usbd_shell.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Nordic Semiconductor ASA + * Copyright (c) 2022,2024 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -14,23 +14,46 @@ #include #include -const struct shell *ctx_shell; - -USBD_CONFIGURATION_DEFINE(config_baz, USB_SCD_REMOTE_WAKEUP, 200); -USBD_CONFIGURATION_DEFINE(config_foo, USB_SCD_SELF_POWERED, 200); - +/* Default configurations used in the shell context. */ +USBD_CONFIGURATION_DEFINE(config_1_fs, USB_SCD_REMOTE_WAKEUP, 200); +USBD_CONFIGURATION_DEFINE(config_1_hs, USB_SCD_REMOTE_WAKEUP, 200); +USBD_CONFIGURATION_DEFINE(config_2_fs, USB_SCD_SELF_POWERED, 200); +USBD_CONFIGURATION_DEFINE(config_2_hs, USB_SCD_SELF_POWERED, 200); + +static struct usbd_shell_config { + struct usbd_config_node *cfg_nd; + enum usbd_speed speed; + const char *name; +} sh_configs[] = { + {.cfg_nd = &config_1_fs, .speed = USBD_SPEED_FS, .name = "FS1",}, + {.cfg_nd = &config_1_hs, .speed = USBD_SPEED_HS, .name = "HS1",}, + {.cfg_nd = &config_2_fs, .speed = USBD_SPEED_FS, .name = "FS2",}, + {.cfg_nd = &config_2_hs, .speed = USBD_SPEED_HS, .name = "HS2",}, +}; + +static struct usbd_shell_speed { + enum usbd_speed speed; + const char *name; +} sh_speed[] = { + {.speed = USBD_SPEED_FS, .name = "fs",}, + {.speed = USBD_SPEED_HS, .name = "hs",}, +}; + +/* Default string descriptors used in the shell context. */ USBD_DESC_LANG_DEFINE(lang); USBD_DESC_MANUFACTURER_DEFINE(mfr, "ZEPHYR"); USBD_DESC_PRODUCT_DEFINE(product, "Zephyr USBD foobaz"); -USBD_DESC_SERIAL_NUMBER_DEFINE(sn, "0123456789ABCDEF"); +USBD_DESC_SERIAL_NUMBER_DEFINE(sn); +/* Default device descriptors and context used in the shell. */ USBD_DEVICE_DEFINE(sh_uds_ctx, DEVICE_DT_GET(DT_NODELABEL(zephyr_udc0)), 0x2fe3, 0xffff); static struct usbd_contex *my_uds_ctx = &sh_uds_ctx; +static enum usbd_speed current_cmd_speed = USBD_SPEED_FS; -int cmd_wakeup_request(const struct shell *sh, - size_t argc, char **argv) +static int cmd_wakeup_request(const struct shell *sh, + size_t argc, char **argv) { int err; @@ -50,17 +73,16 @@ static int cmd_register(const struct shell *sh, uint8_t cfg; int ret; - cfg = strtol(argv[2], NULL, 10); - ret = usbd_register_class(my_uds_ctx, argv[1], cfg); - + cfg = strtol(argv[3], NULL, 10); + ret = usbd_register_class(my_uds_ctx, argv[1], current_cmd_speed, cfg); if (ret) { shell_error(sh, - "dev: failed to add USB class %s to configuration %u", - argv[1], cfg); + "dev: failed to register USB class %s to configuration %s %u", + argv[1], argv[2], cfg); } else { shell_print(sh, - "dev: added USB class %s to configuration %u", - argv[1], cfg); + "dev: register USB class %s to configuration %s %u", + argv[1], argv[2], cfg); } return ret; @@ -72,23 +94,23 @@ static int cmd_unregister(const struct shell *sh, uint8_t cfg; int ret; - cfg = strtol(argv[2], NULL, 10); - ret = usbd_unregister_class(my_uds_ctx, argv[1], cfg); + cfg = strtol(argv[3], NULL, 10); + ret = usbd_unregister_class(my_uds_ctx, argv[1], current_cmd_speed, cfg); if (ret) { shell_error(sh, - "dev: failed to remove USB class %s from configuration %u", - argv[1], cfg); + "dev: failed to remove USB class %s from configuration %s %u", + argv[1], argv[2], cfg); } else { shell_print(sh, - "dev: removed USB class %s from configuration %u", - argv[1], cfg); + "dev: removed USB class %s from configuration %s %u", + argv[1], argv[2], cfg); } return ret; } -static int cmd_usbd_magic(const struct shell *sh, - size_t argc, char **argv) +static int cmd_usbd_default_strings(const struct shell *sh, + size_t argc, char **argv) { int err; @@ -98,52 +120,49 @@ static int cmd_usbd_magic(const struct shell *sh, err |= usbd_add_descriptor(my_uds_ctx, &sn); if (err) { - shell_error(sh, "dev: Failed to initialize descriptors, %d", err); + shell_error(sh, "dev: Failed to add default string descriptors, %d", err); + } else { + shell_print(sh, "dev: added default string descriptors"); } - err = usbd_add_configuration(my_uds_ctx, &config_foo); - if (err) { - shell_error(sh, "dev: Failed to add configuration"); - } + return err; +} + +static int register_classes(const struct shell *sh) +{ + int err; - if (IS_ENABLED(CONFIG_USBD_LOOPBACK_CLASS)) { - err = usbd_register_class(my_uds_ctx, "loopback_0", 1); + STRUCT_SECTION_FOREACH_ALTERNATE(usbd_class_fs, usbd_class_node, c_nd) { + err = usbd_register_class(my_uds_ctx, c_nd->c_data->name, + USBD_SPEED_FS, 1); if (err) { - shell_error(sh, "dev: Failed to add loopback_0 class"); + shell_error(sh, + "dev: failed to register FS %s (%d)", + c_nd->c_data->name, err); + return err; } - } - ctx_shell = sh; - err = usbd_init(my_uds_ctx); - if (err) { - shell_error(sh, "dev: Failed to initialize device support"); + shell_print(sh, "dev: register FS %s", c_nd->c_data->name); } - err = usbd_enable(my_uds_ctx); - if (err) { - shell_error(sh, "dev: Failed to enable device support"); + if (usbd_caps_speed(my_uds_ctx) != USBD_SPEED_HS) { + return 0; } - return err; -} - -static int cmd_usbd_defaults(const struct shell *sh, - size_t argc, char **argv) -{ - int err; - - err = usbd_add_descriptor(my_uds_ctx, &lang); - err |= usbd_add_descriptor(my_uds_ctx, &mfr); - err |= usbd_add_descriptor(my_uds_ctx, &product); - err |= usbd_add_descriptor(my_uds_ctx, &sn); + STRUCT_SECTION_FOREACH_ALTERNATE(usbd_class_hs, usbd_class_node, c_nd) { + err = usbd_register_class(my_uds_ctx, c_nd->c_data->name, + USBD_SPEED_HS, 1); + if (err) { + shell_error(sh, + "dev: failed to register HS %s (%d)", + c_nd->c_data->name, err); + return err; + } - if (err) { - shell_error(sh, "dev: Failed to initialize descriptors, %d", err); - } else { - shell_print(sh, "dev: USB descriptors initialized"); + shell_print(sh, "dev: register HS %s", c_nd->c_data->name); } - return err; + return 0; } static int cmd_usbd_init(const struct shell *sh, @@ -151,13 +170,12 @@ static int cmd_usbd_init(const struct shell *sh, { int err; - ctx_shell = sh; err = usbd_init(my_uds_ctx); if (err == -EALREADY) { shell_error(sh, "dev: USB already initialized"); } else if (err) { - shell_error(sh, "dev: Failed to initialize %d", err); + shell_error(sh, "dev: Failed to initialize device support (%d)", err); } else { shell_print(sh, "dev: USB initialized"); } @@ -165,6 +183,38 @@ static int cmd_usbd_init(const struct shell *sh, return err; } +static int cmd_usbd_default_config(const struct shell *sh, + size_t argc, char **argv) +{ + int err; + + err = cmd_usbd_default_strings(sh, 0, NULL); + if (err) { + return err; + } + + if (usbd_caps_speed(my_uds_ctx) == USBD_SPEED_HS) { + err = usbd_add_configuration(my_uds_ctx, USBD_SPEED_HS, &config_1_hs); + if (err) { + shell_error(sh, "dev: Failed to add HS configuration"); + return err; + } + } + + err = usbd_add_configuration(my_uds_ctx, USBD_SPEED_FS, &config_1_fs); + if (err) { + shell_error(sh, "dev: Failed to add FS configuration"); + return err; + } + + err = register_classes(sh); + if (err) { + return err; + } + + return cmd_usbd_init(sh, 0, NULL); +} + static int cmd_usbd_enable(const struct shell *sh, size_t argc, char **argv) { @@ -241,10 +291,12 @@ static int cmd_device_bcd(const struct shell *sh, size_t argc, uint16_t bcd; int ret; - bcd = strtol(argv[1], NULL, 16); - ret = usbd_device_set_bcd(my_uds_ctx, bcd); + bcd = strtol(argv[2], NULL, 16); + ret = usbd_device_set_bcd(my_uds_ctx, current_cmd_speed, bcd); if (ret) { shell_error(sh, "dev: failed to set device bcdUSB to %x", bcd); + } else { + shell_error(sh, "dev: set device bcdUSB to %x", bcd); } return ret; @@ -286,13 +338,17 @@ static int cmd_device_code_triple(const struct shell *sh, size_t argc, uint8_t class, subclass, protocol; int ret; - class = strtol(argv[1], NULL, 16); - subclass = strtol(argv[2], NULL, 16); - protocol = strtol(argv[3], NULL, 16); - ret = usbd_device_set_code_triple(my_uds_ctx, class, subclass, protocol); + class = strtol(argv[2], NULL, 16); + subclass = strtol(argv[3], NULL, 16); + protocol = strtol(argv[4], NULL, 16); + ret = usbd_device_set_code_triple(my_uds_ctx, current_cmd_speed, + class, subclass, protocol); if (ret) { shell_error(sh, "dev: failed to set device code triple to %x %x %x", class, subclass, protocol); + } else { + shell_error(sh, "dev: set device code triple to %x %x %x", + class, subclass, protocol); } return ret; @@ -301,94 +357,144 @@ static int cmd_device_code_triple(const struct shell *sh, size_t argc, static int cmd_config_add(const struct shell *sh, size_t argc, char *argv[]) { - uint8_t cfg; - int ret; - - cfg = strtol(argv[1], NULL, 10); - - if (cfg == 1) { - ret = usbd_add_configuration(my_uds_ctx, &config_foo); - } else if (cfg == 2) { - ret = usbd_add_configuration(my_uds_ctx, &config_baz); - } else { - shell_error(sh, "dev: Configuration %u not available", cfg); - return -EINVAL; + int ret = -EINVAL; + + for (unsigned int i = 0; i < ARRAY_SIZE(sh_configs); i++) { + if (!strcmp(argv[1], sh_configs[i].name)) { + ret = usbd_add_configuration(my_uds_ctx, + sh_configs[i].speed, + sh_configs[i].cfg_nd); + break; + } } if (ret) { - shell_error(sh, "dev: failed to add configuration %u", cfg); + shell_error(sh, "dev: failed to add configuration %s", argv[1]); } return ret; } -static int cmd_config_self(const struct shell *sh, size_t argc, - char *argv[]) +static int cmd_config_set_selfpowered(const struct shell *sh, const bool self, + size_t argc, char *argv[]) { - bool self; uint8_t cfg; int ret; - cfg = strtol(argv[1], NULL, 10); - if (!strcmp(argv[2], "yes")) { - self = true; - } else { - self = false; - } + cfg = strtol(argv[2], NULL, 10); - ret = usbd_config_attrib_self(my_uds_ctx, cfg, self); + ret = usbd_config_attrib_self(my_uds_ctx, current_cmd_speed, cfg, self); if (ret) { shell_error(sh, - "dev: failed to set attribute self powered to %u", + "dev: failed to set attribute Self-powered to %u", cfg); + } else { + shell_print(sh, + "dev: set configuration %u attribute Self-powered to %u", + cfg, self); } return ret; } -static int cmd_config_rwup(const struct shell *sh, size_t argc, - char *argv[]) +static int cmd_config_selfpowered(const struct shell *sh, + size_t argc, char *argv[]) +{ + return cmd_config_set_selfpowered(sh, true, argc, argv); +} + +static int cmd_config_buspowered(const struct shell *sh, + size_t argc, char *argv[]) +{ + return cmd_config_set_selfpowered(sh, false, argc, argv); +} + +static int cmd_config_rwup(const struct shell *sh, const bool rwup, + size_t argc, char *argv[]) { - bool rwup; uint8_t cfg; int ret; - cfg = strtol(argv[1], NULL, 10); - if (!strcmp(argv[2], "yes")) { - rwup = true; - } else { - rwup = false; - } + cfg = strtol(argv[2], NULL, 10); - ret = usbd_config_attrib_rwup(my_uds_ctx, cfg, rwup); + ret = usbd_config_attrib_rwup(my_uds_ctx, current_cmd_speed, cfg, rwup); if (ret) { shell_error(sh, - "dev: failed to set attribute remote wakeup to %x", - cfg); + "dev: failed set configuration %u Remote Wakeup to %u", + cfg, rwup); + } else { + shell_print(sh, + "dev: set configuration %u Remote Wakeup to %u", + cfg, rwup); } return ret; } +static int cmd_config_set_rwup(const struct shell *sh, + size_t argc, char *argv[]) +{ + return cmd_config_rwup(sh, true, argc, argv); +} + +static int cmd_config_clear_rwup(const struct shell *sh, + size_t argc, char *argv[]) +{ + return cmd_config_rwup(sh, false, argc, argv); +} + static int cmd_config_power(const struct shell *sh, size_t argc, char *argv[]) { + uint16_t power; uint8_t cfg; - uint8_t power; int ret; - cfg = strtol(argv[1], NULL, 10); - power = strtol(argv[1], NULL, 10); + cfg = strtol(argv[2], NULL, 10); + power = strtol(argv[3], NULL, 10); + + if (power > UINT8_MAX) { + power = UINT8_MAX; + shell_print(sh, "dev: limit bMaxPower value to %u", power); + } - ret = usbd_config_maxpower(my_uds_ctx, cfg, power); + ret = usbd_config_maxpower(my_uds_ctx, current_cmd_speed, cfg, power); if (ret) { - shell_error(sh, "dev: failed to set bMaxPower value to %u", cfg); + shell_error(sh, + "dev: failed to set configuration %u bMaxPower value to %u", + cfg, power); + } else { + shell_print(sh, + "dev: set configuration %u bMaxPower value to %u", + cfg, power); } return ret; } -static void class_node_name_lookup(size_t idx, struct shell_static_entry *entry) +static void configuration_speed(size_t idx, struct shell_static_entry *entry) +{ + size_t match_idx = 0; + + entry->syntax = NULL; + entry->handler = NULL; + entry->help = NULL; + entry->subcmd = NULL; + + for (unsigned int i = 0; i < ARRAY_SIZE(sh_speed); i++) { + if (match_idx == idx) { + entry->syntax = sh_speed[i].name; + current_cmd_speed = sh_speed[i].speed; + break; + } + + ++match_idx; + } +} + +SHELL_DYNAMIC_CMD_CREATE(dsub_config_speed, configuration_speed); + +static void configuration_lookup(size_t idx, struct shell_static_entry *entry) { size_t match_idx = 0; @@ -397,10 +503,32 @@ static void class_node_name_lookup(size_t idx, struct shell_static_entry *entry) entry->help = NULL; entry->subcmd = NULL; - STRUCT_SECTION_FOREACH(usbd_class_node, node) { - if ((node->name != NULL) && (strlen(node->name) != 0)) { + for (unsigned int i = 0; i < ARRAY_SIZE(sh_configs); i++) { + if (match_idx == idx) { + entry->syntax = sh_configs[i].name; + break; + } + + ++match_idx; + } +} + +SHELL_DYNAMIC_CMD_CREATE(dsub_config_name, configuration_lookup); + +static void class_node_name_lookup(size_t idx, struct shell_static_entry *entry) +{ + size_t match_idx = 0; + + entry->syntax = NULL; + entry->handler = NULL; + entry->help = NULL; + entry->subcmd = &dsub_config_speed; + + STRUCT_SECTION_FOREACH_ALTERNATE(usbd_class_fs, usbd_class_node, c_nd) { + if ((c_nd->c_data->name != NULL) && + (strlen(c_nd->c_data->name) != 0)) { if (match_idx == idx) { - entry->syntax = node->name; + entry->syntax = c_nd->c_data->name; break; } @@ -434,60 +562,87 @@ SHELL_DYNAMIC_CMD_CREATE(dsub_node_name, class_node_name_lookup); SHELL_DYNAMIC_CMD_CREATE(dsub_context_name, device_context_lookup); SHELL_STATIC_SUBCMD_SET_CREATE(device_cmds, - SHELL_CMD_ARG(bcd, NULL, "", - cmd_device_bcd, 2, 0), - SHELL_CMD_ARG(pid, NULL, "", + SHELL_CMD_ARG(pid, NULL, + " sets device Product ID", cmd_device_pid, 2, 0), - SHELL_CMD_ARG(vid, NULL, "", + SHELL_CMD_ARG(vid, NULL, + " sets device Vendor ID", cmd_device_vid, 2, 0), - SHELL_CMD_ARG(triple, NULL, " ", - cmd_device_code_triple, 4, 0), + SHELL_CMD_ARG(bcd, &dsub_config_speed, + " sets device release number", + cmd_device_bcd, 3, 0), + SHELL_CMD_ARG(triple, &dsub_config_speed, + " sets device code triple", + cmd_device_code_triple, 5, 0), SHELL_SUBCMD_SET_END ); SHELL_STATIC_SUBCMD_SET_CREATE(config_cmds, - SHELL_CMD_ARG(add, NULL, "", + SHELL_CMD_ARG(add, &dsub_config_name, + " adds one of the pre-defined configurations", cmd_config_add, 2, 0), - SHELL_CMD_ARG(power, NULL, " ", - cmd_config_power, 3, 0), - SHELL_CMD_ARG(rwup, NULL, " ", - cmd_config_rwup, 3, 0), - SHELL_CMD_ARG(self, NULL, " ", - cmd_config_self, 3, 0), + SHELL_CMD_ARG(power, &dsub_config_speed, + " sets the bMaxPower", + cmd_config_power, 4, 0), + SHELL_CMD_ARG(set-rwup, &dsub_config_speed, + " sets Remote Wakeup bit", + cmd_config_set_rwup, 3, 0), + SHELL_CMD_ARG(clear-rwup, &dsub_config_speed, + " clears Remote Wakeup bit", + cmd_config_clear_rwup, 3, 0), + SHELL_CMD_ARG(selfpowered, &dsub_config_speed, + " sets Self-power bit", + cmd_config_selfpowered, 3, 0), + SHELL_CMD_ARG(buspowered, &dsub_config_speed, + " clears Self-power bit", + cmd_config_buspowered, 3, 0), SHELL_SUBCMD_SET_END ); SHELL_STATIC_SUBCMD_SET_CREATE(class_cmds, - SHELL_CMD_ARG(add, &dsub_node_name, " ", - cmd_register, 3, 0), - SHELL_CMD_ARG(remove, &dsub_node_name, " ", - cmd_unregister, 3, 0), + SHELL_CMD_ARG(register, &dsub_node_name, + " registers class instance", + cmd_register, 4, 0), + SHELL_CMD_ARG(unregister, &dsub_node_name, + " unregisters class instance", + cmd_unregister, 4, 0), SHELL_SUBCMD_SET_END ); SHELL_STATIC_SUBCMD_SET_CREATE(sub_usbd_cmds, - SHELL_CMD_ARG(wakeup, NULL, "[none]", - cmd_wakeup_request, 1, 0), - SHELL_CMD_ARG(magic, NULL, "[none]", - cmd_usbd_magic, 1, 0), - SHELL_CMD_ARG(defaults, NULL, "[none]", - cmd_usbd_defaults, 1, 0), - SHELL_CMD_ARG(init, NULL, "[none]", + SHELL_CMD_ARG(defstr, NULL, + "[none] adds default string descriptors", + cmd_usbd_default_strings, 1, 0), + SHELL_CMD_ARG(defcfg, NULL, + "[none] initializes default configuration with all available classes", + cmd_usbd_default_config, 1, 0), + SHELL_CMD_ARG(init, NULL, + "[none] initializes USB device support", cmd_usbd_init, 1, 0), - SHELL_CMD_ARG(enable, NULL, "[none]", + SHELL_CMD_ARG(enable, NULL, + "[none] enables USB device support]", cmd_usbd_enable, 1, 0), - SHELL_CMD_ARG(disable, NULL, "[none]", + SHELL_CMD_ARG(disable, NULL, + "[none] disables USB device support", cmd_usbd_disable, 1, 0), - SHELL_CMD_ARG(shutdown, NULL, "[none]", + SHELL_CMD_ARG(shutdown, NULL, + "[none] shutdown USB device support", cmd_usbd_shutdown, 1, 0), - SHELL_CMD_ARG(select, &dsub_context_name, "", + SHELL_CMD_ARG(select, &dsub_context_name, + " selects context used by the shell", cmd_select, 2, 0), - SHELL_CMD_ARG(device, &device_cmds, "device commands", + SHELL_CMD_ARG(device, &device_cmds, + "device commands", NULL, 1, 0), - SHELL_CMD_ARG(config, &config_cmds, "configuration commands", + SHELL_CMD_ARG(config, &config_cmds, + "configuration commands", NULL, 1, 0), - SHELL_CMD_ARG(class, &class_cmds, "class commands", + SHELL_CMD_ARG(class, &class_cmds, + "class commands", NULL, 1, 0), + SHELL_CMD_ARG(wakeup, NULL, + "[none] signals remote wakeup", + cmd_wakeup_request, 1, 0), SHELL_SUBCMD_SET_END ); diff --git a/subsys/usb/host/usbh_data.ld b/subsys/usb/host/usbh_data.ld index f04fd236fca..193c63efc0e 100644 --- a/subsys/usb/host/usbh_data.ld +++ b/subsys/usb/host/usbh_data.ld @@ -1,4 +1,4 @@ #include -ITERABLE_SECTION_RAM(usbh_contex, 4) -ITERABLE_SECTION_RAM(usbh_class_data, 4) +ITERABLE_SECTION_RAM(usbh_contex, Z_LINK_ITERABLE_SUBALIGN) +ITERABLE_SECTION_RAM(usbh_class_data, Z_LINK_ITERABLE_SUBALIGN) diff --git a/subsys/usb/usb_c/usbc_pe_common.c b/subsys/usb/usb_c/usbc_pe_common.c index cc59cecbadc..de29264d5d5 100644 --- a/subsys/usb/usb_c/usbc_pe_common.c +++ b/subsys/usb/usb_c/usbc_pe_common.c @@ -1251,12 +1251,14 @@ static const struct smf_state pe_states[PE_STATE_COUNT] = { NULL, pe_sender_response_run, pe_sender_response_exit, + NULL, NULL), #ifdef CONFIG_USBC_CSM_SOURCE_ONLY [PE_SRC_HARD_RESET_PARENT] = SMF_CREATE_STATE( pe_src_hard_reset_parent_entry, pe_src_hard_reset_parent_run, pe_src_hard_reset_parent_exit, + NULL, NULL), #endif #ifdef CONFIG_USBC_CSM_SINK_ONLY @@ -1264,148 +1266,177 @@ static const struct smf_state pe_states[PE_STATE_COUNT] = { pe_snk_startup_entry, pe_snk_startup_run, NULL, + NULL, NULL), [PE_SNK_DISCOVERY] = SMF_CREATE_STATE( pe_snk_discovery_entry, pe_snk_discovery_run, NULL, + NULL, NULL), [PE_SNK_WAIT_FOR_CAPABILITIES] = SMF_CREATE_STATE( pe_snk_wait_for_capabilities_entry, pe_snk_wait_for_capabilities_run, pe_snk_wait_for_capabilities_exit, + NULL, NULL), [PE_SNK_EVALUATE_CAPABILITY] = SMF_CREATE_STATE( pe_snk_evaluate_capability_entry, NULL, NULL, + NULL, NULL), [PE_SNK_SELECT_CAPABILITY] = SMF_CREATE_STATE( pe_snk_select_capability_entry, pe_snk_select_capability_run, NULL, - &pe_states[PE_SENDER_RESPONSE_PARENT]), + &pe_states[PE_SENDER_RESPONSE_PARENT], + NULL), [PE_SNK_READY] = SMF_CREATE_STATE( pe_snk_ready_entry, pe_snk_ready_run, pe_snk_ready_exit, + NULL, NULL), [PE_SNK_HARD_RESET] = SMF_CREATE_STATE( pe_snk_hard_reset_entry, pe_snk_hard_reset_run, NULL, + NULL, NULL), [PE_SNK_TRANSITION_TO_DEFAULT] = SMF_CREATE_STATE( pe_snk_transition_to_default_entry, pe_snk_transition_to_default_run, NULL, + NULL, NULL), [PE_SNK_GIVE_SINK_CAP] = SMF_CREATE_STATE( pe_snk_give_sink_cap_entry, pe_snk_give_sink_cap_run, NULL, + NULL, NULL), [PE_SNK_GET_SOURCE_CAP] = SMF_CREATE_STATE( pe_snk_get_source_cap_entry, pe_snk_get_source_cap_run, NULL, - &pe_states[PE_SENDER_RESPONSE_PARENT]), + &pe_states[PE_SENDER_RESPONSE_PARENT], + NULL), [PE_SNK_TRANSITION_SINK] = SMF_CREATE_STATE( pe_snk_transition_sink_entry, pe_snk_transition_sink_run, pe_snk_transition_sink_exit, + NULL, NULL), #else [PE_SRC_STARTUP] = SMF_CREATE_STATE( pe_src_startup_entry, pe_src_startup_run, NULL, + NULL, NULL), [PE_SRC_DISCOVERY] = SMF_CREATE_STATE( pe_src_discovery_entry, pe_src_discovery_run, pe_src_discovery_exit, - &pe_states[PE_SENDER_RESPONSE_PARENT]), + &pe_states[PE_SENDER_RESPONSE_PARENT], + NULL), [PE_SRC_SEND_CAPABILITIES] = SMF_CREATE_STATE( pe_src_send_capabilities_entry, pe_src_send_capabilities_run, NULL, - &pe_states[PE_SENDER_RESPONSE_PARENT]), + &pe_states[PE_SENDER_RESPONSE_PARENT], + NULL), [PE_SRC_NEGOTIATE_CAPABILITY] = SMF_CREATE_STATE( pe_src_negotiate_capability_entry, NULL, NULL, + NULL, NULL), [PE_SRC_CAPABILITY_RESPONSE] = SMF_CREATE_STATE( pe_src_capability_response_entry, pe_src_capability_response_run, NULL, + NULL, NULL), [PE_SRC_TRANSITION_SUPPLY] = SMF_CREATE_STATE( pe_src_transition_supply_entry, pe_src_transition_supply_run, pe_src_transition_supply_exit, + NULL, NULL), [PE_SRC_READY] = SMF_CREATE_STATE( pe_src_ready_entry, pe_src_ready_run, pe_src_ready_exit, + NULL, NULL), [PE_SRC_TRANSITION_TO_DEFAULT] = SMF_CREATE_STATE( pe_src_transition_to_default_entry, pe_src_transition_to_default_run, pe_src_transition_to_default_exit, + NULL, NULL), [PE_SRC_HARD_RESET_RECEIVED] = SMF_CREATE_STATE( NULL, NULL, NULL, - &pe_states[PE_SRC_HARD_RESET_PARENT]), + &pe_states[PE_SRC_HARD_RESET_PARENT], + NULL), [PE_SRC_HARD_RESET] = SMF_CREATE_STATE( pe_src_hard_reset_entry, NULL, NULL, - &pe_states[PE_SRC_HARD_RESET_PARENT]), + &pe_states[PE_SRC_HARD_RESET_PARENT], + NULL), #endif [PE_GET_SINK_CAP] = SMF_CREATE_STATE( pe_get_sink_cap_entry, pe_get_sink_cap_run, NULL, - &pe_states[PE_SENDER_RESPONSE_PARENT]), + &pe_states[PE_SENDER_RESPONSE_PARENT], + NULL), [PE_SEND_SOFT_RESET] = SMF_CREATE_STATE( pe_send_soft_reset_entry, pe_send_soft_reset_run, NULL, - &pe_states[PE_SENDER_RESPONSE_PARENT]), + &pe_states[PE_SENDER_RESPONSE_PARENT], + NULL), [PE_SOFT_RESET] = SMF_CREATE_STATE( pe_soft_reset_entry, pe_soft_reset_run, NULL, + NULL, NULL), [PE_SEND_NOT_SUPPORTED] = SMF_CREATE_STATE( pe_send_not_supported_entry, pe_send_not_supported_run, NULL, + NULL, NULL), [PE_DRS_EVALUATE_SWAP] = SMF_CREATE_STATE( pe_drs_evaluate_swap_entry, pe_drs_evaluate_swap_run, NULL, + NULL, NULL), [PE_DRS_SEND_SWAP] = SMF_CREATE_STATE( pe_drs_send_swap_entry, pe_drs_send_swap_run, NULL, - &pe_states[PE_SENDER_RESPONSE_PARENT]), + &pe_states[PE_SENDER_RESPONSE_PARENT], + NULL), [PE_CHUNK_RECEIVED] = SMF_CREATE_STATE( pe_chunk_received_entry, pe_chunk_received_run, NULL, + NULL, NULL), [PE_SUSPEND] = SMF_CREATE_STATE( pe_suspend_entry, pe_suspend_run, NULL, + NULL, NULL), }; BUILD_ASSERT(ARRAY_SIZE(pe_states) == PE_STATE_COUNT); diff --git a/subsys/usb/usb_c/usbc_prl.c b/subsys/usb/usb_c/usbc_prl.c index ca0465bac6d..975709c7a24 100644 --- a/subsys/usb/usb_c/usbc_prl.c +++ b/subsys/usb/usb_c/usbc_prl.c @@ -1265,37 +1265,44 @@ static const struct smf_state prl_tx_states[PRL_TX_STATE_COUNT] = { prl_tx_phy_layer_reset_entry, NULL, NULL, + NULL, NULL), [PRL_TX_WAIT_FOR_MESSAGE_REQUEST] = SMF_CREATE_STATE( prl_tx_wait_for_message_request_entry, prl_tx_wait_for_message_request_run, NULL, + NULL, NULL), [PRL_TX_LAYER_RESET_FOR_TRANSMIT] = SMF_CREATE_STATE( prl_tx_layer_reset_for_transmit_entry, NULL, NULL, + NULL, NULL), [PRL_TX_WAIT_FOR_PHY_RESPONSE] = SMF_CREATE_STATE( prl_tx_wait_for_phy_response_entry, prl_tx_wait_for_phy_response_run, prl_tx_wait_for_phy_response_exit, + NULL, NULL), [PRL_TX_SUSPEND] = SMF_CREATE_STATE( prl_tx_suspend_entry, prl_tx_suspend_run, NULL, + NULL, NULL), #ifdef CONFIG_USBC_CSM_SINK_ONLY [PRL_TX_SNK_START_AMS] = SMF_CREATE_STATE( prl_tx_snk_start_ams_entry, prl_tx_snk_start_ams_run, NULL, + NULL, NULL), [PRL_TX_SNK_PENDING] = SMF_CREATE_STATE( prl_tx_snk_pending_entry, prl_tx_snk_pending_run, NULL, + NULL, NULL), #endif #ifdef CONFIG_USBC_CSM_SOURCE_ONLY @@ -1303,11 +1310,13 @@ static const struct smf_state prl_tx_states[PRL_TX_STATE_COUNT] = { prl_tx_src_source_tx_entry, prl_tx_src_source_tx_run, NULL, + NULL, NULL), [PRL_TX_SRC_PENDING] = SMF_CREATE_STATE( prl_tx_src_pending_entry, prl_tx_src_pending_run, prl_tx_src_pending_exit, + NULL, NULL), #endif }; @@ -1321,26 +1330,31 @@ static const struct smf_state prl_hr_states[PRL_HR_STATE_COUNT] = { prl_hr_wait_for_request_entry, prl_hr_wait_for_request_run, NULL, + NULL, NULL), [PRL_HR_RESET_LAYER] = SMF_CREATE_STATE( prl_hr_reset_layer_entry, NULL, NULL, + NULL, NULL), [PRL_HR_WAIT_FOR_PHY_HARD_RESET_COMPLETE] = SMF_CREATE_STATE( prl_hr_wait_for_phy_hard_reset_complete_entry, prl_hr_wait_for_phy_hard_reset_complete_run, prl_hr_wait_for_phy_hard_reset_complete_exit, + NULL, NULL), [PRL_HR_WAIT_FOR_PE_HARD_RESET_COMPLETE] = SMF_CREATE_STATE( prl_hr_wait_for_pe_hard_reset_complete_entry, prl_hr_wait_for_pe_hard_reset_complete_run, NULL, + NULL, NULL), [PRL_HR_SUSPEND] = SMF_CREATE_STATE( prl_hr_suspend_entry, prl_hr_suspend_run, NULL, + NULL, NULL), }; BUILD_ASSERT(ARRAY_SIZE(prl_hr_states) == PRL_HR_STATE_COUNT); diff --git a/subsys/usb/usb_c/usbc_tc_common.c b/subsys/usb/usb_c/usbc_tc_common.c index e4a58a24899..43d6c9899d3 100644 --- a/subsys/usb/usb_c/usbc_tc_common.c +++ b/subsys/usb/usb_c/usbc_tc_common.c @@ -326,18 +326,21 @@ static const struct smf_state tc_states[TC_STATE_COUNT] = { tc_cc_open_entry, NULL, NULL, + NULL, NULL), #ifdef CONFIG_USBC_CSM_SINK_ONLY [TC_CC_RD_SUPER_STATE] = SMF_CREATE_STATE( tc_cc_rd_entry, NULL, NULL, + NULL, NULL), #else [TC_CC_RP_SUPER_STATE] = SMF_CREATE_STATE( tc_cc_rp_entry, NULL, NULL, + NULL, NULL), #endif /* Normal States */ @@ -346,48 +349,57 @@ static const struct smf_state tc_states[TC_STATE_COUNT] = { tc_unattached_snk_entry, tc_unattached_snk_run, NULL, - &tc_states[TC_CC_RD_SUPER_STATE]), + &tc_states[TC_CC_RD_SUPER_STATE], + NULL), [TC_ATTACH_WAIT_SNK_STATE] = SMF_CREATE_STATE( tc_attach_wait_snk_entry, tc_attach_wait_snk_run, tc_attach_wait_snk_exit, - &tc_states[TC_CC_RD_SUPER_STATE]), + &tc_states[TC_CC_RD_SUPER_STATE], + NULL), [TC_ATTACHED_SNK_STATE] = SMF_CREATE_STATE( tc_attached_snk_entry, tc_attached_snk_run, tc_attached_snk_exit, + NULL, NULL), #else [TC_UNATTACHED_SRC_STATE] = SMF_CREATE_STATE( tc_unattached_src_entry, tc_unattached_src_run, NULL, - &tc_states[TC_CC_RP_SUPER_STATE]), + &tc_states[TC_CC_RP_SUPER_STATE], + NULL), [TC_UNATTACHED_WAIT_SRC_STATE] = SMF_CREATE_STATE( tc_unattached_wait_src_entry, tc_unattached_wait_src_run, tc_unattached_wait_src_exit, + NULL, NULL), [TC_ATTACH_WAIT_SRC_STATE] = SMF_CREATE_STATE( tc_attach_wait_src_entry, tc_attach_wait_src_run, tc_attach_wait_src_exit, - &tc_states[TC_CC_RP_SUPER_STATE]), + &tc_states[TC_CC_RP_SUPER_STATE], + NULL), [TC_ATTACHED_SRC_STATE] = SMF_CREATE_STATE( tc_attached_src_entry, tc_attached_src_run, tc_attached_src_exit, + NULL, NULL), #endif [TC_DISABLED_STATE] = SMF_CREATE_STATE( tc_disabled_entry, tc_disabled_run, NULL, - &tc_states[TC_CC_OPEN_SUPER_STATE]), + &tc_states[TC_CC_OPEN_SUPER_STATE], + NULL), [TC_ERROR_RECOVERY_STATE] = SMF_CREATE_STATE( tc_error_recovery_entry, tc_error_recovery_run, NULL, - &tc_states[TC_CC_OPEN_SUPER_STATE]), + &tc_states[TC_CC_OPEN_SUPER_STATE], + NULL), }; BUILD_ASSERT(ARRAY_SIZE(tc_states) == TC_STATE_COUNT); diff --git a/tests/arch/arm/arm_runtime_nmi/src/arm_runtime_nmi.c b/tests/arch/arm/arm_runtime_nmi/src/arm_runtime_nmi.c index 79a4bbedca3..87e4237d961 100644 --- a/tests/arch/arm/arm_runtime_nmi/src/arm_runtime_nmi.c +++ b/tests/arch/arm/arm_runtime_nmi/src/arm_runtime_nmi.c @@ -12,6 +12,7 @@ #include #include #include +#include /* on v8m arch the nmi pend bit is renamed to pend nmi map it to old name */ #ifndef SCB_ICSR_NMIPENDSET_Msk @@ -67,7 +68,7 @@ ZTEST(arm_runtime_nmi_fn, test_arm_runtime_nmi) #ifdef ARM_CACHEL1_ARMV7_H /* Flush Data Cache now if enabled */ if (IS_ENABLED(CONFIG_DCACHE)) { - SCB_CleanDCache(); + sys_cache_data_flush_all(); } #endif /* ARM_CACHEL1_ARMV7_H */ zassert_true(nmi_triggered, "Isr not triggered!\n"); diff --git a/tests/arch/common/stack_unwind/CMakeLists.txt b/tests/arch/common/stack_unwind/CMakeLists.txt new file mode 100644 index 00000000000..65858efd2fc --- /dev/null +++ b/tests/arch/common/stack_unwind/CMakeLists.txt @@ -0,0 +1,9 @@ +# Copyright (c) 2024 Meta +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(stack_unwind_test) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/tests/arch/common/stack_unwind/enable_fp.conf b/tests/arch/common/stack_unwind/enable_fp.conf new file mode 100644 index 00000000000..5348bd11370 --- /dev/null +++ b/tests/arch/common/stack_unwind/enable_fp.conf @@ -0,0 +1,2 @@ +CONFIG_OVERRIDE_FRAME_POINTER_DEFAULT=y +CONFIG_OMIT_FRAME_POINTER=n diff --git a/tests/arch/common/stack_unwind/prj.conf b/tests/arch/common/stack_unwind/prj.conf new file mode 100644 index 00000000000..8ac350b3c97 --- /dev/null +++ b/tests/arch/common/stack_unwind/prj.conf @@ -0,0 +1,8 @@ +CONFIG_TEST=y + +CONFIG_LOG=y +CONFIG_LOG_BUFFER_SIZE=2048 + +CONFIG_EXCEPTION_STACK_TRACE=y +CONFIG_DEBUG=y +CONFIG_DEBUG_INFO=y diff --git a/tests/arch/common/stack_unwind/src/main.c b/tests/arch/common/stack_unwind/src/main.c new file mode 100644 index 00000000000..04367129838 --- /dev/null +++ b/tests/arch/common/stack_unwind/src/main.c @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2024 Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include + +static void func1(int a); +static void func2(int a); + +static void func2(int a) +{ + printf("%d: %s\n", a, __func__); + + if (a >= 5) { + k_oops(); + } + + func1(a + 1); +} + +static void func1(int a) +{ + printf("%d: %s\n", a, __func__); + func2(a + 1); +} + +int main(void) +{ + printf("Hello World! %s\n", CONFIG_BOARD); + + func1(1); + + return 0; +} diff --git a/tests/arch/common/stack_unwind/testcase.yaml b/tests/arch/common/stack_unwind/testcase.yaml new file mode 100644 index 00000000000..9f29790f95c --- /dev/null +++ b/tests/arch/common/stack_unwind/testcase.yaml @@ -0,0 +1,52 @@ +common: + harness: console + ignore_faults: true + ignore_qemu_crash: true + tags: kernel +tests: + arch.common.stack_unwind.riscv_fp: + arch_allow: riscv + integration_platforms: + - qemu_riscv32 + - qemu_riscv64 + extra_args: OVERLAY_CONFIG="enable_fp.conf" + harness_config: + type: multi_line + regex: + - "E: call trace:" + - "E: 0: fp: \\w+ ra: \\w+" + - "E: 1: fp: \\w+ ra: \\w+" + arch.common.stack_unwind.riscv_sp: + arch_allow: riscv + integration_platforms: + - qemu_riscv32 + - qemu_riscv64 + harness_config: + type: multi_line + regex: + - "E: call trace:" + - "E: 0: sp: \\w+ ra: \\w+" + - "E: 1: sp: \\w+ ra: \\w+" + arch.common.stack_unwind.x86: + arch_allow: x86 + extra_configs: + - CONFIG_NO_OPTIMIZATIONS=y + integration_platforms: + - qemu_x86 + - qemu_x86_64 + harness_config: + type: multi_line + regex: + - "E: call trace:" + - "E: (E|R)IP: \\w+" + arch.common.stack_unwind.arm64: + arch_allow: + - arm64 + integration_platforms: + - qemu_cortex_a53 + extra_args: OVERLAY_CONFIG="enable_fp.conf" + harness_config: + type: multi_line + regex: + - "E: backtrace 0: fp: \\w+ lr: \\w+" + - "E: backtrace 1: fp: \\w+ lr: \\w+" diff --git a/tests/arch/riscv/fpu_sharing/src/main.c b/tests/arch/riscv/fpu_sharing/src/main.c index 55ab1a2e4a0..12bf20f5685 100644 --- a/tests/arch/riscv/fpu_sharing/src/main.c +++ b/tests/arch/riscv/fpu_sharing/src/main.c @@ -245,7 +245,7 @@ ZTEST(riscv_fpu_sharing, test_multi_thread_interaction) thread2_entry, NULL, NULL, NULL, -1, 0, K_NO_WAIT); zassert_true(k_thread_join(&thread1, K_FOREVER) == 0); - zassert_true(k_thread_join(&thread1, K_FOREVER) == 0); + zassert_true(k_thread_join(&thread2, K_FOREVER) == 0); } /* diff --git a/tests/arch/x86/nmi/src/main.c b/tests/arch/x86/nmi/src/main.c index 393d504c7dc..852e949c115 100644 --- a/tests/arch/x86/nmi/src/main.c +++ b/tests/arch/x86/nmi/src/main.c @@ -17,13 +17,13 @@ static volatile int int_handler_executed; -extern uint8_t z_x86_nmi_stack[]; +extern uint8_t z_x86_nmi_stack0[]; extern uint8_t z_x86_nmi_stack1[]; extern uint8_t z_x86_nmi_stack2[]; extern uint8_t z_x86_nmi_stack3[]; uint8_t *nmi_stacks[] = { - z_x86_nmi_stack, + z_x86_nmi_stack0, #if CONFIG_MP_MAX_NUM_CPUS > 1 z_x86_nmi_stack1, #if CONFIG_MP_MAX_NUM_CPUS > 2 diff --git a/tests/bluetooth/audio/ascs/prj.conf b/tests/bluetooth/audio/ascs/prj.conf index 714c9bde4df..2ed3485e335 100644 --- a/tests/bluetooth/audio/ascs/prj.conf +++ b/tests/bluetooth/audio/ascs/prj.conf @@ -2,6 +2,8 @@ CONFIG_ZTEST=y CONFIG_BT=y CONFIG_BT_MAX_CONN=1 +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_ISO_PERIPHERAL=y CONFIG_BT_ISO_MAX_CHAN=1 CONFIG_BT_AUDIO=y CONFIG_BT_ASCS=y diff --git a/tests/bluetooth/audio/cap_commander/prj.conf b/tests/bluetooth/audio/cap_commander/prj.conf index c281867619a..231fe10c2e1 100644 --- a/tests/bluetooth/audio/cap_commander/prj.conf +++ b/tests/bluetooth/audio/cap_commander/prj.conf @@ -15,7 +15,7 @@ CONFIG_BT_AICS_CLIENT_MAX_INSTANCE_COUNT=1 CONFIG_BT_MICP_MIC_CTLR_MAX_AICS_INST=1 CONFIG_BT_CAP_COMMANDER=y - +CONFIG_BT_BAP_BROADCAST_ASSISTANT=y CONFIG_LOG=y CONFIG_BT_CAP_COMMANDER_LOG_LEVEL_DBG=y diff --git a/tests/bluetooth/audio/cap_commander/uut/CMakeLists.txt b/tests/bluetooth/audio/cap_commander/uut/CMakeLists.txt index d1455879e57..007ea55fb9b 100644 --- a/tests/bluetooth/audio/cap_commander/uut/CMakeLists.txt +++ b/tests/bluetooth/audio/cap_commander/uut/CMakeLists.txt @@ -7,10 +7,14 @@ # add_library(uut STATIC + ${ZEPHYR_BASE}/subsys/bluetooth/audio/audio.c + ${ZEPHYR_BASE}/subsys/bluetooth/audio/bap_iso.c + ${ZEPHYR_BASE}/subsys/bluetooth/audio/bap_stream.c ${ZEPHYR_BASE}/subsys/bluetooth/audio/cap_commander.c ${ZEPHYR_BASE}/subsys/bluetooth/audio/cap_common.c ${ZEPHYR_BASE}/subsys/logging/log_minimal.c ${ZEPHYR_BASE}/subsys/net/buf_simple.c + bap_broadcast_assistant.c aics.c csip.c micp.c diff --git a/tests/bluetooth/audio/cap_commander/uut/bap_broadcast_assistant.c b/tests/bluetooth/audio/cap_commander/uut/bap_broadcast_assistant.c new file mode 100644 index 00000000000..e4ec106c8f6 --- /dev/null +++ b/tests/bluetooth/audio/cap_commander/uut/bap_broadcast_assistant.c @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "zephyr/bluetooth/audio/bap.h" + +static struct bt_bap_broadcast_assistant_cb *broadcast_assistant_cbs; + +int bt_bap_broadcast_assistant_register_cb(struct bt_bap_broadcast_assistant_cb *cb) +{ + broadcast_assistant_cbs = cb; + + return 0; +} + +int bt_bap_broadcast_assistant_add_src(struct bt_conn *conn, + const struct bt_bap_broadcast_assistant_add_src_param *param) +{ + /* Note that proper parameter checking is done in the caller */ + zassert_not_null(conn, "conn is NULL"); + zassert_not_null(param, "param is NULL"); + + if (broadcast_assistant_cbs->add_src != NULL) { + broadcast_assistant_cbs->add_src(conn, 0); + } + + return 0; +} diff --git a/tests/bluetooth/audio/cap_commander/uut/csip.c b/tests/bluetooth/audio/cap_commander/uut/csip.c index c6e910e8c0b..4fcf5b29504 100644 --- a/tests/bluetooth/audio/cap_commander/uut/csip.c +++ b/tests/bluetooth/audio/cap_commander/uut/csip.c @@ -52,6 +52,16 @@ int bt_csip_set_coordinator_discover(struct bt_conn *conn) return 0; } +struct bt_csip_set_coordinator_set_member * +bt_csip_set_coordinator_csis_member_by_conn(struct bt_conn *conn) +{ + if (conn == NULL) { + return NULL; + } + + return &member; +} + void mock_bt_csip_init(void) { } diff --git a/tests/bluetooth/audio/codec/prj.conf b/tests/bluetooth/audio/codec/prj.conf index 7701c36e5e3..0015890a012 100644 --- a/tests/bluetooth/audio/codec/prj.conf +++ b/tests/bluetooth/audio/codec/prj.conf @@ -1,8 +1,11 @@ CONFIG_ZTEST=y CONFIG_BT=y +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_ISO_PERIPHERAL=y CONFIG_BT_AUDIO=y CONFIG_BT_BAP_UNICAST_SERVER=y +CONFIG_BT_ASCS=y CONFIG_LOG=y CONFIG_BT_AUDIO_LOG_LEVEL_DBG=y diff --git a/tests/bluetooth/audio/mocks/include/cap_commander.h b/tests/bluetooth/audio/mocks/include/cap_commander.h index 1e56aca6930..6133ce2ae64 100644 --- a/tests/bluetooth/audio/mocks/include/cap_commander.h +++ b/tests/bluetooth/audio/mocks/include/cap_commander.h @@ -16,6 +16,7 @@ void mock_cap_commander_init(void); void mock_cap_commander_cleanup(void); DECLARE_FAKE_VOID_FUNC(mock_cap_commander_discovery_complete_cb, struct bt_conn *, int, + const struct bt_csip_set_coordinator_set_member *, const struct bt_csip_set_coordinator_csis_inst *); DECLARE_FAKE_VOID_FUNC(mock_cap_commander_volume_changed_cb, struct bt_conn *, int); DECLARE_FAKE_VOID_FUNC(mock_cap_commander_volume_mute_changed_cb, struct bt_conn *, int); diff --git a/tests/bluetooth/audio/mocks/src/cap_commander.c b/tests/bluetooth/audio/mocks/src/cap_commander.c index 4305f8e1b8e..c652de7946c 100644 --- a/tests/bluetooth/audio/mocks/src/cap_commander.c +++ b/tests/bluetooth/audio/mocks/src/cap_commander.c @@ -18,6 +18,7 @@ FAKE(mock_cap_commander_microphone_gain_changed_cb) DEFINE_FAKE_VOID_FUNC(mock_cap_commander_discovery_complete_cb, struct bt_conn *, int, + const struct bt_csip_set_coordinator_set_member *, const struct bt_csip_set_coordinator_csis_inst *); DEFINE_FAKE_VOID_FUNC(mock_cap_commander_volume_changed_cb, struct bt_conn *, int); diff --git a/tests/bluetooth/common/testlib/include/testlib/adv.h b/tests/bluetooth/common/testlib/include/testlib/adv.h index 2b326802b1c..6062fc2ad6a 100644 --- a/tests/bluetooth/common/testlib/include/testlib/adv.h +++ b/tests/bluetooth/common/testlib/include/testlib/adv.h @@ -7,6 +7,6 @@ #include -int bt_testlib_adv_conn(struct bt_conn **conn, int id, uint32_t adv_options); +int bt_testlib_adv_conn(struct bt_conn **conn, int id, const char *name); #endif /* ZEPHYR_TESTS_BLUETOOTH_COMMON_TESTLIB_INCLUDE_TESTLIB_ADV_H_ */ diff --git a/tests/bluetooth/common/testlib/src/adv.c b/tests/bluetooth/common/testlib/src/adv.c index e67d3bb6fe8..ba2a201199d 100644 --- a/tests/bluetooth/common/testlib/src/adv.c +++ b/tests/bluetooth/common/testlib/src/adv.c @@ -35,7 +35,7 @@ static void connected_cb(struct bt_le_ext_adv *adv, struct bt_le_ext_adv_connect k_mutex_unlock(&g_ctx_lock); } -int bt_testlib_adv_conn(struct bt_conn **conn, int id, uint32_t adv_options) +int bt_testlib_adv_conn(struct bt_conn **conn, int id, const char *name) { int api_err; struct bt_le_ext_adv *adv = NULL; @@ -51,7 +51,6 @@ int bt_testlib_adv_conn(struct bt_conn **conn, int id, uint32_t adv_options) param.interval_min = BT_GAP_ADV_FAST_INT_MIN_1; param.interval_max = BT_GAP_ADV_FAST_INT_MAX_1; param.options |= BT_LE_ADV_OPT_CONNECTABLE; - param.options |= adv_options; k_condvar_init(&ctx.done); @@ -60,6 +59,16 @@ int bt_testlib_adv_conn(struct bt_conn **conn, int id, uint32_t adv_options) g_ctx = &ctx; api_err = bt_le_ext_adv_create(¶m, &cb, &adv); + if (!api_err && name != NULL) { + struct bt_data ad; + + ad.type = BT_DATA_NAME_COMPLETE; + ad.data_len = strlen(name); + ad.data = (const uint8_t *)name; + + api_err = bt_le_ext_adv_set_data(adv, &ad, 1, NULL, 0); + } + if (!api_err) { api_err = bt_le_ext_adv_start(adv, BT_LE_EXT_ADV_START_DEFAULT); } diff --git a/tests/bluetooth/controller/common/src/helper_pdu.c b/tests/bluetooth/controller/common/src/helper_pdu.c index fe2af51bd67..7419de8fbce 100644 --- a/tests/bluetooth/controller/common/src/helper_pdu.c +++ b/tests/bluetooth/controller/common/src/helper_pdu.c @@ -406,7 +406,7 @@ void helper_pdu_encode_zero(struct pdu_data *pdu, void *param) void helper_node_encode_cte_rsp(struct node_rx_pdu *rx, void *param) { - rx->hdr.rx_ftr.iq_report = (struct cte_conn_iq_report *)param; + rx->rx_ftr.iq_report = (struct cte_conn_iq_report *)param; } void helper_pdu_encode_cis_req(struct pdu_data *pdu, void *param) @@ -1054,7 +1054,7 @@ void helper_node_verify_cte_rsp(const char *file, uint32_t line, struct node_rx_ void *param) { struct cte_conn_iq_report *p_iq_report = param; - struct cte_conn_iq_report *rx_iq_report = rx->hdr.rx_ftr.iq_report; + struct cte_conn_iq_report *rx_iq_report = rx->rx_ftr.iq_report; zassert_equal(rx_iq_report->cte_info.time, p_iq_report->cte_info.time, "CTE Time mismatch.\nCalled at %s:%d\n", file, line); diff --git a/tests/bluetooth/controller/ctrl_api/prj.conf b/tests/bluetooth/controller/ctrl_api/prj.conf index 7718b673947..a7d8ebfd28a 100644 --- a/tests/bluetooth/controller/ctrl_api/prj.conf +++ b/tests/bluetooth/controller/ctrl_api/prj.conf @@ -14,6 +14,8 @@ CONFIG_BT_LLL_VENDOR_NORDIC=y CONFIG_BT_CENTRAL=y CONFIG_BT_PERIPHERAL=y +CONFIG_BT_ISO_PERIPHERAL=y +CONFIG_BT_ISO_CENTRAL=y CONFIG_BT_CTLR_PERIPHERAL_ISO=y CONFIG_BT_CTLR_CENTRAL_ISO=y diff --git a/tests/bluetooth/controller/ctrl_api/src/main.c b/tests/bluetooth/controller/ctrl_api/src/main.c index 204abf20f03..1de1a319acf 100644 --- a/tests/bluetooth/controller/ctrl_api/src/main.c +++ b/tests/bluetooth/controller/ctrl_api/src/main.c @@ -464,7 +464,6 @@ ZTEST(internal, test_int_create_proc) zassert_not_null(ctx, NULL); zassert_equal(ctx->proc, PROC_VERSION_EXCHANGE); - zassert_equal(ctx->collision, 0); for (int i = 0U; i < CONFIG_BT_CTLR_LLCP_LOCAL_PROC_CTX_BUF_NUM; i++) { zassert_not_null(ctx, NULL); diff --git a/tests/bluetooth/controller/ctrl_chmu/prj.conf b/tests/bluetooth/controller/ctrl_chmu/prj.conf index 7718b673947..a7d8ebfd28a 100644 --- a/tests/bluetooth/controller/ctrl_chmu/prj.conf +++ b/tests/bluetooth/controller/ctrl_chmu/prj.conf @@ -14,6 +14,8 @@ CONFIG_BT_LLL_VENDOR_NORDIC=y CONFIG_BT_CENTRAL=y CONFIG_BT_PERIPHERAL=y +CONFIG_BT_ISO_PERIPHERAL=y +CONFIG_BT_ISO_CENTRAL=y CONFIG_BT_CTLR_PERIPHERAL_ISO=y CONFIG_BT_CTLR_CENTRAL_ISO=y diff --git a/tests/bluetooth/controller/ctrl_cis_create/prj.conf b/tests/bluetooth/controller/ctrl_cis_create/prj.conf index 7b2d389656b..3074f9f35d1 100644 --- a/tests/bluetooth/controller/ctrl_cis_create/prj.conf +++ b/tests/bluetooth/controller/ctrl_cis_create/prj.conf @@ -14,6 +14,8 @@ CONFIG_BT_LLL_VENDOR_NORDIC=y CONFIG_BT_CENTRAL=y CONFIG_BT_PERIPHERAL=y +CONFIG_BT_ISO_PERIPHERAL=y +CONFIG_BT_ISO_CENTRAL=y CONFIG_BT_CTLR_PERIPHERAL_ISO=y CONFIG_BT_CTLR_CENTRAL_ISO=y @@ -29,8 +31,6 @@ CONFIG_BT_CTLR_PHY_2M=y CONFIG_BT_CTLR_PHY_CODED=y CONFIG_BT_CTLR_ADV_EXT=y -CONFIG_BT_CTLR_ADV_ISO=y -CONFIG_BT_CTLR_SYNC_ISO=y CONFIG_BT_CTLR_CENTRAL_ISO=y CONFIG_BT_CTLR_PERIPHERAL_ISO=y diff --git a/tests/bluetooth/controller/ctrl_cis_create/src/main.c b/tests/bluetooth/controller/ctrl_cis_create/src/main.c index 54a8d742208..ba892586c60 100644 --- a/tests/bluetooth/controller/ctrl_cis_create/src/main.c +++ b/tests/bluetooth/controller/ctrl_cis_create/src/main.c @@ -272,7 +272,7 @@ ZTEST(cis_create, test_cc_create_periph_rem_host_accept) event_done(&conn); /* NODE_CIS_ESTABLISHED carry extra information in header rx footer param field */ - zassert_equal_ptr(ntf->hdr.rx_ftr.param, &cis_mock); + zassert_equal_ptr(ntf->rx_ftr.param, &cis_mock); zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(), "Free CTX buffers %d", llcp_ctx_buffers_free()); diff --git a/tests/bluetooth/controller/ctrl_cis_terminate/prj.conf b/tests/bluetooth/controller/ctrl_cis_terminate/prj.conf index 7b2d389656b..3074f9f35d1 100644 --- a/tests/bluetooth/controller/ctrl_cis_terminate/prj.conf +++ b/tests/bluetooth/controller/ctrl_cis_terminate/prj.conf @@ -14,6 +14,8 @@ CONFIG_BT_LLL_VENDOR_NORDIC=y CONFIG_BT_CENTRAL=y CONFIG_BT_PERIPHERAL=y +CONFIG_BT_ISO_PERIPHERAL=y +CONFIG_BT_ISO_CENTRAL=y CONFIG_BT_CTLR_PERIPHERAL_ISO=y CONFIG_BT_CTLR_CENTRAL_ISO=y @@ -29,8 +31,6 @@ CONFIG_BT_CTLR_PHY_2M=y CONFIG_BT_CTLR_PHY_CODED=y CONFIG_BT_CTLR_ADV_EXT=y -CONFIG_BT_CTLR_ADV_ISO=y -CONFIG_BT_CTLR_SYNC_ISO=y CONFIG_BT_CTLR_CENTRAL_ISO=y CONFIG_BT_CTLR_PERIPHERAL_ISO=y diff --git a/tests/bluetooth/controller/ctrl_collision/prj.conf b/tests/bluetooth/controller/ctrl_collision/prj.conf index 7718b673947..a7d8ebfd28a 100644 --- a/tests/bluetooth/controller/ctrl_collision/prj.conf +++ b/tests/bluetooth/controller/ctrl_collision/prj.conf @@ -14,6 +14,8 @@ CONFIG_BT_LLL_VENDOR_NORDIC=y CONFIG_BT_CENTRAL=y CONFIG_BT_PERIPHERAL=y +CONFIG_BT_ISO_PERIPHERAL=y +CONFIG_BT_ISO_CENTRAL=y CONFIG_BT_CTLR_PERIPHERAL_ISO=y CONFIG_BT_CTLR_CENTRAL_ISO=y diff --git a/tests/bluetooth/controller/ctrl_conn_update/prj.conf b/tests/bluetooth/controller/ctrl_conn_update/prj.conf index 6026d874f22..2b392fdf13d 100644 --- a/tests/bluetooth/controller/ctrl_conn_update/prj.conf +++ b/tests/bluetooth/controller/ctrl_conn_update/prj.conf @@ -14,6 +14,8 @@ CONFIG_BT_LLL_VENDOR_NORDIC=y CONFIG_BT_CENTRAL=y CONFIG_BT_PERIPHERAL=y +CONFIG_BT_ISO_PERIPHERAL=y +CONFIG_BT_ISO_CENTRAL=y CONFIG_BT_CTLR_PERIPHERAL_ISO=y CONFIG_BT_CTLR_CENTRAL_ISO=y CONFIG_BT_CTLR_CONN_PARAM_REQ=y diff --git a/tests/bluetooth/controller/ctrl_conn_update/prj_apm.conf b/tests/bluetooth/controller/ctrl_conn_update/prj_apm.conf index 5827974497f..dcaecf5050c 100644 --- a/tests/bluetooth/controller/ctrl_conn_update/prj_apm.conf +++ b/tests/bluetooth/controller/ctrl_conn_update/prj_apm.conf @@ -14,6 +14,8 @@ CONFIG_BT_LLL_VENDOR_NORDIC=y CONFIG_BT_CENTRAL=y CONFIG_BT_PERIPHERAL=y +CONFIG_BT_ISO_PERIPHERAL=y +CONFIG_BT_ISO_CENTRAL=y CONFIG_BT_CTLR_PERIPHERAL_ISO=y CONFIG_BT_CTLR_CENTRAL_ISO=y CONFIG_BT_CTLR_CONN_PARAM_REQ=y diff --git a/tests/bluetooth/controller/ctrl_conn_update/prj_no_param_req.conf b/tests/bluetooth/controller/ctrl_conn_update/prj_no_param_req.conf index 7c90aa769a1..6278afaffb1 100644 --- a/tests/bluetooth/controller/ctrl_conn_update/prj_no_param_req.conf +++ b/tests/bluetooth/controller/ctrl_conn_update/prj_no_param_req.conf @@ -14,6 +14,8 @@ CONFIG_BT_LLL_VENDOR_NORDIC=y CONFIG_BT_CENTRAL=y CONFIG_BT_PERIPHERAL=y +CONFIG_BT_ISO_PERIPHERAL=y +CONFIG_BT_ISO_CENTRAL=y CONFIG_BT_CTLR_PERIPHERAL_ISO=y CONFIG_BT_CTLR_CENTRAL_ISO=y CONFIG_BT_CTLR_CONN_PARAM_REQ=n diff --git a/tests/bluetooth/controller/ctrl_cte_req/prj.conf b/tests/bluetooth/controller/ctrl_cte_req/prj.conf index 8941e79bc4f..0d521c3e75e 100644 --- a/tests/bluetooth/controller/ctrl_cte_req/prj.conf +++ b/tests/bluetooth/controller/ctrl_cte_req/prj.conf @@ -17,6 +17,8 @@ CONFIG_BT_LLL_VENDOR_NORDIC=y CONFIG_BT_CENTRAL=y CONFIG_BT_PERIPHERAL=y +CONFIG_BT_ISO_PERIPHERAL=y +CONFIG_BT_ISO_CENTRAL=y CONFIG_BT_CTLR_PERIPHERAL_ISO=y CONFIG_BT_CTLR_CENTRAL_ISO=y diff --git a/tests/bluetooth/controller/ctrl_data_length_update/prj.conf b/tests/bluetooth/controller/ctrl_data_length_update/prj.conf index 09d9cd9bab9..be14c4efa44 100644 --- a/tests/bluetooth/controller/ctrl_data_length_update/prj.conf +++ b/tests/bluetooth/controller/ctrl_data_length_update/prj.conf @@ -14,6 +14,8 @@ CONFIG_BT_LLL_VENDOR_NORDIC=y CONFIG_BT_CENTRAL=y CONFIG_BT_PERIPHERAL=y +CONFIG_BT_ISO_PERIPHERAL=y +CONFIG_BT_ISO_CENTRAL=y CONFIG_BT_CTLR_PERIPHERAL_ISO=y CONFIG_BT_CTLR_CENTRAL_ISO=y diff --git a/tests/bluetooth/controller/ctrl_data_length_update/prj_nocoded.conf b/tests/bluetooth/controller/ctrl_data_length_update/prj_nocoded.conf index dcfc2eded1d..e27ad98dad8 100644 --- a/tests/bluetooth/controller/ctrl_data_length_update/prj_nocoded.conf +++ b/tests/bluetooth/controller/ctrl_data_length_update/prj_nocoded.conf @@ -14,6 +14,8 @@ CONFIG_BT_LLL_VENDOR_NORDIC=y CONFIG_BT_CENTRAL=y CONFIG_BT_PERIPHERAL=y +CONFIG_BT_ISO_PERIPHERAL=y +CONFIG_BT_ISO_CENTRAL=y CONFIG_BT_CTLR_PERIPHERAL_ISO=y CONFIG_BT_CTLR_CENTRAL_ISO=y diff --git a/tests/bluetooth/controller/ctrl_data_length_update/prj_nophy.conf b/tests/bluetooth/controller/ctrl_data_length_update/prj_nophy.conf index 115ad42a41a..85708da1320 100644 --- a/tests/bluetooth/controller/ctrl_data_length_update/prj_nophy.conf +++ b/tests/bluetooth/controller/ctrl_data_length_update/prj_nophy.conf @@ -14,6 +14,8 @@ CONFIG_BT_LLL_VENDOR_NORDIC=y CONFIG_BT_CENTRAL=y CONFIG_BT_PERIPHERAL=y +CONFIG_BT_ISO_PERIPHERAL=y +CONFIG_BT_ISO_CENTRAL=y CONFIG_BT_CTLR_PERIPHERAL_ISO=y CONFIG_BT_CTLR_CENTRAL_ISO=y diff --git a/tests/bluetooth/controller/ctrl_encrypt/prj.conf b/tests/bluetooth/controller/ctrl_encrypt/prj.conf index 09d9cd9bab9..be14c4efa44 100644 --- a/tests/bluetooth/controller/ctrl_encrypt/prj.conf +++ b/tests/bluetooth/controller/ctrl_encrypt/prj.conf @@ -14,6 +14,8 @@ CONFIG_BT_LLL_VENDOR_NORDIC=y CONFIG_BT_CENTRAL=y CONFIG_BT_PERIPHERAL=y +CONFIG_BT_ISO_PERIPHERAL=y +CONFIG_BT_ISO_CENTRAL=y CONFIG_BT_CTLR_PERIPHERAL_ISO=y CONFIG_BT_CTLR_CENTRAL_ISO=y diff --git a/tests/bluetooth/controller/ctrl_feature_exchange/prj.conf b/tests/bluetooth/controller/ctrl_feature_exchange/prj.conf index 7718b673947..a7d8ebfd28a 100644 --- a/tests/bluetooth/controller/ctrl_feature_exchange/prj.conf +++ b/tests/bluetooth/controller/ctrl_feature_exchange/prj.conf @@ -14,6 +14,8 @@ CONFIG_BT_LLL_VENDOR_NORDIC=y CONFIG_BT_CENTRAL=y CONFIG_BT_PERIPHERAL=y +CONFIG_BT_ISO_PERIPHERAL=y +CONFIG_BT_ISO_CENTRAL=y CONFIG_BT_CTLR_PERIPHERAL_ISO=y CONFIG_BT_CTLR_CENTRAL_ISO=y diff --git a/tests/bluetooth/controller/ctrl_hci/prj.conf b/tests/bluetooth/controller/ctrl_hci/prj.conf index 5f5a1abb057..89c01eed822 100644 --- a/tests/bluetooth/controller/ctrl_hci/prj.conf +++ b/tests/bluetooth/controller/ctrl_hci/prj.conf @@ -14,6 +14,8 @@ CONFIG_BT_LLL_VENDOR_NORDIC=y CONFIG_BT_CENTRAL=y CONFIG_BT_PERIPHERAL=y +CONFIG_BT_ISO_PERIPHERAL=y +CONFIG_BT_ISO_CENTRAL=y CONFIG_BT_CTLR_PERIPHERAL_ISO=y CONFIG_BT_CTLR_CENTRAL_ISO=y CONFIG_BT_MAX_CONN=4 diff --git a/tests/bluetooth/controller/ctrl_invalid/prj.conf b/tests/bluetooth/controller/ctrl_invalid/prj.conf index 09d9cd9bab9..be14c4efa44 100644 --- a/tests/bluetooth/controller/ctrl_invalid/prj.conf +++ b/tests/bluetooth/controller/ctrl_invalid/prj.conf @@ -14,6 +14,8 @@ CONFIG_BT_LLL_VENDOR_NORDIC=y CONFIG_BT_CENTRAL=y CONFIG_BT_PERIPHERAL=y +CONFIG_BT_ISO_PERIPHERAL=y +CONFIG_BT_ISO_CENTRAL=y CONFIG_BT_CTLR_PERIPHERAL_ISO=y CONFIG_BT_CTLR_CENTRAL_ISO=y diff --git a/tests/bluetooth/controller/ctrl_le_ping/prj.conf b/tests/bluetooth/controller/ctrl_le_ping/prj.conf index 09d9cd9bab9..be14c4efa44 100644 --- a/tests/bluetooth/controller/ctrl_le_ping/prj.conf +++ b/tests/bluetooth/controller/ctrl_le_ping/prj.conf @@ -14,6 +14,8 @@ CONFIG_BT_LLL_VENDOR_NORDIC=y CONFIG_BT_CENTRAL=y CONFIG_BT_PERIPHERAL=y +CONFIG_BT_ISO_PERIPHERAL=y +CONFIG_BT_ISO_CENTRAL=y CONFIG_BT_CTLR_PERIPHERAL_ISO=y CONFIG_BT_CTLR_CENTRAL_ISO=y diff --git a/tests/bluetooth/controller/ctrl_min_used_chans/prj.conf b/tests/bluetooth/controller/ctrl_min_used_chans/prj.conf index 09d9cd9bab9..be14c4efa44 100644 --- a/tests/bluetooth/controller/ctrl_min_used_chans/prj.conf +++ b/tests/bluetooth/controller/ctrl_min_used_chans/prj.conf @@ -14,6 +14,8 @@ CONFIG_BT_LLL_VENDOR_NORDIC=y CONFIG_BT_CENTRAL=y CONFIG_BT_PERIPHERAL=y +CONFIG_BT_ISO_PERIPHERAL=y +CONFIG_BT_ISO_CENTRAL=y CONFIG_BT_CTLR_PERIPHERAL_ISO=y CONFIG_BT_CTLR_CENTRAL_ISO=y diff --git a/tests/bluetooth/controller/ctrl_phy_update/prj.conf b/tests/bluetooth/controller/ctrl_phy_update/prj.conf index 09d9cd9bab9..be14c4efa44 100644 --- a/tests/bluetooth/controller/ctrl_phy_update/prj.conf +++ b/tests/bluetooth/controller/ctrl_phy_update/prj.conf @@ -14,6 +14,8 @@ CONFIG_BT_LLL_VENDOR_NORDIC=y CONFIG_BT_CENTRAL=y CONFIG_BT_PERIPHERAL=y +CONFIG_BT_ISO_PERIPHERAL=y +CONFIG_BT_ISO_CENTRAL=y CONFIG_BT_CTLR_PERIPHERAL_ISO=y CONFIG_BT_CTLR_CENTRAL_ISO=y diff --git a/tests/bluetooth/controller/ctrl_phy_update/prj_rx_cnt.conf b/tests/bluetooth/controller/ctrl_phy_update/prj_rx_cnt.conf index 20d9e982e95..3ad2c76bc78 100644 --- a/tests/bluetooth/controller/ctrl_phy_update/prj_rx_cnt.conf +++ b/tests/bluetooth/controller/ctrl_phy_update/prj_rx_cnt.conf @@ -14,6 +14,8 @@ CONFIG_BT_LLL_VENDOR_NORDIC=y CONFIG_BT_CENTRAL=y CONFIG_BT_PERIPHERAL=y +CONFIG_BT_ISO_PERIPHERAL=y +CONFIG_BT_ISO_CENTRAL=y CONFIG_BT_CTLR_PERIPHERAL_ISO=y CONFIG_BT_CTLR_CENTRAL_ISO=y diff --git a/tests/bluetooth/controller/ctrl_phy_update/src/main.c b/tests/bluetooth/controller/ctrl_phy_update/src/main.c index 8101149bd1b..5951b685932 100644 --- a/tests/bluetooth/controller/ctrl_phy_update/src/main.c +++ b/tests/bluetooth/controller/ctrl_phy_update/src/main.c @@ -585,6 +585,95 @@ ZTEST(phy_periph, test_phy_update_periph_loc) "Free CTX buffers %d", llcp_ctx_buffers_free()); } +ZTEST(phy_periph, test_phy_update_periph_loc_invalid_central) +{ + uint8_t err; + struct node_tx *tx; + struct node_rx_pdu *ntf; + struct pdu_data_llctrl_phy_req req = { .rx_phys = PHY_2M, .tx_phys = PHY_2M }; + uint16_t instant; + struct pdu_data_llctrl_conn_param_req conn_param_req = { }; + + struct node_rx_pu pu = { .status = BT_HCI_ERR_SUCCESS }; + + struct pdu_data_llctrl_phy_upd_ind phy_update_ind = { .c_to_p_phy = PHY_2M, + .p_to_c_phy = PHY_2M }; + + /* Role */ + test_set_role(&conn, BT_HCI_ROLE_PERIPHERAL); + + /* Connect */ + ull_cp_state_set(&conn, ULL_CP_CONNECTED); + + /* Initiate an PHY Update Procedure */ + err = ull_cp_phy_update(&conn, PHY_2M, PREFER_S8_CODING, PHY_2M, HOST_INITIATED); + zassert_equal(err, BT_HCI_ERR_SUCCESS); + + /* Prepare */ + event_prepare(&conn); + + /* Tx Queue should have one LL Control PDU */ + lt_rx(LL_PHY_REQ, &conn, &tx, &req); + lt_rx_q_is_empty(&conn); + + /* Check that data tx was paused */ + zassert_equal(conn.tx_q.pause_data, 1U, "Data tx is not paused"); + + /* TX Ack */ + event_tx_ack(&conn, tx); + + /* Check that data tx is no longer paused */ + zassert_equal(conn.tx_q.pause_data, 0U, "Data tx is paused"); + + /* Done */ + event_done(&conn); + + /* Release Tx */ + ull_cp_release_tx(&conn, tx); + + /* Prepare */ + event_prepare(&conn); + + /* Tx Queue should NOT have a LL Control PDU */ + lt_rx_q_is_empty(&conn); + + /* Rx */ + phy_update_ind.instant = instant = event_counter(&conn) + 6; + lt_tx(LL_PHY_UPDATE_IND, &conn, &phy_update_ind); + + /* Done */ + event_done(&conn); + + /* Check that data tx is no longer paused */ + zassert_equal(conn.tx_q.pause_data, 0U, "Data tx is paused"); + + /* One event ahead */ + /* Prepare */ + event_prepare(&conn); + + /* Tx Queue should NOT have a LL Control PDU */ + lt_rx_q_is_empty(&conn); + + /* Done */ + event_done(&conn); + + /* There should NOT be a host notification */ + ut_rx_q_is_empty(); + + /* 'Inject' invalid param request from central */ + /* Prepare */ + event_prepare(&conn); + /* Rx */ + lt_tx(LL_CONNECTION_PARAM_REQ, &conn, &conn_param_req); + + /* Done */ + event_done(&conn); + + /* Termination 'triggered' */ + zassert_equal(conn.llcp_terminate.reason_final, BT_HCI_ERR_DIFF_TRANS_COLLISION, + "Terminate reason %d", conn.llcp_terminate.reason_final); +} + ZTEST(phy_periph, test_phy_update_periph_rem) { struct node_tx *tx; diff --git a/tests/bluetooth/controller/ctrl_sca_update/prj.conf b/tests/bluetooth/controller/ctrl_sca_update/prj.conf index 09d9cd9bab9..be14c4efa44 100644 --- a/tests/bluetooth/controller/ctrl_sca_update/prj.conf +++ b/tests/bluetooth/controller/ctrl_sca_update/prj.conf @@ -14,6 +14,8 @@ CONFIG_BT_LLL_VENDOR_NORDIC=y CONFIG_BT_CENTRAL=y CONFIG_BT_PERIPHERAL=y +CONFIG_BT_ISO_PERIPHERAL=y +CONFIG_BT_ISO_CENTRAL=y CONFIG_BT_CTLR_PERIPHERAL_ISO=y CONFIG_BT_CTLR_CENTRAL_ISO=y diff --git a/tests/bluetooth/controller/ctrl_terminate/prj.conf b/tests/bluetooth/controller/ctrl_terminate/prj.conf index 09d9cd9bab9..be14c4efa44 100644 --- a/tests/bluetooth/controller/ctrl_terminate/prj.conf +++ b/tests/bluetooth/controller/ctrl_terminate/prj.conf @@ -14,6 +14,8 @@ CONFIG_BT_LLL_VENDOR_NORDIC=y CONFIG_BT_CENTRAL=y CONFIG_BT_PERIPHERAL=y +CONFIG_BT_ISO_PERIPHERAL=y +CONFIG_BT_ISO_CENTRAL=y CONFIG_BT_CTLR_PERIPHERAL_ISO=y CONFIG_BT_CTLR_CENTRAL_ISO=y diff --git a/tests/bluetooth/controller/ctrl_tx_buffer_alloc/prj.conf b/tests/bluetooth/controller/ctrl_tx_buffer_alloc/prj.conf index e3a1f8d893b..a10bddb77fe 100644 --- a/tests/bluetooth/controller/ctrl_tx_buffer_alloc/prj.conf +++ b/tests/bluetooth/controller/ctrl_tx_buffer_alloc/prj.conf @@ -15,6 +15,8 @@ CONFIG_BT_LLL_VENDOR_NORDIC=y CONFIG_BT_MAX_CONN=4 CONFIG_BT_CENTRAL=y CONFIG_BT_PERIPHERAL=y +CONFIG_BT_ISO_PERIPHERAL=y +CONFIG_BT_ISO_CENTRAL=y CONFIG_BT_CTLR_PERIPHERAL_ISO=y CONFIG_BT_CTLR_CENTRAL_ISO=y diff --git a/tests/bluetooth/controller/ctrl_tx_buffer_alloc/prj_1.conf b/tests/bluetooth/controller/ctrl_tx_buffer_alloc/prj_1.conf index de0e26455ee..7c8cc3db039 100644 --- a/tests/bluetooth/controller/ctrl_tx_buffer_alloc/prj_1.conf +++ b/tests/bluetooth/controller/ctrl_tx_buffer_alloc/prj_1.conf @@ -15,6 +15,8 @@ CONFIG_BT_LLL_VENDOR_NORDIC=y CONFIG_BT_MAX_CONN=4 CONFIG_BT_CENTRAL=y CONFIG_BT_PERIPHERAL=y +CONFIG_BT_ISO_PERIPHERAL=y +CONFIG_BT_ISO_CENTRAL=y CONFIG_BT_CTLR_PERIPHERAL_ISO=y CONFIG_BT_CTLR_CENTRAL_ISO=y diff --git a/tests/bluetooth/controller/ctrl_tx_buffer_alloc/prj_2.conf b/tests/bluetooth/controller/ctrl_tx_buffer_alloc/prj_2.conf index 46650448d02..5172998ddd4 100644 --- a/tests/bluetooth/controller/ctrl_tx_buffer_alloc/prj_2.conf +++ b/tests/bluetooth/controller/ctrl_tx_buffer_alloc/prj_2.conf @@ -14,6 +14,8 @@ CONFIG_BT_LLL_VENDOR_NORDIC=y CONFIG_BT_CENTRAL=y CONFIG_BT_PERIPHERAL=y +CONFIG_BT_ISO_PERIPHERAL=y +CONFIG_BT_ISO_CENTRAL=y CONFIG_BT_CTLR_PERIPHERAL_ISO=y CONFIG_BT_CTLR_CENTRAL_ISO=y diff --git a/tests/bluetooth/controller/ctrl_tx_buffer_alloc/prj_3.conf b/tests/bluetooth/controller/ctrl_tx_buffer_alloc/prj_3.conf index b829cf265e4..78ca4237124 100644 --- a/tests/bluetooth/controller/ctrl_tx_buffer_alloc/prj_3.conf +++ b/tests/bluetooth/controller/ctrl_tx_buffer_alloc/prj_3.conf @@ -15,6 +15,8 @@ CONFIG_BT_LLL_VENDOR_NORDIC=y CONFIG_BT_MAX_CONN=4 CONFIG_BT_CENTRAL=y CONFIG_BT_PERIPHERAL=y +CONFIG_BT_ISO_PERIPHERAL=y +CONFIG_BT_ISO_CENTRAL=y CONFIG_BT_CTLR_PERIPHERAL_ISO=y CONFIG_BT_CTLR_CENTRAL_ISO=y diff --git a/tests/bluetooth/controller/ctrl_tx_buffer_alloc/prj_max.conf b/tests/bluetooth/controller/ctrl_tx_buffer_alloc/prj_max.conf index c01ee28211d..f6ecf7bb959 100644 --- a/tests/bluetooth/controller/ctrl_tx_buffer_alloc/prj_max.conf +++ b/tests/bluetooth/controller/ctrl_tx_buffer_alloc/prj_max.conf @@ -15,6 +15,8 @@ CONFIG_BT_LLL_VENDOR_NORDIC=y CONFIG_BT_MAX_CONN=4 CONFIG_BT_CENTRAL=y CONFIG_BT_PERIPHERAL=y +CONFIG_BT_ISO_PERIPHERAL=y +CONFIG_BT_ISO_CENTRAL=y CONFIG_BT_CTLR_PERIPHERAL_ISO=y CONFIG_BT_CTLR_CENTRAL_ISO=y diff --git a/tests/bluetooth/controller/ctrl_tx_buffer_alloc/prj_max_common.conf b/tests/bluetooth/controller/ctrl_tx_buffer_alloc/prj_max_common.conf index 7b83d2d6a12..56b7f7a3bef 100644 --- a/tests/bluetooth/controller/ctrl_tx_buffer_alloc/prj_max_common.conf +++ b/tests/bluetooth/controller/ctrl_tx_buffer_alloc/prj_max_common.conf @@ -14,6 +14,8 @@ CONFIG_BT_LLL_VENDOR_NORDIC=y CONFIG_BT_CENTRAL=y CONFIG_BT_PERIPHERAL=y +CONFIG_BT_ISO_PERIPHERAL=y +CONFIG_BT_ISO_CENTRAL=y CONFIG_BT_CTLR_PERIPHERAL_ISO=y CONFIG_BT_CTLR_CENTRAL_ISO=y diff --git a/tests/bluetooth/controller/ctrl_tx_queue/prj.conf b/tests/bluetooth/controller/ctrl_tx_queue/prj.conf index 09d9cd9bab9..be14c4efa44 100644 --- a/tests/bluetooth/controller/ctrl_tx_queue/prj.conf +++ b/tests/bluetooth/controller/ctrl_tx_queue/prj.conf @@ -14,6 +14,8 @@ CONFIG_BT_LLL_VENDOR_NORDIC=y CONFIG_BT_CENTRAL=y CONFIG_BT_PERIPHERAL=y +CONFIG_BT_ISO_PERIPHERAL=y +CONFIG_BT_ISO_CENTRAL=y CONFIG_BT_CTLR_PERIPHERAL_ISO=y CONFIG_BT_CTLR_CENTRAL_ISO=y diff --git a/tests/bluetooth/controller/ctrl_unsupported/prj.conf b/tests/bluetooth/controller/ctrl_unsupported/prj.conf index 09d9cd9bab9..be14c4efa44 100644 --- a/tests/bluetooth/controller/ctrl_unsupported/prj.conf +++ b/tests/bluetooth/controller/ctrl_unsupported/prj.conf @@ -14,6 +14,8 @@ CONFIG_BT_LLL_VENDOR_NORDIC=y CONFIG_BT_CENTRAL=y CONFIG_BT_PERIPHERAL=y +CONFIG_BT_ISO_PERIPHERAL=y +CONFIG_BT_ISO_CENTRAL=y CONFIG_BT_CTLR_PERIPHERAL_ISO=y CONFIG_BT_CTLR_CENTRAL_ISO=y diff --git a/tests/bluetooth/controller/ctrl_unsupported/prj_unsupported.conf b/tests/bluetooth/controller/ctrl_unsupported/prj_unsupported.conf index f01e17406ee..714279ebba3 100644 --- a/tests/bluetooth/controller/ctrl_unsupported/prj_unsupported.conf +++ b/tests/bluetooth/controller/ctrl_unsupported/prj_unsupported.conf @@ -14,6 +14,8 @@ CONFIG_BT_LLL_VENDOR_NORDIC=y CONFIG_BT_CENTRAL=y CONFIG_BT_PERIPHERAL=y +CONFIG_BT_ISO_PERIPHERAL=y +CONFIG_BT_ISO_CENTRAL=y CONFIG_BT_CTLR_PERIPHERAL_ISO=y CONFIG_BT_CTLR_CENTRAL_ISO=y diff --git a/tests/bluetooth/controller/ctrl_version/prj.conf b/tests/bluetooth/controller/ctrl_version/prj.conf index 09d9cd9bab9..be14c4efa44 100644 --- a/tests/bluetooth/controller/ctrl_version/prj.conf +++ b/tests/bluetooth/controller/ctrl_version/prj.conf @@ -14,6 +14,8 @@ CONFIG_BT_LLL_VENDOR_NORDIC=y CONFIG_BT_CENTRAL=y CONFIG_BT_PERIPHERAL=y +CONFIG_BT_ISO_PERIPHERAL=y +CONFIG_BT_ISO_CENTRAL=y CONFIG_BT_CTLR_PERIPHERAL_ISO=y CONFIG_BT_CTLR_CENTRAL_ISO=y diff --git a/tests/bluetooth/controller/mock_ctrl/src/ull_central.c b/tests/bluetooth/controller/mock_ctrl/src/ull_central.c index ab067dcbb9d..b2ac0891ed6 100644 --- a/tests/bluetooth/controller/mock_ctrl/src/ull_central.c +++ b/tests/bluetooth/controller/mock_ctrl/src/ull_central.c @@ -20,7 +20,7 @@ #include "lll/lll_df_types.h" #include "lll_conn.h" -void ull_central_setup(memq_link_t *link, struct node_rx_hdr *rx, struct node_rx_ftr *ftr, +void ull_central_setup(memq_link_t *link, struct node_rx_pdu *rx, struct node_rx_ftr *ftr, struct lll_conn *lll) { } diff --git a/tests/bluetooth/controller/mock_ctrl/src/ull_peripheral.c b/tests/bluetooth/controller/mock_ctrl/src/ull_peripheral.c index fb7a6f8f1c5..1369fc2cbc9 100644 --- a/tests/bluetooth/controller/mock_ctrl/src/ull_peripheral.c +++ b/tests/bluetooth/controller/mock_ctrl/src/ull_peripheral.c @@ -22,7 +22,7 @@ #include "lll_conn.h" #include "ull_conn_types.h" -void ull_periph_setup(memq_link_t *link, struct node_rx_hdr *rx, struct node_rx_ftr *ftr, +void ull_periph_setup(memq_link_t *link, struct node_rx_pdu *rx, struct node_rx_ftr *ftr, struct lll_conn *lll) { } diff --git a/tests/bluetooth/ctrl_isoal/Kconfig b/tests/bluetooth/ctrl_isoal/Kconfig index 30049d53a5e..e6623e8e3b2 100644 --- a/tests/bluetooth/ctrl_isoal/Kconfig +++ b/tests/bluetooth/ctrl_isoal/Kconfig @@ -12,17 +12,10 @@ config BT_CTLR_CONN_ISO_GROUPS range 1 240 default 1 -config BT_CTLR_DEBUG_ISOAL - bool "[DEPRECATED] Bluetooth ISO-AL debug" - select DEPRECATED - depends on BT_CTLR_ISO - help - This option enables debug support for the Bluetooth ISO-AL. - +parent-module = BT module = BT_CTLR_ISOAL -legacy-debug-sym = BT_CTLR_DEBUG_ISOAL module-str = "Bluetooth Controller ISO-AL" -source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +source "subsys/logging/Kconfig.template.log_config_inherit" config BT_CTLR_ISOAL_LOG_DBG_VERBOSE bool "ISO-AL verbose debug logging" diff --git a/tests/bluetooth/ctrl_isoal/src/sub_sets/isoal_test_rx.c b/tests/bluetooth/ctrl_isoal/src/sub_sets/isoal_test_rx.c index 06407816c38..b7beb40f38a 100644 --- a/tests/bluetooth/ctrl_isoal/src/sub_sets/isoal_test_rx.c +++ b/tests/bluetooth/ctrl_isoal/src/sub_sets/isoal_test_rx.c @@ -176,17 +176,20 @@ static isoal_status_t custom_sink_sdu_emit_test(const struct isoal_sink *sink_ct _expected, \ sink_sdu_emit_test_fake.call_count) -FAKE_VALUE_FUNC(isoal_status_t, sink_sdu_write_test, void *, const uint8_t *, const size_t); +FAKE_VALUE_FUNC(isoal_status_t, sink_sdu_write_test, void *, const size_t, + const uint8_t *, const size_t); /** * Callback test fixture to be provided for RX sink creation. Writes provided * data into target SDU buffer. * @param dbuf SDU buffer (Includes current write location field) + * @param sdu_written Number of bytes already written to this SDU * @param pdu_payload Current PDU being reassembled by ISO-AL * @param consume_len Length of data to transfer * @return Status of the operation */ static isoal_status_t -custom_sink_sdu_write_test(void *dbuf, const uint8_t *pdu_payload, const size_t consume_len) +custom_sink_sdu_write_test(void *dbuf, const size_t sdu_written, + const uint8_t *pdu_payload, const size_t consume_len) { isoal_test_debug_trace_func_call(__func__, "IN"); @@ -204,22 +207,27 @@ custom_sink_sdu_write_test(void *dbuf, const uint8_t *pdu_payload, const size_t return sink_sdu_write_test_fake.return_val; } -#define ZASSERT_ISOAL_SDU_WRITE_TEST(_typ, _frag_buf, _payload_buf, _length) \ +#define ZASSERT_ISOAL_SDU_WRITE_TEST(_typ, _frag_buf, _sdu_written, _payload_buf, _length) \ zassert_equal_ptr(_frag_buf, \ sink_sdu_write_test_fake.arg0_##_typ, \ "\t\tExpected write buffer at %p, got %p.", \ _frag_buf, \ sink_sdu_write_test_fake.arg0_##_typ); \ + zassert_equal(_sdu_written, \ + sink_sdu_write_test_fake.arg1_##_typ, \ + "\t\tExpected sdu_written of %u, got %u.", \ + _sdu_written, \ + sink_sdu_write_test_fake.arg1_##_typ); \ zassert_equal_ptr(_payload_buf, \ - sink_sdu_write_test_fake.arg1_##_typ, \ + sink_sdu_write_test_fake.arg2_##_typ, \ "\t\tExpected write source at %p, got %p.", \ _payload_buf, \ - sink_sdu_write_test_fake.arg1_##_typ); \ + sink_sdu_write_test_fake.arg2_##_typ); \ zassert_equal(_length, \ - sink_sdu_write_test_fake.arg2_##_typ, \ + sink_sdu_write_test_fake.arg3_##_typ, \ "\t\tExpected write length of %u, got %u.", \ _length, \ - sink_sdu_write_test_fake.arg2_##_typ) + sink_sdu_write_test_fake.arg3_##_typ) #define ZASSERT_ISOAL_SDU_WRITE_TEST_CALL_COUNT(_expected) \ zassert_equal(_expected, \ @@ -877,6 +885,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_single_pdu) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + 0, /* SDU written */ &rx_pdu_meta_buf.pdu[3], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ /* SDU should be emitted */ @@ -1047,6 +1056,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_single_pdu_ts_wrap1) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + 0, /* SDU written */ &rx_pdu_meta_buf.pdu[3], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ /* SDU should be emitted */ @@ -1182,6 +1192,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_single_pdu_ts_wrap2) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + 0, /* SDU written */ &rx_pdu_meta_buf.pdu[3], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ /* SDU should be emitted */ @@ -1231,6 +1242,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_dbl_pdu) uint8_t iso_interval_int; uint64_t payload_number; uint16_t total_sdu_size; + uint16_t sdu_written = 0; uint32_t pdu_timestamp; uint32_t sdu_timestamp; uint16_t testdata_indx; @@ -1312,6 +1324,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_dbl_pdu) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -1328,6 +1341,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_dbl_pdu) /* PDU 1 -------------------------------------------------------------*/ isoal_test_init_rx_pdu_buffer(&rx_pdu_meta_buf); + sdu_written += (testdata_size - testdata_indx); payload_number++; testdata_indx = testdata_size; testdata_size += 10; @@ -1360,6 +1374,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_dbl_pdu) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ /* SDU should be emitted */ @@ -1414,6 +1429,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_dbl_split) uint8_t iso_interval_int; uint64_t payload_number; uint16_t total_sdu_size; + uint16_t sdu_written = 0; uint32_t pdu_timestamp; uint32_t sdu_timestamp; uint16_t testdata_indx; @@ -1493,6 +1509,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_dbl_split) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -1508,6 +1525,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_dbl_split) /* SDU 0 - PDU 1 -----------------------------------------------------*/ isoal_test_init_rx_pdu_buffer(&rx_pdu_meta_buf); + sdu_written += (testdata_size - testdata_indx); payload_number++; testdata_indx = testdata_size; testdata_size += 10; @@ -1538,6 +1556,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_dbl_split) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ /* SDU should be emitted */ @@ -1563,6 +1582,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_dbl_split) /* SDU 1 - PDU 2 -----------------------------------------------------*/ isoal_test_init_rx_pdu_buffer(&rx_pdu_meta_buf); isoal_test_init_rx_sdu_buffer(&rx_sdu_frag_buf); + sdu_written = 0; payload_number++; seqn++; sdu_timestamp = (uint32_t)((int64_t)pdu_timestamp + latency + sdu_interval); @@ -1596,6 +1616,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_dbl_split) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -1611,6 +1632,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_dbl_split) /* SDU 1 - PDU 3 -----------------------------------------------------*/ isoal_test_init_rx_pdu_buffer(&rx_pdu_meta_buf); + sdu_written += (testdata_size - testdata_indx); payload_number++; testdata_indx = testdata_size; testdata_size += 10; @@ -1641,6 +1663,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_dbl_split) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ /* SDU should be emitted */ @@ -1666,6 +1689,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_dbl_split) /* SDU 2 - PDU 4 -----------------------------------------------------*/ isoal_test_init_rx_pdu_buffer(&rx_pdu_meta_buf); isoal_test_init_rx_sdu_buffer(&rx_sdu_frag_buf); + sdu_written = 0; payload_number++; seqn++; pdu_timestamp = 9249 + ISO_INT_UNIT_US; @@ -1703,6 +1727,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_dbl_split) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ /* SDU should be emitted */ @@ -1755,6 +1780,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_multi_split) uint8_t iso_interval_int; uint64_t payload_number; uint16_t total_sdu_size; + uint16_t sdu_written = 0; uint32_t pdu_timestamp; uint32_t sdu_timestamp; uint16_t testdata_indx; @@ -1834,6 +1860,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_multi_split) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -1849,6 +1876,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_multi_split) /* PDU 1 -------------------------------------------------------------*/ isoal_test_init_rx_pdu_buffer(&rx_pdu_meta_buf); + sdu_written += (testdata_size - testdata_indx); payload_number++; testdata_indx = testdata_size; testdata_size += 10; @@ -1876,6 +1904,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_multi_split) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -1891,6 +1920,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_multi_split) /* PDU 3 -------------------------------------------------------------*/ isoal_test_init_rx_pdu_buffer(&rx_pdu_meta_buf); + sdu_written += (testdata_size - testdata_indx); payload_number++; testdata_indx = testdata_size; testdata_size += 10; @@ -1918,6 +1948,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_multi_split) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -1933,6 +1964,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_multi_split) /* PDU 3 -------------------------------------------------------------*/ isoal_test_init_rx_pdu_buffer(&rx_pdu_meta_buf); + sdu_written += (testdata_size - testdata_indx); payload_number++; testdata_indx = testdata_size; testdata_size += 10; @@ -1960,6 +1992,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_multi_split) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -1975,6 +2008,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_multi_split) /* PDU 4 -------------------------------------------------------------*/ isoal_test_init_rx_pdu_buffer(&rx_pdu_meta_buf); + sdu_written += (testdata_size - testdata_indx); payload_number++; testdata_indx = testdata_size; testdata_size += 10; @@ -2005,6 +2039,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_multi_split) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ /* SDU should be emitted */ @@ -2059,6 +2094,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_multi_split_on_border) uint8_t iso_interval_int; uint64_t payload_number; uint16_t total_sdu_size; + uint16_t sdu_written = 0; uint32_t pdu_timestamp; uint32_t sdu_timestamp; uint16_t testdata_indx; @@ -2138,6 +2174,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_multi_split_on_border) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -2153,6 +2190,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_multi_split_on_border) /* PDU 1 -------------------------------------------------------------*/ isoal_test_init_rx_pdu_buffer(&rx_pdu_meta_buf); + sdu_written += (testdata_size - testdata_indx); payload_number++; testdata_indx = testdata_size; testdata_size += 23; @@ -2183,6 +2221,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_multi_split_on_border) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ /* SDU should be emitted */ @@ -2208,6 +2247,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_multi_split_on_border) /* PDU 2 -------------------------------------------------------------*/ isoal_test_init_rx_pdu_buffer(&rx_pdu_meta_buf); isoal_test_init_rx_sdu_buffer(&rx_sdu_frag_buf); + sdu_written = 0; payload_number++; testdata_indx = testdata_size; testdata_size += 40; @@ -2242,6 +2282,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_multi_split_on_border) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ /* SDU should be emitted */ @@ -2266,6 +2307,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_multi_split_on_border) /* PDU 3 -------------------------------------------------------------*/ isoal_test_init_rx_pdu_buffer(&rx_pdu_meta_buf); + sdu_written = 0; payload_number++; testdata_indx = testdata_size; testdata_size += 10; @@ -2297,6 +2339,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_multi_split_on_border) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -2312,6 +2355,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_multi_split_on_border) /* PDU 4 -------------------------------------------------------------*/ isoal_test_init_rx_pdu_buffer(&rx_pdu_meta_buf); + sdu_written += (testdata_size - testdata_indx); payload_number++; testdata_indx = testdata_size; testdata_size += 10; @@ -2342,6 +2386,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_multi_split_on_border) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ /* SDU should be emitted */ @@ -2471,6 +2516,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_long_pdu_short_sdu) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(history[0], &rx_sdu_frag_buf[0], /* SDU buffer */ + 0, /* SDU written */ &rx_pdu_meta_buf.pdu[3], /* PDU payload */ 20); /* Size */ /* SDU should be emitted */ @@ -2498,6 +2544,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_long_pdu_short_sdu) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(history[1], &rx_sdu_frag_buf[1], /* SDU buffer */ + 0, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + 20], /* PDU payload */ 20); /* Size */ /* SDU should be emitted */ @@ -2620,6 +2667,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_dbl_pdu_prem) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + 0, /* SDU written */ &rx_pdu_meta_buf.pdu[3], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ /* SDU should be emitted */ @@ -2680,6 +2728,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_dbl_pdu_prem) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + 0, /* SDU written */ &rx_pdu_meta_buf.pdu[3], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ /* SDU should be emitted */ @@ -2900,6 +2949,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_seq_err) uint8_t iso_interval_int; uint64_t payload_number; uint16_t total_sdu_size; + uint16_t sdu_written = 0; uint32_t pdu_timestamp; uint32_t sdu_timestamp; uint16_t testdata_indx; @@ -2978,6 +3028,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_seq_err) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -2991,6 +3042,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_seq_err) FSM_TO_STR(ISOAL_CONTINUE)); /* PDU 2 Not transferred to ISO-AL ------------------------------------*/ + sdu_written += (testdata_size - testdata_indx); payload_number++; testdata_indx = testdata_size; testdata_size += 10; @@ -3029,6 +3081,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_seq_err) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ /* SDU should be emitted */ @@ -3058,6 +3111,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_seq_err) /* PDU 4 -------------------------------------------------------------*/ isoal_test_init_rx_pdu_buffer(&rx_pdu_meta_buf); isoal_test_init_rx_sdu_buffer(&rx_sdu_frag_buf); + sdu_written = 0; payload_number++; seqn++; pdu_timestamp = 9249 + ISO_INT_UNIT_US; @@ -3093,6 +3147,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_seq_err) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ /* SDU should not be emitted */ @@ -3129,6 +3184,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_seq_pdu_err1) uint8_t iso_interval_int; uint64_t payload_number; uint16_t total_sdu_size; + uint16_t sdu_written = 0; uint32_t pdu_timestamp; uint32_t sdu_timestamp; uint16_t testdata_indx; @@ -3208,6 +3264,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_seq_pdu_err1) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ /* SDU should not be emitted */ @@ -3284,6 +3341,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_seq_pdu_err1) /* PDU 4 -------------------------------------------------------------*/ isoal_test_init_rx_pdu_buffer(&rx_pdu_meta_buf); isoal_test_init_rx_sdu_buffer(&rx_sdu_frag_buf); + sdu_written = 0; payload_number++; seqn++; pdu_timestamp = 9249 + ISO_INT_UNIT_US; @@ -3318,6 +3376,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_seq_pdu_err1) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ /* SDU should not be emitted */ @@ -3336,6 +3395,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_seq_pdu_err1) /* PDU 5 -------------------------------------------------------------*/ isoal_test_init_rx_pdu_buffer(&rx_pdu_meta_buf); + sdu_written += (testdata_size - testdata_indx); payload_number++; testdata_indx = testdata_size; testdata_size += 10; @@ -3365,6 +3425,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_seq_pdu_err1) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ /* SDU should be emitted */ @@ -3409,6 +3470,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_seq_pdu_err2) uint8_t iso_interval_int; uint64_t payload_number; uint16_t total_sdu_size; + uint16_t sdu_written = 0; uint32_t pdu_timestamp; uint32_t sdu_timestamp; uint16_t testdata_indx; @@ -3491,6 +3553,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_seq_pdu_err2) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ /* SDU should be emitted */ @@ -3583,6 +3646,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_seq_pdu_err2) /* PDU 4 -------------------------------------------------------------*/ isoal_test_init_rx_pdu_buffer(&rx_pdu_meta_buf); isoal_test_init_rx_sdu_buffer(&rx_sdu_frag_buf); + sdu_written = 0; payload_number++; seqn++; pdu_timestamp = 9249 + ISO_INT_UNIT_US; @@ -3617,6 +3681,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_seq_pdu_err2) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ /* SDU should not be emitted */ @@ -3635,6 +3700,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_seq_pdu_err2) /* PDU 5 -------------------------------------------------------------*/ isoal_test_init_rx_pdu_buffer(&rx_pdu_meta_buf); + sdu_written += (testdata_size - testdata_indx); payload_number++; testdata_indx = testdata_size; testdata_size += 10; @@ -3664,6 +3730,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_seq_pdu_err2) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ /* SDU should be emitted */ @@ -3706,6 +3773,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_padding) uint8_t iso_interval_int; uint64_t payload_number; uint16_t total_sdu_size; + uint16_t sdu_written = 0; uint32_t pdu_timestamp; uint32_t sdu_timestamp; uint16_t testdata_indx; @@ -3785,6 +3853,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_padding) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ /* SDU should not be emitted */ @@ -3798,6 +3867,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_padding) /* PDU 2 -------------------------------------------------------------*/ isoal_test_init_rx_pdu_buffer(&rx_pdu_meta_buf); + sdu_written += (testdata_size - testdata_indx); payload_number++; testdata_indx = testdata_size; testdata_size += 10; @@ -3829,6 +3899,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_padding) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ /* SDU should be emitted */ @@ -4013,6 +4084,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_padding_no_end) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + 0, /* SDU written */ &rx_pdu_meta_buf.pdu[3], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ /* SDU should not be emitted */ @@ -4471,6 +4543,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_padding_leading) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + 0, /* SDU written */ &rx_pdu_meta_buf.pdu[3], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -4778,6 +4851,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_padding_error2) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + 0, /* SDU written */ &rx_pdu_meta_buf.pdu[3], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ /* SDU should not be emitted */ @@ -4887,6 +4961,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_padding_error3) uint8_t iso_interval_int; uint64_t payload_number; uint16_t total_sdu_size; + uint16_t sdu_written = 0; uint32_t pdu_timestamp; uint32_t sdu_timestamp; uint16_t testdata_indx; @@ -4966,6 +5041,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_padding_error3) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ /* SDU should not be emitted */ @@ -4979,6 +5055,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_padding_error3) /* PDU 2 -------------------------------------------------------------*/ isoal_test_init_rx_pdu_buffer(&rx_pdu_meta_buf); + sdu_written += (testdata_size - testdata_indx); payload_number++; testdata_indx = testdata_size; testdata_size += 10; @@ -5008,6 +5085,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_padding_error3) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ /* SDU should be emitted */ @@ -5201,6 +5279,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_seq_err_zero_length) uint8_t iso_interval_int; uint64_t payload_number; uint16_t total_sdu_size; + uint16_t sdu_written = 0; uint32_t pdu_timestamp; uint32_t sdu_timestamp; uint16_t testdata_indx; @@ -5280,6 +5359,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_seq_err_zero_length) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ /* SDU should not be emitted */ @@ -5292,6 +5372,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_seq_err_zero_length) FSM_TO_STR(ISOAL_CONTINUE)); /* PDU 2 Not transferred to ISO-AL ------------------------------------*/ + sdu_written += (testdata_size - testdata_indx); payload_number++; testdata_indx = testdata_size; testdata_size += 10; @@ -5328,6 +5409,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_seq_err_zero_length) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ /* SDU should be emitted */ @@ -5437,6 +5519,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_dbl_pdu_no_end) uint8_t iso_interval_int; uint64_t payload_number; uint16_t total_sdu_size; + uint16_t sdu_written = 0; uint32_t pdu_timestamp; uint32_t sdu_timestamp; uint16_t testdata_indx; @@ -5516,6 +5599,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_dbl_pdu_no_end) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ /* SDU should not be emitted */ @@ -5529,6 +5613,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_dbl_pdu_no_end) /* PDU 2 -------------------------------------------------------------*/ isoal_test_init_rx_pdu_buffer(&rx_pdu_meta_buf); + sdu_written += (testdata_size - testdata_indx); payload_number++; testdata_indx = testdata_size; testdata_size += 10; @@ -5558,6 +5643,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_dbl_pdu_no_end) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ /* SDU should be emitted */ @@ -5769,6 +5855,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_dbl_pdu_invalid_llid2) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + 0, /* SDU written */ &rx_pdu_meta_buf.pdu[3], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ /* SDU should not be emitted */ @@ -5903,6 +5990,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_dbl_pdu_invalid_llid2_pdu_err) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + 0, /* SDU written */ &rx_pdu_meta_buf.pdu[3], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ /* SDU should not be emitted */ @@ -6073,6 +6161,7 @@ ZTEST(test_rx_framed, test_rx_framed_single_pdu_single_sdu) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + 0, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[0]], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -6204,6 +6293,7 @@ ZTEST(test_rx_framed, test_rx_framed_single_pdu_single_sdu_ts_wrap1) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + 0, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[0]], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -6336,6 +6426,7 @@ ZTEST(test_rx_framed, test_rx_framed_single_pdu_single_sdu_ts_wrap2) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + 0, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[0]], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -6380,6 +6471,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_single_sdu) uint16_t pdu_data_loc[5]; uint64_t payload_number; uint16_t total_sdu_size; + uint16_t sdu_written = 0; uint32_t sdu_timeoffset; uint32_t pdu_timestamp; uint32_t sdu_timestamp; @@ -6464,6 +6556,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_single_sdu) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[0]], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -6479,6 +6572,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_single_sdu) /* PDU 2 -------------------------------------------------------------*/ isoal_test_init_rx_pdu_buffer(&rx_pdu_meta_buf); + sdu_written += (testdata_size - testdata_indx); payload_number++; testdata_indx = testdata_size; testdata_size += 10; @@ -6505,6 +6599,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_single_sdu) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[1]], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -6520,6 +6615,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_single_sdu) /* PDU 3 -------------------------------------------------------------*/ isoal_test_init_rx_pdu_buffer(&rx_pdu_meta_buf); + sdu_written += (testdata_size - testdata_indx); payload_number++; testdata_indx = testdata_size; testdata_size += 10; @@ -6549,6 +6645,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_single_sdu) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[2]], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -6594,6 +6691,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_dbl_sdu) uint32_t iso_interval_us; uint64_t payload_number; uint16_t total_sdu_size; + uint16_t sdu_written = 0; uint32_t sdu_timeoffset; uint32_t pdu_timestamp; uint16_t testdata_indx; @@ -6681,6 +6779,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_dbl_sdu) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf[0], /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[0]], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -6697,6 +6796,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_dbl_sdu) /* PDU 2 -------------------------------------------------------------*/ isoal_test_init_rx_pdu_buffer(&rx_pdu_meta_buf); + sdu_written += (testdata_size - testdata_indx); payload_number++; testdata_indx = testdata_size; testdata_size += 10; @@ -6741,6 +6841,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_dbl_sdu) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(history[1], &rx_sdu_frag_buf[0], /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[1]], /* PDU payload */ 10); /* Size */ @@ -6758,6 +6859,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_dbl_sdu) collated_status); /* SDU status */ /* SDU 2 */ + sdu_written = 0; seqn++; /* A new SDU should be allocated */ ZASSERT_ISOAL_SDU_ALLOC_TEST(val, @@ -6767,6 +6869,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_dbl_sdu) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf[1], /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[2]], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -6783,6 +6886,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_dbl_sdu) /* PDU 3 -------------------------------------------------------------*/ isoal_test_init_rx_pdu_buffer(&rx_pdu_meta_buf); + sdu_written += (testdata_size - testdata_indx); payload_number++; testdata_indx = testdata_size; testdata_size += 10; @@ -6811,6 +6915,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_dbl_sdu) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf[1], /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[3]], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -6858,6 +6963,7 @@ ZTEST(test_rx_framed, test_rx_framed_zero_length_sdu) isoal_sdu_cnt_t seqn[3]; uint64_t payload_number; uint16_t total_sdu_size; + uint16_t sdu_written = 0; uint32_t sdu_timeoffset; uint32_t pdu_timestamp; uint16_t testdata_indx; @@ -6947,6 +7053,7 @@ ZTEST(test_rx_framed, test_rx_framed_zero_length_sdu) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf[0], /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[0]], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -6963,6 +7070,7 @@ ZTEST(test_rx_framed, test_rx_framed_zero_length_sdu) /* PDU 2 -------------------------------------------------------------*/ isoal_test_init_rx_pdu_buffer(&rx_pdu_meta_buf); + sdu_written += (testdata_size - testdata_indx); payload_number++; testdata_indx = testdata_size; testdata_size += 10; @@ -7021,6 +7129,7 @@ ZTEST(test_rx_framed, test_rx_framed_zero_length_sdu) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(history[1], &rx_sdu_frag_buf[0], /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[1]], /* PDU payload */ 10); /* Size */ @@ -7039,6 +7148,7 @@ ZTEST(test_rx_framed, test_rx_framed_zero_length_sdu) collated_status); /* SDU status */ /* SDU 2 */ + sdu_written = 0; total_sdu_size = COLLATED_RX_SDU_INFO(sdu_size[1], sdu_size[1]); collated_status = COLLATED_RX_SDU_INFO(ISOAL_SDU_STATUS_VALID, ISOAL_SDU_STATUS_VALID); @@ -7071,6 +7181,7 @@ ZTEST(test_rx_framed, test_rx_framed_zero_length_sdu) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf[2], /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[3]], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -7087,6 +7198,7 @@ ZTEST(test_rx_framed, test_rx_framed_zero_length_sdu) /* PDU 3 -------------------------------------------------------------*/ isoal_test_init_rx_pdu_buffer(&rx_pdu_meta_buf); + sdu_written += (testdata_size - testdata_indx); payload_number++; testdata_indx = testdata_size; testdata_size += 10; @@ -7116,6 +7228,7 @@ ZTEST(test_rx_framed, test_rx_framed_zero_length_sdu) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf[2], /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[3]], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -7250,6 +7363,7 @@ ZTEST(test_rx_framed, test_rx_framed_dbl_pdu_dbl_sdu_padding) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + 0, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[0]], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -7351,6 +7465,7 @@ ZTEST(test_rx_framed, test_rx_framed_dbl_pdu_dbl_sdu_padding) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + 0, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[1]], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -7720,6 +7835,7 @@ ZTEST(test_rx_framed, test_rx_framed_padding_only) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf[3], /* SDU buffer */ + 0, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -8281,6 +8397,7 @@ ZTEST(test_rx_framed, test_rx_framed_dbl_pdu_dbl_sdu_pdu_err1) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + 0, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[1]], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -8497,6 +8614,7 @@ ZTEST(test_rx_framed, test_rx_framed_dbl_pdu_dbl_sdu_pdu_err2) ZASSERT_ISOAL_SDU_WRITE_TEST_CALL_COUNT(1); ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf[1], /* SDU buffer */ + 0, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[1]], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -8634,6 +8752,7 @@ ZTEST(test_rx_framed, test_rx_framed_dbl_pdu_dbl_sdu_pdu_err3) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + 0, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[0]], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -8829,6 +8948,7 @@ ZTEST(test_rx_framed, test_rx_framed_dbl_pdu_dbl_sdu_seq_err1) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf[0], /* SDU buffer */ + 0, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[0]], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -8937,6 +9057,7 @@ ZTEST(test_rx_framed, test_rx_framed_dbl_pdu_dbl_sdu_seq_err1) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf[1], /* SDU buffer */ + 0, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[1]], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -9202,6 +9323,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_single_sdu_pdu_err1) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + 0, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[3]], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -9333,6 +9455,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_single_sdu_pdu_err2) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + 0, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[0]], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -9471,6 +9594,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_single_sdu_pdu_err2) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + 0, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[3]], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -9516,6 +9640,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_single_sdu_pdu_err3) uint32_t iso_interval_us; uint64_t payload_number; uint16_t total_sdu_size; + uint16_t sdu_written = 0; uint32_t sdu_timeoffset; uint32_t pdu_timestamp; uint32_t sdu_timestamp; @@ -9602,6 +9727,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_single_sdu_pdu_err3) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[0]], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -9618,6 +9744,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_single_sdu_pdu_err3) /* PDU 2 -------------------------------------------------------------*/ isoal_test_init_rx_pdu_buffer(&rx_pdu_meta_buf); + sdu_written += (testdata_size - testdata_indx); payload_number++; testdata_indx = testdata_size; testdata_size += 10; @@ -9644,6 +9771,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_single_sdu_pdu_err3) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[1]], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -9710,6 +9838,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_single_sdu_pdu_err3) isoal_test_init_rx_pdu_buffer(&rx_pdu_meta_buf); isoal_test_init_rx_sdu_buffer(&rx_sdu_frag_buf); + sdu_written = 0; payload_number++; sdu_timeoffset = get_next_time_offset(sdu_timeoffset, iso_interval_us, sdu_interval, false); @@ -9749,6 +9878,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_single_sdu_pdu_err3) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[3]], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -9880,6 +10010,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_single_sdu_seq_err1) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + 0, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[0]], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -9994,6 +10125,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_single_sdu_seq_err1) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + 0, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[3]], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -10125,6 +10257,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_single_sdu_pdu_seq_err1) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + 0, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[0]], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -10239,6 +10372,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_single_sdu_pdu_seq_err1) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + 0, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[3]], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -10280,6 +10414,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_dbl_sdu_pdu_err1) uint32_t group_sync_delay; isoal_sdu_len_t sdu_size[2]; uint16_t total_sdu_size[2]; + uint16_t sdu_written = 0; uint8_t iso_interval_int; uint32_t sdu_timestamp[2]; uint16_t pdu_data_loc[5]; @@ -10449,6 +10584,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_dbl_sdu_pdu_err1) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf[1], /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[2]], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -10465,6 +10601,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_dbl_sdu_pdu_err1) /* PDU 3 -------------------------------------------------------------*/ isoal_test_init_rx_pdu_buffer(&rx_pdu_meta_buf); + sdu_written += (testdata_size - testdata_indx); payload_number++; testdata_indx = testdata_size; testdata_size += 10; @@ -10497,6 +10634,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_dbl_sdu_pdu_err1) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf[1], /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[3]], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -10534,6 +10672,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_dbl_sdu_pdu_err1) isoal_test_init_rx_pdu_buffer(&rx_pdu_meta_buf); isoal_test_init_rx_sdu_buffer(&rx_sdu_frag_buf[0]); + sdu_written = 0; payload_number++; pdu_timestamp = 9249 + iso_interval_us; sdu_timeoffset = get_next_time_offset(sdu_timeoffset, iso_interval_us, sdu_interval, true); @@ -10597,6 +10736,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_dbl_sdu_pdu_err1) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf[0], /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[4]], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -10751,6 +10891,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_dbl_sdu_pdu_err2) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf[0], /* SDU buffer */ + 0, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[0]], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -10967,6 +11108,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_dbl_sdu_pdu_err2) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf[0], /* SDU buffer */ + 0, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[4]], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -11029,6 +11171,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_dbl_sdu_pdu_err3) uint32_t iso_interval_us; uint64_t payload_number; uint16_t total_sdu_size; + uint16_t sdu_written = 0; uint32_t sdu_timeoffset; uint32_t pdu_timestamp; uint16_t testdata_indx; @@ -11117,6 +11260,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_dbl_sdu_pdu_err3) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf[0], /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[0]], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -11133,6 +11277,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_dbl_sdu_pdu_err3) /* PDU 1 -------------------------------------------------------------*/ isoal_test_init_rx_pdu_buffer(&rx_pdu_meta_buf); + sdu_written += (testdata_size - testdata_indx); payload_number++; testdata_indx = testdata_size; testdata_size += 10; @@ -11177,6 +11322,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_dbl_sdu_pdu_err3) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(history[1], &rx_sdu_frag_buf[0], /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[1]], /* PDU payload */ 10); /* Size */ @@ -11195,6 +11341,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_dbl_sdu_pdu_err3) collated_status); /* SDU status */ /* SDU 1 -------------------------------------------------------------*/ + sdu_written = 0; seqn++; /* A new SDU should be allocated */ ZASSERT_ISOAL_SDU_ALLOC_TEST(history[1], @@ -11204,6 +11351,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_dbl_sdu_pdu_err3) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf[1], /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[2]], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -11333,6 +11481,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_dbl_sdu_pdu_err3) collated_status); /* SDU status */ /* SDU 3 -------------------------------------------------------------*/ + sdu_written = 0; seqn++; total_sdu_size = COLLATED_RX_SDU_INFO(sdu_size[0], sdu_size[0]); collated_status = COLLATED_RX_SDU_INFO(ISOAL_SDU_STATUS_VALID, ISOAL_SDU_STATUS_VALID); @@ -11345,6 +11494,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_dbl_sdu_pdu_err3) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf[0], /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[4]], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -11499,6 +11649,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_dbl_sdu_seq_err1) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + 0, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[0]], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -11692,6 +11843,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_dbl_sdu_seq_err1) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf[0], /* SDU buffer */ + 0, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[4]], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -11847,6 +11999,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_dbl_sdu_pdu_seq_err1) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf[0], /* SDU buffer */ + 0, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[0]], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -12034,6 +12187,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_dbl_sdu_pdu_seq_err1) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + 0, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[4]], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -12079,6 +12233,7 @@ ZTEST(test_rx_framed, test_rx_framed_single_invalid_pdu_single_sdu) uint16_t pdu_data_loc[5]; uint64_t payload_number; uint16_t total_sdu_size; + uint16_t sdu_written = 0; uint32_t sdu_timeoffset; uint32_t pdu_timestamp; uint32_t sdu_timestamp; @@ -12182,18 +12337,23 @@ ZTEST(test_rx_framed, test_rx_framed_single_invalid_pdu_single_sdu) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(history[0], &rx_sdu_frag_buf, /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[0]], /* PDU payload */ 13); /* Size */ + sdu_written += 13; ZASSERT_ISOAL_SDU_WRITE_TEST(history[1], &rx_sdu_frag_buf, /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[1]], /* PDU payload */ 5); /* Size */ + sdu_written += 5; ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[2]], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -12240,6 +12400,7 @@ ZTEST(test_rx_framed, test_rx_framed_single_invalid_pdu_single_sdu_hdr_err) uint16_t pdu_data_loc[5]; uint64_t payload_number; uint16_t total_sdu_size; + uint16_t sdu_written = 0; uint32_t sdu_timeoffset; uint32_t pdu_timestamp; uint32_t sdu_timestamp; @@ -12360,30 +12521,39 @@ ZTEST(test_rx_framed, test_rx_framed_single_invalid_pdu_single_sdu_hdr_err) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(history[0], &rx_sdu_frag_buf, /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[0]], /* PDU payload */ 3); /* Size */ + sdu_written += 3; ZASSERT_ISOAL_SDU_WRITE_TEST(history[1], &rx_sdu_frag_buf, /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[1]], /* PDU payload */ 4); /* Size */ + sdu_written += 4; ZASSERT_ISOAL_SDU_WRITE_TEST(history[2], &rx_sdu_frag_buf, /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[2]], /* PDU payload */ 4); /* Size */ + sdu_written += 4; ZASSERT_ISOAL_SDU_WRITE_TEST(history[3], &rx_sdu_frag_buf, /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[3]], /* PDU payload */ 4); /* Size */ + sdu_written += 4; ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf, /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[4]], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -12445,6 +12615,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_dbl_sdu_seg_err1) isoal_sdu_cnt_t seqn[2]; uint64_t payload_number; uint16_t total_sdu_size; + uint16_t sdu_written = 0; uint32_t sdu_timeoffset; uint32_t pdu_timestamp; uint16_t testdata_indx; @@ -12612,6 +12783,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_dbl_sdu_seg_err1) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf[1], /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[2]], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -12629,6 +12801,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_dbl_sdu_seg_err1) /* PDU 2 -------------------------------------------------------------*/ isoal_test_init_rx_pdu_buffer(&rx_pdu_meta_buf); + sdu_written += (testdata_size - testdata_indx); payload_number++; testdata_indx = testdata_size; testdata_size += 10; @@ -12660,6 +12833,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_dbl_sdu_seg_err1) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf[1], /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[3]], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -12727,6 +12901,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_dbl_sdu_seg_err2) uint32_t iso_interval_us; uint64_t payload_number; uint16_t total_sdu_size; + uint16_t sdu_written = 0; uint32_t sdu_timeoffset; uint32_t pdu_timestamp; uint16_t testdata_indx; @@ -12816,6 +12991,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_dbl_sdu_seg_err2) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf[0], /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[0]], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ @@ -12833,6 +13009,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_dbl_sdu_seg_err2) /* PDU 2 -------------------------------------------------------------*/ isoal_test_init_rx_pdu_buffer(&rx_pdu_meta_buf); + sdu_written += (testdata_size - testdata_indx); payload_number++; testdata_indx = testdata_size; testdata_size += 10; @@ -12880,6 +13057,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_dbl_sdu_seg_err2) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf[0], /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[1]], /* PDU payload */ 10); /* Size */ @@ -13032,6 +13210,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_dbl_sdu_seg_err2) collated_status); /* SDU status */ /* SDU 3 -------------------------------------------------------------*/ + sdu_written = 0; seqn++; total_sdu_size = COLLATED_RX_SDU_INFO(sdu_size[0], sdu_size[0]); collated_status = COLLATED_RX_SDU_INFO(ISOAL_SDU_STATUS_VALID, ISOAL_SDU_STATUS_VALID); @@ -13044,6 +13223,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_dbl_sdu_seg_err2) /* SDU payload should be written */ ZASSERT_ISOAL_SDU_WRITE_TEST(val, &rx_sdu_frag_buf[0], /* SDU buffer */ + sdu_written, /* SDU written */ &rx_pdu_meta_buf.pdu[3 + pdu_data_loc[4]], /* PDU payload */ (testdata_size - testdata_indx)); /* Size */ diff --git a/tests/bluetooth/df/connection_cte_req/src/test_cte_req_enable.c b/tests/bluetooth/df/connection_cte_req/src/test_cte_req_enable.c index e518903cba2..f9f10d5ccab 100644 --- a/tests/bluetooth/df/connection_cte_req/src/test_cte_req_enable.c +++ b/tests/bluetooth/df/connection_cte_req/src/test_cte_req_enable.c @@ -97,7 +97,7 @@ ZTEST(test_hci_set_conn_cte_rx_params_with_conn_set, int err; err = send_conn_cte_req_enable(g_conn_handle, &g_data, true); - zassert_equal(err, -EIO, + zassert_equal(err, -EACCES, "Unexpected error value for CTE request enable before set rx params"); } @@ -109,7 +109,7 @@ ZTEST(test_hci_set_conn_cte_rx_params_with_rx_param_set, g_data.cte_request_interval = REQUEST_INTERVAL_TOO_LOW; err = send_conn_cte_req_enable(g_conn_handle, &g_data, true); - zassert_equal(err, -EIO, + zassert_equal(err, -EACCES, "Unexpected error value for CTE request enable with too short request" " interval"); } diff --git a/tests/bluetooth/df/connectionless_cte_tx/src/test_set_cl_cte_tx_enable.c b/tests/bluetooth/df/connectionless_cte_tx/src/test_set_cl_cte_tx_enable.c index 313f94e7762..35267739edd 100644 --- a/tests/bluetooth/df/connectionless_cte_tx/src/test_set_cl_cte_tx_enable.c +++ b/tests/bluetooth/df/connectionless_cte_tx/src/test_set_cl_cte_tx_enable.c @@ -71,7 +71,7 @@ ZTEST(test_set_cl_cte_tx_enable, test_set_cl_cte_tx_enable_cte_params_not_set) /* test logic */ err = send_set_cl_cte_tx_enable(g_adv->handle, g_adv->flags, true); - zassert_equal(err, -EIO, "Unexpected error value for enable CTE before " + zassert_equal(err, -EACCES, "Unexpected error value for enable CTE before " "CTE params set"); /* clean up */ @@ -90,7 +90,7 @@ ZTEST(test_set_cl_cte_tx_enable, test_set_cl_cte_tx_enable_per_adv_coded_phy) /* test logic */ err = send_set_cl_cte_tx_enable(g_adv->handle, g_adv->flags, true); - zassert_equal(err, -EIO, "Unexpected error value for enable CTE for " + zassert_equal(err, -EACCES, "Unexpected error value for enable CTE for " "coded PHY"); /* clean up */ @@ -151,7 +151,7 @@ ZTEST(test_set_cl_cte_tx_enable, test_set_cl_cte_tx_disable_when_no_CTE_enabled) /* test logic */ err = send_set_cl_cte_tx_enable(g_adv->handle, g_adv->flags, false); - zassert_equal(err, -EIO, "Unexpected error value for disable CTE " + zassert_equal(err, -EACCES, "Unexpected error value for disable CTE " "before CTE enable"); /* clean up */ diff --git a/tests/bluetooth/hci_prop_evt/src/main.c b/tests/bluetooth/hci_prop_evt/src/main.c index cac605bd2e4..cf46a2bad65 100644 --- a/tests/bluetooth/hci_prop_evt/src/main.c +++ b/tests/bluetooth/hci_prop_evt/src/main.c @@ -201,6 +201,9 @@ static const struct cmd_handler cmds[] = { { BT_HCI_OP_LE_SET_RANDOM_ADDRESS, sizeof(struct bt_hci_cp_le_set_random_address), generic_success }, + { BT_HCI_OP_LE_READ_MAX_ADV_DATA_LEN, + sizeof(struct bt_hci_rp_le_read_max_adv_data_len), + generic_success }, }; /* HCI driver open. */ diff --git a/tests/bluetooth/host/buf/CMakeLists.txt b/tests/bluetooth/host/buf/CMakeLists.txt deleted file mode 100644 index 59af3780d4f..00000000000 --- a/tests/bluetooth/host/buf/CMakeLists.txt +++ /dev/null @@ -1,20 +0,0 @@ -# -# CMakeLists.txt file for creating of mocks library. -# - -add_library(mocks STATIC - mocks/net_buf.c - mocks/iso.c - mocks/hci_core.c - mocks/net_buf_expects.c - - ${ZEPHYR_BASE}/subsys/bluetooth/host/buf.c -) - -target_include_directories(mocks PUBLIC - . - ${ZEPHYR_BASE}/tests/bluetooth/host - ${ZEPHYR_BASE}/subsys/bluetooth -) - -target_link_libraries(mocks PRIVATE test_interface) diff --git a/tests/bluetooth/host/buf/bt_buf_get_evt/CMakeLists.txt b/tests/bluetooth/host/buf/bt_buf_get_evt/CMakeLists.txt deleted file mode 100644 index 46098c51466..00000000000 --- a/tests/bluetooth/host/buf/bt_buf_get_evt/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -cmake_minimum_required(VERSION 3.20.0) - -project(bluetooth_bt_buf_get_evt) - -find_package(Zephyr COMPONENTS unittest REQUIRED HINTS $ENV{ZEPHYR_BASE}) - -add_subdirectory(${ZEPHYR_BASE}/tests/bluetooth/host host_mocks) -add_subdirectory(${ZEPHYR_BASE}/tests/bluetooth/host/buf mocks) - -target_link_libraries(testbinary PRIVATE mocks host_mocks) -target_sources(testbinary - PRIVATE - src/main.c - src/test_suite_hci_evt_cmd.c - src/test_suite_hci_evt_num_completed_packets.c -) diff --git a/tests/bluetooth/host/buf/bt_buf_get_evt/prj.conf b/tests/bluetooth/host/buf/bt_buf_get_evt/prj.conf deleted file mode 100644 index 652e7e5d169..00000000000 --- a/tests/bluetooth/host/buf/bt_buf_get_evt/prj.conf +++ /dev/null @@ -1,5 +0,0 @@ -CONFIG_ZTEST=y -CONFIG_BT=y -CONFIG_ASSERT=y -CONFIG_ASSERT_LEVEL=2 -CONFIG_ASSERT_VERBOSE=y diff --git a/tests/bluetooth/host/buf/bt_buf_get_evt/src/main.c b/tests/bluetooth/host/buf/bt_buf_get_evt/src/main.c deleted file mode 100644 index a17aee2b204..00000000000 --- a/tests/bluetooth/host/buf/bt_buf_get_evt/src/main.c +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright (c) 2022 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include -#include "mocks/net_buf.h" -#include "mocks/net_buf_expects.h" -#include "mocks/buf_help_utils.h" - -DEFINE_FFF_GLOBALS; - -/* Rows count equals number of events x 2 */ -#define TEST_PARAMETERS_LUT_ROWS_COUNT 60 - -/* LUT containing testing parameters that will be used - * during each iteration to cover different scenarios - */ -static const struct testing_params testing_params_lut[] = { - TEST_PARAM_PAIR_DEFINE(BT_HCI_EVT_UNKNOWN), - TEST_PARAM_PAIR_DEFINE(BT_HCI_EVT_VENDOR), - TEST_PARAM_PAIR_DEFINE(BT_HCI_EVT_INQUIRY_COMPLETE), - TEST_PARAM_PAIR_DEFINE(BT_HCI_EVT_CONN_COMPLETE), - TEST_PARAM_PAIR_DEFINE(BT_HCI_EVT_CONN_REQUEST), - TEST_PARAM_PAIR_DEFINE(BT_HCI_EVT_DISCONN_COMPLETE), - TEST_PARAM_PAIR_DEFINE(BT_HCI_EVT_AUTH_COMPLETE), - TEST_PARAM_PAIR_DEFINE(BT_HCI_EVT_REMOTE_NAME_REQ_COMPLETE), - TEST_PARAM_PAIR_DEFINE(BT_HCI_EVT_ENCRYPT_CHANGE), - TEST_PARAM_PAIR_DEFINE(BT_HCI_EVT_REMOTE_FEATURES), - TEST_PARAM_PAIR_DEFINE(BT_HCI_EVT_REMOTE_VERSION_INFO), - TEST_PARAM_PAIR_DEFINE(BT_HCI_EVT_HARDWARE_ERROR), - TEST_PARAM_PAIR_DEFINE(BT_HCI_EVT_ROLE_CHANGE), - TEST_PARAM_PAIR_DEFINE(BT_HCI_EVT_PIN_CODE_REQ), - TEST_PARAM_PAIR_DEFINE(BT_HCI_EVT_LINK_KEY_REQ), - TEST_PARAM_PAIR_DEFINE(BT_HCI_EVT_LINK_KEY_NOTIFY), - TEST_PARAM_PAIR_DEFINE(BT_HCI_EVT_DATA_BUF_OVERFLOW), - TEST_PARAM_PAIR_DEFINE(BT_HCI_EVT_INQUIRY_RESULT_WITH_RSSI), - TEST_PARAM_PAIR_DEFINE(BT_HCI_EVT_REMOTE_EXT_FEATURES), - TEST_PARAM_PAIR_DEFINE(BT_HCI_EVT_SYNC_CONN_COMPLETE), - TEST_PARAM_PAIR_DEFINE(BT_HCI_EVT_EXTENDED_INQUIRY_RESULT), - TEST_PARAM_PAIR_DEFINE(BT_HCI_EVT_ENCRYPT_KEY_REFRESH_COMPLETE), - TEST_PARAM_PAIR_DEFINE(BT_HCI_EVT_IO_CAPA_REQ), - TEST_PARAM_PAIR_DEFINE(BT_HCI_EVT_IO_CAPA_RESP), - TEST_PARAM_PAIR_DEFINE(BT_HCI_EVT_USER_CONFIRM_REQ), - TEST_PARAM_PAIR_DEFINE(BT_HCI_EVT_USER_PASSKEY_REQ), - TEST_PARAM_PAIR_DEFINE(BT_HCI_EVT_SSP_COMPLETE), - TEST_PARAM_PAIR_DEFINE(BT_HCI_EVT_USER_PASSKEY_NOTIFY), - TEST_PARAM_PAIR_DEFINE(BT_HCI_EVT_LE_META_EVENT), - TEST_PARAM_PAIR_DEFINE(BT_HCI_EVT_AUTH_PAYLOAD_TIMEOUT_EXP) -}; - -BUILD_ASSERT(ARRAY_SIZE(testing_params_lut) == TEST_PARAMETERS_LUT_ROWS_COUNT); - -ZTEST_SUITE(bt_buf_get_evt_default_events_returns_not_null, NULL, NULL, NULL, NULL, NULL); -ZTEST_SUITE(bt_buf_get_evt_default_events_returns_null, NULL, NULL, NULL, NULL, NULL); - -/* Return the memory pool used for event memory allocation - * based on compilation flags - */ -static struct net_buf_pool *get_memory_pool(bool discardable) -{ - struct net_buf_pool *memory_pool; - - if ((IS_ENABLED(CONFIG_BT_HCI_ACL_FLOW_CONTROL))) { - memory_pool = bt_buf_get_evt_pool(); - } else { - memory_pool = bt_buf_get_hci_rx_pool(); - } - - if (discardable) { - memory_pool = bt_buf_get_discardable_pool(); - } - - return memory_pool; -} - -/* - * Return value from bt_buf_get_evt() should not be NULL - * - * Constraints: - * - All events except 'BT_HCI_EVT_CMD_COMPLETE', 'BT_HCI_EVT_CMD_STATUS' or - * 'BT_HCI_EVT_NUM_COMPLETED_PACKETS' - * - Timeout value is a positive non-zero value - * - * Expected behaviour: - * - net_buf_alloc() to be called with the correct memory allocation pool - * and the same timeout value passed to bt_buf_get_evt() - * - bt_buf_get_evt() returns the same reference returned by net_buf_alloc_fixed() - */ -ZTEST(bt_buf_get_evt_default_events_returns_not_null, test_returns_not_null) -{ - const size_t user_data_size = sizeof(struct bt_buf_data); - uint8_t expected_buf_data[sizeof(struct net_buf) + user_data_size]; - struct net_buf *expected_buf = (struct net_buf *)expected_buf_data; - struct net_buf *returned_buf; - uint8_t returned_buffer_type; - k_timeout_t timeout = Z_TIMEOUT_TICKS(1000); - struct testing_params const *params_vector; - uint8_t evt; - bool discardable; - - expected_buf->user_data_size = user_data_size; - - for (size_t i = 0; i < (ARRAY_SIZE(testing_params_lut)); i++) { - - /* Register resets */ - NET_BUF_FFF_FAKES_LIST(RESET_FAKE); - - params_vector = &testing_params_lut[i]; - evt = params_vector->evt; - discardable = params_vector->discardable; - - zassert_true((evt != BT_HCI_EVT_CMD_COMPLETE && evt != BT_HCI_EVT_CMD_STATUS && - evt != BT_HCI_EVT_NUM_COMPLETED_PACKETS), - "Invalid event type %u to this test", evt); - - net_buf_alloc_fixed_fake.return_val = expected_buf; - - returned_buf = bt_buf_get_evt(evt, discardable, timeout); - - expect_single_call_net_buf_alloc(get_memory_pool(discardable), &timeout); - expect_single_call_net_buf_reserve(expected_buf); - expect_not_called_net_buf_ref(); - - zassert_equal(returned_buf, expected_buf, - "bt_buf_get_evt() returned incorrect buffer pointer value"); - - returned_buffer_type = bt_buf_get_type(returned_buf); - zassert_equal(returned_buffer_type, BT_BUF_EVT, - "bt_buf_get_evt() returned incorrect buffer type %u, expected %u (%s)", - returned_buffer_type, BT_BUF_EVT, STRINGIFY(BT_BUF_EVT)); - } -} - -/* - * Return value from bt_buf_get_evt() should be NULL - * - * Constraints: - * - All events except 'BT_HCI_EVT_CMD_COMPLETE', 'BT_HCI_EVT_CMD_STATUS' or - * 'BT_HCI_EVT_NUM_COMPLETED_PACKETS' - * - Timeout value is a positive non-zero value - * - * Expected behaviour: - * - net_buf_alloc() to be called with the correct memory allocation pool - * and the same timeout value passed to bt_buf_get_evt() - * - bt_buf_get_evt() returns NULL - */ -ZTEST(bt_buf_get_evt_default_events_returns_null, test_returns_null) -{ - struct net_buf *returned_buf; - k_timeout_t timeout = Z_TIMEOUT_TICKS(1000); - struct testing_params const *params_vector; - uint8_t evt; - bool discardable; - - for (size_t i = 0; i < (ARRAY_SIZE(testing_params_lut)); i++) { - - /* Register resets */ - NET_BUF_FFF_FAKES_LIST(RESET_FAKE); - - params_vector = &testing_params_lut[i]; - evt = params_vector->evt; - discardable = params_vector->discardable; - - zassert_true((evt != BT_HCI_EVT_CMD_COMPLETE && evt != BT_HCI_EVT_CMD_STATUS && - evt != BT_HCI_EVT_NUM_COMPLETED_PACKETS), - "Invalid event type %u to this test", evt); - - net_buf_alloc_fixed_fake.return_val = NULL; - - returned_buf = bt_buf_get_evt(evt, discardable, timeout); - - expect_single_call_net_buf_alloc(get_memory_pool(discardable), &timeout); - expect_not_called_net_buf_reserve(); - expect_not_called_net_buf_ref(); - - zassert_is_null(returned_buf, - "bt_buf_get_evt() returned non-NULL value while expecting NULL"); - } -} diff --git a/tests/bluetooth/host/buf/bt_buf_get_evt/src/test_suite_hci_evt_cmd.c b/tests/bluetooth/host/buf/bt_buf_get_evt/src/test_suite_hci_evt_cmd.c deleted file mode 100644 index 2c4d2fed7aa..00000000000 --- a/tests/bluetooth/host/buf/bt_buf_get_evt/src/test_suite_hci_evt_cmd.c +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2022 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include -#include "mocks/net_buf.h" -#include "mocks/net_buf_expects.h" -#include "mocks/buf_help_utils.h" - -/* Rows count equals number of events x 2 */ -#define TEST_PARAMETERS_LUT_ROWS_COUNT 4 - -/* LUT containing testing parameters that will be used - * during each iteration to cover different scenarios - */ -static const struct testing_params testing_params_lut[] = { - TEST_PARAM_PAIR_DEFINE(BT_HCI_EVT_CMD_COMPLETE), - TEST_PARAM_PAIR_DEFINE(BT_HCI_EVT_CMD_STATUS) -}; - -BUILD_ASSERT(ARRAY_SIZE(testing_params_lut) == TEST_PARAMETERS_LUT_ROWS_COUNT); - -/* Return the memory pool used for event memory allocation - * based on compilation flags - */ -static struct net_buf_pool *get_memory_pool(void) -{ - struct net_buf_pool *memory_pool; - - if ((IS_ENABLED(CONFIG_BT_HCI_ACL_FLOW_CONTROL))) { - memory_pool = bt_buf_get_evt_pool(); - } else { - memory_pool = bt_buf_get_hci_rx_pool(); - } - - return memory_pool; -} diff --git a/tests/bluetooth/host/buf/bt_buf_get_evt/src/test_suite_hci_evt_num_completed_packets.c b/tests/bluetooth/host/buf/bt_buf_get_evt/src/test_suite_hci_evt_num_completed_packets.c deleted file mode 100644 index c7f9f716b88..00000000000 --- a/tests/bluetooth/host/buf/bt_buf_get_evt/src/test_suite_hci_evt_num_completed_packets.c +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright (c) 2022 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include "mocks/net_buf.h" -#include "mocks/net_buf_expects.h" -#include "mocks/buf_help_utils.h" - -/* Rows count equals number of events x 2 */ -#define TEST_PARAMETERS_LUT_ROWS_COUNT 2 - -/* LUT containing testing parameters that will be used - * during each iteration to cover different scenarios - */ -static const struct testing_params testing_params_lut[] = { - TEST_PARAM_PAIR_DEFINE(BT_HCI_EVT_NUM_COMPLETED_PACKETS), -}; - -BUILD_ASSERT(ARRAY_SIZE(testing_params_lut) == TEST_PARAMETERS_LUT_ROWS_COUNT); - -/* Return the memory pool used for event memory allocation - * based on compilation flags - */ -static struct net_buf_pool *get_memory_pool(bool discardable) -{ - struct net_buf_pool *memory_pool; - - if ((IS_ENABLED(CONFIG_BT_HCI_ACL_FLOW_CONTROL))) { - memory_pool = bt_buf_get_evt_pool(); - } else { - memory_pool = bt_buf_get_hci_rx_pool(); - } - - if ((IS_ENABLED(CONFIG_BT_CONN) || IS_ENABLED(CONFIG_BT_ISO))) { - memory_pool = bt_buf_get_num_complete_pool(); - } else { - if (discardable) { - memory_pool = bt_buf_get_discardable_pool(); - } - } - - return memory_pool; -} - -ZTEST_SUITE(bt_buf_get_evt_num_completed_pkts_type, NULL, NULL, NULL, NULL, NULL); - -/* - * Return value from bt_buf_get_evt() should not be NULL - * - * Constraints: - * - Only event type 'BT_HCI_EVT_NUM_COMPLETED_PACKETS' - * - Timeout value is a positive non-zero value - * - * Expected behaviour: - * - net_buf_alloc() to be called with the correct memory allocation pool - * and the same timeout value passed to bt_buf_get_evt() - * - bt_buf_get_evt() returns the same reference returned by net_buf_alloc_fixed() - */ -ZTEST(bt_buf_get_evt_num_completed_pkts_type, test_returns_not_null) -{ - const size_t user_data_size = sizeof(struct bt_buf_data); - uint8_t *expected_buf_data[sizeof(struct net_buf) + user_data_size]; - struct net_buf *expected_buf = (struct net_buf *)expected_buf_data; - struct net_buf *returned_buf; - uint8_t returned_buffer_type; - k_timeout_t timeout = Z_TIMEOUT_TICKS(1000); - struct testing_params const *params_vector; - uint8_t evt; - bool discardable; - - expected_buf->user_data_size = user_data_size; - - for (size_t i = 0; i < (ARRAY_SIZE(testing_params_lut)); i++) { - - /* Register resets */ - NET_BUF_FFF_FAKES_LIST(RESET_FAKE); - - params_vector = &testing_params_lut[i]; - evt = params_vector->evt; - discardable = params_vector->discardable; - - zassert_true((evt == BT_HCI_EVT_NUM_COMPLETED_PACKETS), - "Invalid event type %u to this test", evt); - - net_buf_alloc_fixed_fake.return_val = expected_buf; - - returned_buf = bt_buf_get_evt(evt, discardable, timeout); - - expect_single_call_net_buf_alloc(get_memory_pool(discardable), &timeout); - expect_single_call_net_buf_reserve(expected_buf); - expect_not_called_net_buf_ref(); - - zassert_equal(returned_buf, expected_buf, - "bt_buf_get_evt() returned incorrect buffer pointer value"); - - returned_buffer_type = bt_buf_get_type(returned_buf); - zassert_equal(returned_buffer_type, BT_BUF_EVT, - "bt_buf_get_evt() returned incorrect buffer type %u, expected %u (%s)", - returned_buffer_type, BT_BUF_EVT, STRINGIFY(BT_BUF_EVT)); - } -} - -/* - * Return value from bt_buf_get_evt() should be NULL - * - * Constraints: - * - Only event type 'BT_HCI_EVT_NUM_COMPLETED_PACKETS' - * - Timeout value is a positive non-zero value - * - * Expected behaviour: - * - net_buf_alloc() to be called with the correct memory allocation pool - * and the same timeout value passed to bt_buf_get_evt() - * - bt_buf_get_evt() returns NULL - */ -ZTEST(bt_buf_get_evt_num_completed_pkts_type, test_returns_null) -{ - struct net_buf *returned_buf; - k_timeout_t timeout = Z_TIMEOUT_TICKS(1000); - struct testing_params const *params_vector; - uint8_t evt; - bool discardable; - - for (size_t i = 0; i < (ARRAY_SIZE(testing_params_lut)); i++) { - - /* Register resets */ - NET_BUF_FFF_FAKES_LIST(RESET_FAKE); - - params_vector = &testing_params_lut[i]; - evt = params_vector->evt; - discardable = params_vector->discardable; - - zassert_true((evt == BT_HCI_EVT_NUM_COMPLETED_PACKETS), - "Invalid event type %u to this test", evt); - - net_buf_alloc_fixed_fake.return_val = NULL; - - returned_buf = bt_buf_get_evt(evt, discardable, timeout); - - expect_single_call_net_buf_alloc(get_memory_pool(discardable), &timeout); - expect_not_called_net_buf_reserve(); - expect_not_called_net_buf_ref(); - - zassert_is_null(returned_buf, - "bt_buf_get_evt() returned non-NULL value while expecting NULL"); - } -} diff --git a/tests/bluetooth/host/buf/bt_buf_get_evt/testcase.yaml b/tests/bluetooth/host/buf/bt_buf_get_evt/testcase.yaml deleted file mode 100644 index 2b7cf5aa414..00000000000 --- a/tests/bluetooth/host/buf/bt_buf_get_evt/testcase.yaml +++ /dev/null @@ -1,21 +0,0 @@ -common: - tags: - - bluetooth - - host -tests: - bluetooth.host.bt_buf_get_evt.default: - type: unit - bluetooth.host.bt_buf_get_evt.hci_acl_flow_control: - type: unit - extra_configs: - - CONFIG_BT_CENTRAL=y - - CONFIG_BT_HCI_ACL_FLOW_CONTROL=y - bluetooth.host.bt_buf_get_evt.iso_unicast: - type: unit - # enable CONFIG_BT_ISO_UNICAST - extra_configs: - - CONFIG_BT_ISO_CENTRAL=y - bluetooth.host.bt_buf_get_evt.iso_sync_receiver: - type: unit - extra_configs: - - CONFIG_BT_ISO_SYNC_RECEIVER=y diff --git a/tests/bluetooth/host/buf/bt_buf_get_rx/CMakeLists.txt b/tests/bluetooth/host/buf/bt_buf_get_rx/CMakeLists.txt deleted file mode 100644 index d657ec82060..00000000000 --- a/tests/bluetooth/host/buf/bt_buf_get_rx/CMakeLists.txt +++ /dev/null @@ -1,17 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -cmake_minimum_required(VERSION 3.20.0) - -project(bluetooth_bt_buf_get_rx) - -find_package(Zephyr COMPONENTS unittest REQUIRED HINTS $ENV{ZEPHYR_BASE}) - -add_subdirectory(${ZEPHYR_BASE}/tests/bluetooth/host host_mocks) -add_subdirectory(${ZEPHYR_BASE}/tests/bluetooth/host/buf mocks) - -target_link_libraries(testbinary PRIVATE mocks host_mocks) -target_sources(testbinary - PRIVATE - src/main.c - src/test_suite_invalid_inputs.c -) diff --git a/tests/bluetooth/host/buf/bt_buf_get_rx/prj.conf b/tests/bluetooth/host/buf/bt_buf_get_rx/prj.conf deleted file mode 100644 index 652e7e5d169..00000000000 --- a/tests/bluetooth/host/buf/bt_buf_get_rx/prj.conf +++ /dev/null @@ -1,5 +0,0 @@ -CONFIG_ZTEST=y -CONFIG_BT=y -CONFIG_ASSERT=y -CONFIG_ASSERT_LEVEL=2 -CONFIG_ASSERT_VERBOSE=y diff --git a/tests/bluetooth/host/buf/bt_buf_get_rx/src/main.c b/tests/bluetooth/host/buf/bt_buf_get_rx/src/main.c deleted file mode 100644 index 4324d75dde5..00000000000 --- a/tests/bluetooth/host/buf/bt_buf_get_rx/src/main.c +++ /dev/null @@ -1,289 +0,0 @@ -/* - * Copyright (c) 2022 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include -#include "mocks/net_buf.h" -#include "mocks/net_buf_expects.h" -#include "mocks/buf_help_utils.h" - -DEFINE_FFF_GLOBALS; - -static void tc_setup(void *f) -{ - /* Register resets */ - NET_BUF_FFF_FAKES_LIST(RESET_FAKE); -} - -ZTEST_SUITE(test_bt_buf_get_rx_returns_null, NULL, NULL, tc_setup, NULL, NULL); -ZTEST_SUITE(test_bt_buf_get_rx_returns_not_null, NULL, NULL, tc_setup, NULL, NULL); - -/* - * Return value from bt_buf_get_rx() should be NULL - * - * This is to test the behaviour when memory allocation request fails - * - * Constraints: - * - Use valid buffer type 'BT_BUF_EVT' - * - Timeout value is a positive non-zero value - * - net_buf_alloc() returns a NULL value - * - * Expected behaviour: - * - net_buf_alloc() to be called with the correct memory allocation pool - * and the same timeout value passed to bt_buf_get_rx() - * - bt_buf_get_rx() returns NULL - */ -ZTEST(test_bt_buf_get_rx_returns_null, test_returns_null_type_bt_buf_evt) -{ - struct net_buf *returned_buf; - k_timeout_t timeout = Z_TIMEOUT_TICKS(1000); - - struct net_buf_pool *memory_pool; - - if ((IS_ENABLED(CONFIG_BT_HCI_ACL_FLOW_CONTROL))) { - memory_pool = bt_buf_get_evt_pool(); - } else { - memory_pool = bt_buf_get_hci_rx_pool(); - } - - net_buf_alloc_fixed_fake.return_val = NULL; - - returned_buf = bt_buf_get_rx(BT_BUF_EVT, timeout); - - expect_single_call_net_buf_alloc(memory_pool, &timeout); - expect_not_called_net_buf_reserve(); - expect_not_called_net_buf_ref(); - - zassert_is_null(returned_buf, - "bt_buf_get_rx() returned non-NULL value while expecting NULL"); -} - -/* - * Return value from bt_buf_get_rx() should be NULL - * - * This is to test the behaviour when memory allocation request fails - * - * Constraints: - * - Use valid buffer type 'BT_BUF_ACL_IN' - * - Timeout value is a positive non-zero value - * - net_buf_alloc() returns a NULL value - * - * Expected behaviour: - * - net_buf_alloc() to be called with the correct memory allocation pool - * and the same timeout value passed to bt_buf_get_rx() - * - bt_buf_get_rx() returns NULL - */ -ZTEST(test_bt_buf_get_rx_returns_null, test_returns_null_type_bt_buf_acl_in) -{ - struct net_buf *returned_buf; - k_timeout_t timeout = Z_TIMEOUT_TICKS(1000); - - struct net_buf_pool *memory_pool; - - if ((IS_ENABLED(CONFIG_BT_HCI_ACL_FLOW_CONTROL))) { - memory_pool = bt_buf_get_acl_in_pool(); - } else { - memory_pool = bt_buf_get_hci_rx_pool(); - } - - net_buf_alloc_fixed_fake.return_val = NULL; - - returned_buf = bt_buf_get_rx(BT_BUF_ACL_IN, timeout); - - expect_single_call_net_buf_alloc(memory_pool, &timeout); - expect_not_called_net_buf_reserve(); - expect_not_called_net_buf_ref(); - - zassert_is_null(returned_buf, - "bt_buf_get_rx() returned non-NULL value while expecting NULL"); -} - -/* - * Return value from bt_buf_get_rx() should be NULL - * - * This is to test the behaviour when memory allocation request fails - * - * Constraints: - * - Use valid buffer type 'BT_BUF_ISO_IN' - * - Timeout value is a positive non-zero value - * - net_buf_alloc() returns a NULL value - * - * Expected behaviour: - * - net_buf_alloc() to be called with the correct memory allocation pool - * and the same timeout value passed to bt_buf_get_rx() - * - bt_buf_get_rx() returns NULL - */ -ZTEST(test_bt_buf_get_rx_returns_null, test_returns_null_type_bt_buf_iso_in) -{ - struct net_buf *returned_buf; - k_timeout_t timeout = Z_TIMEOUT_TICKS(1000); - - struct net_buf_pool *memory_pool; - - if ((IS_ENABLED(CONFIG_BT_ISO_UNICAST) || IS_ENABLED(CONFIG_BT_ISO_SYNC_RECEIVER))) { - memory_pool = bt_buf_get_iso_rx_pool(); - } else { - if ((IS_ENABLED(CONFIG_BT_HCI_ACL_FLOW_CONTROL))) { - memory_pool = bt_buf_get_acl_in_pool(); - } else { - memory_pool = bt_buf_get_hci_rx_pool(); - } - } - - net_buf_alloc_fixed_fake.return_val = NULL; - - returned_buf = bt_buf_get_rx(BT_BUF_ISO_IN, timeout); - - expect_single_call_net_buf_alloc(memory_pool, &timeout); - expect_not_called_net_buf_reserve(); - expect_not_called_net_buf_ref(); - - zassert_is_null(returned_buf, - "bt_buf_get_rx() returned non-NULL value while expecting NULL"); -} - -/* - * Return value from bt_buf_get_rx() shouldn't be NULL - * - * Constraints: - * - Use valid buffer type 'BT_BUF_EVT' - * - Timeout value is a positive non-zero value - * - net_buf_alloc() return a not NULL value - * - * Expected behaviour: - * - net_buf_alloc() to be called with the correct memory allocation pool - * and the same timeout value passed to bt_buf_get_rx() - * - bt_buf_get_rx() returns the same value returned by net_buf_alloc_fixed() - * - Return buffer matches the buffer type requested - */ -ZTEST(test_bt_buf_get_rx_returns_not_null, test_returns_not_null_type_bt_buf_evt) -{ - static struct net_buf expected_buf; - struct net_buf *returned_buf; - uint8_t returned_buffer_type; - k_timeout_t timeout = Z_TIMEOUT_TICKS(1000); - - struct net_buf_pool *memory_pool; - - if ((IS_ENABLED(CONFIG_BT_HCI_ACL_FLOW_CONTROL))) { - memory_pool = bt_buf_get_evt_pool(); - } else { - memory_pool = bt_buf_get_hci_rx_pool(); - } - - net_buf_alloc_fixed_fake.return_val = &expected_buf; - - returned_buf = bt_buf_get_rx(BT_BUF_EVT, timeout); - - expect_single_call_net_buf_alloc(memory_pool, &timeout); - expect_single_call_net_buf_reserve(&expected_buf); - expect_not_called_net_buf_ref(); - - zassert_equal(returned_buf, &expected_buf, - "bt_buf_get_rx() returned incorrect buffer pointer value"); - - returned_buffer_type = bt_buf_get_type(returned_buf); - zassert_equal(returned_buffer_type, BT_BUF_EVT, - "bt_buf_get_rx() returned incorrect buffer type %u, expected %u (%s)", - returned_buffer_type, BT_BUF_EVT, STRINGIFY(BT_BUF_EVT)); -} - -/* - * Return value from bt_buf_get_rx() shouldn't be NULL - * - * Constraints: - * - Use valid buffer type 'BT_BUF_ACL_IN' - * - Timeout value is a positive non-zero value - * - net_buf_alloc() return a not NULL value - * - * Expected behaviour: - * - net_buf_alloc() to be called with the correct memory allocation pool - * and the same timeout value passed to bt_buf_get_rx() - * - bt_buf_get_rx() returns the same value returned by net_buf_alloc_fixed() - * - Return buffer matches the buffer type requested - */ -ZTEST(test_bt_buf_get_rx_returns_not_null, test_returns_not_null_type_bt_buf_acl_in) -{ - static struct net_buf expected_buf; - struct net_buf *returned_buf; - uint8_t returned_buffer_type; - k_timeout_t timeout = Z_TIMEOUT_TICKS(1000); - - struct net_buf_pool *memory_pool; - - if ((IS_ENABLED(CONFIG_BT_HCI_ACL_FLOW_CONTROL))) { - memory_pool = bt_buf_get_acl_in_pool(); - } else { - memory_pool = bt_buf_get_hci_rx_pool(); - } - - net_buf_alloc_fixed_fake.return_val = &expected_buf; - - returned_buf = bt_buf_get_rx(BT_BUF_ACL_IN, timeout); - - expect_single_call_net_buf_alloc(memory_pool, &timeout); - expect_single_call_net_buf_reserve(&expected_buf); - expect_not_called_net_buf_ref(); - - zassert_equal(returned_buf, &expected_buf, - "bt_buf_get_rx() returned incorrect buffer pointer value"); - - returned_buffer_type = bt_buf_get_type(returned_buf); - zassert_equal(returned_buffer_type, BT_BUF_ACL_IN, - "bt_buf_get_rx() returned incorrect buffer type %u, expected %u (%s)", - returned_buffer_type, BT_BUF_ACL_IN, STRINGIFY(BT_BUF_ACL_IN)); -} - -/* - * Return value from bt_buf_get_rx() shouldn't be NULL - * - * Constraints: - * - Use valid buffer type 'BT_BUF_ISO_IN' - * - Timeout value is a positive non-zero value - * - net_buf_alloc() return a not NULL value - * - * Expected behaviour: - * - net_buf_alloc() to be called with the correct memory allocation pool - * and the same timeout value passed to bt_buf_get_rx() - * - bt_buf_get_rx() returns the same value returned by net_buf_alloc_fixed() - * - Return buffer matches the buffer type requested - */ -ZTEST(test_bt_buf_get_rx_returns_not_null, test_returns_not_null_type_bt_buf_iso_in) -{ - static struct net_buf expected_buf; - struct net_buf *returned_buf; - uint8_t returned_buffer_type; - k_timeout_t timeout = Z_TIMEOUT_TICKS(1000); - - struct net_buf_pool *memory_pool; - - if ((IS_ENABLED(CONFIG_BT_ISO_UNICAST) || IS_ENABLED(CONFIG_BT_ISO_SYNC_RECEIVER))) { - memory_pool = bt_buf_get_iso_rx_pool(); - } else { - if ((IS_ENABLED(CONFIG_BT_HCI_ACL_FLOW_CONTROL))) { - memory_pool = bt_buf_get_acl_in_pool(); - } else { - memory_pool = bt_buf_get_hci_rx_pool(); - } - } - - net_buf_alloc_fixed_fake.return_val = &expected_buf; - - returned_buf = bt_buf_get_rx(BT_BUF_ISO_IN, timeout); - - expect_single_call_net_buf_alloc(memory_pool, &timeout); - expect_single_call_net_buf_reserve(&expected_buf); - expect_not_called_net_buf_ref(); - - zassert_equal(returned_buf, &expected_buf, - "bt_buf_get_rx() returned incorrect buffer pointer value"); - - returned_buffer_type = bt_buf_get_type(returned_buf); - zassert_equal(returned_buffer_type, BT_BUF_ISO_IN, - "bt_buf_get_rx() returned incorrect buffer type %u, expected %u (%s)", - returned_buffer_type, BT_BUF_ISO_IN, STRINGIFY(BT_BUF_ISO_IN)); -} diff --git a/tests/bluetooth/host/buf/bt_buf_get_rx/src/test_suite_invalid_inputs.c b/tests/bluetooth/host/buf/bt_buf_get_rx/src/test_suite_invalid_inputs.c deleted file mode 100644 index 5034c34d013..00000000000 --- a/tests/bluetooth/host/buf/bt_buf_get_rx/src/test_suite_invalid_inputs.c +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2022 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include "host_mocks/assert.h" - -ZTEST_SUITE(test_bt_buf_get_rx_invalid_input, NULL, NULL, NULL, NULL, NULL); - -/* - * Test passing invalid buffer type to bt_buf_get_rx() - * - * Constraints: - * - Use invalid buffer type 'BT_BUF_CMD' - * - * Expected behaviour: - * - An assertion should be raised as an invalid parameter was used - */ -ZTEST(test_bt_buf_get_rx_invalid_input, test_invalid_input_type_bt_buf_cmd) -{ - expect_assert(); - bt_buf_get_rx(BT_BUF_CMD, Z_TIMEOUT_TICKS(1000)); -} - -/* - * Test passing invalid buffer type to bt_buf_get_rx() - * - * Constraints: - * - Use invalid buffer type 'BT_BUF_ACL_OUT' - * - * Expected behaviour: - * - An assertion should be raised as an invalid parameter was used - */ -ZTEST(test_bt_buf_get_rx_invalid_input, test_invalid_input_type_bt_buf_acl_out) -{ - expect_assert(); - bt_buf_get_rx(BT_BUF_ACL_OUT, Z_TIMEOUT_TICKS(1000)); -} - -/* - * Test passing invalid buffer type to bt_buf_get_rx() - * - * Constraints: - * - Use invalid buffer type 'BT_BUF_ISO_OUT' - * - * Expected behaviour: - * - An assertion should be raised as an invalid parameter was used - */ -ZTEST(test_bt_buf_get_rx_invalid_input, test_invalid_input_type_bt_buf_iso_out) -{ - expect_assert(); - bt_buf_get_rx(BT_BUF_ISO_OUT, Z_TIMEOUT_TICKS(1000)); -} - -/* - * Test passing invalid buffer type to bt_buf_get_rx() - * - * Constraints: - * - Use invalid buffer type 'BT_BUF_H4' - * - * Expected behaviour: - * - An assertion should be raised as an invalid parameter was used - */ -ZTEST(test_bt_buf_get_rx_invalid_input, test_invalid_input_type_bt_buf_h4) -{ - expect_assert(); - bt_buf_get_rx(BT_BUF_H4, Z_TIMEOUT_TICKS(1000)); -} diff --git a/tests/bluetooth/host/buf/bt_buf_get_rx/testcase.yaml b/tests/bluetooth/host/buf/bt_buf_get_rx/testcase.yaml deleted file mode 100644 index bfe1120055e..00000000000 --- a/tests/bluetooth/host/buf/bt_buf_get_rx/testcase.yaml +++ /dev/null @@ -1,21 +0,0 @@ -common: - tags: - - bluetooth - - host -tests: - bluetooth.host.bt_buf_get_rx.default: - type: unit - bluetooth.host.bt_buf_get_rx.hci_acl_flow_control: - type: unit - extra_configs: - - CONFIG_BT_CENTRAL=y - - CONFIG_BT_HCI_ACL_FLOW_CONTROL=y - bluetooth.host.bt_buf_get_rx.iso_unicast: - type: unit - # enable CONFIG_BT_ISO_UNICAST - extra_configs: - - CONFIG_BT_ISO_CENTRAL=y - bluetooth.host.bt_buf_get_rx.iso_sync_receiver: - type: unit - extra_configs: - - CONFIG_BT_ISO_SYNC_RECEIVER=y diff --git a/tests/bluetooth/host/buf/bt_buf_get_type/CMakeLists.txt b/tests/bluetooth/host/buf/bt_buf_get_type/CMakeLists.txt deleted file mode 100644 index 0b1f50a25af..00000000000 --- a/tests/bluetooth/host/buf/bt_buf_get_type/CMakeLists.txt +++ /dev/null @@ -1,16 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -cmake_minimum_required(VERSION 3.20.0) - -project(bluetooth_bt_buf_get_type) - -find_package(Zephyr COMPONENTS unittest REQUIRED HINTS $ENV{ZEPHYR_BASE}) - -add_subdirectory(${ZEPHYR_BASE}/tests/bluetooth/host host_mocks) -add_subdirectory(${ZEPHYR_BASE}/tests/bluetooth/host/buf mocks) - -target_link_libraries(testbinary PRIVATE mocks host_mocks) -target_sources(testbinary - PRIVATE - src/main.c -) diff --git a/tests/bluetooth/host/buf/bt_buf_get_type/prj.conf b/tests/bluetooth/host/buf/bt_buf_get_type/prj.conf deleted file mode 100644 index 652e7e5d169..00000000000 --- a/tests/bluetooth/host/buf/bt_buf_get_type/prj.conf +++ /dev/null @@ -1,5 +0,0 @@ -CONFIG_ZTEST=y -CONFIG_BT=y -CONFIG_ASSERT=y -CONFIG_ASSERT_LEVEL=2 -CONFIG_ASSERT_VERBOSE=y diff --git a/tests/bluetooth/host/buf/bt_buf_get_type/src/main.c b/tests/bluetooth/host/buf/bt_buf_get_type/src/main.c deleted file mode 100644 index 2b5f49e0cfe..00000000000 --- a/tests/bluetooth/host/buf/bt_buf_get_type/src/main.c +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2022 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include -#include - -DEFINE_FFF_GLOBALS; - -/* Rows count equals number of types */ -#define TEST_PARAMETERS_LUT_ROWS_COUNT 7 - -/* LUT containing testing parameters that will be used - * during each iteration to cover different scenarios - */ -static const enum bt_buf_type testing_params_lut[] = { - /** HCI command */ - BT_BUF_CMD, - /** HCI event */ - BT_BUF_EVT, - /** Outgoing ACL data */ - BT_BUF_ACL_OUT, - /** Incoming ACL data */ - BT_BUF_ACL_IN, - /** Outgoing ISO data */ - BT_BUF_ISO_OUT, - /** Incoming ISO data */ - BT_BUF_ISO_IN, - /** H:4 data */ - BT_BUF_H4, -}; - -BUILD_ASSERT(ARRAY_SIZE(testing_params_lut) == TEST_PARAMETERS_LUT_ROWS_COUNT); - -ZTEST_SUITE(test_bt_buf_get_set_retrieve_type, NULL, NULL, NULL, NULL, NULL); - -/* - * Buffer type is set and retrieved correctly - * - * Constraints: - * - Use valid buffer buffer reference - * - Use valid buffer type - * - * Expected behaviour: - * - Buffer type field inside 'struct net_buf' is set correctly - * - Retrieving buffer type through bt_buf_get_type() returns the correct - * value - */ -ZTEST(test_bt_buf_get_set_retrieve_type, test_buffer_type_set_get_correctly) -{ - static struct net_buf testing_buffer; - struct net_buf *buf = &testing_buffer; - enum bt_buf_type current_test_buffer_type; - enum bt_buf_type buffer_type_set, returned_buffer_type; - - for (size_t i = 0; i < ARRAY_SIZE(testing_params_lut); i++) { - - current_test_buffer_type = testing_params_lut[i]; - - bt_buf_set_type(buf, current_test_buffer_type); - - returned_buffer_type = bt_buf_get_type(buf); - buffer_type_set = ((struct bt_buf_data *)net_buf_user_data(buf))->type; - - zassert_equal(buffer_type_set, current_test_buffer_type, - "Buffer type %u set by bt_buf_set_type() is incorrect, expected %u", - buffer_type_set, current_test_buffer_type); - - zassert_equal( - returned_buffer_type, current_test_buffer_type, - "Buffer type %u returned by bt_buf_get_type() is incorrect, expected %u", - returned_buffer_type, current_test_buffer_type); - } -} diff --git a/tests/bluetooth/host/buf/bt_buf_get_type/testcase.yaml b/tests/bluetooth/host/buf/bt_buf_get_type/testcase.yaml deleted file mode 100644 index d7ca762e312..00000000000 --- a/tests/bluetooth/host/buf/bt_buf_get_type/testcase.yaml +++ /dev/null @@ -1,7 +0,0 @@ -common: - tags: - - bluetooth - - host -tests: - bluetooth.host.bt_buf_get_type.default: - type: unit diff --git a/tests/bluetooth/host/buf/mocks/buf_help_utils.h b/tests/bluetooth/host/buf/mocks/buf_help_utils.h deleted file mode 100644 index aa7a420291f..00000000000 --- a/tests/bluetooth/host/buf/mocks/buf_help_utils.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2022 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include - -struct net_buf_pool *bt_buf_get_evt_pool(void); -struct net_buf_pool *bt_buf_get_acl_in_pool(void); -struct net_buf_pool *bt_buf_get_hci_rx_pool(void); -struct net_buf_pool *bt_buf_get_discardable_pool(void); -struct net_buf_pool *bt_buf_get_num_complete_pool(void); -struct net_buf_pool *bt_buf_get_discardable_pool(void); -struct net_buf_pool *bt_buf_get_num_complete_pool(void); -struct net_buf_pool *bt_buf_get_iso_rx_pool(void); - -/* LUT testing parameter item */ -struct testing_params { - uint8_t evt; /* Event type */ - bool discardable; /* Discardable flag */ -}; - -#define TEST_PARAM_PAIR_DEFINE(EVT) {EVT, true}, {EVT, false} diff --git a/tests/bluetooth/host/buf/mocks/hci_core.c b/tests/bluetooth/host/buf/mocks/hci_core.c deleted file mode 100644 index cec63240899..00000000000 --- a/tests/bluetooth/host/buf/mocks/hci_core.c +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2022 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include - -struct bt_dev bt_dev = { - .manufacturer = 0x1234, -}; - -#if defined(CONFIG_BT_HCI_ACL_FLOW_CONTROL) -void bt_hci_host_num_completed_packets(struct net_buf *buf) -{ -} -#endif diff --git a/tests/bluetooth/host/buf/mocks/iso.c b/tests/bluetooth/host/buf/mocks/iso.c deleted file mode 100644 index 3a66fad2058..00000000000 --- a/tests/bluetooth/host/buf/mocks/iso.c +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2022 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include - -/* This file doesn't contain mocks, but rather fakes of the necessary parts of - * subsys/bluetooth/host/iso.c. The API implementations that are copied here - * should be kept in sync with the original. - */ - -#if defined(CONFIG_BT_ISO_UNICAST) || defined(CONFIG_BT_ISO_SYNC_RECEIVER) -NET_BUF_POOL_FIXED_DEFINE(iso_rx_pool, CONFIG_BT_ISO_RX_BUF_COUNT, - BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_RX_MTU), 8, NULL); - -struct net_buf *bt_iso_get_rx(k_timeout_t timeout) -{ - struct net_buf *buf = net_buf_alloc(&iso_rx_pool, timeout); - - if (buf) { - net_buf_reserve(buf, BT_BUF_RESERVE); - bt_buf_set_type(buf, BT_BUF_ISO_IN); - } - - return buf; -} - -struct net_buf_pool *bt_buf_get_iso_rx_pool(void) -{ - return &iso_rx_pool; -} -#endif diff --git a/tests/bluetooth/host/buf/mocks/net_buf.c b/tests/bluetooth/host/buf/mocks/net_buf.c deleted file mode 100644 index 03490d00647..00000000000 --- a/tests/bluetooth/host/buf/mocks/net_buf.c +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2022 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include -#include - -static uint8_t *fixed_data_alloc(struct net_buf *buf, size_t *size, - k_timeout_t timeout) -{ - zassert_unreachable("Unexpected call to '%s()' occurred", __func__); - return NULL; -} - -static void fixed_data_unref(struct net_buf *buf, uint8_t *data) -{ - zassert_unreachable("Unexpected call to '%s()' occurred", __func__); -} - -const struct net_buf_data_cb net_buf_fixed_cb = { - .alloc = fixed_data_alloc, - .unref = fixed_data_unref, -}; - -DEFINE_FAKE_VALUE_FUNC(struct net_buf *, net_buf_alloc_fixed, struct net_buf_pool *, k_timeout_t); -DEFINE_FAKE_VOID_FUNC(net_buf_simple_reserve, struct net_buf_simple *, size_t); -DEFINE_FAKE_VALUE_FUNC(struct net_buf *, net_buf_ref, struct net_buf *); diff --git a/tests/bluetooth/host/buf/mocks/net_buf.h b/tests/bluetooth/host/buf/mocks/net_buf.h deleted file mode 100644 index d137f4f6d02..00000000000 --- a/tests/bluetooth/host/buf/mocks/net_buf.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (c) 2022 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include - -/* List of fakes used by this unit tester */ -#define NET_BUF_FFF_FAKES_LIST(FAKE) \ - FAKE(net_buf_alloc_fixed) \ - FAKE(net_buf_simple_reserve) \ - FAKE(net_buf_ref) - -DECLARE_FAKE_VALUE_FUNC(struct net_buf *, net_buf_alloc_fixed, struct net_buf_pool *, k_timeout_t); -DECLARE_FAKE_VOID_FUNC(net_buf_simple_reserve, struct net_buf_simple *, size_t); -DECLARE_FAKE_VALUE_FUNC(struct net_buf *, net_buf_ref, struct net_buf *); diff --git a/tests/bluetooth/host/buf/mocks/net_buf_expects.c b/tests/bluetooth/host/buf/mocks/net_buf_expects.c deleted file mode 100644 index e8930309147..00000000000 --- a/tests/bluetooth/host/buf/mocks/net_buf_expects.c +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2022 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include "mocks/net_buf.h" -#include "mocks/net_buf_expects.h" - -void expect_single_call_net_buf_alloc(struct net_buf_pool *pool, k_timeout_t *timeout) -{ - const char *func_name = "net_buf_alloc_fixed"; - - zassert_equal(net_buf_alloc_fixed_fake.call_count, 1, "'%s()' was called more than once", - func_name); - - zassert_equal_ptr(net_buf_alloc_fixed_fake.arg0_val, pool, - "'%s()' was called with incorrect '%s' value", func_name, "pool"); - - zassert_mem_equal(&net_buf_alloc_fixed_fake.arg1_val, timeout, sizeof(k_timeout_t), - "'%s()' was called with incorrect '%s' value", func_name, "timeout"); -} - -void expect_not_called_net_buf_alloc(void) -{ - const char *func_name = "net_buf_alloc_fixed"; - - zassert_equal(net_buf_alloc_fixed_fake.call_count, 0, "'%s()' was called unexpectedly", - func_name); -} - -void expect_single_call_net_buf_reserve(struct net_buf *buf) -{ - const char *func_name = "net_buf_simple_reserve"; - - zassert_equal(net_buf_simple_reserve_fake.call_count, 1, "'%s()' was called more than once", - func_name); - - zassert_equal_ptr(net_buf_simple_reserve_fake.arg0_val, &buf->b, - "'%s()' was called with incorrect '%s' value", func_name, "buf"); - - zassert_equal(net_buf_simple_reserve_fake.arg1_val, BT_BUF_RESERVE, - "'%s()' was called with incorrect '%s' value", func_name, "reserve"); -} - -void expect_not_called_net_buf_reserve(void) -{ - const char *func_name = "net_buf_simple_reserve"; - - zassert_equal(net_buf_simple_reserve_fake.call_count, 0, "'%s()' was called unexpectedly", - func_name); -} - -void expect_single_call_net_buf_ref(struct net_buf *buf) -{ - const char *func_name = "net_buf_ref"; - - zassert_equal(net_buf_ref_fake.call_count, 1, "'%s()' was called more than once", - func_name); - - zassert_equal_ptr(net_buf_ref_fake.arg0_val, buf, - "'%s()' was called with incorrect '%s' value", func_name, "buf"); -} - -void expect_not_called_net_buf_ref(void) -{ - const char *func_name = "net_buf_ref"; - - zassert_equal(net_buf_ref_fake.call_count, 0, "'%s()' was called unexpectedly", - func_name); -} diff --git a/tests/bluetooth/host/buf/mocks/net_buf_expects.h b/tests/bluetooth/host/buf/mocks/net_buf_expects.h deleted file mode 100644 index 99e84fd85be..00000000000 --- a/tests/bluetooth/host/buf/mocks/net_buf_expects.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2022 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include - -/* - * Validate expected behaviour when net_buf_alloc() is called - * - * Expected behaviour: - * - net_buf_alloc() to be called once with : - * - correct memory allocation pool - */ -void expect_single_call_net_buf_alloc(struct net_buf_pool *pool, k_timeout_t *timeout); - -/* - * Validate expected behaviour when net_buf_alloc() isn't called - * - * Expected behaviour: - * - net_buf_alloc() isn't called at all - */ -void expect_not_called_net_buf_alloc(void); - -/* - * Validate expected behaviour when net_buf_reserve() is called - * - * Expected behaviour: - * - net_buf_reserve() to be called once with : - * - correct reference value - * - 'reserve' argument set to 'BT_BUF_RESERVE' value - */ -void expect_single_call_net_buf_reserve(struct net_buf *buf); - -/* - * Validate expected behaviour when net_buf_reserve() isn't called - * - * Expected behaviour: - * - net_buf_reserve() isn't called at all - */ -void expect_not_called_net_buf_reserve(void); - -/* - * Validate expected behaviour when net_buf_ref() is called - * - * Expected behaviour: - * - net_buf_ref() to be called once with correct reference value - */ -void expect_single_call_net_buf_ref(struct net_buf *buf); - -/* - * Validate expected behaviour when net_buf_ref() isn't called - * - * Expected behaviour: - * - net_buf_ref() isn't called at all - */ -void expect_not_called_net_buf_ref(void); diff --git a/tests/bluetooth/host/id/bt_id_add/src/main.c b/tests/bluetooth/host/id/bt_id_add/src/main.c index f9b4b2ee6f3..2806414aeb1 100644 --- a/tests/bluetooth/host/id/bt_id_add/src/main.c +++ b/tests/bluetooth/host/id/bt_id_add/src/main.c @@ -119,7 +119,7 @@ ZTEST(bt_id_add, test_conn_lookup_returns_valid_conn_ref) bt_id_add(&keys); - expect_single_call_bt_conn_lookup_state_le(BT_ID_DEFAULT, NULL, BT_CONN_CONNECTING); + expect_single_call_bt_conn_lookup_state_le(BT_ID_DEFAULT, NULL, BT_CONN_INITIATING); expect_single_call_bt_conn_unref(&conn_ref); zassert_true((keys.state & BT_KEYS_ID_PENDING_ADD) == BT_KEYS_ID_PENDING_ADD, diff --git a/tests/bluetooth/host/id/bt_id_del/src/main.c b/tests/bluetooth/host/id/bt_id_del/src/main.c index 6b8dc1f19e7..55332b3c01c 100644 --- a/tests/bluetooth/host/id/bt_id_del/src/main.c +++ b/tests/bluetooth/host/id/bt_id_del/src/main.c @@ -125,7 +125,7 @@ ZTEST(bt_id_del, test_conn_lookup_returns_valid_conn_ref) bt_id_del(&keys); - expect_single_call_bt_conn_lookup_state_le(BT_ID_DEFAULT, NULL, BT_CONN_CONNECTING); + expect_single_call_bt_conn_lookup_state_le(BT_ID_DEFAULT, NULL, BT_CONN_INITIATING); expect_single_call_bt_conn_unref(&conn_ref); zassert_true((keys.state & BT_KEYS_ID_PENDING_DEL) == BT_KEYS_ID_PENDING_DEL, diff --git a/tests/bluetooth/host/id/bt_le_ext_adv_oob_get_local/src/test_suite_invalid_inputs.c b/tests/bluetooth/host/id/bt_le_ext_adv_oob_get_local/src/test_suite_invalid_inputs.c index c0e051d12b0..e3df2249328 100644 --- a/tests/bluetooth/host/id/bt_le_ext_adv_oob_get_local/src/test_suite_invalid_inputs.c +++ b/tests/bluetooth/host/id/bt_le_ext_adv_oob_get_local/src/test_suite_invalid_inputs.c @@ -115,7 +115,8 @@ ZTEST(bt_le_ext_adv_oob_get_local_invalid_inputs, test_updating_rpa_fails_while_ err = bt_le_ext_adv_oob_get_local(&adv, &oob); - expect_single_call_bt_conn_lookup_state_le(BT_ID_DEFAULT, NULL, BT_CONN_CONNECTING_SCAN); + expect_single_call_bt_conn_lookup_state_le(BT_ID_DEFAULT, NULL, + BT_CONN_SCAN_BEFORE_INITIATING); zassert_true(err == -EINVAL, "Unexpected error code '%d' was returned", err); } diff --git a/tests/bluetooth/host/id/bt_le_oob_get_local/src/test_suite_invalid_inputs.c b/tests/bluetooth/host/id/bt_le_oob_get_local/src/test_suite_invalid_inputs.c index b2d72aeb5df..477c1ac0024 100644 --- a/tests/bluetooth/host/id/bt_le_oob_get_local/src/test_suite_invalid_inputs.c +++ b/tests/bluetooth/host/id/bt_le_oob_get_local/src/test_suite_invalid_inputs.c @@ -113,7 +113,8 @@ ZTEST(bt_le_oob_get_local_invalid_inputs, test_updating_rpa_fails_while_establis err = bt_le_oob_get_local(BT_ID_DEFAULT, &oob); - expect_single_call_bt_conn_lookup_state_le(BT_ID_DEFAULT, NULL, BT_CONN_CONNECTING_SCAN); + expect_single_call_bt_conn_lookup_state_le(BT_ID_DEFAULT, NULL, + BT_CONN_SCAN_BEFORE_INITIATING); zassert_true(err == -EINVAL, "Unexpected error code '%d' was returned", err); } @@ -156,7 +157,8 @@ ZTEST(bt_le_oob_get_local_invalid_inputs, test_conn_state_checked_with_null_adv) err = bt_le_oob_get_local(BT_ID_DEFAULT, &oob); expect_single_call_bt_le_adv_lookup_legacy(); - expect_single_call_bt_conn_lookup_state_le(BT_ID_DEFAULT, NULL, BT_CONN_CONNECTING_SCAN); + expect_single_call_bt_conn_lookup_state_le(BT_ID_DEFAULT, NULL, + BT_CONN_SCAN_BEFORE_INITIATING); zassert_true(err == -EINVAL, "Unexpected error code '%d' was returned", err); } @@ -205,7 +207,8 @@ ZTEST(bt_le_oob_get_local_invalid_inputs, test_conn_state_checked_non_matched_id err = bt_le_oob_get_local(BT_ID_DEFAULT, &oob); expect_single_call_bt_le_adv_lookup_legacy(); - expect_single_call_bt_conn_lookup_state_le(BT_ID_DEFAULT, NULL, BT_CONN_CONNECTING_SCAN); + expect_single_call_bt_conn_lookup_state_le(BT_ID_DEFAULT, NULL, + BT_CONN_SCAN_BEFORE_INITIATING); zassert_true(err == -EINVAL, "Unexpected error code '%d' was returned", err); } @@ -257,7 +260,8 @@ ZTEST(bt_le_oob_get_local_invalid_inputs, test_conn_state_checked_adv_enable_not err = bt_le_oob_get_local(BT_ID_DEFAULT, &oob); expect_single_call_bt_le_adv_lookup_legacy(); - expect_single_call_bt_conn_lookup_state_le(BT_ID_DEFAULT, NULL, BT_CONN_CONNECTING_SCAN); + expect_single_call_bt_conn_lookup_state_le(BT_ID_DEFAULT, NULL, + BT_CONN_SCAN_BEFORE_INITIATING); zassert_true(err == -EINVAL, "Unexpected error code '%d' was returned", err); } @@ -309,7 +313,8 @@ ZTEST(bt_le_oob_get_local_invalid_inputs, test_conn_state_checked_adv_use_identi err = bt_le_oob_get_local(BT_ID_DEFAULT, &oob); expect_single_call_bt_le_adv_lookup_legacy(); - expect_single_call_bt_conn_lookup_state_le(BT_ID_DEFAULT, NULL, BT_CONN_CONNECTING_SCAN); + expect_single_call_bt_conn_lookup_state_le(BT_ID_DEFAULT, NULL, + BT_CONN_SCAN_BEFORE_INITIATING); zassert_true(err == -EINVAL, "Unexpected error code '%d' was returned", err); } @@ -361,7 +366,8 @@ ZTEST(bt_le_oob_get_local_invalid_inputs, test_conn_state_checked_public_dev_add err = bt_le_oob_get_local(BT_ID_DEFAULT, &oob); expect_single_call_bt_le_adv_lookup_legacy(); - expect_single_call_bt_conn_lookup_state_le(BT_ID_DEFAULT, NULL, BT_CONN_CONNECTING_SCAN); + expect_single_call_bt_conn_lookup_state_le(BT_ID_DEFAULT, NULL, + BT_CONN_SCAN_BEFORE_INITIATING); zassert_true(err == -EINVAL, "Unexpected error code '%d' was returned", err); } diff --git a/tests/bluetooth/host/id/bt_setup_random_id_addr/src/test_suite_bt_settings_enabled.c b/tests/bluetooth/host/id/bt_setup_random_id_addr/src/test_suite_bt_settings_enabled.c index e2b63adfefe..bc843b5d9ca 100644 --- a/tests/bluetooth/host/id/bt_setup_random_id_addr/src/test_suite_bt_settings_enabled.c +++ b/tests/bluetooth/host/id/bt_setup_random_id_addr/src/test_suite_bt_settings_enabled.c @@ -50,7 +50,7 @@ ZTEST_SUITE(bt_setup_random_id_addr_bt_settings_enabled, NULL, NULL, tc_setup, N * Test reading controller static random address fails and no attempt to store settings. * * Constraints: - * - bt_read_static_addr() returns zero + * - vs_read_static_addr() returns zero * * Expected behaviour: * - ID count is set to 0 and bt_setup_random_id_addr() returns a negative error code @@ -60,7 +60,7 @@ ZTEST(bt_setup_random_id_addr_bt_settings_enabled, test_bt_read_static_addr_retu { int err; - /* This will force bt_read_static_addr() to fail */ + /* This will force vs_read_static_addr() to fail */ bt_hci_cmd_send_sync_fake.return_val = 1; err = bt_setup_random_id_addr(); diff --git a/tests/bluetooth/init/prj_ctlr_4_0.conf b/tests/bluetooth/init/prj_ctlr_4_0.conf index a92a542f6d7..ba2013915d1 100644 --- a/tests/bluetooth/init/prj_ctlr_4_0.conf +++ b/tests/bluetooth/init/prj_ctlr_4_0.conf @@ -25,7 +25,7 @@ CONFIG_BT_CTLR_SCAN_REQ_NOTIFY=n CONFIG_BT_CTLR_SCAN_REQ_RSSI=n CONFIG_BT_CTLR_PROFILE_ISR=n CONFIG_BT_CTLR_DEBUG_PINS=n -CONFIG_BT_HCI_VS_EXT=n +CONFIG_BT_HCI_VS=n CONFIG_BT_PERIPHERAL=y CONFIG_BT_CENTRAL=y CONFIG_BT_SMP=y diff --git a/tests/bluetooth/init/prj_ctlr_4_0_dbg.conf b/tests/bluetooth/init/prj_ctlr_4_0_dbg.conf index 53559510ac4..372d4a29010 100644 --- a/tests/bluetooth/init/prj_ctlr_4_0_dbg.conf +++ b/tests/bluetooth/init/prj_ctlr_4_0_dbg.conf @@ -25,9 +25,10 @@ CONFIG_BT_CTLR_CONN_RSSI=n CONFIG_BT_CTLR_ADV_INDICATION=n CONFIG_BT_CTLR_SCAN_REQ_NOTIFY=n CONFIG_BT_CTLR_SCAN_REQ_RSSI=n +CONFIG_BT_CTLR_OPTIMIZE_FOR_APP_DEFAULT=y CONFIG_BT_CTLR_PROFILE_ISR=n CONFIG_BT_CTLR_DEBUG_PINS=n -CONFIG_BT_HCI_VS_EXT=y +CONFIG_BT_HCI_VS=y CONFIG_BT_CTLR_VS_SCAN_REQ_RX=y CONFIG_BT_PERIPHERAL=y CONFIG_BT_CENTRAL=y diff --git a/tests/bluetooth/init/prj_ctlr_5_x_dbg.conf b/tests/bluetooth/init/prj_ctlr_5_x_dbg.conf index f37e9c6f309..920a9f08860 100644 --- a/tests/bluetooth/init/prj_ctlr_5_x_dbg.conf +++ b/tests/bluetooth/init/prj_ctlr_5_x_dbg.conf @@ -41,10 +41,11 @@ CONFIG_BT_CTLR_SYNC_ISO_RESERVE_MAX=n CONFIG_BT_CTLR_CENTRAL_RESERVE_MAX=n CONFIG_BT_CTLR_CIS_ACCEPT_MIN_OFFSET_STRICT=y CONFIG_BT_CTLR_EVENT_OVERHEAD_RESERVE_MAX=n +CONFIG_BT_CTLR_OPTIMIZE_FOR_SIZE=y CONFIG_BT_CTLR_PROFILE_ISR=y CONFIG_BT_CTLR_DEBUG_PINS=y CONFIG_BT_CTLR_TEST=y -CONFIG_BT_HCI_VS_EXT=y +CONFIG_BT_HCI_VS=y CONFIG_BT_HCI_MESH_EXT=n CONFIG_BT_PERIPHERAL=y CONFIG_BT_CENTRAL=y diff --git a/tests/bluetooth/init/prj_ctlr_dbg.conf b/tests/bluetooth/init/prj_ctlr_dbg.conf index f2bf1f7ffd4..386e81a33f9 100644 --- a/tests/bluetooth/init/prj_ctlr_dbg.conf +++ b/tests/bluetooth/init/prj_ctlr_dbg.conf @@ -31,10 +31,11 @@ CONFIG_BT_CTLR_ADV_INDICATION=y CONFIG_BT_CTLR_SCAN_REQ_NOTIFY=y CONFIG_BT_CTLR_SCAN_REQ_RSSI=y CONFIG_BT_CTLR_SCAN_INDICATION=y +CONFIG_BT_CTLR_OPTIMIZE_FOR_SPEED=y CONFIG_BT_CTLR_PROFILE_ISR=y CONFIG_BT_CTLR_DEBUG_PINS=y CONFIG_BT_CTLR_TEST=y -CONFIG_BT_HCI_VS_EXT=y +CONFIG_BT_HCI_VS=y CONFIG_BT_HCI_MESH_EXT=n CONFIG_BT_PERIPHERAL=y CONFIG_BT_CENTRAL=y diff --git a/tests/bluetooth/init/prj_ctlr_ticker.conf b/tests/bluetooth/init/prj_ctlr_ticker.conf index ba983f09a73..47c4f3f7062 100644 --- a/tests/bluetooth/init/prj_ctlr_ticker.conf +++ b/tests/bluetooth/init/prj_ctlr_ticker.conf @@ -35,7 +35,7 @@ CONFIG_BT_CTLR_TEST=y CONFIG_BT_TICKER_EXT=n CONFIG_BT_TICKER_SLOT_AGNOSTIC=y CONFIG_BT_TICKER_PREFER_START_BEFORE_STOP=y -CONFIG_BT_HCI_VS_EXT=y +CONFIG_BT_HCI_VS=y CONFIG_BT_HCI_MESH_EXT=n CONFIG_BT_PERIPHERAL=y CONFIG_BT_CENTRAL=y diff --git a/tests/bluetooth/init/prj_ctlr_tiny.conf b/tests/bluetooth/init/prj_ctlr_tiny.conf index 19de37a5a84..a9dcf2327e0 100644 --- a/tests/bluetooth/init/prj_ctlr_tiny.conf +++ b/tests/bluetooth/init/prj_ctlr_tiny.conf @@ -29,7 +29,7 @@ CONFIG_BT_CTLR_SCAN_REQ_RSSI=n CONFIG_BT_CTLR_PROFILE_ISR=n CONFIG_BT_CTLR_PROFILE_ISR=n CONFIG_BT_CTLR_DEBUG_PINS=n -CONFIG_BT_HCI_VS_EXT=n +CONFIG_BT_HCI_VS=n CONFIG_BT_PERIPHERAL=y CONFIG_BT_CENTRAL=y CONFIG_BT_SMP=y diff --git a/tests/bluetooth/mesh_shell/src/main.c b/tests/bluetooth/mesh_shell/src/main.c index f5dbdc41b40..2428b38a19f 100644 --- a/tests/bluetooth/mesh_shell/src/main.c +++ b/tests/bluetooth/mesh_shell/src/main.c @@ -46,7 +46,8 @@ BT_MESH_SHELL_HEALTH_PUB_DEFINE(health_pub); 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(&bt_mesh_shell_health_srv, &health_pub), + BT_MESH_MODEL_HEALTH_SRV(&bt_mesh_shell_health_srv, &health_pub, + health_srv_meta), BT_MESH_MODEL_HEALTH_CLI(&bt_mesh_shell_health_cli), #if defined(CONFIG_BT_MESH_DFD_SRV) BT_MESH_MODEL_DFD_SRV(&dfd_srv), diff --git a/tests/bluetooth/shell/audio.conf b/tests/bluetooth/shell/audio.conf index d28c311feef..e783677ad0f 100644 --- a/tests/bluetooth/shell/audio.conf +++ b/tests/bluetooth/shell/audio.conf @@ -48,6 +48,7 @@ CONFIG_BT_PER_ADV_SYNC_TRANSFER_RECEIVER=y CONFIG_BT_PER_ADV_SYNC_TRANSFER_SENDER=y # Support an ISO channel per ASE +CONFIG_BT_ISO_PERIPHERAL=y CONFIG_BT_ISO_MAX_CHAN=4 CONFIG_BT_ISO_TEST_PARAMS=y CONFIG_BT_ISO_TX_BUF_COUNT=10 @@ -68,6 +69,7 @@ CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT=2 CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE=255 CONFIG_BT_AUDIO_CODEC_CAP_MAX_METADATA_SIZE=255 +CONFIG_BT_ASCS=y CONFIG_BT_ASCS_ASE_SNK_COUNT=2 CONFIG_BT_ASCS_ASE_SRC_COUNT=2 CONFIG_BT_BAP_UNICAST_CLIENT=y @@ -151,7 +153,6 @@ CONFIG_BT_HAS_PRESET_NAME_DYNAMIC=y CONFIG_BT_HAS_PRESET_COUNT=4 CONFIG_BT_HAS_CLIENT=y CONFIG_BT_HAS_FEATURES_NOTIFIABLE=y -CONFIG_BT_HAS_PRESET_CONTROL_POINT_NOTIFIABLE=y # Common Audio Profile CONFIG_BT_CAP_ACCEPTOR=y @@ -216,3 +217,23 @@ CONFIG_BT_CAP_COMMANDER_LOG_LEVEL_DBG=y CONFIG_BT_CAP_COMMON_LOG_LEVEL_DBG=y CONFIG_BT_TMAP_LOG_LEVEL_DBG=y CONFIG_BT_GMAP_LOG_LEVEL_DBG=y + +# Controller settings +CONFIG_BT_CTLR_DATA_LENGTH_MAX=251 + +# Support having both a connectable and a non-connectable set +CONFIG_BT_CTLR_ADV_SET=2 +CONFIG_BT_CTLR_ADV_AUX_SET=2 +CONFIG_BT_CTLR_ADV_SYNC_SET=2 +CONFIG_BT_CTLR_ADV_DATA_LEN_MAX=191 +CONFIG_BT_CTLR_ADV_DATA_BUF_MAX=6 + +CONFIG_BT_CTLR_SCAN_DATA_LEN_MAX=1650 + +# Match the number of broadcast streams supported in BAP +CONFIG_BT_CTLR_SYNC_ISO_STREAM_MAX=4 +CONFIG_BT_CTLR_ADV_ISO_STREAM_MAX=4 + +# Match the number of unicast streams supported in BAP +CONFIG_BT_CTLR_ISOAL_SOURCES=2 +CONFIG_BT_CTLR_ISOAL_SINKS=2 diff --git a/tests/bluetooth/shell/boards/native_posix.conf b/tests/bluetooth/shell/boards/native_posix.conf index a2ab2f4e87a..80cbf626797 100644 --- a/tests/bluetooth/shell/boards/native_posix.conf +++ b/tests/bluetooth/shell/boards/native_posix.conf @@ -11,6 +11,3 @@ CONFIG_SYS_CLOCK_TICKS_PER_SEC=500 # For LC3 the following configs are needed CONFIG_FPU=y 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 diff --git a/tests/bluetooth/shell/boards/native_sim.conf b/tests/bluetooth/shell/boards/native_sim.conf index a2ab2f4e87a..80cbf626797 100644 --- a/tests/bluetooth/shell/boards/native_sim.conf +++ b/tests/bluetooth/shell/boards/native_sim.conf @@ -11,6 +11,3 @@ CONFIG_SYS_CLOCK_TICKS_PER_SEC=500 # For LC3 the following configs are needed CONFIG_FPU=y 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 diff --git a/tests/bluetooth/shell/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf b/tests/bluetooth/shell/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf index 8d48d5e1c20..68e0a8a7e50 100644 --- a/tests/bluetooth/shell/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf +++ b/tests/bluetooth/shell/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf @@ -1,6 +1,12 @@ # For LC3 the following configs are needed CONFIG_FPU=y 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 + +# For USB audio the following configs are needed +CONFIG_RING_BUFFER=y +CONFIG_USB_DEVICE_STACK=y +CONFIG_USB_DEVICE_AUDIO=y +CONFIG_USB_DEVICE_PRODUCT="Zephyr Shell USB" + +# Enable encryption in the host +CONFIG_BT_TINYCRYPT_ECC=y diff --git a/tests/bluetooth/shell/boards/nrf5340dk_nrf5340_cpuapp.conf b/tests/bluetooth/shell/boards/nrf5340dk_nrf5340_cpuapp.conf index 8d48d5e1c20..68e0a8a7e50 100644 --- a/tests/bluetooth/shell/boards/nrf5340dk_nrf5340_cpuapp.conf +++ b/tests/bluetooth/shell/boards/nrf5340dk_nrf5340_cpuapp.conf @@ -1,6 +1,12 @@ # For LC3 the following configs are needed CONFIG_FPU=y 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 + +# For USB audio the following configs are needed +CONFIG_RING_BUFFER=y +CONFIG_USB_DEVICE_STACK=y +CONFIG_USB_DEVICE_AUDIO=y +CONFIG_USB_DEVICE_PRODUCT="Zephyr Shell USB" + +# Enable encryption in the host +CONFIG_BT_TINYCRYPT_ECC=y diff --git a/tests/bluetooth/shell/cdc_acm.conf b/tests/bluetooth/shell/cdc_acm.conf index bd9204fa006..3e95d3badc7 100644 --- a/tests/bluetooth/shell/cdc_acm.conf +++ b/tests/bluetooth/shell/cdc_acm.conf @@ -3,4 +3,3 @@ CONFIG_USB_DEVICE_PRODUCT="Zephyr BT Shell" CONFIG_UART_LINE_CTRL=y CONFIG_SHELL_BACKEND_SERIAL_CHECK_DTR=y -CONFIG_SHELL_BACKEND_SERIAL_INIT_PRIORITY=51 diff --git a/tests/bluetooth/shell/snippets/xterm-native-shell/xterm-native-shell.conf b/tests/bluetooth/shell/snippets/xterm-native-shell/xterm-native-shell.conf index b29c9b615a6..9d3dedf1f70 100644 --- a/tests/bluetooth/shell/snippets/xterm-native-shell/xterm-native-shell.conf +++ b/tests/bluetooth/shell/snippets/xterm-native-shell/xterm-native-shell.conf @@ -1,4 +1,5 @@ CONFIG_NATIVE_UART_0_ON_OWN_PTY=y CONFIG_UART_NATIVE_WAIT_PTS_READY_ENABLE=y +CONFIG_SHELL_CMD_BUFF_SIZE=8192 CONFIG_SHELL_BACKEND_SERIAL_RX_RING_BUFFER_SIZE=8192 CONFIG_LOG_PRINTK=n diff --git a/tests/bluetooth/shell/src/main.c b/tests/bluetooth/shell/src/main.c index d64ccdbe0aa..b3933335f4e 100644 --- a/tests/bluetooth/shell/src/main.c +++ b/tests/bluetooth/shell/src/main.c @@ -53,7 +53,7 @@ static int cmd_hrs_simulate(const struct shell *sh, if (!hrs_registered && IS_ENABLED(CONFIG_BT_BROADCASTER)) { shell_print(sh, "Registering HRS Service"); hrs_registered = true; - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, + err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), NULL, 0); if (err) { shell_error(sh, "Advertising failed to start" diff --git a/tests/bluetooth/shell/testcase.yaml b/tests/bluetooth/shell/testcase.yaml index 7ce46d768fe..3ddde520a86 100644 --- a/tests/bluetooth/shell/testcase.yaml +++ b/tests/bluetooth/shell/testcase.yaml @@ -230,6 +230,7 @@ tests: build_only: true extra_configs: - CONFIG_BT_BAP_UNICAST_SERVER=n + - CONFIG_BT_ASCS=n - CONFIG_BT_BAP_UNICAST_CLIENT=n - CONFIG_BT_BAP_BROADCAST_SOURCE=n bluetooth.audio_shell.no_unicast_client: @@ -349,3 +350,28 @@ tests: platform_allow: native_posix extra_configs: - CONFIG_BT_CAP_COMMANDER=n + bluetooth.audio_shell.no_lc3: + extra_args: CONF_FILE="audio.conf" + build_only: true + platform_allow: + - nrf5340dk/nrf5340/cpuapp + - nrf5340_audio_dk/nrf5340/cpuapp + integration_platforms: + - nrf5340dk/nrf5340/cpuapp + - nrf5340_audio_dk/nrf5340/cpuapp + extra_configs: + - CONFIG_FPU=n + - CONFIG_LIBLC3=n + bluetooth.audio_shell.no_usb: + extra_args: CONF_FILE="audio.conf" + build_only: true + platform_allow: + - nrf5340dk/nrf5340/cpuapp + - nrf5340_audio_dk/nrf5340/cpuapp + integration_platforms: + - nrf5340dk/nrf5340/cpuapp + - nrf5340_audio_dk/nrf5340/cpuapp + extra_configs: + - CONFIG_RING_BUFFER=n + - CONFIG_USB_DEVICE_STACK=n + - CONFIG_USB_DEVICE_AUDIO=n diff --git a/tests/bluetooth/tester/CMakeLists.txt b/tests/bluetooth/tester/CMakeLists.txt index 3efd379c7c2..eb3ad4bda24 100644 --- a/tests/bluetooth/tester/CMakeLists.txt +++ b/tests/bluetooth/tester/CMakeLists.txt @@ -94,3 +94,7 @@ endif() if(CONFIG_BT_TMAP) target_sources(app PRIVATE src/btp_tmap.c) endif() + +if(CONFIG_BT_OTS) + target_sources(app PRIVATE src/btp_ots.c) +endif() diff --git a/tests/bluetooth/tester/overlay-le-audio.conf b/tests/bluetooth/tester/overlay-le-audio.conf index ba1b6a4e55e..6b0186e55d8 100644 --- a/tests/bluetooth/tester/overlay-le-audio.conf +++ b/tests/bluetooth/tester/overlay-le-audio.conf @@ -1,4 +1,6 @@ CONFIG_BT_AUDIO=y +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_ISO_PERIPHERAL=y CONFIG_BT_EXT_ADV=y CONFIG_BT_BAP_UNICAST_SERVER=y CONFIG_BT_BAP_UNICAST_CLIENT=y @@ -54,6 +56,7 @@ CONFIG_BT_L2CAP_TX_MTU=255 CONFIG_BT_BUF_ACL_RX_SIZE=255 # ASCS +CONFIG_BT_ASCS=y CONFIG_BT_ASCS_ASE_SNK_COUNT=2 CONFIG_BT_ASCS_ASE_SRC_COUNT=2 diff --git a/tests/bluetooth/tester/overlay-mesh.conf b/tests/bluetooth/tester/overlay-mesh.conf index 9fded71f792..1609177c533 100644 --- a/tests/bluetooth/tester/overlay-mesh.conf +++ b/tests/bluetooth/tester/overlay-mesh.conf @@ -1,5 +1,3 @@ -CONFIG_ENTROPY_GENERATOR=y - CONFIG_BT_MESH=y CONFIG_BT_MESH_RELAY=y CONFIG_BT_MESH_PB_ADV=y diff --git a/tests/bluetooth/tester/prj.conf b/tests/bluetooth/tester/prj.conf index ac240dbe63c..84ba74652dd 100644 --- a/tests/bluetooth/tester/prj.conf +++ b/tests/bluetooth/tester/prj.conf @@ -39,3 +39,12 @@ CONFIG_BT_RX_STACK_SIZE=4096 CONFIG_BT_TINYCRYPT_ECC=y CONFIG_BT_TESTING=y CONFIG_UTF8=y + +CONFIG_BT_OTS=y +CONFIG_BT_OTS_DIR_LIST_OBJ=y +CONFIG_BT_OTS_OBJ_NAME_WRITE_SUPPORT=y +CONFIG_BT_OTS_OACP_WRITE_SUPPORT=y +CONFIG_BT_OTS_OACP_PATCH_SUPPORT=y +CONFIG_BT_OTS_OACP_CREATE_SUPPORT=y +CONFIG_BT_OTS_OACP_DELETE_SUPPORT=y +CONFIG_BT_OTS_OACP_CHECKSUM_SUPPORT=y diff --git a/tests/bluetooth/tester/src/btp/btp.h b/tests/bluetooth/tester/src/btp/btp.h index d57e38892b4..50443463997 100644 --- a/tests/bluetooth/tester/src/btp/btp.h +++ b/tests/bluetooth/tester/src/btp/btp.h @@ -37,6 +37,7 @@ #include "btp_cap.h" #include "btp_tbs.h" #include "btp_tmap.h" +#include "btp_ots.h" #define BTP_MTU 1024 #define BTP_DATA_MAX_SIZE (BTP_MTU - sizeof(struct btp_hdr)) @@ -73,8 +74,9 @@ #define BTP_SERVICE_ID_CAP 26 #define BTP_SERVICE_ID_TBS 27 #define BTP_SERVICE_ID_TMAP 28 +#define BTP_SERVICE_ID_OTS 29 -#define BTP_SERVICE_ID_MAX BTP_SERVICE_ID_TMAP +#define BTP_SERVICE_ID_MAX BTP_SERVICE_ID_OTS #define BTP_STATUS_SUCCESS 0x00 #define BTP_STATUS_FAILED 0x01 diff --git a/tests/bluetooth/tester/src/btp/btp_ots.h b/tests/bluetooth/tester/src/btp/btp_ots.h new file mode 100644 index 00000000000..ae6900eb0f5 --- /dev/null +++ b/tests/bluetooth/tester/src/btp/btp_ots.h @@ -0,0 +1,28 @@ +/* btp_ots.h - Bluetooth OTS tester headers */ + +/* + * Copyright (c) 2024 Codecoup + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* OTS commands */ +#define BTP_OTS_READ_SUPPORTED_COMMANDS 0x01 +struct btp_ots_read_supported_commands_rp { + uint8_t data[0]; +} __packed; + +#define BTP_OTS_REGISTER_OBJECT_FLAGS_SKIP_UNSUPPORTED_PROPS 0x01 + +#define BTP_OTS_REGISTER_OBJECT 0x02 +struct btp_ots_register_object_cmd { + uint8_t flags; + uint32_t ots_props; + uint32_t alloc_size; + uint32_t current_size; + uint8_t name_len; + uint8_t name[0]; +} __packed; +struct btp_ots_register_object_rp { + uint64_t object_id; +} __packed; diff --git a/tests/bluetooth/tester/src/btp/bttester.h b/tests/bluetooth/tester/src/btp/bttester.h index a5f29dd61d8..d7ce2699310 100644 --- a/tests/bluetooth/tester/src/btp/bttester.h +++ b/tests/bluetooth/tester/src/btp/bttester.h @@ -135,3 +135,6 @@ uint8_t tester_unregister_tbs(void); uint8_t tester_init_tmap(void); uint8_t tester_unregister_tmap(void); + +uint8_t tester_init_ots(void); +uint8_t tester_unregister_ots(void); diff --git a/tests/bluetooth/tester/src/btp_bap_broadcast.c b/tests/bluetooth/tester/src/btp_bap_broadcast.c index 1177d0585dc..75b2ed716e8 100644 --- a/tests/bluetooth/tester/src/btp_bap_broadcast.c +++ b/tests/bluetooth/tester/src/btp_bap_broadcast.c @@ -295,7 +295,7 @@ uint8_t btp_bap_broadcast_source_setup(const void *cmd, uint16_t cmd_len, struct bt_audio_codec_cfg codec_cfg; const struct btp_bap_broadcast_source_setup_cmd *cp = cmd; struct btp_bap_broadcast_source_setup_rp *rp = rsp; - struct bt_le_adv_param *param = BT_LE_EXT_ADV_NCONN_NAME; + struct bt_le_adv_param *param = BT_LE_EXT_ADV_NCONN; /* Only one local source/BIG supported for now */ struct btp_bap_broadcast_local_source *source = &local_source; @@ -307,7 +307,7 @@ uint8_t btp_bap_broadcast_source_setup(const void *cmd, uint16_t cmd_len, NET_BUF_SIMPLE_DEFINE(base_buf, 128); /* Broadcast Audio Streaming Endpoint advertising data */ - struct bt_data base_ad; + struct bt_data base_ad[2]; struct bt_data per_ad; LOG_DBG(""); @@ -344,11 +344,14 @@ uint8_t btp_bap_broadcast_source_setup(const void *cmd, uint16_t cmd_len, /* Setup extended advertising data */ net_buf_simple_add_le16(&ad_buf, BT_UUID_BROADCAST_AUDIO_VAL); net_buf_simple_add_le24(&ad_buf, source->broadcast_id); - base_ad.type = BT_DATA_SVC_DATA16; - base_ad.data_len = ad_buf.len; - base_ad.data = ad_buf.data; - err = tester_gap_create_adv_instance(param, BTP_GAP_ADDR_TYPE_IDENTITY, &base_ad, 1, NULL, - 0, &gap_settings); + base_ad[0].type = BT_DATA_SVC_DATA16; + base_ad[0].data_len = ad_buf.len; + base_ad[0].data = ad_buf.data; + base_ad[1].type = BT_DATA_NAME_COMPLETE; + base_ad[1].data_len = sizeof(CONFIG_BT_DEVICE_NAME) - 1; + base_ad[1].data = CONFIG_BT_DEVICE_NAME; + err = tester_gap_create_adv_instance(param, BTP_GAP_ADDR_TYPE_IDENTITY, base_ad, 2, + NULL, 0, &gap_settings); if (err != 0) { LOG_DBG("Failed to create extended advertising instance: %d", err); @@ -1263,10 +1266,9 @@ static void bap_broadcast_assistant_recv_state_cb(struct bt_conn *conn, int err, btp_send_broadcast_receive_state_ev(conn, state); } -static void bap_broadcast_assistant_recv_state_removed_cb(struct bt_conn *conn, int err, - uint8_t src_id) +static void bap_broadcast_assistant_recv_state_removed_cb(struct bt_conn *conn, uint8_t src_id) { - LOG_DBG("err: %d", err); + LOG_DBG(""); } static void bap_broadcast_assistant_scan_start_cb(struct bt_conn *conn, int err) diff --git a/tests/bluetooth/tester/src/btp_cap.c b/tests/bluetooth/tester/src/btp_cap.c index ea1a6acf89e..58d34bd0651 100644 --- a/tests/bluetooth/tester/src/btp_cap.c +++ b/tests/bluetooth/tester/src/btp_cap.c @@ -50,6 +50,7 @@ static void btp_send_discovery_completed_ev(struct bt_conn *conn, uint8_t status } static void cap_discovery_complete_cb(struct bt_conn *conn, int err, + const struct bt_csip_set_coordinator_set_member *member, const struct bt_csip_set_coordinator_csis_inst *csis_inst) { LOG_DBG(""); @@ -531,13 +532,13 @@ static int cap_broadcast_source_adv_setup(struct btp_bap_broadcast_local_source uint32_t *gap_settings) { int err; - struct bt_le_adv_param *param = BT_LE_EXT_ADV_NCONN_NAME; + struct bt_le_adv_param *param = BT_LE_EXT_ADV_NCONN; NET_BUF_SIMPLE_DEFINE(ad_buf, BT_UUID_SIZE_16 + BT_AUDIO_BROADCAST_ID_SIZE); NET_BUF_SIMPLE_DEFINE(base_buf, 128); /* Broadcast Audio Streaming Endpoint advertising data */ - struct bt_data base_ad; + struct bt_data base_ad[2]; struct bt_data per_ad; err = bt_cap_initiator_broadcast_get_id(source->cap_broadcast, &source->broadcast_id); @@ -552,11 +553,14 @@ static int cap_broadcast_source_adv_setup(struct btp_bap_broadcast_local_source /* Setup extended advertising data */ net_buf_simple_add_le16(&ad_buf, BT_UUID_BROADCAST_AUDIO_VAL); net_buf_simple_add_le24(&ad_buf, source->broadcast_id); - base_ad.type = BT_DATA_SVC_DATA16; - base_ad.data_len = ad_buf.len; - base_ad.data = ad_buf.data; - err = tester_gap_create_adv_instance(param, BTP_GAP_ADDR_TYPE_IDENTITY, &base_ad, 1, NULL, - 0, gap_settings); + base_ad[0].type = BT_DATA_SVC_DATA16; + base_ad[0].data_len = ad_buf.len; + base_ad[0].data = ad_buf.data; + base_ad[1].type = BT_DATA_NAME_COMPLETE; + base_ad[1].data_len = sizeof(CONFIG_BT_DEVICE_NAME) - 1; + base_ad[1].data = CONFIG_BT_DEVICE_NAME; + err = tester_gap_create_adv_instance(param, BTP_GAP_ADDR_TYPE_IDENTITY, base_ad, 2, + NULL, 0, gap_settings); if (err != 0) { LOG_DBG("Failed to create extended advertising instance: %d", err); diff --git a/tests/bluetooth/tester/src/btp_core.c b/tests/bluetooth/tester/src/btp_core.c index 3492013b130..a3f496bece6 100644 --- a/tests/bluetooth/tester/src/btp_core.c +++ b/tests/bluetooth/tester/src/btp_core.c @@ -245,6 +245,11 @@ static uint8_t register_service(const void *cmd, uint16_t cmd_len, status = tester_init_tmap(); break; #endif /* CONFIG_BT_TMAP */ +#if defined(CONFIG_BT_OTS) + case BTP_SERVICE_ID_OTS: + status = tester_init_ots(); + break; +#endif /* CONFIG_BT_OTS */ default: LOG_WRN("unknown id: 0x%02x", cp->id); status = BTP_STATUS_FAILED; @@ -387,6 +392,11 @@ static uint8_t unregister_service(const void *cmd, uint16_t cmd_len, status = tester_unregister_tmap(); break; #endif /* CONFIG_BT_TMAP */ +#if defined(CONFIG_BT_OTS) + case BTP_SERVICE_ID_OTS: + status = tester_unregister_ots(); + break; +#endif /* CONFIG_BT_OTS */ default: LOG_WRN("unknown id: 0x%x", cp->id); status = BTP_STATUS_FAILED; diff --git a/tests/bluetooth/tester/src/btp_mesh.c b/tests/bluetooth/tester/src/btp_mesh.c index 65b3a81c6e2..3beced415da 100644 --- a/tests/bluetooth/tester/src/btp_mesh.c +++ b/tests/bluetooth/tester/src/btp_mesh.c @@ -684,7 +684,6 @@ static struct bt_mesh_health_cli health_cli = { }; -#ifdef CONFIG_BT_MESH_LARGE_COMP_DATA_SRV static uint8_t health_tests[] = { BT_MESH_HEALTH_TEST_INFO(COMPANY_ID_LF, 6, 0x01, 0x02, 0x03, 0x04, 0x34, 0x15), @@ -718,13 +717,9 @@ static const struct bt_mesh_models_metadata_entry health_srv_meta_alt[] = { }, BT_MESH_MODELS_METADATA_END, }; -#endif static struct bt_mesh_health_srv health_srv = { .cb = &health_srv_cb, -#ifdef CONFIG_BT_MESH_LARGE_COMP_DATA_SRV - .metadata = health_srv_meta, -#endif }; BT_MESH_HEALTH_PUB_DEFINE(health_pub, CUR_FAULTS_MAX); @@ -1027,7 +1022,63 @@ static uint8_t proxy_solicit(const void *cmd, uint16_t cmd_len, 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), + BT_MESH_MODEL_HEALTH_SRV(&health_srv, &health_pub, health_srv_meta), + BT_MESH_MODEL_HEALTH_CLI(&health_cli), +#if defined(CONFIG_BT_MESH_SAR_CFG_SRV) + BT_MESH_MODEL_SAR_CFG_SRV, +#endif +#if defined(CONFIG_BT_MESH_SAR_CFG_CLI) + BT_MESH_MODEL_SAR_CFG_CLI(&sar_cfg_cli), +#endif +#if defined(CONFIG_BT_MESH_LARGE_COMP_DATA_SRV) + BT_MESH_MODEL_LARGE_COMP_DATA_SRV, +#endif +#if defined(CONFIG_BT_MESH_LARGE_COMP_DATA_CLI) + BT_MESH_MODEL_LARGE_COMP_DATA_CLI(&lcd_cli), +#endif +#if defined(CONFIG_BT_MESH_OP_AGG_SRV) + BT_MESH_MODEL_OP_AGG_SRV, +#endif +#if defined(CONFIG_BT_MESH_OP_AGG_CLI) + BT_MESH_MODEL_OP_AGG_CLI, +#endif +#if defined(CONFIG_BT_MESH_RPR_CLI) + BT_MESH_MODEL_RPR_CLI(&rpr_cli), +#endif +#if defined(CONFIG_BT_MESH_RPR_SRV) + BT_MESH_MODEL_RPR_SRV, +#endif +#if defined(CONFIG_BT_MESH_DFD_SRV) + BT_MESH_MODEL_DFD_SRV(&dfd_srv), +#endif +#if defined(CONFIG_BT_MESH_DFU_SRV) + BT_MESH_MODEL_DFU_SRV(&dfu_srv), +#endif +#if defined(CONFIG_BT_MESH_BLOB_CLI) && !defined(CONFIG_BT_MESH_DFD_SRV) + BT_MESH_MODEL_BLOB_CLI(&blob_cli), +#endif +#if defined(CONFIG_BT_MESH_PRIV_BEACON_SRV) + BT_MESH_MODEL_PRIV_BEACON_SRV, +#endif +#if defined(CONFIG_BT_MESH_PRIV_BEACON_CLI) + BT_MESH_MODEL_PRIV_BEACON_CLI(&priv_beacon_cli), +#endif +#if defined(CONFIG_BT_MESH_OD_PRIV_PROXY_CLI) + BT_MESH_MODEL_OD_PRIV_PROXY_CLI(&od_priv_proxy_cli), +#endif +#if defined(CONFIG_BT_MESH_SOL_PDU_RPL_CLI) + BT_MESH_MODEL_SOL_PDU_RPL_CLI(&srpl_cli), +#endif +#if defined(CONFIG_BT_MESH_OD_PRIV_PROXY_SRV) + BT_MESH_MODEL_OD_PRIV_PROXY_SRV, +#endif + +}; + +static const struct bt_mesh_model root_models_alt[] = { + BT_MESH_MODEL_CFG_SRV, + BT_MESH_MODEL_CFG_CLI(&cfg_cli), + BT_MESH_MODEL_HEALTH_SRV(&health_srv, &health_pub, health_srv_meta_alt), BT_MESH_MODEL_HEALTH_CLI(&health_cli), #if defined(CONFIG_BT_MESH_SAR_CFG_SRV) BT_MESH_MODEL_SAR_CFG_SRV, @@ -1100,6 +1151,10 @@ static const struct bt_mesh_elem elements[] = { BT_MESH_ELEM(0, root_models, vnd_models), }; +static const struct bt_mesh_elem elements_alt[] = { + BT_MESH_ELEM(0, root_models_alt, vnd_models), +}; + static void link_open(bt_mesh_prov_bearer_t bearer) { struct btp_mesh_prov_link_open_ev ev; @@ -1247,8 +1302,8 @@ static const struct bt_mesh_comp comp = { static const struct bt_mesh_comp comp_alt = { .cid = CID_LOCAL, - .elem = elements, - .elem_count = ARRAY_SIZE(elements), + .elem = elements_alt, + .elem_count = ARRAY_SIZE(elements_alt), .vid = 2, }; @@ -1414,9 +1469,6 @@ static uint8_t init(const void *cmd, uint16_t cmd_len, err = bt_mesh_init(&prov, &comp); } else { LOG_WRN("Loading alternative comp data"); -#ifdef CONFIG_BT_MESH_LARGE_COMP_DATA_SRV - health_srv.metadata = health_srv_meta_alt; -#endif err = bt_mesh_init(&prov, &comp_alt); } diff --git a/tests/bluetooth/tester/src/btp_ots.c b/tests/bluetooth/tester/src/btp_ots.c new file mode 100644 index 00000000000..defea7d2fed --- /dev/null +++ b/tests/bluetooth/tester/src/btp_ots.c @@ -0,0 +1,339 @@ +/* btp_ots.c - Bluetooth OTS Tester */ + +/* + * Copyright (c) 2024 Codecoup + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include + +#include +#include + +#include +#define LOG_MODULE_NAME bttester_ots +LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_BTTESTER_LOG_LEVEL); + +#include "btp/btp.h" + +#define OBJ_POOL_SIZE CONFIG_BT_OTS_MAX_OBJ_CNT +#define OBJ_MAX_SIZE 100 + +static struct object { + uint8_t data[OBJ_MAX_SIZE]; + char name[CONFIG_BT_OTS_OBJ_MAX_NAME_LEN + 1]; + bool in_use; +} objects[OBJ_POOL_SIZE]; + +struct object_creation_data { + struct object *object; + struct bt_ots_obj_size size; + uint32_t props; +}; + +#define OTS_OBJ_ID_TO_OBJ_IDX(id) (((id) - BT_OTS_OBJ_ID_MIN) % ARRAY_SIZE(objects)) + +static struct object_creation_data *object_being_created; + +static struct bt_ots *ots; + +static uint8_t ots_supported_commands(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + struct btp_ots_read_supported_commands_rp *rp = rsp; + + tester_set_bit(rp->data, BTP_OTS_READ_SUPPORTED_COMMANDS); + tester_set_bit(rp->data, BTP_OTS_REGISTER_OBJECT); + + *rsp_len = sizeof(*rp) + 1; + + return BTP_STATUS_SUCCESS; +} + +static struct object *get_object(void) +{ + for (size_t i = 0; i < ARRAY_SIZE(objects); i++) { + if (!objects[i].in_use) { + objects[i].in_use = true; + return &objects[i]; + } + } + + return NULL; +} + +static uint8_t register_object(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_ots_register_object_cmd *cp = cmd; + struct btp_ots_register_object_rp *rp = rsp; + struct object_creation_data obj_data; + struct bt_ots_obj_add_param param; + uint32_t supported_props = 0; + struct object *obj; + uint32_t props; + int err; + + if ((cmd_len < sizeof(*cp)) || (cmd_len != sizeof(*cp) + cp->name_len)) { + return BTP_STATUS_FAILED; + } + + if (cp->name_len == 0 || cp->name_len > CONFIG_BT_OTS_OBJ_MAX_NAME_LEN) { + return BTP_STATUS_FAILED; + } + + /* all supported props (execute, append, truncate not supported) */ + BT_OTS_OBJ_SET_PROP_DELETE(supported_props); + BT_OTS_OBJ_SET_PROP_READ(supported_props); + BT_OTS_OBJ_SET_PROP_WRITE(supported_props); + BT_OTS_OBJ_SET_PROP_PATCH(supported_props); + + props = sys_le32_to_cpu(cp->ots_props); + if (cp->flags & BTP_OTS_REGISTER_OBJECT_FLAGS_SKIP_UNSUPPORTED_PROPS) { + props &= supported_props; + } + + obj = get_object(); + if (!obj) { + return BTP_STATUS_FAILED; + } + + (void)memset(&obj_data, 0, sizeof(obj_data)); + + memcpy(obj->name, cp->name, cp->name_len); + obj_data.object = obj; + obj_data.size.cur = sys_le32_to_cpu(cp->current_size); + obj_data.size.alloc = sys_le32_to_cpu(cp->alloc_size); + obj_data.props = props; + + /* bt_ots_obj_add() lacks user_data so we need to use global for + * passing this + */ + object_being_created = &obj_data; + + param.size = obj_data.size.alloc; + param.type.uuid.type = BT_UUID_TYPE_16; + param.type.uuid_16.val = BT_UUID_OTS_TYPE_UNSPECIFIED_VAL; + + err = bt_ots_obj_add(ots, ¶m); + object_being_created = NULL; + + if (err < 0) { + memset(obj, 0, sizeof(*obj)); + return BTP_STATUS_FAILED; + } + + rp->object_id = sys_cpu_to_le64(err); + *rsp_len = sizeof(*rp); + + return BTP_STATUS_SUCCESS; +} + +static const struct btp_handler ots_handlers[] = { + { + .opcode = BTP_OTS_READ_SUPPORTED_COMMANDS, + .index = BTP_INDEX_NONE, + .expect_len = 0, + .func = ots_supported_commands + }, + { + .opcode = BTP_OTS_REGISTER_OBJECT, + .index = 0, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = register_object + }, +}; + +static int ots_obj_created(struct bt_ots *ots, struct bt_conn *conn, uint64_t id, + const struct bt_ots_obj_add_param *add_param, + struct bt_ots_obj_created_desc *created_desc) +{ + struct object *obj; + + LOG_DBG("id=%"PRIu64" size=%u", id, add_param->size); + + /* TS suggests to use OTS service UUID for testing this */ + if (conn && bt_uuid_cmp(&add_param->type.uuid, BT_UUID_OTS) == 0) { + return -ENOTSUP; + } + + if (add_param->size > OBJ_MAX_SIZE) { + return -ENOMEM; + } + + if (conn || !object_being_created) { + uint32_t obj_index = OTS_OBJ_ID_TO_OBJ_IDX(id); + + if (obj_index >= OBJ_POOL_SIZE) { + return -ENOMEM; + } + + obj = &objects[obj_index]; + if (obj->in_use) { + return -ENOMEM; + } + + obj->in_use = false; + created_desc->name = obj->name; + created_desc->size.alloc = OBJ_MAX_SIZE; + BT_OTS_OBJ_SET_PROP_READ(created_desc->props); + BT_OTS_OBJ_SET_PROP_WRITE(created_desc->props); + BT_OTS_OBJ_SET_PROP_PATCH(created_desc->props); + BT_OTS_OBJ_SET_PROP_DELETE(created_desc->props); + } else { + obj = object_being_created->object; + created_desc->name = obj->name; + created_desc->size = object_being_created->size; + created_desc->props = object_being_created->props; + } + + return 0; +} + +static int ots_obj_deleted(struct bt_ots *ots, struct bt_conn *conn, + uint64_t id) +{ + uint32_t obj_index = OTS_OBJ_ID_TO_OBJ_IDX(id); + struct object *obj; + + LOG_DBG("id=%"PRIu64, id); + + if (obj_index >= OBJ_POOL_SIZE) { + return -ENOENT; + } + + obj = &objects[obj_index]; + memset(obj, 0, sizeof(*obj)); + + return 0; +} + +static void ots_obj_selected(struct bt_ots *ots, struct bt_conn *conn, + uint64_t id) +{ + LOG_DBG("id=%"PRIu64, id); +} + +static ssize_t ots_obj_read(struct bt_ots *ots, struct bt_conn *conn, + uint64_t id, void **data, size_t len, + off_t offset) +{ + uint32_t obj_index = OTS_OBJ_ID_TO_OBJ_IDX(id); + + LOG_DBG("id=%"PRIu64" data=%p offset=%ld len=%zu", id, data, (long)offset, len); + + if (!data) { + return 0; + } + + if (obj_index >= OBJ_POOL_SIZE) { + return -ENOENT; + } + + *data = &objects[obj_index].data[offset]; + + return len; +} + +static ssize_t ots_obj_write(struct bt_ots *ots, struct bt_conn *conn, + uint64_t id, const void *data, size_t len, + off_t offset, size_t rem) +{ + uint32_t obj_index = OTS_OBJ_ID_TO_OBJ_IDX(id); + + LOG_DBG("id=%"PRIu64" data=%p offset=%ld len=%zu", id, data, (long)offset, len); + + if (obj_index >= OBJ_POOL_SIZE) { + return -ENOENT; + } + + (void)memcpy(&objects[obj_index].data[offset], data, len); + + return len; +} + +static void ots_obj_name_written(struct bt_ots *ots, struct bt_conn *conn, + uint64_t id, const char *cur_name, const char *new_name) +{ + LOG_DBG("id=%"PRIu64"cur_name=%s new_name=%s", id, cur_name, new_name); +} + +static int ots_obj_cal_checksum(struct bt_ots *ots, struct bt_conn *conn, uint64_t id, + off_t offset, size_t len, void **data) +{ + uint32_t obj_index = OTS_OBJ_ID_TO_OBJ_IDX(id); + + if (obj_index >= OBJ_POOL_SIZE) { + return -ENOENT; + } + + *data = &objects[obj_index].data[offset]; + return 0; +} + +static struct bt_ots_cb ots_callbacks = { + .obj_created = ots_obj_created, + .obj_deleted = ots_obj_deleted, + .obj_selected = ots_obj_selected, + .obj_read = ots_obj_read, + .obj_write = ots_obj_write, + .obj_name_written = ots_obj_name_written, + .obj_cal_checksum = ots_obj_cal_checksum, +}; + +static int ots_init(void) +{ + int err; + struct bt_ots_init_param ots_init; + + /* Configure OTS initialization. */ + (void)memset(&ots_init, 0, sizeof(ots_init)); + BT_OTS_OACP_SET_FEAT_READ(ots_init.features.oacp); + BT_OTS_OACP_SET_FEAT_WRITE(ots_init.features.oacp); + BT_OTS_OACP_SET_FEAT_CREATE(ots_init.features.oacp); + BT_OTS_OACP_SET_FEAT_DELETE(ots_init.features.oacp); + BT_OTS_OACP_SET_FEAT_CHECKSUM(ots_init.features.oacp); + BT_OTS_OACP_SET_FEAT_PATCH(ots_init.features.oacp); + BT_OTS_OLCP_SET_FEAT_GO_TO(ots_init.features.olcp); + ots_init.cb = &ots_callbacks; + + /* Initialize OTS instance. */ + err = bt_ots_init(ots, &ots_init); + if (err) { + LOG_ERR("Failed to init OTS (err:%d)\n", err); + return err; + } + + return 0; +} + +uint8_t tester_init_ots(void) +{ + int err; + + /* TODO there is no API to return OTS instance to pool */ + if (!ots) { + ots = bt_ots_free_instance_get(); + } + + if (!ots) { + return BTP_STATUS_FAILED; + } + + err = ots_init(); + if (err) { + return BTP_STATUS_VAL(err); + } + + tester_register_command_handlers(BTP_SERVICE_ID_OTS, ots_handlers, + ARRAY_SIZE(ots_handlers)); + + return BTP_STATUS_SUCCESS; +} + +uint8_t tester_unregister_ots(void) +{ + memset(objects, 0, sizeof(objects)); + + return BTP_STATUS_SUCCESS; +} diff --git a/tests/boards/intel_adsp/ssp/src/main.c b/tests/boards/intel_adsp/ssp/src/main.c index 7ba608e4bbb..4b0b8f09bd0 100644 --- a/tests/boards/intel_adsp/ssp/src/main.c +++ b/tests/boards/intel_adsp/ssp/src/main.c @@ -44,7 +44,7 @@ struct sof_dai_ssp_params { } __packed; static const struct device *const dev_dai_ssp = - DEVICE_DT_GET(DT_NODELABEL(ssp0)); + DEVICE_DT_GET(DT_NODELABEL(ssp00)); static const struct device *const dev_dma_dw = DEVICE_DT_GET(DT_NODELABEL(lpgpdma0)); diff --git a/tests/boot/test_mcuboot/testcase.yaml b/tests/boot/test_mcuboot/testcase.yaml index f30581262a2..abb1d3a44b1 100644 --- a/tests/boot/test_mcuboot/testcase.yaml +++ b/tests/boot/test_mcuboot/testcase.yaml @@ -7,7 +7,7 @@ common: - "I: Starting bootloader" - "Launching primary slot application on (.*)" - "Secondary application ready for swap, rebooting" - - "I: Starting swap using (.*)" + - "I: Starting swap using (.*)|I: Image 0 upgrade secondary slot -> primary slot" - "Swapped application booted on (.*)" tests: bootloader.mcuboot: @@ -34,6 +34,7 @@ tests: - mimxrt595_evk/mimxrt595s/cm33 - mimxrt685_evk/mimxrt685s/cm33 - nrf52840dk/nrf52840 + - rd_rw612_bga integration_platforms: - frdm_k64f - nrf52840dk/nrf52840 diff --git a/tests/bsim/bluetooth/audio/prj.conf b/tests/bsim/bluetooth/audio/prj.conf index fb182f0aa07..90e5924bf6c 100644 --- a/tests/bsim/bluetooth/audio/prj.conf +++ b/tests/bsim/bluetooth/audio/prj.conf @@ -24,6 +24,7 @@ CONFIG_BT_BAP_UNICAST_CLIENT=y CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT=4 CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT=2 CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT=2 +CONFIG_BT_ASCS=y CONFIG_BT_ASCS_ASE_SNK_COUNT=2 CONFIG_BT_ASCS_ASE_SRC_COUNT=2 CONFIG_BT_BAP_BROADCAST_SOURCE=y @@ -34,6 +35,7 @@ CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT=2 CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT=1 CONFIG_BT_BAP_BROADCAST_SNK_SUBGROUP_COUNT=1 CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT=2 +CONFIG_BT_ISO_PERIPHERAL=y CONFIG_BT_ISO_TX_BUF_COUNT=4 CONFIG_BT_ISO_MAX_CHAN=4 CONFIG_BT_ISO_TX_MTU=310 @@ -204,7 +206,7 @@ CONFIG_LOG_MODE_IMMEDIATE=y CONFIG_BT_CTLR_ADV_ISO=y CONFIG_BT_CTLR_SYNC_ISO=y CONFIG_BT_CTLR_SCAN_DATA_LEN_MAX=255 -CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=251 +CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=255 CONFIG_BT_CTLR_ADV_DATA_LEN_MAX=191 # Controller ISO Broadcast Settings diff --git a/tests/bsim/bluetooth/audio/src/bap_bass_broadcaster_test.c b/tests/bsim/bluetooth/audio/src/bap_bass_broadcaster_test.c index 00e18673fff..782195e3bce 100644 --- a/tests/bsim/bluetooth/audio/src/bap_bass_broadcaster_test.c +++ b/tests/bsim/bluetooth/audio/src/bap_bass_broadcaster_test.c @@ -32,7 +32,7 @@ static void test_main(void) printk("Bluetooth initialized\n"); /* 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_NCONN, NULL, &adv); if (err) { FAIL("Failed to create advertising set (err %d)\n", err); return; diff --git a/tests/bsim/bluetooth/audio/src/bap_broadcast_assistant_test.c b/tests/bsim/bluetooth/audio/src/bap_broadcast_assistant_test.c index 86f30cad9f4..58beed0f7bf 100644 --- a/tests/bsim/bluetooth/audio/src/bap_broadcast_assistant_test.c +++ b/tests/bsim/bluetooth/audio/src/bap_broadcast_assistant_test.c @@ -155,14 +155,8 @@ static void bap_broadcast_assistant_recv_state_cb( SET_FLAG(flag_recv_state_updated); } -static void bap_broadcast_assistant_recv_state_removed_cb(struct bt_conn *conn, int err, - uint8_t src_id) +static void bap_broadcast_assistant_recv_state_removed_cb(struct bt_conn *conn, uint8_t src_id) { - if (err != 0) { - FAIL("BASS recv state removed failed (%d)\n", err); - return; - } - printk("BASS recv state %u removed\n", src_id); SET_FLAG(flag_cb_called); diff --git a/tests/bsim/bluetooth/audio/src/bap_broadcast_sink_test.c b/tests/bsim/bluetooth/audio/src/bap_broadcast_sink_test.c index d95251d54d7..7919b4afcc9 100644 --- a/tests/bsim/bluetooth/audio/src/bap_broadcast_sink_test.c +++ b/tests/bsim/bluetooth/audio/src/bap_broadcast_sink_test.c @@ -899,7 +899,7 @@ static void test_start_adv(void) int err; /* Create a non-connectable non-scannable advertising set */ - err = bt_le_ext_adv_create(BT_LE_EXT_ADV_CONN_NAME, NULL, &ext_adv); + err = bt_le_ext_adv_create(BT_LE_EXT_ADV_CONN, NULL, &ext_adv); if (err != 0) { FAIL("Failed to create advertising set (err %d)\n", err); diff --git a/tests/bsim/bluetooth/audio/src/bap_broadcast_source_test.c b/tests/bsim/bluetooth/audio/src/bap_broadcast_source_test.c index 7548147241b..cc0f0a5fc1b 100644 --- a/tests/bsim/bluetooth/audio/src/bap_broadcast_source_test.c +++ b/tests/bsim/bluetooth/audio/src/bap_broadcast_source_test.c @@ -214,7 +214,7 @@ static int setup_extended_adv(struct bt_bap_broadcast_source *source, struct bt_ NET_BUF_SIMPLE_DEFINE(ad_buf, BT_UUID_SIZE_16 + BT_AUDIO_BROADCAST_ID_SIZE); struct bt_le_adv_param adv_param = BT_LE_ADV_PARAM_INIT( - BT_LE_ADV_OPT_EXT_ADV | BT_LE_ADV_OPT_USE_NAME, 0x80, 0x80, NULL); + BT_LE_ADV_OPT_EXT_ADV, 0x80, 0x80, NULL); NET_BUF_SIMPLE_DEFINE(base_buf, 128); struct bt_data ext_ad; struct bt_data per_ad; diff --git a/tests/bsim/bluetooth/audio/src/bap_scan_delegator_test.c b/tests/bsim/bluetooth/audio/src/bap_scan_delegator_test.c index af89a4a8d1b..776fe9ff4b3 100644 --- a/tests/bsim/bluetooth/audio/src/bap_scan_delegator_test.c +++ b/tests/bsim/bluetooth/audio/src/bap_scan_delegator_test.c @@ -680,7 +680,7 @@ static int common_init(void) bt_bap_scan_delegator_register_cb(&scan_delegator_cb); bt_le_per_adv_sync_cb_register(&pa_sync_cb); - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, AD_SIZE, NULL, 0); + err = bt_le_adv_start(BT_LE_ADV_CONN, ad, AD_SIZE, NULL, 0); if (err) { FAIL("Advertising failed to start (err %d)\n", err); return err; diff --git a/tests/bsim/bluetooth/audio/src/bap_unicast_server_test.c b/tests/bsim/bluetooth/audio/src/bap_unicast_server_test.c index 0465948d16f..90e201b1352 100644 --- a/tests/bsim/bluetooth/audio/src/bap_unicast_server_test.c +++ b/tests/bsim/bluetooth/audio/src/bap_unicast_server_test.c @@ -491,7 +491,7 @@ static void init(void) } /* Create a non-connectable non-scannable advertising set */ - err = bt_le_ext_adv_create(BT_LE_EXT_ADV_CONN_NAME, NULL, &ext_adv); + err = bt_le_ext_adv_create(BT_LE_EXT_ADV_CONN, NULL, &ext_adv); if (err != 0) { FAIL("Failed to create advertising set (err %d)\n", err); return; diff --git a/tests/bsim/bluetooth/audio/src/cap_acceptor_test.c b/tests/bsim/bluetooth/audio/src/cap_acceptor_test.c index 051981532c5..9a11cee54ff 100644 --- a/tests/bsim/bluetooth/audio/src/cap_acceptor_test.c +++ b/tests/bsim/bluetooth/audio/src/cap_acceptor_test.c @@ -616,7 +616,7 @@ static void init(void) bt_cap_stream_ops_register(&unicast_streams[i], &unicast_stream_ops); } - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, cap_acceptor_ad, + err = bt_le_adv_start(BT_LE_ADV_CONN, cap_acceptor_ad, ARRAY_SIZE(cap_acceptor_ad), NULL, 0); if (err != 0) { FAIL("Advertising failed to start (err %d)\n", err); diff --git a/tests/bsim/bluetooth/audio/src/cap_commander_test.c b/tests/bsim/bluetooth/audio/src/cap_commander_test.c index 9271a6a12de..8d100ebb826 100644 --- a/tests/bsim/bluetooth/audio/src/cap_commander_test.c +++ b/tests/bsim/bluetooth/audio/src/cap_commander_test.c @@ -36,6 +36,7 @@ CREATE_FLAG(flag_microphone_mute_changed); CREATE_FLAG(flag_microphone_gain_changed); static void cap_discovery_complete_cb(struct bt_conn *conn, int err, + const struct bt_csip_set_coordinator_set_member *member, const struct bt_csip_set_coordinator_csis_inst *csis_inst) { if (err != 0) { diff --git a/tests/bsim/bluetooth/audio/src/cap_initiator_broadcast_test.c b/tests/bsim/bluetooth/audio/src/cap_initiator_broadcast_test.c index 5f1967006d3..34b172ad8ab 100644 --- a/tests/bsim/bluetooth/audio/src/cap_initiator_broadcast_test.c +++ b/tests/bsim/bluetooth/audio/src/cap_initiator_broadcast_test.c @@ -21,8 +21,7 @@ * Broadcast ISO radio events. */ #define BT_LE_EXT_ADV_CUSTOM \ - BT_LE_ADV_PARAM(BT_LE_ADV_OPT_EXT_ADV | \ - BT_LE_ADV_OPT_USE_NAME, \ + BT_LE_ADV_PARAM(BT_LE_ADV_OPT_EXT_ADV, \ 0x0080, 0x0080, NULL) #define BT_LE_PER_ADV_CUSTOM \ diff --git a/tests/bsim/bluetooth/audio/src/cap_initiator_unicast_test.c b/tests/bsim/bluetooth/audio/src/cap_initiator_unicast_test.c index 3ae18ced886..0a4daa04ca1 100644 --- a/tests/bsim/bluetooth/audio/src/cap_initiator_unicast_test.c +++ b/tests/bsim/bluetooth/audio/src/cap_initiator_unicast_test.c @@ -185,6 +185,7 @@ static struct bt_bap_stream_ops unicast_stream_ops = { }; static void cap_discovery_complete_cb(struct bt_conn *conn, int err, + const struct bt_csip_set_coordinator_set_member *member, const struct bt_csip_set_coordinator_csis_inst *csis_inst) { if (err != 0) { diff --git a/tests/bsim/bluetooth/audio/src/csip_notify_server_test.c b/tests/bsim/bluetooth/audio/src/csip_notify_server_test.c index ec94a320ffd..0faa6713d59 100644 --- a/tests/bsim/bluetooth/audio/src/csip_notify_server_test.c +++ b/tests/bsim/bluetooth/audio/src/csip_notify_server_test.c @@ -66,7 +66,7 @@ static void test_main(void) } printk("Start Advertising\n"); - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0); + err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), NULL, 0); if (err != 0) { FAIL("Advertising failed to start (err %d)\n", err); return; @@ -107,7 +107,7 @@ static void test_main(void) } printk("Start Advertising\n"); - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0); + err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), NULL, 0); if (err != 0) { FAIL("Advertising failed to start (err %d)\n", err); return; diff --git a/tests/bsim/bluetooth/audio/src/csip_set_member_test.c b/tests/bsim/bluetooth/audio/src/csip_set_member_test.c index ef2b1dc241d..0833c4e2f8b 100644 --- a/tests/bsim/bluetooth/audio/src/csip_set_member_test.c +++ b/tests/bsim/bluetooth/audio/src/csip_set_member_test.c @@ -70,7 +70,7 @@ static void bt_ready(int err) return; } - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0); + err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), NULL, 0); if (err != 0) { FAIL("Advertising failed to start (err %d)\n", err); } diff --git a/tests/bsim/bluetooth/audio/src/gmap_ugg_test.c b/tests/bsim/bluetooth/audio/src/gmap_ugg_test.c index 0a191d99656..1d686a31016 100644 --- a/tests/bsim/bluetooth/audio/src/gmap_ugg_test.c +++ b/tests/bsim/bluetooth/audio/src/gmap_ugg_test.c @@ -23,8 +23,7 @@ * Broadcast ISO radio events. */ #define BT_LE_EXT_ADV_CUSTOM \ - BT_LE_ADV_PARAM(BT_LE_ADV_OPT_EXT_ADV | \ - BT_LE_ADV_OPT_USE_NAME, \ + BT_LE_ADV_PARAM(BT_LE_ADV_OPT_EXT_ADV, \ 0x0080, 0x0080, NULL) #define BT_LE_PER_ADV_CUSTOM \ @@ -264,6 +263,7 @@ static struct bt_bap_stream_ops stream_ops = { }; static void cap_discovery_complete_cb(struct bt_conn *conn, int err, + const struct bt_csip_set_coordinator_set_member *member, const struct bt_csip_set_coordinator_csis_inst *csis_inst) { if (err != 0) { diff --git a/tests/bsim/bluetooth/audio/src/gmap_ugt_test.c b/tests/bsim/bluetooth/audio/src/gmap_ugt_test.c index a0b4141bf06..2171b6c1aff 100644 --- a/tests/bsim/bluetooth/audio/src/gmap_ugt_test.c +++ b/tests/bsim/bluetooth/audio/src/gmap_ugt_test.c @@ -416,7 +416,7 @@ static void test_main(void) return; } - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, gmap_acceptor_ad, ARRAY_SIZE(gmap_acceptor_ad), + err = bt_le_adv_start(BT_LE_ADV_CONN, gmap_acceptor_ad, ARRAY_SIZE(gmap_acceptor_ad), NULL, 0); if (err != 0) { FAIL("Advertising failed to start (err %d)\n", err); diff --git a/tests/bsim/bluetooth/audio/src/has_test.c b/tests/bsim/bluetooth/audio/src/has_test.c index 1f5c7f62897..949192c4070 100644 --- a/tests/bsim/bluetooth/audio/src/has_test.c +++ b/tests/bsim/bluetooth/audio/src/has_test.c @@ -46,7 +46,7 @@ static void test_common(void) LOG_DBG("Bluetooth initialized"); - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, AD_SIZE, NULL, 0); + err = bt_le_adv_start(BT_LE_ADV_CONN, ad, AD_SIZE, NULL, 0); if (err) { FAIL("Advertising failed to start (err %d)\n", err); return; diff --git a/tests/bsim/bluetooth/audio/src/ias_test.c b/tests/bsim/bluetooth/audio/src/ias_test.c index ef3f46a57e5..72daba4465b 100644 --- a/tests/bsim/bluetooth/audio/src/ias_test.c +++ b/tests/bsim/bluetooth/audio/src/ias_test.c @@ -58,7 +58,7 @@ static void test_main(void) return; } - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, AD_SIZE, NULL, 0); + err = bt_le_adv_start(BT_LE_ADV_CONN, ad, AD_SIZE, NULL, 0); if (err) { FAIL("Advertising failed to start (err %d)\n", err); return; diff --git a/tests/bsim/bluetooth/audio/src/mcs_test.c b/tests/bsim/bluetooth/audio/src/mcs_test.c index 5340d6d9eaf..b94f2cf96e0 100644 --- a/tests/bsim/bluetooth/audio/src/mcs_test.c +++ b/tests/bsim/bluetooth/audio/src/mcs_test.c @@ -22,7 +22,7 @@ static void bt_ready(int err) printk("Bluetooth initialized\n"); - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, AD_SIZE, NULL, 0); + err = bt_le_adv_start(BT_LE_ADV_CONN, ad, AD_SIZE, NULL, 0); if (err) { FAIL("Advertising failed to start (err %d)\n", err); return; diff --git a/tests/bsim/bluetooth/audio/src/media_controller_test.c b/tests/bsim/bluetooth/audio/src/media_controller_test.c index ad91cffb939..cf8ce038c6b 100644 --- a/tests/bsim/bluetooth/audio/src/media_controller_test.c +++ b/tests/bsim/bluetooth/audio/src/media_controller_test.c @@ -1647,7 +1647,7 @@ void test_media_controller_remote_player(void) initialize_bluetooth(); initialize_media(); - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, AD_SIZE, NULL, 0); + err = bt_le_adv_start(BT_LE_ADV_CONN, ad, AD_SIZE, NULL, 0); if (err) { FAIL("Advertising failed to start (err %d)\n", err); } diff --git a/tests/bsim/bluetooth/audio/src/micp_mic_dev_test.c b/tests/bsim/bluetooth/audio/src/micp_mic_dev_test.c index 25d78bdaeb2..ca95b727cb6 100644 --- a/tests/bsim/bluetooth/audio/src/micp_mic_dev_test.c +++ b/tests/bsim/bluetooth/audio/src/micp_mic_dev_test.c @@ -420,7 +420,7 @@ static void test_main(void) printk("MICP initialized\n"); - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, AD_SIZE, NULL, 0); + err = bt_le_adv_start(BT_LE_ADV_CONN, ad, AD_SIZE, NULL, 0); if (err != 0) { FAIL("Advertising failed to start (err %d)\n", err); return; diff --git a/tests/bsim/bluetooth/audio/src/pacs_notify_server_test.c b/tests/bsim/bluetooth/audio/src/pacs_notify_server_test.c index 93adf82d4f1..c60562bcd51 100644 --- a/tests/bsim/bluetooth/audio/src/pacs_notify_server_test.c +++ b/tests/bsim/bluetooth/audio/src/pacs_notify_server_test.c @@ -176,7 +176,7 @@ static void test_main(void) } LOG_DBG("Start Advertising"); - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0); + err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), NULL, 0); if (err != 0) { FAIL("Advertising failed to start (err %d)", err); return; @@ -210,7 +210,7 @@ static void test_main(void) trigger_notifications(); LOG_DBG("Start Advertising"); - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0); + err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), NULL, 0); if (err != 0) { FAIL("Advertising failed to start (err %d)", err); return; @@ -227,7 +227,7 @@ static void test_main(void) } LOG_DBG("Start Advertising"); - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0); + err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), NULL, 0); if (err != 0) { FAIL("Advertising failed to start (err %d)", err); return; @@ -261,7 +261,7 @@ static void test_main(void) } LOG_DBG("Start Advertising"); - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0); + err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), NULL, 0); if (err != 0) { FAIL("Advertising failed to start (err %d)", err); return; diff --git a/tests/bsim/bluetooth/audio/src/pbp_public_broadcast_source_test.c b/tests/bsim/bluetooth/audio/src/pbp_public_broadcast_source_test.c index dec32f366ad..fb5cf85e6b6 100644 --- a/tests/bsim/bluetooth/audio/src/pbp_public_broadcast_source_test.c +++ b/tests/bsim/bluetooth/audio/src/pbp_public_broadcast_source_test.c @@ -217,7 +217,7 @@ 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); + err = bt_le_ext_adv_create(BT_LE_EXT_ADV_NCONN, NULL, adv); if (err != 0) { printk("Unable to create extended advertising set: %d\n", err); diff --git a/tests/bsim/bluetooth/audio/src/tbs_client_test.c b/tests/bsim/bluetooth/audio/src/tbs_client_test.c index 398a44db2fd..b2a6e34fc00 100644 --- a/tests/bsim/bluetooth/audio/src/tbs_client_test.c +++ b/tests/bsim/bluetooth/audio/src/tbs_client_test.c @@ -494,7 +494,7 @@ static void test_main(void) printk("Audio Server: Bluetooth discovered\n"); - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, AD_SIZE, NULL, 0); + err = bt_le_adv_start(BT_LE_ADV_CONN, ad, AD_SIZE, NULL, 0); if (err != 0) { FAIL("Advertising failed to start (err %d)\n", err); return; diff --git a/tests/bsim/bluetooth/audio/src/tmap_server_test.c b/tests/bsim/bluetooth/audio/src/tmap_server_test.c index d731a550b40..00e38e73319 100644 --- a/tests/bsim/bluetooth/audio/src/tmap_server_test.c +++ b/tests/bsim/bluetooth/audio/src/tmap_server_test.c @@ -53,7 +53,7 @@ static void test_main(void) } printk("TMAP initialized. Start advertising...\n"); /* Create a connectable extended advertising set */ - err = bt_le_ext_adv_create(BT_LE_EXT_ADV_CONN_NAME, NULL, &adv); + err = bt_le_ext_adv_create(BT_LE_EXT_ADV_CONN, NULL, &adv); if (err) { printk("Failed to create advertising set (err %d)\n", err); return; diff --git a/tests/bsim/bluetooth/audio/src/vcp_vol_rend_test.c b/tests/bsim/bluetooth/audio/src/vcp_vol_rend_test.c index d4918ab0553..23f02909a8a 100644 --- a/tests/bsim/bluetooth/audio/src/vcp_vol_rend_test.c +++ b/tests/bsim/bluetooth/audio/src/vcp_vol_rend_test.c @@ -1032,7 +1032,7 @@ static void test_main(void) printk("VCP initialized\n"); - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, AD_SIZE, NULL, 0); + err = bt_le_adv_start(BT_LE_ADV_CONN, ad, AD_SIZE, NULL, 0); if (err != 0) { FAIL("Advertising failed to start (err %d)\n", err); return; diff --git a/tests/bsim/bluetooth/audio_samples/broadcast_audio_sink/Kconfig.sysbuild b/tests/bsim/bluetooth/audio_samples/broadcast_audio_sink/Kconfig.sysbuild index 63b369429bd..ff68acec605 100644 --- a/tests/bsim/bluetooth/audio_samples/broadcast_audio_sink/Kconfig.sysbuild +++ b/tests/bsim/bluetooth/audio_samples/broadcast_audio_sink/Kconfig.sysbuild @@ -7,4 +7,4 @@ config NATIVE_SIMULATOR_PRIMARY_MCU_INDEX int # Let's pass the test arguments to the application MCU test # otherwise by default they would have gone to the net core. - default 0 if $(BOARD) = "nrf5340bsim" + default 0 if $(BOARD_TARGET_STRING) = "NRF5340BSIM_NRF5340_CPUAPP" diff --git a/tests/bsim/bluetooth/audio_samples/unicast_audio_client/Kconfig.sysbuild b/tests/bsim/bluetooth/audio_samples/unicast_audio_client/Kconfig.sysbuild index ad82e381a1c..209d7f1cc73 100644 --- a/tests/bsim/bluetooth/audio_samples/unicast_audio_client/Kconfig.sysbuild +++ b/tests/bsim/bluetooth/audio_samples/unicast_audio_client/Kconfig.sysbuild @@ -7,4 +7,4 @@ config NATIVE_SIMULATOR_PRIMARY_MCU_INDEX int # Let's pass the test arguments to the application MCU test # otherwise by default they would have gone to the net core. - default 0 if $(BOARD) = "nrf5340bsim" + default 0 if $(BOARD_TARGET_STRING) = "NRF5340BSIM_NRF5340_CPUAPP" diff --git a/tests/bsim/bluetooth/compile.nrf5340bsim_nrf5340_cpuapp.sh b/tests/bsim/bluetooth/compile.nrf5340bsim_nrf5340_cpuapp.sh index ea9afa930e5..e261adfd960 100755 --- a/tests/bsim/bluetooth/compile.nrf5340bsim_nrf5340_cpuapp.sh +++ b/tests/bsim/bluetooth/compile.nrf5340bsim_nrf5340_cpuapp.sh @@ -16,6 +16,7 @@ app=tests/bsim/bluetooth/ll/conn conf_file=prj_split_privacy.conf sysbuild=1 co app=tests/bsim/bluetooth/ll/bis sysbuild=1 compile app=tests/bsim/bluetooth/ll/cis conf_overlay=overlay-acl_group.conf sysbuild=1 compile +run_in_background ${ZEPHYR_BASE}/tests/bsim/bluetooth/samples/compile.sh run_in_background ${ZEPHYR_BASE}/tests/bsim/bluetooth/audio_samples/compile.sh wait_for_background_jobs diff --git a/tests/bsim/bluetooth/compile.sh b/tests/bsim/bluetooth/compile.sh index 84a4f8c981a..499626d1487 100755 --- a/tests/bsim/bluetooth/compile.sh +++ b/tests/bsim/bluetooth/compile.sh @@ -20,6 +20,7 @@ ${ZEPHYR_BASE}/tests/bsim/bluetooth/audio_samples/compile.sh ${ZEPHYR_BASE}/tests/bsim/bluetooth/host/compile.sh ${ZEPHYR_BASE}/tests/bsim/bluetooth/ll/compile.sh ${ZEPHYR_BASE}/tests/bsim/bluetooth/mesh/compile.sh +${ZEPHYR_BASE}/tests/bsim/bluetooth/samples/compile.sh if [ ${BOARD} == "nrf52_bsim" ]; then ${ZEPHYR_BASE}/tests/bsim/bluetooth/hci_uart/compile.sh fi diff --git a/tests/bsim/bluetooth/host/adv/compile.sh b/tests/bsim/bluetooth/host/adv/compile.sh index b0adc922df6..c17c1395d17 100755 --- a/tests/bsim/bluetooth/host/adv/compile.sh +++ b/tests/bsim/bluetooth/host/adv/compile.sh @@ -20,7 +20,9 @@ app=tests/bsim/bluetooth/host/adv/extended conf_file=prj_advertiser.conf compile app=tests/bsim/bluetooth/host/adv/extended conf_file=prj_scanner.conf compile app=tests/bsim/bluetooth/host/adv/periodic compile app=tests/bsim/bluetooth/host/adv/periodic conf_file=prj_long_data.conf compile +app=tests/bsim/bluetooth/host/adv/periodic conf_file=prj_coded.conf compile app=tests/bsim/bluetooth/host/adv/encrypted/css_sample_data compile app=tests/bsim/bluetooth/host/adv/encrypted/ead_sample compile +app=tests/bsim/bluetooth/host/adv/long_ad compile wait_for_background_jobs diff --git a/tests/bsim/bluetooth/host/adv/extended/src/ext_adv_advertiser.c b/tests/bsim/bluetooth/host/adv/extended/src/ext_adv_advertiser.c index bfeeb8a25be..b23430c4cc6 100644 --- a/tests/bsim/bluetooth/host/adv/extended/src/ext_adv_advertiser.c +++ b/tests/bsim/bluetooth/host/adv/extended/src/ext_adv_advertiser.c @@ -45,7 +45,7 @@ static void create_ext_adv_set(struct bt_le_ext_adv **adv, bool connectable) printk("Creating extended advertising set..."); const struct bt_le_adv_param *adv_param = connectable ? - BT_LE_EXT_ADV_CONN_NAME : BT_LE_EXT_ADV_NCONN_NAME; + BT_LE_EXT_ADV_CONN : BT_LE_EXT_ADV_NCONN; err = bt_le_ext_adv_create(adv_param, NULL, adv); if (err) { diff --git a/tests/bsim/bluetooth/host/adv/long_ad/CMakeLists.txt b/tests/bsim/bluetooth/host/adv/long_ad/CMakeLists.txt new file mode 100644 index 00000000000..c33acdb226d --- /dev/null +++ b/tests/bsim/bluetooth/host/adv/long_ad/CMakeLists.txt @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) + +project(long_ad) + +# This contains babblesim-specific helpers, e.g. device synchronization. +add_subdirectory(${ZEPHYR_BASE}/tests/bsim/babblekit babblekit) +target_link_libraries(app PRIVATE babblekit) + +zephyr_include_directories( + ${BSIM_COMPONENTS_PATH}/libUtilv1/src/ + ${BSIM_COMPONENTS_PATH}/libPhyComv1/src/ +) + +target_sources(app PRIVATE + src/main.c + src/advertiser.c + src/scanner.c +) diff --git a/tests/bsim/bluetooth/host/adv/long_ad/prj.conf b/tests/bsim/bluetooth/host/adv/long_ad/prj.conf new file mode 100644 index 00000000000..46b0393ec53 --- /dev/null +++ b/tests/bsim/bluetooth/host/adv/long_ad/prj.conf @@ -0,0 +1,26 @@ +CONFIG_BT=y +CONFIG_BT_DEVICE_NAME="long-ad" + +CONFIG_BT_BROADCASTER=y +CONFIG_BT_OBSERVER=y + +CONFIG_BT_EXT_ADV=y + +CONFIG_BT_CTLR_ADV_DATA_CHAIN=y +CONFIG_BT_CTLR_ADVANCED_FEATURES=y + +CONFIG_BT_EXT_SCAN_BUF_SIZE=266 +CONFIG_BT_CTLR_ADV_DATA_BUF_MAX=2 +CONFIG_BT_CTLR_ADV_DATA_LEN_MAX=266 +CONFIG_BT_CTLR_SCAN_DATA_LEN_MAX=266 + +CONFIG_BT_EXT_ADV_MAX_ADV_SET=1 + +CONFIG_ASSERT=y + +CONFIG_LOG=y + +# Will call `raise(SIGTRAP)` on fatal error. +# If a debugger is connected to the app, it will automatically be stopped. +# Makes retrieving an exception stacktrace very easy. +CONFIG_ARCH_POSIX_TRAP_ON_FATAL=y diff --git a/tests/bsim/bluetooth/host/adv/long_ad/src/ad.h b/tests/bsim/bluetooth/host/adv/long_ad/src/ad.h new file mode 100644 index 00000000000..b6e05df1d12 --- /dev/null +++ b/tests/bsim/bluetooth/host/adv/long_ad/src/ad.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +static const uint8_t test_ad1[] = { + 0xe9, 0xff, 0x7c, 0xe8, 0x40, 0x60, 0x3a, 0x10, 0x43, 0xba, 0x2e, 0x75, 0xbd, 0x0a, 0x07, + 0xe2, 0xf1, 0x61, 0x56, 0xea, 0xc1, 0x70, 0x98, 0x6f, 0x8a, 0xb1, 0x74, 0x52, 0x43, 0x6f, + 0x47, 0xbf, 0x81, 0x95, 0x60, 0xe7, 0x80, 0x68, 0x9a, 0x16, 0xe9, 0xa8, 0x61, 0x03, 0x3a, + 0x3e, 0xc1, 0x8e, 0x2a, 0xde, 0x27, 0x9b, 0xaa, 0xe7, 0x7d, 0x79, 0x20, 0x5e, 0xd0, 0x4a, + 0xb3, 0xd7, 0x5a, 0x3c, 0xfc, 0x1b, 0x6e, 0xd6, 0x19, 0x3b, 0xa7, 0x94, 0xc1, 0xeb, 0x1e, + 0x6c, 0x94, 0x76, 0x6f, 0x45, 0x0f, 0x72, 0x22, 0xbf, 0x3c, 0x4a, 0xaf, 0x0f, 0xf8, 0x82, + 0xa6, 0xa6, 0x2a, 0x9f, 0x15, 0x93, 0x38, 0x5b, 0x71, 0xec, 0x0d, 0xed, 0xfe, 0x26, 0x8a, + 0xca, 0x2b, 0x29, 0x9a, 0x55, 0x9d, 0x14, 0xf1, 0x21, 0x10, 0xa4, 0x05, 0x5f, 0xf8, 0x46, + 0x73, 0x90, 0xc3, 0x62, 0x46, 0x57, 0x36, 0x65, 0xfc, 0x98, 0xc1, 0xe5, 0xc6, 0xcd, 0x58, + 0xc0, 0xa9, 0x97, 0x76, 0x43, 0x8c, 0x84, 0xac, 0xa2, 0x84, 0xe3, 0xe0, 0x45, 0x1c, 0xb9, + 0xc2, 0x44, 0xdc, 0xbc, 0x15, 0x3c, 0x81, 0x0f, 0x65, 0x13, 0xc6, 0xe1, 0x8b, 0x74, 0xb1, + 0x1f, 0x54, 0x67, 0xfc, 0x1d, 0x72, 0x4d, 0x4f, 0x29, 0x61, 0x4c, 0xf9, 0x3f, 0xfc, 0x98, + 0xf6, 0x00, 0xbe, 0xfd, 0x17, 0x51, 0x86, 0x21, 0x83, 0x32, 0x87, 0xed, 0xdf, 0xb9, 0xc1, + 0xc9, 0xe7, 0x3a, 0xe7, 0x12, 0x19, 0x98, 0x2e, 0x9d, 0xcc, 0xa8, 0xa9, 0x94, 0xe9, 0x31, + 0xb1, 0xa0, 0xf0, 0xd1, 0x72, 0x1c, 0xfe, 0x21, 0xa0, 0xb9, 0xf0, 0x47, 0x15, 0xa1, 0x1a, + 0x7a, 0x80, 0xac, 0x0d, 0x2b, 0xa7, 0x7a, 0x2f, 0x22, 0x97, 0xff, 0x45, 0x13, 0xaf, 0xb9, + 0x82, 0x68, 0xfc, 0x52, 0xd1, 0xff, 0xc5, 0x03, 0x01, 0xc1, 0x21, 0xd3, 0xfc, 0xb1, 0xcd, + 0x65, 0xd5, 0x7e, 0x1b, 0x81, 0x7c, 0x62, 0x7d, 0x24, 0x9e, 0xfa, 0xe7, 0x12, 0x01, 0x9a, + 0x19, 0x11, 0xa7, 0x50, 0x40, 0x1b, 0x99, 0xb9, 0xf4, 0x17, 0xbe, 0xbe, 0x8d, 0xaa, 0xde, + 0xdd, 0xba, 0xfe, 0xb2, 0x76, 0x50, 0x99, 0xb4, 0xf4, 0x0e, 0x8e, 0xea, 0x8e, 0x90, 0x2e, + 0x77, 0xc9, 0xd2, 0xa9, 0xe2, 0xd5, 0xdb, 0x51, 0x77, 0xf4, 0x87, 0xb8, 0xb7, 0xc9, 0x0b, + 0x8e, 0x3c, 0x7c, 0x8e, 0xf6, 0x0a, 0xb1, 0x26, 0x25, 0xba, 0x73, 0x09, 0x25, 0x14, 0x32, + 0xd9, 0xba, 0x2c, 0x52, 0xd2, 0x9a, 0xfc, 0xae, 0xd6, 0xcc, 0x9d, 0xc3, 0xf9, 0x4e, 0x1a, + 0x37, 0x15, 0x3f, 0x1b, 0x86, 0x6a, 0x0a, 0x08, 0xe6, 0x1e, 0xcc, 0xf6, 0xe6, 0xca, 0x19, + 0x93, 0x61, 0x5f, 0x32, 0x34, 0x4b, 0xc6, 0x3d, 0x3d, 0x21, 0x66, 0x82, 0xaa, 0x68, 0x4d, + 0x08, 0x4b, 0x6d, 0x34, 0x98, 0x28, 0xdd, 0xa5, 0xae, 0x43, 0xe3, +}; +BUILD_ASSERT(sizeof(test_ad1) > CONFIG_BT_CTLR_ADV_DATA_LEN_MAX); + +static const uint8_t test_ad2[] = { + 0xff, 0xff, 0x1d, 0x10, 0x11, 0x25, 0x2c, 0x1b, 0x9a, 0x18, 0xb3, 0xea, 0x99, 0x70, 0x93, + 0x4e, 0x5b, 0x93, 0x27, 0x86, 0xd9, 0x03, 0xf4, 0x22, 0x32, 0x09, 0x37, 0xed, 0x80, 0xe1, + 0xb2, 0xb8, 0x0d, 0x33, 0x70, 0x1e, 0xf1, 0x22, 0x73, 0xe5, 0xea, 0x33, 0x51, 0x98, 0x72, + 0x0a, 0xfc, 0x99, 0xbf, 0xe5, 0x28, 0x09, 0x7e, 0x7b, 0xab, 0xbb, 0xad, 0xc9, 0x92, 0x54, + 0x2d, 0xcd, 0x9c, 0x24, 0xba, 0x06, 0xa4, 0xbc, 0xad, 0x47, 0x7a, 0xa2, 0xac, 0x06, 0xb1, + 0xa6, 0xc5, 0x9c, 0x46, 0x5c, 0xdf, 0x74, 0x60, 0xa9, 0xa8, 0xe1, 0x7f, 0x48, 0x2e, 0x34, + 0xcc, 0xd2, 0x20, 0x4e, 0x7a, 0xa1, 0x2c, 0x3a, 0x84, 0x0b, 0x34, 0x39, 0xd5, 0x6f, 0x85, + 0x44, 0xf3, 0x93, 0xc0, 0xe5, 0x3e, 0xc0, 0x26, 0xa0, 0xe4, 0x21, 0xac, 0xf8, 0xa0, 0x19, + 0xb6, 0xdd, 0xe7, 0xb7, 0x44, 0x25, 0x42, 0x70, 0xf2, 0xb2, 0x36, 0x75, 0x77, 0xbb, 0x8c, + 0x86, 0x9f, 0x58, 0x29, 0xa9, 0xcd, 0xa3, 0x2b, 0x40, 0x53, 0x87, 0xd5, 0xe6, 0x14, 0x9f, + 0xec, 0x71, 0x9a, 0x75, 0x04, 0x50, 0xab, 0x9b, 0x46, 0x53, 0xdf, 0x95, 0xd8, 0xb6, 0x67, + 0xc9, 0x6b, 0x83, 0x36, 0x94, 0x67, 0x62, 0x98, 0xb8, 0xd8, 0xc1, 0x88, 0xa0, 0x3c, 0x98, + 0xbb, 0xd1, 0x68, 0x20, 0x26, 0x48, 0x89, 0x94, 0xca, 0x8b, 0xe2, 0x1d, 0xb4, 0xb5, 0xc0, + 0xef, 0x4f, 0xa7, 0x19, 0xaa, 0xd1, 0x95, 0xb2, 0x23, 0x88, 0xd0, 0x5a, 0x5a, 0x5d, 0xad, + 0x7e, 0x1e, 0x68, 0xd1, 0xa0, 0x64, 0xd1, 0xf9, 0x59, 0x72, 0xde, 0x00, 0x90, 0x49, 0x97, + 0xb3, 0x50, 0xdf, 0xb5, 0x15, 0x41, 0x72, 0x8c, 0x32, 0x66, 0xff, 0x4b, 0x2f, 0xd6, 0x89, + 0x97, 0x52, 0xd8, 0xba, 0xb2, 0xd0, 0x5b, 0x11, 0x8b, 0x38, 0xa2, 0x42, 0xfb, 0x47, 0xfe, + 0xb5, 0x09, 0x09, 0xf0, 0x9f, 0x94, 0xb5, 0xf0, 0x9f, 0xa6, 0xb7, +}; +BUILD_ASSERT(sizeof(test_ad2) == CONFIG_BT_CTLR_ADV_DATA_LEN_MAX); diff --git a/tests/bsim/bluetooth/host/adv/long_ad/src/advertiser.c b/tests/bsim/bluetooth/host/adv/long_ad/src/advertiser.c new file mode 100644 index 00000000000..b4fbc02b0d2 --- /dev/null +++ b/tests/bsim/bluetooth/host/adv/long_ad/src/advertiser.c @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include +#include +#include + +#include "ad.h" +#include "babblekit/testcase.h" + +LOG_MODULE_REGISTER(advertiser, LOG_LEVEL_INF); + +static void create_adv(struct bt_le_ext_adv **adv) +{ + int err; + struct bt_le_adv_param params; + + memset(¶ms, 0, sizeof(struct bt_le_adv_param)); + + params.options |= BT_LE_ADV_OPT_EXT_ADV; + + params.id = BT_ID_DEFAULT; + params.sid = 0; + params.interval_min = BT_GAP_ADV_SLOW_INT_MIN; + params.interval_max = BT_GAP_ADV_SLOW_INT_MAX; + + err = bt_le_ext_adv_create(¶ms, NULL, adv); + if (err) { + TEST_FAIL("Failed to create advertiser (%d)\n", err); + } +} + +static void start_adv(struct bt_le_ext_adv *adv) +{ + int err; + int32_t timeout = 0; + uint8_t num_events = 0; + + struct bt_le_ext_adv_start_param start_params; + + start_params.timeout = timeout; + start_params.num_events = num_events; + + err = bt_le_ext_adv_start(adv, &start_params); + if (err) { + TEST_FAIL("Failed to start advertiser (%d)\n", err); + } +} + +static size_t ad_deserialize(const uint8_t *input, size_t input_size, struct bt_data output[]) +{ + uint8_t type; + uint8_t data_len; + const uint8_t *data; + + size_t idx = 0; + size_t ad_len = 0; + + while (idx < input_size) { + data_len = input[idx] - 1; + type = input[idx + 1]; + data = &input[idx + 2]; + + if (data_len + 2 > input_size - idx) { + TEST_FAIL("malformed advertising data, expected %d bytes of data but got " + "only %d " + "bytes", + data_len + 1, input_size - idx); + return -1; + } + + output[ad_len].data = data; + output[ad_len].type = type; + output[ad_len].data_len = data_len; + + ad_len += 1; + idx += data_len + 2; + } + + return ad_len; +} + +static int set_ad_data(struct bt_le_ext_adv *adv, const uint8_t *serialized_ad, + size_t serialized_ad_size) +{ + int err; + size_t ad_len = 0; + uint8_t max_ad_len = 10; + + struct bt_data ad[max_ad_len]; + + ad_len = ad_deserialize(serialized_ad, serialized_ad_size, ad); + + err = bt_le_ext_adv_set_data(adv, ad, ad_len, NULL, 0); + if (err != 0 && err != -EDOM) { + TEST_FAIL("Failed to set advertising data (%d)\n", err); + } + + return err; +} + +void entrypoint_advertiser(void) +{ + /* Test purpose: + * + * Verifies that we can send Advertising Data up to the size set in the + * Kconfig. And if we try to set data too large we get the correct + * error code. + * + * Two devices: + * - `advertiser`: tries to send the data + * - `scanner`: will receive the data and check that they match with the + * data sent + * + * Procedure: + * - [advertiser] try to use `test_ad1` as advertising data + * - [advertiser] get the expected error (adv or scan resp too large) + * - [advertiser] try to use `test_ad2` as advertising data + * - [advertiser] get a success + * - [advertiser] start advertiser + * - [scanner] start scanner + * - [scanner] wait until receiving advertising data matching `test_ad2` + * + * [verdict] + * - advertiser receives the correct error code when trying to set + * advertising data + * - scanner receives the correct data in advertising data + */ + int err; + struct bt_le_ext_adv *adv = NULL; + + TEST_START("advertiser"); + + err = bt_enable(NULL); + TEST_ASSERT(err == 0, "Can't enable Bluetooth (err %d)", err); + + LOG_DBG("Bluetooth initialized"); + + create_adv(&adv); + LOG_DBG("Advertiser created"); + + err = set_ad_data(adv, test_ad1, ARRAY_SIZE(test_ad1)); + TEST_ASSERT(err == -EDOM, + "Tried to set Advertising Data larger than the controller can accept, " + "expected failure with error code %d but got %d", + -EDOM, err); + + err = set_ad_data(adv, test_ad2, ARRAY_SIZE(test_ad2)); + TEST_ASSERT(err == 0, + "Tried to set Advertising Data as large as the maximum advertising data size " + "the controller can accept, expected success but got error code %d", + err); + LOG_DBG("AD set"); + + start_adv(adv); + LOG_DBG("Advertiser started"); + + TEST_PASS("advertiser"); +} diff --git a/tests/bsim/bluetooth/host/adv/long_ad/src/main.c b/tests/bsim/bluetooth/host/adv/long_ad/src/main.c new file mode 100644 index 00000000000..00144d6092d --- /dev/null +++ b/tests/bsim/bluetooth/host/adv/long_ad/src/main.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "bs_tracing.h" +#include "bstests.h" +#include "babblekit/testcase.h" + +extern void entrypoint_advertiser(void); +extern void entrypoint_scanner(void); +extern enum bst_result_t bst_result; + +static void test_end_cb(void) +{ + /* This callback will fire right before the executable returns */ + static const char demo_state[] = "My interesting state"; + + if (bst_result != Passed) { + TEST_PRINT("Test has not passed. State: %s", demo_state); + } +} + +static const struct bst_test_instance entrypoints[] = { + { + .test_id = "advertiser", + .test_delete_f = test_end_cb, + .test_main_f = entrypoint_advertiser, + }, + { + .test_id = "scanner", + .test_delete_f = test_end_cb, + .test_main_f = entrypoint_scanner, + }, + BSTEST_END_MARKER, +}; + +static struct bst_test_list *install(struct bst_test_list *tests) +{ + return bst_add_tests(tests, entrypoints); +}; + +bst_test_install_t test_installers[] = {install, NULL}; + +int main(void) +{ + bst_main(); + + return 0; +} diff --git a/tests/bsim/bluetooth/host/adv/long_ad/src/scanner.c b/tests/bsim/bluetooth/host/adv/long_ad/src/scanner.c new file mode 100644 index 00000000000..b1d17877b74 --- /dev/null +++ b/tests/bsim/bluetooth/host/adv/long_ad/src/scanner.c @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include +#include +#include + +#include "ad.h" + +#include "babblekit/flags.h" +#include "babblekit/testcase.h" + +LOG_MODULE_REGISTER(scanner, LOG_LEVEL_INF); + +DEFINE_FLAG(scan_received); + +static bool data_parse_cb(struct bt_data *data, void *user_data) +{ + LOG_DBG("Type: %02x (size: %d)", data->type, data->data_len); + LOG_HEXDUMP_DBG(data->data, data->data_len, "Data:"); + + return true; +} + +static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type, + struct net_buf_simple *ad) +{ + char addr_str[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(addr, addr_str, sizeof(addr_str)); + + LOG_DBG("Device found: %s (RSSI %d)", addr_str, rssi); + + if (ad->len > 0) { + LOG_INF("Received AD of size %d", ad->len); + + TEST_ASSERT(ad->len == ARRAY_SIZE(test_ad2), + "Received %d bytes of Advertising Data %d bytes were expected", ad->len, + ARRAY_SIZE(test_ad2)); + + if (memcmp(ad->data, test_ad2, ad->len) != 0) { + LOG_HEXDUMP_ERR(ad->data, ad->len, "Received AD:"); + LOG_HEXDUMP_ERR(test_ad2, ARRAY_SIZE(test_ad2), "Expected AD:"); + TEST_FAIL("Received Advertising Data doesn't match expected ones"); + } + } + + bt_data_parse(ad, data_parse_cb, NULL); + + SET_FLAG(scan_received); +} + +static void start_scan(void) +{ + int err; + + err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, device_found); + if (err) { + TEST_FAIL("Scanning failed to start (err %d)\n", err); + } + + LOG_DBG("Scanning successfully started"); +} + +void entrypoint_scanner(void) +{ + /* Test purpose: + * + * Verifies that we can send Advertising Data up to the size set in the + * Kconfig. And if we try to set data too large we get the correct + * error code. + * + * Two devices: + * - `advertiser`: tries to send the data + * - `scanner`: will receive the data and check that they match with the + * data sent + * + * Procedure: + * - [advertiser] try to use `test_ad1` as advertising data + * - [advertiser] get the expected error (adv or scan resp too large) + * - [advertiser] try to use `test_ad2` as advertising data + * - [advertiser] get a success + * - [advertiser] start advertiser + * - [scanner] start scanner + * - [scanner] wait until receiving advertising data matching `test_ad2` + * + * [verdict] + * - advertiser receives the correct error code when trying to set + * advertising data + * - scanner receives the correct data in advertising data + */ + int err; + + TEST_START("scanner"); + + err = bt_enable(NULL); + TEST_ASSERT(err == 0, "Can't enable Bluetooth (err %d)", err); + + LOG_DBG("Bluetooth initialized"); + + start_scan(); + + LOG_DBG("Wait until we receive at least one AD"); + WAIT_FOR_FLAG(scan_received); + + TEST_PASS_AND_EXIT("scanner"); +} diff --git a/tests/bsim/bluetooth/host/adv/long_ad/test_scripts/_compile.sh b/tests/bsim/bluetooth/host/adv/long_ad/test_scripts/_compile.sh new file mode 100755 index 00000000000..e717a4b2bbe --- /dev/null +++ b/tests/bsim/bluetooth/host/adv/long_ad/test_scripts/_compile.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +# Copyright 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 +set -eu +: "${ZEPHYR_BASE:?ZEPHYR_BASE must be defined}" + +INCR_BUILD=1 + +source ${ZEPHYR_BASE}/tests/bsim/compile.source + +app="$(guess_test_relpath)" compile + +wait_for_background_jobs diff --git a/tests/bsim/bluetooth/host/adv/long_ad/test_scripts/run.sh b/tests/bsim/bluetooth/host/adv/long_ad/test_scripts/run.sh new file mode 100755 index 00000000000..ad78f49e54e --- /dev/null +++ b/tests/bsim/bluetooth/host/adv/long_ad/test_scripts/run.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +# Copyright (c) 2024 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +set -eu + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +test_name="$(guess_test_long_name)" + +simulation_id=${test_name} + +verbosity_level=2 + +SIM_LEN_US=$((2 * 1000 * 1000)) + +test_exe="${BSIM_OUT_PATH}/bin/bs_${BOARD_TS}_${test_name}_prj_conf" + +cd ${BSIM_OUT_PATH}/bin + +Execute "${test_exe}" -v=${verbosity_level} -s=${simulation_id} -d=0 -rs=420 -testid=advertiser +Execute "${test_exe}" -v=${verbosity_level} -s=${simulation_id} -d=1 -rs=69 -testid=scanner + +Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} -D=2 -sim_length=${SIM_LEN_US} $@ + +wait_for_background_jobs diff --git a/tests/bsim/bluetooth/host/adv/periodic/CMakeLists.txt b/tests/bsim/bluetooth/host/adv/periodic/CMakeLists.txt index ebf037dffce..85b2a61c9db 100644 --- a/tests/bsim/bluetooth/host/adv/periodic/CMakeLists.txt +++ b/tests/bsim/bluetooth/host/adv/periodic/CMakeLists.txt @@ -9,7 +9,7 @@ target_sources(app PRIVATE src/common.c src/main.c src/per_adv_advertiser.c - src/per_adv_syncer.c + src/per_adv_sync.c ) zephyr_include_directories( diff --git a/tests/bsim/bluetooth/host/adv/periodic/prj_coded.conf b/tests/bsim/bluetooth/host/adv/periodic/prj_coded.conf new file mode 100644 index 00000000000..50c4c33e08a --- /dev/null +++ b/tests/bsim/bluetooth/host/adv/periodic/prj_coded.conf @@ -0,0 +1,15 @@ +CONFIG_BT=y +CONFIG_BT_DEVICE_NAME="test_per_adv" +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_CENTRAL=y +CONFIG_BT_SMP=y +CONFIG_BT_PRIVACY=y + +CONFIG_BT_EXT_ADV=y +CONFIG_BT_EXT_ADV_MAX_ADV_SET=2 +CONFIG_BT_CTLR_ADVANCED_FEATURES=y +CONFIG_BT_CTLR_ADV_AUX_SET=2 +CONFIG_BT_CTLR_ADV_DATA_BUF_MAX=2 +CONFIG_BT_CTLR_PHY_CODED=y +CONFIG_BT_PER_ADV=y +CONFIG_BT_PER_ADV_SYNC=y diff --git a/tests/bsim/bluetooth/host/adv/periodic/src/main.c b/tests/bsim/bluetooth/host/adv/periodic/src/main.c index a71ffa91d01..a2465921d5a 100644 --- a/tests/bsim/bluetooth/host/adv/periodic/src/main.c +++ b/tests/bsim/bluetooth/host/adv/periodic/src/main.c @@ -6,11 +6,11 @@ #include "bstests.h" -extern struct bst_test_list *test_per_adv_syncer(struct bst_test_list *tests); +extern struct bst_test_list *test_per_adv_sync(struct bst_test_list *tests); extern struct bst_test_list *test_per_adv_advertiser(struct bst_test_list *tests); bst_test_install_t test_installers[] = { - test_per_adv_syncer, + test_per_adv_sync, test_per_adv_advertiser, NULL }; diff --git a/tests/bsim/bluetooth/host/adv/periodic/src/per_adv_advertiser.c b/tests/bsim/bluetooth/host/adv/periodic/src/per_adv_advertiser.c index e778ee27235..3808ec6ba30 100644 --- a/tests/bsim/bluetooth/host/adv/periodic/src/per_adv_advertiser.c +++ b/tests/bsim/bluetooth/host/adv/periodic/src/per_adv_advertiser.c @@ -89,7 +89,7 @@ static void create_per_adv_set(struct bt_le_ext_adv **adv) int err; printk("Creating extended 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_NCONN, NULL, adv); if (err) { printk("Failed to create advertising set: %d\n", err); return; @@ -106,12 +106,36 @@ static void create_per_adv_set(struct bt_le_ext_adv **adv) printk("done.\n"); } +#if defined(CONFIG_BT_CTLR_PHY_CODED) +static void create_per_adv_set_coded(struct bt_le_ext_adv **adv) +{ + int err; + + printk("Creating coded PHY extended advertising set..."); + err = bt_le_ext_adv_create(BT_LE_EXT_ADV_CODED_NCONN, NULL, adv); + if (err) { + printk("Failed to create advertising set: %d\n", err); + return; + } + printk("done.\n"); + + printk("Setting 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; + } + printk("done.\n"); +} +#endif /* CONFIG_BT_CTLR_PHY_CODED */ + static void create_conn_adv_set(struct bt_le_ext_adv **adv) { int err; printk("Creating connectable extended advertising set..."); - err = bt_le_ext_adv_create(BT_LE_EXT_ADV_CONN_NAME, NULL, adv); + err = bt_le_ext_adv_create(BT_LE_EXT_ADV_CONN, NULL, adv); if (err) { printk("Failed to create advertising set: %d\n", err); return; @@ -228,6 +252,31 @@ static void main_per_adv_advertiser(void) PASS("Periodic advertiser passed\n"); } +#if defined(CONFIG_BT_CTLR_PHY_CODED) +static void main_per_adv_advertiser_coded(void) +{ + struct bt_le_ext_adv *per_adv; + + common_init(); + + create_per_adv_set_coded(&per_adv); + + start_per_adv_set(per_adv); + start_ext_adv_set(per_adv); + + /* Advertise for a bit */ + k_sleep(K_SECONDS(10)); + + stop_per_adv_set(per_adv); + stop_ext_adv_set(per_adv); + + delete_adv_set(per_adv); + per_adv = NULL; + + PASS("Periodic advertiser coded PHY passed\n"); +} +#endif /* CONFIG_BT_CTLR_PHY_CODED */ + static void main_per_adv_conn_advertiser(void) { struct bt_le_ext_adv *conn_adv; @@ -329,6 +378,16 @@ static const struct bst_test_instance per_adv_advertiser[] = { .test_tick_f = test_tick, .test_main_f = main_per_adv_advertiser }, +#if defined(CONFIG_BT_CTLR_PHY_CODED) + { + .test_id = "per_adv_advertiser_coded_phy", + .test_descr = "Basic periodic advertising test on Coded PHY. " + "Advertiser and periodic advertiser uses Coded PHY", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = main_per_adv_advertiser_coded + }, +#endif /* CONFIG_BT_CTLR_PHY_CODED */ { .test_id = "per_adv_conn_advertiser", .test_descr = "Periodic advertising test with concurrent ACL " @@ -348,7 +407,7 @@ static const struct bst_test_instance per_adv_advertiser[] = { { .test_id = "per_adv_long_data_advertiser", .test_descr = "Periodic advertising test with a longer data length. " - "To test the syncers reassembly of large data packets", + "To test the reassembly of large data packets", .test_post_init_f = test_init, .test_tick_f = test_tick, .test_main_f = main_per_adv_long_data_advertiser diff --git a/tests/bsim/bluetooth/host/adv/periodic/src/per_adv_sync.c b/tests/bsim/bluetooth/host/adv/periodic/src/per_adv_sync.c new file mode 100644 index 00000000000..c2ff633d23d --- /dev/null +++ b/tests/bsim/bluetooth/host/adv/periodic/src/per_adv_sync.c @@ -0,0 +1,416 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include + +#include "bs_types.h" +#include "bs_tracing.h" +#include "time_machine.h" +#include "bstests.h" + +#include +#include + +#include + +#include "common.h" + +extern enum bst_result_t bst_result; + +static struct bt_conn *g_conn; +static bt_addr_le_t per_addr; +static uint8_t per_sid; + +CREATE_FLAG(flag_connected); +CREATE_FLAG(flag_bonded); +CREATE_FLAG(flag_per_adv); +CREATE_FLAG(flag_per_adv_sync); +CREATE_FLAG(flag_per_adv_sync_lost); +CREATE_FLAG(flag_per_adv_recv); + +static void connected(struct bt_conn *conn, uint8_t err) +{ + char addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + if (err != BT_HCI_ERR_SUCCESS) { + FAIL("Failed to connect to %s: %u\n", addr, err); + return; + } + + printk("Connected to %s\n", addr); + g_conn = bt_conn_ref(conn); + SET_FLAG(flag_connected); +} + +static void disconnected(struct bt_conn *conn, uint8_t reason) +{ + char addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + printk("Disconnected: %s (reason %u)\n", addr, reason); + + bt_conn_unref(g_conn); + g_conn = NULL; +} + +static struct bt_conn_cb conn_cbs = { + .connected = connected, + .disconnected = disconnected, +}; + +static void pairing_complete_cb(struct bt_conn *conn, bool bonded) +{ + if (conn == g_conn && bonded) { + SET_FLAG(flag_bonded); + } +} + +static struct bt_conn_auth_info_cb auto_info_cbs = { + .pairing_complete = pairing_complete_cb, +}; + +static void scan_recv(const struct bt_le_scan_recv_info *info, + struct net_buf_simple *buf) +{ + if (!TEST_FLAG(flag_connected) && + info->adv_props & BT_GAP_ADV_PROP_CONNECTABLE) { + int err; + + printk("Stopping scan\n"); + err = bt_le_scan_stop(); + if (err != 0) { + FAIL("Failed to stop scan: %d", err); + return; + } + + err = bt_conn_le_create(info->addr, BT_CONN_LE_CREATE_CONN, + BT_LE_CONN_PARAM_DEFAULT, &g_conn); + if (err != 0) { + FAIL("Could not connect to peer: %d", err); + return; + } + } else if (!TEST_FLAG(flag_per_adv) && info->interval != 0U) { + + per_sid = info->sid; + bt_addr_le_copy(&per_addr, info->addr); + + SET_FLAG(flag_per_adv); + } +} + +static struct bt_le_scan_cb scan_callbacks = { + .recv = scan_recv, +}; + +static void sync_cb(struct bt_le_per_adv_sync *sync, + struct bt_le_per_adv_sync_synced_info *info) +{ + char le_addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr)); + + printk("PER_ADV_SYNC[%u]: [DEVICE]: %s synced, " + "Interval 0x%04x (%u us)\n", + bt_le_per_adv_sync_get_index(sync), le_addr, + info->interval, BT_CONN_INTERVAL_TO_US(info->interval)); + + SET_FLAG(flag_per_adv_sync); +} + +static void term_cb(struct bt_le_per_adv_sync *sync, + const struct bt_le_per_adv_sync_term_info *info) +{ + char le_addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr)); + + printk("PER_ADV_SYNC[%u]: [DEVICE]: %s sync terminated\n", + bt_le_per_adv_sync_get_index(sync), le_addr); + + SET_FLAG(flag_per_adv_sync_lost); +} + +static void recv_cb(struct bt_le_per_adv_sync *recv_sync, + const struct bt_le_per_adv_sync_recv_info *info, + struct net_buf_simple *buf) +{ + char le_addr[BT_ADDR_LE_STR_LEN]; + uint8_t buf_data_len; + + if (TEST_FLAG(flag_per_adv_recv)) { + return; + } + + bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr)); + printk("PER_ADV_SYNC[%u]: [DEVICE]: %s advertisment received\n", + bt_le_per_adv_sync_get_index(recv_sync), le_addr); + + while (buf->len > 0) { + buf_data_len = (uint8_t)net_buf_simple_pull_le16(buf); + if (buf->data[0] - 1 != sizeof(mfg_data) || + memcmp(buf->data, mfg_data, sizeof(mfg_data))) { + FAIL("Unexpected adv data received\n"); + } + net_buf_simple_pull(buf, ARRAY_SIZE(mfg_data)); + } + + SET_FLAG(flag_per_adv_recv); +} + +static struct bt_le_per_adv_sync_cb sync_callbacks = { + .synced = sync_cb, + .term = term_cb, + .recv = recv_cb, +}; + +static void common_init(void) +{ + int err; + + err = bt_enable(NULL); + + if (err) { + FAIL("Bluetooth init failed: %d\n", err); + return; + } + + bt_le_scan_cb_register(&scan_callbacks); + bt_le_per_adv_sync_cb_register(&sync_callbacks); + bt_conn_cb_register(&conn_cbs); + bt_conn_auth_info_cb_register(&auto_info_cbs); +} + +static void start_scan(void) +{ + int err; + + printk("Start scanning..."); + + err = bt_le_scan_start(IS_ENABLED(CONFIG_BT_CTLR_PHY_CODED) ? + BT_LE_SCAN_CODED_ACTIVE : BT_LE_SCAN_ACTIVE, + NULL); + if (err) { + FAIL("Failed to start scan: %d\n", err); + return; + } + printk("done.\n"); +} + +static void create_pa_sync(struct bt_le_per_adv_sync **sync) +{ + struct bt_le_per_adv_sync_param sync_create_param = { 0 }; + int err; + + printk("Creating periodic advertising sync..."); + bt_addr_le_copy(&sync_create_param.addr, &per_addr); + sync_create_param.options = 0; + sync_create_param.sid = per_sid; + sync_create_param.skip = 0; + sync_create_param.timeout = 0x0a; + err = bt_le_per_adv_sync_create(&sync_create_param, sync); + if (err) { + FAIL("Failed to create periodic advertising sync: %d\n", err); + return; + } + printk("done.\n"); + + printk("Waiting for periodic sync...\n"); + WAIT_FOR_FLAG(flag_per_adv_sync); + printk("Periodic sync established.\n"); +} + +static void start_bonding(void) +{ + int err; + + printk("Setting security..."); + err = bt_conn_set_security(g_conn, BT_SECURITY_L2); + if (err) { + FAIL("Failed to set security: %d\n", err); + return; + } + printk("done.\n"); +} + +static void main_per_adv_sync(void) +{ + struct bt_le_per_adv_sync *sync = NULL; + + common_init(); + start_scan(); + + printk("Waiting for periodic advertising...\n"); + WAIT_FOR_FLAG(flag_per_adv); + printk("Found periodic advertising.\n"); + + create_pa_sync(&sync); + + printk("Waiting for periodic sync lost...\n"); + WAIT_FOR_FLAG(flag_per_adv_sync_lost); + + PASS("Periodic advertising sync passed\n"); +} + +static void main_per_adv_sync_app_not_scanning(void) +{ + int err; + struct bt_le_per_adv_sync *sync = NULL; + + common_init(); + start_scan(); + + printk("Waiting for periodic advertising...\n"); + WAIT_FOR_FLAG(flag_per_adv); + printk("Found periodic advertising.\n"); + + printk("Stopping scan\n"); + err = bt_le_scan_stop(); + if (err != 0) { + FAIL("Failed to stop scan: %d", err); + return; + } + + create_pa_sync(&sync); + + printk("Waiting for periodic sync lost...\n"); + WAIT_FOR_FLAG(flag_per_adv_sync_lost); + + PASS("Periodic advertising sync passed\n"); +} + +static void main_per_adv_conn_sync(void) +{ + struct bt_le_per_adv_sync *sync = NULL; + + common_init(); + start_scan(); + + printk("Waiting for connection..."); + WAIT_FOR_FLAG(flag_connected); + printk("done.\n"); + + start_scan(); + + printk("Waiting for periodic advertising...\n"); + WAIT_FOR_FLAG(flag_per_adv); + printk("Found periodic advertising.\n"); + + create_pa_sync(&sync); + + printk("Waiting for periodic sync lost...\n"); + WAIT_FOR_FLAG(flag_per_adv_sync_lost); + + PASS("Periodic advertising sync passed\n"); +} + +static void main_per_adv_conn_privacy_sync(void) +{ + struct bt_le_per_adv_sync *sync = NULL; + + common_init(); + start_scan(); + + printk("Waiting for connection..."); + WAIT_FOR_FLAG(flag_connected); + printk("done.\n"); + + start_bonding(); + + printk("Waiting for bonding..."); + WAIT_FOR_FLAG(flag_bonded); + printk("done.\n"); + + start_scan(); + + printk("Waiting for periodic advertising...\n"); + WAIT_FOR_FLAG(flag_per_adv); + printk("Found periodic advertising.\n"); + + create_pa_sync(&sync); + + printk("Waiting for periodic sync lost...\n"); + WAIT_FOR_FLAG(flag_per_adv_sync_lost); + + PASS("Periodic advertising sync passed\n"); +} + +static void main_per_adv_long_data_sync(void) +{ +#if (CONFIG_BT_PER_ADV_SYNC_BUF_SIZE > 0) + struct bt_le_per_adv_sync *sync = NULL; + + common_init(); + start_scan(); + + printk("Waiting for periodic advertising...\n"); + WAIT_FOR_FLAG(flag_per_adv); + printk("Found periodic advertising.\n"); + + create_pa_sync(&sync); + + printk("Waiting to receive periodic advertisment...\n"); + WAIT_FOR_FLAG(flag_per_adv_recv); + + printk("Waiting for periodic sync lost...\n"); + WAIT_FOR_FLAG(flag_per_adv_sync_lost); +#endif + PASS("Periodic advertising long data sync passed\n"); +} + +static const struct bst_test_instance per_adv_sync[] = { + { + .test_id = "per_adv_sync", + .test_descr = "Basic periodic advertising sync test. " + "Will just sync to a periodic advertiser.", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = main_per_adv_sync + }, + { + .test_id = "per_adv_sync_app_not_scanning", + .test_descr = "Basic periodic advertising sync test but where " + "the app stopped scanning before creating sync." + "Expect the host to start scanning automatically.", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = main_per_adv_sync_app_not_scanning + }, + { + .test_id = "per_adv_conn_sync", + .test_descr = "Periodic advertising sync test, but where there " + "is a connection between the advertiser and the " + "synchronized device.", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = main_per_adv_conn_sync + }, + { + .test_id = "per_adv_conn_privacy_sync", + .test_descr = "Periodic advertising sync test, but where " + "advertiser and synchronized device are bonded and using " + "privacy", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = main_per_adv_conn_privacy_sync + }, + { + .test_id = "per_adv_long_data_sync", + .test_descr = "Periodic advertising sync test with larger " + "data length. Test is used to verify that " + "reassembly of long data is handeled correctly.", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = main_per_adv_long_data_sync + }, + BSTEST_END_MARKER +}; + +struct bst_test_list *test_per_adv_sync(struct bst_test_list *tests) +{ + return bst_add_tests(tests, per_adv_sync); +} diff --git a/tests/bsim/bluetooth/host/adv/periodic/src/per_adv_syncer.c b/tests/bsim/bluetooth/host/adv/periodic/src/per_adv_syncer.c deleted file mode 100644 index 274a6ca4cec..00000000000 --- a/tests/bsim/bluetooth/host/adv/periodic/src/per_adv_syncer.c +++ /dev/null @@ -1,377 +0,0 @@ -/* - * Copyright (c) 2023 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ -#include - -#include "bs_types.h" -#include "bs_tracing.h" -#include "time_machine.h" -#include "bstests.h" - -#include -#include - -#include - -#include "common.h" - -extern enum bst_result_t bst_result; - -static struct bt_conn *g_conn; -static bt_addr_le_t per_addr; -static uint8_t per_sid; - -CREATE_FLAG(flag_connected); -CREATE_FLAG(flag_bonded); -CREATE_FLAG(flag_per_adv); -CREATE_FLAG(flag_per_adv_sync); -CREATE_FLAG(flag_per_adv_sync_lost); -CREATE_FLAG(flag_per_adv_recv); - -static void connected(struct bt_conn *conn, uint8_t err) -{ - char addr[BT_ADDR_LE_STR_LEN]; - - bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); - - if (err != BT_HCI_ERR_SUCCESS) { - FAIL("Failed to connect to %s: %u\n", addr, err); - return; - } - - printk("Connected to %s\n", addr); - g_conn = bt_conn_ref(conn); - SET_FLAG(flag_connected); -} - -static void disconnected(struct bt_conn *conn, uint8_t reason) -{ - char addr[BT_ADDR_LE_STR_LEN]; - - bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); - - printk("Disconnected: %s (reason %u)\n", addr, reason); - - bt_conn_unref(g_conn); - g_conn = NULL; -} - -static struct bt_conn_cb conn_cbs = { - .connected = connected, - .disconnected = disconnected, -}; - -static void pairing_complete_cb(struct bt_conn *conn, bool bonded) -{ - if (conn == g_conn && bonded) { - SET_FLAG(flag_bonded); - } -} - -static struct bt_conn_auth_info_cb auto_info_cbs = { - .pairing_complete = pairing_complete_cb, -}; - -static void scan_recv(const struct bt_le_scan_recv_info *info, - struct net_buf_simple *buf) -{ - if (!TEST_FLAG(flag_connected) && - info->adv_props & BT_GAP_ADV_PROP_CONNECTABLE) { - int err; - - printk("Stopping scan\n"); - err = bt_le_scan_stop(); - if (err != 0) { - FAIL("Failed to stop scan: %d", err); - return; - } - - err = bt_conn_le_create(info->addr, BT_CONN_LE_CREATE_CONN, - BT_LE_CONN_PARAM_DEFAULT, &g_conn); - if (err != 0) { - FAIL("Could not connect to peer: %d", err); - return; - } - } else if (!TEST_FLAG(flag_per_adv) && info->interval != 0U) { - - per_sid = info->sid; - bt_addr_le_copy(&per_addr, info->addr); - - SET_FLAG(flag_per_adv); - } -} - -static struct bt_le_scan_cb scan_callbacks = { - .recv = scan_recv, -}; - -static void sync_cb(struct bt_le_per_adv_sync *sync, - struct bt_le_per_adv_sync_synced_info *info) -{ - char le_addr[BT_ADDR_LE_STR_LEN]; - - bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr)); - - printk("PER_ADV_SYNC[%u]: [DEVICE]: %s synced, " - "Interval 0x%04x (%u us)\n", - bt_le_per_adv_sync_get_index(sync), le_addr, - info->interval, BT_CONN_INTERVAL_TO_US(info->interval)); - - SET_FLAG(flag_per_adv_sync); -} - -static void term_cb(struct bt_le_per_adv_sync *sync, - const struct bt_le_per_adv_sync_term_info *info) -{ - char le_addr[BT_ADDR_LE_STR_LEN]; - - bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr)); - - printk("PER_ADV_SYNC[%u]: [DEVICE]: %s sync terminated\n", - bt_le_per_adv_sync_get_index(sync), le_addr); - - SET_FLAG(flag_per_adv_sync_lost); -} - -static void recv_cb(struct bt_le_per_adv_sync *recv_sync, - const struct bt_le_per_adv_sync_recv_info *info, - struct net_buf_simple *buf) -{ - char le_addr[BT_ADDR_LE_STR_LEN]; - uint8_t buf_data_len; - - if (TEST_FLAG(flag_per_adv_recv)) { - return; - } - - bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr)); - printk("PER_ADV_SYNC[%u]: [DEVICE]: %s advertisment received\n", - bt_le_per_adv_sync_get_index(recv_sync), le_addr); - - while (buf->len > 0) { - buf_data_len = (uint8_t)net_buf_simple_pull_le16(buf); - if (buf->data[0] - 1 != sizeof(mfg_data) || - memcmp(buf->data, mfg_data, sizeof(mfg_data))) { - FAIL("Unexpected adv data received\n"); - } - net_buf_simple_pull(buf, ARRAY_SIZE(mfg_data)); - } - - SET_FLAG(flag_per_adv_recv); -} - -static struct bt_le_per_adv_sync_cb sync_callbacks = { - .synced = sync_cb, - .term = term_cb, - .recv = recv_cb, -}; - -static void common_init(void) -{ - int err; - - err = bt_enable(NULL); - - if (err) { - FAIL("Bluetooth init failed: %d\n", err); - return; - } - - bt_le_scan_cb_register(&scan_callbacks); - bt_le_per_adv_sync_cb_register(&sync_callbacks); - bt_conn_cb_register(&conn_cbs); - bt_conn_auth_info_cb_register(&auto_info_cbs); -} - -static void start_scan(void) -{ - int err; - - printk("Start scanning..."); - err = bt_le_scan_start(BT_LE_SCAN_ACTIVE, NULL); - if (err) { - FAIL("Failed to start scan: %d\n", err); - return; - } - printk("done.\n"); -} - -static void create_pa_sync(struct bt_le_per_adv_sync **sync) -{ - struct bt_le_per_adv_sync_param sync_create_param = { 0 }; - int err; - - printk("Creating periodic advertising sync..."); - bt_addr_le_copy(&sync_create_param.addr, &per_addr); - sync_create_param.options = 0; - sync_create_param.sid = per_sid; - sync_create_param.skip = 0; - sync_create_param.timeout = 0x0a; - err = bt_le_per_adv_sync_create(&sync_create_param, sync); - if (err) { - FAIL("Failed to create periodic advertising sync: %d\n", err); - return; - } - printk("done.\n"); - - printk("Waiting for periodic sync...\n"); - WAIT_FOR_FLAG(flag_per_adv_sync); - printk("Periodic sync established.\n"); -} - -static void start_bonding(void) -{ - int err; - - printk("Setting security..."); - err = bt_conn_set_security(g_conn, BT_SECURITY_L2); - if (err) { - FAIL("Failed to set security: %d\n", err); - return; - } - printk("done.\n"); -} - -static void main_per_adv_syncer(void) -{ - struct bt_le_per_adv_sync *sync = NULL; - - common_init(); - start_scan(); - - printk("Waiting for periodic advertising...\n"); - WAIT_FOR_FLAG(flag_per_adv); - printk("Found periodic advertising.\n"); - - create_pa_sync(&sync); - - printk("Waiting for periodic sync lost...\n"); - WAIT_FOR_FLAG(flag_per_adv_sync_lost); - - PASS("Periodic advertising syncer passed\n"); -} - -static void main_per_adv_conn_syncer(void) -{ - struct bt_le_per_adv_sync *sync = NULL; - - common_init(); - start_scan(); - - printk("Waiting for connection..."); - WAIT_FOR_FLAG(flag_connected); - printk("done.\n"); - - start_scan(); - - printk("Waiting for periodic advertising...\n"); - WAIT_FOR_FLAG(flag_per_adv); - printk("Found periodic advertising.\n"); - - create_pa_sync(&sync); - - printk("Waiting for periodic sync lost...\n"); - WAIT_FOR_FLAG(flag_per_adv_sync_lost); - - PASS("Periodic advertising syncer passed\n"); -} - -static void main_per_adv_conn_privacy_syncer(void) -{ - struct bt_le_per_adv_sync *sync = NULL; - - common_init(); - start_scan(); - - printk("Waiting for connection..."); - WAIT_FOR_FLAG(flag_connected); - printk("done.\n"); - - start_bonding(); - - printk("Waiting for bonding..."); - WAIT_FOR_FLAG(flag_bonded); - printk("done.\n"); - - start_scan(); - - printk("Waiting for periodic advertising...\n"); - WAIT_FOR_FLAG(flag_per_adv); - printk("Found periodic advertising.\n"); - - create_pa_sync(&sync); - - printk("Waiting for periodic sync lost...\n"); - WAIT_FOR_FLAG(flag_per_adv_sync_lost); - - PASS("Periodic advertising syncer passed\n"); -} - -static void main_per_adv_long_data_syncer(void) -{ -#if (CONFIG_BT_PER_ADV_SYNC_BUF_SIZE > 0) - struct bt_le_per_adv_sync *sync = NULL; - - common_init(); - start_scan(); - - printk("Waiting for periodic advertising...\n"); - WAIT_FOR_FLAG(flag_per_adv); - printk("Found periodic advertising.\n"); - - create_pa_sync(&sync); - - printk("Waiting to receive periodic advertisment...\n"); - WAIT_FOR_FLAG(flag_per_adv_recv); - - printk("Waiting for periodic sync lost...\n"); - WAIT_FOR_FLAG(flag_per_adv_sync_lost); -#endif - PASS("Periodic advertising long data syncer passed\n"); -} - -static const struct bst_test_instance per_adv_syncer[] = { - { - .test_id = "per_adv_syncer", - .test_descr = "Basic periodic advertising sync test. " - "Will just sync to a periodic advertiser.", - .test_post_init_f = test_init, - .test_tick_f = test_tick, - .test_main_f = main_per_adv_syncer - }, - { - .test_id = "per_adv_conn_syncer", - .test_descr = "Periodic advertising sync test, but where there " - "is a connection between the advertiser and the " - "syncer.", - .test_post_init_f = test_init, - .test_tick_f = test_tick, - .test_main_f = main_per_adv_conn_syncer - }, - { - .test_id = "per_adv_conn_privacy_syncer", - .test_descr = "Periodic advertising sync test, but where " - "advertiser and syncer are bonded and using " - "privacy", - .test_post_init_f = test_init, - .test_tick_f = test_tick, - .test_main_f = main_per_adv_conn_privacy_syncer - }, - { - .test_id = "per_adv_long_data_syncer", - .test_descr = "Periodic advertising sync test with larger " - "data length. Test is used to verify that " - "reassembly of long data is handeled correctly.", - .test_post_init_f = test_init, - .test_tick_f = test_tick, - .test_main_f = main_per_adv_long_data_syncer - }, - BSTEST_END_MARKER -}; - -struct bst_test_list *test_per_adv_syncer(struct bst_test_list *tests) -{ - return bst_add_tests(tests, per_adv_syncer); -} diff --git a/tests/bsim/bluetooth/host/adv/periodic/tests_scripts/per_adv.sh b/tests/bsim/bluetooth/host/adv/periodic/tests_scripts/per_adv.sh index 4e88aa57cc5..a7b8d99b654 100755 --- a/tests/bsim/bluetooth/host/adv/periodic/tests_scripts/per_adv.sh +++ b/tests/bsim/bluetooth/host/adv/periodic/tests_scripts/per_adv.sh @@ -18,7 +18,7 @@ Execute ./bs_${BOARD_TS}_tests_bsim_bluetooth_host_adv_periodic_prj_conf \ Execute ./bs_${BOARD_TS}_tests_bsim_bluetooth_host_adv_periodic_prj_conf \ -v=${verbosity_level} -s=${simulation_id} -d=1 -RealEncryption=0 \ - -testid=per_adv_syncer -rs=6 + -testid=per_adv_sync -rs=6 Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \ -D=2 -sim_length=20e6 $@ diff --git a/tests/bsim/bluetooth/host/adv/periodic/tests_scripts/per_adv_app_not_scanning.sh b/tests/bsim/bluetooth/host/adv/periodic/tests_scripts/per_adv_app_not_scanning.sh new file mode 100755 index 00000000000..7176929cb2d --- /dev/null +++ b/tests/bsim/bluetooth/host/adv/periodic/tests_scripts/per_adv_app_not_scanning.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +# Periodic advertising sync test where the host starts scanning +# automatically because the application didn't start it. + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +simulation_id="per_adv_not_scanning" +verbosity_level=2 + +cd ${BSIM_OUT_PATH}/bin + +Execute ./bs_${BOARD_TS}_tests_bsim_bluetooth_host_adv_periodic_prj_conf \ + -v=${verbosity_level} -s=${simulation_id} -d=0 -RealEncryption=0 \ + -testid=per_adv_advertiser -rs=23 + +Execute ./bs_${BOARD_TS}_tests_bsim_bluetooth_host_adv_periodic_prj_conf \ + -v=${verbosity_level} -s=${simulation_id} -d=1 -RealEncryption=0 \ + -testid=per_adv_sync_app_not_scanning -rs=6 + +Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \ + -D=2 -sim_length=20e6 $@ + +wait_for_background_jobs diff --git a/tests/bsim/bluetooth/host/adv/periodic/tests_scripts/per_adv_app_not_scanning_coded.sh b/tests/bsim/bluetooth/host/adv/periodic/tests_scripts/per_adv_app_not_scanning_coded.sh new file mode 100755 index 00000000000..31fd0195ddd --- /dev/null +++ b/tests/bsim/bluetooth/host/adv/periodic/tests_scripts/per_adv_app_not_scanning_coded.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +# Periodic advertising sync test where the host starts scanning +# automatically because the application didn't start it. +# The advertiser is using Coded PHY as primary PHY. + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +simulation_id="per_adv_app_not_scanning_coded" +verbosity_level=2 + +cd ${BSIM_OUT_PATH}/bin + +Execute ./bs_${BOARD_TS}_tests_bsim_bluetooth_host_adv_periodic_prj_coded_conf \ + -v=${verbosity_level} -s=${simulation_id} -d=0 -RealEncryption=0 \ + -testid=per_adv_advertiser_coded_phy -rs=23 + +Execute ./bs_${BOARD_TS}_tests_bsim_bluetooth_host_adv_periodic_prj_coded_conf \ + -v=${verbosity_level} -s=${simulation_id} -d=1 -RealEncryption=0 \ + -testid=per_adv_sync_app_not_scanning -rs=6 + +Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \ + -D=2 -sim_length=20e6 $@ + +wait_for_background_jobs diff --git a/tests/bsim/bluetooth/host/adv/periodic/tests_scripts/per_adv_conn.sh b/tests/bsim/bluetooth/host/adv/periodic/tests_scripts/per_adv_conn.sh index 9c4823538f6..a459c91e450 100755 --- a/tests/bsim/bluetooth/host/adv/periodic/tests_scripts/per_adv_conn.sh +++ b/tests/bsim/bluetooth/host/adv/periodic/tests_scripts/per_adv_conn.sh @@ -18,7 +18,7 @@ Execute ./bs_${BOARD_TS}_tests_bsim_bluetooth_host_adv_periodic_prj_conf \ Execute ./bs_${BOARD_TS}_tests_bsim_bluetooth_host_adv_periodic_prj_conf \ -v=${verbosity_level} -s=${simulation_id} -d=1 -RealEncryption=0 \ - -testid=per_adv_conn_syncer -rs=6 + -testid=per_adv_conn_sync -rs=6 Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \ -D=2 -sim_length=20e6 $@ diff --git a/tests/bsim/bluetooth/host/adv/periodic/tests_scripts/per_adv_conn_privacy.sh b/tests/bsim/bluetooth/host/adv/periodic/tests_scripts/per_adv_conn_privacy.sh index a8d2cdcd31d..1fe7b38d61c 100755 --- a/tests/bsim/bluetooth/host/adv/periodic/tests_scripts/per_adv_conn_privacy.sh +++ b/tests/bsim/bluetooth/host/adv/periodic/tests_scripts/per_adv_conn_privacy.sh @@ -18,7 +18,7 @@ Execute ./bs_${BOARD_TS}_tests_bsim_bluetooth_host_adv_periodic_prj_conf \ Execute ./bs_${BOARD_TS}_tests_bsim_bluetooth_host_adv_periodic_prj_conf \ -v=${verbosity_level} -s=${simulation_id} -d=1 -RealEncryption=0 \ - -testid=per_adv_conn_privacy_syncer -rs=6 + -testid=per_adv_conn_privacy_sync -rs=6 Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \ -D=2 -sim_length=20e6 $@ diff --git a/tests/bsim/bluetooth/host/adv/periodic/tests_scripts/per_adv_long_data.sh b/tests/bsim/bluetooth/host/adv/periodic/tests_scripts/per_adv_long_data.sh index 53ef8e9cbf7..b660ba2598f 100755 --- a/tests/bsim/bluetooth/host/adv/periodic/tests_scripts/per_adv_long_data.sh +++ b/tests/bsim/bluetooth/host/adv/periodic/tests_scripts/per_adv_long_data.sh @@ -18,7 +18,7 @@ Execute ./bs_${BOARD_TS}_tests_bsim_bluetooth_host_adv_periodic_prj_long_data_co Execute ./bs_${BOARD_TS}_tests_bsim_bluetooth_host_adv_periodic_prj_long_data_conf \ -v=${verbosity_level} -s=${simulation_id} -d=1 -RealEncryption=0 \ - -testid=per_adv_long_data_syncer -rs=6 + -testid=per_adv_long_data_sync -rs=6 Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \ -D=2 -sim_length=20e6 $@ diff --git a/tests/bsim/bluetooth/host/adv/resume2/connectable/main.c b/tests/bsim/bluetooth/host/adv/resume2/connectable/main.c index 9347ec5ada6..e822362b878 100644 --- a/tests/bsim/bluetooth/host/adv/resume2/connectable/main.c +++ b/tests/bsim/bluetooth/host/adv/resume2/connectable/main.c @@ -34,9 +34,7 @@ int main(void) bt_testlib_conn_wait_free(); - err = bt_testlib_adv_conn( - &conn, BT_ID_DEFAULT, - (BT_LE_ADV_OPT_USE_NAME | BT_LE_ADV_OPT_FORCE_NAME_IN_AD)); + err = bt_testlib_adv_conn(&conn, BT_ID_DEFAULT, bt_get_name()); __ASSERT_NO_MSG(!err); bt_testlib_wait_disconnected(conn); diff --git a/tests/bsim/bluetooth/host/adv/resume2/dut/main.c b/tests/bsim/bluetooth/host/adv/resume2/dut/main.c index 9c0b69f6d11..03fd621212b 100644 --- a/tests/bsim/bluetooth/host/adv/resume2/dut/main.c +++ b/tests/bsim/bluetooth/host/adv/resume2/dut/main.c @@ -70,13 +70,24 @@ int main(void) err = bt_set_name("dut"); __ASSERT_NO_MSG(!err); + struct bt_data ad[1] = {0}; + + const char *dev_name = bt_get_name(); + + ad[0].type = BT_DATA_NAME_COMPLETE; + ad[0].data_len = strlen(dev_name); + ad[0].data = (const uint8_t *)dev_name; + LOG_INF("---------- Test setup ----------"); LOG_INF("Environment test: Advertiser fills connection capacity."); /* `bt_le_adv_start` is invoked once, and.. */ - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME_AD, NULL, 0, NULL, 0); + err = bt_le_adv_start(BT_LE_ADV_CONN, NULL, 0, NULL, 0); + __ASSERT_NO_MSG(!err); + + err = bt_le_adv_update_data(ad, 1, NULL, 0); __ASSERT_NO_MSG(!err); /* .. the advertiser shall autoresume. Since it's not @@ -154,7 +165,10 @@ int main(void) /* With one connection slot taken by the central role, we fill the rest. */ - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME_AD, NULL, 0, NULL, 0); + err = bt_le_adv_start(BT_LE_ADV_CONN, NULL, 0, NULL, 0); + __ASSERT_NO_MSG(!err); + + err = bt_le_adv_update_data(ad, 1, NULL, 0); __ASSERT_NO_MSG(!err); LOG_INF("Waiting for connections..."); diff --git a/tests/bsim/bluetooth/host/att/compile.sh b/tests/bsim/bluetooth/host/att/compile.sh index b3da250ba1b..59d232be3a4 100755 --- a/tests/bsim/bluetooth/host/att/compile.sh +++ b/tests/bsim/bluetooth/host/att/compile.sh @@ -23,6 +23,8 @@ app=tests/bsim/bluetooth/host/att/retry_on_sec_err/server compile app=tests/bsim/bluetooth/host/att/sequential/dut compile app=tests/bsim/bluetooth/host/att/sequential/tester compile app=tests/bsim/bluetooth/host/att/pipeline/dut compile +app=tests/bsim/bluetooth/host/att/pipeline/dut \ + conf_file='prj.conf;rx_tx_prio_invert.extra.conf' compile app=tests/bsim/bluetooth/host/att/pipeline/tester compile app=tests/bsim/bluetooth/host/att/long_read compile app=tests/bsim/bluetooth/host/att/open_close compile diff --git a/tests/bsim/bluetooth/host/att/eatt/src/common.c b/tests/bsim/bluetooth/host/att/eatt/src/common.c index b7bd5b4b73f..209292320de 100644 --- a/tests/bsim/bluetooth/host/att/eatt/src/common.c +++ b/tests/bsim/bluetooth/host/att/eatt/src/common.c @@ -140,7 +140,7 @@ void peripheral_setup_and_connect(void) FAIL("Can't enable Bluetooth (err %d)\n", err); } - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0); + err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), NULL, 0); if (err) { FAIL("Advertising failed to start (err %d)\n", err); } diff --git a/tests/bsim/bluetooth/host/att/eatt_notif/src/server_test.c b/tests/bsim/bluetooth/host/att/eatt_notif/src/server_test.c index cc20925b49e..56cb28e1093 100644 --- a/tests/bsim/bluetooth/host/att/eatt_notif/src/server_test.c +++ b/tests/bsim/bluetooth/host/att/eatt_notif/src/server_test.c @@ -190,7 +190,7 @@ static void test_main(void) printk("Bluetooth initialized\n"); - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0); + err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), NULL, 0); if (err != 0) { FAIL("Advertising failed to start (err %d)\n", err); return; diff --git a/tests/bsim/bluetooth/host/att/long_read/main.c b/tests/bsim/bluetooth/host/att/long_read/main.c index 83a1b3afe76..f0746d961e1 100644 --- a/tests/bsim/bluetooth/host/att/long_read/main.c +++ b/tests/bsim/bluetooth/host/att/long_read/main.c @@ -194,9 +194,7 @@ void the_test(void) if (peripheral) { EXPECT_ZERO(bt_set_name("peripheral")); - EXPECT_ZERO(bt_testlib_adv_conn( - &conn, BT_ID_DEFAULT, - (BT_LE_ADV_OPT_USE_NAME | BT_LE_ADV_OPT_FORCE_NAME_IN_AD))); + EXPECT_ZERO(bt_testlib_adv_conn(&conn, BT_ID_DEFAULT, bt_get_name())); } if (central) { diff --git a/tests/bsim/bluetooth/host/att/open_close/src/main.c b/tests/bsim/bluetooth/host/att/open_close/src/main.c index 42fdee6824a..60fff019844 100644 --- a/tests/bsim/bluetooth/host/att/open_close/src/main.c +++ b/tests/bsim/bluetooth/host/att/open_close/src/main.c @@ -136,9 +136,7 @@ void a_test_iteration(int i) if (peripheral) { EXPECT_ZERO(bt_set_name("peripheral")); - EXPECT_ZERO(bt_testlib_adv_conn( - &conn, BT_ID_DEFAULT, - (BT_LE_ADV_OPT_USE_NAME | BT_LE_ADV_OPT_FORCE_NAME_IN_AD))); + EXPECT_ZERO(bt_testlib_adv_conn(&conn, BT_ID_DEFAULT, bt_get_name())); } if (central) { diff --git a/tests/bsim/bluetooth/host/att/pipeline/dut/Kconfig b/tests/bsim/bluetooth/host/att/pipeline/dut/Kconfig new file mode 100644 index 00000000000..71d844b76ee --- /dev/null +++ b/tests/bsim/bluetooth/host/att/pipeline/dut/Kconfig @@ -0,0 +1,14 @@ +# Copyright 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +# This file adds prompts to allow setting the symbols in a +# configuration file (e.g. 'prj.conf'), as needed for some of +# the test variants. + +config BT_HCI_TX_PRIO + prompt "" + +config BT_RX_PRIO + prompt "" + +source "Kconfig.zephyr" diff --git a/tests/bsim/bluetooth/host/att/pipeline/dut/rx_tx_prio_invert.extra.conf b/tests/bsim/bluetooth/host/att/pipeline/dut/rx_tx_prio_invert.extra.conf new file mode 100644 index 00000000000..555da337bf5 --- /dev/null +++ b/tests/bsim/bluetooth/host/att/pipeline/dut/rx_tx_prio_invert.extra.conf @@ -0,0 +1,2 @@ +CONFIG_BT_HCI_TX_PRIO=8 +CONFIG_BT_RX_PRIO=7 diff --git a/tests/bsim/bluetooth/host/att/pipeline/test_scripts/_compile.sh b/tests/bsim/bluetooth/host/att/pipeline/test_scripts/_compile.sh index ff0f485b17d..06d5d718a9d 100755 --- a/tests/bsim/bluetooth/host/att/pipeline/test_scripts/_compile.sh +++ b/tests/bsim/bluetooth/host/att/pipeline/test_scripts/_compile.sh @@ -8,6 +8,7 @@ INCR_BUILD=1 source ${ZEPHYR_BASE}/tests/bsim/compile.source app="$(guess_test_relpath)"/dut compile +app="$(guess_test_relpath)"/dut conf_file='prj.conf;rx_tx_prio_invert.extra.conf' compile app="$(guess_test_relpath)"/tester compile wait_for_background_jobs diff --git a/tests/bsim/bluetooth/host/att/pipeline/test_scripts/run_test_shall_not_pipeline_variant_rx_tx_prio_invert.sh b/tests/bsim/bluetooth/host/att/pipeline/test_scripts/run_test_shall_not_pipeline_variant_rx_tx_prio_invert.sh new file mode 100755 index 00000000000..d271c9c04fa --- /dev/null +++ b/tests/bsim/bluetooth/host/att/pipeline/test_scripts/run_test_shall_not_pipeline_variant_rx_tx_prio_invert.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env bash +# Copyright 2023-2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +# Test purpose: +# +# Basic check that the DUT GATT client does not pipeline ATT +# requests. +# +# Sending a new request on a bearer before the response to the +# previous request has been received ('pipelining') is a +# protocol violation. +# +# Test variant 'rx_tx_prio_invert': +# +# - The priority of the RX and TX threads is inverted compared +# to the default configuration. The result shall be the same. +# +# Test procedure: +# +# - DUT is excercised by calling `gatt_write` in a loop. +# - Tester does not immediately respond but delays the response +# a bit to ensure the LL has time to transport any extra +# requests, exposing a bug. +# - Tester verifies there is no such extra request while it's +# delaying the response. Detecting an extra request proves a +# protocol violation. + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +dut_exe="bs_${BOARD_TS}_tests_bsim_bluetooth_host_att_pipeline_dut_prj_conf" +dut_exe+="_rx_tx_prio_invert_extra_conf" +tester_exe="bs_${BOARD_TS}_tests_bsim_bluetooth_host_att_pipeline_tester_prj_conf" + +simulation_id="att_pipeline_test_shall_not_pipeline_variant_rx_tx_prio_invert" +verbosity_level=2 +sim_length_us=100e6 + +cd ${BSIM_OUT_PATH}/bin + +Execute ./bs_2G4_phy_v1 \ + -v=${verbosity_level} -s="${simulation_id}" -D=2 -sim_length=${sim_length_us} $@ + +Execute "./$tester_exe" \ + -v=${verbosity_level} -s="${simulation_id}" -d=1 -testid=tester_1 -RealEncryption=1 -rs=100 + +Execute "./$dut_exe" \ + -v=${verbosity_level} -s="${simulation_id}" -d=0 -testid=dut_1 -RealEncryption=1 + +wait_for_background_jobs diff --git a/tests/bsim/bluetooth/host/att/pipeline/test_scripts/run_test_tolerate_pipeline_variant_rx_tx_prio_invert.sh b/tests/bsim/bluetooth/host/att/pipeline/test_scripts/run_test_tolerate_pipeline_variant_rx_tx_prio_invert.sh new file mode 100755 index 00000000000..bc7928e349f --- /dev/null +++ b/tests/bsim/bluetooth/host/att/pipeline/test_scripts/run_test_tolerate_pipeline_variant_rx_tx_prio_invert.sh @@ -0,0 +1,55 @@ +#!/usr/bin/env bash +# Copyright 2023-2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +# Test purpose: +# +# Check that DUT GATT server gracefully handles a pipelining +# client. +# +# The DUT GATT server must remain available to a well-behaved +# peer while a bad peer tries to spam ATT requests. +# +# Test variant 'rx_tx_prio_invert': +# +# - The priority of the RX and TX threads is inverted compared +# to the default configuration. The result shall be the same. +# +# Test procedure: +# +# - The well-behaved peer performs a discovery procedure +# repeatedly. +# - The bad peer spams ATT requests as fast as possible. +# - The connection with the well-behaved peer shall remain +# responsive. +# - Either: The DUT may disconnect the bad peer ACL after +# receiving a protocol violation occurs. The bad peer shall +# be able to reconnect and continue the bad behavior. +# - Or: The DUT may process and respond to the pipelined +# requests, preserving their ordering. + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +dut_exe="bs_${BOARD_TS}_tests_bsim_bluetooth_host_att_pipeline_dut_prj_conf" +dut_exe+="_rx_tx_prio_invert_extra_conf" +tester_exe="bs_${BOARD_TS}_tests_bsim_bluetooth_host_att_pipeline_tester_prj_conf" + +simulation_id="att_pipeline_test_tolerate_pipeline_variant_rx_tx_prio_invert" +verbosity_level=2 +sim_length_us=100e6 + +cd ${BSIM_OUT_PATH}/bin + +Execute ./bs_2G4_phy_v1 \ + -v=${verbosity_level} -s="${simulation_id}" -D=3 -sim_length=${sim_length_us} $@ + +Execute "./$tester_exe" \ + -v=${verbosity_level} -s="${simulation_id}" -d=2 -testid=tester -RealEncryption=1 -rs=100 + +Execute "./$dut_exe" \ + -v=${verbosity_level} -s="${simulation_id}" -d=1 -testid=dut -RealEncryption=1 -rs=2000 + +Execute "./$dut_exe" \ + -v=${verbosity_level} -s="${simulation_id}" -d=0 -testid=dut -RealEncryption=1 + +wait_for_background_jobs diff --git a/tests/bsim/bluetooth/host/att/pipeline/tester/prj.conf b/tests/bsim/bluetooth/host/att/pipeline/tester/prj.conf index c05fc3aa163..a5ca6cf0f62 100644 --- a/tests/bsim/bluetooth/host/att/pipeline/tester/prj.conf +++ b/tests/bsim/bluetooth/host/att/pipeline/tester/prj.conf @@ -3,7 +3,6 @@ CONFIG_ASSERT=y CONFIG_BT=y CONFIG_BT_HCI_RAW=y -CONFIG_BT_HCI_RAW_RESERVE=1 CONFIG_BT_MAX_CONN=1 CONFIG_BT_BUF_CMD_TX_COUNT=10 diff --git a/tests/bsim/bluetooth/host/att/read_fill_buf/server/main.c b/tests/bsim/bluetooth/host/att/read_fill_buf/server/main.c index 22904c33db5..244eb6e7a66 100644 --- a/tests/bsim/bluetooth/host/att/read_fill_buf/server/main.c +++ b/tests/bsim/bluetooth/host/att/read_fill_buf/server/main.c @@ -45,8 +45,7 @@ void the_test(void) err = bt_set_name("d1"); __ASSERT_NO_MSG(!err); - err = bt_testlib_adv_conn(NULL, BT_ID_DEFAULT, - (BT_LE_ADV_OPT_USE_NAME | BT_LE_ADV_OPT_FORCE_NAME_IN_AD)); + err = bt_testlib_adv_conn(NULL, BT_ID_DEFAULT, bt_get_name()); __ASSERT_NO_MSG(!err); PASS("PASS\n"); diff --git a/tests/bsim/bluetooth/host/att/retry_on_sec_err/server/main.c b/tests/bsim/bluetooth/host/att/retry_on_sec_err/server/main.c index b07f0034aab..59f6c91cd7c 100644 --- a/tests/bsim/bluetooth/host/att/retry_on_sec_err/server/main.c +++ b/tests/bsim/bluetooth/host/att/retry_on_sec_err/server/main.c @@ -39,8 +39,7 @@ static void test_common(struct bt_conn **conn) err = bt_set_name("d1"); __ASSERT_NO_MSG(!err); - err = bt_testlib_adv_conn(conn, BT_ID_DEFAULT, - (BT_LE_ADV_OPT_USE_NAME | BT_LE_ADV_OPT_FORCE_NAME_IN_AD)); + err = bt_testlib_adv_conn(conn, BT_ID_DEFAULT, bt_get_name()); __ASSERT_NO_MSG(!err); } diff --git a/tests/bsim/bluetooth/host/att/sequential/tester/prj.conf b/tests/bsim/bluetooth/host/att/sequential/tester/prj.conf index 461c7dd5029..5217040a117 100644 --- a/tests/bsim/bluetooth/host/att/sequential/tester/prj.conf +++ b/tests/bsim/bluetooth/host/att/sequential/tester/prj.conf @@ -3,7 +3,6 @@ CONFIG_ASSERT=y CONFIG_BT=y CONFIG_BT_HCI_RAW=y -CONFIG_BT_HCI_RAW_RESERVE=1 CONFIG_BT_MAX_CONN=1 CONFIG_BT_BUF_CMD_TX_COUNT=10 diff --git a/tests/bsim/bluetooth/host/compile.sh b/tests/bsim/bluetooth/host/compile.sh index cc0d49ea360..265bb6fae39 100755 --- a/tests/bsim/bluetooth/host/compile.sh +++ b/tests/bsim/bluetooth/host/compile.sh @@ -18,6 +18,7 @@ ${ZEPHYR_BASE}/tests/bsim/bluetooth/host/l2cap/compile.sh ${ZEPHYR_BASE}/tests/bsim/bluetooth/host/security/compile.sh app=tests/bsim/bluetooth/host/iso/cis compile +app=tests/bsim/bluetooth/host/iso/bis compile app=tests/bsim/bluetooth/host/misc/disable compile app=tests/bsim/bluetooth/host/misc/disconnect/dut compile diff --git a/tests/bsim/bluetooth/host/gatt/authorization/src/gatt_server_test.c b/tests/bsim/bluetooth/host/gatt/authorization/src/gatt_server_test.c index 5e0f674cb16..79962c31689 100644 --- a/tests/bsim/bluetooth/host/gatt/authorization/src/gatt_server_test.c +++ b/tests/bsim/bluetooth/host/gatt/authorization/src/gatt_server_test.c @@ -339,7 +339,7 @@ static void test_main(void) printk("Bluetooth initialized\n"); - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0); + err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), NULL, 0); if (err != 0) { FAIL("Advertising failed to start (err %d)\n", err); return; diff --git a/tests/bsim/bluetooth/host/gatt/caching/src/gatt_server_test.c b/tests/bsim/bluetooth/host/gatt/caching/src/gatt_server_test.c index 02d8759f342..6149378ecb6 100644 --- a/tests/bsim/bluetooth/host/gatt/caching/src/gatt_server_test.c +++ b/tests/bsim/bluetooth/host/gatt/caching/src/gatt_server_test.c @@ -101,7 +101,7 @@ static void test_main_common(bool connect_eatt) printk("Bluetooth initialized\n"); - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0); + err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), NULL, 0); if (err != 0) { FAIL("Advertising failed to start (err %d)\n", err); diff --git a/tests/bsim/bluetooth/host/gatt/general/src/gatt_server_test.c b/tests/bsim/bluetooth/host/gatt/general/src/gatt_server_test.c index 304b6ee2686..c266b4739a4 100644 --- a/tests/bsim/bluetooth/host/gatt/general/src/gatt_server_test.c +++ b/tests/bsim/bluetooth/host/gatt/general/src/gatt_server_test.c @@ -159,7 +159,7 @@ static void test_main(void) printk("Bluetooth initialized\n"); - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0); + err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), NULL, 0); if (err != 0) { FAIL("Advertising failed to start (err %d)\n", err); return; diff --git a/tests/bsim/bluetooth/host/gatt/notify/src/gatt_server_test.c b/tests/bsim/bluetooth/host/gatt/notify/src/gatt_server_test.c index e60659876ad..551a41ebaad 100644 --- a/tests/bsim/bluetooth/host/gatt/notify/src/gatt_server_test.c +++ b/tests/bsim/bluetooth/host/gatt/notify/src/gatt_server_test.c @@ -183,7 +183,7 @@ static void setup(void) printk("Bluetooth initialized\n"); - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0); + err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), NULL, 0); if (err != 0) { FAIL("Advertising failed to start (err %d)\n", err); return; diff --git a/tests/bsim/bluetooth/host/gatt/notify_multiple/src/gatt_server_test.c b/tests/bsim/bluetooth/host/gatt/notify_multiple/src/gatt_server_test.c index 743cb3e269c..3083eb767d6 100644 --- a/tests/bsim/bluetooth/host/gatt/notify_multiple/src/gatt_server_test.c +++ b/tests/bsim/bluetooth/host/gatt/notify_multiple/src/gatt_server_test.c @@ -145,7 +145,7 @@ static void test_main(void) printk("Bluetooth initialized\n"); - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0); + err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), NULL, 0); if (err != 0) { FAIL("Advertising failed to start (err %d)\n", err); return; diff --git a/tests/bsim/bluetooth/host/iso/bis/CMakeLists.txt b/tests/bsim/bluetooth/host/iso/bis/CMakeLists.txt new file mode 100644 index 00000000000..89a3d5cf313 --- /dev/null +++ b/tests/bsim/bluetooth/host/iso/bis/CMakeLists.txt @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) + +project(bsim_test_iso_bis) + +add_subdirectory(${ZEPHYR_BASE}/tests/bsim/babblekit babblekit) +target_link_libraries(app PRIVATE babblekit) + +target_sources(app PRIVATE + src/common.c + src/bis_broadcaster.c + src/bis_receiver.c + src/main.c +) + +zephyr_include_directories( + ${BSIM_COMPONENTS_PATH}/libUtilv1/src/ + ${BSIM_COMPONENTS_PATH}/libPhyComv1/src/ +) diff --git a/tests/bsim/bluetooth/host/iso/bis/prj.conf b/tests/bsim/bluetooth/host/iso/bis/prj.conf new file mode 100644 index 00000000000..e1e57deda07 --- /dev/null +++ b/tests/bsim/bluetooth/host/iso/bis/prj.conf @@ -0,0 +1,27 @@ +CONFIG_BT=y +CONFIG_LOG=y +CONFIG_ASSERT=y +CONFIG_BT_EXT_ADV=y +CONFIG_BT_PER_ADV=y +CONFIG_BT_PER_ADV_SYNC=y + +CONFIG_BT_DEVICE_NAME="BIS test" + +CONFIG_BT_ISO_BROADCASTER=y +CONFIG_BT_ISO_SYNC_RECEIVER=y +CONFIG_BT_ISO_TX_BUF_COUNT=4 +CONFIG_BT_ISO_MAX_CHAN=4 +CONFIG_BT_ISO_TX_MTU=200 +CONFIG_BT_ISO_RX_MTU=200 + +CONFIG_BT_ISO_LOG_LEVEL_DBG=y + +# Controller ISO configs +CONFIG_BT_CTLR_ADV_ISO=y +CONFIG_BT_CTLR_ADV_ISO_STREAM_MAX=4 +CONFIG_BT_CTLR_SYNC_ISO=y +CONFIG_BT_CTLR_SYNC_ISO_STREAM_MAX=4 +CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=208 +CONFIG_BT_CTLR_ISO_TX_BUFFERS=4 +CONFIG_BT_CTLR_ISOAL_SOURCES=4 +CONFIG_BT_CTLR_ISOAL_SINKS=4 diff --git a/tests/bsim/bluetooth/host/iso/bis/src/bis_broadcaster.c b/tests/bsim/bluetooth/host/iso/bis/src/bis_broadcaster.c new file mode 100644 index 00000000000..165b6add683 --- /dev/null +++ b/tests/bsim/bluetooth/host/iso/bis/src/bis_broadcaster.c @@ -0,0 +1,328 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "common.h" + +#include +#include +#include + +#include "babblekit/flags.h" +#include "babblekit/sync.h" +#include "babblekit/testcase.h" + +LOG_MODULE_REGISTER(bis_broadcaster, LOG_LEVEL_INF); + +#define LATENCY_MS 10U /* 10ms */ +#define SDU_INTERVAL_US 10U * USEC_PER_MSEC /* 10 ms */ + +extern enum bst_result_t bst_result; +static struct bt_iso_chan iso_chans[CONFIG_BT_ISO_MAX_CHAN]; +static struct bt_iso_chan *default_chan = &iso_chans[0]; +static uint16_t seq_num; +NET_BUF_POOL_FIXED_DEFINE(tx_pool, CONFIG_BT_ISO_TX_BUF_COUNT, + BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU), + CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); + +static DEFINE_FLAG(flag_iso_connected); + +static void send_data_cb(struct k_work *work); +K_WORK_DELAYABLE_DEFINE(iso_send_work, send_data_cb); + +static void send_data(struct bt_iso_chan *chan) +{ + static uint8_t buf_data[CONFIG_BT_ISO_TX_MTU]; + static size_t len_to_send = 1U; + static bool data_initialized; + struct net_buf *buf; + int ret; + + if (!IS_FLAG_SET(flag_iso_connected)) { + /* TX has been aborted */ + return; + } + + if (!data_initialized) { + for (int i = 0; i < ARRAY_SIZE(buf_data); i++) { + buf_data[i] = (uint8_t)i; + } + + data_initialized = true; + } + + buf = net_buf_alloc(&tx_pool, K_NO_WAIT); + TEST_ASSERT(buf != NULL, "Failed to allocate buffer"); + + net_buf_reserve(buf, BT_ISO_CHAN_SEND_RESERVE); + + net_buf_add_mem(buf, buf_data, len_to_send); + + ret = bt_iso_chan_send(default_chan, buf, seq_num++); + if (ret < 0) { + LOG_DBG("Failed to send ISO data: %d", ret); + net_buf_unref(buf); + + /* Reschedule for next interval */ + k_work_reschedule(&iso_send_work, K_USEC(SDU_INTERVAL_US)); + + return; + } + + len_to_send++; + if (len_to_send > ARRAY_SIZE(buf_data)) { + len_to_send = 1; + } +} + +static void send_data_cb(struct k_work *work) +{ + const uint16_t tx_pool_cnt = tx_pool.uninit_count; + + /* Send/enqueue as many as we can */ + for (uint16_t i = 0U; i < tx_pool_cnt; i++) { + send_data(default_chan); + } +} + +static void iso_connected_cb(struct bt_iso_chan *chan) +{ + LOG_INF("ISO Channel %p connected", chan); + + if (chan == default_chan) { + seq_num = 0U; + + SET_FLAG(flag_iso_connected); + } +} + +static void iso_disconnected_cb(struct bt_iso_chan *chan, uint8_t reason) +{ + LOG_INF("ISO Channel %p disconnected (reason 0x%02x)", chan, reason); + + if (chan == default_chan) { + k_work_cancel_delayable(&iso_send_work); + + UNSET_FLAG(flag_iso_connected); + } +} + +static void sdu_sent_cb(struct bt_iso_chan *chan) +{ + if (!IS_FLAG_SET(flag_iso_connected)) { + /* TX has been aborted */ + return; + } + + send_data(chan); +} + +static void init(void) +{ + static struct bt_iso_chan_ops iso_ops = { + .disconnected = iso_disconnected_cb, + .connected = iso_connected_cb, + .sent = sdu_sent_cb, + }; + static struct bt_iso_chan_io_qos iso_tx = { + .sdu = CONFIG_BT_ISO_TX_MTU, + .phy = BT_GAP_LE_PHY_2M, + .rtn = 1, + .path = NULL, + }; + static struct bt_iso_chan_qos iso_qos = { + .tx = &iso_tx, + .rx = NULL, + }; + int err; + + err = bt_enable(NULL); + TEST_ASSERT(err == 0, "Bluetooth enable failed: %d", err); + + for (size_t i = 0U; i < ARRAY_SIZE(iso_chans); i++) { + iso_chans[i].ops = &iso_ops; + iso_chans[i].qos = &iso_qos; + } + + bk_sync_init(); +} + +static void create_ext_adv(struct bt_le_ext_adv **adv) +{ + int err; + + LOG_INF("Creating extended advertising set with periodic advertising"); + + /* Create a non-connectable non-scannable advertising set */ + err = bt_le_ext_adv_create(BT_LE_EXT_ADV_NCONN, NULL, adv); + TEST_ASSERT(err == 0, "Unable to create extended advertising set: %d", err); + + /* Set periodic advertising parameters */ + err = bt_le_per_adv_set_param(*adv, BT_LE_PER_ADV_PARAM(BT_GAP_PER_ADV_FAST_INT_MIN_2, + BT_GAP_PER_ADV_FAST_INT_MAX_2, + BT_LE_PER_ADV_OPT_NONE)); + TEST_ASSERT(err == 0, "Failed to set periodic advertising parameters: %d", err); +} + +static void start_ext_adv(struct bt_le_ext_adv *adv) +{ + int err; + + LOG_INF("Starting extended and periodic advertising"); + + /* Start extended advertising */ + err = bt_le_ext_adv_start(adv, BT_LE_EXT_ADV_START_DEFAULT); + TEST_ASSERT(err == 0, "Failed to start extended advertising: %d", err); + + /* FIXME: Temporary workaround to get around an assert in the controller + * Open issue: https://github.com/zephyrproject-rtos/zephyr/issues/72852 + */ + k_sleep(K_MSEC(100)); + + /* Enable Periodic Advertising */ + err = bt_le_per_adv_start(adv); + TEST_ASSERT(err == 0, "Failed to enable periodic advertising: %d", err); +} + +static void create_big(struct bt_le_ext_adv *adv, size_t cnt, struct bt_iso_big **out_big) +{ + struct bt_iso_chan *channels[ARRAY_SIZE(iso_chans)]; + struct bt_iso_big_create_param param = { + .packing = BT_ISO_PACKING_SEQUENTIAL, + .framing = BT_ISO_FRAMING_UNFRAMED, + .interval = SDU_INTERVAL_US, + .bis_channels = channels, + .latency = LATENCY_MS, + .encryption = false, + .num_bis = cnt, + }; + int err; + + for (size_t i = 0U; i < cnt; i++) { + channels[i] = &iso_chans[i]; + } + + LOG_INF("Creating BIG"); + + err = bt_iso_big_create(adv, ¶m, out_big); + TEST_ASSERT(err == 0, "Failed to create BIG: %d", err); + + WAIT_FOR_FLAG(flag_iso_connected); +} + +static void start_tx(void) +{ + const uint16_t tx_pool_cnt = tx_pool.uninit_count; + + LOG_INF("Starting TX"); + + /* Send/enqueue as many as we can */ + for (uint16_t i = 0U; i < tx_pool_cnt; i++) { + send_data(default_chan); + } +} + +static void terminate_big(struct bt_iso_big *big) +{ + int err; + + LOG_INF("Terminating BIG"); + + err = bt_iso_big_terminate(big); + TEST_ASSERT(err == 0, "Failed to terminate BIG: %d", err); + + big = NULL; +} + +static void reset_bluetooth(void) +{ + int err; + + LOG_INF("Resetting Bluetooth"); + + err = bt_disable(); + TEST_ASSERT(err == 0, "Failed to disable: %d", err); + + err = bt_enable(NULL); + TEST_ASSERT(err == 0, "Failed to re-enable: %d", err); +} + +static void test_main(void) +{ + struct bt_le_ext_adv *adv; + struct bt_iso_big *big; + + init(); + + /* Create advertising set and BIG and start it and starting TXing */ + create_ext_adv(&adv); + create_big(adv, 1U, &big); + start_ext_adv(adv); + start_tx(); + + /* Wait for receiver to tell us to terminate */ + bk_sync_wait(); + + terminate_big(big); + big = NULL; + + TEST_PASS("Test passed"); +} + +static void test_main_disable(void) +{ + struct bt_le_ext_adv *adv; + struct bt_iso_big *big; + + init(); + + /* Create advertising set and BIG */ + create_ext_adv(&adv); + create_big(adv, ARRAY_SIZE(iso_chans), &big); + + /* Reset BT to see if we can set it up again */ + reset_bluetooth(); + + /* After a disable, all advertising sets and BIGs are removed */ + big = NULL; + adv = NULL; + + /* Set everything up again to see if everything still works as expected */ + create_ext_adv(&adv); + create_big(adv, ARRAY_SIZE(iso_chans), &big); + start_ext_adv(adv); + start_tx(); + + /* Wait for receiver to tell us to terminate */ + bk_sync_wait(); + + terminate_big(big); + big = NULL; + + TEST_PASS("Disable test passed"); +} + +static const struct bst_test_instance test_def[] = { + { + .test_id = "broadcaster", + .test_descr = "Minimal BIS broadcaster that broadcast ISO data", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_main, + }, + { + .test_id = "broadcaster_disable", + .test_descr = "BIS broadcaster that tests bt_disable for ISO", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_main_disable, + }, + BSTEST_END_MARKER, +}; + +struct bst_test_list *test_main_bis_broadcaster_install(struct bst_test_list *tests) +{ + return bst_add_tests(tests, test_def); +} diff --git a/tests/bsim/bluetooth/host/iso/bis/src/bis_receiver.c b/tests/bsim/bluetooth/host/iso/bis/src/bis_receiver.c new file mode 100644 index 00000000000..6d1ec087b23 --- /dev/null +++ b/tests/bsim/bluetooth/host/iso/bis/src/bis_receiver.c @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "common.h" + +#include +#include +#include + +#include "babblekit/flags.h" +#include "babblekit/sync.h" +#include "babblekit/testcase.h" + +LOG_MODULE_REGISTER(bis_receiver, LOG_LEVEL_INF); + +#define PA_SYNC_INTERVAL_TO_TIMEOUT_RATIO 5U /* Set the timeout relative to interval */ + +extern enum bst_result_t bst_result; + +static DEFINE_FLAG(flag_broadcaster_found); +static DEFINE_FLAG(flag_iso_connected); +static DEFINE_FLAG(flag_data_received); +static DEFINE_FLAG(flag_pa_synced); +static DEFINE_FLAG(flag_biginfo); + +static struct bt_iso_chan iso_chans[CONFIG_BT_ISO_MAX_CHAN]; +static struct bt_le_scan_recv_info broadcaster_info; +static bt_addr_le_t broadcaster_addr; +static uint8_t broadcaster_num_bis; + +/** Log data as d_0 d_1 d_2 ... d_(n-2) d_(n-1) d_(n) to show the 3 first and 3 last octets + * + * Examples: + * 01 + * 0102 + * 010203 + * 01020304 + * 0102030405 + * 010203040506 + * 010203...050607 + * 010203...060708 + * etc. + */ +static void iso_log_data(uint8_t *data, size_t data_len) +{ + /* Maximum number of octets from each end of the data */ + const uint8_t max_octets = 3; + char data_str[35]; + size_t str_len; + + str_len = bin2hex(data, MIN(max_octets, data_len), data_str, sizeof(data_str)); + if (data_len > max_octets) { + if (data_len > (max_octets * 2)) { + static const char dots[] = "..."; + + strcat(&data_str[str_len], dots); + str_len += strlen(dots); + } + + str_len += bin2hex(data + (data_len - MIN(max_octets, data_len - max_octets)), + MIN(max_octets, data_len - max_octets), data_str + str_len, + sizeof(data_str) - str_len); + } + + LOG_DBG("\t %s", data_str); +} + +static void iso_recv(struct bt_iso_chan *chan, const struct bt_iso_recv_info *info, + struct net_buf *buf) +{ + if (info->flags & BT_ISO_FLAGS_VALID) { + LOG_DBG("Incoming data channel %p len %u", chan, buf->len); + iso_log_data(buf->data, buf->len); + SET_FLAG(flag_data_received); + } +} + +static void iso_connected(struct bt_iso_chan *chan) +{ + LOG_INF("ISO Channel %p connected", chan); + + SET_FLAG(flag_iso_connected); +} + +static void iso_disconnected(struct bt_iso_chan *chan, uint8_t reason) +{ + LOG_INF("ISO Channel %p disconnected (reason 0x%02x)", chan, reason); + + UNSET_FLAG(flag_iso_connected); +} + +static void broadcast_scan_recv(const struct bt_le_scan_recv_info *info, struct net_buf_simple *ad) +{ + if (IS_FLAG_SET(flag_broadcaster_found)) { + /* no-op*/ + return; + } + + LOG_INF("Broadcaster found"); + + if (info->interval != 0U) { + memcpy(&broadcaster_info, info, sizeof(broadcaster_info)); + bt_addr_le_copy(&broadcaster_addr, info->addr); + SET_FLAG(flag_broadcaster_found); + } +} + +static void pa_synced_cb(struct bt_le_per_adv_sync *sync, + struct bt_le_per_adv_sync_synced_info *info) +{ + LOG_INF("PA synced"); + + SET_FLAG(flag_pa_synced); +} + +static void pa_term_cb(struct bt_le_per_adv_sync *sync, + const struct bt_le_per_adv_sync_term_info *info) +{ + LOG_INF("PA terminated"); + + UNSET_FLAG(flag_pa_synced); +} + +static void pa_biginfo_cb(struct bt_le_per_adv_sync *sync, const struct bt_iso_biginfo *biginfo) +{ + if (IS_FLAG_SET(flag_biginfo)) { + /* no-op*/ + return; + } + + LOG_INF("BIGInfo received"); + + broadcaster_num_bis = biginfo->num_bis; + SET_FLAG(flag_biginfo); +} + +static void init(void) +{ + static struct bt_le_per_adv_sync_cb pa_sync_cbs = { + .biginfo = pa_biginfo_cb, + .synced = pa_synced_cb, + .term = pa_term_cb, + }; + static struct bt_le_scan_cb bap_scan_cb = { + .recv = broadcast_scan_recv, + }; + static struct bt_iso_chan_io_qos iso_rx = { + .sdu = CONFIG_BT_ISO_TX_MTU, + }; + static struct bt_iso_chan_ops iso_ops = { + .recv = iso_recv, + .connected = iso_connected, + .disconnected = iso_disconnected, + }; + static struct bt_iso_chan_qos iso_qos = { + .rx = &iso_rx, + }; + int err; + + err = bt_enable(NULL); + TEST_ASSERT(err == 0, "Bluetooth enable failed (err %d)", err); + + for (size_t i = 0U; i < ARRAY_SIZE(iso_chans); i++) { + iso_chans[i].ops = &iso_ops; + iso_chans[i].qos = &iso_qos; + } + + bt_le_per_adv_sync_cb_register(&pa_sync_cbs); + bt_le_scan_cb_register(&bap_scan_cb); + + bk_sync_init(); +} + +static uint16_t interval_to_sync_timeout(uint16_t pa_interval) +{ + uint32_t interval_ms; + uint16_t pa_timeout; + uint32_t timeout; + + /* Add retries and convert to unit in 10's of ms */ + interval_ms = BT_GAP_PER_ADV_INTERVAL_TO_MS(pa_interval); + timeout = (interval_ms * PA_SYNC_INTERVAL_TO_TIMEOUT_RATIO) / 10U; + + /* Enforce restraints */ + pa_timeout = CLAMP(timeout, BT_GAP_PER_ADV_MIN_TIMEOUT, BT_GAP_PER_ADV_MAX_TIMEOUT); + + return pa_timeout; +} + +static void scan_and_sync_pa(struct bt_le_per_adv_sync **out_sync) +{ + struct bt_le_per_adv_sync_param create_params = {0}; + int err; + + LOG_INF("Starting scan"); + err = bt_le_scan_start(BT_LE_SCAN_ACTIVE, NULL); + TEST_ASSERT(err == 0, "Failed to start scan: %d", err); + + WAIT_FOR_FLAG(flag_broadcaster_found); + + bt_addr_le_copy(&create_params.addr, &broadcaster_addr); + create_params.options = BT_LE_PER_ADV_SYNC_OPT_FILTER_DUPLICATE; + create_params.sid = broadcaster_info.sid; + create_params.skip = 0U; + create_params.timeout = interval_to_sync_timeout(broadcaster_info.interval); + + LOG_INF("Creating PA sync"); + err = bt_le_per_adv_sync_create(&create_params, out_sync); + TEST_ASSERT(err == 0, "Failed to sync to PA: %d", err); + + WAIT_FOR_FLAG(flag_pa_synced); + + LOG_INF("Stopping scan"); + err = bt_le_scan_stop(); + TEST_ASSERT(err == 0, "Failed to stop scan: %d", err); +} + +static void sync_big(struct bt_le_per_adv_sync *sync, uint8_t cnt, struct bt_iso_big **out_big) +{ + struct bt_iso_chan *bis_channels[CONFIG_BT_ISO_MAX_CHAN]; + struct bt_iso_big_sync_param param = { + .sync_timeout = interval_to_sync_timeout(broadcaster_info.interval), + .bis_bitfield = BIT_MASK(cnt) << 1U, /* BIS indexes start from 1, thus shift by 1 */ + .bis_channels = bis_channels, + .mse = BT_ISO_SYNC_MSE_MIN, + .encryption = false, + .num_bis = cnt, + }; + int err; + + TEST_ASSERT(cnt <= ARRAY_SIZE(bis_channels)); + for (size_t i = 0U; i < cnt; i++) { + bis_channels[i] = &iso_chans[i]; + } + + LOG_INF("Creating BIG sync"); + err = bt_iso_big_sync(sync, ¶m, out_big); + TEST_ASSERT(err == 0, "Failed to create BIG sync: %d"); + + WAIT_FOR_FLAG(flag_iso_connected); +} + +static void test_main(void) +{ + struct bt_le_per_adv_sync *sync; + struct bt_iso_big *big; + + init(); + scan_and_sync_pa(&sync); + WAIT_FOR_FLAG(flag_biginfo); + sync_big(sync, MIN(broadcaster_num_bis, CONFIG_BT_ISO_MAX_CHAN), &big); + + LOG_INF("Waiting for data"); + WAIT_FOR_FLAG(flag_data_received); + bk_sync_send(); + + LOG_INF("Waiting for sync lost"); + WAIT_FOR_FLAG_UNSET(flag_iso_connected); + + TEST_PASS("Test passed"); +} + +static const struct bst_test_instance test_def[] = { + { + .test_id = "receiver", + .test_descr = "receiver", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_main, + }, + BSTEST_END_MARKER, +}; + +struct bst_test_list *test_main_bis_receiver_install(struct bst_test_list *tests) +{ + return bst_add_tests(tests, test_def); +} diff --git a/tests/bsim/bluetooth/host/iso/bis/src/common.c b/tests/bsim/bluetooth/host/iso/bis/src/common.c new file mode 100644 index 00000000000..f644f9181c2 --- /dev/null +++ b/tests/bsim/bluetooth/host/iso/bis/src/common.c @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include + +#include +#include +#include +#include + +#include "babblekit/flags.h" +#include "babblekit/testcase.h" + +#include "common.h" + +extern enum bst_result_t bst_result; + +void test_init(void) +{ + bst_result = In_progress; + bst_ticker_set_next_tick_absolute(WAIT_TIME); +} + +void test_tick(bs_time_t HW_device_time) +{ + if (bst_result != Passed) { + TEST_FAIL("Test failed (not passed after %" PRIu64 " us)", WAIT_TIME); + } +} diff --git a/tests/bsim/bluetooth/host/iso/bis/src/common.h b/tests/bsim/bluetooth/host/iso/bis/src/common.h new file mode 100644 index 00000000000..60a191e3883 --- /dev/null +++ b/tests/bsim/bluetooth/host/iso/bis/src/common.h @@ -0,0 +1,16 @@ +/* + * Common functions and helpers for ISO broadcast tests + * + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "bs_types.h" +#include "bs_tracing.h" +#include "bstests.h" + +#define WAIT_TIME (30e6) /* 30 seconds*/ + +void test_init(void); +void test_tick(bs_time_t HW_device_time); diff --git a/tests/bsim/bluetooth/host/iso/bis/src/main.c b/tests/bsim/bluetooth/host/iso/bis/src/main.c new file mode 100644 index 00000000000..3bfdb375334 --- /dev/null +++ b/tests/bsim/bluetooth/host/iso/bis/src/main.c @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "bstests.h" + +extern struct bst_test_list *test_main_bis_broadcaster_install(struct bst_test_list *tests); +extern struct bst_test_list *test_main_bis_receiver_install(struct bst_test_list *tests); + +bst_test_install_t test_installers[] = { + test_main_bis_broadcaster_install, + test_main_bis_receiver_install, + NULL, +}; + +int main(void) +{ + bst_main(); + return 0; +} diff --git a/tests/bsim/bluetooth/host/iso/bis/tests_scripts/_compile.sh b/tests/bsim/bluetooth/host/iso/bis/tests_scripts/_compile.sh new file mode 100755 index 00000000000..e717a4b2bbe --- /dev/null +++ b/tests/bsim/bluetooth/host/iso/bis/tests_scripts/_compile.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +# Copyright 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 +set -eu +: "${ZEPHYR_BASE:?ZEPHYR_BASE must be defined}" + +INCR_BUILD=1 + +source ${ZEPHYR_BASE}/tests/bsim/compile.source + +app="$(guess_test_relpath)" compile + +wait_for_background_jobs diff --git a/tests/bsim/bluetooth/host/iso/bis/tests_scripts/bis.sh b/tests/bsim/bluetooth/host/iso/bis/tests_scripts/bis.sh new file mode 100755 index 00000000000..18c76e299e3 --- /dev/null +++ b/tests/bsim/bluetooth/host/iso/bis/tests_scripts/bis.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +# Copyright (c) 2023 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +simulation_id="iso_bis" +verbosity_level=2 + +cd ${BSIM_OUT_PATH}/bin + +Execute ./bs_${BOARD_TS}_tests_bsim_bluetooth_host_iso_bis_prj_conf \ + -v=${verbosity_level} -s=${simulation_id} -d=0 -testid=broadcaster + +Execute ./bs_${BOARD_TS}_tests_bsim_bluetooth_host_iso_bis_prj_conf \ + -v=${verbosity_level} -s=${simulation_id} -d=1 -testid=receiver + +Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \ + -D=2 -sim_length=30e6 $@ + +wait_for_background_jobs diff --git a/tests/bsim/bluetooth/host/iso/bis/tests_scripts/bis_disable.sh b/tests/bsim/bluetooth/host/iso/bis/tests_scripts/bis_disable.sh new file mode 100755 index 00000000000..980af68ee6f --- /dev/null +++ b/tests/bsim/bluetooth/host/iso/bis/tests_scripts/bis_disable.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +# Copyright (c) 2023 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +simulation_id="iso_bis_disable" +verbosity_level=2 + +cd ${BSIM_OUT_PATH}/bin + +Execute ./bs_${BOARD_TS}_tests_bsim_bluetooth_host_iso_bis_prj_conf \ + -v=${verbosity_level} -s=${simulation_id} -d=0 -testid=broadcaster_disable + +Execute ./bs_${BOARD_TS}_tests_bsim_bluetooth_host_iso_bis_prj_conf \ + -v=${verbosity_level} -s=${simulation_id} -d=1 -testid=receiver + +Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \ + -D=2 -sim_length=30e6 $@ + +wait_for_background_jobs diff --git a/tests/bsim/bluetooth/host/iso/cis/prj.conf b/tests/bsim/bluetooth/host/iso/cis/prj.conf index d1a1b8cd161..134cd4beed5 100644 --- a/tests/bsim/bluetooth/host/iso/cis/prj.conf +++ b/tests/bsim/bluetooth/host/iso/cis/prj.conf @@ -17,7 +17,8 @@ CONFIG_BT_ISO_LOG_LEVEL_DBG=y # Controller Connected ISO configs CONFIG_BT_CTLR_CENTRAL_ISO=y CONFIG_BT_CTLR_PERIPHERAL_ISO=y +CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=208 +CONFIG_BT_CTLR_ISO_TX_BUFFERS=4 CONFIG_BT_CTLR_ISOAL_SOURCES=2 CONFIG_BT_CTLR_ISOAL_SINKS=2 - -CONFIG_BT_CTLR_ISO_TX_BUFFERS=4 +CONFIG_BT_CTLR_CONN_ISO_STREAMS_PER_GROUP=4 diff --git a/tests/bsim/bluetooth/host/iso/cis/src/cis_central.c b/tests/bsim/bluetooth/host/iso/cis/src/cis_central.c index 2cae15e7862..9c85946c1a2 100644 --- a/tests/bsim/bluetooth/host/iso/cis/src/cis_central.c +++ b/tests/bsim/bluetooth/host/iso/cis/src/cis_central.c @@ -107,19 +107,23 @@ static void iso_connected(struct bt_iso_chan *chan) seq_num = 0U; enqueue_cnt = ENQUEUE_COUNT; - /* Start send timer */ - k_work_schedule(&iso_send_work, K_MSEC(0)); + if (chan == default_chan) { + /* Start send timer */ + k_work_schedule(&iso_send_work, K_MSEC(0)); - SET_FLAG(flag_iso_connected); + SET_FLAG(flag_iso_connected); + } } static void iso_disconnected(struct bt_iso_chan *chan, uint8_t reason) { printk("ISO Channel %p disconnected (reason 0x%02x)\n", chan, reason); - k_work_cancel_delayable(&iso_send_work); + if (chan == default_chan) { + k_work_cancel_delayable(&iso_send_work); - UNSET_FLAG(flag_iso_connected); + UNSET_FLAG(flag_iso_connected); + } } static void sdu_sent_cb(struct bt_iso_chan *chan) @@ -188,12 +192,19 @@ static void set_cig_defaults(struct bt_iso_cig_param *param) } -static void create_cig(void) +static void create_cig(size_t iso_channels) { + struct bt_iso_chan *channels[ARRAY_SIZE(iso_chans)]; struct bt_iso_cig_param param; int err; + for (size_t i = 0U; i < iso_channels; i++) { + channels[i] = &iso_chans[i]; + } + set_cig_defaults(¶m); + param.num_cis = iso_channels; + param.cis_channels = channels; err = bt_iso_cig_create(¶m, &cig); if (err != 0) { @@ -385,10 +396,34 @@ static void terminate_cig(void) cig = NULL; } +static void reset_bluetooth(void) +{ + int err; + + printk("Resetting Bluetooth\n"); + + err = bt_disable(); + if (err != 0) { + FAIL("Failed to disable (%d)\n", err); + + return; + } + + /* After a disable, all CIGs and BIGs are removed */ + cig = NULL; + + err = bt_enable(NULL); + if (err != 0) { + FAIL("Failed to re-enable (%d)\n", err); + + return; + } +} + static void test_main(void) { init(); - create_cig(); + create_cig(1); reconfigure_cig(); connect_acl(); connect_cis(); @@ -404,6 +439,34 @@ static void test_main(void) PASS("Test passed\n"); } +static void test_main_disable(void) +{ + init(); + + /* Setup and connect before disabling */ + create_cig(ARRAY_SIZE(iso_chans)); + connect_acl(); + connect_cis(); + + /* Reset BT to see if we can set it up again */ + reset_bluetooth(); + + /* Set everything up again to see if everything still works as expected */ + create_cig(ARRAY_SIZE(iso_chans)); + connect_acl(); + connect_cis(); + + while (seq_num < 100U) { + k_sleep(K_USEC(interval_us)); + } + + disconnect_cis(); + disconnect_acl(); + terminate_cig(); + + PASS("Disable test passed\n"); +} + static const struct bst_test_instance test_def[] = { { .test_id = "central", @@ -412,6 +475,13 @@ static const struct bst_test_instance test_def[] = { .test_tick_f = test_tick, .test_main_f = test_main, }, + { + .test_id = "central_disable", + .test_descr = "CIS central that tests bt_disable for ISO", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_main_disable, + }, BSTEST_END_MARKER, }; diff --git a/tests/bsim/bluetooth/host/iso/cis/src/cis_peripheral.c b/tests/bsim/bluetooth/host/iso/cis/src/cis_peripheral.c index fdaed6ef0ed..a07ffbb6efb 100644 --- a/tests/bsim/bluetooth/host/iso/cis/src/cis_peripheral.c +++ b/tests/bsim/bluetooth/host/iso/cis/src/cis_peripheral.c @@ -144,7 +144,7 @@ static void adv_connect(void) { int err; - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0); + err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), NULL, 0); if (err) { FAIL("Advertising failed to start (err %d)\n", err); diff --git a/tests/bsim/bluetooth/host/iso/cis/tests_scripts/cis_disable.sh b/tests/bsim/bluetooth/host/iso/cis/tests_scripts/cis_disable.sh new file mode 100755 index 00000000000..dfd2d8d11e2 --- /dev/null +++ b/tests/bsim/bluetooth/host/iso/cis/tests_scripts/cis_disable.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +# Copyright (c) 2023 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +simulation_id="iso_cis_disable" +verbosity_level=2 + +cd ${BSIM_OUT_PATH}/bin + +Execute ./bs_${BOARD_TS}_tests_bsim_bluetooth_host_iso_cis_prj_conf \ + -v=${verbosity_level} -s=${simulation_id} -d=0 -testid=central_disable + +Execute ./bs_${BOARD_TS}_tests_bsim_bluetooth_host_iso_cis_prj_conf \ + -v=${verbosity_level} -s=${simulation_id} -d=1 -testid=peripheral + +Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \ + -D=2 -sim_length=30e6 $@ + +wait_for_background_jobs diff --git a/tests/bsim/bluetooth/host/l2cap/compile.sh b/tests/bsim/bluetooth/host/l2cap/compile.sh index b08686e12ab..b8f5201dd25 100755 --- a/tests/bsim/bluetooth/host/l2cap/compile.sh +++ b/tests/bsim/bluetooth/host/l2cap/compile.sh @@ -13,14 +13,16 @@ source ${ZEPHYR_BASE}/tests/bsim/compile.source app=tests/bsim/bluetooth/host/l2cap/general compile app=tests/bsim/bluetooth/host/l2cap/userdata compile app=tests/bsim/bluetooth/host/l2cap/stress compile +app=tests/bsim/bluetooth/host/l2cap/stress conf_file=prj_nofrag.conf compile app=tests/bsim/bluetooth/host/l2cap/stress conf_file=prj_syswq.conf compile app=tests/bsim/bluetooth/host/l2cap/split/dut compile app=tests/bsim/bluetooth/host/l2cap/split/tester compile +app=tests/bsim/bluetooth/host/l2cap/ecred/dut compile +app=tests/bsim/bluetooth/host/l2cap/ecred/peer compile app=tests/bsim/bluetooth/host/l2cap/credits compile app=tests/bsim/bluetooth/host/l2cap/credits conf_file=prj_ecred.conf compile app=tests/bsim/bluetooth/host/l2cap/credits_seg_recv compile app=tests/bsim/bluetooth/host/l2cap/credits_seg_recv conf_file=prj_ecred.conf compile -app=tests/bsim/bluetooth/host/l2cap/frags compile app=tests/bsim/bluetooth/host/l2cap/send_on_connect compile app=tests/bsim/bluetooth/host/l2cap/send_on_connect conf_file=prj_ecred.conf compile diff --git a/tests/bsim/bluetooth/host/l2cap/credits/src/main.c b/tests/bsim/bluetooth/host/l2cap/credits/src/main.c index dcc3d5a2373..cf44c85f262 100644 --- a/tests/bsim/bluetooth/host/l2cap/credits/src/main.c +++ b/tests/bsim/bluetooth/host/l2cap/credits/src/main.c @@ -210,15 +210,10 @@ static void disconnect_device(struct bt_conn *conn, void *data) WAIT_FOR_FLAG_UNSET(is_connected); } -#define BT_LE_ADV_CONN_NAME_OT BT_LE_ADV_PARAM(BT_LE_ADV_OPT_CONNECTABLE | \ - BT_LE_ADV_OPT_USE_NAME | \ - BT_LE_ADV_OPT_ONE_TIME, \ - BT_GAP_ADV_FAST_INT_MIN_2, \ - BT_GAP_ADV_FAST_INT_MAX_2, NULL) - -static const struct bt_data ad[] = { - BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), -}; +#define BT_LE_ADV_CONN_OT BT_LE_ADV_PARAM(BT_LE_ADV_OPT_CONNECTABLE | \ + BT_LE_ADV_OPT_ONE_TIME, \ + BT_GAP_ADV_FAST_INT_MIN_2, \ + BT_GAP_ADV_FAST_INT_MAX_2, NULL) static void test_peripheral_main(void) { @@ -238,7 +233,7 @@ static void test_peripheral_main(void) LOG_DBG("Peripheral Bluetooth initialized."); LOG_DBG("Connectable advertising..."); - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME_OT, ad, ARRAY_SIZE(ad), NULL, 0); + err = bt_le_adv_start(BT_LE_ADV_CONN_OT, NULL, 0, NULL, 0); if (err) { FAIL("Advertising failed to start (err %d)", err); return; diff --git a/tests/bsim/bluetooth/host/l2cap/credits_seg_recv/src/main.c b/tests/bsim/bluetooth/host/l2cap/credits_seg_recv/src/main.c index 77dd72dde02..7db0f8def30 100644 --- a/tests/bsim/bluetooth/host/l2cap/credits_seg_recv/src/main.c +++ b/tests/bsim/bluetooth/host/l2cap/credits_seg_recv/src/main.c @@ -227,15 +227,10 @@ static void disconnect_device(struct bt_conn *conn, void *data) WAIT_FOR_FLAG_UNSET(is_connected); } -#define BT_LE_ADV_CONN_NAME_OT \ - BT_LE_ADV_PARAM(BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_USE_NAME | \ - BT_LE_ADV_OPT_ONE_TIME, \ +#define BT_LE_ADV_CONN_OT \ + BT_LE_ADV_PARAM(BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_ONE_TIME, \ BT_GAP_ADV_FAST_INT_MIN_2, BT_GAP_ADV_FAST_INT_MAX_2, NULL) -static const struct bt_data ad[] = { - BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), -}; - static void test_peripheral_main(void) { int err; @@ -256,7 +251,7 @@ static void test_peripheral_main(void) LOG_DBG("Peripheral Bluetooth initialized."); LOG_DBG("Connectable advertising..."); - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME_OT, ad, ARRAY_SIZE(ad), NULL, 0); + err = bt_le_adv_start(BT_LE_ADV_CONN_OT, NULL, 0, NULL, 0); if (err) { FAIL("Advertising failed to start (err %d)", err); return; diff --git a/tests/bsim/bluetooth/host/l2cap/ecred/dut/CMakeLists.txt b/tests/bsim/bluetooth/host/l2cap/ecred/dut/CMakeLists.txt new file mode 100644 index 00000000000..200ffba68ce --- /dev/null +++ b/tests/bsim/bluetooth/host/l2cap/ecred/dut/CMakeLists.txt @@ -0,0 +1,23 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) + +project(ecred_dut) + +add_subdirectory(${ZEPHYR_BASE}/tests/bluetooth/common/testlib testlib) +target_link_libraries(app PRIVATE testlib) + +add_subdirectory(${ZEPHYR_BASE}/tests/bsim/babblekit babblekit) +target_link_libraries(app PRIVATE babblekit) + +zephyr_include_directories( + ${BSIM_COMPONENTS_PATH}/libUtilv1/src/ + ${BSIM_COMPONENTS_PATH}/libPhyComv1/src/ +) + +target_sources(app PRIVATE + src/main.c + src/dut.c +) diff --git a/tests/bsim/bluetooth/host/l2cap/ecred/dut/Kconfig b/tests/bsim/bluetooth/host/l2cap/ecred/dut/Kconfig new file mode 100644 index 00000000000..d1289e2c121 --- /dev/null +++ b/tests/bsim/bluetooth/host/l2cap/ecred/dut/Kconfig @@ -0,0 +1,18 @@ +# Kconfig options for the test +# +# Only used as single point for log level configuration. +# Can be extended with any new kconfig, really. +# +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +menu "Test configuration" + +module = APP +module-str = app + +source "subsys/logging/Kconfig.template.log_config" + +endmenu + +source "Kconfig.zephyr" diff --git a/tests/bsim/bluetooth/host/l2cap/ecred/dut/prj.conf b/tests/bsim/bluetooth/host/l2cap/ecred/dut/prj.conf new file mode 100644 index 00000000000..ba574d9f200 --- /dev/null +++ b/tests/bsim/bluetooth/host/l2cap/ecred/dut/prj.conf @@ -0,0 +1,29 @@ +CONFIG_BT=y +CONFIG_BT_DEVICE_NAME="ecred" +CONFIG_BT_CENTRAL=y + +CONFIG_BT_SMP=y # Next config depends on it +CONFIG_BT_L2CAP_DYNAMIC_CHANNEL=y +CONFIG_BT_L2CAP_ECRED=y + +# Disable auto-initiated procedures so they don't +# mess with the test's execution. +CONFIG_BT_AUTO_PHY_UPDATE=n +CONFIG_BT_AUTO_DATA_LEN_UPDATE=n +CONFIG_BT_GAP_AUTO_UPDATE_CONN_PARAMS=n + +# Dependency of testlib/adv and testlib/scan. +CONFIG_BT_EXT_ADV=y + +CONFIG_ASSERT=y +CONFIG_LOG=y +CONFIG_THREAD_NAME=y +CONFIG_LOG_THREAD_ID_PREFIX=y + +CONFIG_ARCH_POSIX_TRAP_ON_FATAL=y + +# CONFIG_APP_LOG_LEVEL_DBG=y +# CONFIG_BT_L2CAP_LOG_LEVEL_DBG=y + +# Don't print the bt init stuff +CONFIG_BT_HCI_CORE_LOG_LEVEL_WRN=y diff --git a/tests/bsim/bluetooth/host/l2cap/ecred/dut/src/dut.c b/tests/bsim/bluetooth/host/l2cap/ecred/dut/src/dut.c new file mode 100644 index 00000000000..0a822efc4b0 --- /dev/null +++ b/tests/bsim/bluetooth/host/l2cap/ecred/dut/src/dut.c @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include "testlib/conn.h" +#include "testlib/scan.h" + +#include "babblekit/flags.h" +#include "babblekit/testcase.h" + +LOG_MODULE_REGISTER(dut, CONFIG_APP_LOG_LEVEL); + +static atomic_t disconnected_channels; + +static struct bt_l2cap_le_chan chans[4]; + +void sent_cb(struct bt_l2cap_chan *chan) +{ + LOG_DBG("%p", chan); +} + +int recv_cb(struct bt_l2cap_chan *chan, struct net_buf *buf) +{ + LOG_DBG("%p", chan); + + return 0; +} + +void l2cap_chan_connected_cb(struct bt_l2cap_chan *l2cap_chan) +{ + TEST_ASSERT("This shouldn't happen"); +} + +void l2cap_chan_disconnected_cb(struct bt_l2cap_chan *chan) +{ + atomic_inc(&disconnected_channels); +} + +static struct bt_l2cap_chan_ops ops = { + .connected = l2cap_chan_connected_cb, + .disconnected = l2cap_chan_disconnected_cb, + .recv = recv_cb, + .sent = sent_cb, +}; + +void entrypoint_dut(void) +{ + /* Test purpose: + * + * Verify that a peer that doesn't support ECRED channels doesn't result + * in us keeping half-open channels. + * + * Two devices: + * - `dut`: tries to establish 4 ecred chans + * - `peer`: rejects the request + * + * Initial conditions: + * - Both devices are connected + * + * Procedure: + * - [dut] request to establish 4 ecred channels + * - [peer] reject command as unknown + * - [dut] get `disconnected` called on all 4 channels + * + * [verdict] + * - each channel gets the `disconnected` callback called + */ + int err; + bt_addr_le_t peer = {}; + struct bt_conn *conn = NULL; + + TEST_START("dut"); + + /* Initialize Bluetooth */ + err = bt_enable(NULL); + TEST_ASSERT(err == 0, "Can't enable Bluetooth (err %d)", err); + LOG_DBG("Bluetooth initialized"); + + err = bt_testlib_scan_find_name(&peer, "ecred_peer"); + TEST_ASSERT(!err, "Failed to start scan (err %d)", err); + + /* Create a connection using that address */ + err = bt_testlib_connect(&peer, &conn); + TEST_ASSERT(!err, "Failed to initiate connection (err %d)", err); + + LOG_DBG("Connected"); + + LOG_INF("Send ECRED connection request"); + struct bt_l2cap_chan *chan_list[5] = {0}; + + for (int i = 0; i < 4; i++) { + /* Register the callbacks */ + chans[i].chan.ops = &ops; + + /* Add the channel to the connection request list */ + chan_list[i] = &chans[i].chan; + } + + /* The PSM doesn't matter, as the peer doesn't support the command */ + err = bt_l2cap_ecred_chan_connect(conn, chan_list, 0x0080); + TEST_ASSERT(!err, "Error connecting l2cap channels (err %d)\n", err); + + LOG_INF("Wait until peer rejects the channel establishment request"); + while (atomic_get(&disconnected_channels) < 4) { + k_sleep(K_MSEC(10)); + } + + TEST_PASS_AND_EXIT("dut"); +} diff --git a/tests/bsim/bluetooth/host/l2cap/ecred/dut/src/main.c b/tests/bsim/bluetooth/host/l2cap/ecred/dut/src/main.c new file mode 100644 index 00000000000..300b77e778b --- /dev/null +++ b/tests/bsim/bluetooth/host/l2cap/ecred/dut/src/main.c @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "bs_tracing.h" +#include "bstests.h" +#include "babblekit/testcase.h" + +extern void entrypoint_dut(void); +extern enum bst_result_t bst_result; + + +static void test_end_cb(void) +{ + if (bst_result != Passed) { + TEST_PRINT("Test has not passed."); + } +} + +static const struct bst_test_instance entrypoints[] = { + { + .test_id = "dut", + .test_delete_f = test_end_cb, + .test_main_f = entrypoint_dut, + }, + BSTEST_END_MARKER, +}; + +static struct bst_test_list *install(struct bst_test_list *tests) +{ + return bst_add_tests(tests, entrypoints); +}; + +bst_test_install_t test_installers[] = {install, NULL}; + +int main(void) +{ + bst_main(); + + return 0; +} diff --git a/tests/bsim/bluetooth/host/l2cap/ecred/peer/CMakeLists.txt b/tests/bsim/bluetooth/host/l2cap/ecred/peer/CMakeLists.txt new file mode 100644 index 00000000000..bfc8237ea67 --- /dev/null +++ b/tests/bsim/bluetooth/host/l2cap/ecred/peer/CMakeLists.txt @@ -0,0 +1,23 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) + +project(ecred_peer) + +add_subdirectory(${ZEPHYR_BASE}/tests/bluetooth/common/testlib testlib) +target_link_libraries(app PRIVATE testlib) + +add_subdirectory(${ZEPHYR_BASE}/tests/bsim/babblekit babblekit) +target_link_libraries(app PRIVATE babblekit) + +zephyr_include_directories( + ${BSIM_COMPONENTS_PATH}/libUtilv1/src/ + ${BSIM_COMPONENTS_PATH}/libPhyComv1/src/ +) + +target_sources(app PRIVATE + src/main.c + src/peer.c +) diff --git a/tests/bsim/bluetooth/host/l2cap/ecred/peer/prj.conf b/tests/bsim/bluetooth/host/l2cap/ecred/peer/prj.conf new file mode 100644 index 00000000000..e7941a800a8 --- /dev/null +++ b/tests/bsim/bluetooth/host/l2cap/ecred/peer/prj.conf @@ -0,0 +1,29 @@ +CONFIG_BT=y +CONFIG_BT_DEVICE_NAME="ecred_peer" +CONFIG_BT_PERIPHERAL=y + +CONFIG_BT_SMP=y +CONFIG_BT_L2CAP_DYNAMIC_CHANNEL=y +CONFIG_BT_L2CAP_ECRED=n + +# Disable auto-initiated procedures so they don't +# mess with the test's execution. +CONFIG_BT_AUTO_PHY_UPDATE=n +CONFIG_BT_AUTO_DATA_LEN_UPDATE=n +CONFIG_BT_GAP_AUTO_UPDATE_CONN_PARAMS=n + +# Dependency of testlib/adv and testlib/scan. +CONFIG_BT_EXT_ADV=y + +CONFIG_ASSERT=y +CONFIG_LOG=y +CONFIG_THREAD_NAME=y +CONFIG_LOG_THREAD_ID_PREFIX=y + +CONFIG_ARCH_POSIX_TRAP_ON_FATAL=y + +# CONFIG_APP_LOG_LEVEL_DBG=y +# CONFIG_BT_L2CAP_LOG_LEVEL_DBG=y + +# Don't print the bt init stuff +CONFIG_BT_HCI_CORE_LOG_LEVEL_WRN=y diff --git a/tests/bsim/bluetooth/host/l2cap/ecred/peer/src/main.c b/tests/bsim/bluetooth/host/l2cap/ecred/peer/src/main.c new file mode 100644 index 00000000000..4ba6fc1efe8 --- /dev/null +++ b/tests/bsim/bluetooth/host/l2cap/ecred/peer/src/main.c @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "bs_tracing.h" +#include "bstests.h" +#include "babblekit/testcase.h" + +extern void entrypoint_peer(void); +extern enum bst_result_t bst_result; + + +static void test_end_cb(void) +{ + if (bst_result != Passed) { + TEST_PRINT("Test has not passed."); + } +} + +static const struct bst_test_instance entrypoints[] = { + { + .test_id = "peer", + .test_delete_f = test_end_cb, + .test_main_f = entrypoint_peer, + }, + BSTEST_END_MARKER, +}; + +static struct bst_test_list *install(struct bst_test_list *tests) +{ + return bst_add_tests(tests, entrypoints); +}; + +bst_test_install_t test_installers[] = {install, NULL}; + +int main(void) +{ + bst_main(); + + return 0; +} diff --git a/tests/bsim/bluetooth/host/l2cap/ecred/peer/src/peer.c b/tests/bsim/bluetooth/host/l2cap/ecred/peer/src/peer.c new file mode 100644 index 00000000000..026ff5a5b65 --- /dev/null +++ b/tests/bsim/bluetooth/host/l2cap/ecred/peer/src/peer.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include "testlib/adv.h" +#include "testlib/att_read.h" +#include "testlib/att_write.h" +#include "testlib/conn.h" + +#include "babblekit/flags.h" +#include "babblekit/testcase.h" + +void entrypoint_peer(void) +{ + int err; + struct bt_conn *conn; + + /* Mark test as in progress. */ + TEST_START("peer"); + + /* Initialize Bluetooth */ + err = bt_enable(NULL); + TEST_ASSERT(err == 0, "Can't enable Bluetooth (err %d)", err); + + err = bt_testlib_adv_conn(&conn, BT_ID_DEFAULT, bt_get_name()); + TEST_ASSERT(!err, "Failed to start connectable advertising (err %d)", err); + + TEST_PASS("peer"); +} diff --git a/tests/bsim/bluetooth/host/l2cap/ecred/test_scripts/_compile.sh b/tests/bsim/bluetooth/host/l2cap/ecred/test_scripts/_compile.sh new file mode 100755 index 00000000000..44b965da81d --- /dev/null +++ b/tests/bsim/bluetooth/host/l2cap/ecred/test_scripts/_compile.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +# Copyright 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 +set -eu +: "${ZEPHYR_BASE:?ZEPHYR_BASE must be defined}" + +INCR_BUILD=1 + +source ${ZEPHYR_BASE}/tests/bsim/compile.source + +app="$(guess_test_relpath)/dut" compile +app="$(guess_test_relpath)/peer" compile + +wait_for_background_jobs diff --git a/tests/bsim/bluetooth/host/l2cap/ecred/test_scripts/run.sh b/tests/bsim/bluetooth/host/l2cap/ecred/test_scripts/run.sh new file mode 100755 index 00000000000..43ac0f88e65 --- /dev/null +++ b/tests/bsim/bluetooth/host/l2cap/ecred/test_scripts/run.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +# Copyright (c) 2024 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +set -eu + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +test_name="$(guess_test_long_name)" + +simulation_id=${test_name} +verbosity_level=2 + +SIM_LEN_US=$((1 * 1000 * 1000)) + +dut_exe="${BSIM_OUT_PATH}/bin/bs_${BOARD_TS}_${test_name}_dut_prj_conf" +peer_exe="${BSIM_OUT_PATH}/bin/bs_${BOARD_TS}_${test_name}_peer_prj_conf" + +cd ${BSIM_OUT_PATH}/bin + +Execute "${dut_exe}" -v=${verbosity_level} -s=${simulation_id} -d=0 -rs=420 -testid=dut +Execute "${peer_exe}" -v=${verbosity_level} -s=${simulation_id} -d=1 -rs=69 -testid=peer + +Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} -D=2 -sim_length=${SIM_LEN_US} $@ + +wait_for_background_jobs diff --git a/tests/bsim/bluetooth/host/l2cap/frags/CMakeLists.txt b/tests/bsim/bluetooth/host/l2cap/frags/CMakeLists.txt deleted file mode 100644 index 0a40ef4a135..00000000000 --- a/tests/bsim/bluetooth/host/l2cap/frags/CMakeLists.txt +++ /dev/null @@ -1,16 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -cmake_minimum_required(VERSION 3.20.0) - -find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) -project(bsim_test_l2cap_frags) - -target_sources(app PRIVATE - src/main.c - src/common.c) - -zephyr_include_directories( - src/ - ${BSIM_COMPONENTS_PATH}/libUtilv1/src/ - ${BSIM_COMPONENTS_PATH}/libPhyComv1/src/ - ) diff --git a/tests/bsim/bluetooth/host/l2cap/frags/prj.conf b/tests/bsim/bluetooth/host/l2cap/frags/prj.conf deleted file mode 100644 index 6681ea288ee..00000000000 --- a/tests/bsim/bluetooth/host/l2cap/frags/prj.conf +++ /dev/null @@ -1,22 +0,0 @@ -CONFIG_BT=y -CONFIG_BT_CENTRAL=y -CONFIG_BT_PERIPHERAL=y -CONFIG_BT_DEVICE_NAME="L2CAP frags test" - -CONFIG_BT_EATT=n -CONFIG_BT_L2CAP_ECRED=n - -CONFIG_BT_SMP=y # Next config depends on it -CONFIG_BT_L2CAP_DYNAMIC_CHANNEL=y - -# Disable auto-initiated procedures so they don't -# mess with the test's execution. -CONFIG_BT_AUTO_PHY_UPDATE=n -CONFIG_BT_AUTO_DATA_LEN_UPDATE=n -CONFIG_BT_GAP_AUTO_UPDATE_CONN_PARAMS=n - -CONFIG_LOG=y -CONFIG_ASSERT=y - -CONFIG_BT_L2CAP_LOG_LEVEL_DBG=y -CONFIG_ARCH_POSIX_TRAP_ON_FATAL=y diff --git a/tests/bsim/bluetooth/host/l2cap/frags/src/common.c b/tests/bsim/bluetooth/host/l2cap/frags/src/common.c deleted file mode 100644 index c6679d83494..00000000000 --- a/tests/bsim/bluetooth/host/l2cap/frags/src/common.c +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2024 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "common.h" - -extern enum bst_result_t bst_result; - -void test_init(void) -{ - bst_ticker_set_next_tick_absolute(WAIT_TIME); - bst_result = In_progress; -} - -void test_tick(bs_time_t HW_device_time) -{ - if (bst_result != Passed) { - FAIL("test failed (not passed after %i seconds)\n", WAIT_SECONDS); - } -} diff --git a/tests/bsim/bluetooth/host/l2cap/frags/src/common.h b/tests/bsim/bluetooth/host/l2cap/frags/src/common.h deleted file mode 100644 index 4fb971616b3..00000000000 --- a/tests/bsim/bluetooth/host/l2cap/frags/src/common.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Common functions and helpers for L2CAP tests - * - * Copyright (c) 2024 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include - -#include -#include -#include - -#include -#include -#include -#include "bs_types.h" -#include "bs_tracing.h" -#include "bstests.h" -#include "bs_pc_backchannel.h" - -extern enum bst_result_t bst_result; - -#define CREATE_FLAG(flag) static atomic_t flag = (atomic_t)false -#define SET_FLAG(flag) (void)atomic_set(&flag, (atomic_t)true) -#define UNSET_FLAG(flag) (void)atomic_set(&flag, (atomic_t)false) -#define TEST_FLAG(flag) (atomic_get(&flag) == (atomic_t)true) -#define WAIT_FOR_FLAG_SET(flag) \ - while (!(bool)atomic_get(&flag)) { \ - (void)k_sleep(K_MSEC(1)); \ - } -#define WAIT_FOR_FLAG_UNSET(flag) \ - while ((bool)atomic_get(&flag)) { \ - (void)k_sleep(K_MSEC(1)); \ - } - - -#define WAIT_SECONDS 30 /* seconds */ -#define WAIT_TIME (WAIT_SECONDS * USEC_PER_SEC) /* microseconds*/ - -#define FAIL(...) \ - do { \ - bst_result = Failed; \ - bs_trace_error_time_line(__VA_ARGS__); \ - } while (0) - -#define PASS(...) \ - do { \ - bst_result = Passed; \ - bs_trace_info_time(1, __VA_ARGS__); \ - } while (0) - -#define ASSERT(expr, ...) if (!(expr)) {FAIL(__VA_ARGS__); } - -void test_init(void); -void test_tick(bs_time_t HW_device_time); diff --git a/tests/bsim/bluetooth/host/l2cap/frags/src/main.c b/tests/bsim/bluetooth/host/l2cap/frags/src/main.c deleted file mode 100644 index df7924e1829..00000000000 --- a/tests/bsim/bluetooth/host/l2cap/frags/src/main.c +++ /dev/null @@ -1,489 +0,0 @@ -/* - * The goal of this test is to verify the buf->frags feature works with L2CAP - * credit-based channels. - * - * Copyright (c) 2024 Nordic Semiconductor - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "bstests.h" -#include "common.h" - -#define LOG_MODULE_NAME main -#include -LOG_MODULE_REGISTER(LOG_MODULE_NAME, LOG_LEVEL_DBG); - -CREATE_FLAG(is_connected); -CREATE_FLAG(flag_l2cap_connected); - -#define SMALL_BUF_SIZE 10 -#define LARGE_BUF_SIZE 50 -#define POOL_NUM 2 -#define PAYLOAD_SIZE (POOL_NUM * (SMALL_BUF_SIZE + LARGE_BUF_SIZE)) - -#define L2CAP_MTU PAYLOAD_SIZE -#define PAYLOAD_NUM 3 - -NET_BUF_POOL_DEFINE(sdu_rx_pool, 1, BT_L2CAP_SDU_BUF_SIZE(L2CAP_MTU), - CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); - -static void small_buf_destroy(struct net_buf *buf) -{ - LOG_DBG("%p", buf); - net_buf_destroy(buf); -} - -NET_BUF_POOL_DEFINE(small_buf_pool, POOL_NUM, BT_L2CAP_SDU_BUF_SIZE(SMALL_BUF_SIZE), - CONFIG_BT_CONN_TX_USER_DATA_SIZE, small_buf_destroy); - -static void large_buf_destroy(struct net_buf *buf) -{ - LOG_DBG("%p", buf); - net_buf_destroy(buf); -} - -NET_BUF_POOL_DEFINE(large_buf_pool, POOL_NUM, LARGE_BUF_SIZE, - CONFIG_BT_CONN_TX_USER_DATA_SIZE, large_buf_destroy); - -static uint8_t tx_data[PAYLOAD_SIZE]; -static uint16_t rx_cnt; - -K_SEM_DEFINE(sdu_received, 0, 1); -K_SEM_DEFINE(tx_sem, 1, 1); - -struct test_ctx { - struct bt_l2cap_le_chan le_chan; - size_t tx_remaining; - struct net_buf *rx_sdu; -} test_ctx; - -struct net_buf *alloc_and_memcpy(struct net_buf_pool *pool, - size_t reserve, - uint8_t *data, - size_t len) -{ - struct net_buf *buf = net_buf_alloc(pool, K_NO_WAIT); - - if (buf == NULL) { - FAIL("No more memory\n"); - return NULL; - } - - net_buf_reserve(buf, reserve); - net_buf_add_mem(buf, data, len); - - return buf; -} - -int l2cap_chan_send(struct bt_l2cap_chan *chan, uint8_t *data, size_t len) -{ - uint8_t *data_start = data; - struct net_buf *buf, *b; - int ret; - - LOG_DBG("chan %p conn %u data %p len %d", - chan, bt_conn_index(chan->conn), data, len); - - if (k_sem_take(&tx_sem, K_NO_WAIT)) { - FAIL("Already TXing\n"); - return -EAGAIN; - } - - /* Payload is comprised of two small buffers and two big buffers. The - * very first buffer needs a reserve() called on it as per l2cap API - * requirements. - */ - buf = alloc_and_memcpy(&small_buf_pool, - BT_L2CAP_SDU_CHAN_SEND_RESERVE, - data, SMALL_BUF_SIZE); - ASSERT(buf, "No more memory\n"); - - data += SMALL_BUF_SIZE; - - b = alloc_and_memcpy(&small_buf_pool, 0, data, SMALL_BUF_SIZE); - ASSERT(buf, "No more memory\n"); - - LOG_DBG("append frag %p to buf %p", b, buf); - net_buf_frag_add(buf, b); - data += SMALL_BUF_SIZE; - - b = alloc_and_memcpy(&large_buf_pool, 0, data, LARGE_BUF_SIZE); - ASSERT(buf, "No more memory\n"); - - LOG_DBG("append frag %p to buf %p", b, buf); - net_buf_frag_add(buf, b); - data += LARGE_BUF_SIZE; - - b = alloc_and_memcpy(&large_buf_pool, 0, data, LARGE_BUF_SIZE); - ASSERT(buf, "No more memory\n"); - - LOG_DBG("append frag %p to buf %p", b, buf); - net_buf_frag_add(buf, b); - data += LARGE_BUF_SIZE; - - ASSERT(data == (data_start + len), "logic error\n"); - - ret = bt_l2cap_chan_send(chan, buf); - ASSERT(ret >= 0, "Failed sending: err %d", ret); - - LOG_DBG("sent: len %d", len); - - return ret; -} - -struct net_buf *alloc_buf_cb(struct bt_l2cap_chan *chan) -{ - return net_buf_alloc(&sdu_rx_pool, K_NO_WAIT); -} - -void continue_sending(struct test_ctx *ctx) -{ - struct bt_l2cap_chan *chan = &ctx->le_chan.chan; - - LOG_DBG("%p, remaining %d", chan, ctx->tx_remaining); - - if (ctx->tx_remaining) { - l2cap_chan_send(chan, tx_data, sizeof(tx_data)); - } else { - LOG_DBG("Done sending %u", bt_conn_index(chan->conn)); - } -} - -void sent_cb(struct bt_l2cap_chan *chan) -{ - LOG_DBG("%p", chan); - - if (test_ctx.tx_remaining) { - test_ctx.tx_remaining--; - } - - k_sem_give(&tx_sem); - continue_sending(&test_ctx); -} - -int recv_cb(struct bt_l2cap_chan *chan, struct net_buf *buf) -{ - LOG_DBG("len %d", buf->len); - rx_cnt++; - - /* Verify SDU data matches TX'd data. */ - ASSERT(memcmp(buf->data, tx_data, buf->len) == 0, "RX data doesn't match TX"); - - return 0; -} - -void l2cap_chan_connected_cb(struct bt_l2cap_chan *l2cap_chan) -{ - struct bt_l2cap_le_chan *chan = - CONTAINER_OF(l2cap_chan, struct bt_l2cap_le_chan, chan); - - /* TODO: check that actual MPS < expected MPS */ - - SET_FLAG(flag_l2cap_connected); - LOG_DBG("%x (tx mtu %d mps %d) (tx mtu %d mps %d)", - l2cap_chan, - chan->tx.mtu, - chan->tx.mps, - chan->rx.mtu, - chan->rx.mps); -} - -void l2cap_chan_disconnected_cb(struct bt_l2cap_chan *chan) -{ - UNSET_FLAG(flag_l2cap_connected); - LOG_DBG("%p", chan); -} - -static struct bt_l2cap_chan_ops ops = { - .connected = l2cap_chan_connected_cb, - .disconnected = l2cap_chan_disconnected_cb, - .alloc_buf = alloc_buf_cb, - .recv = recv_cb, - .sent = sent_cb, -}; - -int server_accept_cb(struct bt_conn *conn, struct bt_l2cap_server *server, - struct bt_l2cap_chan **chan) -{ - struct bt_l2cap_le_chan *le_chan = &test_ctx.le_chan; - - memset(le_chan, 0, sizeof(*le_chan)); - le_chan->chan.ops = &ops; - le_chan->rx.mtu = L2CAP_MTU; - *chan = &le_chan->chan; - - return 0; -} - -static struct bt_l2cap_server test_l2cap_server = { - .accept = server_accept_cb -}; - -static int l2cap_server_register(bt_security_t sec_level) -{ - test_l2cap_server.psm = 0; - test_l2cap_server.sec_level = sec_level; - - int err = bt_l2cap_server_register(&test_l2cap_server); - - ASSERT(err == 0, "Failed to register l2cap server."); - - return test_l2cap_server.psm; -} - -static void connected(struct bt_conn *conn, uint8_t conn_err) -{ - char addr[BT_ADDR_LE_STR_LEN]; - - bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); - - if (conn_err) { - FAIL("Failed to connect to %s (%u)", addr, conn_err); - return; - } - - LOG_DBG("%s", addr); - - SET_FLAG(is_connected); -} - -static void disconnected(struct bt_conn *conn, uint8_t reason) -{ - char addr[BT_ADDR_LE_STR_LEN]; - - bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); - - LOG_DBG("%p %s (reason 0x%02x)", conn, addr, reason); - - UNSET_FLAG(is_connected); -} - -BT_CONN_CB_DEFINE(conn_callbacks) = { - .connected = connected, - .disconnected = disconnected, -}; - -static void disconnect_device(struct bt_conn *conn, void *data) -{ - int err; - - SET_FLAG(is_connected); - - err = bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); - ASSERT(!err, "Failed to initate disconnect (err %d)", err); - - LOG_DBG("Waiting for disconnection..."); - WAIT_FOR_FLAG_UNSET(is_connected); -} - -#define BT_LE_ADV_CONN_NAME_OT BT_LE_ADV_PARAM(BT_LE_ADV_OPT_CONNECTABLE | \ - BT_LE_ADV_OPT_USE_NAME | \ - BT_LE_ADV_OPT_ONE_TIME, \ - BT_GAP_ADV_FAST_INT_MIN_2, \ - BT_GAP_ADV_FAST_INT_MAX_2, NULL) - -static const struct bt_data ad[] = { - BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), -}; - -static void test_peripheral_main(void) -{ - LOG_DBG("*L2CAP FRAGS Peripheral started*"); - int err; - - /* Prepare tx_data */ - for (size_t i = 0; i < sizeof(tx_data); i++) { - tx_data[i] = (uint8_t)i; - } - - err = bt_enable(NULL); - if (err) { - FAIL("Can't enable Bluetooth (err %d)", err); - return; - } - - LOG_DBG("Peripheral Bluetooth initialized."); - LOG_DBG("Connectable advertising..."); - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME_OT, ad, ARRAY_SIZE(ad), NULL, 0); - if (err) { - FAIL("Advertising failed to start (err %d)", err); - return; - } - - LOG_DBG("Advertising started."); - LOG_DBG("Peripheral waiting for connection..."); - WAIT_FOR_FLAG_SET(is_connected); - LOG_DBG("Peripheral Connected."); - - int psm = l2cap_server_register(BT_SECURITY_L1); - - LOG_DBG("Registered server PSM %x", psm); - - LOG_DBG("Peripheral waiting for transfer completion"); - while (rx_cnt < PAYLOAD_NUM) { - k_sleep(K_MSEC(100)); - } - - bt_conn_foreach(BT_CONN_TYPE_LE, disconnect_device, NULL); - LOG_INF("Total received: %d", rx_cnt); - - ASSERT(rx_cnt == PAYLOAD_NUM, "Did not receive expected no of SDUs\n"); - - PASS("L2CAP FRAGS Peripheral passed\n"); -} - -static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type, - struct net_buf_simple *ad) -{ - struct bt_le_conn_param *param; - struct bt_conn *conn; - int err; - - err = bt_le_scan_stop(); - if (err) { - FAIL("Stop LE scan failed (err %d)", err); - return; - } - - char str[BT_ADDR_LE_STR_LEN]; - - bt_addr_le_to_str(addr, str, sizeof(str)); - - LOG_DBG("Connecting to %s", str); - - param = BT_LE_CONN_PARAM_DEFAULT; - err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, param, &conn); - if (err) { - FAIL("Create conn failed (err %d)", err); - return; - } -} - -static void connect_peripheral(void) -{ - struct bt_le_scan_param scan_param = { - .type = BT_LE_SCAN_TYPE_ACTIVE, - .options = BT_LE_SCAN_OPT_NONE, - .interval = BT_GAP_SCAN_FAST_INTERVAL, - .window = BT_GAP_SCAN_FAST_WINDOW, - }; - - UNSET_FLAG(is_connected); - - int err = bt_le_scan_start(&scan_param, device_found); - - ASSERT(!err, "Scanning failed to start (err %d)\n", err); - - LOG_DBG("Central initiating connection..."); - WAIT_FOR_FLAG_SET(is_connected); -} - -static void connect_l2cap_channel(struct bt_conn *conn, void *data) -{ - int err; - struct bt_l2cap_le_chan *le_chan = &test_ctx.le_chan; - - le_chan->chan.ops = &ops; - le_chan->rx.mtu = L2CAP_MTU; - - UNSET_FLAG(flag_l2cap_connected); - - err = bt_l2cap_chan_connect(conn, &le_chan->chan, 0x0080); - ASSERT(!err, "Error connecting l2cap channel (err %d)\n", err); - - WAIT_FOR_FLAG_SET(flag_l2cap_connected); -} - -static void connect_l2cap_ecred_channel(struct bt_conn *conn, void *data) -{ - int err; - struct bt_l2cap_le_chan *le_chan = &test_ctx.le_chan; - struct bt_l2cap_chan *chan_list[2] = { &le_chan->chan, 0 }; - - le_chan->chan.ops = &ops; - le_chan->rx.mtu = L2CAP_MTU; - - UNSET_FLAG(flag_l2cap_connected); - - err = bt_l2cap_ecred_chan_connect(conn, chan_list, 0x0080); - ASSERT(!err, "Error connecting l2cap channel (err %d)\n", err); - - WAIT_FOR_FLAG_SET(flag_l2cap_connected); -} - -static void test_central_main(void) -{ - LOG_DBG("*L2CAP FRAGS Central started*"); - int err; - - /* Prepare tx_data */ - for (size_t i = 0; i < sizeof(tx_data); i++) { - tx_data[i] = (uint8_t)i; - } - - err = bt_enable(NULL); - ASSERT(err == 0, "Can't enable Bluetooth (err %d)\n", err); - LOG_DBG("Central Bluetooth initialized."); - - connect_peripheral(); - - /* Connect L2CAP channels */ - LOG_DBG("Connect L2CAP channels"); - if (IS_ENABLED(CONFIG_BT_L2CAP_ECRED)) { - bt_conn_foreach(BT_CONN_TYPE_LE, connect_l2cap_ecred_channel, NULL); - } else { - bt_conn_foreach(BT_CONN_TYPE_LE, connect_l2cap_channel, NULL); - } - - /* Send PAYLOAD_NUM SDUs to each peripheral */ - LOG_DBG("Start sending SDUs"); - test_ctx.tx_remaining = PAYLOAD_NUM; - l2cap_chan_send(&test_ctx.le_chan.chan, tx_data, sizeof(tx_data)); - - LOG_DBG("Wait until all transfers are completed."); - while (test_ctx.tx_remaining) { - k_msleep(100); - } - - WAIT_FOR_FLAG_UNSET(is_connected); - LOG_DBG("Peripheral disconnected."); - PASS("L2CAP FRAGS Central passed\n"); -} - -static const struct bst_test_instance test_def[] = { - { - .test_id = "peripheral", - .test_descr = "Peripheral L2CAP FRAGS", - .test_post_init_f = test_init, - .test_tick_f = test_tick, - .test_main_f = test_peripheral_main - }, - { - .test_id = "central", - .test_descr = "Central L2CAP FRAGS", - .test_post_init_f = test_init, - .test_tick_f = test_tick, - .test_main_f = test_central_main - }, - BSTEST_END_MARKER -}; - -struct bst_test_list *test_main_l2cap_credits_install(struct bst_test_list *tests) -{ - return bst_add_tests(tests, test_def); -} - -extern struct bst_test_list *test_main_l2cap_credits_install(struct bst_test_list *tests); - -bst_test_install_t test_installers[] = { - test_main_l2cap_credits_install, - NULL -}; - -int main(void) -{ - bst_main(); - - return 0; -} diff --git a/tests/bsim/bluetooth/host/l2cap/frags/tests_scripts/_compile.sh b/tests/bsim/bluetooth/host/l2cap/frags/tests_scripts/_compile.sh deleted file mode 100755 index 80030a894f2..00000000000 --- a/tests/bsim/bluetooth/host/l2cap/frags/tests_scripts/_compile.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2023 Nordic Semiconductor ASA -# SPDX-License-Identifier: Apache-2.0 -set -eu -: "${ZEPHYR_BASE:?ZEPHYR_BASE must be defined}" - -INCR_BUILD=1 -source ${ZEPHYR_BASE}/tests/bsim/compile.source - -app="$(guess_test_relpath)" compile - -wait_for_background_jobs diff --git a/tests/bsim/bluetooth/host/l2cap/frags/tests_scripts/run.sh b/tests/bsim/bluetooth/host/l2cap/frags/tests_scripts/run.sh deleted file mode 100755 index e3a7b8e624d..00000000000 --- a/tests/bsim/bluetooth/host/l2cap/frags/tests_scripts/run.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env bash -# Copyright (c) 2024 Nordic Semiconductor -# SPDX-License-Identifier: Apache-2.0 - -source ${ZEPHYR_BASE}/tests/bsim/sh_common.source - -verbosity_level=2 -simulation_id=$(guess_test_long_name) -bsim_exe=./bs_${BOARD_TS}_$(guess_test_long_name)_prj_conf - -cd ${BSIM_OUT_PATH}/bin - -Execute "${bsim_exe}" -v=${verbosity_level} -s=${simulation_id} -d=0 -testid=central -rs=420 -Execute "${bsim_exe}" -v=${verbosity_level} -s=${simulation_id} -d=1 -testid=peripheral -rs=100 - -Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} -D=2 -sim_length=30e6 $@ - -wait_for_background_jobs diff --git a/tests/bsim/bluetooth/host/l2cap/general/src/main_l2cap_ecred.c b/tests/bsim/bluetooth/host/l2cap/general/src/main_l2cap_ecred.c index f28ce93c693..dbee4d4f3c3 100644 --- a/tests/bsim/bluetooth/host/l2cap/general/src/main_l2cap_ecred.c +++ b/tests/bsim/bluetooth/host/l2cap/general/src/main_l2cap_ecred.c @@ -449,7 +449,7 @@ static void test_peripheral_main(void) LOG_DBG("Peripheral Bluetooth initialized."); LOG_DBG("Connectable advertising..."); - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0); + err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), NULL, 0); if (err) { FAIL("Advertising failed to start (err %d)", err); return; diff --git a/tests/bsim/bluetooth/host/l2cap/send_on_connect/src/main_l2cap_send_on_connect.c b/tests/bsim/bluetooth/host/l2cap/send_on_connect/src/main_l2cap_send_on_connect.c index ac01dbcc38a..60ed49eb229 100644 --- a/tests/bsim/bluetooth/host/l2cap/send_on_connect/src/main_l2cap_send_on_connect.c +++ b/tests/bsim/bluetooth/host/l2cap/send_on_connect/src/main_l2cap_send_on_connect.c @@ -187,7 +187,7 @@ static void test_peripheral_main(void) register_l2cap_server(); - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0); + err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), NULL, 0); if (err != 0) { FAIL("Advertising failed to start (err %d)\n", err); return; diff --git a/tests/bsim/bluetooth/host/l2cap/split/tester/prj.conf b/tests/bsim/bluetooth/host/l2cap/split/tester/prj.conf index 82dfa9686ee..dc9a8373fb0 100644 --- a/tests/bsim/bluetooth/host/l2cap/split/tester/prj.conf +++ b/tests/bsim/bluetooth/host/l2cap/split/tester/prj.conf @@ -3,7 +3,6 @@ CONFIG_ASSERT=y CONFIG_BT=y CONFIG_BT_HCI_RAW=y -CONFIG_BT_HCI_RAW_RESERVE=1 CONFIG_BT_MAX_CONN=16 CONFIG_BT_BUF_CMD_TX_COUNT=10 diff --git a/tests/bsim/bluetooth/host/l2cap/stress/prj_nofrag.conf b/tests/bsim/bluetooth/host/l2cap/stress/prj_nofrag.conf new file mode 100644 index 00000000000..ea9cda13529 --- /dev/null +++ b/tests/bsim/bluetooth/host/l2cap/stress/prj_nofrag.conf @@ -0,0 +1,47 @@ +CONFIG_BT=y +CONFIG_BT_CENTRAL=y +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_DEVICE_NAME="L2CAP stress test" + +CONFIG_BT_EATT=n +CONFIG_BT_L2CAP_ECRED=n + +CONFIG_BT_SMP=y # Next config depends on it +CONFIG_BT_L2CAP_DYNAMIC_CHANNEL=y + +# Disable auto-initiated procedures so they don't +# mess with the test's execution. +CONFIG_BT_AUTO_PHY_UPDATE=n +CONFIG_BT_AUTO_DATA_LEN_UPDATE=n +CONFIG_BT_GAP_AUTO_UPDATE_CONN_PARAMS=n + +# L2CAP MPS +# 23+27+27=77 makes exactly three full packets +CONFIG_BT_L2CAP_TX_MTU=77 + +# Send L2CAP PDUs without any fragmentation. +CONFIG_BT_BUF_ACL_TX_SIZE=81 + +CONFIG_BT_BUF_ACL_TX_COUNT=4 + +# The minimum value for this is +# L2AP MPS + L2CAP header (4) +CONFIG_BT_BUF_ACL_RX_SIZE=81 + +CONFIG_BT_L2CAP_TX_BUF_COUNT=100 + +CONFIG_BT_CTLR_DATA_LENGTH_MAX=81 +CONFIG_BT_CTLR_RX_BUFFERS=10 + +CONFIG_BT_MAX_CONN=10 + +CONFIG_LOG=y +CONFIG_ASSERT=y +CONFIG_NET_BUF_POOL_USAGE=y + +# CONFIG_BT_L2CAP_LOG_LEVEL_DBG=y +# CONFIG_BT_CONN_LOG_LEVEL_DBG=y +CONFIG_LOG_THREAD_ID_PREFIX=y +CONFIG_THREAD_NAME=y + +CONFIG_ARCH_POSIX_TRAP_ON_FATAL=y diff --git a/tests/bsim/bluetooth/host/l2cap/stress/src/main.c b/tests/bsim/bluetooth/host/l2cap/stress/src/main.c index b20dafea3fa..7b229ad0127 100644 --- a/tests/bsim/bluetooth/host/l2cap/stress/src/main.c +++ b/tests/bsim/bluetooth/host/l2cap/stress/src/main.c @@ -20,7 +20,7 @@ CREATE_FLAG(flag_l2cap_connected); #define L2CAP_CHANS NUM_PERIPHERALS #define SDU_NUM 20 #define SDU_LEN 3000 -#define NUM_SEGMENTS 10 +#define NUM_SEGMENTS 100 #define RESCHEDULE_DELAY K_MSEC(100) static void sdu_destroy(struct net_buf *buf) @@ -309,15 +309,10 @@ static void disconnect_device(struct bt_conn *conn, void *data) WAIT_FOR_FLAG_UNSET(is_connected); } -#define BT_LE_ADV_CONN_NAME_OT BT_LE_ADV_PARAM(BT_LE_ADV_OPT_CONNECTABLE | \ - BT_LE_ADV_OPT_USE_NAME | \ - BT_LE_ADV_OPT_ONE_TIME, \ - BT_GAP_ADV_FAST_INT_MIN_2, \ - BT_GAP_ADV_FAST_INT_MAX_2, NULL) - -static const struct bt_data ad[] = { - BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), -}; +#define BT_LE_ADV_CONN_OT BT_LE_ADV_PARAM(BT_LE_ADV_OPT_CONNECTABLE | \ + BT_LE_ADV_OPT_ONE_TIME, \ + BT_GAP_ADV_FAST_INT_MIN_2, \ + BT_GAP_ADV_FAST_INT_MAX_2, NULL) static void test_peripheral_main(void) { @@ -337,7 +332,7 @@ static void test_peripheral_main(void) LOG_DBG("Peripheral Bluetooth initialized."); LOG_DBG("Connectable advertising..."); - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME_OT, ad, ARRAY_SIZE(ad), NULL, 0); + err = bt_le_adv_start(BT_LE_ADV_CONN_OT, NULL, 0, NULL, 0); if (err) { FAIL("Advertising failed to start (err %d)", err); return; @@ -479,7 +474,7 @@ static void test_central_main(void) } LOG_DBG("All peripherals disconnected."); - LOG_DBG("Max segment pool usage: %u bufs", max_seg_allocated); + LOG_INF("Max segment pool usage: %u bufs", max_seg_allocated); PASS("L2CAP STRESS Central passed\n"); } diff --git a/tests/bsim/bluetooth/host/l2cap/stress/tests_scripts/_compile.sh b/tests/bsim/bluetooth/host/l2cap/stress/tests_scripts/_compile.sh index a30326f1afc..b446204dce8 100755 --- a/tests/bsim/bluetooth/host/l2cap/stress/tests_scripts/_compile.sh +++ b/tests/bsim/bluetooth/host/l2cap/stress/tests_scripts/_compile.sh @@ -8,6 +8,7 @@ INCR_BUILD=1 source ${ZEPHYR_BASE}/tests/bsim/compile.source app="$(guess_test_relpath)" compile +app="$(guess_test_relpath)" conf_file=prj_nofrag.conf compile app="$(guess_test_relpath)" conf_file=prj_syswq.conf compile wait_for_background_jobs diff --git a/tests/bsim/bluetooth/host/l2cap/stress/tests_scripts/l2cap_nofrag.sh b/tests/bsim/bluetooth/host/l2cap/stress/tests_scripts/l2cap_nofrag.sh new file mode 100755 index 00000000000..4d4bb7f9152 --- /dev/null +++ b/tests/bsim/bluetooth/host/l2cap/stress/tests_scripts/l2cap_nofrag.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +# Copyright (c) 2022 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +# EATT test +simulation_id="l2cap_stress_nofrag" +verbosity_level=2 +EXECUTE_TIMEOUT=240 + +bsim_exe=./bs_${BOARD_TS}_tests_bsim_bluetooth_host_l2cap_stress_prj_nofrag_conf + +cd ${BSIM_OUT_PATH}/bin + +Execute "${bsim_exe}" -v=${verbosity_level} -s=${simulation_id} -d=0 -testid=central -rs=43 + +Execute "${bsim_exe}" -v=${verbosity_level} -s=${simulation_id} -d=1 -testid=peripheral -rs=42 +Execute "${bsim_exe}" -v=${verbosity_level} -s=${simulation_id} -d=2 -testid=peripheral -rs=10 +Execute "${bsim_exe}" -v=${verbosity_level} -s=${simulation_id} -d=3 -testid=peripheral -rs=23 +Execute "${bsim_exe}" -v=${verbosity_level} -s=${simulation_id} -d=4 -testid=peripheral -rs=7884 +Execute "${bsim_exe}" -v=${verbosity_level} -s=${simulation_id} -d=5 -testid=peripheral -rs=230 +Execute "${bsim_exe}" -v=${verbosity_level} -s=${simulation_id} -d=6 -testid=peripheral -rs=9 + +Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} -D=7 -sim_length=400e6 $@ + +wait_for_background_jobs diff --git a/tests/bsim/bluetooth/host/l2cap/userdata/src/main_l2cap_userdata.c b/tests/bsim/bluetooth/host/l2cap/userdata/src/main_l2cap_userdata.c index 46d1389dee9..df5f4c1bffd 100644 --- a/tests/bsim/bluetooth/host/l2cap/userdata/src/main_l2cap_userdata.c +++ b/tests/bsim/bluetooth/host/l2cap/userdata/src/main_l2cap_userdata.c @@ -151,7 +151,7 @@ static void test_peripheral_main(void) return; } - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0); + err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), NULL, 0); if (err != 0) { FAIL("Advertising failed to start (err %d)\n", err); return; diff --git a/tests/bsim/bluetooth/host/misc/conn_stress/peripheral/src/main.c b/tests/bsim/bluetooth/host/misc/conn_stress/peripheral/src/main.c index d0e0b9fb6a3..03d706b6214 100644 --- a/tests/bsim/bluetooth/host/misc/conn_stress/peripheral/src/main.c +++ b/tests/bsim/bluetooth/host/misc/conn_stress/peripheral/src/main.c @@ -400,7 +400,7 @@ void test_peripheral_main(void) sprintf(name, "per-%d", get_device_nbr()); bt_set_name(name); - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, NULL, 0, NULL, 0); + err = bt_le_adv_start(BT_LE_ADV_CONN, NULL, 0, NULL, 0); if (err) { LOG_ERR("Advertising failed to start (err %d)", err); __ASSERT_NO_MSG(err); diff --git a/tests/bsim/bluetooth/host/misc/disable/src/gatt_server_test.c b/tests/bsim/bluetooth/host/misc/disable/src/gatt_server_test.c index 56c8a26a7ce..1dc6ec5f96e 100644 --- a/tests/bsim/bluetooth/host/misc/disable/src/gatt_server_test.c +++ b/tests/bsim/bluetooth/host/misc/disable/src/gatt_server_test.c @@ -154,7 +154,7 @@ static void test_main(void) printk("Bluetooth initialized\n"); - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0); + err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), NULL, 0); if (err != 0) { FAIL("Advertising failed to start (err %d)\n", err); return; diff --git a/tests/bsim/bluetooth/host/misc/disconnect/tester/prj.conf b/tests/bsim/bluetooth/host/misc/disconnect/tester/prj.conf index 461c7dd5029..5217040a117 100644 --- a/tests/bsim/bluetooth/host/misc/disconnect/tester/prj.conf +++ b/tests/bsim/bluetooth/host/misc/disconnect/tester/prj.conf @@ -3,7 +3,6 @@ CONFIG_ASSERT=y CONFIG_BT=y CONFIG_BT_HCI_RAW=y -CONFIG_BT_HCI_RAW_RESERVE=1 CONFIG_BT_MAX_CONN=1 CONFIG_BT_BUF_CMD_TX_COUNT=10 diff --git a/tests/bsim/bluetooth/host/misc/sample_test/src/peer.c b/tests/bsim/bluetooth/host/misc/sample_test/src/peer.c index 475043c0d3a..d8a142df52c 100644 --- a/tests/bsim/bluetooth/host/misc/sample_test/src/peer.c +++ b/tests/bsim/bluetooth/host/misc/sample_test/src/peer.c @@ -172,8 +172,7 @@ void entrypoint_peer(void) LOG_DBG("Bluetooth initialized"); - err = bt_testlib_adv_conn(&conn, BT_ID_DEFAULT, - (BT_LE_ADV_OPT_USE_NAME | BT_LE_ADV_OPT_FORCE_NAME_IN_AD)); + err = bt_testlib_adv_conn(&conn, BT_ID_DEFAULT, bt_get_name()); TEST_ASSERT(!err, "Failed to start connectable advertising (err %d)", err); LOG_DBG("Discover test characteristic"); diff --git a/tests/bsim/bluetooth/host/misc/unregister_conn_cb/src/main.c b/tests/bsim/bluetooth/host/misc/unregister_conn_cb/src/main.c index f11b179ee34..1461ab69a9c 100644 --- a/tests/bsim/bluetooth/host/misc/unregister_conn_cb/src/main.c +++ b/tests/bsim/bluetooth/host/misc/unregister_conn_cb/src/main.c @@ -127,7 +127,7 @@ static void test_peripheral_main(void) bt_conn_cb_register(&conn_callbacks); - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0); + err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), NULL, 0); if (err != 0) { FAIL("Advertising failed to start (err %d)\n", err); return; diff --git a/tests/bsim/bluetooth/host/privacy/central/src/tester.c b/tests/bsim/bluetooth/host/privacy/central/src/tester.c index 1c29b53e0c4..1bbb8fc8de6 100644 --- a/tests/bsim/bluetooth/host/privacy/central/src/tester.c +++ b/tests/bsim/bluetooth/host/privacy/central/src/tester.c @@ -88,7 +88,7 @@ void start_advertising(void) params.sid = 0; params.secondary_max_skip = 0; params.options = BT_LE_ADV_OPT_EXT_ADV | BT_LE_ADV_OPT_SCANNABLE | - BT_LE_ADV_OPT_NOTIFY_SCAN_REQ | BT_LE_ADV_OPT_USE_NAME; + BT_LE_ADV_OPT_NOTIFY_SCAN_REQ; params.interval_min = BT_GAP_ADV_FAST_INT_MIN_1; params.interval_max = BT_GAP_ADV_FAST_INT_MAX_1; params.peer = NULL; diff --git a/tests/bsim/bluetooth/ll/advx/src/main.c b/tests/bsim/bluetooth/ll/advx/src/main.c index 449670cfe03..7954896c7f0 100644 --- a/tests/bsim/bluetooth/ll/advx/src/main.c +++ b/tests/bsim/bluetooth/ll/advx/src/main.c @@ -167,6 +167,7 @@ static void test_advx_main(void) struct bt_le_ext_adv_start_param ext_adv_param; struct bt_le_ext_adv *adv; uint8_t num_sent_expected; + struct bt_data sd[1]; uint16_t evt_prop; uint8_t adv_type; uint16_t handle; @@ -184,7 +185,7 @@ static void test_advx_main(void) printk("success.\n"); printk("Connectable advertising..."); - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0); + err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), NULL, 0); if (err) { printk("Advertising failed to start (err %d)\n", err); return; @@ -299,13 +300,24 @@ static void test_advx_main(void) printk("success.\n"); printk("Create scannable extended advertising set..."); - err = bt_le_ext_adv_create(BT_LE_EXT_ADV_SCAN_NAME, &adv_callbacks, + err = bt_le_ext_adv_create(BT_LE_EXT_ADV_SCAN, &adv_callbacks, &adv); if (err) { goto exit; } printk("success.\n"); + /* Scannable advertiser need to have scan response data */ + printk("Set scan response data..."); + sd[0].type = BT_DATA_NAME_COMPLETE; + sd[0].data_len = sizeof(CONFIG_BT_DEVICE_NAME) - 1; + sd[0].data = CONFIG_BT_DEVICE_NAME; + err = bt_le_ext_adv_set_data(adv, NULL, 0, sd, 1); + if (err) { + goto exit; + } + printk("success.\n"); + printk("Start scannable advertising..."); ext_adv_param.timeout = 0; ext_adv_param.num_events = 0; @@ -334,7 +346,7 @@ static void test_advx_main(void) printk("Create connectable extended advertising set..."); is_connected = false; is_disconnected = false; - err = bt_le_ext_adv_create(BT_LE_EXT_ADV_CONN_NAME, &adv_callbacks, &adv); + err = bt_le_ext_adv_create(BT_LE_EXT_ADV_CONN, &adv_callbacks, &adv); if (err) { goto exit; } @@ -389,7 +401,7 @@ static void test_advx_main(void) k_sleep(K_MSEC(1000)); printk("Create connectable advertising set..."); - err = bt_le_ext_adv_create(BT_LE_ADV_CONN_NAME, &adv_callbacks, &adv); + err = bt_le_ext_adv_create(BT_LE_ADV_CONN, &adv_callbacks, &adv); if (err) { goto exit; } diff --git a/tests/bsim/bluetooth/ll/bis/Kconfig b/tests/bsim/bluetooth/ll/bis/Kconfig new file mode 100644 index 00000000000..3e7fd07e430 --- /dev/null +++ b/tests/bsim/bluetooth/ll/bis/Kconfig @@ -0,0 +1,11 @@ +# Copyright 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config TEST_LL_INTERFACE + bool "Test Broadcast ISO using internal LL interface" + help + Test Broadcast ISO using internal LL interface. + +menu "Zephyr Kernel" +source "Kconfig.zephyr" +endmenu diff --git a/tests/bsim/bluetooth/ll/bis/Kconfig.sysbuild b/tests/bsim/bluetooth/ll/bis/Kconfig.sysbuild index f534fabcd22..6cf765d44e2 100644 --- a/tests/bsim/bluetooth/ll/bis/Kconfig.sysbuild +++ b/tests/bsim/bluetooth/ll/bis/Kconfig.sysbuild @@ -11,4 +11,4 @@ config NATIVE_SIMULATOR_PRIMARY_MCU_INDEX int # Let's pass the test arguments to the application MCU test # otherwise by default they would have gone to the net core. - default 0 if $(BOARD) = "nrf5340bsim" + default 0 if $(BOARD_TARGET_STRING) = "NRF5340BSIM_NRF5340_CPUAPP" diff --git a/tests/bsim/bluetooth/ll/bis/overlay-ll_interface.conf b/tests/bsim/bluetooth/ll/bis/overlay-ll_interface.conf new file mode 100644 index 00000000000..c3e37d09387 --- /dev/null +++ b/tests/bsim/bluetooth/ll/bis/overlay-ll_interface.conf @@ -0,0 +1 @@ +CONFIG_TEST_LL_INTERFACE=y diff --git a/tests/bsim/bluetooth/ll/bis/prj.conf b/tests/bsim/bluetooth/ll/bis/prj.conf index 02e2f3168db..afa1f595861 100644 --- a/tests/bsim/bluetooth/ll/bis/prj.conf +++ b/tests/bsim/bluetooth/ll/bis/prj.conf @@ -8,7 +8,7 @@ CONFIG_BT_PER_ADV_SYNC=y CONFIG_BT_ISO_BROADCASTER=y CONFIG_BT_ISO_SYNC_RECEIVER=y -CONFIG_BT_ISO_TX_MTU=251 +CONFIG_BT_ISO_TX_MTU=247 CONFIG_BT_ISO_RX_MTU=251 CONFIG_BT_CTLR_ADV_EXT=y @@ -16,8 +16,8 @@ CONFIG_BT_CTLR_ADV_ISO=y CONFIG_BT_CTLR_SYNC_ISO=y CONFIG_BT_CTLR_ISO_TX_BUFFERS=2 -CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=251 -CONFIG_BT_CTLR_ADV_ISO_PDU_LEN_MAX=251 +CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=255 +CONFIG_BT_CTLR_ADV_ISO_PDU_LEN_MAX=247 CONFIG_BT_CTLR_SYNC_ISO_PDU_LEN_MAX=251 CONFIG_BT_CTLR_TEST=y diff --git a/tests/bsim/bluetooth/ll/bis/prj_vs_dp.conf b/tests/bsim/bluetooth/ll/bis/prj_vs_dp.conf index 9cf785bc925..2f0f9ccc86d 100644 --- a/tests/bsim/bluetooth/ll/bis/prj_vs_dp.conf +++ b/tests/bsim/bluetooth/ll/bis/prj_vs_dp.conf @@ -15,7 +15,7 @@ CONFIG_BT_CTLR_ADV_EXT=y CONFIG_BT_CTLR_ADV_ISO=y CONFIG_BT_CTLR_SYNC_ISO=y -CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=251 +CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=255 CONFIG_BT_CTLR_ADV_ISO_PDU_LEN_MAX=251 CONFIG_BT_CTLR_SYNC_ISO_PDU_LEN_MAX=251 diff --git a/tests/bsim/bluetooth/ll/bis/src/main.c b/tests/bsim/bluetooth/ll/bis/src/main.c index 480d375997e..77bd1d5421d 100644 --- a/tests/bsim/bluetooth/ll/bis/src/main.c +++ b/tests/bsim/bluetooth/ll/bis/src/main.c @@ -60,6 +60,8 @@ static uint8_t chan_map[] = { 0x1F, 0XF1, 0x1F, 0xF1, 0x1F }; static bool volatile is_iso_connected; static uint8_t volatile is_iso_disconnected; static bool volatile deleting_pa_sync; + +#if !defined(CONFIG_TEST_LL_INTERFACE) static void iso_connected(struct bt_iso_chan *chan); static void iso_disconnected(struct bt_iso_chan *chan, uint8_t reason); static void iso_recv(struct bt_iso_chan *chan, @@ -122,10 +124,11 @@ static isoal_status_t test_sink_sdu_emit(const struct isoal_sink *si } static isoal_status_t test_sink_sdu_write(void *dbuf, + const size_t sdu_written, const uint8_t *pdu_payload, const size_t consume_len) { - memcpy(dbuf, pdu_payload, consume_len); + memcpy((uint8_t *)dbuf + sdu_written, pdu_payload, consume_len); return ISOAL_STATUS_OK; } @@ -193,13 +196,14 @@ static void iso_send(struct k_work *work) k_work_schedule(&iso_send_work, K_USEC(9970)); } +#endif /* !CONFIG_TEST_LL_INTERFACE */ static void setup_ext_adv(struct bt_le_ext_adv **adv) { int err; printk("Create 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_NCONN, NULL, adv); if (err) { FAIL("Failed to create advertising set (err %d)\n", err); return; @@ -261,7 +265,7 @@ static void teardown_ext_adv(struct bt_le_ext_adv *adv) printk("success.\n"); } -#if TEST_LL_INTERFACE +#if defined(CONFIG_TEST_LL_INTERFACE) static void create_ll_big(uint8_t big_handle, struct bt_le_ext_adv *adv) { uint16_t max_sdu = CONFIG_BT_CTLR_ADV_ISO_PDU_LEN_MAX; @@ -303,8 +307,8 @@ static void terminate_ll_big(uint8_t big_handle) } printk("success.\n"); } -#endif /* TEST_LL_INTERFACE */ +#else /* !CONFIG_TEST_LL_INTERFACE */ static void create_big(struct bt_le_ext_adv *adv, struct bt_iso_big **big) { struct bt_iso_big_create_param big_create_param = { 0 }; @@ -337,6 +341,26 @@ static void create_big(struct bt_le_ext_adv *adv, struct bt_iso_big **big) printk("ISO connected\n"); } +static void terminate_big(struct bt_iso_big *big) +{ + int err; + + printk("Terminating BIG...\n"); + err = bt_iso_big_terminate(big); + if (err) { + FAIL("Could not terminate BIG: %d\n", err); + return; + } + printk("success.\n"); + + printk("Wait for ISO disconnected callback..."); + while (is_iso_disconnected == 0U) { + k_sleep(K_MSEC(100)); + } + printk("ISO disconnected\n"); +} +#endif /* !CONFIG_TEST_LL_INTERFACE */ + #if defined(CONFIG_BT_ISO_TEST_PARAMS) static void create_advanced_big(struct bt_le_ext_adv *adv, struct bt_iso_big **big) { @@ -378,29 +402,9 @@ static void create_advanced_big(struct bt_le_ext_adv *adv, struct bt_iso_big **b } #endif /* CONFIG_BT_ISO_TEST_PARAMS */ -static void terminate_big(struct bt_iso_big *big) -{ - int err; - - printk("Terminating BIG...\n"); - err = bt_iso_big_terminate(big); - if (err) { - FAIL("Could not terminate BIG: %d\n", err); - return; - } - printk("success.\n"); - - printk("Wait for ISO disconnected callback..."); - while (is_iso_disconnected == 0U) { - k_sleep(K_MSEC(100)); - } - printk("ISO disconnected\n"); -} - static void test_iso_main(void) { struct bt_le_ext_adv *adv; - struct bt_iso_big *big; int err; printk("\n*ISO broadcast test*\n"); @@ -415,16 +419,19 @@ static void test_iso_main(void) setup_ext_adv(&adv); -#if TEST_LL_INTERFACE +#if defined(CONFIG_TEST_LL_INTERFACE) uint8_t big_handle = 0; create_ll_big(big_handle, adv); -#endif + +#else /* !CONFIG_TEST_LL_INTERFACE */ + struct bt_iso_big *big; create_big(adv, &big); k_work_init_delayable(&iso_send_work, iso_send); k_work_schedule(&iso_send_work, K_NO_WAIT); +#endif /* !CONFIG_TEST_LL_INTERFACE */ k_sleep(K_MSEC(5000)); @@ -459,11 +466,11 @@ static void test_iso_main(void) k_sleep(K_MSEC(5000)); - k_work_cancel_delayable(&iso_send_work); - -#if TEST_LL_INTERFACE +#if defined(CONFIG_TEST_LL_INTERFACE) terminate_ll_big(big_handle); -#endif + +#else /* !CONFIG_TEST_LL_INTERFACE */ + k_work_cancel_delayable(&iso_send_work); terminate_big(big); big = NULL; @@ -477,6 +484,7 @@ static void test_iso_main(void) terminate_big(big); big = NULL; #endif /* CONFIG_BT_ISO_TEST_PARAMS */ +#endif /* !CONFIG_TEST_LL_INTERFACE */ k_sleep(K_MSEC(10000)); @@ -499,6 +507,7 @@ static const char *phy2str(uint8_t phy) } } +#if !defined(CONFIG_TEST_LL_INTERFACE) /** Print data as d_0 d_1 d_2 ... d_(n-2) d_(n-1) d_(n) to show the 3 first and 3 last octets * * Examples: @@ -585,6 +594,7 @@ static void iso_disconnected(struct bt_iso_chan *chan, uint8_t reason) is_iso_disconnected = reason; } +#endif /* !CONFIG_TEST_LL_INTERFACE */ static bool volatile is_sync; @@ -819,18 +829,17 @@ static void test_iso_recv_main(void) } printk("success.\n"); -#if TEST_LL_INTERFACE - printk("Creating BIG Sync..."); +#if defined(CONFIG_TEST_LL_INTERFACE) uint8_t bcode[BT_ISO_BROADCAST_CODE_SIZE] = { 0 }; uint16_t sync_timeout = 10; + uint8_t bis[1] = { 0x01, }; uint8_t big_handle = 0; - uint8_t bis_handle = 0; uint8_t encryption = 0; - uint8_t bis_count = 1; /* TODO: Add support for multiple BIS per BIG */ uint8_t mse = 0; + printk("Creating BIG Sync..."); err = ll_big_sync_create(big_handle, sync->handle, encryption, bcode, - mse, sync_timeout, bis_count, &bis_handle); + mse, sync_timeout, ARRAY_SIZE(bis), bis); if (err) { FAIL("Could not create BIG sync: %d\n", err); return; @@ -839,18 +848,8 @@ static void test_iso_recv_main(void) k_sleep(K_MSEC(5000)); - printk("Deleting Periodic Advertising Sync..."); - deleting_pa_sync = true; - err = bt_le_per_adv_sync_delete(sync); - if (err) { - FAIL("Failed to delete periodic advertising sync (err %d)\n", - err); - return; - } - printk("success.\n"); - printk("Terminating BIG Sync..."); - struct node_rx_hdr *node_rx = NULL; + struct node_rx_pdu *node_rx = NULL; err = ll_big_sync_terminate(big_handle, (void **)&node_rx); if (err) { FAIL("Could not terminate BIG sync: %d\n", err); @@ -866,7 +865,7 @@ static void test_iso_recv_main(void) printk("Creating BIG Sync after terminate..."); err = ll_big_sync_create(big_handle, sync->handle, encryption, bcode, - mse, sync_timeout, bis_count, &bis_handle); + mse, sync_timeout, ARRAY_SIZE(bis), bis); if (err) { FAIL("Could not create BIG sync: %d\n", err); return; @@ -883,10 +882,21 @@ static void test_iso_recv_main(void) printk("success.\n"); if (node_rx) { - node_rx->next = NULL; + node_rx->hdr.next = NULL; ll_rx_mem_release((void **)&node_rx); } -#else + + printk("Deleting Periodic Advertising Sync..."); + deleting_pa_sync = true; + err = bt_le_per_adv_sync_delete(sync); + if (err) { + FAIL("Failed to delete periodic advertising sync (err %d)\n", + err); + return; + } + printk("success.\n"); + +#else /* !CONFIG_TEST_LL_INTERFACE */ struct bt_iso_big_sync_param big_param = { 0, }; struct bt_iso_big *big; @@ -998,7 +1008,6 @@ static void test_iso_recv_main(void) return; } printk("success.\n"); -#endif for (int chan = 0; chan < CONFIG_BT_ISO_MAX_CHAN; chan++) { if (expected_seq_num[chan] < SEQ_NUM_MAX) { @@ -1007,6 +1016,7 @@ static void test_iso_recv_main(void) return; } } +#endif /* !CONFIG_TEST_LL_INTERFACE */ PASS("ISO recv test Passed\n"); diff --git a/tests/bsim/bluetooth/ll/bis/tests_scripts/broadcast_iso_ll_interface.sh b/tests/bsim/bluetooth/ll/bis/tests_scripts/broadcast_iso_ll_interface.sh new file mode 100755 index 00000000000..da4b6726c70 --- /dev/null +++ b/tests/bsim/bluetooth/ll/bis/tests_scripts/broadcast_iso_ll_interface.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +# Copyright 2020 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +# Basic ISO broadcast test: a broadcaster transmits a BIS and a receiver listens +# to the BIS. +simulation_id="broadcast_iso_ll_interface" +verbosity_level=2 + +cd ${BSIM_OUT_PATH}/bin + +Execute ./bs_${BOARD_TS}_tests_bsim_bluetooth_ll_bis_prj_conf_overlay-ll_interface_conf \ + -v=${verbosity_level} -s=${simulation_id} -d=0 -testid=receive + +Execute ./bs_${BOARD_TS}_tests_bsim_bluetooth_ll_bis_prj_conf_overlay-ll_interface_conf \ + -v=${verbosity_level} -s=${simulation_id} -d=1 -testid=broadcast + +Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \ + -D=2 -sim_length=30e6 $@ + +wait_for_background_jobs diff --git a/tests/bsim/bluetooth/ll/cis/Kconfig.sysbuild b/tests/bsim/bluetooth/ll/cis/Kconfig.sysbuild index f534fabcd22..6cf765d44e2 100644 --- a/tests/bsim/bluetooth/ll/cis/Kconfig.sysbuild +++ b/tests/bsim/bluetooth/ll/cis/Kconfig.sysbuild @@ -11,4 +11,4 @@ config NATIVE_SIMULATOR_PRIMARY_MCU_INDEX int # Let's pass the test arguments to the application MCU test # otherwise by default they would have gone to the net core. - default 0 if $(BOARD) = "nrf5340bsim" + default 0 if $(BOARD_TARGET_STRING) = "NRF5340BSIM_NRF5340_CPUAPP" diff --git a/tests/bsim/bluetooth/ll/cis/prj.conf b/tests/bsim/bluetooth/ll/cis/prj.conf index a4d3c3e8c5f..c124cbd223e 100644 --- a/tests/bsim/bluetooth/ll/cis/prj.conf +++ b/tests/bsim/bluetooth/ll/cis/prj.conf @@ -28,7 +28,7 @@ CONFIG_LOG=y CONFIG_BT_LL_SW_SPLIT=y CONFIG_BT_CTLR_CENTRAL_ISO=y CONFIG_BT_CTLR_PERIPHERAL_ISO=y -CONFIG_BT_CTLR_CONN_ISO_SDU_LEN_MAX=251 +CONFIG_BT_CTLR_CONN_ISO_SDU_LEN_MAX=247 CONFIG_BT_CTLR_CONN_ISO_PDU_LEN_MAX=251 CONFIG_BT_CTLR_CONN_ISO_STREAMS=9 CONFIG_BT_CTLR_CONN_ISO_STREAMS_PER_GROUP=9 @@ -36,7 +36,7 @@ CONFIG_BT_CTLR_ISOAL_SOURCES=9 CONFIG_BT_CTLR_ISOAL_SINKS=9 CONFIG_BT_CTLR_ISO_TX_BUFFERS=18 -CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=251 +CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=255 CONFIG_BT_CTLR_ISO_RX_BUFFERS=1 CONFIG_BT_CTLR_PHY_CODED=n diff --git a/tests/bsim/bluetooth/ll/cis/src/main.c b/tests/bsim/bluetooth/ll/cis/src/main.c index e54b2e5224c..c3b369939e1 100644 --- a/tests/bsim/bluetooth/ll/cis/src/main.c +++ b/tests/bsim/bluetooth/ll/cis/src/main.c @@ -76,16 +76,14 @@ static bt_addr_le_t peer_addr; #if defined(CONFIG_TEST_USE_LEGACY_ADVERTISING) #define BT_LE_ADV_CONN_CUSTOM BT_LE_ADV_PARAM(BT_LE_ADV_OPT_CONNECTABLE | \ - BT_LE_ADV_OPT_ONE_TIME | \ - BT_LE_ADV_OPT_USE_NAME, \ + BT_LE_ADV_OPT_ONE_TIME, \ ADV_INTERVAL_MIN, \ ADV_INTERVAL_MAX, \ NULL) #else /* !CONFIG_TEST_USE_LEGACY_ADVERTISING */ #define BT_LE_ADV_CONN_CUSTOM BT_LE_ADV_PARAM(BT_LE_ADV_OPT_CONNECTABLE | \ BT_LE_ADV_OPT_EXT_ADV | \ - BT_LE_ADV_OPT_ONE_TIME | \ - BT_LE_ADV_OPT_USE_NAME, \ + BT_LE_ADV_OPT_ONE_TIME, \ ADV_INTERVAL_MIN, \ ADV_INTERVAL_MAX, \ NULL) diff --git a/tests/bsim/bluetooth/ll/cis/sysbuild/hci_ipc/nrf5340_cpunet_iso_acl_group-bt_ll_sw_split.conf b/tests/bsim/bluetooth/ll/cis/sysbuild/hci_ipc/nrf5340_cpunet_iso_acl_group-bt_ll_sw_split.conf index 4a53b153a5c..5119ac0d3ed 100644 --- a/tests/bsim/bluetooth/ll/cis/sysbuild/hci_ipc/nrf5340_cpunet_iso_acl_group-bt_ll_sw_split.conf +++ b/tests/bsim/bluetooth/ll/cis/sysbuild/hci_ipc/nrf5340_cpunet_iso_acl_group-bt_ll_sw_split.conf @@ -11,7 +11,6 @@ CONFIG_CBPRINTF_REDUCED_INTEGRAL=y CONFIG_BT=y CONFIG_BT_HCI_RAW=y -CONFIG_BT_HCI_RAW_RESERVE=1 CONFIG_BT_MAX_CONN=4 # Workaround: Unable to allocate command buffer when using K_NO_WAIT since @@ -85,7 +84,7 @@ CONFIG_BT_CTLR_LLCP_LOCAL_PROC_CTX_BUF_NUM=9 CONFIG_BT_CTLR_ADV_EXT=y CONFIG_BT_CTLR_ADV_PERIODIC=y CONFIG_BT_CTLR_ADV_ISO=y -CONFIG_BT_CTLR_ADV_ISO_PDU_LEN_MAX=251 +CONFIG_BT_CTLR_ADV_ISO_PDU_LEN_MAX=247 CONFIG_BT_CTLR_ADV_ISO_STREAM_MAX=2 # ISO Receive Controller @@ -98,14 +97,14 @@ CONFIG_BT_CTLR_SYNC_ISO_STREAM_MAX=2 # ISO Connection Oriented CONFIG_BT_CTLR_CENTRAL_ISO=y CONFIG_BT_CTLR_PERIPHERAL_ISO=y -CONFIG_BT_CTLR_CONN_ISO_SDU_LEN_MAX=251 +CONFIG_BT_CTLR_CONN_ISO_SDU_LEN_MAX=247 CONFIG_BT_CTLR_CONN_ISO_PDU_LEN_MAX=251 CONFIG_BT_CTLR_CONN_ISO_STREAMS=4 CONFIG_BT_CTLR_CONN_ISO_STREAMS_PER_GROUP=4 # ISO Transmissions CONFIG_BT_CTLR_ISO_TX_BUFFERS=18 -CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=251 +CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=255 CONFIG_BT_CTLR_ISOAL_SOURCES=4 # ISO Receptions diff --git a/tests/bsim/bluetooth/ll/compile.sh b/tests/bsim/bluetooth/ll/compile.sh index 487e34da4ab..c27c55a0047 100755 --- a/tests/bsim/bluetooth/ll/compile.sh +++ b/tests/bsim/bluetooth/ll/compile.sh @@ -22,8 +22,8 @@ app=tests/bsim/bluetooth/ll/conn conf_file=prj_split_low_lat.conf compile app=tests/bsim/bluetooth/ll/conn conf_file=prj_split_single_timer.conf compile app=tests/bsim/bluetooth/ll/bis compile -app=tests/bsim/bluetooth/ll/bis \ - conf_overlay=overlay-ticker_expire_info.conf compile +app=tests/bsim/bluetooth/ll/bis conf_overlay=overlay-ll_interface.conf compile +app=tests/bsim/bluetooth/ll/bis conf_overlay=overlay-ticker_expire_info.conf compile app=tests/bsim/bluetooth/ll/bis conf_file=prj_vs_dp.conf compile app=tests/bsim/bluetooth/ll/edtt/hci_test_app \ diff --git a/tests/bsim/bluetooth/ll/conn/Kconfig.sysbuild b/tests/bsim/bluetooth/ll/conn/Kconfig.sysbuild index f534fabcd22..6cf765d44e2 100644 --- a/tests/bsim/bluetooth/ll/conn/Kconfig.sysbuild +++ b/tests/bsim/bluetooth/ll/conn/Kconfig.sysbuild @@ -11,4 +11,4 @@ config NATIVE_SIMULATOR_PRIMARY_MCU_INDEX int # Let's pass the test arguments to the application MCU test # otherwise by default they would have gone to the net core. - default 0 if $(BOARD) = "nrf5340bsim" + default 0 if $(BOARD_TARGET_STRING) = "NRF5340BSIM_NRF5340_CPUAPP" diff --git a/tests/bsim/bluetooth/ll/conn/src/test_connect2.c b/tests/bsim/bluetooth/ll/conn/src/test_connect2.c index a0470af51a6..12d37385e47 100644 --- a/tests/bsim/bluetooth/ll/conn/src/test_connect2.c +++ b/tests/bsim/bluetooth/ll/conn/src/test_connect2.c @@ -133,7 +133,7 @@ static void bt_ready(void) printk("Peripheral Bluetooth initialized\n"); - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0); + err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), NULL, 0); if (err) { FAIL("Advertising failed to start (err %d)\n", err); return; diff --git a/tests/bsim/bluetooth/ll/multiple_id/prj.conf b/tests/bsim/bluetooth/ll/multiple_id/prj.conf index 0fb600d717c..173fc296c7c 100644 --- a/tests/bsim/bluetooth/ll/multiple_id/prj.conf +++ b/tests/bsim/bluetooth/ll/multiple_id/prj.conf @@ -34,7 +34,13 @@ CONFIG_BT_CTLR_DATA_LENGTH_MAX=251 # Each PHY update can pause connections for 6 interval hence to let other # parallel connection establishment to succeed increase Rx buffer count. -CONFIG_BT_CTLR_RX_BUFFERS=6 +# A minimum of 1 Rx buffer is required to receive data PDU, during control +# procedures Rx buffer could be held, preventing new connections to be +# established, a value of 3 is tuned based on this test case execution for 2 +# iterations. If there is buffer leak, simulated by using value of 2 here, the +# test is failing. +# If there is buffer leak, this test now should catch it. +CONFIG_BT_CTLR_RX_BUFFERS=3 # Provide enough spacing between connections so that multiple peripheral roles # when connected to a single peer device (peripheral_identity sample) have diff --git a/tests/bsim/bluetooth/ll/multiple_id/src/main.c b/tests/bsim/bluetooth/ll/multiple_id/src/main.c index 717bc637b1c..e9aff70db86 100644 --- a/tests/bsim/bluetooth/ll/multiple_id/src/main.c +++ b/tests/bsim/bluetooth/ll/multiple_id/src/main.c @@ -18,7 +18,12 @@ #include "time_machine.h" #include "bstests.h" -#define ITERATIONS 10 +/* The test case is performing 250 simultaneous connections and managing + * parallel control procedures utilizing the available/configured minimum + * buffer counts. Hence, two iterations of connect-disconnect should be + * sufficient to catch any regressions/buffer leaks. + */ +#define ITERATIONS 2 int init_central(uint8_t iterations); int init_peripheral(uint8_t iterations); @@ -81,7 +86,7 @@ static void test_peripheral_main(void) static void test_multiple_init(void) { - bst_ticker_set_next_tick_absolute(4500e6); + bst_ticker_set_next_tick_absolute(1500e6); bst_result = In_progress; } diff --git a/tests/bsim/bluetooth/ll/multiple_id/tests_scripts/multiple.sh b/tests/bsim/bluetooth/ll/multiple_id/tests_scripts/multiple.sh index 2d9eaece5ef..de272fdd0fe 100755 --- a/tests/bsim/bluetooth/ll/multiple_id/tests_scripts/multiple.sh +++ b/tests/bsim/bluetooth/ll/multiple_id/tests_scripts/multiple.sh @@ -7,7 +7,7 @@ source ${ZEPHYR_BASE}/tests/bsim/sh_common.source # Multiple connection between two devices with multiple peripheral identity simulation_id="multiple" verbosity_level=2 -EXECUTE_TIMEOUT=2200 +EXECUTE_TIMEOUT=1600 cd ${BSIM_OUT_PATH}/bin @@ -18,6 +18,6 @@ Execute ./bs_${BOARD_TS}_tests_bsim_bluetooth_ll_multiple_id_prj_conf\ -v=${verbosity_level} -s=${simulation_id} -d=1 -testid=peripheral Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \ - -D=2 -sim_length=4500e6 $@ -argschannel -at=40 + -D=2 -sim_length=1800e6 $@ -argschannel -at=40 wait_for_background_jobs diff --git a/tests/bsim/bluetooth/mesh/src/dfu_blob_common.c b/tests/bsim/bluetooth/mesh/src/dfu_blob_common.c index c519eefd6f7..2603192e98a 100644 --- a/tests/bsim/bluetooth/mesh/src/dfu_blob_common.c +++ b/tests/bsim/bluetooth/mesh/src/dfu_blob_common.c @@ -52,7 +52,7 @@ void common_sar_conf(uint16_t addr) */ struct bt_mesh_sar_tx tx_set = { .seg_int_step = 1, - .unicast_retrans_count = 3, + .unicast_retrans_count = 0, .unicast_retrans_without_prog_count = 2, .unicast_retrans_int_step = 7, .unicast_retrans_int_inc = 1, diff --git a/tests/bsim/bluetooth/mesh/src/mesh_test.c b/tests/bsim/bluetooth/mesh/src/mesh_test.c index a3a562842d2..6865e5202ba 100644 --- a/tests/bsim/bluetooth/mesh/src/mesh_test.c +++ b/tests/bsim/bluetooth/mesh/src/mesh_test.c @@ -10,6 +10,8 @@ #include #define LOG_MODULE_NAME mesh_test +#define COMPANY_ID_LF 0x05F1 +#define COMPANY_ID_NORDIC_SEMI 0x05F9 #include LOG_MODULE_REGISTER(LOG_MODULE_NAME); @@ -162,6 +164,15 @@ static struct bt_mesh_health_srv health_srv; static struct bt_mesh_model_pub health_pub = { .msg = NET_BUF_SIMPLE(BT_MESH_TX_SDU_MAX), }; +static const uint8_t health_tests[] = { + BT_MESH_HEALTH_TEST_INFO(COMPANY_ID_LF, 6, 0x01, 0x02, 0x03, 0x04, 0x34, 0x15), + BT_MESH_HEALTH_TEST_INFO(COMPANY_ID_NORDIC_SEMI, 3, 0x01, 0x02, 0x03), +}; + +const struct bt_mesh_models_metadata_entry health_srv_meta[] = { + BT_MESH_HEALTH_TEST_INFO_METADATA(health_tests), + BT_MESH_MODELS_METADATA_END, +}; #if defined(CONFIG_BT_MESH_SAR_CFG) static struct bt_mesh_sar_cfg_cli sar_cfg_cli; @@ -179,7 +190,7 @@ static const struct bt_mesh_model models[] = { BT_MESH_MODEL_CFG_SRV, BT_MESH_MODEL_CFG_CLI(&cfg_cli), BT_MESH_MODEL_CB(TEST_MOD_ID, model_op, &pub, NULL, &test_model_cb), - BT_MESH_MODEL_HEALTH_SRV(&health_srv, &health_pub), + BT_MESH_MODEL_HEALTH_SRV(&health_srv, &health_pub, health_srv_meta), #if defined(CONFIG_BT_MESH_SAR_CFG) BT_MESH_MODEL_SAR_CFG_SRV, BT_MESH_MODEL_SAR_CFG_CLI(&sar_cfg_cli), diff --git a/tests/bsim/bluetooth/mesh/src/test_blob.c b/tests/bsim/bluetooth/mesh/src/test_blob.c index 36d816d3558..c020a87e9e2 100644 --- a/tests/bsim/bluetooth/mesh/src/test_blob.c +++ b/tests/bsim/bluetooth/mesh/src/test_blob.c @@ -924,9 +924,9 @@ static void test_cli_trans_complete(void) blob_cli_inputs_prepare(BLOB_GROUP_ADDR); blob_cli_xfer.xfer.mode = is_pull_mode ? BT_MESH_BLOB_XFER_MODE_PULL : BT_MESH_BLOB_XFER_MODE_PUSH; - blob_cli_xfer.xfer.size = CONFIG_BT_MESH_BLOB_BLOCK_SIZE_MAX * 2; + blob_cli_xfer.xfer.size = CONFIG_BT_MESH_BLOB_BLOCK_SIZE_MIN * 4; blob_cli_xfer.xfer.id = 1; - blob_cli_xfer.xfer.block_size_log = 12; + blob_cli_xfer.xfer.block_size_log = 9; blob_cli_xfer.xfer.chunk_size = 377; blob_cli_xfer.inputs.timeout_base = 10; @@ -999,9 +999,9 @@ static void test_cli_trans_resume(void) blob_cli_inputs_prepare(BLOB_GROUP_ADDR); blob_cli_xfer.xfer.mode = is_pull_mode ? BT_MESH_BLOB_XFER_MODE_PULL : BT_MESH_BLOB_XFER_MODE_PUSH; - blob_cli_xfer.xfer.size = CONFIG_BT_MESH_BLOB_BLOCK_SIZE_MAX * 2; + blob_cli_xfer.xfer.size = CONFIG_BT_MESH_BLOB_BLOCK_SIZE_MIN * 4; blob_cli_xfer.xfer.id = 1; - blob_cli_xfer.xfer.block_size_log = 12; + blob_cli_xfer.xfer.block_size_log = 9; blob_cli_xfer.xfer.chunk_size = 377; blob_cli_xfer.inputs.timeout_base = 10; @@ -1054,7 +1054,7 @@ static void test_srv_trans_resume(void) bt_mesh_blob_srv_recv(&blob_srv, 1, &blob_io, 0, 10); /* Let server receive a couple of chunks from second block before disruption */ - for (int i = 0; i < 3; i++) { + for (int i = 0; i < 2; i++) { if (k_sem_take(&first_block_wr_sem, K_SECONDS(180))) { FAIL("Server did not receive the first BLOB block"); } @@ -1220,9 +1220,9 @@ static void cli_common_fail_on_init(void) blob_cli_inputs_prepare(BLOB_GROUP_ADDR); blob_cli_xfer.xfer.mode = BT_MESH_BLOB_XFER_MODE_PUSH; - blob_cli_xfer.xfer.size = CONFIG_BT_MESH_BLOB_BLOCK_SIZE_MAX * 1; + blob_cli_xfer.xfer.size = CONFIG_BT_MESH_BLOB_BLOCK_SIZE_MIN * 2; blob_cli_xfer.xfer.id = 1; - blob_cli_xfer.xfer.block_size_log = 12; + blob_cli_xfer.xfer.block_size_log = 9; blob_cli_xfer.xfer.chunk_size = 377; blob_cli_xfer.inputs.timeout_base = 10; } @@ -1422,9 +1422,9 @@ static void cli_stop_setup(void) blob_cli_inputs_prepare(BLOB_GROUP_ADDR); blob_cli_xfer.xfer.mode = is_pull_mode ? BT_MESH_BLOB_XFER_MODE_PULL : BT_MESH_BLOB_XFER_MODE_PUSH; - blob_cli_xfer.xfer.size = CONFIG_BT_MESH_BLOB_BLOCK_SIZE_MAX * 2; + blob_cli_xfer.xfer.size = CONFIG_BT_MESH_BLOB_BLOCK_SIZE_MIN * 4; blob_cli_xfer.xfer.id = 1; - blob_cli_xfer.xfer.block_size_log = 12; + blob_cli_xfer.xfer.block_size_log = 9; blob_cli_xfer.xfer.chunk_size = 377; blob_cli_xfer.inputs.timeout_base = 10; } @@ -1444,7 +1444,7 @@ static void test_cli_stop(void) { int err; - bt_mesh_test_cfg_set(NULL, 1000); + bt_mesh_test_cfg_set(NULL, 500); k_sem_init(&blob_caps_sem, 0, 1); k_sem_init(&lost_target_sem, 0, 1); k_sem_init(&blob_cli_end_sem, 0, 1); @@ -1526,8 +1526,8 @@ static void srv_check_reboot_and_continue(void) ASSERT_EQUAL(BLOB_CLI_ADDR, blob_srv.state.cli); ASSERT_EQUAL(1, blob_srv.state.timeout_base); ASSERT_EQUAL(BT_MESH_RX_SDU_MAX - BT_MESH_MIC_SHORT, blob_srv.state.mtu_size); - ASSERT_EQUAL(CONFIG_BT_MESH_BLOB_BLOCK_SIZE_MAX * 2, blob_srv.state.xfer.size); - ASSERT_EQUAL(12, blob_srv.state.xfer.block_size_log); + ASSERT_EQUAL(CONFIG_BT_MESH_BLOB_BLOCK_SIZE_MIN * 4, blob_srv.state.xfer.size); + ASSERT_EQUAL(9, blob_srv.state.xfer.block_size_log); ASSERT_EQUAL(1, blob_srv.state.xfer.id); ASSERT_TRUE(blob_srv.state.xfer.mode != BT_MESH_BLOB_XFER_MODE_NONE); /* First block should be already received, second one pending */ @@ -1539,7 +1539,7 @@ static void srv_check_reboot_and_continue(void) static void test_srv_stop(void) { - bt_mesh_test_cfg_set(NULL, 1000); + bt_mesh_test_cfg_set(NULL, 500); k_sem_init(&blob_srv_end_sem, 0, 1); k_sem_init(&first_block_wr_sem, 0, 1); k_sem_init(&blob_srv_suspend_sem, 0, 1); @@ -1594,7 +1594,7 @@ static void test_cli_friend_pull(void) { int err; - bt_mesh_test_cfg_set(NULL, 1000); + bt_mesh_test_cfg_set(NULL, 500); bt_mesh_test_friendship_init(1); @@ -1629,7 +1629,7 @@ static void test_cli_friend_pull(void) static void test_srv_lpn_pull(void) { - bt_mesh_test_cfg_set(NULL, 1000); + bt_mesh_test_cfg_set(NULL, 500); bt_mesh_test_friendship_init(1); diff --git a/tests/bsim/bluetooth/mesh/src/test_lcd.c b/tests/bsim/bluetooth/mesh/src/test_lcd.c index cd6a515294e..c31c5d43f72 100644 --- a/tests/bsim/bluetooth/mesh/src/test_lcd.c +++ b/tests/bsim/bluetooth/mesh/src/test_lcd.c @@ -86,7 +86,7 @@ static void test_args_parse(int argc, char *argv[]) bs_args_parse_all_cmd_line(argc, argv, args_struct); } -static const struct bt_mesh_models_metadata_entry *dummy_meta_entry[] = {}; +static const struct bt_mesh_models_metadata_entry dummy_meta_entry[1]; /* Empty elements to create large composition/meta data */ #define DUMMY_ELEM(i, _) BT_MESH_ELEM((i) + 2, \ diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_srv_persistence.sh b/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_srv_persistence.sh deleted file mode 100755 index b18a949b43d..00000000000 --- a/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_srv_persistence.sh +++ /dev/null @@ -1,91 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2023 Nordic Semiconductor -# SPDX-License-Identifier: Apache-2.0 - -source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh - -# Note: -# Tests must be added in pairs and in sequence. -# First test pair: executes Receive Firmware procedure up to certain point using distributor and -# target. -# Second test pair: tests are executed with `recover` enabled. This means target will recover -# settings from persistent storage, which will allow to verify if stored DFU server's phase and -# image index were loaded correctly. -# Test cases are designed to be run using single target. `dfu_cli_stop` test case in recovery part -# plays dummy role, and is there to keep order of settings files being loaded. -overlay=overlay_pst_conf -RunTestFlash dfu_dist_recover_phase \ - dfu_cli_stop -flash_erase dfu_target_dfu_stop -flash_erase \ - -- -argstest recover=0 expected-phase=2 - -overlay=overlay_pst_conf -RunTestFlash dfu_dist_recover_phase \ - dfu_cli_stop dfu_target_dfu_stop \ - -- -argstest recover=1 expected-phase=3 - -overlay=overlay_pst_conf -RunTestFlash dfu_dist_recover_phase \ - dfu_cli_stop dfu_target_dfu_stop \ - -- -argstest recover=1 expected-phase=4 - -overlay=overlay_pst_conf -RunTestFlash dfu_dist_recover_phase \ - dfu_cli_stop dfu_target_dfu_stop \ - -- -argstest recover=1 expected-phase=6 - -# Use phase `BT_MESH_DFU_PHASE_APPLY_SUCCESS` as marker to bring whole procedure to an end -overlay=overlay_pst_conf -RunTestFlash dfu_dist_recover_phase \ - dfu_cli_stop -flash_rm dfu_target_dfu_stop -flash_rm \ - -- -argstest recover=1 expected-phase=8 - -# To test recovery from Verify Fail begin new distribution that will end there, -# reboot devices and continue to Applying. -overlay=overlay_pst_conf -RunTestFlash dfu_dist_recover_phase \ - dfu_cli_stop -flash_erase dfu_target_dfu_stop -flash_erase \ - -- -argstest recover=0 expected-phase=5 - -overlay=overlay_pst_conf -RunTestFlash dfu_dist_recover_phase \ - dfu_cli_stop -flash_rm dfu_target_dfu_stop -flash_rm \ - -- -argstest recover=1 expected-phase=6 - -# The same test but with PSA crypto -overlay="overlay_pst_conf_overlay_psa_conf" -RunTestFlash dfu_dist_recover_phase_psa \ - dfu_cli_stop -flash_erase dfu_target_dfu_stop -flash_erase \ - -- -argstest recover=0 expected-phase=2 - -overlay="overlay_pst_conf_overlay_psa_conf" -RunTestFlash dfu_dist_recover_phase_psa \ - dfu_cli_stop dfu_target_dfu_stop \ - -- -argstest recover=1 expected-phase=3 - -overlay="overlay_pst_conf_overlay_psa_conf" -RunTestFlash dfu_dist_recover_phase_psa \ - dfu_cli_stop dfu_target_dfu_stop \ - -- -argstest recover=1 expected-phase=4 - -overlay="overlay_pst_conf_overlay_psa_conf" -RunTestFlash dfu_dist_recover_phase_psa \ - dfu_cli_stop dfu_target_dfu_stop \ - -- -argstest recover=1 expected-phase=6 - -# Use phase `BT_MESH_DFU_PHASE_APPLY_SUCCESS` as marker to bring whole procedure to an end -overlay="overlay_pst_conf_overlay_psa_conf" -RunTestFlash dfu_dist_recover_phase_psa \ - dfu_cli_stop -flash_rm dfu_target_dfu_stop -flash_rm \ - -- -argstest recover=1 expected-phase=8 - -# To test recovery from Verify Fail begin new distribution that will end there, -# reboot devices and continue to Applying. -overlay="overlay_pst_conf_overlay_psa_conf" -RunTestFlash dfu_dist_recover_phase_psa \ - dfu_cli_stop -flash_erase dfu_target_dfu_stop -flash_erase \ - -- -argstest recover=0 expected-phase=5 - -overlay="overlay_pst_conf_overlay_psa_conf" -RunTestFlash dfu_dist_recover_phase_psa \ - dfu_cli_stop -flash_rm dfu_target_dfu_stop -flash_rm \ - -- -argstest recover=1 expected-phase=6 diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_srv_recovery.sh b/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_srv_recovery.sh new file mode 100755 index 00000000000..62a30c2e816 --- /dev/null +++ b/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_srv_recovery.sh @@ -0,0 +1,67 @@ +#!/usr/bin/env bash +# Copyright 2023 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh + +# Note: +# Tests must be added in pairs and in sequence. +# First test pair: executes Receive Firmware procedure up to certain point using distributor and +# target. +# Second test pair: tests are executed with `recover` enabled. This means target will recover +# settings from persistent storage, which will allow to verify if stored DFU server's phase and +# image index were loaded correctly. +# Test cases are designed to be run using single target. `dfu_cli_stop` test case in recovery part +# plays dummy role, and is there to keep order of settings files being loaded. +overlay=overlay_pst_conf +RunTestFlash dfu_dist_recover_phase \ + dfu_cli_stop -flash_erase dfu_target_dfu_stop -flash_erase \ + -- -argstest recover=0 expected-phase=2 + +overlay=overlay_pst_conf +RunTestFlash dfu_dist_recover_phase \ + dfu_cli_stop dfu_target_dfu_stop \ + -- -argstest recover=1 expected-phase=3 + +overlay=overlay_pst_conf +RunTestFlash dfu_dist_recover_phase \ + dfu_cli_stop dfu_target_dfu_stop \ + -- -argstest recover=1 expected-phase=4 + +overlay=overlay_pst_conf +RunTestFlash dfu_dist_recover_phase \ + dfu_cli_stop dfu_target_dfu_stop \ + -- -argstest recover=1 expected-phase=6 + +# Use phase `BT_MESH_DFU_PHASE_APPLY_SUCCESS` as marker to bring whole procedure to an end +overlay=overlay_pst_conf +RunTestFlash dfu_dist_recover_phase \ + dfu_cli_stop -flash_rm dfu_target_dfu_stop -flash_rm \ + -- -argstest recover=1 expected-phase=8 + +# The same test but with PSA crypto +overlay="overlay_pst_conf_overlay_psa_conf" +RunTestFlash dfu_dist_recover_phase_psa \ + dfu_cli_stop -flash_erase dfu_target_dfu_stop -flash_erase \ + -- -argstest recover=0 expected-phase=2 + +overlay="overlay_pst_conf_overlay_psa_conf" +RunTestFlash dfu_dist_recover_phase_psa \ + dfu_cli_stop dfu_target_dfu_stop \ + -- -argstest recover=1 expected-phase=3 + +overlay="overlay_pst_conf_overlay_psa_conf" +RunTestFlash dfu_dist_recover_phase_psa \ + dfu_cli_stop dfu_target_dfu_stop \ + -- -argstest recover=1 expected-phase=4 + +overlay="overlay_pst_conf_overlay_psa_conf" +RunTestFlash dfu_dist_recover_phase_psa \ + dfu_cli_stop dfu_target_dfu_stop \ + -- -argstest recover=1 expected-phase=6 + +# Use phase `BT_MESH_DFU_PHASE_APPLY_SUCCESS` as marker to bring whole procedure to an end +overlay="overlay_pst_conf_overlay_psa_conf" +RunTestFlash dfu_dist_recover_phase_psa \ + dfu_cli_stop -flash_rm dfu_target_dfu_stop -flash_rm \ + -- -argstest recover=1 expected-phase=8 diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_srv_recovery_verify_fail.sh b/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_srv_recovery_verify_fail.sh new file mode 100755 index 00000000000..c43d94e80cc --- /dev/null +++ b/tests/bsim/bluetooth/mesh/tests_scripts/dfu/dfu_srv_recovery_verify_fail.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +# Copyright 2024 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh + +# Note: +# Tests must be added in pairs and in sequence. +# First test pair: executes Receive Firmware procedure up to certain point using distributor and +# target. +# Second test pair: tests recovery from Verify Fail begin new distribution that will end there, +# reboot devices and continue to Applying. +overlay=overlay_pst_conf +RunTestFlash dfu_dist_recover_verify_fail \ + dfu_cli_stop -flash_erase dfu_target_dfu_stop -flash_erase \ + -- -argstest recover=0 expected-phase=5 + +overlay=overlay_pst_conf +RunTestFlash dfu_dist_recover_verify_fail \ + dfu_cli_stop -flash_rm dfu_target_dfu_stop -flash_rm \ + -- -argstest recover=1 expected-phase=6 + +# The same test but with PSA crypto +overlay="overlay_pst_conf_overlay_psa_conf" +RunTestFlash dfu_dist_recover_verify_fail_psa \ + dfu_cli_stop -flash_erase dfu_target_dfu_stop -flash_erase \ + -- -argstest recover=0 expected-phase=5 + +overlay="overlay_pst_conf_overlay_psa_conf" +RunTestFlash dfu_dist_recover_verify_fail_psa \ + dfu_cli_stop -flash_rm dfu_target_dfu_stop -flash_rm \ + -- -argstest recover=1 expected-phase=6 diff --git a/tests/bsim/bluetooth/samples/central_hr_peripheral_hr/CMakeLists.txt b/tests/bsim/bluetooth/samples/central_hr_peripheral_hr/CMakeLists.txt new file mode 100644 index 00000000000..d716aed6fc1 --- /dev/null +++ b/tests/bsim/bluetooth/samples/central_hr_peripheral_hr/CMakeLists.txt @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(central_hr_peripheral_hr_test) + +set(central_hr_path ${ZEPHYR_BASE}/samples/bluetooth/central_hr) + +target_sources(app PRIVATE + ${central_hr_path}/src/main.c +) + +target_sources(app PRIVATE + src/sample_test.c + src/test_main.c +) + +zephyr_library_include_directories(${ZEPHYR_BASE}/samples/bluetooth) + +zephyr_include_directories( + ${BSIM_COMPONENTS_PATH}/libUtilv1/src/ + ${BSIM_COMPONENTS_PATH}/libPhyComv1/src/ + ) diff --git a/tests/bsim/bluetooth/samples/central_hr_peripheral_hr/Kconfig b/tests/bsim/bluetooth/samples/central_hr_peripheral_hr/Kconfig new file mode 100644 index 00000000000..e2cbc2de917 --- /dev/null +++ b/tests/bsim/bluetooth/samples/central_hr_peripheral_hr/Kconfig @@ -0,0 +1,10 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +# source sample's Kconfig, if any +# source "${ZEPHYR_BASE}/samples/bluetooth/central_hr/Kconfig" +# OR +# source Zephyr Kernel's Kconfig, as below (not both) +menu "Zephyr Kernel" +source "Kconfig.zephyr" +endmenu diff --git a/tests/bsim/bluetooth/samples/central_hr_peripheral_hr/Kconfig.sysbuild b/tests/bsim/bluetooth/samples/central_hr_peripheral_hr/Kconfig.sysbuild new file mode 100644 index 00000000000..8a4e25038c4 --- /dev/null +++ b/tests/bsim/bluetooth/samples/central_hr_peripheral_hr/Kconfig.sysbuild @@ -0,0 +1,11 @@ +# Copyright (c) 2023-2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +# source the samples' Kconfig.sysbuild, if any +source "${ZEPHYR_BASE}/samples/bluetooth/central_hr/Kconfig.sysbuild" + +config NATIVE_SIMULATOR_PRIMARY_MCU_INDEX + int + # Let's pass the test arguments to the application MCU test + # otherwise by default they would have gone to the net core. + default 0 if $(BOARD_TARGET_STRING)="NRF5340BSIM_NRF5340_CPUAPP" diff --git a/tests/bsim/bluetooth/samples/central_hr_peripheral_hr/boards/nrf5340bsim_nrf5340_cpuapp.conf b/tests/bsim/bluetooth/samples/central_hr_peripheral_hr/boards/nrf5340bsim_nrf5340_cpuapp.conf new file mode 100644 index 00000000000..4d2c3afd09e --- /dev/null +++ b/tests/bsim/bluetooth/samples/central_hr_peripheral_hr/boards/nrf5340bsim_nrf5340_cpuapp.conf @@ -0,0 +1 @@ +CONFIG_BT_BUF_ACL_RX_SIZE=255 diff --git a/tests/bsim/bluetooth/samples/central_hr_peripheral_hr/prj.conf b/tests/bsim/bluetooth/samples/central_hr_peripheral_hr/prj.conf new file mode 100644 index 00000000000..ad774080560 --- /dev/null +++ b/tests/bsim/bluetooth/samples/central_hr_peripheral_hr/prj.conf @@ -0,0 +1,2 @@ +# Please build using the sample configuration file: +# ${ZEPHYR_BASE}/samples/bluetooth/central_hr/prj.conf diff --git a/tests/bsim/bluetooth/samples/central_hr_peripheral_hr/src/sample_test.c b/tests/bsim/bluetooth/samples/central_hr_peripheral_hr/src/sample_test.c new file mode 100644 index 00000000000..107ae44b3c6 --- /dev/null +++ b/tests/bsim/bluetooth/samples/central_hr_peripheral_hr/src/sample_test.c @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2023-2024 Nordic Semiconductor ASA + * Copyright (c) 2017-2019 Oticon A/S + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "bs_types.h" +#include "bs_tracing.h" +#include "bs_utils.h" +#include "time_machine.h" +#include "bstests.h" + +#define WAIT_TIME 10 /* Seconds */ + +#define PASS_THRESHOLD 5 /* packets */ + +extern enum bst_result_t bst_result; + +#define FAIL(...) \ + do { \ + bst_result = Failed; \ + bs_trace_error_time_line(__VA_ARGS__); \ + } while (0) + +#define PASS(...) \ + do { \ + bst_result = Passed; \ + bs_trace_info_time(1, __VA_ARGS__); \ + } while (0) + +static void test_sample_init(void) +{ + /* We set an absolute deadline in 30 seconds */ + bst_ticker_set_next_tick_absolute(WAIT_TIME*1e6); + bst_result = In_progress; +} + +static void test_sample_tick(bs_time_t HW_device_time) +{ + /* + * If in WAIT_TIME seconds we did not get enough packets through + * we consider the test failed + */ + + extern uint64_t total_rx_count; + + bs_trace_info_time(2, "%"PRIu64" packets received, expected >= %i\n", + total_rx_count, PASS_THRESHOLD); + + if (total_rx_count >= PASS_THRESHOLD) { + PASS("PASSED\n"); + bs_trace_exit("Done, disconnecting from simulation\n"); + } else { + FAIL("FAILED (Did not pass after %i seconds)\n", WAIT_TIME); + } +} + +static const struct bst_test_instance test_sample[] = { + { + .test_id = "central_hr_peripheral_hr", + .test_descr = "Test based on the peripheral and central HR samples. " + "It expects to be connected to a compatible sample, " + "waits for " STR(WAIT_TIME) " seconds, and checks how " + "many packets have been received correctly", + .test_post_init_f = test_sample_init, + .test_tick_f = test_sample_tick, + }, + BSTEST_END_MARKER +}; + +struct bst_test_list *test_sample_install(struct bst_test_list *tests) +{ + tests = bst_add_tests(tests, test_sample); + return tests; +} diff --git a/tests/bsim/bluetooth/samples/central_hr_peripheral_hr/src/test_main.c b/tests/bsim/bluetooth/samples/central_hr_peripheral_hr/src/test_main.c new file mode 100644 index 00000000000..601b9fcefa9 --- /dev/null +++ b/tests/bsim/bluetooth/samples/central_hr_peripheral_hr/src/test_main.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2023-2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "bstests.h" + +extern struct bst_test_list *test_sample_install(struct bst_test_list *tests); + +bst_test_install_t test_installers[] = { + test_sample_install, + NULL +}; diff --git a/tests/bsim/bluetooth/samples/central_hr_peripheral_hr/sysbuild.cmake b/tests/bsim/bluetooth/samples/central_hr_peripheral_hr/sysbuild.cmake new file mode 100644 index 00000000000..98cdf5ccbcd --- /dev/null +++ b/tests/bsim/bluetooth/samples/central_hr_peripheral_hr/sysbuild.cmake @@ -0,0 +1,6 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +include(${ZEPHYR_BASE}/samples/bluetooth/central_hr/sysbuild.cmake) + +native_simulator_set_primary_mcu_index(${DEFAULT_IMAGE} ${NET_APP}) diff --git a/tests/bsim/bluetooth/samples/central_hr_peripheral_hr/tests_scripts/central_hr_peripheral_hr.sh b/tests/bsim/bluetooth/samples/central_hr_peripheral_hr/tests_scripts/central_hr_peripheral_hr.sh new file mode 100755 index 00000000000..301a8834b7e --- /dev/null +++ b/tests/bsim/bluetooth/samples/central_hr_peripheral_hr/tests_scripts/central_hr_peripheral_hr.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +# Copyright 2023-2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +simulation_id="central_hr_peripheral_hr_test" +verbosity_level=2 +EXECUTE_TIMEOUT=60 + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +cd ${BSIM_OUT_PATH}/bin + +Execute ./bs_${BOARD_TS}_samples_bluetooth_peripheral_hr_prj_conf \ + -v=${verbosity_level} -s=${simulation_id} -d=0 -RealEncryption=1 + +Execute ./bs_${BOARD_TS}_tests_bsim_bluetooth_samples_central_hr_peripheral_hr_prj_conf \ + -v=${verbosity_level} -s=${simulation_id} -d=1 -RealEncryption=1 \ + -testid=central_hr_peripheral_hr + +Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \ + -D=2 -sim_length=12e6 $@ + +wait_for_background_jobs #Wait for all programs in background and return != 0 if any fails diff --git a/tests/bsim/bluetooth/samples/central_hr_peripheral_hr/tests_scripts/central_hr_peripheral_hr_extended.sh b/tests/bsim/bluetooth/samples/central_hr_peripheral_hr/tests_scripts/central_hr_peripheral_hr_extended.sh new file mode 100755 index 00000000000..b2083ca1f06 --- /dev/null +++ b/tests/bsim/bluetooth/samples/central_hr_peripheral_hr/tests_scripts/central_hr_peripheral_hr_extended.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +# Copyright 2023-2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +simulation_id="central_hr_peripheral_hr_extended_test" +test_long_name="$(guess_test_long_name)" +verbosity_level=2 +EXECUTE_TIMEOUT=60 + +cd ${BSIM_OUT_PATH}/bin + +Execute ./bs_${BOARD_TS}_samples_bluetooth_peripheral_hr_prj_conf_overlay-extended_conf \ + -v=${verbosity_level} -s=${simulation_id} -d=0 -RealEncryption=1 + +Execute ./bs_${BOARD_TS}_${test_long_name}_prj_conf_overlay-extended_conf \ + -v=${verbosity_level} -s=${simulation_id} -d=1 -RealEncryption=1 \ + -testid=central_hr_peripheral_hr + +Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \ + -D=2 -sim_length=12e6 $@ + +wait_for_background_jobs #Wait for all programs in background and return != 0 if any fails diff --git a/tests/bsim/bluetooth/samples/central_hr_peripheral_hr/tests_scripts/central_hr_peripheral_hr_phy_coded.sh b/tests/bsim/bluetooth/samples/central_hr_peripheral_hr/tests_scripts/central_hr_peripheral_hr_phy_coded.sh new file mode 100755 index 00000000000..7232fe454a9 --- /dev/null +++ b/tests/bsim/bluetooth/samples/central_hr_peripheral_hr/tests_scripts/central_hr_peripheral_hr_phy_coded.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +# Copyright 2023-2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +simulation_id="central_hr_peripheral_hr_phy_coded_test" +test_long_name="$(guess_test_long_name)" +verbosity_level=2 +EXECUTE_TIMEOUT=60 + +cd ${BSIM_OUT_PATH}/bin + +Execute ./bs_${BOARD_TS}_samples_bluetooth_peripheral_hr_prj_conf_overlay-phy_coded_conf \ + -v=${verbosity_level} -s=${simulation_id} -d=0 -RealEncryption=1 + +Execute ./bs_${BOARD_TS}_${test_long_name}_prj_conf_overlay-phy_coded_conf \ + -v=${verbosity_level} -s=${simulation_id} -d=1 -RealEncryption=1 \ + -testid=central_hr_peripheral_hr + +Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \ + -D=2 -sim_length=12e6 $@ + +wait_for_background_jobs #Wait for all programs in background and return != 0 if any fails diff --git a/tests/bsim/bluetooth/samples/compile.sh b/tests/bsim/bluetooth/samples/compile.sh new file mode 100755 index 00000000000..3b61bdf1779 --- /dev/null +++ b/tests/bsim/bluetooth/samples/compile.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash +# Copyright 2023-2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +# Compile all the applications needed by the bsim tests in these subfolders + +#set -x #uncomment this line for debugging +set -ue + +: "${ZEPHYR_BASE:?ZEPHYR_BASE must be set to point to the zephyr root\ + directory}" + +source ${ZEPHYR_BASE}/tests/bsim/compile.source + +app=samples/bluetooth/peripheral_hr \ + sysbuild=1 \ + compile +app=tests/bsim/bluetooth/samples/central_hr_peripheral_hr \ + sysbuild=1 \ + extra_conf_file=${ZEPHYR_BASE}/samples/bluetooth/central_hr/prj.conf \ + compile +app=samples/bluetooth/peripheral_hr \ + sysbuild=1 \ + conf_overlay=overlay-extended.conf \ + compile +app=tests/bsim/bluetooth/samples/central_hr_peripheral_hr \ + sysbuild=1 \ + extra_conf_file=${ZEPHYR_BASE}/samples/bluetooth/central_hr/prj.conf \ + conf_overlay=${ZEPHYR_BASE}/samples/bluetooth/central_hr/overlay-extended.conf \ + compile +app=samples/bluetooth/peripheral_hr \ + sysbuild=1 \ + conf_overlay=overlay-phy_coded.conf \ + compile +app=tests/bsim/bluetooth/samples/central_hr_peripheral_hr \ + sysbuild=1 \ + extra_conf_file=${ZEPHYR_BASE}/samples/bluetooth/central_hr/prj.conf \ + conf_overlay=${ZEPHYR_BASE}/samples/bluetooth/central_hr/overlay-phy_coded.conf \ + compile + +wait_for_background_jobs diff --git a/tests/bsim/bluetooth/tests.nrf5340bsim_nrf5340_cpuapp.txt b/tests/bsim/bluetooth/tests.nrf5340bsim_nrf5340_cpuapp.txt index 27a1fc4a76f..fec0c4a6002 100644 --- a/tests/bsim/bluetooth/tests.nrf5340bsim_nrf5340_cpuapp.txt +++ b/tests/bsim/bluetooth/tests.nrf5340bsim_nrf5340_cpuapp.txt @@ -2,4 +2,5 @@ # This file is used in CI to select which tests are run tests/bsim/bluetooth/ll/conn/tests_scripts/basic_conn_encrypted_split_privacy.sh tests/bsim/bluetooth/ll/bis/tests_scripts/broadcast_iso.sh +tests/bsim/bluetooth/samples/ tests/bsim/bluetooth/audio_samples/ diff --git a/tests/bsim/compile.source b/tests/bsim/compile.source index 515e9cc693d..784c8dc06e1 100644 --- a/tests/bsim/compile.source +++ b/tests/bsim/compile.source @@ -19,6 +19,7 @@ function _compile(){ local app_root="${app_root:-${ZEPHYR_BASE}}" local BOARD_ROOT="${BOARD_ROOT:-${ZEPHYR_BASE}}" local conf_file="${conf_file:-prj.conf}" + local extra_conf_file="${extra_conf_file:-""}" local conf_overlay="${conf_overlay:-""}" default_cmake_args=(-DCONFIG_COVERAGE=y -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ @@ -29,8 +30,9 @@ function _compile(){ local cc_flags="${cc_flags:-""}" if [ "${conf_overlay}" ]; then - overlays="${conf_overlay//;/_}" - local exe_basename="${exe_name:-bs_${BOARD}_${app}_${conf_file}_${overlays}}" + overlay_basename="${conf_overlay##*/}" + overlay_file="${overlay_basename//;/_}" + local exe_basename="${exe_name:-bs_${BOARD}_${app}_${conf_file}_${overlay_file}}" else local exe_basename="${exe_name:-bs_${BOARD}_${app}_${conf_file}}" fi @@ -53,6 +55,7 @@ function _compile(){ fi orifs="$IFS"; IFS= local cmake_cmd+=( -DOVERLAY_CONFIG="${conf_overlay}" \ + -DEXTRA_CONF_FILE="${extra_conf_file}" \ ${modules_arg} \ "${cmake_args[@]}" ${cc_flags:+-DCMAKE_C_FLAGS=${cc_flags}} ${cmake_extra_args}) if [ -v sysbuild ]; then diff --git a/tests/bsim/run_parallel.sh b/tests/bsim/run_parallel.sh index 99416529034..0a96229e59b 100755 --- a/tests/bsim/run_parallel.sh +++ b/tests/bsim/run_parallel.sh @@ -78,10 +78,10 @@ if [ `command -v parallel` ]; then parallel ' echo "" start=$(date +%s%N) - {} $@ &> {#}.log + {} $@ &> {#}.log ; result=$? dur=$(($(date +%s%N) - $start)) dur_s=$(awk -vdur=$dur "BEGIN { printf(\"%0.3f\", dur/1000000000)}") - if [ $? -ne 0 ]; then + if [ $result -ne 0 ]; then (>&2 echo -e "\e[91m{} FAILED\e[39m ($dur_s s)") (>&2 cat {#}.log) echo "" diff --git a/tests/crypto/mbedtls/prj.conf b/tests/crypto/mbedtls/prj.conf index 9b6af503e03..9f916487099 100644 --- a/tests/crypto/mbedtls/prj.conf +++ b/tests/crypto/mbedtls/prj.conf @@ -4,5 +4,8 @@ CONFIG_MBEDTLS_BUILTIN=y CONFIG_MBEDTLS_TEST=y CONFIG_ZTEST=y CONFIG_TEST_USERSPACE=y +CONFIG_MINIMAL_LIBC=y CONFIG_MINIMAL_LIBC_NON_REENTRANT_FUNCTIONS=y CONFIG_MINIMAL_LIBC_RAND=y +CONFIG_ENTROPY_GENERATOR=y +CONFIG_TEST_RANDOM_GENERATOR=y diff --git a/tests/drivers/adc/adc_api/boards/bl654_dvk_nrf52840_pa.overlay b/tests/drivers/adc/adc_api/boards/bl654_dvk_nrf52840_pa.overlay new file mode 100644 index 00000000000..2af48efc4d1 --- /dev/null +++ b/tests/drivers/adc/adc_api/boards/bl654_dvk_nrf52840_pa.overlay @@ -0,0 +1,7 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2023 Benjamin Bjƶrnsson + */ + +#include "nordic,nrf-saadc-common.dtsi" diff --git a/tests/drivers/adc/adc_api/boards/esp32s3_devkitm.conf b/tests/drivers/adc/adc_api/boards/esp32s2_devkitc.conf similarity index 100% rename from tests/drivers/adc/adc_api/boards/esp32s3_devkitm.conf rename to tests/drivers/adc/adc_api/boards/esp32s2_devkitc.conf diff --git a/tests/drivers/adc/adc_api/boards/yd_esp32.overlay b/tests/drivers/adc/adc_api/boards/esp32s2_devkitc.overlay similarity index 100% rename from tests/drivers/adc/adc_api/boards/yd_esp32.overlay rename to tests/drivers/adc/adc_api/boards/esp32s2_devkitc.overlay diff --git a/tests/drivers/adc/adc_api/boards/esp32s3_luatos_core.conf b/tests/drivers/adc/adc_api/boards/esp32s3_devkitm_procpu.conf similarity index 100% rename from tests/drivers/adc/adc_api/boards/esp32s3_luatos_core.conf rename to tests/drivers/adc/adc_api/boards/esp32s3_devkitm_procpu.conf diff --git a/tests/drivers/adc/adc_api/boards/esp32s3_devkitm.overlay b/tests/drivers/adc/adc_api/boards/esp32s3_devkitm_procpu.overlay similarity index 100% rename from tests/drivers/adc/adc_api/boards/esp32s3_devkitm.overlay rename to tests/drivers/adc/adc_api/boards/esp32s3_devkitm_procpu.overlay diff --git a/tests/drivers/adc/adc_api/boards/esp32s3_luatos_core_esp32s3_procpu_usb.conf b/tests/drivers/adc/adc_api/boards/esp32s3_luatos_core_procpu.conf similarity index 100% rename from tests/drivers/adc/adc_api/boards/esp32s3_luatos_core_esp32s3_procpu_usb.conf rename to tests/drivers/adc/adc_api/boards/esp32s3_luatos_core_procpu.conf diff --git a/tests/drivers/adc/adc_api/boards/esp32s3_luatos_core.overlay b/tests/drivers/adc/adc_api/boards/esp32s3_luatos_core_procpu.overlay similarity index 100% rename from tests/drivers/adc/adc_api/boards/esp32s3_luatos_core.overlay rename to tests/drivers/adc/adc_api/boards/esp32s3_luatos_core_procpu.overlay diff --git a/tests/drivers/adc/adc_api/boards/esp_wrover_kit.conf b/tests/drivers/adc/adc_api/boards/esp32s3_luatos_core_procpu_usb.conf similarity index 100% rename from tests/drivers/adc/adc_api/boards/esp_wrover_kit.conf rename to tests/drivers/adc/adc_api/boards/esp32s3_luatos_core_procpu_usb.conf diff --git a/tests/drivers/adc/adc_api/boards/esp32s3_luatos_core_esp32s3_procpu_usb.overlay b/tests/drivers/adc/adc_api/boards/esp32s3_luatos_core_procpu_usb.overlay similarity index 100% rename from tests/drivers/adc/adc_api/boards/esp32s3_luatos_core_esp32s3_procpu_usb.overlay rename to tests/drivers/adc/adc_api/boards/esp32s3_luatos_core_procpu_usb.overlay diff --git a/tests/drivers/adc/adc_api/boards/esp_wrover_kit_procpu.conf b/tests/drivers/adc/adc_api/boards/esp_wrover_kit_procpu.conf new file mode 100644 index 00000000000..b6c5c80f924 --- /dev/null +++ b/tests/drivers/adc/adc_api/boards/esp_wrover_kit_procpu.conf @@ -0,0 +1 @@ +CONFIG_ADC_ASYNC=n diff --git a/tests/drivers/adc/adc_api/boards/esp_wrover_kit.overlay b/tests/drivers/adc/adc_api/boards/esp_wrover_kit_procpu.overlay similarity index 100% rename from tests/drivers/adc/adc_api/boards/esp_wrover_kit.overlay rename to tests/drivers/adc/adc_api/boards/esp_wrover_kit_procpu.overlay diff --git a/tests/drivers/adc/adc_api/boards/frdm_mcxn947_mcxn947_cpu0.overlay b/tests/drivers/adc/adc_api/boards/frdm_mcxn947_mcxn947_cpu0.overlay new file mode 100644 index 00000000000..99d447efc68 --- /dev/null +++ b/tests/drivers/adc/adc_api/boards/frdm_mcxn947_mcxn947_cpu0.overlay @@ -0,0 +1,36 @@ +/* + * Copyright 2024 NXP + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + zephyr,user { + io-channels = <&lpadc0 0>, <&lpadc0 1>; + }; +}; + +&lpadc0 { + #address-cells = <1>; + #size-cells = <0>; + + channel@0 { + reg = <0>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_EXTERNAL1"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + zephyr,input-positive = ; + }; + + channel@1 { + reg = <1>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_EXTERNAL1"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + zephyr,input-positive = ; + }; +}; diff --git a/tests/drivers/adc/adc_api/boards/lpcxpresso55s69_lpc55s69_cpu0_ns.overlay b/tests/drivers/adc/adc_api/boards/lpcxpresso55s69_lpc55s69_cpu0_ns.overlay new file mode 100644 index 00000000000..386e405b7bb --- /dev/null +++ b/tests/drivers/adc/adc_api/boards/lpcxpresso55s69_lpc55s69_cpu0_ns.overlay @@ -0,0 +1,60 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2023 Benjamin Bjƶrnsson + */ + +#include + +/ { + zephyr,user { + io-channels = <&adc0 0>, <&adc0 1>, <&adc0 2>; + }; +}; + +&adc0 { + #address-cells = <1>; + #size-cells = <0>; + + /* + * Channel 0 is used in single ended mode, with 12 bit resolution + * CH0A is routed to P19 pin 4 + */ + channel@0 { + reg = <0>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_EXTERNAL0"; + zephyr,vref-mv = <3300>; + zephyr,acquisition-time = ; + zephyr,resolution = <13>; + zephyr,input-positive = ; + }; + + /* + * Channel 1 is used in single ended mode, with 16 bit resolution + * CH4A is routed to P17 pin 19 + */ + channel@1 { + reg = <1>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_EXTERNAL0"; + zephyr,vref-mv = <3300>; + zephyr,acquisition-time = ; + zephyr,resolution = <16>; + zephyr,input-positive = ; + }; + + /* + * Channel 2 is used in single ended mode, with 12 bit resolution + * CH4B is routed to P18 pin 1 + */ + channel@2 { + reg = <2>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_EXTERNAL0"; + zephyr,vref-mv = <3300>; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + zephyr,input-positive = ; + }; +}; diff --git a/tests/drivers/adc/adc_api/boards/nrf5340_audio_dk_nrf5340_cpuapp.overlay b/tests/drivers/adc/adc_api/boards/nrf5340_audio_dk_nrf5340_cpuapp.overlay new file mode 100644 index 00000000000..2af48efc4d1 --- /dev/null +++ b/tests/drivers/adc/adc_api/boards/nrf5340_audio_dk_nrf5340_cpuapp.overlay @@ -0,0 +1,7 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2023 Benjamin Bjƶrnsson + */ + +#include "nordic,nrf-saadc-common.dtsi" diff --git a/tests/drivers/adc/adc_api/boards/numaker_m2l31ki.conf b/tests/drivers/adc/adc_api/boards/numaker_m2l31ki.conf new file mode 100644 index 00000000000..9fb2581d7f4 --- /dev/null +++ b/tests/drivers/adc/adc_api/boards/numaker_m2l31ki.conf @@ -0,0 +1 @@ +CONFIG_TEST_USERSPACE=n diff --git a/tests/drivers/adc/adc_api/boards/numaker_m2l31ki.overlay b/tests/drivers/adc/adc_api/boards/numaker_m2l31ki.overlay new file mode 100644 index 00000000000..1fb978f147e --- /dev/null +++ b/tests/drivers/adc/adc_api/boards/numaker_m2l31ki.overlay @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +/ { + zephyr,user { + io-channels = <&eadc0 5>, <&eadc0 7>; + }; +}; + +&pinctrl { + /* EVB's UNO Pin A2 & A0 for channel 5 & 7 --> PB5, PB7 */ + eadc0_default: eadc0_default { + group0 { + pinmux = , ; + }; + }; +}; + +&eadc0 { + status = "okay"; + pinctrl-0 = <&eadc0_default>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + + channel@5 { + reg = <5>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <10>; + }; + + channel@7 { + reg = <7>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <10>; + }; +}; diff --git a/tests/drivers/adc/adc_api/boards/rd_rw612_bga.overlay b/tests/drivers/adc/adc_api/boards/rd_rw612_bga.overlay new file mode 100644 index 00000000000..53596ab11c4 --- /dev/null +++ b/tests/drivers/adc/adc_api/boards/rd_rw612_bga.overlay @@ -0,0 +1,38 @@ +/* + * Copyright 2023 NXP + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + zephyr,user { + /* adjust channel number according to pinmux in board.dts */ + io-channels = <&adc0 0 &adc0 1>; + }; +}; + +&adc0 { + #address-cells = <1>; + #size-cells = <0>; + + channel@0 { + reg = <0>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_VDD_1"; + zephyr,vref-mv = <1800>; + zephyr,acquisition-time = ; + zephyr,resolution = <16>; + zephyr,input-positive = ; + }; + + channel@1 { + reg = <1>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_VDD_1"; + zephyr,vref-mv = <1800>; + zephyr,acquisition-time = ; + zephyr,resolution = <16>; + zephyr,input-positive = ; + }; +}; diff --git a/tests/drivers/adc/adc_api/boards/vmu_rt1170.overlay b/tests/drivers/adc/adc_api/boards/vmu_rt1170_mimxrt1176_cm7.overlay similarity index 100% rename from tests/drivers/adc/adc_api/boards/vmu_rt1170.overlay rename to tests/drivers/adc/adc_api/boards/vmu_rt1170_mimxrt1176_cm7.overlay diff --git a/tests/drivers/adc/adc_api/boards/yd_esp32_procpu.overlay b/tests/drivers/adc/adc_api/boards/yd_esp32_procpu.overlay new file mode 100644 index 00000000000..c288312aa3a --- /dev/null +++ b/tests/drivers/adc/adc_api/boards/yd_esp32_procpu.overlay @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2022 Wolter HV + * Copyright (c) 2023 Benjamin Bjƶrnsson + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + zephyr,user { + /* adjust channel number according to pinmux in board.dts */ + io-channels = <&adc0 0>, <&adc0 1>; + }; +}; + +&adc0 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + channel@0 { + reg = <0>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; + + channel@1 { + reg = <1>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; +}; diff --git a/tests/drivers/adc/adc_rescale/boards/native_sim_native_64.overlay b/tests/drivers/adc/adc_rescale/boards/native_sim_native_64.overlay new file mode 100644 index 00000000000..91647f82e20 --- /dev/null +++ b/tests/drivers/adc/adc_rescale/boards/native_sim_native_64.overlay @@ -0,0 +1,6 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "native_sim.overlay" diff --git a/tests/drivers/build_all/dac/app.overlay b/tests/drivers/build_all/dac/app.overlay index 8f7c91819ac..ec86ed2b26c 100644 --- a/tests/drivers/build_all/dac/app.overlay +++ b/tests/drivers/build_all/dac/app.overlay @@ -68,6 +68,41 @@ voltage_reference = <0>; power_down_mode = <0>; }; + + test_i2c_dacx0501:dacx0501@62 { + compatible = "ti,dacx0501"; + status = "okay"; + reg = <0x62>; + voltage-reference = "internal"; + output-gain = "mul2"; + }; + + test_ad5691: ad5691@4a { + status = "okay"; + compatible = "adi,ad5691"; + reg = <0x4a>; + resolution = <12>; + voltage-reference-mv = <2500>; + #io-channel-cells = < 1 >; + }; + + test_ad5692: ad5692@4b { + status = "okay"; + compatible = "adi,ad5692"; + reg = <0x4b>; + resolution = <14>; + voltage-reference-mv = <2500>; + #io-channel-cells = < 1 >; + }; + + test_ad5693: ad5693@4c { + status = "okay"; + compatible = "adi,ad5693"; + reg = <0x4c>; + resolution = <16>; + voltage-reference-mv = <2500>; + #io-channel-cells = < 1 >; + }; }; test_spi: spi@33334444 { diff --git a/tests/drivers/build_all/display/app.overlay b/tests/drivers/build_all/display/app.overlay index cd6669e4516..86554578ff9 100644 --- a/tests/drivers/build_all/display/app.overlay +++ b/tests/drivers/build_all/display/app.overlay @@ -10,6 +10,9 @@ * (and be extended to test) real hardware. */ +#include +#include + / { test { #address-cells = <1>; @@ -53,6 +56,20 @@ pgc = [F0 06 0B 07 06 05 2E 33 47 3A 17 16 2E 31]; ngc = [F0 09 0D 09 08 23 2E 33 46 38 13 13 2C 32]; }; + + test_mipi_dbi_st7735r: st7735t@2 { + compatible = "sitronix,st7735r"; + mipi-max-frequency = <250000000>; + mipi-mode = ; + reg = <2>; + /* Arbitrary values */ + x-offset = <0>; + y-offset = <0>; + gamctrp1 = [10 0E 02 03 0E 07 02 07 0A 12 27 37 00 0D 0E 10]; + gamctrn1 = [10 0E 03 03 0F 06 02 08 0A 13 26 36 00 0D 0E 10]; + width = <160>; + height = <128>; + }; }; @@ -65,7 +82,7 @@ clock-frequency = <2000000>; /* one entry for every devices at spi.dtsi */ - cs-gpios = <&test_gpio 0 0 &test_gpio 0 1>; + cs-gpios = <&test_gpio 0 0 &test_gpio 0 1 &test_gpio 0 2>; test_spi_gc9x01x: gc9x01x@1 { compatible = "galaxycore,gc9x01x"; @@ -83,6 +100,10 @@ compatible = "greeled,lpd8806"; reg = <2>; spi-max-frequency = <2000000>; + chain-length = <1>; + color-mapping = ; }; test_led_strip_1: ws2812_spi@3 { diff --git a/tests/drivers/build_all/fpga/app.overlay b/tests/drivers/build_all/fpga/app.overlay index e26db8e7ba7..6135bfa5745 100644 --- a/tests/drivers/build_all/fpga/app.overlay +++ b/tests/drivers/build_all/fpga/app.overlay @@ -38,6 +38,18 @@ #include "spi.dtsi" }; }; + + fpga0: bridges { + compatible = "altr,socfpga-agilex-bridge"; + status = "okay"; + }; + + sip_smc: smc { + compatible = "intel,socfpga-agilex-sip-smc"; + method = "smc"; + status = "okay"; + zephyr,num-clients = <2>; + }; }; /* Put device specific modifications to properties or disabling of devices diff --git a/tests/drivers/build_all/fpga/prj.conf b/tests/drivers/build_all/fpga/prj.conf index 579660e8df1..d6c9a05db52 100644 --- a/tests/drivers/build_all/fpga/prj.conf +++ b/tests/drivers/build_all/fpga/prj.conf @@ -11,3 +11,8 @@ CONFIG_FPGA=y # iCE40 FPGAs on a single bus to 1. CONFIG_PINCTRL=n CONFIG_ICE40_FPGA=y +CONFIG_ALTERA_AGILEX_BRIDGE_FPGA=y +CONFIG_ARM_SIP_SVC_DRIVER=y +CONFIG_ARM_SIP_SVC_SUBSYS=y +CONFIG_ARM_SIP_SVC_SUBSYS_SINGLY_OPEN=y +CONFIG_HEAP_MEM_POOL_SIZE=16384 diff --git a/tests/drivers/build_all/input/app.overlay b/tests/drivers/build_all/input/app.overlay index 93e7bf1c144..23bd36a3074 100644 --- a/tests/drivers/build_all/input/app.overlay +++ b/tests/drivers/build_all/input/app.overlay @@ -245,7 +245,8 @@ /* one entry for every devices */ cs-gpios = <&test_gpio 0 0>, <&test_gpio 1 0>, - <&test_gpio 2 0>; + <&test_gpio 2 0>, + <&test_gpio 3 0>; xpt2046@0 { compatible = "xptek,xpt2046"; @@ -286,6 +287,18 @@ invert-x; invert-y; }; + + paw32xx@3 { + compatible = "pixart,paw32xx"; + reg = <3>; + spi-max-frequency = <0>; + motion-gpios = <&test_gpio 0 0>; + zephyr,axis-x = <0>; + zephyr,axis-y = <1>; + invert-x; + invert-y; + res-cpi = <800>; + }; }; }; }; diff --git a/tests/drivers/build_all/modem/uart.dtsi b/tests/drivers/build_all/modem/uart.dtsi index 08da2c325d3..96077f329ca 100644 --- a/tests/drivers/build_all/modem/uart.dtsi +++ b/tests/drivers/build_all/modem/uart.dtsi @@ -76,3 +76,9 @@ test_nordic_nrf91_slm: nordic_nrf91_slm { mdm-power-gpios = <&test_gpio 0 0>; }; + +test_sqn_gm02s: sqn_gm02s { + compatible = "sqn,gm02s"; + + mdm-reset-gpios = <&test_gpio 0 0>; +}; diff --git a/tests/drivers/build_all/sensor/adc.dtsi b/tests/drivers/build_all/sensor/adc.dtsi index b853ab0cad7..51dc06812fc 100644 --- a/tests/drivers/build_all/sensor/adc.dtsi +++ b/tests/drivers/build_all/sensor/adc.dtsi @@ -85,3 +85,12 @@ test_lm35: lm35 { io-channels = <&adc0 0>; status = "okay"; }; + +test_murata_ncp15xh103: murata-ncp15xh103 { + compatible = "murata,ncp15xh103"; + io-channels = <&test_adc 0>; + pullup-uv = <3300000>; + pullup-ohm = <0>; + pulldown-ohm = <10000>; + connected-positive; +}; diff --git a/tests/drivers/build_all/sensor/app.overlay b/tests/drivers/build_all/sensor/app.overlay index aec784c2688..ebfa224848a 100644 --- a/tests/drivers/build_all/sensor/app.overlay +++ b/tests/drivers/build_all/sensor/app.overlay @@ -74,6 +74,15 @@ #include "i2c.dtsi" }; + test_pwm: pwm@12341234 { + compatible = "vnd,pwm"; + reg = <0x12341234 0x1000>; + #pwm-cells = <3>; + status = "okay"; + + #include "pwm.dtsi" + }; + test_spi: spi@33334444 { #address-cells = <1>; #size-cells = <0>; diff --git a/tests/drivers/build_all/sensor/i2c.dtsi b/tests/drivers/build_all/sensor/i2c.dtsi index 57ca61a0077..5de1f832802 100644 --- a/tests/drivers/build_all/sensor/i2c.dtsi +++ b/tests/drivers/build_all/sensor/i2c.dtsi @@ -22,6 +22,7 @@ #include #include #include +#include /**************************************** * PLEASE KEEP REG ADDRESSES SEQUENTIAL * @@ -1030,3 +1031,21 @@ test_i2c_iis328dq: iis328dq@8a { int2-gpios = <&test_gpio 0 0>; threshold-int-pad = <2>; }; + +test_i2c_nct75: test_i2c_nct75@8b { + compatible = "onnn,nct75"; + reg = <0x8b>; + status = "okay"; +}; + +test_i2c_tmp114: tmp114@8c { + compatible = "ti,tmp114"; + reg = <0x8c>; +}; + +test_i2c_ina226: ina226@8d { + compatible = "ti,ina226"; + reg = <0x8d>; + current-lsb-microamps = <5000>; + rshunt-micro-ohms = <500>; +}; diff --git a/tests/drivers/build_all/sensor/prj.conf b/tests/drivers/build_all/sensor/prj.conf index fe677345578..2fb7bedcac8 100644 --- a/tests/drivers/build_all/sensor/prj.conf +++ b/tests/drivers/build_all/sensor/prj.conf @@ -7,6 +7,8 @@ CONFIG_ADC=y CONFIG_GPIO=y CONFIG_I2C=y CONFIG_I3C=y +CONFIG_PWM=y +CONFIG_PWM_CAPTURE=y CONFIG_SERIAL=y CONFIG_SPI=y CONFIG_MFD=y diff --git a/tests/drivers/build_all/sensor/pwm.dtsi b/tests/drivers/build_all/sensor/pwm.dtsi new file mode 100644 index 00000000000..e1b1ec978a9 --- /dev/null +++ b/tests/drivers/build_all/sensor/pwm.dtsi @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2024 Vitrolife A/S + * + * SPDX-License-Identifier: Apache-2.0 + * + * Application overlay for pwm devices + */ + +test_pwm_tsic_xx6: tsic_xx6 { + status = "okay"; + compatible = "ist,tsic-xx6"; + pwms = <&test_pwm 0 0 0>; + data-bits = <14>; + lower-temperature-limit = <(-100)>; + higher-temperature-limit = <250>; +}; diff --git a/tests/drivers/build_all/sensor/src/generic_test.c b/tests/drivers/build_all/sensor/src/generic_test.c index 2d5e0c1df86..30d4d72f567 100644 --- a/tests/drivers/build_all/sensor/src/generic_test.c +++ b/tests/drivers/build_all/sensor/src/generic_test.c @@ -30,7 +30,7 @@ union sensor_data_union { * Set up an RTIO context that can be shared for all sensors */ -static enum sensor_channel iodev_all_channels[SENSOR_CHAN_ALL]; +static struct sensor_chan_spec iodev_all_channels[SENSOR_CHAN_ALL]; static struct sensor_read_config iodev_read_config = { .channels = iodev_all_channels, .max = SENSOR_CHAN_ALL, @@ -110,8 +110,9 @@ static void run_generic_test(const struct device *dev) q31_t lower, upper; int8_t shift; + struct sensor_chan_spec ch_spec = {.chan_type = ch, .chan_idx = 0}; - if (emul_sensor_backend_get_sample_range(emul, ch, &lower, &upper, + if (emul_sensor_backend_get_sample_range(emul, ch_spec, &lower, &upper, &channel_table[ch].epsilon, &shift) == 0) { /* This channel is supported */ channel_table[ch].supported = true; @@ -120,7 +121,7 @@ static void run_generic_test(const struct device *dev) channel_table[ch].epsilon, shift); /* Add to the list of channels to read */ - iodev_all_channels[iodev_read_config.count++] = ch; + iodev_all_channels[iodev_read_config.count++].chan_type = ch; /* Generate a set of CONFIG_GENERIC_SENSOR_TEST_NUM_EXPECTED_VALS test * values. @@ -155,16 +156,18 @@ static void run_generic_test(const struct device *dev) /* Set this iteration's expected values in emul for every supported channel */ for (size_t i = 0; i < iodev_read_config.count; i++) { - enum sensor_channel ch = iodev_all_channels[i]; + struct sensor_chan_spec ch_spec = iodev_all_channels[i]; rv = emul_sensor_backend_set_channel( - emul, ch, &channel_table[ch].expected_values[iteration], - channel_table[ch].expected_value_shift); - zassert_ok( - rv, - "Cannot set value 0x%08x on channel %d (error %d, iteration %d/%d)", - channel_table[i].expected_values[iteration], ch, rv, iteration + 1, - CONFIG_GENERIC_SENSOR_TEST_NUM_EXPECTED_VALS); + emul, ch_spec, + &channel_table[ch_spec.chan_type].expected_values[iteration], + channel_table[ch_spec.chan_type].expected_value_shift); + zassert_ok(rv, + "Cannot set value 0x%08x on channel (type: %d, index: %d) " + "(error %d, iteration %d/%d)", + channel_table[i].expected_values[iteration], ch_spec.chan_type, + ch_spec.chan_idx, rv, iteration + 1, + CONFIG_GENERIC_SENSOR_TEST_NUM_EXPECTED_VALS); } /* Perform the actual sensor read */ diff --git a/tests/drivers/build_all/sensor/w1.dtsi b/tests/drivers/build_all/sensor/w1.dtsi index a7a6a554eb0..2566057e5f4 100644 --- a/tests/drivers/build_all/sensor/w1.dtsi +++ b/tests/drivers/build_all/sensor/w1.dtsi @@ -12,3 +12,9 @@ test_w1_ds18b20: ds18b20 { resolution = <12>; status = "okay"; }; + +test_w1_ds18s20: ds18s20 { + compatible = "maxim,ds18s20"; + family-code = <0x10>; + status = "okay"; +}; diff --git a/tests/drivers/build_all/video/app.overlay b/tests/drivers/build_all/video/app.overlay index a38cfdd0e13..e06d2940817 100644 --- a/tests/drivers/build_all/video/app.overlay +++ b/tests/drivers/build_all/video/app.overlay @@ -47,6 +47,13 @@ reg = <0x2>; reset-gpios = <&test_gpio 0 0>; }; + + test_i2c_ov5640: ov5640@3 { + compatible = "ovti,ov5640"; + reg = <0x3>; + reset-gpios = <&test_gpio 0 0>; + powerdown-gpios = <&test_gpio 1 0>; + }; }; }; }; diff --git a/tests/drivers/build_all/video/mimxrt1170_evk_mimxrt1176_cm7.overlay b/tests/drivers/build_all/video/mimxrt1170_evk_mimxrt1176_cm7.overlay new file mode 100644 index 00000000000..99542ad4c78 --- /dev/null +++ b/tests/drivers/build_all/video/mimxrt1170_evk_mimxrt1176_cm7.overlay @@ -0,0 +1,56 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + * + * Names in this file should be chosen in a way that won't conflict + * with real-world devicetree nodes, to allow these tests to run on + * (and be extended to test) real hardware. + */ + +/ { + test { + #address-cells = <1>; + #size-cells = <1>; + + test_gpio: gpio@deadbeef { + compatible = "vnd,gpio"; + gpio-controller; + reg = <0xdeadbeef 0x1000>; + #gpio-cells = <0x2>; + status = "okay"; + }; + + test_i2c: i2c@11112222 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "vnd,i2c"; + reg = <0x11112222 0x1000>; + status = "okay"; + clock-frequency = <100000>; + + test_i2c_ov5640: ov5640@1 { + compatible = "ovti,ov5640"; + reg = <0x1>; + reset-gpios = <&test_gpio 0 0>; + powerdown-gpios = <&test_gpio 1 0>; + }; + }; + + test_csi: csi@22223333 { + compatible = "nxp,imx-csi"; + reg = <0x22223333 0x4000>; + status = "okay"; + interrupt-parent = <&nvic>; + interrupts = <56 1>; + source = <&test_mipi_csi2rx>; + }; + + test_mipi_csi2rx: mipi_csi2rx@33334444 { + compatible = "nxp,mipi-csi2rx"; + reg = <0x33334444 0x200>; + status = "okay"; + sensor = <&test_i2c_ov5640>; + }; + }; +}; diff --git a/tests/drivers/build_all/video/testcase.yaml b/tests/drivers/build_all/video/testcase.yaml index 08dd430da73..49acda27c13 100644 --- a/tests/drivers/build_all/video/testcase.yaml +++ b/tests/drivers/build_all/video/testcase.yaml @@ -13,4 +13,10 @@ tests: - gpio - i2c drivers.video.mcux_csi.build: - platform_allow: mimxrt1064_evk + platform_allow: + - mimxrt1064_evk + - mimxrt1170_evk/mimxrt1176/cm7 + drivers.video.mcux_mipi_csi2rx.build: + platform_allow: + - mimxrt1170_evk/mimxrt1176/cm7 + - mimxrt1170_evk@B/mimxrt1176/cm7 diff --git a/tests/drivers/can/api/src/canfd.c b/tests/drivers/can/api/src/canfd.c index ec881b07343..6941c42e775 100644 --- a/tests/drivers/can/api/src/canfd.c +++ b/tests/drivers/can/api/src/canfd.c @@ -397,22 +397,14 @@ ZTEST_USER(canfd, test_set_timing_data_min) */ ZTEST_USER(canfd, test_set_bitrate_too_high) { - uint32_t max = 8000000U; - int expected = -EINVAL; + uint32_t max = can_get_bitrate_max(can_dev); int err; - err = can_get_max_bitrate(can_dev, &max); - if (err != -ENOSYS) { - zassert_equal(err, 0, "failed to get max bitrate (err %d)", err); - zassert_not_equal(max, 0, "max bitrate is 0"); - expected = -ENOTSUP; - } - err = can_stop(can_dev); zassert_equal(err, 0, "failed to stop CAN controller (err %d)", err); err = can_set_bitrate_data(can_dev, max + 1); - zassert_equal(err, expected, "too high data phase bitrate accepted"); + zassert_equal(err, -ENOTSUP, "too high data phase bitrate accepted"); err = can_start(can_dev); zassert_equal(err, 0, "failed to start CAN controller (err %d)", err); @@ -499,19 +491,7 @@ static bool canfd_predicate(const void *state) void *canfd_setup(void) { - int err; - - k_sem_init(&rx_callback_sem, 0, 2); - k_sem_init(&tx_callback_sem, 0, 2); - - (void)can_stop(can_dev); - - err = can_set_mode(can_dev, CAN_MODE_LOOPBACK | CAN_MODE_FD); - zassert_equal(err, 0, "failed to set CAN FD loopback mode (err %d)", err); - zassert_equal(CAN_MODE_LOOPBACK | CAN_MODE_FD, can_get_mode(can_dev)); - - err = can_start(can_dev); - zassert_equal(err, 0, "failed to start CAN controller (err %d)", err); + can_common_test_setup(CAN_MODE_LOOPBACK | CAN_MODE_FD); return NULL; } diff --git a/tests/drivers/can/api/src/classic.c b/tests/drivers/can/api/src/classic.c index c59e3466774..9355651b7f1 100644 --- a/tests/drivers/can/api/src/classic.c +++ b/tests/drivers/can/api/src/classic.c @@ -393,9 +393,9 @@ static void send_receive(const struct can_filter *filter1, * @param data_frame CAN data frame * @param rtr_frame CAN RTR frame */ -void send_receive_rtr(const struct can_filter *filter, - const struct can_frame *data_frame, - const struct can_frame *rtr_frame) +static void send_receive_rtr(const struct can_filter *filter, + const struct can_frame *data_frame, + const struct can_frame *rtr_frame) { struct can_frame frame; int filter_id; @@ -480,19 +480,8 @@ ZTEST(can_classic, test_set_state_change_callback) */ ZTEST_USER(can_classic, test_bitrate_limits) { - uint32_t min = 0U; - uint32_t max = 0U; - int err; - - err = can_get_min_bitrate(can_dev, &min); - zassert_equal(err, 0, "failed to get min bitrate (err %d)", err); - - err = can_get_max_bitrate(can_dev, &max); - if (err == -ENOSYS) { - ztest_test_skip(); - } - - zassert_equal(err, 0, "failed to get max bitrate (err %d)", err); + uint32_t min = can_get_bitrate_min(can_dev); + uint32_t max = can_get_bitrate_max(can_dev); zassert_true(min <= max, "min bitrate must be lower or equal to max bitrate"); } @@ -502,22 +491,14 @@ ZTEST_USER(can_classic, test_bitrate_limits) */ ZTEST_USER(can_classic, test_set_bitrate_too_high) { - uint32_t max = 1000000U; - int expected = -EINVAL; + uint32_t max = can_get_bitrate_max(can_dev); int err; - err = can_get_max_bitrate(can_dev, &max); - if (err != -ENOSYS) { - zassert_equal(err, 0, "failed to get max bitrate (err %d)", err); - zassert_not_equal(max, 0, "max bitrate is 0"); - expected = -ENOTSUP; - } - err = can_stop(can_dev); zassert_equal(err, 0, "failed to stop CAN controller (err %d)", err); err = can_set_bitrate(can_dev, max + 1); - zassert_equal(err, expected, "too high bitrate accepted"); + zassert_equal(err, -ENOTSUP, "too high bitrate accepted"); err = can_start(can_dev); zassert_equal(err, 0, "failed to start CAN controller (err %d)", err); @@ -625,6 +606,66 @@ ZTEST(can_classic, test_add_filter) can_remove_rx_filter(can_dev, filter_id); } +/** + * @brief Test adding an invalid CAN RX filter. + * + * @param dev Pointer to the device structure for the driver instance. + * @param frame Pointer to the CAN RX filter. + */ +static void add_invalid_rx_filter(const struct device *dev, const struct can_filter *filter) +{ + int filter_id; + + Z_TEST_SKIP_IFNDEF(CONFIG_RUNTIME_ERROR_CHECKS); + + filter_id = can_add_rx_filter(dev, rx_std_callback_1, NULL, filter); + zassert_equal(filter_id, -EINVAL, "added invalid filter"); +} + +/** + * @brief Test adding NULL filter. + */ +ZTEST(can_classic, test_add_invalid_null_filter) +{ + add_invalid_rx_filter(can_dev, NULL); +} + +/** + * @brief Test adding invalid standard (11-bit) filters. + */ +ZTEST(can_classic, test_add_invalid_std_filter) +{ + struct can_filter filter = { + .flags = 0U, + }; + + filter.id = CAN_STD_ID_MASK; + filter.mask = CAN_STD_ID_MASK + 1U; + add_invalid_rx_filter(can_dev, &filter); + + filter.id = CAN_STD_ID_MASK + 1U; + filter.mask = CAN_STD_ID_MASK; + add_invalid_rx_filter(can_dev, &filter); +} + +/** + * @brief Test adding invalid extended (29-bit) filters. + */ +ZTEST(can_classic, test_add_invalid_ext_filter) +{ + struct can_filter filter = { + .flags = CAN_FILTER_IDE, + }; + + filter.id = CAN_EXT_ID_MASK; + filter.mask = CAN_EXT_ID_MASK + 1U; + add_invalid_rx_filter(can_dev, &filter); + + filter.id = CAN_EXT_ID_MASK + 1U; + filter.mask = CAN_EXT_ID_MASK; + add_invalid_rx_filter(can_dev, &filter); +} + /** * @brief Test adding up to and above the maximum number of RX filters. * @@ -719,6 +760,55 @@ ZTEST(can_classic, test_send_callback) zassert_equal(err, 0, "missing TX callback"); } +/** + * @brief Test sending an invalid CAN frame. + * + * @param dev Pointer to the device structure for the driver instance. + * @param frame Pointer to the CAN frame to send. + */ +static void send_invalid_frame(const struct device *dev, const struct can_frame *frame) +{ + int err; + + Z_TEST_SKIP_IFNDEF(CONFIG_RUNTIME_ERROR_CHECKS); + + err = can_send(dev, frame, TEST_SEND_TIMEOUT, NULL, NULL); + zassert_equal(err, -EINVAL, "wrong error on sending invalid frame (err %d)", err); +} + +/** + * @brief Test sending NULL frame. + */ +ZTEST(can_classic, test_send_null_frame) +{ + send_invalid_frame(can_dev, NULL); +} + +/** + * @brief Test sending frame with standard (11-bit) CAN ID out-of-range. + */ +ZTEST(can_classic, test_send_std_id_out_of_range) +{ + struct can_frame frame = { + .id = CAN_STD_ID_MASK + 1U, + }; + + send_invalid_frame(can_dev, &frame); +} + +/** + * @brief Test sending frame with extended (29-bit) CAN ID out-of-range. + */ +ZTEST(can_classic, test_send_ext_id_out_of_range) +{ + struct can_frame frame = { + .flags = CAN_FRAME_IDE, + .id = CAN_EXT_ID_MASK + 1U, + }; + + send_invalid_frame(can_dev, &frame); +} + /** * @brief Test send/receive with standard (11-bit) CAN IDs. */ @@ -1224,24 +1314,7 @@ ZTEST_USER(can_classic, test_set_mode_while_started) void *can_classic_setup(void) { - int err; - - k_sem_init(&rx_callback_sem, 0, 2); - k_sem_init(&tx_callback_sem, 0, 2); - - k_object_access_grant(&can_msgq, k_current_get()); - k_object_access_grant(can_dev, k_current_get()); - - zassert_true(device_is_ready(can_dev), "CAN device not ready"); - - (void)can_stop(can_dev); - - err = can_set_mode(can_dev, CAN_MODE_LOOPBACK); - zassert_equal(err, 0, "failed to set loopback mode (err %d)", err); - zassert_equal(CAN_MODE_LOOPBACK, can_get_mode(can_dev)); - - err = can_start(can_dev); - zassert_equal(err, 0, "failed to start CAN controller (err %d)", err); + can_common_test_setup(CAN_MODE_LOOPBACK); return NULL; } diff --git a/tests/drivers/can/api/src/common.c b/tests/drivers/can/api/src/common.c index 1854ef8fb11..a386f409a99 100644 --- a/tests/drivers/can/api/src/common.c +++ b/tests/drivers/can/api/src/common.c @@ -222,3 +222,25 @@ void assert_frame_equal(const struct can_frame *frame1, "Received data differ"); } } + +void can_common_test_setup(can_mode_t initial_mode) +{ + int err; + + k_sem_init(&rx_callback_sem, 0, 2); + k_sem_init(&tx_callback_sem, 0, 2); + + k_object_access_grant(&can_msgq, k_current_get()); + k_object_access_grant(can_dev, k_current_get()); + + zassert_true(device_is_ready(can_dev), "CAN device not ready"); + + (void)can_stop(can_dev); + + err = can_set_mode(can_dev, initial_mode); + zassert_equal(err, 0, "failed to set initial mode (err %d)", err); + zassert_equal(initial_mode, can_get_mode(can_dev)); + + err = can_start(can_dev); + zassert_equal(err, 0, "failed to start CAN controller (err %d)", err); +} diff --git a/tests/drivers/can/api/src/common.h b/tests/drivers/can/api/src/common.h index 92d5352e3e6..75c11d4a43c 100644 --- a/tests/drivers/can/api/src/common.h +++ b/tests/drivers/can/api/src/common.h @@ -163,3 +163,10 @@ extern const struct can_filter test_std_some_filter; void assert_frame_equal(const struct can_frame *frame1, const struct can_frame *frame2, uint32_t id_mask); + +/** + * @brief Common setup function for the CAN controller device under test. + * + * @param initial_mode Initial CAN controller operational mode. + */ +void can_common_test_setup(can_mode_t initial_mode); diff --git a/tests/drivers/can/api/twai-enable.overlay b/tests/drivers/can/api/twai-enable.overlay index c98aba18376..7a4ee3b7daf 100644 --- a/tests/drivers/can/api/twai-enable.overlay +++ b/tests/drivers/can/api/twai-enable.overlay @@ -9,7 +9,6 @@ status = "okay"; pinctrl-0 = <&twai_default>; pinctrl-names = "default"; - bus-speed = <125000>; can-transceiver { max-bitrate = <1000000>; diff --git a/tests/drivers/can/shell/app.overlay b/tests/drivers/can/shell/app.overlay index 5d9827e2f35..1de44e0e9c5 100644 --- a/tests/drivers/can/shell/app.overlay +++ b/tests/drivers/can/shell/app.overlay @@ -8,7 +8,5 @@ fake_can: fake_can { compatible = "zephyr,fake-can"; status = "okay"; - bus-speed = <125000>; - bus-speed-data = <1000000>; }; }; diff --git a/tests/drivers/can/timing/boards/native_posix_native_64.conf b/tests/drivers/can/timing/boards/native_posix_native_64.conf new file mode 100644 index 00000000000..7b071f3a54f --- /dev/null +++ b/tests/drivers/can/timing/boards/native_posix_native_64.conf @@ -0,0 +1 @@ +CONFIG_TEST_ALL_BITRATES=y diff --git a/tests/drivers/can/timing/boards/native_sim_native_64.conf b/tests/drivers/can/timing/boards/native_sim_native_64.conf new file mode 100644 index 00000000000..7b071f3a54f --- /dev/null +++ b/tests/drivers/can/timing/boards/native_sim_native_64.conf @@ -0,0 +1 @@ +CONFIG_TEST_ALL_BITRATES=y diff --git a/tests/drivers/can/timing/boards/stm32h745i_disco_stm32h745xx_m7.conf b/tests/drivers/can/timing/boards/stm32h745i_disco_stm32h745xx_m7.conf new file mode 100644 index 00000000000..7b071f3a54f --- /dev/null +++ b/tests/drivers/can/timing/boards/stm32h745i_disco_stm32h745xx_m7.conf @@ -0,0 +1 @@ +CONFIG_TEST_ALL_BITRATES=y diff --git a/tests/drivers/charger/sbs_charger/testcase.yaml b/tests/drivers/charger/sbs_charger/testcase.yaml index 75c9994b8f5..18d5d309876 100644 --- a/tests/drivers/charger/sbs_charger/testcase.yaml +++ b/tests/drivers/charger/sbs_charger/testcase.yaml @@ -1,12 +1,14 @@ +common: + platform_key: + - arch + - simulation + tags: + - drivers + - charger tests: # section.subsection drivers.charger.sbs.emulated: - tags: - - drivers - - charger - filter: > - dt_compat_enabled("sbs,sbs-charger") and - (CONFIG_QEMU_TARGET or CONFIG_ARCH_POSIX) + filter: dt_compat_enabled("sbs,sbs-charger") extra_args: CONF_FILE="prj.conf;boards/emulated_board.conf" DTC_OVERLAY_FILE="boards/emulated_board.overlay" @@ -21,12 +23,7 @@ tests: - rcar_salvator_xs - numaker_pfm_m467 drivers.charger.sbs.emulated_64_bit_i2c_addr: - tags: - - drivers - - charger - filter: > - dt_compat_enabled("sbs,sbs-charger") and - (CONFIG_QEMU_TARGET or CONFIG_ARCH_POSIX) + filter: dt_compat_enabled("sbs,sbs-charger") platform_allow: - qemu_cortex_a53 - qemu_cortex_a53/qemu_cortex_a53/smp diff --git a/tests/drivers/counter/counter_basic_api/boards/esp32s3_devkitm.overlay b/tests/drivers/counter/counter_basic_api/boards/esp32s3_devkitm_procpu.overlay similarity index 100% rename from tests/drivers/counter/counter_basic_api/boards/esp32s3_devkitm.overlay rename to tests/drivers/counter/counter_basic_api/boards/esp32s3_devkitm_procpu.overlay diff --git a/tests/drivers/counter/counter_basic_api/boards/esp32s3_luatos_core.overlay b/tests/drivers/counter/counter_basic_api/boards/esp32s3_luatos_core_procpu.overlay similarity index 100% rename from tests/drivers/counter/counter_basic_api/boards/esp32s3_luatos_core.overlay rename to tests/drivers/counter/counter_basic_api/boards/esp32s3_luatos_core_procpu.overlay diff --git a/tests/drivers/counter/counter_basic_api/boards/esp32s3_luatos_core_esp32s3_procpu_usb.overlay b/tests/drivers/counter/counter_basic_api/boards/esp32s3_luatos_core_procpu_usb.overlay similarity index 100% rename from tests/drivers/counter/counter_basic_api/boards/esp32s3_luatos_core_esp32s3_procpu_usb.overlay rename to tests/drivers/counter/counter_basic_api/boards/esp32s3_luatos_core_procpu_usb.overlay diff --git a/tests/drivers/counter/counter_basic_api/boards/imx93_evk_mimx9352_a55.overlay b/tests/drivers/counter/counter_basic_api/boards/imx93_evk_mimx9352_a55.overlay new file mode 100644 index 00000000000..e20242c8b05 --- /dev/null +++ b/tests/drivers/counter/counter_basic_api/boards/imx93_evk_mimx9352_a55.overlay @@ -0,0 +1,9 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&tpm2 { + status = "okay"; +}; diff --git a/tests/drivers/counter/counter_basic_api/boards/nrf54h20dk_nrf54h20_common.dtsi b/tests/drivers/counter/counter_basic_api/boards/nrf54h20dk_nrf54h20_common.dtsi new file mode 100644 index 00000000000..d442c112262 --- /dev/null +++ b/tests/drivers/counter/counter_basic_api/boards/nrf54h20dk_nrf54h20_common.dtsi @@ -0,0 +1,60 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +&timer120 { + status = "okay"; + prescaler = <7>; +}; + +&timer121 { + status = "okay"; + prescaler = <7>; +}; + +&timer130 { + status = "okay"; + prescaler = <4>; +}; + +&timer131 { + status = "okay"; + prescaler = <4>; +}; + +&timer132 { + status = "okay"; + prescaler = <4>; +}; + +&timer133 { + status = "okay"; + prescaler = <4>; +}; + +&timer134 { + status = "okay"; + prescaler = <4>; +}; + +&timer135 { + status = "okay"; + prescaler = <4>; +}; + +&timer136 { + status = "okay"; + prescaler = <4>; +}; + +&timer137 { + status = "okay"; + prescaler = <4>; +}; + +&rtc130 { + status = "okay"; + ppi-wrap; +}; + +&rtc131 { + status = "okay"; +}; diff --git a/tests/drivers/counter/counter_basic_api/boards/nrf54h20dk_nrf54h20_cpuapp.overlay b/tests/drivers/counter/counter_basic_api/boards/nrf54h20dk_nrf54h20_cpuapp.overlay index 8cabf100ae2..f65b4dd3b0b 100644 --- a/tests/drivers/counter/counter_basic_api/boards/nrf54h20dk_nrf54h20_cpuapp.overlay +++ b/tests/drivers/counter/counter_basic_api/boards/nrf54h20dk_nrf54h20_cpuapp.overlay @@ -1,58 +1,3 @@ -&timer120 { - status = "okay"; - prescaler = <7>; -}; +/* SPDX-License-Identifier: Apache-2.0 */ -&timer121 { - status = "okay"; - prescaler = <7>; -}; - -&timer130 { - status = "okay"; - prescaler = <4>; -}; - -&timer131 { - status = "okay"; - prescaler = <4>; -}; - -&timer132 { - status = "okay"; - prescaler = <4>; -}; - -&timer133 { - status = "okay"; - prescaler = <4>; -}; - -&timer134 { - status = "okay"; - prescaler = <4>; -}; - -&timer135 { - status = "okay"; - prescaler = <4>; -}; - -&timer136 { - status = "okay"; - prescaler = <4>; -}; - -&timer137 { - status = "okay"; - prescaler = <4>; -}; - -&rtc130 { - status = "okay"; - ppi-wrap; -}; - -&rtc131 { - status = "okay"; -}; +#include "nrf54h20dk_nrf54h20_common.dtsi" diff --git a/tests/drivers/counter/counter_basic_api/boards/nrf54h20dk_nrf54h20_cpurad.overlay b/tests/drivers/counter/counter_basic_api/boards/nrf54h20dk_nrf54h20_cpurad.overlay index 7cacbc5d7ec..88c288a4528 100644 --- a/tests/drivers/counter/counter_basic_api/boards/nrf54h20dk_nrf54h20_cpurad.overlay +++ b/tests/drivers/counter/counter_basic_api/boards/nrf54h20dk_nrf54h20_cpurad.overlay @@ -1,3 +1,7 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include "nrf54h20dk_nrf54h20_common.dtsi" + &timer020 { status = "okay"; prescaler = <7>; @@ -13,65 +17,6 @@ prescaler = <7>; }; -&timer120 { - status = "okay"; - prescaler = <7>; -}; - -&timer121 { - status = "okay"; - prescaler = <7>; -}; - -&timer130 { - status = "okay"; - prescaler = <4>; -}; - -&timer131 { - status = "okay"; - prescaler = <4>; -}; - -&timer132 { - status = "okay"; - prescaler = <4>; -}; - -&timer133 { - status = "okay"; - prescaler = <4>; -}; - -&timer134 { - status = "okay"; - prescaler = <4>; -}; - -&timer135 { - status = "okay"; - prescaler = <4>; -}; - -&timer136 { - status = "okay"; - prescaler = <4>; -}; - -&timer137 { - status = "okay"; - prescaler = <4>; -}; - -&rtc130 { - status = "okay"; - ppi-wrap; -}; - -&rtc131 { - status = "okay"; -}; - &rtc { status = "okay"; }; diff --git a/tests/drivers/counter/counter_basic_api/boards/nrf54l15bsim_nrf54l15_cpuapp.overlay b/tests/drivers/counter/counter_basic_api/boards/nrf54l15bsim_nrf54l15_cpuapp.overlay new file mode 100644 index 00000000000..b1942e1f84f --- /dev/null +++ b/tests/drivers/counter/counter_basic_api/boards/nrf54l15bsim_nrf54l15_cpuapp.overlay @@ -0,0 +1 @@ +#include "nrf54l15pdk_nrf54l15_cpuapp.overlay" diff --git a/tests/drivers/counter/counter_basic_api/boards/yd_esp32.overlay b/tests/drivers/counter/counter_basic_api/boards/yd_esp32_procpu.overlay similarity index 100% rename from tests/drivers/counter/counter_basic_api/boards/yd_esp32.overlay rename to tests/drivers/counter/counter_basic_api/boards/yd_esp32_procpu.overlay diff --git a/tests/drivers/counter/counter_basic_api/src/test_counter.c b/tests/drivers/counter/counter_basic_api/src/test_counter.c index 34f94e2fbd8..c9c8418b00f 100644 --- a/tests/drivers/counter/counter_basic_api/src/test_counter.c +++ b/tests/drivers/counter/counter_basic_api/src/test_counter.c @@ -57,6 +57,9 @@ static const struct device *const devices[] = { DEVS_FOR_DT_COMPAT(microchip_xec_timer) DEVS_FOR_DT_COMPAT(nxp_imx_epit) DEVS_FOR_DT_COMPAT(nxp_imx_gpt) +#ifdef CONFIG_COUNTER_MCUX_TPM + DEVS_FOR_DT_COMPAT(nxp_tpm_timer) +#endif DEVS_FOR_DT_COMPAT(renesas_smartbond_timer) #ifdef CONFIG_COUNTER_MCUX_CTIMER DEVS_FOR_DT_COMPAT(nxp_lpc_ctimer) @@ -181,6 +184,7 @@ static void test_all_instances(counter_test_func_t func, func(devices[i]); } else { TC_PRINT("Skipped for %s\n", devices[i]->name); + ztest_test_skip(); } counter_tear_down_instance(devices[i]); /* Allow logs to be printed. */ diff --git a/tests/drivers/counter/counter_nrf_rtc/fixed_top/nrf52840dk_nrf52840.overlay b/tests/drivers/counter/counter_nrf_rtc/fixed_top/boards/nrf52840dk_nrf52840.overlay similarity index 100% rename from tests/drivers/counter/counter_nrf_rtc/fixed_top/nrf52840dk_nrf52840.overlay rename to tests/drivers/counter/counter_nrf_rtc/fixed_top/boards/nrf52840dk_nrf52840.overlay diff --git a/tests/drivers/counter/counter_nrf_rtc/fixed_top/boards/nrf52_bsim.overlay b/tests/drivers/counter/counter_nrf_rtc/fixed_top/boards/nrf52_bsim.overlay new file mode 100644 index 00000000000..ebfed9cf903 --- /dev/null +++ b/tests/drivers/counter/counter_nrf_rtc/fixed_top/boards/nrf52_bsim.overlay @@ -0,0 +1,8 @@ +&rtc0 { + status = "okay"; + fixed-top; +}; +&rtc2 { + status = "okay"; + fixed-top; +}; diff --git a/tests/drivers/counter/counter_nrf_rtc/fixed_top/boards/nrf54h20dk_nrf54h20_common.dtsi b/tests/drivers/counter/counter_nrf_rtc/fixed_top/boards/nrf54h20dk_nrf54h20_common.dtsi new file mode 100644 index 00000000000..181611f712d --- /dev/null +++ b/tests/drivers/counter/counter_nrf_rtc/fixed_top/boards/nrf54h20dk_nrf54h20_common.dtsi @@ -0,0 +1,11 @@ + /* SPDX-License-Identifier: Apache-2.0 */ + +&rtc130 { + status = "okay"; + fixed-top; +}; + +&rtc131 { + status = "okay"; + fixed-top; +}; diff --git a/tests/drivers/counter/counter_nrf_rtc/fixed_top/boards/nrf54h20dk_nrf54h20_cpuapp.overlay b/tests/drivers/counter/counter_nrf_rtc/fixed_top/boards/nrf54h20dk_nrf54h20_cpuapp.overlay new file mode 100644 index 00000000000..f65b4dd3b0b --- /dev/null +++ b/tests/drivers/counter/counter_nrf_rtc/fixed_top/boards/nrf54h20dk_nrf54h20_cpuapp.overlay @@ -0,0 +1,3 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include "nrf54h20dk_nrf54h20_common.dtsi" diff --git a/tests/drivers/counter/counter_nrf_rtc/fixed_top/boards/nrf54h20dk_nrf54h20_cpurad.overlay b/tests/drivers/counter/counter_nrf_rtc/fixed_top/boards/nrf54h20dk_nrf54h20_cpurad.overlay new file mode 100644 index 00000000000..f7f44e2dc43 --- /dev/null +++ b/tests/drivers/counter/counter_nrf_rtc/fixed_top/boards/nrf54h20dk_nrf54h20_cpurad.overlay @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include "nrf54h20dk_nrf54h20_common.dtsi" + +&rtc { + status = "okay"; + fixed-top; +}; diff --git a/tests/drivers/counter/counter_nrf_rtc/fixed_top/src/test_counter_fixed_top.c b/tests/drivers/counter/counter_nrf_rtc/fixed_top/src/test_counter_fixed_top.c index ba6666449ce..66fabc91725 100644 --- a/tests/drivers/counter/counter_nrf_rtc/fixed_top/src/test_counter_fixed_top.c +++ b/tests/drivers/counter/counter_nrf_rtc/fixed_top/src/test_counter_fixed_top.c @@ -55,6 +55,7 @@ static void counter_tear_down_instance(const struct device *dev) static void test_all_instances(counter_test_func_t func) { + zassert_true(ARRAY_SIZE(devices) > 0); for (int i = 0; i < ARRAY_SIZE(devices); i++) { counter_setup_instance(devices[i]); func(i); @@ -99,6 +100,12 @@ static void test_top_handler_on_instance(int idx) .callback = top_handler, .flags = 0 }; +#if defined(CONFIG_SOC_SERIES_BSIM_NRFXX) + /* For simulated devices we need to convert the hardcoded DT address from the real + * peripheral into the correct one for simulation + */ + reg = nhw_convert_periph_base_addr(reg); +#endif top_cfg.ticks = counter_get_max_top_value(dev); diff --git a/tests/drivers/dac/dac_api/boards/esp_wrover_kit.overlay b/tests/drivers/dac/dac_api/boards/esp_wrover_kit_procpu.overlay similarity index 100% rename from tests/drivers/dac/dac_api/boards/esp_wrover_kit.overlay rename to tests/drivers/dac/dac_api/boards/esp_wrover_kit_procpu.overlay diff --git a/tests/drivers/dac/dac_api/boards/yd_esp32.overlay b/tests/drivers/dac/dac_api/boards/yd_esp32_procpu.overlay similarity index 100% rename from tests/drivers/dac/dac_api/boards/yd_esp32.overlay rename to tests/drivers/dac/dac_api/boards/yd_esp32_procpu.overlay diff --git a/tests/drivers/dac/dac_api/src/test_dac.c b/tests/drivers/dac/dac_api/src/test_dac.c index 612aa824ec0..b63410ef53c 100644 --- a/tests/drivers/dac/dac_api/src/test_dac.c +++ b/tests/drivers/dac/dac_api/src/test_dac.c @@ -45,6 +45,7 @@ #elif defined(CONFIG_BOARD_TWR_KE18F) || \ defined(CONFIG_BOARD_FRDM_K64F) || \ defined(CONFIG_BOARD_FRDM_K22F) || \ + defined(CONFIG_BOARD_FRDM_MCXN947) || \ defined(CONFIG_BOARD_SEEEDUINO_XIAO) || \ defined(CONFIG_BOARD_ARDUINO_MKRZERO) || \ defined(CONFIG_BOARD_ARDUINO_ZERO) || \ @@ -69,6 +70,7 @@ defined(CONFIG_BOARD_ESP32_DEVKITC_WROVER) || \ defined(CONFIG_BOARD_ESP_WROVER_KIT) || \ defined(CONFIG_BOARD_ESP32S2_SAOLA) || \ + defined(CONFIG_BOARD_ESP32S2_DEVKITC) || \ defined(CONFIG_BOARD_GD32A503V_EVAL) || \ defined(CONFIG_BOARD_GD32E103V_EVAL) || \ defined(CONFIG_BOARD_GD32F450I_EVAL) || \ @@ -87,6 +89,12 @@ #define DAC_RESOLUTION 12 #define DAC_CHANNEL_ID 0 +#elif defined(CONFIG_BOARD_RD_RW612_BGA) + +#define DAC_DEVICE_NODE DT_NODELABEL(dac0) +#define DAC_RESOLUTION 10 +#define DAC_CHANNEL_ID 0 + #else #error "Unsupported board." #endif diff --git a/tests/drivers/disk/disk_access/boards/native_sim.overlay b/tests/drivers/disk/disk_access/boards/native_sim.overlay new file mode 100644 index 00000000000..f8e71a2d4b8 --- /dev/null +++ b/tests/drivers/disk/disk_access/boards/native_sim.overlay @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&flashcontroller0 { + reg = <0x00000000 DT_SIZE_K(1024)>; +}; + +&flash0 { + reg = <0x00000000 DT_SIZE_K(1024)>; + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + flashdisk_partition: partition@0 { + label = "flashdisk"; + reg = <0x00000000 DT_SIZE_K(1024)>; + }; + }; +}; + +/ { + test_disk: storage_disk { + compatible = "zephyr,flash-disk"; + partition = <&flashdisk_partition>; + disk-name = "NAND"; + cache-size = <4096>; + }; + + ramdisk0 { + compatible = "zephyr,ram-disk"; + disk-name = "RAM"; + sector-size = <512>; + sector-count = <192>; + }; +}; diff --git a/tests/drivers/disk/disk_access/boards/native_sim_native_64.overlay b/tests/drivers/disk/disk_access/boards/native_sim_native_64.overlay new file mode 100644 index 00000000000..e4994493dd6 --- /dev/null +++ b/tests/drivers/disk/disk_access/boards/native_sim_native_64.overlay @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "native_sim.overlay" diff --git a/tests/drivers/disk/disk_access/src/main.c b/tests/drivers/disk/disk_access/src/main.c index 97fafae9d8c..4e0348c0a0d 100644 --- a/tests/drivers/disk/disk_access/src/main.c +++ b/tests/drivers/disk/disk_access/src/main.c @@ -14,18 +14,35 @@ #include #include +#ifdef CONFIG_DISK_DRIVER_LOOPBACK +#include +#include +#include +#endif + #if defined(CONFIG_DISK_DRIVER_SDMMC) -#define DISK_NAME CONFIG_SDMMC_VOLUME_NAME +#define DISK_NAME_PHYS CONFIG_SDMMC_VOLUME_NAME #elif IS_ENABLED(CONFIG_DISK_DRIVER_MMC) -#define DISK_NAME CONFIG_MMC_VOLUME_NAME -#elif IS_ENABLED(CONFIG_DISK_DRIVER_RAM) -#define DISK_NAME "RAM" +#define DISK_NAME_PHYS CONFIG_MMC_VOLUME_NAME +#elif IS_ENABLED(CONFIG_DISK_DRIVER_FLASH) +#define DISK_NAME_PHYS "NAND" #elif IS_ENABLED(CONFIG_NVME) -#define DISK_NAME "nvme0n0" +#define DISK_NAME_PHYS "nvme0n0" +#elif IS_ENABLED(CONFIG_DISK_DRIVER_RAM) +/* Since ramdisk is enabled by default on e.g. qemu boards, it needs to be checked last to not + * override other backends. + */ +#define DISK_NAME_PHYS "RAM" #else #error "No disk device defined, is your board supported?" #endif +#ifdef CONFIG_DISK_DRIVER_LOOPBACK +#define DISK_NAME "loopback0" +#else +#define DISK_NAME DISK_NAME_PHYS +#endif + /* Assume the largest sector we will encounter is 512 bytes */ #define SECTOR_SIZE 512 @@ -44,6 +61,43 @@ static uint32_t disk_sector_size; /* + 4 to make sure the second buffer is dword-aligned for NVME */ static uint8_t scratch_buf[2][SECTOR_COUNT4 * SECTOR_SIZE + 4]; +#ifdef CONFIG_DISK_DRIVER_LOOPBACK +#define BACKING_PATH "/"DISK_NAME_PHYS":" + +static struct loopback_disk_access lo_access; +static FATFS fat_fs; +static struct fs_mount_t backing_mount = { + .type = FS_FATFS, + .mnt_point = BACKING_PATH, + .fs_data = &fat_fs, +}; +static const uint8_t zero_kb[1024] = {}; +static void setup_loopback_backing(void) +{ + int rc; + + rc = fs_mkfs(FS_FATFS, (uintptr_t)&BACKING_PATH[1], NULL, 0); + zassert_equal(rc, 0, "Failed to format backing file system"); + + rc = fs_mount(&backing_mount); + zassert_equal(rc, 0, "Failed to mount backing file system"); + + struct fs_file_t f; + + fs_file_t_init(&f); + rc = fs_open(&f, BACKING_PATH "/loopback.img", FS_O_WRITE | FS_O_CREATE); + zassert_equal(rc, 0, "Failed to create backing file"); + for (int i = 0; i < 64; i++) { + rc = fs_write(&f, zero_kb, sizeof(zero_kb)); + zassert_equal(rc, sizeof(zero_kb), "Failed to enlarge backing file"); + } + rc = fs_close(&f); + zassert_equal(rc, 0, "Failed to close backing file"); + + rc = loopback_disk_access_register(&lo_access, BACKING_PATH "/loopback.img", DISK_NAME); + zassert_equal(rc, 0, "Loopback disk access initialization failed"); +} +#endif /* Sets up test by initializing disk */ static void test_setup(void) @@ -221,9 +275,11 @@ ZTEST(disk_driver, test_write) } } - static void *disk_driver_setup(void) { +#ifdef CONFIG_DISK_DRIVER_LOOPBACK + setup_loopback_backing(); +#endif test_setup(); return NULL; diff --git a/tests/drivers/disk/disk_access/testcase.yaml b/tests/drivers/disk/disk_access/testcase.yaml index 86c7a365a5f..9fc566158bc 100644 --- a/tests/drivers/disk/disk_access/testcase.yaml +++ b/tests/drivers/disk/disk_access/testcase.yaml @@ -19,3 +19,20 @@ tests: extra_configs: - CONFIG_NVME=y platform_allow: qemu_x86_64 + drivers.disk.flash: + extra_configs: + - CONFIG_DISK_DRIVER_FLASH=y + platform_allow: + - native_sim/native/64 + - native_sim + drivers.disk.loopback: + extra_configs: + - CONFIG_DISK_DRIVER_LOOPBACK=y + - CONFIG_FILE_SYSTEM=y + - CONFIG_FILE_SYSTEM_MKFS=y + - CONFIG_FAT_FILESYSTEM_ELM=y + platform_allow: + - native_sim/native/64 + - native_sim + drivers.disk.stm32_sdhc: + filter: dt_compat_enabled("st,stm32-sdmmc") diff --git a/tests/drivers/disk/disk_performance/boards/rcar_h3ulcb_r8a77951_a57.overlay b/tests/drivers/disk/disk_performance/boards/rcar_h3ulcb_r8a77951_a57.overlay new file mode 100644 index 00000000000..9442e02b45f --- /dev/null +++ b/tests/drivers/disk/disk_performance/boards/rcar_h3ulcb_r8a77951_a57.overlay @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +&emmc2 { + disk { + status = "okay"; + }; + status = "okay"; +}; diff --git a/tests/drivers/disk/disk_performance/boards/rcar_salvator_xs.overlay b/tests/drivers/disk/disk_performance/boards/rcar_salvator_xs.overlay new file mode 100644 index 00000000000..9442e02b45f --- /dev/null +++ b/tests/drivers/disk/disk_performance/boards/rcar_salvator_xs.overlay @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +&emmc2 { + disk { + status = "okay"; + }; + status = "okay"; +}; diff --git a/tests/drivers/dma/chan_blen_transfer/boards/esp32s3_devkitm.conf b/tests/drivers/dma/chan_blen_transfer/boards/esp32s3_devkitm_procpu.conf similarity index 100% rename from tests/drivers/dma/chan_blen_transfer/boards/esp32s3_devkitm.conf rename to tests/drivers/dma/chan_blen_transfer/boards/esp32s3_devkitm_procpu.conf diff --git a/tests/drivers/dma/chan_blen_transfer/boards/esp32s3_devkitm.overlay b/tests/drivers/dma/chan_blen_transfer/boards/esp32s3_devkitm_procpu.overlay similarity index 100% rename from tests/drivers/dma/chan_blen_transfer/boards/esp32s3_devkitm.overlay rename to tests/drivers/dma/chan_blen_transfer/boards/esp32s3_devkitm_procpu.overlay diff --git a/tests/drivers/dma/chan_blen_transfer/boards/esp32s3_luatos_core.conf b/tests/drivers/dma/chan_blen_transfer/boards/esp32s3_luatos_core_procpu.conf similarity index 100% rename from tests/drivers/dma/chan_blen_transfer/boards/esp32s3_luatos_core.conf rename to tests/drivers/dma/chan_blen_transfer/boards/esp32s3_luatos_core_procpu.conf diff --git a/tests/drivers/dma/chan_blen_transfer/boards/esp32s3_luatos_core.overlay b/tests/drivers/dma/chan_blen_transfer/boards/esp32s3_luatos_core_procpu.overlay similarity index 100% rename from tests/drivers/dma/chan_blen_transfer/boards/esp32s3_luatos_core.overlay rename to tests/drivers/dma/chan_blen_transfer/boards/esp32s3_luatos_core_procpu.overlay diff --git a/tests/drivers/dma/chan_blen_transfer/boards/esp32s3_luatos_core_esp32s3_procpu_usb.conf b/tests/drivers/dma/chan_blen_transfer/boards/esp32s3_luatos_core_procpu_usb.conf similarity index 100% rename from tests/drivers/dma/chan_blen_transfer/boards/esp32s3_luatos_core_esp32s3_procpu_usb.conf rename to tests/drivers/dma/chan_blen_transfer/boards/esp32s3_luatos_core_procpu_usb.conf diff --git a/tests/drivers/dma/chan_blen_transfer/boards/esp32s3_luatos_core_esp32s3_procpu_usb.overlay b/tests/drivers/dma/chan_blen_transfer/boards/esp32s3_luatos_core_procpu_usb.overlay similarity index 100% rename from tests/drivers/dma/chan_blen_transfer/boards/esp32s3_luatos_core_esp32s3_procpu_usb.overlay rename to tests/drivers/dma/chan_blen_transfer/boards/esp32s3_luatos_core_procpu_usb.overlay diff --git a/tests/drivers/dma/chan_blen_transfer/src/test_dma.c b/tests/drivers/dma/chan_blen_transfer/src/test_dma.c index be1415fdaae..2b7f83d5fb1 100644 --- a/tests/drivers/dma/chan_blen_transfer/src/test_dma.c +++ b/tests/drivers/dma/chan_blen_transfer/src/test_dma.c @@ -52,7 +52,7 @@ static int test_task(const struct device *dma, uint32_t chan_id, uint32_t blen) dma_cfg.dest_burst_length = blen; dma_cfg.dma_callback = test_done; dma_cfg.complete_callback_en = 0U; - dma_cfg.error_callback_en = 1U; + dma_cfg.error_callback_dis = 0U; dma_cfg.block_count = 1U; dma_cfg.head_block = &dma_block_cfg; #ifdef CONFIG_DMA_MCUX_TEST_SLOT_START diff --git a/tests/drivers/dma/chan_link_transfer/src/test_dma.c b/tests/drivers/dma/chan_link_transfer/src/test_dma.c index 9e55a36f7d4..78b52b77857 100644 --- a/tests/drivers/dma/chan_link_transfer/src/test_dma.c +++ b/tests/drivers/dma/chan_link_transfer/src/test_dma.c @@ -71,7 +71,7 @@ static int test_task(int minor, int major) dma_cfg.dest_burst_length = 16; dma_cfg.dma_callback = test_done; dma_cfg.complete_callback_en = 0U; - dma_cfg.error_callback_en = 1U; + dma_cfg.error_callback_dis = 0U; dma_cfg.block_count = 1U; dma_cfg.head_block = &dma_block_cfg; #ifdef CONFIG_DMA_MCUX_TEST_SLOT_START diff --git a/tests/drivers/dma/loop_transfer/boards/esp32s3_devkitm.conf b/tests/drivers/dma/loop_transfer/boards/esp32s3_devkitm_procpu.conf similarity index 100% rename from tests/drivers/dma/loop_transfer/boards/esp32s3_devkitm.conf rename to tests/drivers/dma/loop_transfer/boards/esp32s3_devkitm_procpu.conf diff --git a/tests/drivers/dma/loop_transfer/boards/esp32s3_devkitm.overlay b/tests/drivers/dma/loop_transfer/boards/esp32s3_devkitm_procpu.overlay similarity index 100% rename from tests/drivers/dma/loop_transfer/boards/esp32s3_devkitm.overlay rename to tests/drivers/dma/loop_transfer/boards/esp32s3_devkitm_procpu.overlay diff --git a/tests/drivers/dma/loop_transfer/boards/esp32s3_luatos_core.conf b/tests/drivers/dma/loop_transfer/boards/esp32s3_luatos_core_procpu.conf similarity index 100% rename from tests/drivers/dma/loop_transfer/boards/esp32s3_luatos_core.conf rename to tests/drivers/dma/loop_transfer/boards/esp32s3_luatos_core_procpu.conf diff --git a/tests/drivers/dma/loop_transfer/boards/esp32s3_luatos_core.overlay b/tests/drivers/dma/loop_transfer/boards/esp32s3_luatos_core_procpu.overlay similarity index 100% rename from tests/drivers/dma/loop_transfer/boards/esp32s3_luatos_core.overlay rename to tests/drivers/dma/loop_transfer/boards/esp32s3_luatos_core_procpu.overlay diff --git a/tests/drivers/dma/loop_transfer/boards/esp32s3_luatos_core_esp32s3_procpu_usb.conf b/tests/drivers/dma/loop_transfer/boards/esp32s3_luatos_core_procpu_usb.conf similarity index 100% rename from tests/drivers/dma/loop_transfer/boards/esp32s3_luatos_core_esp32s3_procpu_usb.conf rename to tests/drivers/dma/loop_transfer/boards/esp32s3_luatos_core_procpu_usb.conf diff --git a/tests/drivers/dma/loop_transfer/boards/esp32s3_luatos_core_esp32s3_procpu_usb.overlay b/tests/drivers/dma/loop_transfer/boards/esp32s3_luatos_core_procpu_usb.overlay similarity index 100% rename from tests/drivers/dma/loop_transfer/boards/esp32s3_luatos_core_esp32s3_procpu_usb.overlay rename to tests/drivers/dma/loop_transfer/boards/esp32s3_luatos_core_procpu_usb.overlay diff --git a/tests/drivers/dma/loop_transfer/src/test_dma_loop.c b/tests/drivers/dma/loop_transfer/src/test_dma_loop.c index c938ff18385..429c41f1e58 100644 --- a/tests/drivers/dma/loop_transfer/src/test_dma_loop.c +++ b/tests/drivers/dma/loop_transfer/src/test_dma_loop.c @@ -55,12 +55,10 @@ static void test_transfer(const struct device *dev, uint32_t id) dma_block_cfg.dest_address = (uint32_t)rx_data[transfer_count]; #endif - zassert_false(dma_config(dev, id, &dma_cfg), - "Not able to config transfer %d", - transfer_count + 1); - zassert_false(dma_start(dev, id), - "Not able to start next transfer %d", - transfer_count + 1); + zassert_ok(dma_config(dev, id, &dma_cfg), "Not able to config transfer %d", + transfer_count + 1); + zassert_ok(dma_start(dev, id), "Not able to start next transfer %d", + transfer_count + 1); } } @@ -254,7 +252,8 @@ static int test_loop_suspend_resume(const struct device *dma) done = 1; TC_PRINT("suspend not supported\n"); dma_stop(dma, chan_id); - return TC_PASS; + ztest_test_skip(); + return TC_SKIP; } tc = transfer_count; irq_unlock(irq_key); diff --git a/tests/drivers/flash/common/boards/nrf52840dk_flash_spi.conf b/tests/drivers/flash/common/boards/nrf52840dk_flash_spi.conf index b75955ff30e..8d6e65493ef 100644 --- a/tests/drivers/flash/common/boards/nrf52840dk_flash_spi.conf +++ b/tests/drivers/flash/common/boards/nrf52840dk_flash_spi.conf @@ -1,2 +1,3 @@ CONFIG_SPI=y CONFIG_SPI_NOR=y +CONFIG_SOC_FLASH_NRF=n diff --git a/tests/drivers/flash/common/boards/nrf52840dk_nrf52840_qspi_nor.conf b/tests/drivers/flash/common/boards/nrf52840dk_nrf52840_qspi_nor.conf index 2f45801a48c..18c116a418c 100644 --- a/tests/drivers/flash/common/boards/nrf52840dk_nrf52840_qspi_nor.conf +++ b/tests/drivers/flash/common/boards/nrf52840dk_nrf52840_qspi_nor.conf @@ -3,3 +3,4 @@ CONFIG_NORDIC_QSPI_NOR=y CONFIG_NORDIC_QSPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096 +CONFIG_SOC_FLASH_NRF=n diff --git a/tests/drivers/flash/common/prj.conf b/tests/drivers/flash/common/prj.conf index cffa07b7f26..2496d765165 100644 --- a/tests/drivers/flash/common/prj.conf +++ b/tests/drivers/flash/common/prj.conf @@ -1,4 +1,5 @@ CONFIG_TEST=y CONFIG_ZTEST=y CONFIG_FLASH=y +CONFIG_FLASH_PAGE_LAYOUT=y CONFIG_MAIN_STACK_SIZE=2048 diff --git a/tests/drivers/flash/stm32/prj.conf b/tests/drivers/flash/stm32/prj.conf index 15aa2063b47..7f73471f718 100644 --- a/tests/drivers/flash/stm32/prj.conf +++ b/tests/drivers/flash/stm32/prj.conf @@ -3,6 +3,5 @@ CONFIG_ZTEST=y CONFIG_FLASH=y CONFIG_FLASH_EX_OP_ENABLED=y -CONFIG_FLASH_STM32_BLOCK_REGISTERS=y CONFIG_MAIN_STACK_SIZE=2048 diff --git a/tests/drivers/flash/stm32/src/main.c b/tests/drivers/flash/stm32/src/main.c index d4d0bf1c201..ea45ecb8463 100644 --- a/tests/drivers/flash/stm32/src/main.c +++ b/tests/drivers/flash/stm32/src/main.c @@ -16,6 +16,7 @@ #define TEST_AREA_SIZE FIXED_PARTITION_SIZE(TEST_AREA) #define TEST_AREA_MAX (TEST_AREA_OFFSET + TEST_AREA_SIZE) #define TEST_AREA_DEVICE FIXED_PARTITION_DEVICE(TEST_AREA) +#define TEST_AREA_DEVICE_REG DT_REG_ADDR(DT_MTD_FROM_FIXED_PARTITION(DT_NODELABEL(TEST_AREA))) #define EXPECTED_SIZE 512 @@ -179,4 +180,71 @@ ZTEST(flash_stm32, test_stm32_readout_protection_disabled) } #endif +#ifdef CONFIG_FLASH_STM32_BLOCK_REGISTERS + +#if defined(CONFIG_FLASH_STM32_WRITE_PROTECT) || defined(CONFIG_FLASH_STM32_READOUT_PROTECTION) +#error Block Register tests unable to run other tests, because of locked registers. +#endif + +int flash_stm32_option_bytes_lock(const struct device *dev, bool enable); + +static bool flash_opt_locked(void) +{ + FLASH_TypeDef *regs = (FLASH_TypeDef *)TEST_AREA_DEVICE_REG; + + return regs->OPTCR & FLASH_OPTCR_OPTLOCK; +} + +static void flash_cr_unlock(void) +{ + FLASH_TypeDef *regs = (FLASH_TypeDef *)TEST_AREA_DEVICE_REG; + + regs->KEYR = FLASH_KEY1; + regs->KEYR = FLASH_KEY2; +} + +static bool flash_cr_locked(void) +{ + FLASH_TypeDef *regs = (FLASH_TypeDef *)TEST_AREA_DEVICE_REG; + + return regs->CR & FLASH_CR_LOCK; +} + +ZTEST(flash_stm32, test_stm32_block_registers) +{ + /* Test OPT lock. */ + TC_PRINT("Unlocking OPT\n"); + flash_stm32_option_bytes_lock(flash_dev, false); + zassert_false(flash_opt_locked(), "Unable to unlock OPT"); + + TC_PRINT("Blocking OPT\n"); + flash_ex_op(flash_dev, FLASH_STM32_EX_OP_BLOCK_OPTION_REG, (uintptr_t)NULL, NULL); + + zassert_true(flash_opt_locked(), "Blocking OPT didn't lock OPT"); + TC_PRINT("Try to unlock blocked OPT\n"); + __set_FAULTMASK(1); + flash_stm32_option_bytes_lock(flash_dev, false); + /* Clear Bus Fault pending bit */ + SCB->SHCSR &= ~SCB_SHCSR_BUSFAULTPENDED_Msk; + __set_FAULTMASK(0); + zassert_true(flash_opt_locked(), "OPT unlocked after being blocked"); + + /* Test CR lock. */ + zassert_true(flash_cr_locked(), "CR should be locked by default"); + TC_PRINT("Unlocking CR\n"); + flash_cr_unlock(); + zassert_false(flash_cr_locked(), "Unable to unlock CR"); + TC_PRINT("Blocking CR\n"); + flash_ex_op(flash_dev, FLASH_STM32_EX_OP_BLOCK_CONTROL_REG, (uintptr_t)NULL, NULL); + zassert_true(flash_cr_locked(), "Blocking CR didn't lock CR"); + __set_FAULTMASK(1); + TC_PRINT("Try to unlock blocked CR\n"); + flash_cr_unlock(); + /* Clear Bus Fault pending bit */ + SCB->SHCSR &= ~SCB_SHCSR_BUSFAULTPENDED_Msk; + __set_FAULTMASK(0); + zassert_true(flash_cr_locked(), "CR unlocked after being blocked"); +} +#endif + ZTEST_SUITE(flash_stm32, NULL, flash_stm32_setup, NULL, NULL, NULL); diff --git a/tests/drivers/flash/stm32/testcase.yaml b/tests/drivers/flash/stm32/testcase.yaml index fe13b3444fd..c65df8bdffb 100644 --- a/tests/drivers/flash/stm32/testcase.yaml +++ b/tests/drivers/flash/stm32/testcase.yaml @@ -12,6 +12,14 @@ tests: - CONFIG_FLASH_STM32_READOUT_PROTECTION=y filter: dt_compat_enabled("st,stm32f4-flash-controller") and dt_label_with_parent_compat_enabled("storage_partition", "fixed-partitions") + drivers.flash.stm32.f4.block_registers: + platform_allow: + - nucleo_f429zi + - google_dragonclaw + extra_configs: + - CONFIG_FLASH_STM32_BLOCK_REGISTERS=y + filter: dt_compat_enabled("st,stm32f4-flash-controller") and + dt_label_with_parent_compat_enabled("storage_partition", "fixed-partitions") drivers.flash.stm32.l4: platform_allow: - nucleo_l452re/stm32l452xx/p diff --git a/tests/drivers/flash_simulator/boards/nucleo_f411re.overlay b/tests/drivers/flash_simulator/boards/nucleo_f411re.overlay deleted file mode 100644 index bbe0f8dabe1..00000000000 --- a/tests/drivers/flash_simulator/boards/nucleo_f411re.overlay +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2023 Laczen - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/ { - sram_2001C000:sram@2001C000 { - compatible = "zephyr,memory-region", "mmio-sram"; - reg = <0x2001C000 0x4000>; - zephyr,memory-region = "FlashSim"; - status = "okay"; - }; - - soc { - sim_flash_controller: sim-flash-controller@0 { - compatible = "zephyr,sim-flash"; - reg = <0x0 0x1>; - - #address-cells = <1>; - #size-cells = <1>; - erase-value = <0xff>; - memory-region = <&sram_2001C000>; - - flash_sim0: flash_sim@0 { - status = "okay"; - compatible = "soc-nv-flash"; - erase-block-size = <512>; - /* the flash_simulator test uses a write block - * size of 4 for alignment test, so set it to 4. - */ - write-block-size = <4>; - reg = <0x00000000 DT_SIZE_K(16)>; - }; - }; - }; -}; - -&flash_sim0 { - partitions { - compatible = "fixed-partitions"; - #address-cells = <1>; - #size-cells = <1>; - - lfsram_partition: partition@0 { - label = "lfsram"; - reg = <0x00000000 DT_SIZE_K(16)>; - }; - }; -}; diff --git a/tests/drivers/flash_simulator/CMakeLists.txt b/tests/drivers/flash_simulator/flash_sim_impl/CMakeLists.txt similarity index 100% rename from tests/drivers/flash_simulator/CMakeLists.txt rename to tests/drivers/flash_simulator/flash_sim_impl/CMakeLists.txt diff --git a/tests/drivers/flash_simulator/boards/native_64_ev_0x00.overlay b/tests/drivers/flash_simulator/flash_sim_impl/boards/native_64_ev_0x00.overlay similarity index 100% rename from tests/drivers/flash_simulator/boards/native_64_ev_0x00.overlay rename to tests/drivers/flash_simulator/flash_sim_impl/boards/native_64_ev_0x00.overlay diff --git a/tests/drivers/flash_simulator/boards/native_ev_0x00.overlay b/tests/drivers/flash_simulator/flash_sim_impl/boards/native_ev_0x00.overlay similarity index 100% rename from tests/drivers/flash_simulator/boards/native_ev_0x00.overlay rename to tests/drivers/flash_simulator/flash_sim_impl/boards/native_ev_0x00.overlay diff --git a/tests/drivers/flash_simulator/boards/native_posix.overlay b/tests/drivers/flash_simulator/flash_sim_impl/boards/native_posix.overlay similarity index 100% rename from tests/drivers/flash_simulator/boards/native_posix.overlay rename to tests/drivers/flash_simulator/flash_sim_impl/boards/native_posix.overlay diff --git a/tests/drivers/flash_simulator/flash_sim_impl/boards/native_posix_native_64.overlay b/tests/drivers/flash_simulator/flash_sim_impl/boards/native_posix_native_64.overlay new file mode 100644 index 00000000000..9fe8b9c2160 --- /dev/null +++ b/tests/drivers/flash_simulator/flash_sim_impl/boards/native_posix_native_64.overlay @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "native_posix.overlay" diff --git a/tests/drivers/flash_simulator/boards/native_sim.overlay b/tests/drivers/flash_simulator/flash_sim_impl/boards/native_sim.overlay similarity index 100% rename from tests/drivers/flash_simulator/boards/native_sim.overlay rename to tests/drivers/flash_simulator/flash_sim_impl/boards/native_sim.overlay diff --git a/tests/drivers/flash_simulator/flash_sim_impl/boards/native_sim_native_64.overlay b/tests/drivers/flash_simulator/flash_sim_impl/boards/native_sim_native_64.overlay new file mode 100644 index 00000000000..e4994493dd6 --- /dev/null +++ b/tests/drivers/flash_simulator/flash_sim_impl/boards/native_sim_native_64.overlay @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "native_sim.overlay" diff --git a/tests/drivers/flash_simulator/flash_sim_impl/boards/nucleo_f411re.overlay b/tests/drivers/flash_simulator/flash_sim_impl/boards/nucleo_f411re.overlay new file mode 100644 index 00000000000..60ce2f36e21 --- /dev/null +++ b/tests/drivers/flash_simulator/flash_sim_impl/boards/nucleo_f411re.overlay @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2023 Laczen + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + sram_2001C000:sram@2001C000 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x2001C000 0x4000>; + zephyr,memory-region = "FlashSim"; + status = "okay"; + }; + + soc { + sim_flash_controller: sim-flash-controller@0 { + compatible = "zephyr,sim-flash"; + reg = <0x0 0x1>; + + #address-cells = <1>; + #size-cells = <1>; + erase-value = <0xff>; + memory-region = <&sram_2001C000>; + + flash_sim0: flash_sim@0 { + status = "okay"; + compatible = "soc-nv-flash"; + erase-block-size = <512>; + /* the flash_simulator test uses a write block + * size of 4 for alignment test, so set it to 4. + */ + write-block-size = <4>; + reg = <0x00000000 DT_SIZE_K(16)>; + }; + }; + }; +}; + +&flash_sim0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + lfsram_partition: partition@0 { + label = "lfsram"; + reg = <0x00000000 DT_SIZE_K(16)>; + }; + }; +}; diff --git a/tests/drivers/flash_simulator/boards/qemu_x86_ev_0x00.overlay b/tests/drivers/flash_simulator/flash_sim_impl/boards/qemu_x86_ev_0x00.overlay similarity index 100% rename from tests/drivers/flash_simulator/boards/qemu_x86_ev_0x00.overlay rename to tests/drivers/flash_simulator/flash_sim_impl/boards/qemu_x86_ev_0x00.overlay diff --git a/tests/drivers/flash_simulator/prj.conf b/tests/drivers/flash_simulator/flash_sim_impl/prj.conf similarity index 100% rename from tests/drivers/flash_simulator/prj.conf rename to tests/drivers/flash_simulator/flash_sim_impl/prj.conf diff --git a/tests/drivers/flash_simulator/src/main.c b/tests/drivers/flash_simulator/flash_sim_impl/src/main.c similarity index 100% rename from tests/drivers/flash_simulator/src/main.c rename to tests/drivers/flash_simulator/flash_sim_impl/src/main.c diff --git a/tests/drivers/flash_simulator/testcase.yaml b/tests/drivers/flash_simulator/flash_sim_impl/testcase.yaml similarity index 100% rename from tests/drivers/flash_simulator/testcase.yaml rename to tests/drivers/flash_simulator/flash_sim_impl/testcase.yaml diff --git a/tests/drivers/flash_simulator/flash_sim_reboot/CMakeLists.txt b/tests/drivers/flash_simulator/flash_sim_reboot/CMakeLists.txt new file mode 100644 index 00000000000..6f4d8151e35 --- /dev/null +++ b/tests/drivers/flash_simulator/flash_sim_reboot/CMakeLists.txt @@ -0,0 +1,12 @@ +# +# Copyright (c) 2018 Nordic Semiconductor ASA. +# +# SPDX-License-Identifier: Apache-2.0 +# + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(flash_simulator_reboot) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/tests/drivers/flash_simulator/flash_sim_reboot/boards/mps2_an385.overlay b/tests/drivers/flash_simulator/flash_sim_reboot/boards/mps2_an385.overlay new file mode 100644 index 00000000000..8672ce0e8eb --- /dev/null +++ b/tests/drivers/flash_simulator/flash_sim_reboot/boards/mps2_an385.overlay @@ -0,0 +1,27 @@ +#include + +/ { + sram_203F0000:sram@203F0000 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x203F0000 0x10000>; + zephyr,memory-region = "FlashSim"; + status = "okay"; + }; + + sim_flash_controller: sim_flash_controller { + compatible = "zephyr,sim-flash"; + + #address-cells = <1>; + #size-cells = <1>; + erase-value = <0xff>; + memory-region = <&sram_203F0000>; + + flash_sim0: flash_sim@0 { + compatible = "soc-nv-flash"; + reg = <0x00000000 0x10000>; + + erase-block-size = <1024>; + write-block-size = <4>; + }; + }; +}; diff --git a/tests/drivers/flash_simulator/flash_sim_reboot/prj.conf b/tests/drivers/flash_simulator/flash_sim_reboot/prj.conf new file mode 100644 index 00000000000..4e78174c5c6 --- /dev/null +++ b/tests/drivers/flash_simulator/flash_sim_reboot/prj.conf @@ -0,0 +1,4 @@ +CONFIG_ZTEST=y +CONFIG_FLASH=y +CONFIG_FLASH_SIMULATOR=y +CONFIG_REBOOT=y diff --git a/tests/drivers/flash_simulator/flash_sim_reboot/src/main.c b/tests/drivers/flash_simulator/flash_sim_reboot/src/main.c new file mode 100644 index 00000000000..93c0b9c9654 --- /dev/null +++ b/tests/drivers/flash_simulator/flash_sim_reboot/src/main.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2018 Nordic Semiconductor ASA. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#define MAGIC_WORD 0xABDE2134 + +#define SOC_NV_FLASH_NODE DT_CHILD(DT_INST(0, zephyr_sim_flash), flash_sim_0) +#define FLASH_SIMULATOR_FLASH_SIZE DT_REG_SIZE(SOC_NV_FLASH_NODE) + +static const struct device *const flash_dev = DEVICE_DT_GET(DT_NODELABEL(sim_flash_controller)); +static uint32_t boot_count __noinit; + +ZTEST(flash_sim_reboot, test_preserve_over_reboot) +{ + uint32_t word = MAGIC_WORD; + int rc; + + if (boot_count == 0) { + printk("First boot, erasing flash\n"); + rc = flash_erase(flash_dev, 0, FLASH_SIMULATOR_FLASH_SIZE); + zassert_equal(0, rc, "Failed to erase flash"); + printk("Writing magic word to offset 0\n"); + rc = flash_write(flash_dev, 0, &word, sizeof(word)); + zassert_equal(0, rc, "Failed to write flash"); + printk("Rebooting device...\n"); + boot_count += 1; + sys_reboot(SYS_REBOOT_WARM); + zassert_unreachable("Failed to reboot"); + } else if (boot_count == 1) { + printk("Second boot, reading magic word\n"); + rc = flash_read(flash_dev, 0, &word, sizeof(word)); + zassert_equal(0, rc, "Failed to read flash"); + zassert_equal(MAGIC_WORD, word, "Magic word not preserved"); + } else { + zassert_unreachable("Unexpected boot_count value %d", boot_count); + } +} + +void *flash_sim_setup(void) +{ + zassert_true(device_is_ready(flash_dev), "Simulated flash device not ready"); + + return NULL; +} + +ZTEST_SUITE(flash_sim_reboot, NULL, flash_sim_setup, NULL, NULL, NULL); diff --git a/tests/drivers/flash_simulator/flash_sim_reboot/testcase.yaml b/tests/drivers/flash_simulator/flash_sim_reboot/testcase.yaml new file mode 100644 index 00000000000..069bbac09c9 --- /dev/null +++ b/tests/drivers/flash_simulator/flash_sim_reboot/testcase.yaml @@ -0,0 +1,10 @@ +common: + tags: + - drivers + - flash +tests: + drivers.flash.flash_simulator.boot_no_erase: + timeout: 5 + platform_allow: mps2/an385 + integration_platforms: + - mps2/an385 diff --git a/tests/drivers/fuel_gauge/sbs_gauge/testcase.yaml b/tests/drivers/fuel_gauge/sbs_gauge/testcase.yaml index bcdcd84127b..246c1831bc8 100644 --- a/tests/drivers/fuel_gauge/sbs_gauge/testcase.yaml +++ b/tests/drivers/fuel_gauge/sbs_gauge/testcase.yaml @@ -3,9 +3,10 @@ tests: tags: - drivers - fuel_gauge - filter: > - dt_compat_enabled("sbs,sbs-gauge-new-api") and - (CONFIG_QEMU_TARGET or CONFIG_BOARD_NATIVE_SIM) + platform_key: + - arch + - simulation + filter: dt_compat_enabled("sbs,sbs-gauge-new-api") extra_args: - CONF_FILE="prj.conf;boards/emulated_board.conf" - DTC_OVERLAY_FILE="boards/emulated_board.overlay" @@ -24,9 +25,10 @@ tests: tags: - drivers - fuel_gauge - filter: > - dt_compat_enabled("sbs,sbs-gauge-new-api") and - (CONFIG_QEMU_TARGET or CONFIG_BOARD_NATIVE_SIM) + platform_key: + - arch + - simulation + filter: dt_compat_enabled("sbs,sbs-gauge-new-api") platform_allow: - hifive_unmatched - qemu_cortex_a53 diff --git a/tests/drivers/gnss/gnss_api/CMakeLists.txt b/tests/drivers/gnss/gnss_api/CMakeLists.txt new file mode 100644 index 00000000000..50762c41059 --- /dev/null +++ b/tests/drivers/gnss/gnss_api/CMakeLists.txt @@ -0,0 +1,15 @@ +# Copyright (c) 2024 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_api) + +target_sources(app PRIVATE + src/test_enabled_systems.c + src/test_fix_rate.c + src/test_navigation_mode.c + src/test_suite.c +) diff --git a/tests/drivers/gnss/gnss_api/Kconfig b/tests/drivers/gnss/gnss_api/Kconfig new file mode 100644 index 00000000000..34238dcdf71 --- /dev/null +++ b/tests/drivers/gnss/gnss_api/Kconfig @@ -0,0 +1,32 @@ +# Copyright (c) 2024 Trackunit Corporation +# SPDX-License-Identifier: Apache-2.0 + +source "Kconfig.zephyr" + +config TEST_ENABLED_SYSTEMS_0 + int "Enabled systems configuration 0" + range 0 255 + default 0 + +config TEST_ENABLED_SYSTEMS_1 + int "Enabled systems configuration 1" + range 0 255 + default 0 + +config TEST_ENABLED_SYSTEMS_2 + int "Enabled systems configuration 2" + range 0 255 + default 0 + +config TEST_ENABLED_SYSTEMS_3 + int "Enabled systems configuration 3" + range 0 255 + default 0 + +config TEST_SEARCH_PERIOD + int "Search period for satellites in seconds" + default 60 + +config TEST_FIX_TIMEOUT + int "Timeout waiting for a fix in seconds" + default 60 diff --git a/tests/drivers/gnss/gnss_api/boards/native_sim.conf b/tests/drivers/gnss/gnss_api/boards/native_sim.conf new file mode 100644 index 00000000000..58a3450defb --- /dev/null +++ b/tests/drivers/gnss/gnss_api/boards/native_sim.conf @@ -0,0 +1,13 @@ +# Copyright (c) 2024 Trackunit Corporation +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_GNSS_SATELLITES=y + +# GPS +CONFIG_TEST_ENABLED_SYSTEMS_0=1 +# GPS + GLONASS +CONFIG_TEST_ENABLED_SYSTEMS_1=3 +# GPS + GLONASS + QZSS +CONFIG_TEST_ENABLED_SYSTEMS_2=19 +# GPS + GLONASS + GALILEO + BEIDOU + QZSS + SBAS +CONFIG_TEST_ENABLED_SYSTEMS_3=95 diff --git a/tests/drivers/gnss/gnss_api/boards/native_sim.overlay b/tests/drivers/gnss/gnss_api/boards/native_sim.overlay new file mode 100644 index 00000000000..c81955df1ac --- /dev/null +++ b/tests/drivers/gnss/gnss_api/boards/native_sim.overlay @@ -0,0 +1,16 @@ +/* + * Copyright 2024 Trackunit Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + gnss = &gnss; + }; + + gnss: gnss { + compatible = "zephyr,gnss-emul"; + status = "okay"; + }; +}; diff --git a/tests/drivers/gnss/gnss_api/boards/native_sim_64.conf b/tests/drivers/gnss/gnss_api/boards/native_sim_64.conf new file mode 100644 index 00000000000..58a3450defb --- /dev/null +++ b/tests/drivers/gnss/gnss_api/boards/native_sim_64.conf @@ -0,0 +1,13 @@ +# Copyright (c) 2024 Trackunit Corporation +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_GNSS_SATELLITES=y + +# GPS +CONFIG_TEST_ENABLED_SYSTEMS_0=1 +# GPS + GLONASS +CONFIG_TEST_ENABLED_SYSTEMS_1=3 +# GPS + GLONASS + QZSS +CONFIG_TEST_ENABLED_SYSTEMS_2=19 +# GPS + GLONASS + GALILEO + BEIDOU + QZSS + SBAS +CONFIG_TEST_ENABLED_SYSTEMS_3=95 diff --git a/tests/drivers/gnss/gnss_api/boards/native_sim_64.overlay b/tests/drivers/gnss/gnss_api/boards/native_sim_64.overlay new file mode 100644 index 00000000000..c81955df1ac --- /dev/null +++ b/tests/drivers/gnss/gnss_api/boards/native_sim_64.overlay @@ -0,0 +1,16 @@ +/* + * Copyright 2024 Trackunit Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + gnss = &gnss; + }; + + gnss: gnss { + compatible = "zephyr,gnss-emul"; + status = "okay"; + }; +}; diff --git a/tests/drivers/gnss/gnss_api/boards/qemu_x86.conf b/tests/drivers/gnss/gnss_api/boards/qemu_x86.conf new file mode 100644 index 00000000000..58a3450defb --- /dev/null +++ b/tests/drivers/gnss/gnss_api/boards/qemu_x86.conf @@ -0,0 +1,13 @@ +# Copyright (c) 2024 Trackunit Corporation +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_GNSS_SATELLITES=y + +# GPS +CONFIG_TEST_ENABLED_SYSTEMS_0=1 +# GPS + GLONASS +CONFIG_TEST_ENABLED_SYSTEMS_1=3 +# GPS + GLONASS + QZSS +CONFIG_TEST_ENABLED_SYSTEMS_2=19 +# GPS + GLONASS + GALILEO + BEIDOU + QZSS + SBAS +CONFIG_TEST_ENABLED_SYSTEMS_3=95 diff --git a/tests/drivers/gnss/gnss_api/boards/qemu_x86.overlay b/tests/drivers/gnss/gnss_api/boards/qemu_x86.overlay new file mode 100644 index 00000000000..c81955df1ac --- /dev/null +++ b/tests/drivers/gnss/gnss_api/boards/qemu_x86.overlay @@ -0,0 +1,16 @@ +/* + * Copyright 2024 Trackunit Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + gnss = &gnss; + }; + + gnss: gnss { + compatible = "zephyr,gnss-emul"; + status = "okay"; + }; +}; diff --git a/tests/drivers/gnss/gnss_api/boards/qemu_x86_64.conf b/tests/drivers/gnss/gnss_api/boards/qemu_x86_64.conf new file mode 100644 index 00000000000..b1cf5b22cbe --- /dev/null +++ b/tests/drivers/gnss/gnss_api/boards/qemu_x86_64.conf @@ -0,0 +1,18 @@ +# Copyright (c) 2024 Trackunit Corporation +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_GNSS_SATELLITES=y + +# GPS +CONFIG_TEST_ENABLED_SYSTEMS_0=1 +# GPS + GLONASS +CONFIG_TEST_ENABLED_SYSTEMS_1=3 +# GPS + GLONASS + QZSS +CONFIG_TEST_ENABLED_SYSTEMS_2=19 +# GPS + GLONASS + GALILEO + BEIDOU + QZSS + SBAS +CONFIG_TEST_ENABLED_SYSTEMS_3=95 + +# This emulated board runs real-time +# Lower timeouts to prevent unnecessary waiting +CONFIG_TEST_SEARCH_PERIOD=5 +CONFIG_TEST_FIX_TIMEOUT=1 diff --git a/tests/drivers/gnss/gnss_api/boards/qemu_x86_64.overlay b/tests/drivers/gnss/gnss_api/boards/qemu_x86_64.overlay new file mode 100644 index 00000000000..c81955df1ac --- /dev/null +++ b/tests/drivers/gnss/gnss_api/boards/qemu_x86_64.overlay @@ -0,0 +1,16 @@ +/* + * Copyright 2024 Trackunit Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + gnss = &gnss; + }; + + gnss: gnss { + compatible = "zephyr,gnss-emul"; + status = "okay"; + }; +}; diff --git a/tests/drivers/gnss/gnss_api/prj.conf b/tests/drivers/gnss/gnss_api/prj.conf new file mode 100644 index 00000000000..bfb63abec37 --- /dev/null +++ b/tests/drivers/gnss/gnss_api/prj.conf @@ -0,0 +1,6 @@ +# Copyright (c) 2024 Trackunit Corporation +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_GNSS=y +CONFIG_ZTEST=y +CONFIG_ZTEST_STACK_SIZE=4096 diff --git a/tests/drivers/gnss/gnss_api/src/test_enabled_systems.c b/tests/drivers/gnss/gnss_api/src/test_enabled_systems.c new file mode 100644 index 00000000000..246e94631a8 --- /dev/null +++ b/tests/drivers/gnss/gnss_api/src/test_enabled_systems.c @@ -0,0 +1,147 @@ +/* + * Copyright 2024 Trackunit Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#define TEST_SEARCH_PERIOD K_SECONDS(CONFIG_TEST_SEARCH_PERIOD) + +static const struct device *dev = DEVICE_DT_GET(DT_ALIAS(gnss)); +static const gnss_systems_t enabled_systems_array[] = { + CONFIG_TEST_ENABLED_SYSTEMS_0, + CONFIG_TEST_ENABLED_SYSTEMS_1, + CONFIG_TEST_ENABLED_SYSTEMS_2, + CONFIG_TEST_ENABLED_SYSTEMS_3, +}; + +static bool test_reported_are_expected(gnss_systems_t reported, gnss_systems_t expected) +{ + return ((~expected) & reported) == 0; +} + +static void test_set_enabled_systems(gnss_systems_t enabled_systems) +{ + int ret; + + ret = gnss_set_enabled_systems(dev, enabled_systems); + zassert_ok(ret, "failed to set enabled systems (%i)", ret); +} + +static void test_get_system_enabled(gnss_systems_t expected_systems) +{ + int ret; + gnss_systems_t enabled_systems; + + ret = gnss_get_enabled_systems(dev, &enabled_systems); + if (ret == -ENOSYS) { + return; + } + zassert_ok(ret, "failed to get enabled systems (%i)", ret); + + zassert_equal(enabled_systems, expected_systems, + "invalid enabled systems (%u != %u)", + enabled_systems, expected_systems); +} + +#ifdef CONFIG_GNSS_SATELLITES +static atomic_t reported_systems_atom = ATOMIC_INIT(0); + +static void gnss_satellites_cb(const struct device *dev, + const struct gnss_satellite *satellites, + uint16_t size) +{ + for (uint16_t i = 0; i < size; i++) { + atomic_or(&reported_systems_atom, satellites[i].system); + } +} + +GNSS_SATELLITES_CALLBACK_DEFINE(DEVICE_DT_GET(DT_ALIAS(gnss)), gnss_satellites_cb); + +static void test_validate_satellites(gnss_systems_t expected_systems) +{ + gnss_systems_t reported_systems; + bool expected; + + atomic_set(&reported_systems_atom, 0); + PRINT("searching with enabled system %u\n", expected_systems); + k_sleep(TEST_SEARCH_PERIOD); + + reported_systems = atomic_get(&reported_systems_atom); + if (reported_systems == 0) { + PRINT("found no satellites\n"); + } else { + PRINT("found satellites\n"); + } + + expected = test_reported_are_expected(reported_systems, expected_systems); + zassert_true(expected, "unexpected systems reported (%u != %u)", + reported_systems, expected_systems); +} +#endif + +static void test_validate_enabled_systems(void) +{ + gnss_systems_t enabled_systems; + + for (uint8_t i = 0; i < ARRAY_SIZE(enabled_systems_array); i++) { + enabled_systems = enabled_systems_array[i]; + if (enabled_systems == 0) { + continue; + } + + test_set_enabled_systems(enabled_systems); + test_get_system_enabled(enabled_systems); +#ifdef CONFIG_GNSS_SATELLITES + test_validate_satellites(enabled_systems); +#endif + } +} + +static bool test_all_enabled_systems_are_disabled(void) +{ + gnss_systems_t enabled_systems; + + for (uint8_t i = 0; i < ARRAY_SIZE(enabled_systems_array); i++) { + enabled_systems = enabled_systems_array[i]; + if (enabled_systems != 0) { + return false; + } + } + + return true; +} + +static void test_validate_supported_systems(void) +{ + gnss_systems_t supported_systems; + int ret; + gnss_systems_t enabled_systems; + bool supported; + + ret = gnss_get_supported_systems(dev, &supported_systems); + if (ret == -ENOSYS) { + return; + } + zassert_ok(ret, "failed to get supported systems (%i)", ret); + + for (uint8_t i = 0; i < ARRAY_SIZE(enabled_systems_array); i++) { + enabled_systems = enabled_systems_array[0]; + supported = test_reported_are_expected(enabled_systems, supported_systems); + zassert_true(supported, "enabled systems %u is not supported", i); + } +} + +ZTEST(gnss_api, test_enabled_systems) +{ + if (test_all_enabled_systems_are_disabled()) { + ztest_test_skip(); + } + + test_validate_supported_systems(); + test_validate_enabled_systems(); +} diff --git a/tests/drivers/gnss/gnss_api/src/test_fix_rate.c b/tests/drivers/gnss/gnss_api/src/test_fix_rate.c new file mode 100644 index 00000000000..35ceec38dc3 --- /dev/null +++ b/tests/drivers/gnss/gnss_api/src/test_fix_rate.c @@ -0,0 +1,88 @@ +/* + * Copyright 2024 Trackunit Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#define TEST_VALIDATE_PERIOD_MS 10000 +#define TEST_VALIDATE_PERIOD K_MSEC(TEST_VALIDATE_PERIOD_MS) + +#define TEST_MIN_CALLBACK_COUNT(_fix_interval) \ + (((TEST_VALIDATE_PERIOD_MS / _fix_interval) / 5) * 4) + +#define TEST_MAX_CALLBACK_COUNT(_fix_interval) \ + (((TEST_VALIDATE_PERIOD_MS / _fix_interval) / 5) * 6) + +#define TEST_CONFIG_DEFINE(_fix_interval) \ + { \ + .fix_interval = _fix_interval, \ + .min_callback_count = TEST_MIN_CALLBACK_COUNT(_fix_interval), \ + .max_callback_count = TEST_MAX_CALLBACK_COUNT(_fix_interval), \ + } + +static const struct device *dev = DEVICE_DT_GET(DT_ALIAS(gnss)); + +struct test_config { + uint32_t fix_interval; + uint32_t min_callback_count; + uint32_t max_callback_count; +}; + +static const struct test_config configs[] = { + TEST_CONFIG_DEFINE(100), + TEST_CONFIG_DEFINE(500), + TEST_CONFIG_DEFINE(1000), + TEST_CONFIG_DEFINE(2000), +}; + +static atomic_t callback_count_atom = ATOMIC_INIT(0); + +static void gnss_data_cb(const struct device *dev, const struct gnss_data *data) +{ + atomic_inc(&callback_count_atom); +} + +GNSS_DATA_CALLBACK_DEFINE(DEVICE_DT_GET(DT_ALIAS(gnss)), gnss_data_cb); + +static bool test_set_fix_rate(const struct test_config *config) +{ + int ret; + + ret = gnss_set_fix_rate(dev, config->fix_interval); + if (ret == -ENOSYS) { + ztest_test_skip(); + } + if (ret == -EINVAL) { + return false; + } + zassert_ok(ret, "failed to set fix rate %u", config->fix_interval); + return true; +} + +static void test_validate_fix_rate(const struct test_config *config) +{ + bool valid; + uint32_t callback_count; + + atomic_set(&callback_count_atom, 0); + k_sleep(TEST_VALIDATE_PERIOD); + callback_count = atomic_get(&callback_count_atom); + valid = (callback_count >= config->min_callback_count) && + (callback_count <= config->max_callback_count); + zassert_true(valid, "callback count %u invalid", callback_count); +} + +ZTEST(gnss_api, test_fix_rate) +{ + for (uint32_t i = 0; i < ARRAY_SIZE(configs); i++) { + if (!test_set_fix_rate(&configs[i])) { + continue; + } + test_validate_fix_rate(&configs[i]); + } +} diff --git a/tests/drivers/gnss/gnss_api/src/test_navigation_mode.c b/tests/drivers/gnss/gnss_api/src/test_navigation_mode.c new file mode 100644 index 00000000000..c07843b58f6 --- /dev/null +++ b/tests/drivers/gnss/gnss_api/src/test_navigation_mode.c @@ -0,0 +1,60 @@ +/* + * Copyright 2024 Trackunit Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +static const struct device *dev = DEVICE_DT_GET(DT_ALIAS(gnss)); +static const enum gnss_navigation_mode nav_modes[] = { + GNSS_NAVIGATION_MODE_ZERO_DYNAMICS, + GNSS_NAVIGATION_MODE_LOW_DYNAMICS, + GNSS_NAVIGATION_MODE_BALANCED_DYNAMICS, + GNSS_NAVIGATION_MODE_HIGH_DYNAMICS, +}; + +static bool test_set_nav_mode(enum gnss_navigation_mode nav_mode) +{ + int ret; + + ret = gnss_set_navigation_mode(dev, nav_mode); + if (ret == -ENOSYS) { + ztest_test_skip(); + } + if (ret == -EINVAL) { + return false; + } + zassert_ok(ret, "failed to set navigation mode %u", nav_mode); + return true; +} + +static void test_validate_nav_mode(enum gnss_navigation_mode nav_mode) +{ + int ret; + enum gnss_navigation_mode set_nav_mode; + + ret = gnss_get_navigation_mode(dev, &set_nav_mode); + if (ret == -ENOSYS) { + return; + } + zassert_ok(ret, "failed to get navigation mode %u", nav_mode); +} + +ZTEST(gnss_api, test_navigation_mode) +{ + enum gnss_navigation_mode nav_mode; + + for (uint8_t i = 0; i < ARRAY_SIZE(nav_modes); i++) { + nav_mode = nav_modes[i]; + + if (!test_set_nav_mode(nav_mode)) { + continue; + } + + test_validate_nav_mode(nav_mode); + } +} diff --git a/tests/drivers/gnss/gnss_api/src/test_suite.c b/tests/drivers/gnss/gnss_api/src/test_suite.c new file mode 100644 index 00000000000..15439f5d9f3 --- /dev/null +++ b/tests/drivers/gnss/gnss_api/src/test_suite.c @@ -0,0 +1,9 @@ +/* + * Copyright 2024 Trackunit Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +ZTEST_SUITE(gnss_api, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/drivers/gnss/gnss_api/testcase.yaml b/tests/drivers/gnss/gnss_api/testcase.yaml new file mode 100644 index 00000000000..7ce2c22de3e --- /dev/null +++ b/tests/drivers/gnss/gnss_api/testcase.yaml @@ -0,0 +1,7 @@ +# Copyright (c) 2024 Trackunit Corporation +# SPDX-License-Identifier: Apache-2.0 + +tests: + drivers.gnss.gnss_api: + filter: dt_alias_exists("gnss") + timeout: 300 diff --git a/tests/drivers/gnss/gnss_nmea0183/src/main.c b/tests/drivers/gnss/gnss_nmea0183/src/main.c index 680382f7dbc..43cd6a2e53f 100644 --- a/tests/drivers/gnss/gnss_nmea0183/src/main.c +++ b/tests/drivers/gnss/gnss_nmea0183/src/main.c @@ -330,7 +330,7 @@ ZTEST(gnss_nmea0183, test_parse_gga_fix) "Incorrectly parsed number of satelites"); zassert_equal(data.info.hdop, 1410, "Incorrectly parsed HDOP"); - zassert_equal(data.nav_data.altitude, 42371, "Incorrectly parsed altitude"); + zassert_equal(data.nav_data.altitude, 15234, "Incorrectly parsed altitude"); } ZTEST(gnss_nmea0183, test_snprintk) diff --git a/tests/drivers/gpio/gpio_basic_api/boards/esp32s3_devkitm.overlay b/tests/drivers/gpio/gpio_basic_api/boards/esp32s3_devkitm_procpu.overlay similarity index 100% rename from tests/drivers/gpio/gpio_basic_api/boards/esp32s3_devkitm.overlay rename to tests/drivers/gpio/gpio_basic_api/boards/esp32s3_devkitm_procpu.overlay diff --git a/tests/drivers/gpio/gpio_basic_api/boards/esp32s3_luatos_core.overlay b/tests/drivers/gpio/gpio_basic_api/boards/esp32s3_luatos_core_procpu.overlay similarity index 100% rename from tests/drivers/gpio/gpio_basic_api/boards/esp32s3_luatos_core.overlay rename to tests/drivers/gpio/gpio_basic_api/boards/esp32s3_luatos_core_procpu.overlay diff --git a/tests/drivers/gpio/gpio_basic_api/boards/esp32s3_luatos_core_esp32s3_procpu_usb.overlay b/tests/drivers/gpio/gpio_basic_api/boards/esp32s3_luatos_core_procpu_usb.overlay similarity index 100% rename from tests/drivers/gpio/gpio_basic_api/boards/esp32s3_luatos_core_esp32s3_procpu_usb.overlay rename to tests/drivers/gpio/gpio_basic_api/boards/esp32s3_luatos_core_procpu_usb.overlay diff --git a/tests/drivers/gpio/gpio_basic_api/boards/frdm_ke15z.overlay b/tests/drivers/gpio/gpio_basic_api/boards/frdm_ke15z.overlay new file mode 100644 index 00000000000..68c941f0cd5 --- /dev/null +++ b/tests/drivers/gpio/gpio_basic_api/boards/frdm_ke15z.overlay @@ -0,0 +1,17 @@ +/* + * Copyright NXP 2024 + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&gpioc { + status = "okay"; +}; + +/ { + resources { + compatible = "test-gpio-basic-api"; + out-gpios = <&gpioc 8 0>; /* Arduino D0 */ + in-gpios = <&gpioc 9 0>; /* Arduino D1 */ + }; +}; diff --git a/tests/drivers/gpio/gpio_basic_api/boards/intel_adl_crb.overlay b/tests/drivers/gpio/gpio_basic_api/boards/intel_adl_crb.overlay index 565bbaf6321..90c1c06fdcd 100644 --- a/tests/drivers/gpio/gpio_basic_api/boards/intel_adl_crb.overlay +++ b/tests/drivers/gpio/gpio_basic_api/boards/intel_adl_crb.overlay @@ -16,7 +16,7 @@ resources { compatible = "test-gpio-basic-api"; - out-gpios = <&gpio_0_b 14 0>; - in-gpios = <&gpio_0_b 15 0>; + out-gpios = <&gpio_b 14 0>; + in-gpios = <&gpio_b 15 0>; }; }; diff --git a/tests/drivers/gpio/gpio_basic_api/boards/nrf54l15pdk_nrf54l15_cpuflpr.overlay b/tests/drivers/gpio/gpio_basic_api/boards/nrf54l15pdk_nrf54l15_cpuflpr.overlay new file mode 100644 index 00000000000..8eb1b3c9f9f --- /dev/null +++ b/tests/drivers/gpio/gpio_basic_api/boards/nrf54l15pdk_nrf54l15_cpuflpr.overlay @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + resources { + compatible = "test-gpio-basic-api"; + out-gpios = <&gpio1 10 0>; + in-gpios = <&gpio1 11 0>; + }; +}; + +&gpiote20 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; diff --git a/tests/drivers/gpio/gpio_basic_api/boards/nrf54l15pdk_nrf54l15_cpuflpr_xip.overlay b/tests/drivers/gpio/gpio_basic_api/boards/nrf54l15pdk_nrf54l15_cpuflpr_xip.overlay new file mode 100644 index 00000000000..8eb1b3c9f9f --- /dev/null +++ b/tests/drivers/gpio/gpio_basic_api/boards/nrf54l15pdk_nrf54l15_cpuflpr_xip.overlay @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + resources { + compatible = "test-gpio-basic-api"; + out-gpios = <&gpio1 10 0>; + in-gpios = <&gpio1 11 0>; + }; +}; + +&gpiote20 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; diff --git a/tests/drivers/gpio/gpio_basic_api/boards/yd_esp32.overlay b/tests/drivers/gpio/gpio_basic_api/boards/yd_esp32_procpu.overlay similarity index 100% rename from tests/drivers/gpio/gpio_basic_api/boards/yd_esp32.overlay rename to tests/drivers/gpio/gpio_basic_api/boards/yd_esp32_procpu.overlay diff --git a/tests/drivers/i2c/i2c_ram/README.rst b/tests/drivers/i2c/i2c_ram/README.rst index c4863151471..0475a500bc1 100644 --- a/tests/drivers/i2c/i2c_ram/README.rst +++ b/tests/drivers/i2c/i2c_ram/README.rst @@ -4,3 +4,8 @@ i2c ram test Tests an i2c controller driver against a (s/f/nv)ram module doing a simple write and readback. Excercises most of the i2c controller APIs in the process. + +Hardware Setup +============== +- Target supporting I2C (with RTIO for the I2C_RTIO test-cases), e.g: mimxrt1010_evk. +- External I2C RAM chipset connected to the I2C bus, e.g: Fujitsu's MB85 FeRAM. diff --git a/tests/drivers/i2c/i2c_ram/boards/nrf52840dk_nrf52840.overlay b/tests/drivers/i2c/i2c_ram/boards/nrf52840dk_nrf52840.overlay new file mode 100644 index 00000000000..d2b49977fdc --- /dev/null +++ b/tests/drivers/i2c/i2c_ram/boards/nrf52840dk_nrf52840.overlay @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2023 Intel Corporation + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + i2c-ram = &arduino_i2c; + }; +}; diff --git a/tests/drivers/i2c/i2c_ram/src/test_i2c_ram.c b/tests/drivers/i2c/i2c_ram/src/test_i2c_ram.c index 5b9dbb77ce3..3992897d90f 100644 --- a/tests/drivers/i2c/i2c_ram/src/test_i2c_ram.c +++ b/tests/drivers/i2c/i2c_ram/src/test_i2c_ram.c @@ -13,6 +13,7 @@ */ #include +#include #include #include #include @@ -73,6 +74,17 @@ static void i2c_ram_before(void *f) rx_cmd[1] = (addr) & 0xFF; addr += ARRAY_SIZE(tx_data) - TX_DATA_OFFSET; memset(rx_data, 0, ARRAY_SIZE(rx_data)); + +#ifdef CONFIG_PM_DEVICE_RUNTIME + pm_device_runtime_get(i2c_dev); +#endif +} + +static void i2c_ram_after(void *f) +{ +#ifdef CONFIG_PM_DEVICE_RUNTIME + pm_device_runtime_put(i2c_dev); +#endif } ZTEST(i2c_ram, test_ram_transfer) @@ -173,8 +185,8 @@ ZTEST(i2c_ram, test_ram_rtio) TC_PRINT("submitting write from thread %p addr %x\n", k_current_get(), addr); wr_sqe = rtio_sqe_acquire(&i2c_rtio); - wr_sqe->iodev_flags |= RTIO_IODEV_I2C_STOP; rtio_sqe_prep_write(wr_sqe, &i2c_iodev, 0, tx_data, ARRAY_SIZE(tx_data), tx_data); + wr_sqe->iodev_flags |= RTIO_IODEV_I2C_STOP; zassert_ok(rtio_submit(&i2c_rtio, 1), "submit should succeed"); wr_cqe = rtio_cqe_consume(&i2c_rtio); @@ -189,11 +201,11 @@ ZTEST(i2c_ram, test_ram_rtio) msgs[1].flags = I2C_MSG_RESTART | I2C_MSG_READ | I2C_MSG_STOP; wr_sqe = rtio_sqe_acquire(&i2c_rtio); - wr_sqe->flags |= RTIO_SQE_TRANSACTION; rd_sqe = rtio_sqe_acquire(&i2c_rtio); - rd_sqe->iodev_flags |= RTIO_IODEV_I2C_STOP | RTIO_IODEV_I2C_RESTART; rtio_sqe_prep_write(wr_sqe, &i2c_iodev, 0, rx_cmd, ARRAY_SIZE(rx_cmd), rx_cmd); rtio_sqe_prep_read(rd_sqe, &i2c_iodev, 0, rx_data, ARRAY_SIZE(rx_data), rx_data); + wr_sqe->flags |= RTIO_SQE_TRANSACTION; + rd_sqe->iodev_flags |= RTIO_IODEV_I2C_STOP | RTIO_IODEV_I2C_RESTART; zassert_ok(rtio_submit(&i2c_rtio, 2), "submit should succeed"); wr_cqe = rtio_cqe_consume(&i2c_rtio); @@ -226,8 +238,8 @@ void ram_rtio_isr(struct k_timer *tid) case INIT: TC_PRINT("timer submitting write, addr %x\n", addr); wr_sqe = rtio_sqe_acquire(&i2c_rtio); - wr_sqe->iodev_flags |= RTIO_IODEV_I2C_STOP; rtio_sqe_prep_write(wr_sqe, &i2c_iodev, 0, tx_data, ARRAY_SIZE(tx_data), tx_data); + wr_sqe->iodev_flags |= RTIO_IODEV_I2C_STOP; zassert_ok(rtio_submit(&i2c_rtio, 0), "submit should succeed"); isr_state += 1; break; @@ -246,13 +258,13 @@ void ram_rtio_isr(struct k_timer *tid) msgs[1].flags = I2C_MSG_RESTART | I2C_MSG_READ | I2C_MSG_STOP; wr_sqe = rtio_sqe_acquire(&i2c_rtio); - wr_sqe->flags |= RTIO_SQE_TRANSACTION; rd_sqe = rtio_sqe_acquire(&i2c_rtio); - rd_sqe->iodev_flags |= RTIO_IODEV_I2C_STOP | RTIO_IODEV_I2C_RESTART; rtio_sqe_prep_write(wr_sqe, &i2c_iodev, 0, rx_cmd, ARRAY_SIZE(rx_cmd), rx_cmd); rtio_sqe_prep_read(rd_sqe, &i2c_iodev, 0, rx_data, ARRAY_SIZE(rx_data), rx_data); + wr_sqe->flags |= RTIO_SQE_TRANSACTION; + rd_sqe->iodev_flags |= RTIO_IODEV_I2C_STOP | RTIO_IODEV_I2C_RESTART; zassert_ok(rtio_submit(&i2c_rtio, 0), "submit should succeed"); isr_state += 1; } @@ -294,4 +306,4 @@ ZTEST(i2c_ram, test_ram_rtio_isr) #endif /* CONFIG_I2C_RTIO */ -ZTEST_SUITE(i2c_ram, NULL, i2c_ram_setup, i2c_ram_before, NULL, NULL); +ZTEST_SUITE(i2c_ram, NULL, i2c_ram_setup, i2c_ram_before, i2c_ram_after, NULL); diff --git a/tests/drivers/i2c/i2c_ram/testcase.yaml b/tests/drivers/i2c/i2c_ram/testcase.yaml index 3bed6b96a87..d1257778cc3 100644 --- a/tests/drivers/i2c/i2c_ram/testcase.yaml +++ b/tests/drivers/i2c/i2c_ram/testcase.yaml @@ -3,7 +3,7 @@ common: tags: - drivers - i2c - filter: dt_alias_exists("i2c_ram") + filter: dt_alias_exists("i2c-ram") tests: drivers.i2c.ram: depends_on: i2c @@ -11,5 +11,19 @@ tests: - drivers - i2c drivers.i2c.ram.rtio: + filter: CONFIG_HAS_I2C_RTIO extra_configs: - CONFIG_I2C_RTIO=y + drivers.i2c.ram.pm: + filter: CONFIG_HAS_PM + extra_configs: + - CONFIG_PM=y + - CONFIG_PM_DEVICE=y + - CONFIG_PM_DEVICE_RUNTIME=y + drivers.i2c.ram.pm.rtio: + filter: CONFIG_HAS_PM and CONFIG_HAS_I2C_RTIO + extra_configs: + - CONFIG_PM=y + - CONFIG_PM_DEVICE=y + - CONFIG_PM_DEVICE_RUNTIME=y + - CONFIG_I2C_RTIO=y diff --git a/tests/drivers/i2c/i2c_target_api/boards/b_u585i_iot02a.overlay b/tests/drivers/i2c/i2c_target_api/boards/b_u585i_iot02a.overlay index f07d43230e9..c1d15d027cc 100644 --- a/tests/drivers/i2c/i2c_target_api/boards/b_u585i_iot02a.overlay +++ b/tests/drivers/i2c/i2c_target_api/boards/b_u585i_iot02a.overlay @@ -10,6 +10,8 @@ * Short Pin PB9 to PH5, and PB8 to PH4, for the test to pass. */ +/delete-node/ &eeprom0; + &i2c1 { eeprom0: eeprom@54 { compatible = "zephyr,i2c-target-eeprom"; diff --git a/tests/drivers/i2c/i2c_target_api/boards/numaker_pfm_m467.overlay b/tests/drivers/i2c/i2c_target_api/boards/numaker_pfm_m467.overlay index 2d3d972b260..a5cd026c7eb 100644 --- a/tests/drivers/i2c/i2c_target_api/boards/numaker_pfm_m467.overlay +++ b/tests/drivers/i2c/i2c_target_api/boards/numaker_pfm_m467.overlay @@ -10,8 +10,8 @@ i2c3_default: i2c3_default { group0 { - pinmux = , /* UNO D14 */ - ; /* UNO D15 */ + pinmux = , /* UNO D14 */ + ; /* UNO D15 */ }; }; }; diff --git a/tests/drivers/input/gpio_kbd_matrix/boards/native_sim_native_64.overlay b/tests/drivers/input/gpio_kbd_matrix/boards/native_sim_native_64.overlay new file mode 100644 index 00000000000..91647f82e20 --- /dev/null +++ b/tests/drivers/input/gpio_kbd_matrix/boards/native_sim_native_64.overlay @@ -0,0 +1,6 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "native_sim.overlay" diff --git a/tests/drivers/input/gpio_keys/boards/native_sim_native_64.overlay b/tests/drivers/input/gpio_keys/boards/native_sim_native_64.overlay new file mode 100644 index 00000000000..91647f82e20 --- /dev/null +++ b/tests/drivers/input/gpio_keys/boards/native_sim_native_64.overlay @@ -0,0 +1,6 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "native_sim.overlay" diff --git a/tests/drivers/input/kbd_matrix/boards/native_sim_native_64.overlay b/tests/drivers/input/kbd_matrix/boards/native_sim_native_64.overlay new file mode 100644 index 00000000000..91647f82e20 --- /dev/null +++ b/tests/drivers/input/kbd_matrix/boards/native_sim_native_64.overlay @@ -0,0 +1,6 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "native_sim.overlay" diff --git a/tests/drivers/kscan/kscan_input/boards/native_sim_native_64.overlay b/tests/drivers/kscan/kscan_input/boards/native_sim_native_64.overlay new file mode 100644 index 00000000000..91647f82e20 --- /dev/null +++ b/tests/drivers/kscan/kscan_input/boards/native_sim_native_64.overlay @@ -0,0 +1,6 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "native_sim.overlay" diff --git a/tests/drivers/memc/ram/src/main.c b/tests/drivers/memc/ram/src/main.c index 49ce816d487..c8de856aa46 100644 --- a/tests/drivers/memc/ram/src/main.c +++ b/tests/drivers/memc/ram/src/main.c @@ -44,6 +44,9 @@ BUF_DEF(sram1); #if DT_NODE_HAS_STATUS(DT_NODELABEL(sram2), okay) BUF_DEF(sram2); #endif +#if DT_NODE_HAS_STATUS(DT_NODELABEL(memc), okay) +BUF_DEF(psram); +#endif #if DT_NODE_HAS_STATUS(DT_NODELABEL(ram0), okay) #define RAM_SIZE DT_REG_SIZE(DT_NODELABEL(ram0)) @@ -96,3 +99,12 @@ ZTEST(test_ram, test_sram2) ztest_test_skip(); #endif } + +ZTEST(test_ram, test_psram) +{ +#if DT_NODE_HAS_STATUS(DT_NODELABEL(memc), okay) + test_ram_rw(buf_psram, BUF_SIZE); +#else + ztest_test_skip(); +#endif +} diff --git a/tests/drivers/pwm/pwm_api/boards/esp32s3_devkitm.overlay b/tests/drivers/pwm/pwm_api/boards/esp32s3_devkitm_procpu.overlay similarity index 100% rename from tests/drivers/pwm/pwm_api/boards/esp32s3_devkitm.overlay rename to tests/drivers/pwm/pwm_api/boards/esp32s3_devkitm_procpu.overlay diff --git a/tests/drivers/pwm/pwm_api/boards/esp32s3_luatos_core.overlay b/tests/drivers/pwm/pwm_api/boards/esp32s3_luatos_core_procpu.overlay similarity index 100% rename from tests/drivers/pwm/pwm_api/boards/esp32s3_luatos_core.overlay rename to tests/drivers/pwm/pwm_api/boards/esp32s3_luatos_core_procpu.overlay diff --git a/tests/drivers/pwm/pwm_api/boards/esp32s3_luatos_core_esp32s3_procpu_usb.overlay b/tests/drivers/pwm/pwm_api/boards/esp32s3_luatos_core_procpu_usb.overlay similarity index 100% rename from tests/drivers/pwm/pwm_api/boards/esp32s3_luatos_core_esp32s3_procpu_usb.overlay rename to tests/drivers/pwm/pwm_api/boards/esp32s3_luatos_core_procpu_usb.overlay diff --git a/tests/drivers/pwm/pwm_api/boards/mimxrt1060_evk.overlay b/tests/drivers/pwm/pwm_api/boards/mimxrt1060_evk.overlay index ebd3af9f582..ff4a1217720 100644 --- a/tests/drivers/pwm/pwm_api/boards/mimxrt1060_evk.overlay +++ b/tests/drivers/pwm/pwm_api/boards/mimxrt1060_evk.overlay @@ -9,6 +9,13 @@ * by the test, but can be tested using the PWM shell. */ +/ { + aliases { + pwm-0 = &flexpwm1_pwm0; + pwm-1 = &flexpwm1_pwm3; + }; +}; + &flexpwm1_pwm3 { status = "okay"; }; diff --git a/tests/drivers/pwm/pwm_loopback/boards/esp32s3_devkitm.overlay b/tests/drivers/pwm/pwm_loopback/boards/esp32s3_devkitm_procpu.overlay similarity index 100% rename from tests/drivers/pwm/pwm_loopback/boards/esp32s3_devkitm.overlay rename to tests/drivers/pwm/pwm_loopback/boards/esp32s3_devkitm_procpu.overlay diff --git a/tests/drivers/pwm/pwm_loopback/boards/esp32s3_luatos_core.overlay b/tests/drivers/pwm/pwm_loopback/boards/esp32s3_luatos_core_procpu.overlay similarity index 100% rename from tests/drivers/pwm/pwm_loopback/boards/esp32s3_luatos_core.overlay rename to tests/drivers/pwm/pwm_loopback/boards/esp32s3_luatos_core_procpu.overlay diff --git a/tests/drivers/pwm/pwm_loopback/boards/esp32s3_luatos_core_esp32s3_procpu_usb.overlay b/tests/drivers/pwm/pwm_loopback/boards/esp32s3_luatos_core_procpu_usb.overlay similarity index 100% rename from tests/drivers/pwm/pwm_loopback/boards/esp32s3_luatos_core_esp32s3_procpu_usb.overlay rename to tests/drivers/pwm/pwm_loopback/boards/esp32s3_luatos_core_procpu_usb.overlay diff --git a/tests/drivers/pwm/pwm_loopback/boards/numaker_m2l31ki.conf b/tests/drivers/pwm/pwm_loopback/boards/numaker_m2l31ki.conf new file mode 100644 index 00000000000..9fb2581d7f4 --- /dev/null +++ b/tests/drivers/pwm/pwm_loopback/boards/numaker_m2l31ki.conf @@ -0,0 +1 @@ +CONFIG_TEST_USERSPACE=n diff --git a/tests/drivers/pwm/pwm_loopback/boards/numaker_m2l31ki.overlay b/tests/drivers/pwm/pwm_loopback/boards/numaker_m2l31ki.overlay new file mode 100644 index 00000000000..8d4f3c66d43 --- /dev/null +++ b/tests/drivers/pwm/pwm_loopback/boards/numaker_m2l31ki.overlay @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include + +&pinctrl { + epwm1_default: epwm1_default { + group0 { + /* EVB's D2, D5 --> PC4, PA6 */ + pinmux = , + ; + }; + }; +}; + +/ { + pwm_loopback_0 { + compatible = "test-pwm-loopback"; + pwms = <&epwm1 1 0 PWM_POLARITY_NORMAL>, + <&epwm1 5 0 PWM_POLARITY_NORMAL>; + }; +}; + +&epwm1 { + status = "okay"; + prescaler = <19>; + pinctrl-0 = <&epwm1_default>; + pinctrl-names = "default"; +}; diff --git a/tests/drivers/pwm/pwm_loopback/boards/numaker_pfm_m467.overlay b/tests/drivers/pwm/pwm_loopback/boards/numaker_pfm_m467.overlay index 2803a4289a2..3f28f49a4a2 100644 --- a/tests/drivers/pwm/pwm_loopback/boards/numaker_pfm_m467.overlay +++ b/tests/drivers/pwm/pwm_loopback/boards/numaker_pfm_m467.overlay @@ -6,8 +6,8 @@ epwm1_default: epwm1_default { group0 { /* EVB's D5, D3 --> PC12, PC10 */ - pinmux = , - ; + pinmux = , + ; }; }; }; diff --git a/tests/drivers/pwm/pwm_loopback/boards/twr_ke18f.overlay b/tests/drivers/pwm/pwm_loopback/boards/twr_ke18f.overlay index 30651f3a4a4..d5bb67ed33e 100644 --- a/tests/drivers/pwm/pwm_loopback/boards/twr_ke18f.overlay +++ b/tests/drivers/pwm/pwm_loopback/boards/twr_ke18f.overlay @@ -46,4 +46,5 @@ #pwm-cells = <3>; pinctrl-0 = <&ftm2_default>; pinctrl-names = "default"; + clock-source = "fixed"; }; diff --git a/tests/drivers/pwm/pwm_loopback/boards/yd_esp32.overlay b/tests/drivers/pwm/pwm_loopback/boards/yd_esp32_procpu.overlay similarity index 100% rename from tests/drivers/pwm/pwm_loopback/boards/yd_esp32.overlay rename to tests/drivers/pwm/pwm_loopback/boards/yd_esp32_procpu.overlay diff --git a/tests/drivers/regulator/voltage/boards/frdm_mcxn947_mcxn947_cpu0.overlay b/tests/drivers/regulator/voltage/boards/frdm_mcxn947_mcxn947_cpu0.overlay new file mode 100644 index 00000000000..3dfb29da938 --- /dev/null +++ b/tests/drivers/regulator/voltage/boards/frdm_mcxn947_mcxn947_cpu0.overlay @@ -0,0 +1,47 @@ +/* + * Copyright 2024 NXP + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +/* To do this test, connect LPADC0 channel 2A(J8 pin 28) to VREF_OUT (TP1) */ + +/ { + resources: resources { + compatible = "test-regulator-voltage"; + regulators = <&vref>; + tolerance-microvolt = <10000>; + set-read-delay-ms = <1>; + adc-avg-count = <10>; + io-channels = <&lpadc0 0>; + min-microvolt = <1000000>; + max-microvolt = <2100000>; + }; +}; + +&vref { + regulator-initial-mode = ; +}; + +&lpadc0 { + #address-cells = <1>; + #size-cells = <0>; + + /* In this case, the LPADC reference source cannot be set to VREFO, + * switch the reference source to VDD_ANA. + */ + voltage-ref= <2>; + + channel@0 { + reg = <0>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_EXTERNAL0"; + zephyr,vref-mv = <3300>; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + zephyr,input-positive = ; + }; +}; diff --git a/tests/drivers/rtc/rtc_api/boards/b_u585i_iot02a.conf b/tests/drivers/rtc/rtc_api/boards/b_u585i_iot02a.conf new file mode 100644 index 00000000000..8c6c114ee41 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/b_u585i_iot02a.conf @@ -0,0 +1,2 @@ +CONFIG_RTC_CALIBRATION=y +CONFIG_RTC_ALARM=y diff --git a/tests/drivers/rtc/rtc_api/boards/b_u585i_iot02a.overlay b/tests/drivers/rtc/rtc_api/boards/b_u585i_iot02a.overlay new file mode 100644 index 00000000000..bd861fccf42 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/b_u585i_iot02a.overlay @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + rtc = &rtc; + }; +}; diff --git a/tests/drivers/rtc/rtc_api/boards/da1469x_dk_pro.conf b/tests/drivers/rtc/rtc_api/boards/da1469x_dk_pro.conf new file mode 100644 index 00000000000..c4d616ff25d --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/da1469x_dk_pro.conf @@ -0,0 +1,2 @@ +CONFIG_RTC_ALARM=y +CONFIG_RTC_UPDATE=y diff --git a/tests/drivers/rtc/rtc_api/boards/da1469x_dk_pro.overlay b/tests/drivers/rtc/rtc_api/boards/da1469x_dk_pro.overlay new file mode 100644 index 00000000000..4f795b02288 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/da1469x_dk_pro.overlay @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2023 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + rtc = &rtc; + }; +}; + +&rtc { + status = "okay"; +}; diff --git a/tests/drivers/rtc/rtc_api/boards/disco_l475_iot1.conf b/tests/drivers/rtc/rtc_api/boards/disco_l475_iot1.conf new file mode 100644 index 00000000000..8c6c114ee41 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/disco_l475_iot1.conf @@ -0,0 +1,2 @@ +CONFIG_RTC_CALIBRATION=y +CONFIG_RTC_ALARM=y diff --git a/tests/drivers/rtc/rtc_api/boards/disco_l475_iot1.overlay b/tests/drivers/rtc/rtc_api/boards/disco_l475_iot1.overlay new file mode 100644 index 00000000000..bd861fccf42 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/disco_l475_iot1.overlay @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + rtc = &rtc; + }; +}; diff --git a/tests/drivers/rtc/rtc_api/boards/nucleo_f070rb.conf b/tests/drivers/rtc/rtc_api/boards/nucleo_f070rb.conf new file mode 100644 index 00000000000..8c6c114ee41 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/nucleo_f070rb.conf @@ -0,0 +1,2 @@ +CONFIG_RTC_CALIBRATION=y +CONFIG_RTC_ALARM=y diff --git a/tests/drivers/rtc/rtc_api/boards/nucleo_f070rb.overlay b/tests/drivers/rtc/rtc_api/boards/nucleo_f070rb.overlay new file mode 100644 index 00000000000..bd861fccf42 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/nucleo_f070rb.overlay @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + rtc = &rtc; + }; +}; diff --git a/tests/drivers/rtc/rtc_api/boards/nucleo_f091rc.conf b/tests/drivers/rtc/rtc_api/boards/nucleo_f091rc.conf new file mode 100644 index 00000000000..8c6c114ee41 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/nucleo_f091rc.conf @@ -0,0 +1,2 @@ +CONFIG_RTC_CALIBRATION=y +CONFIG_RTC_ALARM=y diff --git a/tests/drivers/rtc/rtc_api/boards/nucleo_f091rc.overlay b/tests/drivers/rtc/rtc_api/boards/nucleo_f091rc.overlay new file mode 100644 index 00000000000..bd861fccf42 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/nucleo_f091rc.overlay @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + rtc = &rtc; + }; +}; diff --git a/tests/drivers/rtc/rtc_api/boards/nucleo_f207zg.conf b/tests/drivers/rtc/rtc_api/boards/nucleo_f207zg.conf new file mode 100644 index 00000000000..d8e316b0bf2 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/nucleo_f207zg.conf @@ -0,0 +1 @@ +CONFIG_RTC_ALARM=y diff --git a/tests/drivers/rtc/rtc_api/boards/nucleo_f207zg.overlay b/tests/drivers/rtc/rtc_api/boards/nucleo_f207zg.overlay new file mode 100644 index 00000000000..bd861fccf42 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/nucleo_f207zg.overlay @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + rtc = &rtc; + }; +}; diff --git a/tests/drivers/rtc/rtc_api/boards/nucleo_f401re.conf b/tests/drivers/rtc/rtc_api/boards/nucleo_f401re.conf new file mode 100644 index 00000000000..8c6c114ee41 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/nucleo_f401re.conf @@ -0,0 +1,2 @@ +CONFIG_RTC_CALIBRATION=y +CONFIG_RTC_ALARM=y diff --git a/tests/drivers/rtc/rtc_api/boards/nucleo_f401re.overlay b/tests/drivers/rtc/rtc_api/boards/nucleo_f401re.overlay new file mode 100644 index 00000000000..bd861fccf42 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/nucleo_f401re.overlay @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + rtc = &rtc; + }; +}; diff --git a/tests/drivers/rtc/rtc_api/boards/nucleo_f429zi.conf b/tests/drivers/rtc/rtc_api/boards/nucleo_f429zi.conf new file mode 100644 index 00000000000..8c6c114ee41 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/nucleo_f429zi.conf @@ -0,0 +1,2 @@ +CONFIG_RTC_CALIBRATION=y +CONFIG_RTC_ALARM=y diff --git a/tests/drivers/rtc/rtc_api/boards/nucleo_f429zi.overlay b/tests/drivers/rtc/rtc_api/boards/nucleo_f429zi.overlay new file mode 100644 index 00000000000..bd861fccf42 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/nucleo_f429zi.overlay @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + rtc = &rtc; + }; +}; diff --git a/tests/drivers/rtc/rtc_api/boards/nucleo_f746zg.conf b/tests/drivers/rtc/rtc_api/boards/nucleo_f746zg.conf new file mode 100644 index 00000000000..8c6c114ee41 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/nucleo_f746zg.conf @@ -0,0 +1,2 @@ +CONFIG_RTC_CALIBRATION=y +CONFIG_RTC_ALARM=y diff --git a/tests/drivers/rtc/rtc_api/boards/nucleo_f746zg.overlay b/tests/drivers/rtc/rtc_api/boards/nucleo_f746zg.overlay new file mode 100644 index 00000000000..bd861fccf42 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/nucleo_f746zg.overlay @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + rtc = &rtc; + }; +}; diff --git a/tests/drivers/rtc/rtc_api/boards/nucleo_f767zi.conf b/tests/drivers/rtc/rtc_api/boards/nucleo_f767zi.conf new file mode 100644 index 00000000000..8c6c114ee41 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/nucleo_f767zi.conf @@ -0,0 +1,2 @@ +CONFIG_RTC_CALIBRATION=y +CONFIG_RTC_ALARM=y diff --git a/tests/drivers/rtc/rtc_api/boards/nucleo_f767zi.overlay b/tests/drivers/rtc/rtc_api/boards/nucleo_f767zi.overlay new file mode 100644 index 00000000000..bd861fccf42 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/nucleo_f767zi.overlay @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + rtc = &rtc; + }; +}; diff --git a/tests/drivers/rtc/rtc_api/boards/nucleo_g071rb.conf b/tests/drivers/rtc/rtc_api/boards/nucleo_g071rb.conf new file mode 100644 index 00000000000..8c6c114ee41 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/nucleo_g071rb.conf @@ -0,0 +1,2 @@ +CONFIG_RTC_CALIBRATION=y +CONFIG_RTC_ALARM=y diff --git a/tests/drivers/rtc/rtc_api/boards/nucleo_g071rb.overlay b/tests/drivers/rtc/rtc_api/boards/nucleo_g071rb.overlay new file mode 100644 index 00000000000..bd861fccf42 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/nucleo_g071rb.overlay @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + rtc = &rtc; + }; +}; diff --git a/tests/drivers/rtc/rtc_api/boards/nucleo_g474re.conf b/tests/drivers/rtc/rtc_api/boards/nucleo_g474re.conf new file mode 100644 index 00000000000..8c6c114ee41 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/nucleo_g474re.conf @@ -0,0 +1,2 @@ +CONFIG_RTC_CALIBRATION=y +CONFIG_RTC_ALARM=y diff --git a/tests/drivers/rtc/rtc_api/boards/nucleo_g474re.overlay b/tests/drivers/rtc/rtc_api/boards/nucleo_g474re.overlay new file mode 100644 index 00000000000..bd861fccf42 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/nucleo_g474re.overlay @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + rtc = &rtc; + }; +}; diff --git a/tests/drivers/rtc/rtc_api/boards/nucleo_h563zi.conf b/tests/drivers/rtc/rtc_api/boards/nucleo_h563zi.conf new file mode 100644 index 00000000000..8c6c114ee41 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/nucleo_h563zi.conf @@ -0,0 +1,2 @@ +CONFIG_RTC_CALIBRATION=y +CONFIG_RTC_ALARM=y diff --git a/tests/drivers/rtc/rtc_api/boards/nucleo_h723zg.conf b/tests/drivers/rtc/rtc_api/boards/nucleo_h723zg.conf new file mode 100644 index 00000000000..8c6c114ee41 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/nucleo_h723zg.conf @@ -0,0 +1,2 @@ +CONFIG_RTC_CALIBRATION=y +CONFIG_RTC_ALARM=y diff --git a/tests/drivers/rtc/rtc_api/boards/nucleo_h723zg.overlay b/tests/drivers/rtc/rtc_api/boards/nucleo_h723zg.overlay new file mode 100644 index 00000000000..bd861fccf42 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/nucleo_h723zg.overlay @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + rtc = &rtc; + }; +}; diff --git a/tests/drivers/rtc/rtc_api/boards/nucleo_h743zi.conf b/tests/drivers/rtc/rtc_api/boards/nucleo_h743zi.conf new file mode 100644 index 00000000000..8c6c114ee41 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/nucleo_h743zi.conf @@ -0,0 +1,2 @@ +CONFIG_RTC_CALIBRATION=y +CONFIG_RTC_ALARM=y diff --git a/tests/drivers/rtc/rtc_api/boards/nucleo_h743zi.overlay b/tests/drivers/rtc/rtc_api/boards/nucleo_h743zi.overlay new file mode 100644 index 00000000000..bd861fccf42 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/nucleo_h743zi.overlay @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + rtc = &rtc; + }; +}; diff --git a/tests/drivers/rtc/rtc_api/boards/nucleo_l073rz.conf b/tests/drivers/rtc/rtc_api/boards/nucleo_l073rz.conf new file mode 100644 index 00000000000..8c6c114ee41 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/nucleo_l073rz.conf @@ -0,0 +1,2 @@ +CONFIG_RTC_CALIBRATION=y +CONFIG_RTC_ALARM=y diff --git a/tests/drivers/rtc/rtc_api/boards/nucleo_l073rz.overlay b/tests/drivers/rtc/rtc_api/boards/nucleo_l073rz.overlay new file mode 100644 index 00000000000..bd861fccf42 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/nucleo_l073rz.overlay @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + rtc = &rtc; + }; +}; diff --git a/tests/drivers/rtc/rtc_api/boards/nucleo_l152re.conf b/tests/drivers/rtc/rtc_api/boards/nucleo_l152re.conf new file mode 100644 index 00000000000..d8e316b0bf2 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/nucleo_l152re.conf @@ -0,0 +1 @@ +CONFIG_RTC_ALARM=y diff --git a/tests/drivers/rtc/rtc_api/boards/nucleo_l152re.overlay b/tests/drivers/rtc/rtc_api/boards/nucleo_l152re.overlay new file mode 100644 index 00000000000..bd861fccf42 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/nucleo_l152re.overlay @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + rtc = &rtc; + }; +}; diff --git a/tests/drivers/rtc/rtc_api/boards/nucleo_l4r5zi.conf b/tests/drivers/rtc/rtc_api/boards/nucleo_l4r5zi.conf new file mode 100644 index 00000000000..8c6c114ee41 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/nucleo_l4r5zi.conf @@ -0,0 +1,2 @@ +CONFIG_RTC_CALIBRATION=y +CONFIG_RTC_ALARM=y diff --git a/tests/drivers/rtc/rtc_api/boards/nucleo_l4r5zi.overlay b/tests/drivers/rtc/rtc_api/boards/nucleo_l4r5zi.overlay new file mode 100644 index 00000000000..bd861fccf42 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/nucleo_l4r5zi.overlay @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + rtc = &rtc; + }; +}; diff --git a/tests/drivers/rtc/rtc_api/boards/nucleo_u575zi_q.conf b/tests/drivers/rtc/rtc_api/boards/nucleo_u575zi_q.conf new file mode 100644 index 00000000000..8c6c114ee41 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/nucleo_u575zi_q.conf @@ -0,0 +1,2 @@ +CONFIG_RTC_CALIBRATION=y +CONFIG_RTC_ALARM=y diff --git a/tests/drivers/rtc/rtc_api/boards/nucleo_u575zi_q.overlay b/tests/drivers/rtc/rtc_api/boards/nucleo_u575zi_q.overlay new file mode 100644 index 00000000000..bd861fccf42 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/nucleo_u575zi_q.overlay @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + rtc = &rtc; + }; +}; diff --git a/tests/drivers/rtc/rtc_api/boards/nucleo_u5a5zj_q.conf b/tests/drivers/rtc/rtc_api/boards/nucleo_u5a5zj_q.conf new file mode 100644 index 00000000000..8c6c114ee41 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/nucleo_u5a5zj_q.conf @@ -0,0 +1,2 @@ +CONFIG_RTC_CALIBRATION=y +CONFIG_RTC_ALARM=y diff --git a/tests/drivers/rtc/rtc_api/boards/nucleo_u5a5zj_q.overlay b/tests/drivers/rtc/rtc_api/boards/nucleo_u5a5zj_q.overlay new file mode 100644 index 00000000000..bd861fccf42 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/nucleo_u5a5zj_q.overlay @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + rtc = &rtc; + }; +}; diff --git a/tests/drivers/rtc/rtc_api/boards/nucleo_wb55rg.conf b/tests/drivers/rtc/rtc_api/boards/nucleo_wb55rg.conf new file mode 100644 index 00000000000..8c6c114ee41 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/nucleo_wb55rg.conf @@ -0,0 +1,2 @@ +CONFIG_RTC_CALIBRATION=y +CONFIG_RTC_ALARM=y diff --git a/tests/drivers/rtc/rtc_api/boards/nucleo_wb55rg.overlay b/tests/drivers/rtc/rtc_api/boards/nucleo_wb55rg.overlay new file mode 100644 index 00000000000..bd861fccf42 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/nucleo_wb55rg.overlay @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + rtc = &rtc; + }; +}; diff --git a/tests/drivers/rtc/rtc_api/boards/nucleo_wba52cg.conf b/tests/drivers/rtc/rtc_api/boards/nucleo_wba52cg.conf new file mode 100644 index 00000000000..8c6c114ee41 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/nucleo_wba52cg.conf @@ -0,0 +1,2 @@ +CONFIG_RTC_CALIBRATION=y +CONFIG_RTC_ALARM=y diff --git a/tests/drivers/rtc/rtc_api/boards/nucleo_wba52cg.overlay b/tests/drivers/rtc/rtc_api/boards/nucleo_wba52cg.overlay new file mode 100644 index 00000000000..bd861fccf42 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/nucleo_wba52cg.overlay @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + rtc = &rtc; + }; +}; diff --git a/tests/drivers/rtc/rtc_api/boards/nucleo_wba55cg.conf b/tests/drivers/rtc/rtc_api/boards/nucleo_wba55cg.conf new file mode 100644 index 00000000000..8c6c114ee41 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/nucleo_wba55cg.conf @@ -0,0 +1,2 @@ +CONFIG_RTC_CALIBRATION=y +CONFIG_RTC_ALARM=y diff --git a/tests/drivers/rtc/rtc_api/boards/nucleo_wba55cg.overlay b/tests/drivers/rtc/rtc_api/boards/nucleo_wba55cg.overlay new file mode 100644 index 00000000000..bd861fccf42 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/nucleo_wba55cg.overlay @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + rtc = &rtc; + }; +}; diff --git a/tests/drivers/rtc/rtc_api/boards/nucleo_wl55jc.conf b/tests/drivers/rtc/rtc_api/boards/nucleo_wl55jc.conf new file mode 100644 index 00000000000..d8e316b0bf2 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/nucleo_wl55jc.conf @@ -0,0 +1 @@ +CONFIG_RTC_ALARM=y diff --git a/tests/drivers/rtc/rtc_api/boards/nucleo_wl55jc.overlay b/tests/drivers/rtc/rtc_api/boards/nucleo_wl55jc.overlay new file mode 100644 index 00000000000..bd861fccf42 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/nucleo_wl55jc.overlay @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + rtc = &rtc; + }; +}; diff --git a/tests/drivers/rtc/rtc_api/boards/stm32f3_disco.conf b/tests/drivers/rtc/rtc_api/boards/stm32f3_disco.conf new file mode 100644 index 00000000000..8c6c114ee41 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/stm32f3_disco.conf @@ -0,0 +1,2 @@ +CONFIG_RTC_CALIBRATION=y +CONFIG_RTC_ALARM=y diff --git a/tests/drivers/rtc/rtc_api/boards/stm32f3_disco.overlay b/tests/drivers/rtc/rtc_api/boards/stm32f3_disco.overlay new file mode 100644 index 00000000000..bd861fccf42 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/stm32f3_disco.overlay @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + rtc = &rtc; + }; +}; diff --git a/tests/drivers/rtc/rtc_api/boards/stm32h573i_dk.conf b/tests/drivers/rtc/rtc_api/boards/stm32h573i_dk.conf new file mode 100644 index 00000000000..8c6c114ee41 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/stm32h573i_dk.conf @@ -0,0 +1,2 @@ +CONFIG_RTC_CALIBRATION=y +CONFIG_RTC_ALARM=y diff --git a/tests/drivers/rtc/rtc_api/boards/stm32h573i_dk.overlay b/tests/drivers/rtc/rtc_api/boards/stm32h573i_dk.overlay new file mode 100644 index 00000000000..bd861fccf42 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/stm32h573i_dk.overlay @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + rtc = &rtc; + }; +}; diff --git a/tests/drivers/rtc/rtc_api/boards/stm32h750b_dk.conf b/tests/drivers/rtc/rtc_api/boards/stm32h750b_dk.conf new file mode 100644 index 00000000000..8c6c114ee41 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/stm32h750b_dk.conf @@ -0,0 +1,2 @@ +CONFIG_RTC_CALIBRATION=y +CONFIG_RTC_ALARM=y diff --git a/tests/drivers/rtc/rtc_api/boards/stm32h750b_dk.overlay b/tests/drivers/rtc/rtc_api/boards/stm32h750b_dk.overlay new file mode 100644 index 00000000000..bd861fccf42 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/stm32h750b_dk.overlay @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + rtc = &rtc; + }; +}; diff --git a/tests/drivers/rtc/rtc_api/src/test_alarm.c b/tests/drivers/rtc/rtc_api/src/test_alarm.c index f65baf15877..5f81d05c87b 100644 --- a/tests/drivers/rtc/rtc_api/src/test_alarm.c +++ b/tests/drivers/rtc/rtc_api/src/test_alarm.c @@ -1,5 +1,6 @@ /* - * Copyright 2022 Bjarki Arge Andreasen + * Copyright (c) 2022 Bjarki Arge Andreasen + * Copyright (c) 2024 STMicroelectronics * * SPDX-License-Identifier: Apache-2.0 */ @@ -38,7 +39,7 @@ ZTEST(rtc_api, test_alarm) for (uint16_t i = 0; i < alarms_count; i++) { ret = rtc_alarm_set_time(rtc, i, 0, NULL); - zassert_ok(ret, "Failed to clear alarm time"); + zassert_ok(ret, "Failed to clear alarm %d time", i); } /* Disable alarm callback */ @@ -46,14 +47,14 @@ ZTEST(rtc_api, test_alarm) ret = rtc_alarm_set_callback(rtc, i, NULL, NULL); zassert_true((ret == 0) || (ret == -ENOTSUP), - "Failed to clear and disable alarm callback"); + "Failed to clear and disable alarm %d callback", i); } /* Every supported alarm field should reject invalid values. */ for (uint16_t i = 0; i < alarms_count; i++) { ret = rtc_alarm_get_supported_fields(rtc, i, &alarm_time_mask_supported); - zassert_ok(ret, "Failed to get supported alarm fields"); + zassert_ok(ret, "Failed to get supported alarm %d fields", i); alarm_time_set = (struct rtc_time) { .tm_sec = 70, @@ -77,8 +78,8 @@ ZTEST(rtc_api, test_alarm) ret = rtc_alarm_set_time(rtc, i, masks[j], &alarm_time_set); zassert_equal( -EINVAL, ret, - "%s: RTC should reject invalid alarm time in field %zu.", - rtc->name, j); + "%s: RTC should reject invalid alarm %d time in field %zu.", + rtc->name, i, j); } } } @@ -87,7 +88,7 @@ ZTEST(rtc_api, test_alarm) for (uint16_t i = 0; i < alarms_count; i++) { ret = rtc_alarm_get_supported_fields(rtc, i, &alarm_time_mask_supported); - zassert_ok(ret, "Failed to get supported alarm fields"); + zassert_ok(ret, "Failed to get supported alarm %d fields", i); /* Skip test if alarm does not support the minute and hour fields */ if (((RTC_ALARM_TIME_MASK_MINUTE & alarm_time_mask_supported) == 0) || @@ -104,23 +105,23 @@ ZTEST(rtc_api, test_alarm) for (uint16_t i = 0; i < alarms_count; i++) { ret = rtc_alarm_set_time(rtc, i, alarm_time_mask_set, &alarm_time_set); - zassert_ok(ret, "Failed to set alarm time"); + zassert_ok(ret, "Failed to set alarm %d time", i); } /* Validate alarm time */ for (uint16_t i = 0; i < alarms_count; i++) { ret = rtc_alarm_get_time(rtc, i, &alarm_time_mask_get, &alarm_time_get); - zassert_ok(ret, "Failed to set alarm time"); + zassert_ok(ret, "Failed to set alarm %d time", i); zassert_equal(alarm_time_mask_get, alarm_time_mask_set, - "Incorrect alarm time mask"); + "Incorrect alarm %d time mask", i); zassert_equal(alarm_time_get.tm_min, alarm_time_set.tm_min, - "Incorrect alarm time minute field"); + "Incorrect alarm %d time minute field", i); zassert_equal(alarm_time_get.tm_hour, alarm_time_set.tm_hour, - "Incorrect alarm time hour field"); + "Incorrect alarm %d time hour field", i); } /* Initialize RTC time to set */ @@ -141,7 +142,7 @@ ZTEST(rtc_api, test_alarm) for (uint16_t i = 0; i < alarms_count; i++) { ret = rtc_alarm_is_pending(rtc, i); - zassert_true(ret > -1, "Failed to clear alarm pending status"); + zassert_true(ret > -1, "Failed to clear alarm %d pending status", i); } /* Wait before validating alarm pending status has not been set prematurely */ @@ -151,7 +152,7 @@ ZTEST(rtc_api, test_alarm) for (uint16_t i = 0; i < alarms_count; i++) { ret = rtc_alarm_is_pending(rtc, i); - zassert_ok(ret, "Alarm should not be pending"); + zassert_ok(ret, "Alarm %d should not be pending", i); } /* Wait for alarm to trigger */ @@ -161,7 +162,7 @@ ZTEST(rtc_api, test_alarm) for (uint16_t i = 0; i < alarms_count; i++) { ret = rtc_alarm_is_pending(rtc, i); - zassert_equal(ret, 1, "Alarm should be pending"); + zassert_equal(ret, 1, "Alarm %d should be pending", i); } } @@ -169,10 +170,10 @@ ZTEST(rtc_api, test_alarm) for (uint16_t i = 0; i < alarms_count; i++) { ret = rtc_alarm_set_time(rtc, i, 0, NULL); - zassert_ok(ret, "Failed to disable alarm"); + zassert_ok(ret, "Failed to disable alarm %d", i); ret = rtc_alarm_is_pending(rtc, i); - zassert_true(ret > -1, "Failed to clear alarm pending state"); + zassert_true(ret > -1, "Failed to clear alarm %d pending state", i); } } diff --git a/tests/drivers/rtc/rtc_api/src/test_alarm_callback.c b/tests/drivers/rtc/rtc_api/src/test_alarm_callback.c index 9b51d889c0e..c73cbd5fbdd 100644 --- a/tests/drivers/rtc/rtc_api/src/test_alarm_callback.c +++ b/tests/drivers/rtc/rtc_api/src/test_alarm_callback.c @@ -1,5 +1,6 @@ /* - * Copyright 2022 Bjarki Arge Andreasen + * Copyright (c) 2022 Bjarki Arge Andreasen + * Copyright (c) 2024 STMicroelectronics * * SPDX-License-Identifier: Apache-2.0 */ @@ -54,14 +55,14 @@ ZTEST(rtc_api, test_alarm_callback) for (uint16_t i = 0; i < alarms_count; i++) { ret = rtc_alarm_set_callback(rtc, i, NULL, NULL); - zassert_ok(ret, "Failed to clear and disable alarm"); + zassert_ok(ret, "Failed to clear and disable alarm %d", i); } /* Validate alarms supported fields */ for (uint16_t i = 0; i < alarms_count; i++) { ret = rtc_alarm_get_supported_fields(rtc, i, &alarm_time_mask_supported); - zassert_ok(ret, "Failed to get supported alarm fields"); + zassert_ok(ret, "Failed to get supported alarm %d fields", i); /* Skip test if alarm does not support the minute and hour fields */ if (((RTC_ALARM_TIME_MASK_MINUTE & alarm_time_mask_supported) == 0) || @@ -78,7 +79,7 @@ ZTEST(rtc_api, test_alarm_callback) for (uint16_t i = 0; i < alarms_count; i++) { ret = rtc_alarm_set_time(rtc, i, alarm_time_mask_set, &alarm_time_set); - zassert_ok(ret, "Failed to set alarm time"); + zassert_ok(ret, "Failed to set alarm %d time", i); } /* Initialize RTC time to set */ @@ -98,7 +99,7 @@ ZTEST(rtc_api, test_alarm_callback) for (uint16_t i = 0; i < alarms_count; i++) { ret = rtc_alarm_is_pending(rtc, i); - zassert_true(ret > -1, "Failed to clear alarm pending status"); + zassert_true(ret > -1, "Failed to clear alarm %d pending status", i); } /* Set and enable alarm callback */ @@ -113,7 +114,7 @@ ZTEST(rtc_api, test_alarm_callback) &callback_user_data_even); } - zassert_ok(ret, "Failed to set alarm callback"); + zassert_ok(ret, "Failed to set alarm %d callback", i); } for (uint8_t i = 0; i < 2; i++) { @@ -143,7 +144,7 @@ ZTEST(rtc_api, test_alarm_callback) : atomic_test_bit(&callback_called_mask_even, j); zassert_equal(callback_called_status, true, - "Alarm callback should have been called"); + "Alarm %d callback should have been called", j); } /* Reset RTC time */ @@ -156,14 +157,14 @@ ZTEST(rtc_api, test_alarm_callback) for (uint16_t i = 0; i < alarms_count; i++) { ret = rtc_alarm_set_callback(rtc, i, NULL, NULL); - zassert_ok(ret, "Failed to disable alarm callback"); + zassert_ok(ret, "Failed to disable alarm %d callback", i); ret = rtc_alarm_set_time(rtc, i, 0, NULL); - zassert_ok(ret, "Failed to disable alarm"); + zassert_ok(ret, "Failed to disable alarm %d", i); ret = rtc_alarm_is_pending(rtc, i); - zassert_true(ret > -1, "Failed to clear alarm pending state"); + zassert_true(ret > -1, "Failed to clear alarm %d pending state", i); } } diff --git a/tests/drivers/rtc/rtc_api/src/test_y2k.c b/tests/drivers/rtc/rtc_api/src/test_y2k.c index d702a2d008b..bb64af0cda4 100644 --- a/tests/drivers/rtc/rtc_api/src/test_y2k.c +++ b/tests/drivers/rtc/rtc_api/src/test_y2k.c @@ -40,7 +40,15 @@ ZTEST(rtc_api, test_y2k) /* Party like it's 1999 */ zassert_not_null(gmtime_r(&t[Y99], tm[Y99])); - zassert_ok(rtc_set_time(rtc, &rtm[Y99])); + + int ret = rtc_set_time(rtc, &rtm[Y99]); + + if (ret == -EINVAL) { + TC_PRINT("Rollover not supported\n"); + ztest_test_skip(); + } else { + zassert_ok(ret, "RTC Set Time Failed"); + } /* Living after midnight */ k_sleep(K_SECONDS(SECONDS_BEFORE + SECONDS_AFTER)); diff --git a/tests/drivers/sdhc/src/main.c b/tests/drivers/sdhc/src/main.c index 1ee9b7a1ba9..205b367a741 100644 --- a/tests/drivers/sdhc/src/main.c +++ b/tests/drivers/sdhc/src/main.c @@ -17,6 +17,27 @@ static struct sdhc_io io; K_SEM_DEFINE(card_sem, 0, 1); +/* Prepare IO settings for card */ +static void *sdhc_power_on(void) +{ + int ret; + + ret = sdhc_get_host_props(sdhc_dev, &props); + zassert_equal(ret, 0, "SDHC host props api call failed"); + + io.clock = props.f_min; + io.bus_mode = SDHC_BUSMODE_PUSHPULL; + io.power_mode = SDHC_POWER_ON; + io.bus_width = SDHC_BUS_WIDTH1BIT; + io.timing = SDHC_TIMING_LEGACY; + io.signal_voltage = SD_VOL_3_3_V; + + ret = sdhc_set_io(sdhc_dev, &io); + zassert_equal(ret, 0, "Setting io configuration failed"); + k_msleep(props.power_delay); + return NULL; +} + /* Resets SD host controller, verifies API */ ZTEST(sdhc, test_reset) { @@ -33,6 +54,8 @@ ZTEST(sdhc, test_host_props) { int ret; + zassert_true(device_is_ready(sdhc_dev), "SDHC device is not ready"); + /* Set all host properties to 0xFF */ props.f_max = 0xFF; props.f_min = 0xFF; @@ -56,6 +79,8 @@ ZTEST(sdhc, test_set_io) { int ret; + zassert_true(device_is_ready(sdhc_dev), "SDHC device is not ready"); + io.clock = props.f_min; io.bus_mode = SDHC_BUSMODE_PUSHPULL; io.power_mode = SDHC_POWER_ON; @@ -88,16 +113,12 @@ void sdhc_interrupt_cb(const struct device *dev, int source, const void *data) /* * Verify that the driver can detect a present SD card - * This test must run first, to ensure the card is present. */ -ZTEST(sdhc, test_0_card_presence) +ZTEST(sdhc, test_card_presence) { int ret; - io.clock = props.f_min; - ret = sdhc_set_io(sdhc_dev, &io); - zassert_equal(ret, 0, "Setting io configuration failed"); - k_msleep(props.power_delay); + zassert_true(device_is_ready(sdhc_dev), "SDHC device is not ready"); ret = sdhc_card_present(sdhc_dev); if (ret == 0) { @@ -126,6 +147,8 @@ ZTEST(sdhc, test_card_if_cond) int ret, resp; int check_pattern = SD_IF_COND_CHECK; + zassert_true(device_is_ready(sdhc_dev), "SDHC device is not ready"); + /* Toggle power to card, to clear state */ io.power_mode = SDHC_POWER_OFF; ret = sdhc_set_io(sdhc_dev, &io); @@ -172,4 +195,4 @@ ZTEST(sdhc, test_card_if_cond) } } -ZTEST_SUITE(sdhc, NULL, NULL, NULL, NULL, NULL); +ZTEST_SUITE(sdhc, NULL, sdhc_power_on, NULL, NULL, NULL); diff --git a/tests/drivers/sensor/bmi160/src/fixture.c b/tests/drivers/sensor/bmi160/src/fixture.c index a97be2cb784..3f36744e3d1 100644 --- a/tests/drivers/sensor/bmi160/src/fixture.c +++ b/tests/drivers/sensor/bmi160/src/fixture.c @@ -33,7 +33,9 @@ static void sensor_bmi160_setup_emulator(const struct device *dev, const struct zassert_ok(sensor_attr_set(dev, SENSOR_CHAN_GYRO_XYZ, SENSOR_ATTR_FULL_SCALE, &scale)); for (size_t i = 0; i < ARRAY_SIZE(values); ++i) { - zassert_ok(emul_sensor_backend_set_channel(emulator, values[i].channel, + struct sensor_chan_spec chan_spec = {.chan_type = values[i].channel, .chan_idx = 0}; + + zassert_ok(emul_sensor_backend_set_channel(emulator, chan_spec, &values[i].value, 3)); } } diff --git a/tests/drivers/sensor/temp_sensor/CMakeLists.txt b/tests/drivers/sensor/temp_sensor/CMakeLists.txt new file mode 100644 index 00000000000..6aed768ebda --- /dev/null +++ b/tests/drivers/sensor/temp_sensor/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(temp_sensor) + +FILE(GLOB app_sources src/*.c) + +target_sources(app PRIVATE ${app_sources}) diff --git a/tests/drivers/sensor/temp_sensor/boards/nrf52840dk_nrf52840.overlay b/tests/drivers/sensor/temp_sensor/boards/nrf52840dk_nrf52840.overlay new file mode 100644 index 00000000000..435e4f4a6cc --- /dev/null +++ b/tests/drivers/sensor/temp_sensor/boards/nrf52840dk_nrf52840.overlay @@ -0,0 +1,3 @@ +temp_sensor: &temp { + status = "okay"; +}; diff --git a/tests/drivers/sensor/temp_sensor/boards/nrf54h20dk_nrf54h20_cpuapp.conf b/tests/drivers/sensor/temp_sensor/boards/nrf54h20dk_nrf54h20_cpuapp.conf new file mode 100644 index 00000000000..371797173d9 --- /dev/null +++ b/tests/drivers/sensor/temp_sensor/boards/nrf54h20dk_nrf54h20_cpuapp.conf @@ -0,0 +1,2 @@ +CONFIG_NRFS=y +CONFIG_TEMP_NRFS_TRIGGER_OWN_THREAD=y diff --git a/tests/drivers/sensor/temp_sensor/boards/nrf54h20dk_nrf54h20_cpuapp.overlay b/tests/drivers/sensor/temp_sensor/boards/nrf54h20dk_nrf54h20_cpuapp.overlay new file mode 100644 index 00000000000..012c93a8fa8 --- /dev/null +++ b/tests/drivers/sensor/temp_sensor/boards/nrf54h20dk_nrf54h20_cpuapp.overlay @@ -0,0 +1,3 @@ +temp_sensor: &temp_nrfs { + status = "okay"; +}; diff --git a/tests/drivers/sensor/temp_sensor/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay b/tests/drivers/sensor/temp_sensor/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay new file mode 100644 index 00000000000..435e4f4a6cc --- /dev/null +++ b/tests/drivers/sensor/temp_sensor/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay @@ -0,0 +1,3 @@ +temp_sensor: &temp { + status = "okay"; +}; diff --git a/tests/drivers/sensor/temp_sensor/prj.conf b/tests/drivers/sensor/temp_sensor/prj.conf new file mode 100644 index 00000000000..97305dd78ef --- /dev/null +++ b/tests/drivers/sensor/temp_sensor/prj.conf @@ -0,0 +1,2 @@ +CONFIG_ZTEST=y +CONFIG_SENSOR=y diff --git a/tests/drivers/sensor/temp_sensor/src/main.c b/tests/drivers/sensor/temp_sensor/src/main.c new file mode 100644 index 00000000000..ba4da1f4173 --- /dev/null +++ b/tests/drivers/sensor/temp_sensor/src/main.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2024, Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +static const struct device *temp_dev = DEVICE_DT_GET(DT_NODELABEL(temp_sensor)); +static enum sensor_channel chan_to_use; /* this is filled by before() */ + +static volatile bool trigger_handler_called; + +ZTEST(temp_sensor, test_polling) +{ + int rc; + int cnt; + struct sensor_value val; + + cnt = 0; + while (1) { + int32_t temp_val; + + rc = sensor_sample_fetch_chan(temp_dev, chan_to_use); + zassert_ok(rc, "Cannot fetch chan sample: %d.", rc); + + rc = sensor_channel_get(temp_dev, chan_to_use, &val); + zassert_ok(rc, "Cannot read from channel %d: %d.", + chan_to_use, rc); + + temp_val = (val.val1 * 100) + (val.val2 / 10000); + TC_PRINT("Temperature: %d.%02u\n", + temp_val/100, abs(temp_val) % 100); + + ++cnt; + if (cnt >= 5) { + break; + } + + k_sleep(K_MSEC(500)); + } +} + +static void trigger_handler(const struct device *temp_dev, + const struct sensor_trigger *trig) +{ + ARG_UNUSED(temp_dev); + ARG_UNUSED(trig); + + trigger_handler_called = true; +} + +ZTEST(temp_sensor, test_trigger) +{ + int rc; + struct sensor_value val; + struct sensor_trigger trig = { .type = SENSOR_TRIG_THRESHOLD, + .chan = chan_to_use }; + + /* Check if the sensor allows setting a threshold trigger. + * If not, skip the test. + */ + rc = sensor_trigger_set(temp_dev, &trig, NULL); + if (rc == -ENOSYS || rc == -ENOTSUP) { + TC_PRINT("This sensor does not support threshold trigger.\n"); + ztest_test_skip(); + } + + rc = sensor_channel_get(temp_dev, chan_to_use, &val); + zassert_ok(rc, "Cannot read from channel %d: %d.", + chan_to_use, rc); + + /* Set the upper threshold somewhat below the temperature read above. */ + val.val1 -= 5; + rc = sensor_attr_set(temp_dev, chan_to_use, + SENSOR_ATTR_UPPER_THRESH, &val); + zassert_ok(rc, "Cannot set upper threshold: %d.", rc); + + /* And the lower threshold below the upper one. */ + val.val1 -= 1; + rc = sensor_attr_set(temp_dev, chan_to_use, + SENSOR_ATTR_LOWER_THRESH, &val); + zassert_ok(rc, "Cannot set lower threshold: %d.", rc); + + /* Set sampling frequency to 10 Hz, to expect a trigger after 100 ms. */ + val.val1 = 10; + val.val2 = 0; + rc = sensor_attr_set(temp_dev, chan_to_use, + SENSOR_ATTR_SAMPLING_FREQUENCY, &val); + zassert_ok(rc, "Cannot set sampling frequency: %d.", rc); + + trigger_handler_called = false; + + rc = sensor_trigger_set(temp_dev, &trig, trigger_handler); + zassert_ok(rc, "Cannot enable the trigger: %d.", rc); + + k_sleep(K_MSEC(300)); + zassert_true(trigger_handler_called); + + rc = sensor_trigger_set(temp_dev, &trig, NULL); + zassert_ok(rc, "Cannot disable the trigger: %d.", rc); + + trigger_handler_called = false; + + k_sleep(K_MSEC(300)); + zassert_false(trigger_handler_called); +} + +static void before(void *fixture) +{ + ARG_UNUSED(fixture); + + int rc; + int cnt; + struct sensor_value val; + + zassert_true(device_is_ready(temp_dev), + "Device %s is not ready.", temp_dev->name); + + cnt = 0; + /* Try to fetch a sample to check if the sensor is ready to work. + * Try several times if it appears to be needing a while for some + * initialization of communication etc. + */ + while (1) { + rc = sensor_sample_fetch(temp_dev); + if (rc != -EAGAIN && rc != -ENOTCONN) { + break; + } + + ++cnt; + zassert_false(cnt >= 3, "Cannot fetch a sample: %d.", rc); + + k_sleep(K_MSEC(1000)); + } + zassert_ok(rc, "Cannot fetch a sample: %d.", rc); + + /* Check if the sensor provides the die temperature. + * If not, switch to the ambient one. + */ + chan_to_use = SENSOR_CHAN_DIE_TEMP; + rc = sensor_channel_get(temp_dev, chan_to_use, &val); + if (rc == -ENOTSUP) { + chan_to_use = SENSOR_CHAN_AMBIENT_TEMP; + } +} + +ZTEST_SUITE(temp_sensor, NULL, NULL, before, NULL, NULL); diff --git a/tests/drivers/sensor/temp_sensor/testcase.yaml b/tests/drivers/sensor/temp_sensor/testcase.yaml new file mode 100644 index 00000000000..1a12dcb270d --- /dev/null +++ b/tests/drivers/sensor/temp_sensor/testcase.yaml @@ -0,0 +1,9 @@ +tests: + drivers.sensor.temp_sensor: + tags: + - drivers + - sensors + filter: dt_nodelabel_enabled("temp_sensor") + integration_platforms: + - nrf52840dk/nrf52840 + - nrf54h20dk/nrf54h20/cpuapp diff --git a/tests/drivers/smbus/smbus_emul/src/smbus.c b/tests/drivers/smbus/smbus_emul/src/smbus.c index fee5a18b449..b590470ff70 100644 --- a/tests/drivers/smbus/smbus_emul/src/smbus.c +++ b/tests/drivers/smbus/smbus_emul/src/smbus.c @@ -49,7 +49,6 @@ static void mock_conf_write(pcie_bdf_t bdf, unsigned int reg, uint32_t data) #define CONFIG_SMBUS_INTEL_PCH_ACCESS_IO #define device_map(a, b, c, d) -#define pcie_probe(bdf, id) 1 #define pcie_set_cmd(a, b, c) #define SMBUS_EMUL "smbus_emul" diff --git a/tests/drivers/spi/spi_loopback/boards/esp32s3_devkitm.conf b/tests/drivers/spi/spi_loopback/boards/esp32s3_devkitm_procpu.conf similarity index 100% rename from tests/drivers/spi/spi_loopback/boards/esp32s3_devkitm.conf rename to tests/drivers/spi/spi_loopback/boards/esp32s3_devkitm_procpu.conf diff --git a/tests/drivers/spi/spi_loopback/boards/esp32s3_devkitm.overlay b/tests/drivers/spi/spi_loopback/boards/esp32s3_devkitm_procpu.overlay similarity index 100% rename from tests/drivers/spi/spi_loopback/boards/esp32s3_devkitm.overlay rename to tests/drivers/spi/spi_loopback/boards/esp32s3_devkitm_procpu.overlay diff --git a/tests/drivers/spi/spi_loopback/boards/esp32s3_luatos_core.conf b/tests/drivers/spi/spi_loopback/boards/esp32s3_luatos_core_procpu.conf similarity index 100% rename from tests/drivers/spi/spi_loopback/boards/esp32s3_luatos_core.conf rename to tests/drivers/spi/spi_loopback/boards/esp32s3_luatos_core_procpu.conf diff --git a/tests/drivers/spi/spi_loopback/boards/esp32s3_luatos_core.overlay b/tests/drivers/spi/spi_loopback/boards/esp32s3_luatos_core_procpu.overlay similarity index 100% rename from tests/drivers/spi/spi_loopback/boards/esp32s3_luatos_core.overlay rename to tests/drivers/spi/spi_loopback/boards/esp32s3_luatos_core_procpu.overlay diff --git a/tests/drivers/spi/spi_loopback/boards/esp32s3_luatos_core_esp32s3_procpu_usb.conf b/tests/drivers/spi/spi_loopback/boards/esp32s3_luatos_core_procpu_usb.conf similarity index 100% rename from tests/drivers/spi/spi_loopback/boards/esp32s3_luatos_core_esp32s3_procpu_usb.conf rename to tests/drivers/spi/spi_loopback/boards/esp32s3_luatos_core_procpu_usb.conf diff --git a/tests/drivers/spi/spi_loopback/boards/esp32s3_luatos_core_esp32s3_procpu_usb.overlay b/tests/drivers/spi/spi_loopback/boards/esp32s3_luatos_core_procpu_usb.overlay similarity index 100% rename from tests/drivers/spi/spi_loopback/boards/esp32s3_luatos_core_esp32s3_procpu_usb.overlay rename to tests/drivers/spi/spi_loopback/boards/esp32s3_luatos_core_procpu_usb.overlay diff --git a/tests/drivers/spi/spi_loopback/boards/nucleo_f746zg.conf b/tests/drivers/spi/spi_loopback/boards/nucleo_f746zg.conf index 24be02d577c..c448e14811f 100644 --- a/tests/drivers/spi/spi_loopback/boards/nucleo_f746zg.conf +++ b/tests/drivers/spi/spi_loopback/boards/nucleo_f746zg.conf @@ -1 +1 @@ -CONFIG_DCACHE=n +CONFIG_NOCACHE_MEMORY=y diff --git a/tests/drivers/spi/spi_loopback/boards/nucleo_f746zg.overlay b/tests/drivers/spi/spi_loopback/boards/nucleo_f746zg.overlay index 32899f3aa3d..2d1f0182e0c 100644 --- a/tests/drivers/spi/spi_loopback/boards/nucleo_f746zg.overlay +++ b/tests/drivers/spi/spi_loopback/boards/nucleo_f746zg.overlay @@ -4,6 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +/* Arduino Header pins: MOSI:D11, MISO:D12 */ &spi1 { dmas = <&dma2 5 3 0x28440 0x03 &dma2 2 3 0x28480 0x03>; diff --git a/tests/drivers/spi/spi_loopback/boards/nucleo_f767zi.conf b/tests/drivers/spi/spi_loopback/boards/nucleo_f767zi.conf index 24be02d577c..c448e14811f 100644 --- a/tests/drivers/spi/spi_loopback/boards/nucleo_f767zi.conf +++ b/tests/drivers/spi/spi_loopback/boards/nucleo_f767zi.conf @@ -1 +1 @@ -CONFIG_DCACHE=n +CONFIG_NOCACHE_MEMORY=y diff --git a/tests/drivers/spi/spi_loopback/boards/nucleo_f767zi.overlay b/tests/drivers/spi/spi_loopback/boards/nucleo_f767zi.overlay index 32899f3aa3d..2d1f0182e0c 100644 --- a/tests/drivers/spi/spi_loopback/boards/nucleo_f767zi.overlay +++ b/tests/drivers/spi/spi_loopback/boards/nucleo_f767zi.overlay @@ -4,6 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +/* Arduino Header pins: MOSI:D11, MISO:D12 */ &spi1 { dmas = <&dma2 5 3 0x28440 0x03 &dma2 2 3 0x28480 0x03>; diff --git a/tests/drivers/spi/spi_loopback/boards/olimex_esp32_evb.conf b/tests/drivers/spi/spi_loopback/boards/olimex_esp32_evb_procpu.conf similarity index 100% rename from tests/drivers/spi/spi_loopback/boards/olimex_esp32_evb.conf rename to tests/drivers/spi/spi_loopback/boards/olimex_esp32_evb_procpu.conf diff --git a/tests/drivers/spi/spi_loopback/boards/olimex_esp32_evb.overlay b/tests/drivers/spi/spi_loopback/boards/olimex_esp32_evb_procpu.overlay similarity index 100% rename from tests/drivers/spi/spi_loopback/boards/olimex_esp32_evb.overlay rename to tests/drivers/spi/spi_loopback/boards/olimex_esp32_evb_procpu.overlay diff --git a/tests/drivers/spi/spi_loopback/boards/yd_esp32.conf b/tests/drivers/spi/spi_loopback/boards/yd_esp32_procpu.conf similarity index 100% rename from tests/drivers/spi/spi_loopback/boards/yd_esp32.conf rename to tests/drivers/spi/spi_loopback/boards/yd_esp32_procpu.conf diff --git a/tests/drivers/spi/spi_loopback/boards/yd_esp32.overlay b/tests/drivers/spi/spi_loopback/boards/yd_esp32_procpu.overlay similarity index 100% rename from tests/drivers/spi/spi_loopback/boards/yd_esp32.overlay rename to tests/drivers/spi/spi_loopback/boards/yd_esp32_procpu.overlay diff --git a/tests/drivers/spi/spi_loopback/overlay-stm32-spi-16bits-dma-no-nocache.conf b/tests/drivers/spi/spi_loopback/overlay-stm32-spi-16bits-dma-dt-nocache-mem.conf similarity index 100% rename from tests/drivers/spi/spi_loopback/overlay-stm32-spi-16bits-dma-no-nocache.conf rename to tests/drivers/spi/spi_loopback/overlay-stm32-spi-16bits-dma-dt-nocache-mem.conf diff --git a/tests/drivers/spi/spi_loopback/overlay-stm32-spi-dma-no-nocache.conf b/tests/drivers/spi/spi_loopback/overlay-stm32-spi-dma-dt-nocache-mem.conf similarity index 100% rename from tests/drivers/spi/spi_loopback/overlay-stm32-spi-dma-no-nocache.conf rename to tests/drivers/spi/spi_loopback/overlay-stm32-spi-dma-dt-nocache-mem.conf diff --git a/tests/drivers/spi/spi_loopback/src/spi.c b/tests/drivers/spi/spi_loopback/src/spi.c index a4a138aed17..f091f436396 100644 --- a/tests/drivers/spi/spi_loopback/src/spi.c +++ b/tests/drivers/spi/spi_loopback/src/spi.c @@ -58,6 +58,7 @@ static struct spi_dt_spec spi_slow = SPI_DT_SPEC_GET(SPI_SLOW_DEV, SPI_OP(FRAME_ #define STACK_SIZE (512 + CONFIG_TEST_EXTRA_STACK_SIZE) #define BUF_SIZE 18 #define BUF2_SIZE 36 +#define BUF3_SIZE 8192 #if CONFIG_NOCACHE_MEMORY #define __NOCACHE __attribute__((__section__(".nocache"))) @@ -73,6 +74,9 @@ static __aligned(32) char buffer_rx[BUF_SIZE] __used __NOCACHE; static const char tx2_data[BUF2_SIZE] = "Thequickbrownfoxjumpsoverthelazydog\0"; static __aligned(32) char buffer2_tx[BUF2_SIZE] __used __NOCACHE; static __aligned(32) char buffer2_rx[BUF2_SIZE] __used __NOCACHE; +static const char large_tx_data[BUF3_SIZE] = "Thequickbrownfoxjumpsoverthelazydog\0"; +static __aligned(32) char large_buffer_tx[BUF3_SIZE] __used __NOCACHE; +static __aligned(32) char large_buffer_rx[BUF3_SIZE] __used __NOCACHE; /* * We need 5x(buffer size) + 1 to print a comma-separated list of each @@ -517,6 +521,48 @@ static int spi_rx_bigger_than_tx(struct spi_dt_spec *spec) return 0; } +/* test transferring different buffers on the same dma channels */ +static int spi_complete_large_transfers(struct spi_dt_spec *spec) +{ + struct spi_buf tx_bufs; + const struct spi_buf_set tx = { + .buffers = &tx_bufs, + .count = 1 + }; + + tx_bufs.buf = large_buffer_tx; + tx_bufs.len = BUF3_SIZE; + + + struct spi_buf rx_bufs; + const struct spi_buf_set rx = { + .buffers = &rx_bufs, + .count = 1 + }; + + rx_bufs.buf = large_buffer_rx; + rx_bufs.len = BUF3_SIZE; + + int ret; + + LOG_INF("Start complete large transfers"); + + ret = spi_transceive_dt(spec, &tx, &rx); + if (ret) { + LOG_ERR("Code %d", ret); + zassert_false(ret, "SPI transceive failed"); + return ret; + } + + if (memcmp(large_buffer_tx, large_buffer_rx, BUF3_SIZE)) { + zassert_false(1, "Large Buffer contents are different"); + return -1; + } + + LOG_INF("Passed"); + + return 0; +} #if (CONFIG_SPI_ASYNC) static struct k_poll_signal async_sig = K_POLL_SIGNAL_INITIALIZER(async_sig); static struct k_poll_event async_evt = @@ -565,6 +611,10 @@ static int spi_async_call(struct spi_dt_spec *spec) .buf = buffer2_tx, .len = BUF2_SIZE, }, + { + .buf = large_buffer_tx, + .len = BUF3_SIZE, + }, }; const struct spi_buf rx_bufs[] = { { @@ -575,6 +625,10 @@ static int spi_async_call(struct spi_dt_spec *spec) .buf = buffer2_rx, .len = BUF2_SIZE, }, + { + .buf = large_buffer_rx, + .len = BUF3_SIZE, + }, }; const struct spi_buf_set tx = { .buffers = tx_bufs, @@ -589,6 +643,7 @@ static int spi_async_call(struct spi_dt_spec *spec) LOG_INF("Start async call"); memset(buffer_rx, 0, sizeof(buffer_rx)); memset(buffer2_rx, 0, sizeof(buffer2_rx)); + memset(large_buffer_rx, 0, sizeof(large_buffer_rx)); ret = spi_transceive_signal(spec->bus, &spec->config, &tx, &rx, &async_sig); if (ret == -ENOTSUP) { @@ -628,6 +683,11 @@ static int spi_async_call(struct spi_dt_spec *spec) return -1; } + if (memcmp(large_buffer_tx, large_buffer_rx, BUF3_SIZE)) { + zassert_false(1, "Buffer 3 contents are different"); + return -1; + } + LOG_INF("Passed"); return 0; @@ -684,7 +744,8 @@ ZTEST(spi_loopback, test_spi_loopback) spi_rx_half_start(&spi_slow) || spi_rx_half_end(&spi_slow) || spi_rx_every_4(&spi_slow) || - spi_rx_bigger_than_tx(&spi_slow) + spi_rx_bigger_than_tx(&spi_slow) || + spi_complete_large_transfers(&spi_slow) #if (CONFIG_SPI_ASYNC) || spi_async_call(&spi_slow) #endif @@ -702,7 +763,8 @@ ZTEST(spi_loopback, test_spi_loopback) spi_rx_half_start(&spi_fast) || spi_rx_half_end(&spi_fast) || spi_rx_every_4(&spi_fast) || - spi_rx_bigger_than_tx(&spi_fast) + spi_rx_bigger_than_tx(&spi_fast) || + spi_complete_large_transfers(&spi_fast) #if (CONFIG_SPI_ASYNC) || spi_async_call(&spi_fast) #endif @@ -729,6 +791,8 @@ static void *spi_loopback_setup(void) memcpy(buffer_tx, tx_data, sizeof(tx_data)); memset(buffer2_tx, 0, sizeof(buffer2_tx)); memcpy(buffer2_tx, tx2_data, sizeof(tx2_data)); + memset(large_buffer_tx, 0, sizeof(large_buffer_tx)); + memcpy(large_buffer_tx, large_tx_data, sizeof(large_tx_data)); return NULL; } diff --git a/tests/drivers/spi/spi_loopback/testcase.yaml b/tests/drivers/spi/spi_loopback/testcase.yaml index 083d383b9bd..6c419bab030 100644 --- a/tests/drivers/spi/spi_loopback/testcase.yaml +++ b/tests/drivers/spi/spi_loopback/testcase.yaml @@ -53,6 +53,7 @@ tests: extra_args: - OVERLAY_CONFIG="overlay-stm32-spi-16bits.conf" - DTC_OVERLAY_FILE="overlay-stm32-spi-16bits.overlay" + filter: CONFIG_SOC_FAMILY_STM32 platform_allow: - nucleo_h743zi - nucleo_h753zi @@ -64,6 +65,7 @@ tests: - nucleo_f207zg - nucleo_f429zi - nucleo_f746zg + - nucleo_f767zi - nucleo_wb55rg - nucleo_l152re - nucleo_wl55jc @@ -72,10 +74,12 @@ tests: - stm32h573i_dk integration_platforms: - nucleo_g474re - drivers.spi.stm32_spi_dma_no_nocache.loopback: + drivers.spi.stm32_spi_dma_dt_nocache_mem.loopback: + # this test case is for when nocache memory region is defined in DT + # using `zephyr,memory-attr = < DT_MEM_ARM_MPU_RAM_NOCACHE)>` extra_args: - - OVERLAY_CONFIG="overlay-stm32-spi-dma-no-nocache.conf" - filter: CONFIG_SOC_FAMILY_STM32 + - OVERLAY_CONFIG="overlay-stm32-spi-dma-dt-nocache-mem.conf" + filter: CONFIG_SOC_FAMILY_STM32 and CONFIG_CPU_HAS_DCACHE platform_allow: - nucleo_h743zi - nucleo_h753zi @@ -87,11 +91,11 @@ tests: platform_allow: - nucleo_h743zi - nucleo_h753zi - drivers.spi.stm32_spi_16bits_frames_dma_no_nocache.loopback: + drivers.spi.stm32_spi_16bits_frames_dma_dt_nocache_mem.loopback: extra_args: - - OVERLAY_CONFIG="overlay-stm32-spi-16bits-dma-no-nocache.conf" + - OVERLAY_CONFIG="overlay-stm32-spi-16bits-dma-dt-nocache-mem.conf" - DTC_OVERLAY_FILE="overlay-stm32-spi-16bits.overlay" - filter: CONFIG_SOC_FAMILY_STM32 + filter: CONFIG_SOC_FAMILY_STM32 and CONFIG_CPU_HAS_DCACHE platform_allow: - nucleo_h743zi - nucleo_h753zi @@ -99,6 +103,8 @@ tests: extra_args: OVERLAY_CONFIG="overlay-stm32-spi-interrupt.conf" filter: CONFIG_SOC_FAMILY_STM32 platform_allow: + - nucleo_f746zg + - nucleo_f767zi - nucleo_h743zi - nucleo_h753zi drivers.spi.gd32_spi_interrupt.loopback: diff --git a/tests/drivers/uart/uart_async_api/Kconfig b/tests/drivers/uart/uart_async_api/Kconfig new file mode 100644 index 00000000000..6883eb23509 --- /dev/null +++ b/tests/drivers/uart/uart_async_api/Kconfig @@ -0,0 +1,21 @@ +# Copyright (c) 2024 STMicroelectronics +# +# SPDX-License-Identifier: Apache-2.0 + +mainmenu "UART Async Test" + +source "Kconfig.zephyr" + +if DCACHE + +config DT_DEFINED_NOCACHE + bool "Enable this if a nocache region is defined in devicetree" + +if DT_DEFINED_NOCACHE + +config DT_DEFINED_NOCACHE_NAME + string "Name of the nocache region defined in devicetree (uppercase)" + +endif # DT_DEFINED_NOCACHE + +endif # DCACHE diff --git a/tests/drivers/uart/uart_async_api/boards/esp32s3_devkitm.conf b/tests/drivers/uart/uart_async_api/boards/esp32s3_devkitm_procpu.conf similarity index 100% rename from tests/drivers/uart/uart_async_api/boards/esp32s3_devkitm.conf rename to tests/drivers/uart/uart_async_api/boards/esp32s3_devkitm_procpu.conf diff --git a/tests/drivers/uart/uart_async_api/boards/esp32s3_devkitm.overlay b/tests/drivers/uart/uart_async_api/boards/esp32s3_devkitm_procpu.overlay similarity index 100% rename from tests/drivers/uart/uart_async_api/boards/esp32s3_devkitm.overlay rename to tests/drivers/uart/uart_async_api/boards/esp32s3_devkitm_procpu.overlay diff --git a/tests/drivers/uart/uart_async_api/boards/esp32s3_luatos_core_esp32s3_procpu.conf b/tests/drivers/uart/uart_async_api/boards/esp32s3_luatos_core_procpu.conf similarity index 100% rename from tests/drivers/uart/uart_async_api/boards/esp32s3_luatos_core_esp32s3_procpu.conf rename to tests/drivers/uart/uart_async_api/boards/esp32s3_luatos_core_procpu.conf diff --git a/tests/drivers/uart/uart_async_api/boards/esp32s3_luatos_core_esp32s3_procpu.overlay b/tests/drivers/uart/uart_async_api/boards/esp32s3_luatos_core_procpu.overlay similarity index 100% rename from tests/drivers/uart/uart_async_api/boards/esp32s3_luatos_core_esp32s3_procpu.overlay rename to tests/drivers/uart/uart_async_api/boards/esp32s3_luatos_core_procpu.overlay diff --git a/tests/drivers/uart/uart_async_api/boards/esp32s3_luatos_core_esp32s3_procpu_usb.conf b/tests/drivers/uart/uart_async_api/boards/esp32s3_luatos_core_procpu_usb.conf similarity index 100% rename from tests/drivers/uart/uart_async_api/boards/esp32s3_luatos_core_esp32s3_procpu_usb.conf rename to tests/drivers/uart/uart_async_api/boards/esp32s3_luatos_core_procpu_usb.conf diff --git a/tests/drivers/uart/uart_async_api/boards/esp32s3_luatos_core_esp32s3_procpu_usb.overlay b/tests/drivers/uart/uart_async_api/boards/esp32s3_luatos_core_procpu_usb.overlay similarity index 100% rename from tests/drivers/uart/uart_async_api/boards/esp32s3_luatos_core_esp32s3_procpu_usb.overlay rename to tests/drivers/uart/uart_async_api/boards/esp32s3_luatos_core_procpu_usb.overlay diff --git a/tests/drivers/uart/uart_async_api/boards/nucleo_f746zg_nocachemem.overlay b/tests/drivers/uart/uart_async_api/boards/nucleo_f746zg_nocachemem.overlay new file mode 100644 index 00000000000..2657a0bf45f --- /dev/null +++ b/tests/drivers/uart/uart_async_api/boards/nucleo_f746zg_nocachemem.overlay @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + /* The async_api.nocache_mem_dt test case expects a non-cachable RAM region */ + sram_nocache: memory@2004c000 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x2004c000 DT_SIZE_K(16)>; + zephyr,memory-region = "RAM_NOCACHE"; + zephyr,memory-attr = ; + }; +}; diff --git a/tests/drivers/uart/uart_async_api/boards/nucleo_h723zg.overlay b/tests/drivers/uart/uart_async_api/boards/nucleo_h723zg.overlay index 1eef7ad3ae9..9ecaf11a081 100644 --- a/tests/drivers/uart/uart_async_api/boards/nucleo_h723zg.overlay +++ b/tests/drivers/uart/uart_async_api/boards/nucleo_h723zg.overlay @@ -1,11 +1,18 @@ /* + * Copyright (c) 2024 STMicroelectronics + * * SPDX-License-Identifier: Apache-2.0 */ -dut: &usart2 { - dmas = <&dmamux1 2 44 STM32_DMA_PERIPH_TX>, - <&dmamux1 3 43 STM32_DMA_PERIPH_RX>; +/* Arduino Header pins: Tx:D9, Rx:D10 */ +dut: &uart9 { + pinctrl-0 = <&uart9_tx_pd15 &uart9_rx_pd14>; + pinctrl-names = "default"; + current-speed = <115200>; + dmas = <&dmamux1 2 117 STM32_DMA_PERIPH_TX>, + <&dmamux1 3 116 STM32_DMA_PERIPH_RX>; dma-names = "tx", "rx"; + status = "okay"; }; &dma1 { diff --git a/tests/drivers/uart/uart_async_api/boards/nucleo_h723zg_nocachemem.overlay b/tests/drivers/uart/uart_async_api/boards/nucleo_h723zg_nocachemem.overlay new file mode 100644 index 00000000000..fc9393dcf42 --- /dev/null +++ b/tests/drivers/uart/uart_async_api/boards/nucleo_h723zg_nocachemem.overlay @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&sram1 { + zephyr,memory-attr = ; + zephyr,memory-region = "RAM_NOCACHE"; +}; diff --git a/tests/drivers/uart/uart_async_api/src/test_uart_async.c b/tests/drivers/uart/uart_async_api/src/test_uart_async.c index 26c8de39897..15b4b6fba41 100644 --- a/tests/drivers/uart/uart_async_api/src/test_uart_async.c +++ b/tests/drivers/uart/uart_async_api/src/test_uart_async.c @@ -1,11 +1,22 @@ /* - * Copyright (c) 2019 Nordic Semiconductor ASA + * Copyright (c) 2019 Nordic Semiconductor ASA + * Copyright (c) 2024 STMicroelectronics * * SPDX-License-Identifier: Apache-2.0 */ #include "test_uart.h" +#if defined(CONFIG_DCACHE) && defined(CONFIG_DT_DEFINED_NOCACHE) +#define __NOCACHE __attribute__ ((__section__(CONFIG_DT_DEFINED_NOCACHE_NAME))) +#define NOCACHE_MEM 1 +#elif defined(CONFIG_DCACHE) && defined(CONFIG_NOCACHE_MEMORY) +#define __NOCACHE __nocache +#define NOCACHE_MEM 1 +#else +#define NOCACHE_MEM 0 +#endif /* CONFIG_NOCACHE_MEMORY */ + K_SEM_DEFINE(tx_done, 0, 1); K_SEM_DEFINE(tx_aborted, 0, 1); K_SEM_DEFINE(rx_rdy, 0, 1); @@ -79,14 +90,18 @@ static void uart_async_test_init(void) struct test_data { volatile uint32_t tx_aborted_count; - uint8_t rx_first_buffer[10]; + __aligned(32) uint8_t rx_first_buffer[10]; uint32_t recv_bytes_first_buffer; - uint8_t rx_second_buffer[5]; + __aligned(32) uint8_t rx_second_buffer[5]; uint32_t recv_bytes_second_buffer; bool supply_second_buffer; }; +#if NOCACHE_MEM +static struct test_data tdata __used __NOCACHE; +#else ZTEST_BMEM struct test_data tdata; +#endif /* NOCACHE_MEM */ static void test_single_read_callback(const struct device *dev, struct uart_event *evt, void *user_data) @@ -308,8 +323,13 @@ ZTEST_USER(uart_async_multi_rx, test_multiple_rx_enable) tdata_check_recv_buffers(tx_buf, sizeof(tx_buf)); } +#if NOCACHE_MEM +static __aligned(32) uint8_t chained_read_buf[2][8] __used __NOCACHE; +static __aligned(32) uint8_t chained_cpy_buf[10] __used __NOCACHE; +#else ZTEST_BMEM uint8_t chained_read_buf[2][8]; ZTEST_BMEM uint8_t chained_cpy_buf[10]; +#endif /* NOCACHE_MEM */ ZTEST_BMEM volatile uint8_t rx_data_idx; ZTEST_BMEM uint8_t rx_buf_idx; @@ -358,7 +378,11 @@ static void *chained_read_setup(void) ZTEST_USER(uart_async_chain_read, test_chained_read) { +#if NOCACHE_MEM + static __aligned(32) uint8_t tx_buf[10] __used __NOCACHE; +#else uint8_t tx_buf[10]; +#endif /* NOCACHE_MEM */ int iter = 6; uint32_t rx_timeout_ms = 50; int err; @@ -390,7 +414,11 @@ ZTEST_USER(uart_async_chain_read, test_chained_read) "RX_DISABLED timeout"); } +#if NOCACHE_MEM +static __aligned(32) uint8_t double_buffer[2][12] __used __NOCACHE; +#else ZTEST_BMEM uint8_t double_buffer[2][12]; +#endif /* NOCACHE_MEM */ ZTEST_DMEM uint8_t *next_buf = double_buffer[1]; static void test_double_buffer_callback(const struct device *dev, @@ -431,7 +459,11 @@ static void *double_buffer_setup(void) ZTEST_USER(uart_async_double_buf, test_double_buffer) { +#if NOCACHE_MEM + static __aligned(32) uint8_t tx_buf[4] __used __NOCACHE; +#else uint8_t tx_buf[4]; +#endif /* NOCACHE_MEM */ zassert_equal(uart_rx_enable(uart_dev, double_buffer[0], @@ -456,8 +488,13 @@ ZTEST_USER(uart_async_double_buf, test_double_buffer) "RX_DISABLED timeout"); } +#if NOCACHE_MEM +static __aligned(32) uint8_t test_read_abort_rx_buf[2][100] __used __NOCACHE; +static __aligned(32) uint8_t test_read_abort_read_buf[100] __used __NOCACHE; +#else ZTEST_BMEM uint8_t test_read_abort_rx_buf[2][100]; ZTEST_BMEM uint8_t test_read_abort_read_buf[100]; +#endif /* NOCACHE_MEM */ ZTEST_BMEM int test_read_abort_rx_cnt; static void test_read_abort_callback(const struct device *dev, @@ -526,8 +563,13 @@ static void *read_abort_setup(void) ZTEST_USER(uart_async_read_abort, test_read_abort) { +#if NOCACHE_MEM + static __aligned(32) uint8_t rx_buf[100] __used __NOCACHE; + static __aligned(32) uint8_t tx_buf[100] __used __NOCACHE; +#else uint8_t rx_buf[100]; uint8_t tx_buf[100]; +#endif /* NOCACHE_MEM */ memset(rx_buf, 0, sizeof(rx_buf)); memset(tx_buf, 1, sizeof(tx_buf)); @@ -568,7 +610,11 @@ ZTEST_USER(uart_async_read_abort, test_read_abort) ZTEST_BMEM volatile size_t sent; ZTEST_BMEM volatile size_t received; +#if NOCACHE_MEM +static __aligned(32) uint8_t test_rx_buf[2][100] __used __NOCACHE; +#else ZTEST_BMEM uint8_t test_rx_buf[2][100]; +#endif /* NOCACHE_MEM */ static void test_write_abort_callback(const struct device *dev, struct uart_event *evt, void *user_data) @@ -612,7 +658,11 @@ static void *write_abort_setup(void) ZTEST_USER(uart_async_write_abort, test_write_abort) { +#if NOCACHE_MEM + static __aligned(32) uint8_t tx_buf[100] __used __NOCACHE; +#else uint8_t tx_buf[100]; +#endif /* NOCACHE_MEM */ memset(test_rx_buf, 0, sizeof(test_rx_buf)); memset(tx_buf, 1, sizeof(tx_buf)); @@ -681,8 +731,13 @@ static void *forever_timeout_setup(void) ZTEST_USER(uart_async_timeout, test_forever_timeout) { +#if NOCACHE_MEM + static __aligned(32) uint8_t rx_buf[100] __used __NOCACHE; + static __aligned(32) uint8_t tx_buf[100] __used __NOCACHE; +#else uint8_t rx_buf[100]; uint8_t tx_buf[100]; +#endif /* NOCACHE_MEM */ memset(rx_buf, 0, sizeof(rx_buf)); memset(tx_buf, 1, sizeof(tx_buf)); @@ -715,7 +770,11 @@ ZTEST_USER(uart_async_timeout, test_forever_timeout) } +#if NOCACHE_MEM +const uint8_t chained_write_tx_bufs[2][10] = {"Message 1", "Message 2"}; +#else ZTEST_DMEM uint8_t chained_write_tx_bufs[2][10] = {"Message 1", "Message 2"}; +#endif /* NOCACHE_MEM */ ZTEST_DMEM bool chained_write_next_buf = true; ZTEST_BMEM volatile uint8_t tx_sent; @@ -761,7 +820,11 @@ static void *chained_write_setup(void) ZTEST_USER(uart_async_chain_write, test_chained_write) { +#if NOCACHE_MEM + static __aligned(32) uint8_t rx_buf[20] __used __NOCACHE; +#else uint8_t rx_buf[20]; +#endif /* NOCACHE_MEM */ memset(rx_buf, 0, sizeof(rx_buf)); @@ -787,9 +850,15 @@ ZTEST_USER(uart_async_chain_write, test_chained_write) "RX_DISABLED timeout"); } +#if NOCACHE_MEM +static __aligned(32) uint8_t long_rx_buf[1024] __used __NOCACHE; +static __aligned(32) uint8_t long_rx_buf2[1024] __used __NOCACHE; +static __aligned(32) uint8_t long_tx_buf[1000] __used __NOCACHE; +#else ZTEST_BMEM uint8_t long_rx_buf[1024]; ZTEST_BMEM uint8_t long_rx_buf2[1024]; ZTEST_BMEM uint8_t long_tx_buf[1000]; +#endif /* NOCACHE_MEM */ ZTEST_BMEM volatile uint8_t evt_num; ZTEST_BMEM size_t long_received[2]; diff --git a/tests/drivers/uart/uart_async_api/stm32_nocache_mem_dt.conf b/tests/drivers/uart/uart_async_api/stm32_nocache_mem_dt.conf new file mode 100644 index 00000000000..1d24d39f824 --- /dev/null +++ b/tests/drivers/uart/uart_async_api/stm32_nocache_mem_dt.conf @@ -0,0 +1,4 @@ +CONFIG_DCACHE=y +CONFIG_DT_DEFINED_NOCACHE=y +CONFIG_DT_DEFINED_NOCACHE_NAME="RAM_NOCACHE" +CONFIG_USERSPACE=n diff --git a/tests/drivers/uart/uart_async_api/testcase.yaml b/tests/drivers/uart/uart_async_api/testcase.yaml index a3665f7c570..e7a970d4a58 100644 --- a/tests/drivers/uart/uart_async_api/testcase.yaml +++ b/tests/drivers/uart/uart_async_api/testcase.yaml @@ -74,3 +74,39 @@ tests: - CONFIG_UART_SAM0_ASYNC=y - CONFIG_DMA=y build_only: true + drivers.uart.async_api.nocache_mem: + # nocache memory region is defined by the linker + filter: CONFIG_SERIAL_SUPPORT_ASYNC and CONFIG_CPU_HAS_DCACHE + harness: ztest + harness_config: + fixture: gpio_loopback + depends_on: gpio + platform_allow: + - nucleo_f746zg + - nucleo_h723zg + extra_configs: + - CONFIG_DCACHE=y + - CONFIG_NOCACHE_MEMORY=y + - CONFIG_USERSPACE=n + drivers.uart.async_api.nocache_mem_dt.nucleo_f746zg: + # nocache memory region is defined in DT + harness: ztest + harness_config: + fixture: gpio_loopback + depends_on: gpio + platform_allow: + - nucleo_f746zg + extra_args: + - DTC_OVERLAY_FILE="boards/nucleo_f746zg.overlay;boards/nucleo_f746zg_nocachemem.overlay" + - EXTRA_CONF_FILE=stm32_nocache_mem_dt.conf + drivers.uart.async_api.nocache_mem_dt.nucleo_h723zg: + # nocache memory region is defined in DT + harness: ztest + harness_config: + fixture: gpio_loopback + depends_on: gpio + platform_allow: + - nucleo_h723zg + extra_args: + - DTC_OVERLAY_FILE="boards/nucleo_h723zg.overlay;boards/nucleo_h723zg_nocachemem.overlay" + - EXTRA_CONF_FILE=stm32_nocache_mem_dt.conf diff --git a/tests/drivers/uart/uart_mix_fifo_poll/boards/nrf54h20dk_nrf54h20_common.dtsi b/tests/drivers/uart/uart_mix_fifo_poll/boards/nrf54h20dk_nrf54h20_common.dtsi new file mode 100644 index 00000000000..c102d617f90 --- /dev/null +++ b/tests/drivers/uart/uart_mix_fifo_poll/boards/nrf54h20dk_nrf54h20_common.dtsi @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +&pinctrl { + uart137_default_alt: uart137_default_alt { + group1 { + psels = , + , + , + ; + }; + }; + + uart137_sleep_alt: uart137_sleep_alt { + group1 { + psels = , + , + , + ; + low-power-enable; + }; + }; +}; + +dut: &uart137 { + status = "okay"; + pinctrl-0 = <&uart137_default_alt>; + pinctrl-1 = <&uart137_sleep_alt>; + pinctrl-names = "default", "sleep"; + current-speed = <115200>; + hw-flow-control; +}; + +/* Use timer137 as only this one can generate interrupts on cpusys. */ +counter_dev: &timer137 { + status = "okay"; +}; diff --git a/tests/drivers/uart/uart_mix_fifo_poll/boards/nrf54h20dk_nrf54h20_cpuapp.overlay b/tests/drivers/uart/uart_mix_fifo_poll/boards/nrf54h20dk_nrf54h20_cpuapp.overlay new file mode 100644 index 00000000000..c6ff4eb77af --- /dev/null +++ b/tests/drivers/uart/uart_mix_fifo_poll/boards/nrf54h20dk_nrf54h20_cpuapp.overlay @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include "nrf54h20dk_nrf54h20_common.dtsi" + +&dut { + memory-regions = <&cpuapp_dma_region>; +}; + +&grtc { + interrupts = <109 2>; +}; diff --git a/tests/drivers/uart/uart_mix_fifo_poll/boards/nrf54h20dk_nrf54h20_cpurad.overlay b/tests/drivers/uart/uart_mix_fifo_poll/boards/nrf54h20dk_nrf54h20_cpurad.overlay new file mode 100644 index 00000000000..2bde29c9fc5 --- /dev/null +++ b/tests/drivers/uart/uart_mix_fifo_poll/boards/nrf54h20dk_nrf54h20_cpurad.overlay @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include "nrf54h20dk_nrf54h20_common.dtsi" + +&cpurad_dma_region { + /* Default space is not enough. */ + reg = <0x1e80 0x100>; +}; + +&dut { + memory-regions = <&cpurad_dma_region>; +}; + +&grtc { + interrupts = <109 2>; +}; diff --git a/tests/drivers/uart/uart_mix_fifo_poll/testcase.yaml b/tests/drivers/uart/uart_mix_fifo_poll/testcase.yaml index 7736e085f34..8be2429492e 100644 --- a/tests/drivers/uart/uart_mix_fifo_poll/testcase.yaml +++ b/tests/drivers/uart/uart_mix_fifo_poll/testcase.yaml @@ -9,6 +9,8 @@ common: - nrf9160dk/nrf9160 - nrf5340dk/nrf5340/cpuapp - nrf54l15pdk/nrf54l15/cpuapp + - nrf54h20dk/nrf54h20/cpuapp + - nrf54h20dk/nrf54h20/cpurad - nrf52_bsim integration_platforms: - nrf52840dk/nrf52840 @@ -79,6 +81,10 @@ tests: - CONFIG_UART_ASYNC_API=n - CONFIG_UART_0_ENHANCED_POLL_OUT=n - CONFIG_UART_NRFX_UARTE_LEGACY_SHIM=y + platform_exclude: + - nrf54l15pdk/nrf54l15/cpuapp + - nrf54h20dk/nrf54h20/cpuapp + - nrf54h20dk/nrf54h20/cpurad drivers.uart.legacy.uart_mix_poll_fifo: extra_configs: @@ -86,6 +92,10 @@ tests: - CONFIG_UART_0_INTERRUPT_DRIVEN=y - CONFIG_UART_0_ENHANCED_POLL_OUT=n - CONFIG_UART_NRFX_UARTE_LEGACY_SHIM=y + platform_exclude: + - nrf54l15pdk/nrf54l15/cpuapp + - nrf54h20dk/nrf54h20/cpuapp + - nrf54h20dk/nrf54h20/cpurad drivers.uart.legacy.uart_mix_poll_async_api: extra_configs: @@ -97,3 +107,7 @@ tests: - CONFIG_UART_0_NRF_HW_ASYNC_TIMER=2 - CONFIG_NRFX_TIMER2=y - CONFIG_UART_NRFX_UARTE_LEGACY_SHIM=y + platform_exclude: + - nrf54l15pdk/nrf54l15/cpuapp + - nrf54h20dk/nrf54h20/cpuapp + - nrf54h20dk/nrf54h20/cpurad diff --git a/tests/drivers/uart/uart_pm/src/main.c b/tests/drivers/uart/uart_pm/src/main.c index 07e75ec8dd6..e28d55efb33 100644 --- a/tests/drivers/uart/uart_pm/src/main.c +++ b/tests/drivers/uart/uart_pm/src/main.c @@ -66,7 +66,7 @@ static void async_callback(const struct device *dev, struct uart_event *evt, voi static bool async_verify(const struct device *dev, bool active) { char txbuf[] = "test"; - uint8_t rxbuf[32]; + uint8_t rxbuf[32] = { 0 }; volatile bool tx_done = false; int err; diff --git a/tests/drivers/watchdog/wdt_basic_api/boards/nrf54h20dk_nrf54h20_cpuapp.overlay b/tests/drivers/watchdog/wdt_basic_api/boards/nrf54h20dk_nrf54h20_cpuapp.overlay new file mode 100644 index 00000000000..94e0d719af4 --- /dev/null +++ b/tests/drivers/watchdog/wdt_basic_api/boards/nrf54h20dk_nrf54h20_cpuapp.overlay @@ -0,0 +1,8 @@ +/* + * Copyright 2024 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +&wdt010 { + status = "okay"; +}; diff --git a/tests/drivers/watchdog/wdt_basic_api/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay b/tests/drivers/watchdog/wdt_basic_api/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay index aa2789dd45e..8d3dce3b380 100644 --- a/tests/drivers/watchdog/wdt_basic_api/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay +++ b/tests/drivers/watchdog/wdt_basic_api/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay @@ -4,6 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -&wdt30 { +&wdt31 { status = "okay"; }; diff --git a/tests/drivers/watchdog/wdt_basic_api/boards/nrf54l15pdk_nrf54l15_cpuflpr.overlay b/tests/drivers/watchdog/wdt_basic_api/boards/nrf54l15pdk_nrf54l15_cpuflpr.overlay new file mode 100644 index 00000000000..5c765a8a896 --- /dev/null +++ b/tests/drivers/watchdog/wdt_basic_api/boards/nrf54l15pdk_nrf54l15_cpuflpr.overlay @@ -0,0 +1,8 @@ +/* + * Copyright 2024 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +&wdt31 { + status = "okay"; +}; diff --git a/tests/drivers/watchdog/wdt_basic_api/boards/nrf54l15pdk_nrf54l15_cpuflpr_xip.overlay b/tests/drivers/watchdog/wdt_basic_api/boards/nrf54l15pdk_nrf54l15_cpuflpr_xip.overlay new file mode 100644 index 00000000000..5c765a8a896 --- /dev/null +++ b/tests/drivers/watchdog/wdt_basic_api/boards/nrf54l15pdk_nrf54l15_cpuflpr_xip.overlay @@ -0,0 +1,8 @@ +/* + * Copyright 2024 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +&wdt31 { + status = "okay"; +}; diff --git a/tests/drivers/watchdog/wdt_error_cases/src/main.c b/tests/drivers/watchdog/wdt_error_cases/src/main.c index 65569ad30a4..b16daccb2e3 100644 --- a/tests/drivers/watchdog/wdt_error_cases/src/main.c +++ b/tests/drivers/watchdog/wdt_error_cases/src/main.c @@ -776,6 +776,48 @@ ZTEST(wdt_coverage, test_08d_wdt_disable_check_timeouts_uninstalled) zassert_equal(m_test_08d_B_value, 0, "Timeout B has fired while it shouldn't"); } +/** + * @brief Test error code when wdt_setup() is called after wdt_disable() + * + * Confirm that wdt_setup() returns error value or ASSERTION FAIL + * when it's called before any timeout was configured with wdt_install_timeouts(). + * All timeouts were uninstalled by calling wdt_disable(). + * + */ +ZTEST(wdt_coverage, test_08e_wdt_setup_immediately_after_wdt_disable) +{ + int ret; + + if (!(WDT_TEST_FLAGS & WDT_DISABLE_SUPPORTED)) { + /* Skip this test because wdt_disable() is NOT supported. */ + ztest_test_skip(); + } + + m_cfg_wdt0.callback = NULL; + m_cfg_wdt0.flags = DEFAULT_FLAGS; + m_cfg_wdt0.window.max = DEFAULT_WINDOW_MAX; + m_cfg_wdt0.window.min = DEFAULT_WINDOW_MIN; + + ret = wdt_install_timeout(wdt, &m_cfg_wdt0); + zassert_true(ret >= 0, "Watchdog install error, got unexpected value of %d", ret); + TC_PRINT("Configured WDT channel %d\n", ret); + + ret = wdt_setup(wdt, DEFAULT_OPTIONS); + zassert_true(ret == 0, "Watchdog setup error, got unexpected value of %d", ret); + + ret = wdt_disable(wdt); + zassert_true(ret == 0, "Watchdog disable error, got unexpected value of %d", ret); + + /* Call wdt_setup when no timeouts are configured. */ + /* Timeouts were removed by calling wdt_disable(). */ + ztest_set_assert_valid(true); + ret = wdt_setup(wdt, DEFAULT_OPTIONS); + zassert_true(ret < 0, + "Calling wdt_setup before installing timeouts should fail, got unexpected " + "value of %d", + ret); +} + /** * @brief wdt_feed() negative test * diff --git a/tests/kernel/cache/testcase.yaml b/tests/kernel/cache/testcase.yaml index 2c089e26eaf..22cd07fbdac 100644 --- a/tests/kernel/cache/testcase.yaml +++ b/tests/kernel/cache/testcase.yaml @@ -5,7 +5,6 @@ tests: - cache filter: CONFIG_CACHE_MANAGEMENT platform_exclude: - - adp_xc7k/ae350 - bcm958402m2/bcm58402/m7 - bcm958401m2 integration_platforms: @@ -21,7 +20,6 @@ tests: - libc filter: CONFIG_CACHE_MANAGEMENT and CONFIG_MINIMAL_LIBC_SUPPORTED platform_exclude: - - adp_xc7k/ae350 - bcm958402m2/bcm58402/m7 - bcm958401m2 integration_platforms: diff --git a/tests/kernel/common/prj.conf b/tests/kernel/common/prj.conf index eb2a4d4ccd8..53115b18cfa 100644 --- a/tests/kernel/common/prj.conf +++ b/tests/kernel/common/prj.conf @@ -6,3 +6,4 @@ CONFIG_BOOT_DELAY=500 CONFIG_IRQ_OFFLOAD=y CONFIG_TEST_USERSPACE=y CONFIG_BOUNDS_CHECK_BYPASS_MITIGATION=y +CONFIG_MAX_THREAD_BYTES=3 diff --git a/tests/kernel/common/src/bitarray.c b/tests/kernel/common/src/bitarray.c index 05dd12c5343..a7a7be02a01 100644 --- a/tests/kernel/common/src/bitarray.c +++ b/tests/kernel/common/src/bitarray.c @@ -3,6 +3,7 @@ * * SPDX-License-Identifier: Apache-2.0 */ +#include #include #include @@ -519,6 +520,353 @@ ZTEST(bitarray, test_bitarray_alloc_free) alloc_and_free_interval(); } +ZTEST(bitarray, test_bitarray_popcount_region) +{ + int ret; + size_t count; + + /* Bitarrays have embedded spinlocks and can't on the stack. */ + if (IS_ENABLED(CONFIG_KERNEL_COHERENCE)) { + ztest_test_skip(); + } + + SYS_BITARRAY_DEFINE(ba, 128); + + printk("Testing bit array region popcount spanning single bundle\n"); + + /* Pre-populate the bits */ + ba.bundles[0] = 0x00000005; + ba.bundles[1] = 0x00000000; + ba.bundles[2] = 0x00000000; + ba.bundles[3] = 0x00000000; + + ret = sys_bitarray_popcount_region(&ba, 1, 0, &count); + zassert_equal(ret, 0, "sys_bitarray_popcount_region() returned unexpected value: %d", ret); + zassert_equal(count, 1, "sys_bitarray_popcount_region() returned unexpected count: %d", + count); + + ret = sys_bitarray_popcount_region(&ba, 1, 1, &count); + zassert_equal(ret, 0, "sys_bitarray_popcount_region() returned unexpected value: %d", ret); + zassert_equal(count, 0, "sys_bitarray_popcount_region() returned unexpected count: %d", + count); + + ret = sys_bitarray_popcount_region(&ba, 2, 0, &count); + zassert_equal(ret, 0, "sys_bitarray_popcount_region() returned unexpected value: %d", ret); + zassert_equal(count, 1, "sys_bitarray_popcount_region() returned unexpected count: %d", + count); + + ret = sys_bitarray_popcount_region(&ba, 3, 0, &count); + zassert_equal(ret, 0, "sys_bitarray_popcount_region() returned unexpected value: %d", ret); + zassert_equal(count, 2, "sys_bitarray_popcount_region() returned unexpected count: %d", + count); + + ret = sys_bitarray_popcount_region(&ba, 3, 1, &count); + zassert_equal(ret, 0, "sys_bitarray_popcount_region() returned unexpected value: %d", ret); + zassert_equal(count, 1, "sys_bitarray_popcount_region() returned unexpected count: %d", + count); + + printk("Testing bit array region popcount spanning multiple bundles\n"); + + /* Pre-populate the bits. + * First and last bit of bitarray are set + */ + ba.bundles[0] = 0x00000001; + ba.bundles[1] = 0x00000000; + ba.bundles[2] = 0x00000000; + ba.bundles[3] = 0x80000000; + + ret = sys_bitarray_popcount_region(&ba, 126, 1, &count); + zassert_equal(ret, 0, "sys_bitarray_popcount_region() returned unexpected value: %d", ret); + zassert_equal(count, 0, "sys_bitarray_popcount_region() returned unexpected count: %d", + count); + + ret = sys_bitarray_popcount_region(&ba, 126, 0, &count); + zassert_equal(ret, 0, "sys_bitarray_popcount_region() returned unexpected value: %d", ret); + zassert_equal(count, 1, "sys_bitarray_popcount_region() returned unexpected count: %d", + count); + + ret = sys_bitarray_popcount_region(&ba, 127, 1, &count); + zassert_equal(ret, 0, "sys_bitarray_popcount_region() returned unexpected value: %d", ret); + zassert_equal(count, 1, "sys_bitarray_popcount_region() returned unexpected count: %d", + count); + ret = sys_bitarray_popcount_region(&ba, 1, 127, &count); + zassert_equal(ret, 0, "sys_bitarray_popcount_region() returned unexpected value: %d", ret); + zassert_equal(count, 1, "sys_bitarray_popcount_region() returned unexpected count: %d", + count); + + ret = sys_bitarray_popcount_region(&ba, 128, 0, &count); + zassert_equal(ret, 0, "sys_bitarray_popcount_region() returned unexpected value: %d", ret); + zassert_equal(count, 2, "sys_bitarray_popcount_region() returned unexpected count: %d", + count); + + printk("Testing edge/error cases\n"); + ret = sys_bitarray_popcount_region(&ba, 0, 0, &count); + zassert_equal(ret, -EINVAL, "sys_bitarray_popcount_region() returned unexpected value: %d", + ret); + ret = sys_bitarray_popcount_region(&ba, 0, 128, &count); + zassert_equal(ret, -EINVAL, "sys_bitarray_popcount_region() returned unexpected value: %d", + ret); + ret = sys_bitarray_popcount_region(&ba, 128, 0, &count); + zassert_equal(ret, 0, "sys_bitarray_popcount_region() returned unexpected value: %d", ret); + + ret = sys_bitarray_popcount_region(&ba, 128, 1, &count); + zassert_equal(ret, -EINVAL, "sys_bitarray_popcount_region() returned unexpected value: %d", + ret); + ret = sys_bitarray_popcount_region(&ba, 129, 0, &count); + zassert_equal(ret, -EINVAL, "sys_bitarray_popcount_region() returned unexpected value: %d", + ret); +} + +ZTEST(bitarray, test_bitarray_xor) +{ + int ret; + + /* Bitarrays have embedded spinlocks and can't on the stack. */ + if (IS_ENABLED(CONFIG_KERNEL_COHERENCE)) { + ztest_test_skip(); + } + + SYS_BITARRAY_DEFINE(ba, 128); + SYS_BITARRAY_DEFINE(bb, 128); + SYS_BITARRAY_DEFINE(bc, 129); + + printk("Testing bit array region xor spanning single bundle\n"); + + /* Pre-populate the bits */ + ba.bundles[0] = 0x80001001; + ba.bundles[1] = 0x10000008; + ba.bundles[2] = 0xFFFFFFFF; + ba.bundles[3] = 0x00000000; + + bb.bundles[0] = 0x80010001; + bb.bundles[1] = 0x10000008; + bb.bundles[2] = 0xFFFFFFFF; + bb.bundles[3] = 0x00000000; + + ret = sys_bitarray_xor(&ba, &bb, 32, 0); + zassert_equal(ret, 0, "sys_bitarray_xor() returned unexpected value: %d", ret); + zassert_equal(ba.bundles[0], 0x00011000, "sys_bitarray_xor() result unexpected: %x", + ba.bundles[0]); + zassert_equal(bb.bundles[0], 0x80010001, "sys_bitarray_xor() result unexpected: %x", + bb.bundles[0]); + + zassert_equal(ba.bundles[1], 0x10000008, "sys_bitarray_xor() result unexpected: %x", + ba.bundles[1]); + zassert_equal(bb.bundles[1], 0x10000008, "sys_bitarray_xor() result unexpected: %x", + bb.bundles[1]); + + zassert_equal(ba.bundles[2], 0xFFFFFFFF, "sys_bitarray_xor() result unexpected: %x", + ba.bundles[2]); + zassert_equal(bb.bundles[2], 0xFFFFFFFF, "sys_bitarray_xor() result unexpected: %x", + bb.bundles[2]); + + zassert_equal(ba.bundles[3], 0x00000000, "sys_bitarray_xor() result unexpected: %x", + ba.bundles[3]); + zassert_equal(bb.bundles[3], 0x00000000, "sys_bitarray_xor() result unexpected: %x", + bb.bundles[3]); + + /* Pre-populate the bits */ + ba.bundles[0] = 0x80001001; + ba.bundles[1] = 0x10000008; + ba.bundles[2] = 0xFFFFFFFF; + ba.bundles[3] = 0x00000000; + + bb.bundles[0] = 0x80010001; + bb.bundles[1] = 0x10000008; + bb.bundles[2] = 0xFFFFFFFF; + bb.bundles[3] = 0x00000000; + + ret = sys_bitarray_xor(&ba, &bb, 16, 0); + zassert_equal(ret, 0, "sys_bitarray_xor() returned unexpected value: %d", ret); + zassert_equal(ba.bundles[0], 0x80001000, "sys_bitarray_xor() result unexpected: %x", + ba.bundles[0]); + zassert_equal(bb.bundles[0], 0x80010001, "sys_bitarray_xor() result unexpected: %x", + bb.bundles[0]); + + /* Pre-populate the bits */ + ba.bundles[0] = 0x80001001; + ba.bundles[1] = 0x10000008; + ba.bundles[2] = 0xFFFFFFFF; + ba.bundles[3] = 0x00000000; + + bb.bundles[0] = 0x80010001; + bb.bundles[1] = 0x10000008; + bb.bundles[2] = 0xFFFFFFFF; + bb.bundles[3] = 0x00000000; + + ret = sys_bitarray_xor(&ba, &bb, 16, 16); + zassert_equal(ret, 0, "sys_bitarray_xor() returned unexpected value: %d", ret); + zassert_equal(ba.bundles[0], 0x00011001, "sys_bitarray_xor() result unexpected: %x", + ba.bundles[0]); + zassert_equal(bb.bundles[0], 0x80010001, "sys_bitarray_xor() result unexpected: %x", + bb.bundles[0]); + + printk("Testing bit array region xor spanning multiple bundles\n"); + + /* Pre-populate the bits */ + ba.bundles[0] = 0x00000000; + ba.bundles[1] = 0xFFFFFFFF; + ba.bundles[2] = 0xFFFFFFFF; + ba.bundles[3] = 0xFFFFFFFF; + + bb.bundles[0] = 0x00000000; + bb.bundles[1] = 0xFFFFFFFF; + bb.bundles[2] = 0xFFFFFFFF; + bb.bundles[3] = 0xFFFFFFFF; + + ret = sys_bitarray_xor(&ba, &bb, 32*3 - 2, 32 + 1); + zassert_equal(ret, 0, "sys_bitarray_xor() returned unexpected value: %d", ret); + zassert_equal(ba.bundles[0], 0x00000000, "sys_bitarray_xor() result unexpected: %x", + ba.bundles[0]); + zassert_equal(ba.bundles[1], 0x00000001, "sys_bitarray_xor() result unexpected: %x", + ba.bundles[1]); + zassert_equal(ba.bundles[2], 0x00000000, "sys_bitarray_xor() result unexpected: %x", + ba.bundles[2]); + zassert_equal(ba.bundles[3], 0x80000000, "sys_bitarray_xor() result unexpected: %x", + ba.bundles[3]); + + printk("Testing error cases\n"); + /* Pre-populate the bits */ + ba.bundles[0] = 0x00000000; + ba.bundles[1] = 0x00000000; + ba.bundles[2] = 0x00000000; + ba.bundles[3] = 0x00000000; + + bb.bundles[0] = 0x00000000; + bb.bundles[1] = 0x00000000; + bb.bundles[2] = 0x00000000; + bb.bundles[3] = 0x00000000; + + bc.bundles[0] = 0x00000000; + bc.bundles[1] = 0x00000000; + bc.bundles[2] = 0x00000000; + bc.bundles[3] = 0x00000000; + bc.bundles[4] = 0x00000000; + + ret = sys_bitarray_xor(&ba, &bb, 32, 0); + zassert_equal(ret, 0, "sys_bitarray_xor() returned unexpected value: %d", ret); + ret = sys_bitarray_xor(&ba, &bc, 32, 0); + zassert_equal(ret, -EINVAL, "sys_bitarray_xor() returned unexpected value: %d", ret); + ret = sys_bitarray_xor(&bc, &ba, 32, 0); + zassert_equal(ret, -EINVAL, "sys_bitarray_xor() returned unexpected value: %d", ret); + + ret = sys_bitarray_xor(&ba, &bb, 128, 0); + zassert_equal(ret, 0, "sys_bitarray_xor() returned unexpected value: %d", ret); + ret = sys_bitarray_xor(&ba, &bb, 128, 1); + zassert_equal(ret, -EINVAL, "sys_bitarray_xor() returned unexpected value: %d", ret); + ret = sys_bitarray_xor(&ba, &bb, 129, 0); + zassert_equal(ret, -EINVAL, "sys_bitarray_xor() returned unexpected value: %d", ret); + ret = sys_bitarray_xor(&ba, &bb, 0, 0); + zassert_equal(ret, -EINVAL, "sys_bitarray_xor() returned unexpected value: %d", ret); +} + +ZTEST(bitarray, test_bitarray_find_nth_set) +{ + int ret; + size_t found_at; + + /* Bitarrays have embedded spinlocks and can't on the stack. */ + if (IS_ENABLED(CONFIG_KERNEL_COHERENCE)) { + ztest_test_skip(); + } + + SYS_BITARRAY_DEFINE(ba, 128); + + printk("Testing bit array nth bit set finding spanning single bundle\n"); + + /* Pre-populate the bits */ + ba.bundles[0] = 0x80000001; + ba.bundles[1] = 0x80000001; + ba.bundles[2] = 0x80000001; + ba.bundles[3] = 0x80000001; + + ret = sys_bitarray_find_nth_set(&ba, 1, 1, 0, &found_at); + zassert_equal(ret, 0, "sys_bitarray_find_nth_set() returned unexpected value: %d", ret); + zassert_equal(found_at, 0, "sys_bitarray_find_nth_set() returned unexpected found_at: %d", + found_at); + + ret = sys_bitarray_find_nth_set(&ba, 1, 32, 0, &found_at); + zassert_equal(ret, 0, "sys_bitarray_find_nth_set() returned unexpected value: %d", ret); + zassert_equal(found_at, 0, "sys_bitarray_find_nth_set() returned unexpected found_at: %d", + found_at); + + ret = sys_bitarray_find_nth_set(&ba, 2, 32, 0, &found_at); + zassert_equal(ret, 0, "sys_bitarray_find_nth_set() returned unexpected value: %d", ret); + zassert_equal(found_at, 31, "sys_bitarray_find_nth_set() returned unexpected found_at: %d", + found_at); + + ret = sys_bitarray_find_nth_set(&ba, 1, 31, 1, &found_at); + zassert_equal(ret, 0, "sys_bitarray_find_nth_set() returned unexpected value: %d", ret); + zassert_equal(found_at, 31, "sys_bitarray_find_nth_set() returned unexpected found_at: %d", + found_at); + + ret = sys_bitarray_find_nth_set(&ba, 2, 31, 1, &found_at); + zassert_equal(ret, 1, "sys_bitarray_find_nth_set() returned unexpected value: %d", ret); + + printk("Testing bit array nth bit set finding spanning multiple bundles\n"); + + ret = sys_bitarray_find_nth_set(&ba, 1, 128, 0, &found_at); + zassert_equal(ret, 0, "sys_bitarray_find_nth_set() returned unexpected value: %d", ret); + zassert_equal(found_at, 0, "sys_bitarray_find_nth_set() returned unexpected found_at: %d", + found_at); + + ret = sys_bitarray_find_nth_set(&ba, 8, 128, 0, &found_at); + zassert_equal(ret, 0, "sys_bitarray_find_nth_set() returned unexpected value: %d", ret); + zassert_equal(found_at, 127, "sys_bitarray_find_nth_set() returned unexpected found_at: %d", + found_at); + + ret = sys_bitarray_find_nth_set(&ba, 8, 128, 1, &found_at); + zassert_equal(ret, -EINVAL, "sys_bitarray_find_nth_set() returned unexpected value: %d", + ret); + + ret = sys_bitarray_find_nth_set(&ba, 7, 127, 1, &found_at); + zassert_equal(ret, 0, "sys_bitarray_find_nth_set() returned unexpected value: %d", ret); + zassert_equal(found_at, 127, "sys_bitarray_find_nth_set() returned unexpected found_at: %d", + found_at); + + ret = sys_bitarray_find_nth_set(&ba, 7, 127, 0, &found_at); + zassert_equal(ret, 0, "sys_bitarray_find_nth_set() returned unexpected value: %d", ret); + zassert_equal(found_at, 96, "sys_bitarray_find_nth_set() returned unexpected found_at: %d", + found_at); + + ret = sys_bitarray_find_nth_set(&ba, 6, 127, 1, &found_at); + zassert_equal(ret, 0, "sys_bitarray_find_nth_set() returned unexpected value: %d", ret); + zassert_equal(found_at, 96, "sys_bitarray_find_nth_set() returned unexpected found_at: %d", + found_at); + + ret = sys_bitarray_find_nth_set(&ba, 6, 127, 1, &found_at); + zassert_equal(ret, 0, "sys_bitarray_find_nth_set() returned unexpected value: %d", ret); + zassert_equal(found_at, 96, "sys_bitarray_find_nth_set() returned unexpected found_at: %d", + found_at); + + ret = sys_bitarray_find_nth_set(&ba, 1, 32, 48, &found_at); + zassert_equal(ret, 0, "sys_bitarray_find_nth_set() returned unexpected value: %d", ret); + zassert_equal(found_at, 63, "sys_bitarray_find_nth_set() returned unexpected found_at: %d", + found_at); + + ret = sys_bitarray_find_nth_set(&ba, 2, 32, 48, &found_at); + zassert_equal(ret, 0, "sys_bitarray_find_nth_set() returned unexpected value: %d", ret); + zassert_equal(found_at, 64, "sys_bitarray_find_nth_set() returned unexpected found_at: %d", + found_at); + + printk("Testing error cases\n"); + + ret = sys_bitarray_find_nth_set(&ba, 1, 128, 0, &found_at); + zassert_equal(ret, 0, "sys_bitarray_find_nth_set() returned unexpected value: %d", ret); + + ret = sys_bitarray_find_nth_set(&ba, 1, 128, 1, &found_at); + zassert_equal(ret, -EINVAL, "sys_bitarray_find_nth_set() returned unexpected value: %d", + ret); + + ret = sys_bitarray_find_nth_set(&ba, 1, 129, 0, &found_at); + zassert_equal(ret, -EINVAL, "sys_bitarray_find_nth_set() returned unexpected value: %d", + ret); + + ret = sys_bitarray_find_nth_set(&ba, 0, 128, 0, &found_at); + zassert_equal(ret, -EINVAL, "sys_bitarray_find_nth_set() returned unexpected value: %d", + ret); +} + ZTEST(bitarray, test_bitarray_region_set_clear) { int ret; diff --git a/tests/kernel/context/src/main.c b/tests/kernel/context/src/main.c index ff0e0196c90..516ddb1ef5b 100644 --- a/tests/kernel/context/src/main.c +++ b/tests/kernel/context/src/main.c @@ -245,6 +245,9 @@ static void _test_kernel_cpu_idle(int atomic) k_cpu_idle(); } } while ((idle_loops++ < CONFIG_MAX_IDLE_WAKES) && (idle_timer_done == false)); + zassert_true(idle_timer_done, + "The CPU was waken spuriously too many times (%d > %d)", + idle_loops, CONFIG_MAX_IDLE_WAKES); dt = k_uptime_ticks() - t0; zassert_true(abs((int32_t) (dt - dur)) <= slop, "Inaccurate wakeup, idled for %d ticks, expected %d", diff --git a/tests/kernel/device/app.overlay b/tests/kernel/device/app.overlay index d7426f2b613..108f14bdb3e 100644 --- a/tests/kernel/device/app.overlay +++ b/tests/kernel/device/app.overlay @@ -52,6 +52,20 @@ status = "okay"; }; + fakedeferdriver@E7000000 { + compatible = "fakedeferdriver"; + reg = <0xE7000000 0x2000>; + status = "okay"; + zephyr,deferred-init; + }; + + fakedeferdriver@E8000000 { + compatible = "fakedeferdriver"; + reg = <0xE8000000 0x2000>; + status = "okay"; + zephyr,deferred-init; + }; + fakedomain_0: fakedomain_0 { compatible = "fakedomain"; status = "okay"; diff --git a/tests/kernel/device/boards/hifive_unmatched.overlay b/tests/kernel/device/boards/hifive_unmatched.overlay index 40fa5e74adb..05f9992d889 100644 --- a/tests/kernel/device/boards/hifive_unmatched.overlay +++ b/tests/kernel/device/boards/hifive_unmatched.overlay @@ -49,6 +49,20 @@ status = "okay"; }; + fakedeferdriver@E7000000 { + compatible = "fakedeferdriver"; + reg = <0x0 0xE7000000 0x0 0x2000>; + status = "okay"; + zephyr,deferred-init; + }; + + fakedeferdriver@E8000000 { + compatible = "fakedeferdriver"; + reg = <0x0 0xE8000000 0x0 0x2000>; + status = "okay"; + zephyr,deferred-init; + }; + fakedomain_0: fakedomain_0 { compatible = "fakedomain"; status = "okay"; diff --git a/tests/kernel/device/dts/bindings/fakedeferdriver.yml b/tests/kernel/device/dts/bindings/fakedeferdriver.yml new file mode 100644 index 00000000000..672ed99d1d3 --- /dev/null +++ b/tests/kernel/device/dts/bindings/fakedeferdriver.yml @@ -0,0 +1,8 @@ +# Copyright (c) 2023 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +description: Properties for fake deferred driver. + +compatible: "fakedeferdriver" + +include: base.yaml diff --git a/tests/kernel/device/src/main.c b/tests/kernel/device/src/main.c index 4c02a52ce94..437f2ae056c 100644 --- a/tests/kernel/device/src/main.c +++ b/tests/kernel/device/src/main.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -21,10 +22,23 @@ #define MY_DRIVER_A "my_driver_A" #define MY_DRIVER_B "my_driver_B" +#define FAKEDEFERDRIVER0 DEVICE_DT_GET(DT_PATH(fakedeferdriver_e7000000)) +#define FAKEDEFERDRIVER1 DEVICE_DT_GET(DT_PATH(fakedeferdriver_e8000000)) + /* A device without init call */ DEVICE_DEFINE(dummy_noinit, DUMMY_NOINIT, NULL, NULL, NULL, NULL, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, NULL); +/* To access from userspace, the device needs an API. Use a dummy GPIO one */ +static const struct gpio_driver_api fakedeferdriverapi; + +/* Fake deferred devices */ +DEVICE_DT_DEFINE(DT_INST(0, fakedeferdriver), NULL, NULL, NULL, NULL, + POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, NULL); +DEVICE_DT_DEFINE(DT_INST(1, fakedeferdriver), NULL, NULL, NULL, NULL, + POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, + &fakedeferdriverapi); + /** * @brief Test cases to verify device objects * @@ -387,9 +401,41 @@ ZTEST(device, test_abstraction_driver_common) zassert_true(baz == 2, "common API do_that fail"); } +ZTEST(device, test_deferred_init) +{ + int ret; + + zassert_false(device_is_ready(FAKEDEFERDRIVER0)); + + ret = device_init(FAKEDEFERDRIVER0); + zassert_true(ret == 0); + + zassert_true(device_is_ready(FAKEDEFERDRIVER0)); +} + +ZTEST_USER(device, test_deferred_init_user) +{ + int ret; + + zassert_false(device_is_ready(FAKEDEFERDRIVER1)); + + ret = device_init(FAKEDEFERDRIVER1); + zassert_true(ret == 0); + + zassert_true(device_is_ready(FAKEDEFERDRIVER1)); +} + +void *user_setup(void) +{ +#ifdef CONFIG_USERSPACE + k_object_access_grant(FAKEDEFERDRIVER1, k_current_get()); +#endif + + return NULL; +} /** * @} */ -ZTEST_SUITE(device, NULL, NULL, NULL, NULL, NULL); +ZTEST_SUITE(device, NULL, user_setup, NULL, NULL, NULL); diff --git a/tests/kernel/device/testcase.yaml b/tests/kernel/device/testcase.yaml index 931f2635d60..6946518b2be 100644 --- a/tests/kernel/device/testcase.yaml +++ b/tests/kernel/device/testcase.yaml @@ -1,28 +1,32 @@ common: tags: - device + - kernel - userspace - integration_platforms: - - native_sim tests: kernel.device: - tags: - - kernel - - device + integration_platforms: + - native_sim platform_exclude: xenvm kernel.device.minimallibc: + integration_platforms: + - native_sim filter: CONFIG_MINIMAL_LIBC_SUPPORTED tags: - - kernel - - device - libc extra_configs: - CONFIG_MINIMAL_LIBC=y platform_exclude: xenvm kernel.device.pm: - tags: - - kernel - - device + integration_platforms: + - native_sim platform_exclude: mec15xxevb_assy6853 xenvm extra_configs: - CONFIG_PM_DEVICE=y + kernel.device.linker_generator: + platform_allow: + - qemu_cortex_m3 + tags: + - linker_generator + extra_configs: + - CONFIG_CMAKE_LINKER_GENERATOR=y diff --git a/tests/kernel/interrupt/src/dynamic_isr.c b/tests/kernel/interrupt/src/dynamic_isr.c index d697fda32e8..1fe6db4b4b2 100644 --- a/tests/kernel/interrupt/src/dynamic_isr.c +++ b/tests/kernel/interrupt/src/dynamic_isr.c @@ -22,6 +22,12 @@ static void dyn_isr(const void *arg) #if defined(CONFIG_GEN_SW_ISR_TABLE) extern struct _isr_table_entry _sw_isr_table[]; +#if defined(CONFIG_RISCV_RESERVED_IRQ_ISR_TABLES_OFFSET) +#define IRQ_OFFSET CONFIG_RISCV_RESERVED_IRQ_ISR_TABLES_OFFSET +#else +#define IRQ_OFFSET 0 +#endif + /** * @brief Test dynamic ISR installation * @@ -55,8 +61,8 @@ ZTEST(interrupt_feature, test_isr_dynamic) arch_irq_connect_dynamic(i + CONFIG_GEN_IRQ_START_VECTOR, 0, dyn_isr, argval, 0); - zassert_true(_sw_isr_table[i].isr == dyn_isr && - _sw_isr_table[i].arg == argval, + zassert_true(_sw_isr_table[i + IRQ_OFFSET].isr == dyn_isr && + _sw_isr_table[i + IRQ_OFFSET].arg == argval, "dynamic isr did not install successfully"); } #else diff --git a/tests/kernel/interrupt/src/nested_irq.c b/tests/kernel/interrupt/src/nested_irq.c index ee48a0366d2..21fccc5cadf 100644 --- a/tests/kernel/interrupt/src/nested_irq.c +++ b/tests/kernel/interrupt/src/nested_irq.c @@ -12,7 +12,7 @@ * Run the nested interrupt test for the supported platforms only. */ #if defined(CONFIG_CPU_CORTEX_M) || defined(CONFIG_ARC) || \ - defined(CONFIG_GIC) + defined(CONFIG_GIC) || defined(CONFIG_NRFX_CLIC) #define TEST_NESTED_ISR #endif @@ -56,6 +56,12 @@ */ #define IRQ0_PRIO IRQ_DEFAULT_PRIORITY #define IRQ1_PRIO 0x0 +#elif defined(CONFIG_SOC_NRF54L15_ENGA_CPUFLPR) +#define IRQ0_LINE 16 +#define IRQ1_LINE 17 + +#define IRQ0_PRIO 1 +#define IRQ1_PRIO 2 #else /* * For all the other platforms, use the last two available IRQ lines for diff --git a/tests/kernel/mem_protect/userspace/boards/nucleo_f756zg.overlay b/tests/kernel/mem_protect/userspace/boards/nucleo_f756zg.overlay new file mode 100644 index 00000000000..6277cda5bc1 --- /dev/null +++ b/tests/kernel/mem_protect/userspace/boards/nucleo_f756zg.overlay @@ -0,0 +1,13 @@ +/* + * Copyright 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * Disable quadspi MPU region for testing + * on this stm32f7 target. + * Otherwise one region will be missing from the 8 MPU regions + */ + +/delete-node/ &quadspi_memory; diff --git a/tests/kernel/mem_protect/userspace/src/main.c b/tests/kernel/mem_protect/userspace/src/main.c index cd66c06ab7a..d2b5842ee97 100644 --- a/tests/kernel/mem_protect/userspace/src/main.c +++ b/tests/kernel/mem_protect/userspace/src/main.c @@ -553,17 +553,16 @@ ZTEST_USER(userspace, test_read_other_stack) /* Try to read from another thread's stack. */ unsigned int val; -#if defined(CONFIG_MMU) || defined(CONFIG_MPU) -#if defined(CONFIG_ARCH_MEM_DOMAIN_SYNCHRONOUS_API) - /* With memory domain enabled, all threads within the same domain - * have access to each other threads' stacks, especially with - * CONFIG_ARCH_MEM_DOMAIN_SYNCHRONOUS_API=y (as it is expected - * behavior). The access would not fault which the test expects. - * So skip this test. +#if !defined(CONFIG_MEM_DOMAIN_ISOLATED_STACKS) + /* The minimal requirement to support memory domain permits + * threads of the same memory domain to access each others' stacks. + * Some architectures supports further restricting access which + * can be enabled via a kconfig. So if the kconfig is not enabled, + * skip the test. */ ztest_test_skip(); #endif -#endif + k_thread_create(&test_thread, test_stack, STACKSIZE, uthread_read_body, &val, NULL, NULL, -1, K_USER | K_INHERIT_PERMS, @@ -583,17 +582,16 @@ ZTEST_USER(userspace, test_write_other_stack) /* Try to write to another thread's stack. */ unsigned int val; -#if defined(CONFIG_MMU) || defined(CONFIG_MPU) -#if defined(CONFIG_ARCH_MEM_DOMAIN_SYNCHRONOUS_API) - /* With memory domain enabled, all threads within the same domain - * have access to each other threads' stacks, especially with - * CONFIG_ARCH_MEM_DOMAIN_SYNCHRONOUS_API=y (as it is expected - * behavior). The access would not fault which the test expects. - * So skip this test. +#if !defined(CONFIG_MEM_DOMAIN_ISOLATED_STACKS) + /* The minimal requirement to support memory domain permits + * threads of the same memory domain to access each others' stacks. + * Some architectures supports further restricting access which + * can be enabled via a kconfig. So if the kconfig is not enabled, + * skip the test. */ ztest_test_skip(); #endif -#endif + k_thread_create(&test_thread, test_stack, STACKSIZE, uthread_write_body, &val, NULL, NULL, -1, K_USER | K_INHERIT_PERMS, diff --git a/tests/kernel/profiling/profiling_api/prj.conf b/tests/kernel/profiling/profiling_api/prj.conf index f46372c436c..678d233cdc8 100644 --- a/tests/kernel/profiling/profiling_api/prj.conf +++ b/tests/kernel/profiling/profiling_api/prj.conf @@ -7,8 +7,6 @@ CONFIG_TEST_HW_STACK_PROTECTION=n # Disable HW Stack Protection (see #28664) CONFIG_HW_STACK_PROTECTION=n # to check idle thread -CONFIG_PM=y -CONFIG_PM_POLICY_CUSTOM=y CONFIG_IDLE_STACK_SIZE=2048 # to check isr CONFIG_IRQ_OFFLOAD=y diff --git a/tests/kernel/profiling/profiling_api/src/main.c b/tests/kernel/profiling/profiling_api/src/main.c index baa79cdc879..8488df1ab6a 100644 --- a/tests/kernel/profiling/profiling_api/src/main.c +++ b/tests/kernel/profiling/profiling_api/src/main.c @@ -22,24 +22,6 @@ static void tdata_dump_callback(const struct k_thread *thread, void *user_data) log_stack_usage(thread); } -/* Our PM policy handler */ -const struct pm_state_info *pm_policy_next_state(uint8_t cpu, int32_t ticks) -{ - static bool test_flag; - - ARG_UNUSED(cpu); - - /* Call k_thread_foreach only once otherwise it will - * flood the console with stack dumps. - */ - if (!test_flag) { - k_thread_foreach(tdata_dump_callback, NULL); - test_flag = true; - } - - return NULL; -} - /*work handler*/ static void work_handler(struct k_work *w) { diff --git a/tests/kernel/profiling/profiling_api/testcase.yaml b/tests/kernel/profiling/profiling_api/testcase.yaml index d4dad4abd08..0534fe6e4a4 100644 --- a/tests/kernel/profiling/profiling_api/testcase.yaml +++ b/tests/kernel/profiling/profiling_api/testcase.yaml @@ -11,4 +11,4 @@ tests: - nrf5340dk/nrf5340/cpunet tags: - kernel - - pm + - profiling diff --git a/tests/kernel/semaphore/semaphore/prj.conf b/tests/kernel/semaphore/semaphore/prj.conf index a8b0a3e4d25..e193f5f626d 100644 --- a/tests/kernel/semaphore/semaphore/prj.conf +++ b/tests/kernel/semaphore/semaphore/prj.conf @@ -3,3 +3,4 @@ CONFIG_IRQ_OFFLOAD=y CONFIG_TEST_USERSPACE=y CONFIG_ZTEST_FATAL_HOOK=y CONFIG_PIPES=y +CONFIG_MAX_THREAD_BYTES=3 diff --git a/tests/kernel/semaphore/sys_sem/prj.conf b/tests/kernel/semaphore/sys_sem/prj.conf index 869fd338e6a..e9e32307745 100644 --- a/tests/kernel/semaphore/sys_sem/prj.conf +++ b/tests/kernel/semaphore/sys_sem/prj.conf @@ -1,3 +1,4 @@ CONFIG_ZTEST=y CONFIG_TEST_USERSPACE=y CONFIG_ZTEST_FATAL_HOOK=y +CONFIG_MAX_THREAD_BYTES=3 diff --git a/tests/kernel/smp_abort/CMakeLists.txt b/tests/kernel/smp_abort/CMakeLists.txt new file mode 100644 index 00000000000..8419d0169e4 --- /dev/null +++ b/tests/kernel/smp_abort/CMakeLists.txt @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(smp_abort) + +target_sources(app PRIVATE src/main.c) + +target_include_directories(app PRIVATE + ${ZEPHYR_BASE}/kernel/include + ${ZEPHYR_BASE}/arch/${ARCH}/include + ) diff --git a/tests/kernel/smp_abort/prj.conf b/tests/kernel/smp_abort/prj.conf new file mode 100644 index 00000000000..eeaa3ed4861 --- /dev/null +++ b/tests/kernel/smp_abort/prj.conf @@ -0,0 +1,3 @@ +CONFIG_ZTEST=y +CONFIG_IRQ_OFFLOAD=y +CONFIG_SMP=y diff --git a/tests/kernel/smp_abort/src/main.c b/tests/kernel/smp_abort/src/main.c new file mode 100644 index 00000000000..e0eb2c78819 --- /dev/null +++ b/tests/kernel/smp_abort/src/main.c @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2024 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#if CONFIG_MP_MAX_NUM_CPUS < 2 +#error "SMP test requires at least two CPUs!" +#endif + +#define NUM_THREADS CONFIG_MP_MAX_NUM_CPUS +#define STACK_SIZE 1024 + +K_THREAD_STACK_ARRAY_DEFINE(thread_stack, NUM_THREADS, STACK_SIZE); +struct k_thread thread[NUM_THREADS]; + +struct isr_args { + volatile bool *sync; + volatile bool *wait; + struct k_thread *target; +}; + +volatile bool sync[NUM_THREADS]; + +struct isr_args isr_args[NUM_THREADS]; + +static void isr(const void *args) +{ + const struct isr_args *var = args; + + *(var->sync) = true; /* Flag that ISR is in progress */ + + while (*(var->wait) == false) { /* Wait upon dependent CPU */ + } + + k_thread_abort(var->target); /* Abort thread on another CPU */ +} + +static void thread_entry(void *p1, void *p2, void *p3) +{ + unsigned int index = (unsigned int)(uintptr_t)p1; + struct isr_args *var = p2; + + printk("Thread %u started\n", index); + + irq_offload(isr, var); + + zassert_true(false, "Thread %u did not abort!", index); +} + +ZTEST(smp_abort, test_smp_thread_abort_deadlock) +{ + unsigned int i; + int priority; + + priority = k_thread_priority_get(k_current_get()); + + /* + * Each thread will run on its own CPU and invoke an ISR. + * Each ISR will wait until the next thread enters its ISR + * before attempting to abort that thread. This ensures that + * we have a scenario where each CPU is attempting to abort + * the active thread that was interrupted by an ISR. + */ + + for (i = 0; i < NUM_THREADS; i++) { + isr_args[i].sync = &sync[i]; + isr_args[i].wait = &sync[(i + 1) % NUM_THREADS]; + isr_args[i].target = &thread[(i + 1) % NUM_THREADS]; + } + + for (i = 0; i < NUM_THREADS; i++) { + + k_thread_create(&thread[i], thread_stack[i], + STACK_SIZE, thread_entry, + (void *)(uintptr_t)i, &isr_args[i], NULL, + priority - 1, 0, K_NO_WAIT); + } + + for (i = 0; i < NUM_THREADS; i++) { + k_thread_join(&thread[i], K_FOREVER); + } + + printk("Done!\n"); +} + +ZTEST_SUITE(smp_abort, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/kernel/smp_abort/testcase.yaml b/tests/kernel/smp_abort/testcase.yaml new file mode 100644 index 00000000000..3903e477e17 --- /dev/null +++ b/tests/kernel/smp_abort/testcase.yaml @@ -0,0 +1,7 @@ +tests: + kernel.smp_abort: + arch_exclude: x86 # Buggy irq_offload(), see #71172 + tags: + - kernel + - smp + filter: (CONFIG_MP_MAX_NUM_CPUS > 1) diff --git a/tests/kernel/threads/dynamic_thread_stack/src/main.c b/tests/kernel/threads/dynamic_thread_stack/src/main.c index bb15d824d81..a833197d361 100644 --- a/tests/kernel/threads/dynamic_thread_stack/src/main.c +++ b/tests/kernel/threads/dynamic_thread_stack/src/main.c @@ -9,7 +9,7 @@ #define TIMEOUT_MS 500 -#define POOL_SIZE 20480 +#define POOL_SIZE 28672 #ifdef CONFIG_USERSPACE #define STACK_OBJ_SIZE K_THREAD_STACK_LEN(CONFIG_DYNAMIC_THREAD_STACK_SIZE) @@ -168,6 +168,103 @@ ZTEST(dynamic_thread_stack, test_dynamic_thread_stack_alloc) } } +K_SEM_DEFINE(perm_sem, 0, 1); +ZTEST_BMEM static volatile bool expect_fault; +ZTEST_BMEM static volatile unsigned int expected_reason; + +static void set_fault(unsigned int reason) +{ + expect_fault = true; + expected_reason = reason; + compiler_barrier(); +} + +void k_sys_fatal_error_handler(unsigned int reason, const z_arch_esf_t *pEsf) +{ + if (expect_fault) { + if (expected_reason == reason) { + printk("System error was expected\n"); + expect_fault = false; + } else { + printk("Wrong fault reason, expecting %d\n", + expected_reason); + TC_END_REPORT(TC_FAIL); + k_fatal_halt(reason); + } + } else { + printk("Unexpected fault during test\n"); + TC_END_REPORT(TC_FAIL); + k_fatal_halt(reason); + } +} + +static void perm_func(void *arg1, void *arg2, void *arg3) +{ + k_sem_take((struct k_sem *)arg1, K_FOREVER); +} + +static void perm_func_violator(void *arg1, void *arg2, void *arg3) +{ + (void)k_thread_stack_free((k_thread_stack_t *)arg2); + + zassert_unreachable("should not reach here"); +} + +/** @brief Exercise stack permissions */ +ZTEST(dynamic_thread_stack, test_dynamic_thread_stack_permission) +{ + static k_tid_t tid[2]; + static struct k_thread th[2]; + static k_thread_stack_t *stack[2]; + + if (!IS_ENABLED(CONFIG_DYNAMIC_THREAD_PREFER_ALLOC)) { + ztest_test_skip(); + } + + if (!IS_ENABLED(CONFIG_DYNAMIC_THREAD_ALLOC)) { + ztest_test_skip(); + } + + if (!IS_ENABLED(CONFIG_USERSPACE)) { + ztest_test_skip(); + } + + stack[0] = k_thread_stack_alloc(CONFIG_DYNAMIC_THREAD_STACK_SIZE, K_USER); + zassert_not_null(stack[0]); + + stack[1] = k_thread_stack_alloc(CONFIG_DYNAMIC_THREAD_STACK_SIZE, K_USER); + zassert_not_null(stack[1]); + + k_thread_access_grant(k_current_get(), &perm_sem); + + /* First thread inherit permissions */ + tid[0] = k_thread_create(&th[0], stack[0], CONFIG_DYNAMIC_THREAD_STACK_SIZE, perm_func, + &perm_sem, NULL, NULL, 0, K_USER | K_INHERIT_PERMS, K_NO_WAIT); + zassert_not_null(tid[0]); + + /* Second thread will have access to specific kobjects only */ + tid[1] = k_thread_create(&th[1], stack[1], CONFIG_DYNAMIC_THREAD_STACK_SIZE, + perm_func_violator, &perm_sem, stack[0], NULL, 0, K_USER, + K_FOREVER); + zassert_not_null(tid[1]); + k_thread_access_grant(tid[1], &perm_sem); + k_thread_access_grant(tid[1], &stack[1]); + + set_fault(K_ERR_KERNEL_OOPS); + + k_thread_start(tid[1]); + + /* join all threads and check that flags have been set */ + zassert_ok(k_thread_join(tid[1], K_MSEC(TIMEOUT_MS))); + + k_sem_give(&perm_sem); + zassert_ok(k_thread_join(tid[0], K_MSEC(TIMEOUT_MS))); + + /* clean up stacks allocated from the heap */ + zassert_ok(k_thread_stack_free(stack[0])); + zassert_ok(k_thread_stack_free(stack[1])); +} + static void *dynamic_thread_stack_setup(void) { k_thread_heap_assign(k_current_get(), &stack_heap); diff --git a/tests/kernel/threads/thread_apis/src/test_threads_cancel_abort.c b/tests/kernel/threads/thread_apis/src/test_threads_cancel_abort.c index aad8842a11e..b99347a404f 100644 --- a/tests/kernel/threads/thread_apis/src/test_threads_cancel_abort.c +++ b/tests/kernel/threads/thread_apis/src/test_threads_cancel_abort.c @@ -166,6 +166,11 @@ static void offload_func(const void *param) k_thread_abort(t); + /* Thread memory is unused now, validate that we can clobber it. */ + if (!IS_ENABLED(CONFIG_ARCH_POSIX)) { + memset(t, 0, sizeof(*t)); + } + /* k_thread_abort() in an isr shouldn't affect the ISR's execution */ isr_finished = true; } @@ -201,6 +206,19 @@ ZTEST(threads_lifecycle, test_abort_from_isr) k_thread_join(&tdata, K_FOREVER); zassert_true(isr_finished, "ISR did not complete"); + /* Thread struct was cleared after the abort, make sure it is + * still clear (i.e. that the arch layer didn't write to it + * during interrupt exit). Doesn't work on posix, which needs + * the thread struct for its swap code. + */ + uint8_t *p = (uint8_t *)&tdata; + + if (!IS_ENABLED(CONFIG_ARCH_POSIX)) { + for (int i = 0; i < sizeof(tdata); i++) { + zassert_true(p[i] == 0, "Free memory write to aborted thread"); + } + } + /* Notice: Recover back the offload_sem: This is use for releasing * offload_sem which might be held when thread aborts itself in ISR * context, it will cause irq_offload cannot be used again. @@ -248,6 +266,5 @@ ZTEST(threads_lifecycle, test_abort_from_isr_not_self) /* Simulate taking an interrupt which kills spwan thread */ irq_offload(offload_func, (void *)tid); - k_thread_join(&tdata, K_FOREVER); zassert_true(isr_finished, "ISR did not complete"); } diff --git a/tests/kernel/tickless/tickless_concept/prj.conf b/tests/kernel/tickless/tickless_concept/prj.conf index 9290ae5a65d..289dda3092c 100644 --- a/tests/kernel/tickless/tickless_concept/prj.conf +++ b/tests/kernel/tickless/tickless_concept/prj.conf @@ -1,4 +1,3 @@ CONFIG_ZTEST=y -CONFIG_PM=y CONFIG_SYS_CLOCK_TICKS_PER_SEC=100 CONFIG_MP_MAX_NUM_CPUS=1 diff --git a/tests/kernel/timer/timer_api/prj_tickless.conf b/tests/kernel/timer/timer_api/prj_tickless.conf deleted file mode 100644 index 2b00d1fe866..00000000000 --- a/tests/kernel/timer/timer_api/prj_tickless.conf +++ /dev/null @@ -1,7 +0,0 @@ -CONFIG_ZTEST=y -CONFIG_PM=y -CONFIG_TICKLESS_KERNEL=y -CONFIG_MP_MAX_NUM_CPUS=1 -CONFIG_TEST_RANDOM_GENERATOR=y - -CONFIG_TEST_USERSPACE=y diff --git a/tests/kernel/timer/timer_api/src/main.c b/tests/kernel/timer/timer_api/src/main.c index 58836c2ba9b..ba9a76d4085 100644 --- a/tests/kernel/timer/timer_api/src/main.c +++ b/tests/kernel/timer/timer_api/src/main.c @@ -803,10 +803,30 @@ ZTEST_USER(timer_api, test_sleep_abs) * time slop or more depending on the time to resume */ k_ticks_t late = end - (start + sleep_ticks); + int slop = MAX(2, k_us_to_ticks_ceil32(250)); - zassert_true(late >= 0 && late <= MAX(2, k_us_to_ticks_ceil32(250)), + zassert_true(late >= 0 && late <= slop, "expected wakeup at %lld, got %lld (late %lld)", start + sleep_ticks, end, late); + + /* Let's test that an absolute delay awakes at the correct time + * even if the system did not get some ticks announcements + */ + int tickless_wait = 5; + + start = end; + k_busy_wait(k_ticks_to_us_ceil32(tickless_wait)); + /* We expect to not have got tick announcements, + * as there is currently nothing scheduled + */ + k_sleep(K_TIMEOUT_ABS_TICKS(start + sleep_ticks)); + end = k_uptime_ticks(); + late = end - (start + sleep_ticks); + + zassert_true(late >= 0 && late <= slop, + "expected wakeup at %lld, got %lld (late %lld)", + start + sleep_ticks, end, late); + } static void timer_init(struct k_timer *timer, k_timer_expiry_t expiry_fn, diff --git a/tests/kernel/timer/timer_api/testcase.yaml b/tests/kernel/timer/timer_api/testcase.yaml index 9337459bf51..454403837a0 100644 --- a/tests/kernel/timer/timer_api/testcase.yaml +++ b/tests/kernel/timer/timer_api/testcase.yaml @@ -4,21 +4,6 @@ tests: - kernel - timer - userspace - kernel.timer.tickless: - extra_args: CONF_FILE="prj_tickless.conf" - arch_exclude: - - nios2 - - posix - platform_exclude: - - litex_vexriscv - - rv32m1_vega/openisa_rv32m1/zero_riscy - - rv32m1_vega/openisa_rv32m1/ri5cy - - nrf5340dk/nrf5340/cpunet - tags: - - kernel - - timer - - userspace - - pm kernel.timer.no_multitheading: tags: - kernel diff --git a/tests/kernel/timer/timer_behavior/Kconfig b/tests/kernel/timer/timer_behavior/Kconfig index ba5f18e969e..fa954f000a1 100644 --- a/tests/kernel/timer/timer_behavior/Kconfig +++ b/tests/kernel/timer/timer_behavior/Kconfig @@ -24,6 +24,7 @@ config TIMER_TEST_PERIOD config TIMER_TEST_MAX_STDDEV int "Maximum standard deviation in microseconds allowed" default 33 if NPCX_ITIM_TIMER + default 33 if ITE_IT8XXX2_TIMER default 10 config TIMER_TEST_MAX_DRIFT diff --git a/tests/kernel/workq/work/src/main.c b/tests/kernel/workq/work/src/main.c index 68a89588379..808c83cb17f 100644 --- a/tests/kernel/workq/work/src/main.c +++ b/tests/kernel/workq/work/src/main.c @@ -1263,7 +1263,7 @@ ZTEST(work_1cpu, test_1cpu_immed_reschedule) zassert_equal(rc, 1); } -/* Test no-yield behavior, returns true iff work queue priority is +/* Test no-yield behavior, returns true if and only if work queue priority is * higher than test thread priority */ static bool try_queue_no_yield(struct k_work_q *wq) diff --git a/tests/lib/devicetree/api/app.overlay b/tests/lib/devicetree/api/app.overlay index 5ee7171d932..ee3bef5db41 100644 --- a/tests/lib/devicetree/api/app.overlay +++ b/tests/lib/devicetree/api/app.overlay @@ -528,7 +528,6 @@ test_can0: can@55553333 { compatible = "vnd,can-controller"; reg = < 0x55553333 0x1000 >; - bus-speed = <125000>; status = "okay"; phys = <&test_transceiver0>; }; @@ -536,7 +535,6 @@ test_can1: can@55554444 { compatible = "vnd,can-controller"; reg = < 0x55554444 0x1000 >; - bus-speed = <125000>; status = "okay"; can-transceiver { @@ -548,7 +546,6 @@ test_can2: can@55555555 { compatible = "vnd,can-controller"; reg = < 0x55555555 0x1000 >; - bus-speed = <125000>; status = "okay"; can-transceiver { @@ -559,7 +556,6 @@ test_can3: can@55557777 { compatible = "vnd,can-controller"; reg = < 0x55556666 0x1000 >; - bus-speed = <125000>; status = "okay"; phys = <&test_transceiver1>; }; diff --git a/tests/lib/devicetree/api/src/main.c b/tests/lib/devicetree/api/src/main.c index 5c0937dbc28..c57a280670f 100644 --- a/tests/lib/devicetree/api/src/main.c +++ b/tests/lib/devicetree/api/src/main.c @@ -319,6 +319,10 @@ ZTEST(devicetree_api, test_has_compat) (TA_HAS_COMPAT(vnd_undefined_compat) << 1) | (TA_HAS_COMPAT(vnd_not_a_test_array_compat) << 2)); zassert_equal(compats, 0x3, ""); + +#undef DT_DRV_COMPAT +#define DT_DRV_COMPAT vnd_model1 + zassert_true(DT_INST_NODE_HAS_COMPAT(0, zephyr_model2)); } ZTEST(devicetree_api, test_has_status) @@ -2210,6 +2214,16 @@ ZTEST(devicetree_api, test_child_nodes_list_varg) #undef TEST_FUNC } +#undef DT_DRV_COMPAT +#define DT_DRV_COMPAT vnd_child_bindings +ZTEST(devicetree_api, test_child_nodes_number) +{ + zassert_equal(DT_CHILD_NUM(TEST_CHILDREN), 3, ""); + zassert_equal(DT_INST_CHILD_NUM(0), 3, ""); + zassert_equal(DT_CHILD_NUM_STATUS_OKAY(TEST_CHILDREN), 2, ""); + zassert_equal(DT_INST_CHILD_NUM_STATUS_OKAY(0), 2, ""); +} + ZTEST(devicetree_api, test_great_grandchild) { zassert_equal(DT_PROP(DT_NODELABEL(test_ggc), ggc_prop), 42, ""); diff --git a/tests/lib/smf/CMakeLists.txt b/tests/lib/smf/CMakeLists.txt index 08844e75aa6..3e793f98442 100644 --- a/tests/lib/smf/CMakeLists.txt +++ b/tests/lib/smf/CMakeLists.txt @@ -7,7 +7,7 @@ project(smf) target_sources(app PRIVATE src/main.c) if(CONFIG_SMF_INITIAL_TRANSITION) - target_sources(app PRIVATE src/test_lib_initial_transitions_smf.c) + target_sources(app PRIVATE src/test_lib_self_transition_smf.c) elseif(CONFIG_SMF_ANCESTOR_SUPPORT) target_sources(app PRIVATE src/test_lib_hierarchical_smf.c src/test_lib_hierarchical_5_ancestor_smf.c) diff --git a/tests/lib/smf/src/test_lib_flat_smf.c b/tests/lib/smf/src/test_lib_flat_smf.c index 2a66fb85943..3824565986e 100644 --- a/tests/lib/smf/src/test_lib_flat_smf.c +++ b/tests/lib/smf/src/test_lib_flat_smf.c @@ -213,10 +213,10 @@ static void state_d_exit(void *obj) } static const struct smf_state test_states[] = { - [STATE_A] = SMF_CREATE_STATE(state_a_entry, state_a_run, state_a_exit), - [STATE_B] = SMF_CREATE_STATE(state_b_entry, state_b_run, state_b_exit), - [STATE_C] = SMF_CREATE_STATE(state_c_entry, state_c_run, state_c_exit), - [STATE_D] = SMF_CREATE_STATE(state_d_entry, state_d_run, state_d_exit), + [STATE_A] = SMF_CREATE_STATE(state_a_entry, state_a_run, state_a_exit, NULL, NULL), + [STATE_B] = SMF_CREATE_STATE(state_b_entry, state_b_run, state_b_exit, NULL, NULL), + [STATE_C] = SMF_CREATE_STATE(state_c_entry, state_c_run, state_c_exit, NULL, NULL), + [STATE_D] = SMF_CREATE_STATE(state_d_entry, state_d_run, state_d_exit, NULL, NULL), }; ZTEST(smf_tests, test_smf_flat) diff --git a/tests/lib/smf/src/test_lib_hierarchical_5_ancestor_smf.c b/tests/lib/smf/src/test_lib_hierarchical_5_ancestor_smf.c index b50221e67d3..bd62e9bb110 100644 --- a/tests/lib/smf/src/test_lib_hierarchical_5_ancestor_smf.c +++ b/tests/lib/smf/src/test_lib_hierarchical_5_ancestor_smf.c @@ -412,15 +412,15 @@ static void d_entry(void *obj) } static const struct smf_state test_states[] = { - [P05] SMF_CREATE_STATE(p05_entry, p05_run, p05_exit, NULL), - [P04] SMF_CREATE_STATE(p04_entry, p04_run, p04_exit, &test_states[P05]), - [P03] SMF_CREATE_STATE(p03_entry, p03_run, p03_exit, &test_states[P04]), - [P02] SMF_CREATE_STATE(p02_entry, p02_run, p02_exit, &test_states[P03]), - [P01] SMF_CREATE_STATE(p01_entry, p01_run, p01_exit, &test_states[P02]), - [A] = SMF_CREATE_STATE(a_entry, a_run, a_exit, &test_states[P01]), - [B] = SMF_CREATE_STATE(b_entry, b_run, b_exit, &test_states[P01]), - [C] = SMF_CREATE_STATE(c_entry, c_run, c_exit, NULL), - [D] = SMF_CREATE_STATE(d_entry, NULL, NULL, NULL), + [P05] SMF_CREATE_STATE(p05_entry, p05_run, p05_exit, NULL, NULL), + [P04] SMF_CREATE_STATE(p04_entry, p04_run, p04_exit, &test_states[P05], NULL), + [P03] SMF_CREATE_STATE(p03_entry, p03_run, p03_exit, &test_states[P04], NULL), + [P02] SMF_CREATE_STATE(p02_entry, p02_run, p02_exit, &test_states[P03], NULL), + [P01] SMF_CREATE_STATE(p01_entry, p01_run, p01_exit, &test_states[P02], NULL), + [A] = SMF_CREATE_STATE(a_entry, a_run, a_exit, &test_states[P01], NULL), + [B] = SMF_CREATE_STATE(b_entry, b_run, b_exit, &test_states[P01], NULL), + [C] = SMF_CREATE_STATE(c_entry, c_run, c_exit, NULL, NULL), + [D] = SMF_CREATE_STATE(d_entry, NULL, NULL, NULL, NULL), }; ZTEST(smf_tests, test_smf_hierarchical_5_ancestors) diff --git a/tests/lib/smf/src/test_lib_hierarchical_smf.c b/tests/lib/smf/src/test_lib_hierarchical_smf.c index cf3b4845d31..2070ffb1a16 100644 --- a/tests/lib/smf/src/test_lib_hierarchical_smf.c +++ b/tests/lib/smf/src/test_lib_hierarchical_smf.c @@ -338,17 +338,17 @@ static void state_d_exit(void *obj) static const struct smf_state test_states[] = { [PARENT_AB] = SMF_CREATE_STATE(parent_ab_entry, parent_ab_run, - parent_ab_exit, NULL), + parent_ab_exit, NULL, NULL), [PARENT_C] = SMF_CREATE_STATE(parent_c_entry, parent_c_run, - parent_c_exit, NULL), + parent_c_exit, NULL, NULL), [STATE_A] = SMF_CREATE_STATE(state_a_entry, state_a_run, state_a_exit, - &test_states[PARENT_AB]), + &test_states[PARENT_AB], NULL), [STATE_B] = SMF_CREATE_STATE(state_b_entry, state_b_run, state_b_exit, - &test_states[PARENT_AB]), + &test_states[PARENT_AB], NULL), [STATE_C] = SMF_CREATE_STATE(state_c_entry, state_c_run, state_c_exit, - &test_states[PARENT_C]), + &test_states[PARENT_C], NULL), [STATE_D] = SMF_CREATE_STATE(state_d_entry, state_d_run, state_d_exit, - NULL), + NULL, NULL), }; ZTEST(smf_tests, test_smf_hierarchical) diff --git a/tests/lib/smf/src/test_lib_initial_transitions_smf.c b/tests/lib/smf/src/test_lib_initial_transitions_smf.c deleted file mode 100644 index 2e00dc2d553..00000000000 --- a/tests/lib/smf/src/test_lib_initial_transitions_smf.c +++ /dev/null @@ -1,501 +0,0 @@ -/* - * Copyright 2024 Glenn Andrews - * based on test_lib_hierarchical_smf.c - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include - -/* - * Hierarchical Test Transition: - * - * PARENT_AB_ENTRY --> A_ENTRY --> A_RUN --> PARENT_AB_RUN ---| - * | - * |----------------------------------------------------------| - * | - * |--> A_EXIT --> B_ENTRY --> B_RUN --> B_EXIT --------------| - * | - * |----------------------------------------------------------| - * | - * |--> PARENT_AB_EXIT --> PARENT_C_ENTRY --> C_ENTRY --------| - * | - * |----------------------------------------------------------| - * | - * |--> C_RUN(#1) --> C_RUN(#2) --> C_EXIT --> PARENT_C_RUN --| - * | - * |----------------------------------------------------------| - * | - * |--> PARENT_C_EXIT - */ - -#define TEST_OBJECT(o) ((struct test_object *)o) - -#define SMF_RUN 4 - -/* Initial Setup */ -#define PARENT_AB_ENTRY_BIT (1 << 0) -#define STATE_A_ENTRY_BIT (1 << 1) - -/* Run 0 */ -#define STATE_A_RUN_BIT (1 << 2) -#define PARENT_AB_RUN_BIT (1 << 3) -#define STATE_A_EXIT_BIT (1 << 4) -#define STATE_B_ENTRY_BIT (1 << 5) - -/* Run 1 */ -#define STATE_B_RUN_BIT (1 << 6) -#define STATE_B_EXIT_BIT (1 << 7) -#define PARENT_AB_EXIT_BIT (1 << 8) -#define PARENT_C_ENTRY_BIT (1 << 9) -#define STATE_C_ENTRY_BIT (1 << 10) - -/* Run 2 */ -#define STATE_C_1ST_RUN_BIT (1 << 11) - -/* Run 3 */ -#define STATE_C_2ND_RUN_BIT (1 << 12) -#define PARENT_C_RUN_BIT (1 << 13) -#define STATE_C_EXIT_BIT (1 << 14) -#define PARENT_C_EXIT_BIT (1 << 15) - -#define TEST_PARENT_ENTRY_VALUE_NUM 0 -#define TEST_PARENT_RUN_VALUE_NUM 3 -#define TEST_PARENT_EXIT_VALUE_NUM 8 -#define TEST_ENTRY_VALUE_NUM 1 -#define TEST_RUN_VALUE_NUM 6 -#define TEST_EXIT_VALUE_NUM 14 -#define TEST_VALUE_NUM 16 -static uint32_t test_value[] = { - 0x00, /* PARENT_AB_ENTRY */ - 0x01, /* STATE_A_ENTRY */ - 0x03, /* STATE_A_RUN */ - 0x07, /* PARENT_AB_RUN */ - 0x0f, /* STATE_A_EXIT */ - 0x1f, /* STATE_B_ENTRY */ - 0x3f, /* STATE_B_RUN */ - 0x7f, /* STATE_B_EXIT */ - 0xff, /* PARENT_AB_EXIT */ - 0x1ff, /* PARENT_C_ENTRY */ - 0x3ff, /* STATE_C_ENTRY */ - 0x7ff, /* STATE_C_1ST_RUN */ - 0xfff, /* STATE_C_2ND_RUN */ - 0x1fff, /* STATE_C_EXIT */ - 0x3fff, /* PARENT_C_RUN */ - 0x7fff, /* PARENT_C_EXIT */ - 0xffff, /* FINAL VALUE */ -}; - -/* Forward declaration of test_states */ -static const struct smf_state test_states[]; - -/* List of all TypeC-level states */ -enum test_state { - PARENT_AB, - PARENT_C, - STATE_A, - STATE_B, - STATE_C, - STATE_D -}; - -enum terminate_action { - NONE, - PARENT_ENTRY, - PARENT_RUN, - PARENT_EXIT, - ENTRY, - RUN, - EXIT -}; - -static struct test_object { - struct smf_ctx ctx; - uint32_t transition_bits; - uint32_t tv_idx; - enum terminate_action terminate; - uint32_t first_time; -} test_obj; - -static void parent_ab_entry(void *obj) -{ - struct test_object *o = TEST_OBJECT(obj); - - o->tv_idx = 0; - - zassert_equal(o->transition_bits, test_value[o->tv_idx], - "Test Parent AB entry failed"); - - if (o->terminate == PARENT_ENTRY) { - smf_set_terminate(obj, -1); - return; - } - - o->transition_bits |= PARENT_AB_ENTRY_BIT; -} - -static void parent_ab_run(void *obj) -{ - struct test_object *o = TEST_OBJECT(obj); - - o->tv_idx++; - - zassert_equal(o->transition_bits, test_value[o->tv_idx], - "Test Parent AB run failed"); - - if (o->terminate == PARENT_RUN) { - smf_set_terminate(obj, -1); - return; - } - - o->transition_bits |= PARENT_AB_RUN_BIT; - - smf_set_state(SMF_CTX(obj), &test_states[STATE_B]); -} - -static void parent_ab_exit(void *obj) -{ - struct test_object *o = TEST_OBJECT(obj); - - o->tv_idx++; - - zassert_equal(o->transition_bits, test_value[o->tv_idx], - "Test Parent AB exit failed"); - - if (o->terminate == PARENT_EXIT) { - smf_set_terminate(obj, -1); - return; - } - - o->transition_bits |= PARENT_AB_EXIT_BIT; -} - -static void parent_c_entry(void *obj) -{ - struct test_object *o = TEST_OBJECT(obj); - - o->tv_idx++; - - zassert_equal(o->transition_bits, test_value[o->tv_idx], - "Test Parent C entry failed"); - o->transition_bits |= PARENT_C_ENTRY_BIT; -} - -static void parent_c_run(void *obj) -{ - struct test_object *o = TEST_OBJECT(obj); - - o->tv_idx++; - - if (o->first_time) { - /* This state should not be reached */ - zassert_true(0, "Test Parent C run failed"); - } else { - o->transition_bits |= PARENT_C_RUN_BIT; - - smf_set_state(SMF_CTX(obj), &test_states[STATE_D]); - } -} - -static void parent_c_exit(void *obj) -{ - struct test_object *o = TEST_OBJECT(obj); - - o->tv_idx++; - - zassert_equal(o->transition_bits, test_value[o->tv_idx], - "Test Parent C exit failed"); - o->transition_bits |= PARENT_C_EXIT_BIT; -} - -static void state_a_entry(void *obj) -{ - struct test_object *o = TEST_OBJECT(obj); - - o->tv_idx++; - - zassert_equal(o->transition_bits, test_value[o->tv_idx], - "Test State A entry failed"); - - if (o->terminate == ENTRY) { - smf_set_terminate(obj, -1); - return; - } - - o->transition_bits |= STATE_A_ENTRY_BIT; -} - -static void state_a_run(void *obj) -{ - struct test_object *o = TEST_OBJECT(obj); - - o->tv_idx++; - - zassert_equal(o->transition_bits, test_value[o->tv_idx], - "Test State A run failed"); - - o->transition_bits |= STATE_A_RUN_BIT; - - /* Return to parent run state */ -} - -static void state_a_exit(void *obj) -{ - struct test_object *o = TEST_OBJECT(obj); - - o->tv_idx++; - - zassert_equal(o->transition_bits, test_value[o->tv_idx], - "Test State A exit failed"); - o->transition_bits |= STATE_A_EXIT_BIT; -} - -static void state_b_entry(void *obj) -{ - struct test_object *o = TEST_OBJECT(obj); - - o->tv_idx++; - - zassert_equal(o->transition_bits, test_value[o->tv_idx], - "Test State B entry failed"); - o->transition_bits |= STATE_B_ENTRY_BIT; -} - -static void state_b_run(void *obj) -{ - struct test_object *o = TEST_OBJECT(obj); - - o->tv_idx++; - - zassert_equal(o->transition_bits, test_value[o->tv_idx], - "Test State B run failed"); - - if (o->terminate == RUN) { - smf_set_terminate(obj, -1); - return; - } - - o->transition_bits |= STATE_B_RUN_BIT; - - smf_set_state(SMF_CTX(obj), &test_states[STATE_C]); -} - -static void state_b_exit(void *obj) -{ - struct test_object *o = TEST_OBJECT(obj); - - o->tv_idx++; - - zassert_equal(o->transition_bits, test_value[o->tv_idx], - "Test State B exit failed"); - o->transition_bits |= STATE_B_EXIT_BIT; -} - -static void state_c_entry(void *obj) -{ - struct test_object *o = TEST_OBJECT(obj); - - o->tv_idx++; - - zassert_equal(o->transition_bits, test_value[o->tv_idx], - "Test State C entry failed"); - o->transition_bits |= STATE_C_ENTRY_BIT; -} - -static void state_c_run(void *obj) -{ - struct test_object *o = TEST_OBJECT(obj); - - o->tv_idx++; - - zassert_equal(o->transition_bits, test_value[o->tv_idx], - "Test State C run failed"); - - if (o->first_time) { - o->first_time = false; - o->transition_bits |= STATE_C_1ST_RUN_BIT; - smf_set_handled(SMF_CTX(obj)); - } else { - /* Do nothing, Let parent handle it */ - o->transition_bits |= STATE_C_2ND_RUN_BIT; - } -} - -static void state_c_exit(void *obj) -{ - struct test_object *o = TEST_OBJECT(obj); - - o->tv_idx++; - - zassert_equal(o->transition_bits, test_value[o->tv_idx], - "Test State C exit failed"); - - if (o->terminate == EXIT) { - smf_set_terminate(obj, -1); - return; - } - - o->transition_bits |= STATE_C_EXIT_BIT; -} - -static void state_d_entry(void *obj) -{ - struct test_object *o = TEST_OBJECT(obj); - - o->tv_idx++; -} - -static void state_d_run(void *obj) -{ - /* Do nothing */ -} - -static void state_d_exit(void *obj) -{ - /* Do nothing */ -} - -static const struct smf_state test_states[] = { - [PARENT_AB] = SMF_CREATE_STATE(parent_ab_entry, parent_ab_run, - parent_ab_exit, NULL, &test_states[STATE_A]), - [PARENT_C] = SMF_CREATE_STATE(parent_c_entry, parent_c_run, - parent_c_exit, NULL, &test_states[STATE_C]), - [STATE_A] = SMF_CREATE_STATE(state_a_entry, state_a_run, state_a_exit, - &test_states[PARENT_AB], NULL), - [STATE_B] = SMF_CREATE_STATE(state_b_entry, state_b_run, state_b_exit, - &test_states[PARENT_AB], NULL), - [STATE_C] = SMF_CREATE_STATE(state_c_entry, state_c_run, state_c_exit, - &test_states[PARENT_C], NULL), - [STATE_D] = SMF_CREATE_STATE(state_d_entry, state_d_run, state_d_exit, - NULL, NULL), -}; - -ZTEST(smf_tests, test_smf_initial_transitions) -{ - /* A) Test state transitions */ - - test_obj.transition_bits = 0; - test_obj.first_time = 1; - test_obj.terminate = NONE; - smf_set_initial((struct smf_ctx *)&test_obj, &test_states[PARENT_AB]); - - for (int i = 0; i < SMF_RUN; i++) { - if (smf_run_state((struct smf_ctx *)&test_obj) < 0) { - break; - } - } - - zassert_equal(TEST_VALUE_NUM, test_obj.tv_idx, - "Incorrect test value index"); - zassert_equal(test_obj.transition_bits, test_value[test_obj.tv_idx], - "Final state not reached"); - - /* B) Test termination in parent entry action */ - - test_obj.transition_bits = 0; - test_obj.first_time = 1; - test_obj.terminate = PARENT_ENTRY; - smf_set_initial((struct smf_ctx *)&test_obj, &test_states[PARENT_AB]); - - for (int i = 0; i < SMF_RUN; i++) { - if (smf_run_state((struct smf_ctx *)&test_obj) < 0) { - break; - } - } - - zassert_equal(TEST_PARENT_ENTRY_VALUE_NUM, test_obj.tv_idx, - "Incorrect test value index for parent entry termination"); - zassert_equal(test_obj.transition_bits, test_value[test_obj.tv_idx], - "Final parent entry termination state not reached"); - - /* C) Test termination in parent run action */ - - test_obj.transition_bits = 0; - test_obj.first_time = 1; - test_obj.terminate = PARENT_RUN; - smf_set_initial((struct smf_ctx *)&test_obj, &test_states[PARENT_AB]); - - for (int i = 0; i < SMF_RUN; i++) { - if (smf_run_state((struct smf_ctx *)&test_obj) < 0) { - break; - } - } - - zassert_equal(TEST_PARENT_RUN_VALUE_NUM, test_obj.tv_idx, - "Incorrect test value index for parent run termination"); - zassert_equal(test_obj.transition_bits, test_value[test_obj.tv_idx], - "Final parent run termination state not reached"); - - /* D) Test termination in parent exit action */ - - test_obj.transition_bits = 0; - test_obj.first_time = 1; - test_obj.terminate = PARENT_EXIT; - smf_set_initial((struct smf_ctx *)&test_obj, &test_states[PARENT_AB]); - - for (int i = 0; i < SMF_RUN; i++) { - if (smf_run_state((struct smf_ctx *)&test_obj) < 0) { - break; - } - } - - zassert_equal(TEST_PARENT_EXIT_VALUE_NUM, test_obj.tv_idx, - "Incorrect test value index for parent exit termination"); - zassert_equal(test_obj.transition_bits, test_value[test_obj.tv_idx], - "Final parent exit termination state not reached"); - - /* E) Test termination in child entry action */ - - test_obj.transition_bits = 0; - test_obj.first_time = 1; - test_obj.terminate = ENTRY; - smf_set_initial((struct smf_ctx *)&test_obj, &test_states[PARENT_AB]); - - for (int i = 0; i < SMF_RUN; i++) { - if (smf_run_state((struct smf_ctx *)&test_obj) < 0) { - break; - } - } - - zassert_equal(TEST_ENTRY_VALUE_NUM, test_obj.tv_idx, - "Incorrect test value index for entry termination"); - zassert_equal(test_obj.transition_bits, test_value[test_obj.tv_idx], - "Final entry termination state not reached"); - - /* F) Test termination in child run action */ - - test_obj.transition_bits = 0; - test_obj.first_time = 1; - test_obj.terminate = RUN; - smf_set_initial((struct smf_ctx *)&test_obj, &test_states[PARENT_AB]); - - for (int i = 0; i < SMF_RUN; i++) { - if (smf_run_state((struct smf_ctx *)&test_obj) < 0) { - break; - } - } - - zassert_equal(TEST_RUN_VALUE_NUM, test_obj.tv_idx, - "Incorrect test value index for run termination"); - zassert_equal(test_obj.transition_bits, test_value[test_obj.tv_idx], - "Final run termination state not reached"); - - /* G) Test termination in child exit action */ - - test_obj.transition_bits = 0; - test_obj.first_time = 1; - test_obj.terminate = EXIT; - smf_set_initial((struct smf_ctx *)&test_obj, &test_states[PARENT_AB]); - - for (int i = 0; i < SMF_RUN; i++) { - if (smf_run_state((struct smf_ctx *)&test_obj) < 0) { - break; - } - } - - zassert_equal(TEST_EXIT_VALUE_NUM, test_obj.tv_idx, - "Incorrect test value index for exit termination"); - zassert_equal(test_obj.transition_bits, test_value[test_obj.tv_idx], - "Final exit termination state not reached"); -} diff --git a/tests/lib/smf/src/test_lib_self_transition_smf.c b/tests/lib/smf/src/test_lib_self_transition_smf.c new file mode 100644 index 00000000000..c78e6fa04a5 --- /dev/null +++ b/tests/lib/smf/src/test_lib_self_transition_smf.c @@ -0,0 +1,577 @@ +/* + * Copyright 2024 Glenn Andrews + * based on test_lib_hierarchical_smf.c + * Copyright 2021 The Chromium OS Authors + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/* + * Hierarchical Test Transition to self: + * + * This implements a hierarchical state machine using UML rules and demonstrates + * initial transitions, transitions to self (in PARENT_C) and smf_set_handled (in STATE_B) + * + * The order of entry, exit and run actions is given in the ordering of the test_value[] array. + */ + +#define TEST_OBJECT(o) ((struct test_object *)o) + +#define SMF_RUN 5 + +/* Initial Setup: Testing initial transitions */ +#define ROOT_ENTRY_BIT BIT(0) +#define PARENT_AB_ENTRY_BIT BIT(1) +#define STATE_A_ENTRY_BIT BIT(2) + +/* Run 0: normal state transition */ +#define STATE_A_RUN_BIT BIT(3) +#define STATE_A_EXIT_BIT BIT(4) +#define STATE_B_ENTRY_BIT BIT(5) + +/* Run 1: Test smf_set_handled() */ +#define STATE_B_1ST_RUN_BIT BIT(6) + +/* Run 2: Normal state transition via parent */ +#define STATE_B_2ND_RUN_BIT BIT(7) +#define PARENT_AB_RUN_BIT BIT(8) +#define STATE_B_EXIT_BIT BIT(9) +#define PARENT_AB_EXIT_BIT BIT(10) +#define PARENT_C_1ST_ENTRY_BIT BIT(11) +#define STATE_C_1ST_ENTRY_BIT BIT(12) + +/* Run 3: PARENT_C executes transition to self */ +#define STATE_C_1ST_RUN_BIT BIT(13) +#define PARENT_C_RUN_BIT BIT(14) +#define STATE_C_1ST_EXIT_BIT BIT(15) +#define PARENT_C_1ST_EXIT_BIT BIT(16) +#define PARENT_C_2ND_ENTRY_BIT BIT(17) +#define STATE_C_2ND_ENTRY_BIT BIT(18) + +/* Run 4: Test transition from parent state */ +#define STATE_C_2ND_RUN_BIT BIT(19) +#define STATE_C_2ND_EXIT_BIT BIT(20) +#define PARENT_C_2ND_EXIT_BIT BIT(21) + +/* Unused functions: Error checks if set */ +#define ROOT_RUN_BIT BIT(22) +#define ROOT_EXIT_BIT BIT(23) + +/* Number of state transitions for each test: */ +#define TEST_VALUE_NUM 22 +#define TEST_PARENT_ENTRY_VALUE_NUM 1 +#define TEST_PARENT_RUN_VALUE_NUM 8 +#define TEST_PARENT_EXIT_VALUE_NUM 10 +#define TEST_ENTRY_VALUE_NUM 2 +#define TEST_RUN_VALUE_NUM 6 +#define TEST_EXIT_VALUE_NUM 15 + +/* + * Note: Test values are taken before the appropriate test bit for that state is set i.e. if + * ROOT_ENTRY_BIT is BIT(0), test_value for root_entry() will be BIT_MASK(0) not BIT_MASK(1) + */ +static uint32_t test_value[] = { + /* Initial Setup */ + BIT_MASK(0), /* ROOT_ENTRY_BIT */ + BIT_MASK(1), /* PARENT_AB_ENTRY_BIT */ + BIT_MASK(2), /* STATE_A_ENTRY_BIT */ + /* Run 0 */ + BIT_MASK(3), /* STATE_A_RUN_BIT */ + BIT_MASK(4), /* STATE_A_EXIT_BIT */ + BIT_MASK(5), /* STATE_B_ENTRY_BIT */ + /* Run 1 */ + BIT_MASK(6), /* STATE_B_1ST_RUN_BIT */ + /* Run 2 */ + BIT_MASK(7), /* STATE_B_2ND_RUN_BIT */ + BIT_MASK(8), /* PARENT_AB_RUN_BIT */ + BIT_MASK(9), /* STATE_B_EXIT_BIT */ + BIT_MASK(10), /* PARENT_AB_EXIT_BIT */ + BIT_MASK(11), /* PARENT_C_1ST_ENTRY_BIT */ + BIT_MASK(12), /* STATE_C_1ST_ENTRY_BIT */ + /* Run 3 */ + BIT_MASK(13), /* STATE_C_1ST_RUN_BIT */ + BIT_MASK(14), /* PARENT_C_RUN_BIT */ + BIT_MASK(15), /* STATE_C_1ST_EXIT_BIT */ + BIT_MASK(16), /* PARENT_C_1ST_EXIT_BIT */ + BIT_MASK(17), /* PARENT_C_2ND_ENTRY_BIT */ + BIT_MASK(18), /* STATE_C_2ND_ENTRY_BIT */ + /* Run 4 */ + BIT_MASK(19), /* STATE_C_2ND_RUN_BIT */ + BIT_MASK(20), /* STATE_C_2ND_EXIT_BIT */ + BIT_MASK(21), /* PARENT_C_2ND_EXIT_BIT */ + /* Post-run Check */ + BIT_MASK(22), /* FINAL_VALUE */ +}; + +/* Forward declaration of test_states */ +static const struct smf_state test_states[]; + +/* List of all TypeC-level states */ +enum test_state { + ROOT, + PARENT_AB, + PARENT_C, + STATE_A, + STATE_B, + STATE_C, + STATE_D +}; + +enum terminate_action { + NONE, + PARENT_ENTRY, + PARENT_RUN, + PARENT_EXIT, + ENTRY, + RUN, + EXIT +}; + +#define B_ENTRY_FIRST_TIME BIT(0) +#define B_RUN_FIRST_TIME BIT(1) +#define PARENT_C_ENTRY_FIRST_TIME BIT(2) +#define C_RUN_FIRST_TIME BIT(3) +#define C_ENTRY_FIRST_TIME BIT(4) +#define C_EXIT_FIRST_TIME BIT(5) + +#define FIRST_TIME_BITS \ + (B_ENTRY_FIRST_TIME | B_RUN_FIRST_TIME | PARENT_C_ENTRY_FIRST_TIME | C_RUN_FIRST_TIME | \ + C_ENTRY_FIRST_TIME | C_EXIT_FIRST_TIME) + +static struct test_object { + struct smf_ctx ctx; + uint32_t transition_bits; + uint32_t tv_idx; + enum terminate_action terminate; + uint32_t first_time; +} test_obj; + +static void root_entry(void *obj) +{ + struct test_object *o = TEST_OBJECT(obj); + + o->tv_idx = 0; + + zassert_equal(o->transition_bits, test_value[o->tv_idx], "Test Root entry failed"); + + o->transition_bits |= ROOT_ENTRY_BIT; +} + +static void root_run(void *obj) +{ + struct test_object *o = TEST_OBJECT(obj); + + o->tv_idx++; + + zassert_equal(o->transition_bits, test_value[o->tv_idx], "Test Root run failed"); + + o->transition_bits |= ROOT_RUN_BIT; + + /* Return to parent run state */ +} + +static void root_exit(void *obj) +{ + struct test_object *o = TEST_OBJECT(obj); + + o->tv_idx++; + + zassert_equal(o->transition_bits, test_value[o->tv_idx], "Test Root exit failed"); + o->transition_bits |= ROOT_EXIT_BIT; +} + +static void parent_ab_entry(void *obj) +{ + struct test_object *o = TEST_OBJECT(obj); + + o->tv_idx++; + + zassert_equal(o->transition_bits, test_value[o->tv_idx], "Test Parent AB entry failed"); + + if (o->terminate == PARENT_ENTRY) { + smf_set_terminate(obj, -1); + return; + } + + o->transition_bits |= PARENT_AB_ENTRY_BIT; +} + +static void parent_ab_run(void *obj) +{ + struct test_object *o = TEST_OBJECT(obj); + + o->tv_idx++; + + zassert_equal(o->transition_bits, test_value[o->tv_idx], "Test Parent AB run failed"); + + if (o->terminate == PARENT_RUN) { + smf_set_terminate(obj, -1); + return; + } + + o->transition_bits |= PARENT_AB_RUN_BIT; + + smf_set_state(SMF_CTX(obj), &test_states[STATE_C]); +} + +static void parent_ab_exit(void *obj) +{ + struct test_object *o = TEST_OBJECT(obj); + + o->tv_idx++; + + zassert_equal(o->transition_bits, test_value[o->tv_idx], "Test Parent AB exit failed"); + + if (o->terminate == PARENT_EXIT) { + smf_set_terminate(obj, -1); + return; + } + + o->transition_bits |= PARENT_AB_EXIT_BIT; +} + +static void parent_c_entry(void *obj) +{ + struct test_object *o = TEST_OBJECT(obj); + + o->tv_idx++; + + zassert_equal(o->transition_bits, test_value[o->tv_idx], "Test Parent C entry failed"); + if (o->first_time & PARENT_C_ENTRY_FIRST_TIME) { + o->first_time &= ~PARENT_C_ENTRY_FIRST_TIME; + o->transition_bits |= PARENT_C_1ST_ENTRY_BIT; + } else { + o->transition_bits |= PARENT_C_2ND_ENTRY_BIT; + } +} + +static void parent_c_run(void *obj) +{ + struct test_object *o = TEST_OBJECT(obj); + + o->tv_idx++; + + zassert_equal(o->transition_bits, test_value[o->tv_idx], "Test Parent C run failed"); + + o->transition_bits |= PARENT_C_RUN_BIT; + + smf_set_state(SMF_CTX(obj), &test_states[PARENT_C]); +} + +static void parent_c_exit(void *obj) +{ + struct test_object *o = TEST_OBJECT(obj); + + o->tv_idx++; + + zassert_equal(o->transition_bits, test_value[o->tv_idx], "Test Parent C exit failed"); + + if (o->first_time & B_ENTRY_FIRST_TIME) { + o->first_time &= ~B_ENTRY_FIRST_TIME; + o->transition_bits |= PARENT_C_1ST_EXIT_BIT; + } else { + o->transition_bits |= PARENT_C_2ND_EXIT_BIT; + } +} + +static void state_a_entry(void *obj) +{ + struct test_object *o = TEST_OBJECT(obj); + + o->tv_idx++; + + zassert_equal(o->transition_bits, test_value[o->tv_idx], "Test State A entry failed"); + + if (o->terminate == ENTRY) { + smf_set_terminate(obj, -1); + return; + } + + o->transition_bits |= STATE_A_ENTRY_BIT; +} + +static void state_a_run(void *obj) +{ + struct test_object *o = TEST_OBJECT(obj); + + o->tv_idx++; + + zassert_equal(o->transition_bits, test_value[o->tv_idx], "Test State A run failed"); + + o->transition_bits |= STATE_A_RUN_BIT; + + smf_set_state(SMF_CTX(obj), &test_states[STATE_B]); +} + +static void state_a_exit(void *obj) +{ + struct test_object *o = TEST_OBJECT(obj); + + o->tv_idx++; + + zassert_equal(o->transition_bits, test_value[o->tv_idx], "Test State A exit failed"); + o->transition_bits |= STATE_A_EXIT_BIT; +} + +static void state_b_entry(void *obj) +{ + struct test_object *o = TEST_OBJECT(obj); + + o->tv_idx++; + + zassert_equal(o->transition_bits, test_value[o->tv_idx], "Test State B entry failed"); + + o->transition_bits |= STATE_B_ENTRY_BIT; +} + +static void state_b_run(void *obj) +{ + struct test_object *o = TEST_OBJECT(obj); + + o->tv_idx++; + + zassert_equal(o->transition_bits, test_value[o->tv_idx], "Test State B run failed"); + + if (o->terminate == RUN) { + smf_set_terminate(obj, -1); + return; + } + + if (o->first_time & B_RUN_FIRST_TIME) { + o->first_time &= ~B_RUN_FIRST_TIME; + o->transition_bits |= STATE_B_1ST_RUN_BIT; + smf_set_handled(SMF_CTX(obj)); + } else { + o->transition_bits |= STATE_B_2ND_RUN_BIT; + /* bubble up to PARENT_AB */ + } +} + +static void state_b_exit(void *obj) +{ + struct test_object *o = TEST_OBJECT(obj); + + o->tv_idx++; + + zassert_equal(o->transition_bits, test_value[o->tv_idx], "Test State B exit failed"); + + o->transition_bits |= STATE_B_EXIT_BIT; +} + +static void state_c_entry(void *obj) +{ + struct test_object *o = TEST_OBJECT(obj); + + o->tv_idx++; + + zassert_equal(o->transition_bits, test_value[o->tv_idx], "Test State C entry failed"); + if (o->first_time & C_ENTRY_FIRST_TIME) { + o->first_time &= ~C_ENTRY_FIRST_TIME; + o->transition_bits |= STATE_C_1ST_ENTRY_BIT; + } else { + o->transition_bits |= STATE_C_2ND_ENTRY_BIT; + } +} + +static void state_c_run(void *obj) +{ + struct test_object *o = TEST_OBJECT(obj); + + o->tv_idx++; + + zassert_equal(o->transition_bits, test_value[o->tv_idx], "Test State C run failed"); + + if (o->first_time & C_RUN_FIRST_TIME) { + o->first_time &= ~C_RUN_FIRST_TIME; + o->transition_bits |= STATE_C_1ST_RUN_BIT; + /* Do nothing, Let parent handle it */ + } else { + o->transition_bits |= STATE_C_2ND_RUN_BIT; + smf_set_state(SMF_CTX(obj), &test_states[STATE_D]); + } +} + +static void state_c_exit(void *obj) +{ + struct test_object *o = TEST_OBJECT(obj); + + o->tv_idx++; + + zassert_equal(o->transition_bits, test_value[o->tv_idx], "Test State C exit failed"); + + if (o->terminate == EXIT) { + smf_set_terminate(obj, -1); + return; + } + + if (o->first_time & C_EXIT_FIRST_TIME) { + o->first_time &= ~C_EXIT_FIRST_TIME; + o->transition_bits |= STATE_C_1ST_EXIT_BIT; + } else { + o->transition_bits |= STATE_C_2ND_EXIT_BIT; + } +} + +static void state_d_entry(void *obj) +{ + struct test_object *o = TEST_OBJECT(obj); + + o->tv_idx++; +} + +static void state_d_run(void *obj) +{ + /* Do nothing */ +} + +static void state_d_exit(void *obj) +{ + /* Do nothing */ +} + +static const struct smf_state test_states[] = { + [ROOT] = SMF_CREATE_STATE(root_entry, root_run, root_exit, NULL, &test_states[PARENT_AB]), + [PARENT_AB] = SMF_CREATE_STATE(parent_ab_entry, parent_ab_run, parent_ab_exit, + &test_states[ROOT], &test_states[STATE_A]), + [PARENT_C] = SMF_CREATE_STATE(parent_c_entry, parent_c_run, parent_c_exit, + &test_states[ROOT], &test_states[STATE_C]), + [STATE_A] = SMF_CREATE_STATE(state_a_entry, state_a_run, state_a_exit, + &test_states[PARENT_AB], NULL), + [STATE_B] = SMF_CREATE_STATE(state_b_entry, state_b_run, state_b_exit, + &test_states[PARENT_AB], NULL), + [STATE_C] = SMF_CREATE_STATE(state_c_entry, state_c_run, state_c_exit, + &test_states[PARENT_C], NULL), + [STATE_D] = SMF_CREATE_STATE(state_d_entry, state_d_run, state_d_exit, &test_states[ROOT], + NULL), +}; + +ZTEST(smf_tests, test_smf_self_transition) +{ + /* A) Test state transitions */ + + test_obj.transition_bits = 0; + test_obj.first_time = FIRST_TIME_BITS; + test_obj.terminate = NONE; + smf_set_initial((struct smf_ctx *)&test_obj, &test_states[PARENT_AB]); + + for (int i = 0; i < SMF_RUN; i++) { + if (smf_run_state((struct smf_ctx *)&test_obj) < 0) { + break; + } + } + + zassert_equal(TEST_VALUE_NUM, test_obj.tv_idx, "Incorrect test value index"); + zassert_equal(test_obj.transition_bits, test_value[test_obj.tv_idx], + "Final state not reached"); + + /* B) Test termination in parent entry action */ + + test_obj.transition_bits = 0; + test_obj.first_time = FIRST_TIME_BITS; + test_obj.terminate = PARENT_ENTRY; + smf_set_initial((struct smf_ctx *)&test_obj, &test_states[PARENT_AB]); + + for (int i = 0; i < SMF_RUN; i++) { + if (smf_run_state((struct smf_ctx *)&test_obj) < 0) { + break; + } + } + + zassert_equal(TEST_PARENT_ENTRY_VALUE_NUM, test_obj.tv_idx, + "Incorrect test value index for parent entry termination"); + zassert_equal(test_obj.transition_bits, test_value[test_obj.tv_idx], + "Final parent entry termination state not reached"); + + /* C) Test termination in parent run action */ + + test_obj.transition_bits = 0; + test_obj.first_time = FIRST_TIME_BITS; + test_obj.terminate = PARENT_RUN; + smf_set_initial((struct smf_ctx *)&test_obj, &test_states[PARENT_AB]); + + for (int i = 0; i < SMF_RUN; i++) { + if (smf_run_state((struct smf_ctx *)&test_obj) < 0) { + break; + } + } + + zassert_equal(TEST_PARENT_RUN_VALUE_NUM, test_obj.tv_idx, + "Incorrect test value index for parent run termination"); + zassert_equal(test_obj.transition_bits, test_value[test_obj.tv_idx], + "Final parent run termination state not reached"); + + /* D) Test termination in parent exit action */ + + test_obj.transition_bits = 0; + test_obj.first_time = FIRST_TIME_BITS; + test_obj.terminate = PARENT_EXIT; + smf_set_initial((struct smf_ctx *)&test_obj, &test_states[PARENT_AB]); + + for (int i = 0; i < SMF_RUN; i++) { + if (smf_run_state((struct smf_ctx *)&test_obj) < 0) { + break; + } + } + + zassert_equal(TEST_PARENT_EXIT_VALUE_NUM, test_obj.tv_idx, + "Incorrect test value index for parent exit termination"); + zassert_equal(test_obj.transition_bits, test_value[test_obj.tv_idx], + "Final parent exit termination state not reached"); + + /* E) Test termination in child entry action */ + + test_obj.transition_bits = 0; + test_obj.first_time = FIRST_TIME_BITS; + test_obj.terminate = ENTRY; + smf_set_initial((struct smf_ctx *)&test_obj, &test_states[PARENT_AB]); + + for (int i = 0; i < SMF_RUN; i++) { + if (smf_run_state((struct smf_ctx *)&test_obj) < 0) { + break; + } + } + + zassert_equal(TEST_ENTRY_VALUE_NUM, test_obj.tv_idx, + "Incorrect test value index for entry termination"); + zassert_equal(test_obj.transition_bits, test_value[test_obj.tv_idx], + "Final entry termination state not reached"); + + /* F) Test termination in child run action */ + + test_obj.transition_bits = 0; + test_obj.first_time = FIRST_TIME_BITS; + test_obj.terminate = RUN; + smf_set_initial((struct smf_ctx *)&test_obj, &test_states[PARENT_AB]); + + for (int i = 0; i < SMF_RUN; i++) { + if (smf_run_state((struct smf_ctx *)&test_obj) < 0) { + break; + } + } + + zassert_equal(TEST_RUN_VALUE_NUM, test_obj.tv_idx, + "Incorrect test value index for run termination"); + zassert_equal(test_obj.transition_bits, test_value[test_obj.tv_idx], + "Final run termination state not reached"); + + /* G) Test termination in child exit action */ + + test_obj.transition_bits = 0; + test_obj.first_time = FIRST_TIME_BITS; + test_obj.terminate = EXIT; + smf_set_initial((struct smf_ctx *)&test_obj, &test_states[PARENT_AB]); + + for (int i = 0; i < SMF_RUN; i++) { + if (smf_run_state((struct smf_ctx *)&test_obj) < 0) { + break; + } + } + + zassert_equal(TEST_EXIT_VALUE_NUM, test_obj.tv_idx, + "Incorrect test value index for exit termination"); + zassert_equal(test_obj.transition_bits, test_value[test_obj.tv_idx], + "Final exit termination state not reached"); +} diff --git a/tests/lib/smf/src/test_lib_smf.h b/tests/lib/smf/src/test_lib_smf.h index 6296352fb73..032dec06f79 100644 --- a/tests/lib/smf/src/test_lib_smf.h +++ b/tests/lib/smf/src/test_lib_smf.h @@ -10,6 +10,6 @@ void test_smf_flat(void); void test_smf_hierarchical(void); void test_smf_hierarchical_5_ancestors(void); -void test_smf_initial_transitions(void); +void test_smf_self_transition(void); #endif /* ZEPHYR_TEST_LIB_SMF_H_ */ diff --git a/tests/lib/sys_util/src/main.c b/tests/lib/sys_util/src/main.c index 9e1f7b5fa8c..02e6465e447 100644 --- a/tests/lib/sys_util/src/main.c +++ b/tests/lib/sys_util/src/main.c @@ -37,6 +37,36 @@ ZTEST(sys_util, test_wait_for) end = k_cycle_get_32(); zassert_true(end-start >= expected, "wait for 1ms"); } + +/** + * @brief Test NUM_VA_ARGS works as expected with typical use cases + * + * @see NUM_VA_ARGS() + */ + +ZTEST(sys_util, test_NUM_VA_ARGS) +{ + zassert_equal(0, NUM_VA_ARGS()); + zassert_equal(1, NUM_VA_ARGS(_1)); + zassert_equal(2, NUM_VA_ARGS(_1, _2)); + /* support up to 63 args */ + zassert_equal(63, NUM_VA_ARGS(LISTIFY(63, ~, (,)))); +} + +/** + * @brief Test NUM_VA_ARGS_LESS_1 works as expected with typical use cases + * + * @see NUM_VA_ARGS_LESS_1() + */ + +ZTEST(sys_util, test_NUM_VA_ARGS_LESS_1) +{ + zassert_equal(0, NUM_VA_ARGS_LESS_1()); + zassert_equal(0, NUM_VA_ARGS_LESS_1(_1)); + zassert_equal(1, NUM_VA_ARGS_LESS_1(_1, _2)); + /* support up to 64 args */ + zassert_equal(63, NUM_VA_ARGS_LESS_1(LISTIFY(64, ~, (,)))); +} /** * @} */ diff --git a/tests/misc/check_init_priorities/boards/native_posix_native_64.overlay b/tests/misc/check_init_priorities/boards/native_posix_native_64.overlay new file mode 100644 index 00000000000..1cf720283b3 --- /dev/null +++ b/tests/misc/check_init_priorities/boards/native_posix_native_64.overlay @@ -0,0 +1,7 @@ +/* + * Copyright 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "native_sim.overlay" diff --git a/tests/misc/check_init_priorities/boards/native_sim_native_64.overlay b/tests/misc/check_init_priorities/boards/native_sim_native_64.overlay new file mode 100644 index 00000000000..1cf720283b3 --- /dev/null +++ b/tests/misc/check_init_priorities/boards/native_sim_native_64.overlay @@ -0,0 +1,7 @@ +/* + * Copyright 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "native_sim.overlay" diff --git a/tests/misc/iterable_sections/CMakeLists.txt b/tests/misc/iterable_sections/CMakeLists.txt index 1a187eace6d..350c2a5ca0e 100644 --- a/tests/misc/iterable_sections/CMakeLists.txt +++ b/tests/misc/iterable_sections/CMakeLists.txt @@ -8,15 +8,15 @@ FILE(GLOB app_sources src/*.c) target_sources(app PRIVATE ${app_sources}) zephyr_linker_sources(DATA_SECTIONS sections-ram.ld) -zephyr_iterable_section(NAME test_ram GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) -zephyr_iterable_section(NAME test_ram2 GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) -zephyr_iterable_section(NAME test_ram_named GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) -zephyr_iterable_section(NAME test_ram_numeric NUMERIC GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) -zephyr_iterable_section(NAME ramn_alt GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) +zephyr_iterable_section(NAME test_ram GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) +zephyr_iterable_section(NAME test_ram2 GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) +zephyr_iterable_section(NAME test_ram_named GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) +zephyr_iterable_section(NAME test_ram_numeric NUMERIC GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) +zephyr_iterable_section(NAME ramn_alt GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) zephyr_linker_sources(SECTIONS sections-rom.ld) -zephyr_iterable_section(NAME test_rom KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) -zephyr_iterable_section(NAME test_rom2 KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) -zephyr_iterable_section(NAME test_rom_named KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) -zephyr_iterable_section(NAME test_rom_numeric NUMERIC KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) -zephyr_iterable_section(NAME romn_alt KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) +zephyr_iterable_section(NAME test_rom KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) +zephyr_iterable_section(NAME test_rom2 KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) +zephyr_iterable_section(NAME test_rom_named KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) +zephyr_iterable_section(NAME test_rom_numeric NUMERIC KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) +zephyr_iterable_section(NAME romn_alt KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) diff --git a/tests/misc/iterable_sections/sections-ram.ld b/tests/misc/iterable_sections/sections-ram.ld index 96454fb282d..cf7773b5861 100644 --- a/tests/misc/iterable_sections/sections-ram.ld +++ b/tests/misc/iterable_sections/sections-ram.ld @@ -1,7 +1,7 @@ #include -ITERABLE_SECTION_RAM(test_ram, 4) -ITERABLE_SECTION_RAM(test_ram2, 4) -ITERABLE_SECTION_RAM(test_ram_named, 4) -ITERABLE_SECTION_RAM_NUMERIC(test_ram_numeric, 4) -ITERABLE_SECTION_RAM(ramn_alt, 4) +ITERABLE_SECTION_RAM(test_ram, Z_LINK_ITERABLE_SUBALIGN) +ITERABLE_SECTION_RAM(test_ram2, Z_LINK_ITERABLE_SUBALIGN) +ITERABLE_SECTION_RAM(test_ram_named, Z_LINK_ITERABLE_SUBALIGN) +ITERABLE_SECTION_RAM_NUMERIC(test_ram_numeric, Z_LINK_ITERABLE_SUBALIGN) +ITERABLE_SECTION_RAM(ramn_alt, Z_LINK_ITERABLE_SUBALIGN) diff --git a/tests/misc/iterable_sections/sections-rom.ld b/tests/misc/iterable_sections/sections-rom.ld index 525c480c7bf..b821decdb23 100644 --- a/tests/misc/iterable_sections/sections-rom.ld +++ b/tests/misc/iterable_sections/sections-rom.ld @@ -1,7 +1,7 @@ #include -ITERABLE_SECTION_ROM(test_rom, 4) -ITERABLE_SECTION_ROM(test_rom2, 4) -ITERABLE_SECTION_ROM(test_rom_named, 4) -ITERABLE_SECTION_ROM_NUMERIC(test_rom_numeric, 4) -ITERABLE_SECTION_ROM(romn_alt, 4) +ITERABLE_SECTION_ROM(test_rom, Z_LINK_ITERABLE_SUBALIGN) +ITERABLE_SECTION_ROM(test_rom2, Z_LINK_ITERABLE_SUBALIGN) +ITERABLE_SECTION_ROM(test_rom_named, Z_LINK_ITERABLE_SUBALIGN) +ITERABLE_SECTION_ROM_NUMERIC(test_rom_numeric, Z_LINK_ITERABLE_SUBALIGN) +ITERABLE_SECTION_ROM(romn_alt, Z_LINK_ITERABLE_SUBALIGN) diff --git a/tests/misc/iterable_sections/src/main.c b/tests/misc/iterable_sections/src/main.c index a2dde51bd23..1feed8319b2 100644 --- a/tests/misc/iterable_sections/src/main.c +++ b/tests/misc/iterable_sections/src/main.c @@ -8,15 +8,15 @@ #include struct test_ram { - int i; + long i; }; struct test_ram_named { - int i; + long i; }; struct test_ram_numeric { - int i; + long i; }; #define CHECK_BIT 0x80 @@ -105,15 +105,15 @@ ZTEST(iterable_sections, test_ram) } struct test_rom { - int i; + long i; }; struct test_rom_named { - int i; + long i; }; struct test_rom_numeric { - int i; + long i; }; /* declare in random order to check that the linker is sorting by name */ diff --git a/tests/misc/iterable_sections/testcase.yaml b/tests/misc/iterable_sections/testcase.yaml index eeba6274530..f193cdb6c54 100644 --- a/tests/misc/iterable_sections/testcase.yaml +++ b/tests/misc/iterable_sections/testcase.yaml @@ -1,4 +1,12 @@ +common: + tags: iterable_sections + tests: linker.iterable_sections: - tags: iterable_sections arch_exclude: xtensa + + linker.iterable_sections.linker_generator: + platform_allow: qemu_cortex_m3 + tags: linker_generator + extra_configs: + - CONFIG_CMAKE_LINKER_GENERATOR=y diff --git a/tests/misc/llext-edk/CMakeLists.txt b/tests/misc/llext-edk/CMakeLists.txt new file mode 100644 index 00000000000..4fee915a57f --- /dev/null +++ b/tests/misc/llext-edk/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(llext_edk_test LANGUAGES C) + +target_sources(app PRIVATE src/main.c) +zephyr_include_directories(include) +zephyr_include_directories($ENV{ZEPHYR_BASE}/boards/native/common) diff --git a/tests/misc/llext-edk/extension/CMakeLists.txt b/tests/misc/llext-edk/extension/CMakeLists.txt new file mode 100644 index 00000000000..1b1a9142ee4 --- /dev/null +++ b/tests/misc/llext-edk/extension/CMakeLists.txt @@ -0,0 +1,23 @@ +cmake_minimum_required(VERSION 3.20.0) + +project(extension) + +include($ENV{LLEXT_EDK_INSTALL_DIR}/cmake.cflags) + +# Add LLEXT_CFLAGS to our flags +add_compile_options(${LLEXT_CFLAGS}) +add_compile_options("-Werror") +add_compile_options("-c") + +# Get flags from COMPILE_OPTIONS +get_property(COMPILE_OPTIONS_PROP DIRECTORY PROPERTY COMPILE_OPTIONS) + +add_custom_command( + OUTPUT + ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.llext + COMMAND ${CMAKE_C_COMPILER} ${COMPILE_OPTIONS_PROP} + -o ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.llext + ${PROJECT_SOURCE_DIR}/src/main.c +) + +add_custom_target(extension ALL DEPENDS ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.llext) diff --git a/tests/misc/llext-edk/extension/src/main.c b/tests/misc/llext-edk/extension/src/main.c new file mode 100644 index 00000000000..c4843bee333 --- /dev/null +++ b/tests/misc/llext-edk/extension/src/main.c @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2024 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include + +int start(void) +{ + int bar = 42; + + printk("foo(%d) is %d\n", bar, foo(bar)); + return 0; +} diff --git a/tests/misc/llext-edk/include/app_api.h b/tests/misc/llext-edk/include/app_api.h new file mode 100644 index 00000000000..5270bca6873 --- /dev/null +++ b/tests/misc/llext-edk/include/app_api.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2024 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _TEST_EDK_H_ +#define _TEST_EDK_H_ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +__syscall int foo(int bar); + +#ifdef __cplusplus +} +#endif + +#include +#endif /* _TEST_EDK_H_ */ diff --git a/tests/misc/llext-edk/prj.conf b/tests/misc/llext-edk/prj.conf new file mode 100644 index 00000000000..a479f3a569c --- /dev/null +++ b/tests/misc/llext-edk/prj.conf @@ -0,0 +1,3 @@ +CONFIG_APPLICATION_DEFINED_SYSCALL=y +#CONFIG_USERSPACE=y +CONFIG_LLEXT=y diff --git a/tests/misc/llext-edk/pytest/test_edk.py b/tests/misc/llext-edk/pytest/test_edk.py new file mode 100644 index 00000000000..d85a138d48b --- /dev/null +++ b/tests/misc/llext-edk/pytest/test_edk.py @@ -0,0 +1,66 @@ +# Copyright (c) 2024 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +import logging +import os +import shutil +import tempfile + +from pathlib import Path +from subprocess import check_output +from twister_harness import DeviceAdapter + +logger = logging.getLogger(__name__) + +def test_edk(dut: DeviceAdapter): + # Can we build the edk? + command = [ + "west", + "build", + "-t", + "llext-edk", + "--build-dir", + dut.device_config.build_dir, + ] + output = check_output(command, text=True) + logger.info(output) + + # Install the edk to a temporary location + with tempfile.TemporaryDirectory() as tempdir: + # Copy the edk to the temporary directory using python methods + logger.debug(f"Copying llext-edk.tar.xz to {tempdir}") + edk_path = Path(dut.device_config.build_dir) / "zephyr/llext-edk.tar.xz" + shutil.copy(edk_path, tempdir) + + # Extract the edk using tar + logger.debug(f"Extracting llext-edk.tar.xz to {tempdir}") + command = ["tar", "-xf", "llext-edk.tar.xz"] + output = check_output(command, text=True, cwd=tempdir) + logger.info(output) + + # Copy the extension to another temporary directory to test out of tree builds + with tempfile.TemporaryDirectory() as tempdir_extension: + logger.debug(f"Copying extension to {tempdir_extension}") + ext_dir = Path(os.environ["ZEPHYR_BASE"]) / "tests/misc/llext-edk/extension" + shutil.copytree(ext_dir, tempdir_extension, dirs_exist_ok=True) + + # Set the LLEXT_EDK_INSTALL_DIR environment variable so that the extension + # knows where the EDK is installed + edk_dir = Path(tempdir) / "llext-edk" + env = os.environ.copy() + env.update({"LLEXT_EDK_INSTALL_DIR": edk_dir}) + + # Build the extension using the edk + logger.debug(f"Building extension in {tempdir_extension} - cmake") + command = ["cmake", "-B", "build"] + output = check_output(command, text=True, cwd=tempdir_extension, env=env) + logger.info(output) + + logger.debug(f"Building extension in {tempdir_extension} - make") + command = ["make", "-C", "build"] + output = check_output(command, text=True, cwd=tempdir_extension, env=env) + logger.info(output) + + # Check if the extension was built + assert os.path.exists(Path(tempdir_extension) / "build/extension.llext") diff --git a/tests/misc/llext-edk/src/foo.c b/tests/misc/llext-edk/src/foo.c new file mode 100644 index 00000000000..190dac2bea6 --- /dev/null +++ b/tests/misc/llext-edk/src/foo.c @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2024 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +int z_impl_foo(int bar) +{ + return bar * bar; +} +EXPORT_SYMBOL(z_impl_foo); + +#ifdef CONFIG_USERSPACE +static inline int z_vrfy_foo(int bar) +{ + /* Nothing to verify */ + return z_impl_foo(bar); +} +#include +#endif diff --git a/tests/misc/llext-edk/src/main.c b/tests/misc/llext-edk/src/main.c new file mode 100644 index 00000000000..a5e7ab2e198 --- /dev/null +++ b/tests/misc/llext-edk/src/main.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2024 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include + +int main(void) +{ + return 0; +} diff --git a/tests/misc/llext-edk/testcase.yaml b/tests/misc/llext-edk/testcase.yaml new file mode 100644 index 00000000000..81f7ce0bd56 --- /dev/null +++ b/tests/misc/llext-edk/testcase.yaml @@ -0,0 +1,9 @@ +tests: + misc.edk.pytest: + harness: pytest + tags: + - pytest + - edk + platform_allow: + - native_sim + toolchain_exclude: llvm diff --git a/tests/net/all/prj.conf b/tests/net/all/prj.conf index 90f0d6cfcd5..90d38919cda 100644 --- a/tests/net/all/prj.conf +++ b/tests/net/all/prj.conf @@ -93,26 +93,13 @@ CONFIG_NET_L2_ETHERNET=y CONFIG_NET_L2_CANBUS_RAW=y CONFIG_NET_L2_ETHERNET_MGMT=y CONFIG_NET_L2_IEEE802154_RADIO_DFLT_TX_POWER=2 -CONFIG_NET_L2_BT=y -CONFIG_NET_L2_BT_ZEP1656=y -CONFIG_NET_L2_BT_SEC_LEVEL=4 -CONFIG_NET_L2_BT_MGMT=y -CONFIG_NET_L2_BT_SHELL=y CONFIG_NET_L2_IEEE802154_LOG_LEVEL_DBG=y CONFIG_NET_L2_ETHERNET_LOG_LEVEL_DBG=y -CONFIG_NET_L2_BT_LOG_LEVEL_DBG=y CONFIG_NET_L2_WIFI_MGMT_LOG_LEVEL_DBG=y CONFIG_NET_L2_WIFI_MGMT=y CONFIG_NET_L2_WIFI_SHELL=y CONFIG_NET_L2_PTP=y -# Bluetooth IPSP -CONFIG_BT=y -CONFIG_BT_PERIPHERAL=y -CONFIG_BT_CENTRAL=y -CONFIG_BT_SMP=y -CONFIG_BT_L2CAP_DYNAMIC_CHANNEL=y - # IP offload support CONFIG_NET_OFFLOAD=y CONFIG_NET_OFFLOAD_LOG_LEVEL_DBG=y @@ -171,6 +158,11 @@ CONFIG_NET_IPV6_ND_LOG_LEVEL_DBG=y CONFIG_NET_IPV6_NBR_CACHE_LOG_LEVEL_DBG=y CONFIG_NET_ICMPV6_LOG_LEVEL_DBG=y +# IPv6 privacy extension +CONFIG_NET_IPV6_PE=y +CONFIG_NET_IPV6_PE_PREFER_PUBLIC_ADDRESSES=n +CONFIG_NET_IPV6_PE_FILTER_PREFIX_COUNT=2 + # 6lo CONFIG_NET_6LO=y CONFIG_NET_6LO_CONTEXT=y @@ -188,7 +180,6 @@ CONFIG_NET_CONFIG_IEEE802154_CHANNEL=15 CONFIG_NET_CONFIG_IEEE802154_SECURITY_KEY="key" CONFIG_NET_CONFIG_IEEE802154_SECURITY_KEY_MODE=0 CONFIG_NET_CONFIG_IEEE802154_SECURITY_LEVEL=0 -CONFIG_NET_CONFIG_BT_NODE=y CONFIG_NET_CONFIG_AUTO_INIT=y CONFIG_NET_CONFIG_IEEE802154_RADIO_TX_POWER=10 CONFIG_NET_CONFIG_INIT_PRIO=90 @@ -230,6 +221,7 @@ CONFIG_NET_ARP=y CONFIG_NET_ARP_TABLE_SIZE=3 CONFIG_NET_ARP_LOG_LEVEL_DBG=y CONFIG_NET_ARP_GRATUITOUS=y +CONFIG_NET_ARP_GRATUITOUS_TRANSMISSION=y # Logging CONFIG_NET_LOG=y @@ -368,7 +360,6 @@ CONFIG_NET_SOCKETS_TLS_MAX_CONTEXTS=10 CONFIG_NET_SOCKETS_TLS_MAX_CREDENTIALS=10 # Network interface defaults -CONFIG_NET_DEFAULT_IF_BLUETOOTH=y CONFIG_NET_DEFAULT_IF_CANBUS_RAW=y CONFIG_NET_DEFAULT_IF_DUMMY=y CONFIG_NET_DEFAULT_IF_ETHERNET=y @@ -572,11 +563,6 @@ CONFIG_SHELL_MQTT_INIT_LOG_LEVEL_ERR=y #CONFIG_NET_IPV6_NBR_CACHE_LOG_LEVEL_INF #CONFIG_NET_IPV6_NBR_CACHE_LOG_LEVEL_OFF #CONFIG_NET_IPV6_NBR_CACHE_LOG_LEVEL_WRN -#CONFIG_NET_L2_BT_LOG_LEVEL_DEFAULT -#CONFIG_NET_L2_BT_LOG_LEVEL_ERR -#CONFIG_NET_L2_BT_LOG_LEVEL_INF -#CONFIG_NET_L2_BT_LOG_LEVEL_OFF -#CONFIG_NET_L2_BT_LOG_LEVEL_WRN #CONFIG_NET_L2_ETHERNET_LOG_LEVEL_DEFAULT #CONFIG_NET_L2_ETHERNET_LOG_LEVEL_ERR #CONFIG_NET_L2_ETHERNET_LOG_LEVEL_INF diff --git a/tests/net/dhcpv4/client/testcase.yaml b/tests/net/dhcpv4/client/testcase.yaml index 512d4dc159b..68d6c54271b 100644 --- a/tests/net/dhcpv4/client/testcase.yaml +++ b/tests/net/dhcpv4/client/testcase.yaml @@ -3,6 +3,9 @@ common: tags: - net - dhcpv4 + platform_exclude: + - native_posix/native/64 + - native_posix tests: net.dhcpv4_client: extra_configs: diff --git a/tests/net/dhcpv6/src/main.c b/tests/net/dhcpv6/src/main.c index ace0a0128c2..c5046a2746a 100644 --- a/tests/net/dhcpv6/src/main.c +++ b/tests/net/dhcpv6/src/main.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "../../../subsys/net/lib/dhcpv6/dhcpv6.c" @@ -18,6 +19,7 @@ static struct in6_addr test_prefix = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, static uint8_t test_prefix_len = 64; static uint8_t test_preference; static struct net_dhcpv6_duid_storage test_serverid; +static struct net_mgmt_event_callback net_mgmt_cb; typedef void (*test_dhcpv6_pkt_fn_t)(struct net_if *iface, struct net_pkt *pkt); @@ -176,6 +178,19 @@ static struct net_pkt *test_dhcpv6_create_message( return NULL; } +static void evt_handler(struct net_mgmt_event_callback *cb, uint32_t mgmt_event, + struct net_if *iface) +{ + ARG_UNUSED(cb); + + if (mgmt_event == NET_EVENT_IF_UP) { + struct in6_addr lladdr; + + net_ipv6_addr_create_iid(&lladdr, net_if_get_link_addr(test_ctx.iface)); + (void)net_if_ipv6_addr_add(test_ctx.iface, &lladdr, NET_ADDR_AUTOCONF, 0); + } +} + static void *dhcpv6_tests_setup(void) { struct in6_addr lladdr; @@ -190,6 +205,9 @@ static void *dhcpv6_tests_setup(void) generate_fake_server_duid(); + net_mgmt_init_event_callback(&net_mgmt_cb, evt_handler, NET_EVENT_IF_UP); + net_mgmt_add_event_callback(&net_mgmt_cb); + return NULL; } diff --git a/tests/net/ipv6/prj.conf b/tests/net/ipv6/prj.conf index c2f80f6ead4..b2b2f088673 100644 --- a/tests/net/ipv6/prj.conf +++ b/tests/net/ipv6/prj.conf @@ -17,6 +17,7 @@ CONFIG_ENTROPY_GENERATOR=y CONFIG_TEST_RANDOM_GENERATOR=y CONFIG_NET_IPV6_ND=y CONFIG_NET_IPV6_DAD=y +CONFIG_DNS_RESOLVER=y # To verify NET_IPV6_RA_RDNSS CONFIG_NET_PKT_TX_COUNT=20 CONFIG_NET_PKT_RX_COUNT=20 CONFIG_NET_BUF_RX_COUNT=20 @@ -28,3 +29,10 @@ CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=9 CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=7 CONFIG_NET_IF_IPV6_PREFIX_COUNT=3 CONFIG_NET_UDP_CHECKSUM=n +CONFIG_NET_IF_MAX_IPV6_COUNT=2 +CONFIG_NET_IPV6_PE=y +CONFIG_NET_IPV6_PE_FILTER_PREFIX_COUNT=2 +CONFIG_NET_IPV6_PE_PREFER_PUBLIC_ADDRESSES=n + +# Increase the stack a bit for mps2/an385 +CONFIG_NET_RX_STACK_SIZE=1700 diff --git a/tests/net/ipv6/src/main.c b/tests/net/ipv6/src/main.c index 06939fb47d5..02df9ac650c 100644 --- a/tests/net/ipv6/src/main.c +++ b/tests/net/ipv6/src/main.c @@ -36,14 +36,35 @@ LOG_MODULE_REGISTER(net_test, CONFIG_NET_IPV6_LOG_LEVEL); #define NET_LOG_ENABLED 1 #include "net_private.h" +#if defined(CONFIG_NET_IPV6_PE) +#define NET_IPV6_PE_FILTER_PREFIX_COUNT CONFIG_NET_IPV6_PE_FILTER_PREFIX_COUNT +#else +#define NET_IPV6_PE_FILTER_PREFIX_COUNT 0 +#endif + #define TEST_NET_IF net_if_lookup_by_dev(DEVICE_GET(eth_ipv6_net)) +#define TEST_MSG_SIZE 128 static struct in6_addr my_addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1 } } }; static struct in6_addr peer_addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2 } } }; static struct in6_addr multicast_addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0x1 } } }; + 0, 0, 0, 0, 0, 0, 0, 0x1 } } }; +static struct in6_addr all_nodes_mcast = { { { 0xff, 0x02, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0x1 } } }; + +/* Below should match prefix/addr distributed in RA message. */ +static struct in6_addr test_router_addr = { { { + 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0x2, 0x60, + 0x97, 0xff, 0xfe, 0x07, 0x69, 0xea +} } }; +static struct in6_addr test_ra_prefix = { { { 0x3f, 0xfe, 0x05, 0x07, 0, 0, 0, 1, + 0, 0, 0, 0, 0, 0, 0, 0 } } }; +static struct in6_addr test_ra_autoconf_addr = { { { + 0x3f, 0xfe, 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, + 0x02, 0x00, 0x5e, 0xff, 0xfe, 0x00, 0x53, 0x00 +} } }; /* ICMPv6 NS frame (74 bytes) */ static const unsigned char icmpv6_ns_invalid[] = { @@ -98,9 +119,9 @@ static const unsigned char icmpv6_ra[] = { 0x01, 0x01, 0x00, 0x60, 0x97, 0x07, 0x69, 0xea, /* MTU */ 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0x05, 0xdc, -/* Prefix info */ - 0x03, 0x04, 0x40, 0xc0, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, +/* Prefix info*/ + 0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0xFF, 0xFF, + 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfe, 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Route info */ @@ -135,12 +156,22 @@ static const unsigned char ipv6_hbho[] = { 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, /* ...... */ }; +static int send_msg(struct in6_addr *src, struct in6_addr *dst); + +typedef void (*ns_callback)(struct net_pkt *pkt, void *user_data); + +struct test_ns_handler { + ns_callback fn; + void *user_data; +}; + static bool expecting_ra; static uint32_t dad_time[3]; static bool test_failed; static struct k_sem wait_data; static bool recv_cb_called; struct net_if_addr *ifaddr_record; +static struct test_ns_handler *ns_handler; #define WAIT_TIME 250 #define WAIT_TIME_LONG MSEC_PER_SEC @@ -149,6 +180,7 @@ struct net_if_addr *ifaddr_record; #define PEER_PORT 16233 struct net_test_ipv6 { + struct ethernet_context ctx; uint8_t mac_addr[sizeof(struct net_eth_addr)]; struct net_linkaddr ll_addr; }; @@ -181,6 +213,10 @@ static void net_test_iface_init(struct net_if *iface) net_if_set_link_addr(iface, mac, sizeof(struct net_eth_addr), NET_LINK_ETHERNET); + + if (net_if_l2(iface) == &NET_L2_GET_NAME(ETHERNET)) { + ethernet_init(iface); + } } /** @@ -210,6 +246,55 @@ static void prepare_ra_message(struct net_pkt *pkt) net_pkt_cursor_init(pkt); } +static void inject_na_message(struct net_if *iface, struct in6_addr *src, + struct in6_addr *dst, struct in6_addr *target, + uint8_t flags) +{ + struct net_eth_hdr hdr; + struct net_pkt *pkt; + uint8_t na_flags[] = { flags, 0, 0, 0 }; + uint8_t na_tlla_opt[] = { 0x02, 0x01, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa }; + + pkt = net_pkt_alloc_with_buffer(iface, TEST_MSG_SIZE, AF_INET6, + IPPROTO_ICMPV6, K_NO_WAIT); + zassert_not_null(pkt, "Failed to allocate packet"); + + net_pkt_set_ipv6_hop_limit(pkt, NET_IPV6_ND_HOP_LIMIT); + + hdr.type = htons(NET_ETH_PTYPE_IPV6); + memset(&hdr.src, 0xaa, sizeof(struct net_eth_addr)); + memcpy(&hdr.dst, net_pkt_iface(pkt)->if_dev->link_addr.addr, + sizeof(struct net_eth_addr)); + + /* Reserve space for the L2 header. */ + net_buf_reserve(pkt->frags, sizeof(struct net_eth_hdr)); + net_pkt_cursor_init(pkt); + net_pkt_set_overwrite(pkt, false); + + zassert_ok(net_ipv6_create(pkt, src, dst)); + zassert_ok(net_icmpv6_create(pkt, NET_ICMPV6_NA, 0)); + zassert_ok(net_pkt_write(pkt, na_flags, sizeof(na_flags))); + zassert_ok(net_pkt_write(pkt, target, sizeof(struct in6_addr))); + zassert_ok(net_pkt_write(pkt, na_tlla_opt, sizeof(na_tlla_opt))); + + net_pkt_cursor_init(pkt); + net_ipv6_finalize(pkt, IPPROTO_ICMPV6); + + /* Fill L2 header. */ + net_buf_push_mem(pkt->frags, &hdr, sizeof(struct net_eth_hdr)); + + net_pkt_cursor_init(pkt); + zassert_ok((net_recv_data(iface, pkt)), "Data receive for NA failed."); +} + +static void skip_headers(struct net_pkt *pkt) +{ + net_pkt_cursor_init(pkt); + net_pkt_skip(pkt, sizeof(struct net_eth_hdr)); + net_pkt_skip(pkt, net_pkt_ip_hdr_len(pkt) + net_pkt_ipv6_ext_len(pkt)); + net_pkt_skip(pkt, sizeof(struct net_icmp_hdr)); +} + static struct net_icmp_hdr *get_icmp_hdr(struct net_pkt *pkt) { NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(icmp_access, struct net_icmp_hdr); @@ -261,6 +346,10 @@ static int tester_send(const struct device *dev, struct net_pkt *pkt) } if (icmp->type == NET_ICMPV6_NS) { + if (ns_handler != NULL) { + ns_handler->fn(pkt, ns_handler->user_data); + } + if (dad_time[0] == 0U) { dad_time[0] = k_uptime_get_32(); } else if (dad_time[1] == 0U) { @@ -304,6 +393,30 @@ NET_DEVICE_INIT(eth_ipv6_net, "eth_ipv6_net", &net_test_if_api, _ETH_L2_LAYER, _ETH_L2_CTX_TYPE, NET_ETH_MTU); +static void test_iface_down_up(void) +{ + zassert_ok(net_if_down(TEST_NET_IF), "Failed to bring iface down"); + k_msleep(10); + zassert_ok(net_if_up(TEST_NET_IF), "Failed to bring iface up"); +} + +static void test_iface_down_up_delayed_carrier(void) +{ + zassert_ok(net_if_down(TEST_NET_IF), "Failed to bring iface down"); + k_msleep(10); + net_if_carrier_off(TEST_NET_IF); + zassert_ok(net_if_up(TEST_NET_IF), "Failed to bring iface up"); + k_msleep(10); + net_if_carrier_on(TEST_NET_IF); +} + +static void test_iface_carrier_off_on(void) +{ + net_if_carrier_off(TEST_NET_IF); + k_msleep(10); + net_if_carrier_on(TEST_NET_IF); +} + /* dummy interface for multi-interface tests */ static int dummy_send(const struct device *dev, struct net_pkt *pkt) { @@ -465,7 +578,6 @@ static void nbr_lookup_ok(void) static void *ipv6_setup(void) { struct net_if_addr *ifaddr = NULL, *ifaddr2; - struct net_if_mcast_addr *maddr; struct net_if *iface = TEST_NET_IF; struct net_if *iface2 = NULL; struct net_if_ipv6 *ipv6; @@ -501,12 +613,6 @@ static void *ipv6_setup(void) ifaddr2 = net_if_ipv6_addr_lookup(&my_addr, &iface2); zassert_true(ifaddr2 == ifaddr, "Invalid ifaddr (%p vs %p)\n", ifaddr, ifaddr2); - net_ipv6_addr_create(&multicast_addr, 0xff02, 0, 0, 0, 0, 0, 0, 0x0001); - - maddr = net_if_ipv6_maddr_add(iface, &multicast_addr); - zassert_not_null(maddr, "Cannot add multicast IPv6 address %s\n", - net_sprint_ipv6_addr(&multicast_addr)); - /* The semaphore is there to wait the data to be received. */ k_sem_init(&wait_data, 0, UINT_MAX); @@ -516,9 +622,20 @@ static void *ipv6_setup(void) nbr_lookup_ok(); k_sleep(K_MSEC(50)); + /* Last, randomized MAC byte needs to be copied to the expected autoconf + * address. + */ + test_ra_autoconf_addr.s6_addr[15] = net_if_get_link_addr(iface)->addr[5]; + return NULL; } +static void ipv6_before(void *fixture) +{ + ARG_UNUSED(fixture); + + ns_handler = NULL; +} static void ipv6_teardown(void *dummy) { @@ -625,6 +742,73 @@ ZTEST(net_ipv6, test_send_ns_no_options) "Data receive for invalid NS failed."); } +struct test_nd_context { + struct k_sem wait_ns; + struct in6_addr *exp_ns_addr; + bool reply; +}; + +static void expect_nd_ns(struct net_pkt *pkt, void *user_data) +{ + uint32_t res_bytes; + struct in6_addr target; + struct test_nd_context *ctx = user_data; + + skip_headers(pkt); + + zassert_ok(net_pkt_read_be32(pkt, &res_bytes), "Failed to read reserved bytes"); + zassert_equal(0, res_bytes, "Reserved bytes must be zeroed"); + zassert_ok(net_pkt_read(pkt, &target, sizeof(struct in6_addr)), + "Failed to read target address"); + + if (net_ipv6_addr_cmp(ctx->exp_ns_addr, &target)) { + if (ctx->reply) { + inject_na_message(net_pkt_iface(pkt), &target, &my_addr, + &target, NET_ICMPV6_NA_FLAG_SOLICITED); + } + + k_sem_give(&ctx->wait_ns); + } +} + +ZTEST(net_ipv6, test_send_neighbor_discovery) +{ + struct test_nd_context ctx = { + .exp_ns_addr = &test_router_addr, + .reply = true + }; + struct test_ns_handler handler = { + .fn = expect_nd_ns, + .user_data = &ctx + }; + enum net_verdict verdict; + struct net_nbr *nbr; + + k_sem_init(&ctx.wait_ns, 0, 1); + ns_handler = &handler; + + (void)net_ipv6_nbr_rm(TEST_NET_IF, &test_router_addr); + + verdict = send_msg(&my_addr, &test_router_addr); + zassert_equal(verdict, NET_OK, "Packet was dropped (%d)", verdict); + zassert_ok(k_sem_take(&ctx.wait_ns, K_MSEC(WAIT_TIME)), + "Timeout while waiting for expected NS"); + + k_sleep(K_MSEC(10)); + + /* Neighbor should be here now. */ + nbr = net_ipv6_nbr_lookup(TEST_NET_IF, &test_router_addr); + zassert_not_null(nbr, "Neighbor not found."); + zassert_equal(net_ipv6_nbr_data(nbr)->state, NET_IPV6_NBR_STATE_REACHABLE, + "Neighbor should be reachable at this point."); + + /* Second attempt (neighbor valid) should give no NS. */ + verdict = send_msg(&my_addr, &test_router_addr); + zassert_equal(verdict, NET_OK, "Packet was dropped (%d)", verdict); + zassert_equal(k_sem_take(&ctx.wait_ns, K_MSEC(10)), -EAGAIN, + "Should not get NS"); +} + /** * @brief IPv6 prefix timeout */ @@ -697,10 +881,6 @@ static void rs_message(void) static void ra_message(void) { - struct in6_addr addr = { { { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0x2, 0x60, - 0x97, 0xff, 0xfe, 0x07, 0x69, 0xea } } }; - struct in6_addr prefix = { { { 0x3f, 0xfe, 0x05, 0x07, 0, 0, 0, 1, - 0, 0, 0, 0, 0, 0, 0, 0 } } }; struct in6_addr route_prefix = { { { 0x20, 0x01, 0x0d, 0xb0, 0x0f, 0xff } } }; struct sockaddr_in6 dns_addr = { .sin6_family = AF_INET6, @@ -711,6 +891,7 @@ static void ra_message(void) struct net_route_entry *route; struct dns_resolve_context *ctx; struct sockaddr_in6 *dns_server; + struct net_if_addr *ifaddr; /* We received RA message earlier, make sure that the information * in that message is placed to proper prefix and lookup info. @@ -718,13 +899,21 @@ static void ra_message(void) expecting_ra = false; - zassert_false(!net_if_ipv6_prefix_lookup(TEST_NET_IF, &prefix, 32), + zassert_false(!net_if_ipv6_prefix_lookup(TEST_NET_IF, &test_ra_prefix, 64), "Prefix %s should be here\n", - net_sprint_ipv6_addr(&prefix)); + net_sprint_ipv6_addr(&test_ra_prefix)); - zassert_false(!net_if_ipv6_router_lookup(TEST_NET_IF, &addr), + zassert_false(!net_if_ipv6_router_lookup(TEST_NET_IF, &test_router_addr), "Router %s should be here\n", - net_sprint_ipv6_addr(&addr)); + net_sprint_ipv6_addr(&test_router_addr)); + + /* Check if autoconf address was added correctly. */ + ifaddr = net_if_ipv6_addr_lookup_by_iface(TEST_NET_IF, + &test_ra_autoconf_addr); + zassert_not_null(ifaddr, "Autoconf address %s missing", + net_sprint_ipv6_addr(&test_ra_autoconf_addr)); + zassert_equal(ifaddr->addr_type, NET_ADDR_AUTOCONF, + "Address type should be autoconf"); /* Check if route was added correctly. */ route = net_route_lookup(TEST_NET_IF, &route_prefix); @@ -750,9 +939,91 @@ static void ra_message(void) ZTEST(net_ipv6, test_rs_ra_message) { rs_message(); + /* Small delay to let the net stack process the generated RA message. */ + k_sleep(K_MSEC(10)); ra_message(); } +struct test_dad_context { + struct k_sem wait_dad; + struct in6_addr *exp_dad_addr; + bool reply; +}; + +static void expect_dad_ns(struct net_pkt *pkt, void *user_data) +{ + uint32_t res_bytes; + struct in6_addr target; + struct test_dad_context *ctx = user_data; + + skip_headers(pkt); + + zassert_ok(net_pkt_read_be32(pkt, &res_bytes), "Failed to read reserved bytes"); + zassert_equal(0, res_bytes, "Reserved bytes must be zeroed"); + zassert_ok(net_pkt_read(pkt, &target, sizeof(struct in6_addr)), + "Failed to read target address"); + + if (net_ipv6_addr_cmp(ctx->exp_dad_addr, &target)) { + if (ctx->reply) { + inject_na_message(net_pkt_iface(pkt), &target, + &all_nodes_mcast, &target, 0); + } + + k_sem_give(&ctx->wait_dad); + } +} + +/* Verify that RS is sent after interface state change, RA processed, + * prefix added and autoconf address configured. + */ +static void verify_rs_on_iface_event(void (*action)(void)) +{ + struct net_if_router *router; + struct test_dad_context ctx = { + .exp_dad_addr = &test_ra_autoconf_addr + }; + struct test_ns_handler handler = { + .fn = expect_dad_ns, + .user_data = &ctx + }; + + (void)net_if_ipv6_prefix_rm(TEST_NET_IF, &test_ra_prefix, 64); + + router = net_if_ipv6_router_lookup(TEST_NET_IF, &test_router_addr); + if (router) { + (void)net_if_ipv6_router_rm(router); + } + + k_sem_init(&ctx.wait_dad, 0, 1); + + ns_handler = &handler; + expecting_ra = true; + + action(); + + k_sleep(K_MSEC(10)); + + ra_message(); + + zassert_ok(k_sem_take(&ctx.wait_dad, K_MSEC(WAIT_TIME)), + "Timeout while waiting for DAD NS"); +} + +ZTEST(net_ipv6, test_rs_after_iface_up) +{ + verify_rs_on_iface_event(test_iface_down_up); +} + +ZTEST(net_ipv6, test_rs_after_iface_up_carrier_delayed) +{ + verify_rs_on_iface_event(test_iface_down_up_delayed_carrier); +} + +ZTEST(net_ipv6, test_rs_after_carrier_toggle) +{ + verify_rs_on_iface_event(test_iface_carrier_off_on); +} + /** * @brief IPv6 parse Hop-By-Hop Option */ @@ -1130,20 +1401,17 @@ ZTEST(net_ipv6, test_change_ll_addr) static uint8_t new_mac[] = { 00, 01, 02, 03, 04, 05 }; struct net_linkaddr_storage *ll; struct net_linkaddr *ll_iface; - struct in6_addr dst; struct net_if *iface; struct net_nbr *nbr; uint32_t flags; int ret; - net_ipv6_addr_create(&dst, 0xff02, 0, 0, 0, 0, 0, 0, 1); - iface = TEST_NET_IF; flags = NET_ICMPV6_NA_FLAG_ROUTER | NET_ICMPV6_NA_FLAG_OVERRIDE; - ret = net_ipv6_send_na(iface, &peer_addr, &dst, + ret = net_ipv6_send_na(iface, &peer_addr, &all_nodes_mcast, &peer_addr, flags); zassert_false(ret < 0, "Cannot send NA 1"); @@ -1162,7 +1430,7 @@ ZTEST(net_ipv6, test_change_ll_addr) */ ll_iface->addr = new_mac; - ret = net_ipv6_send_na(iface, &peer_addr, &dst, + ret = net_ipv6_send_na(iface, &peer_addr, &all_nodes_mcast, &peer_addr, flags); zassert_false(ret < 0, "Cannot send NA 2"); @@ -1174,12 +1442,7 @@ ZTEST(net_ipv6, test_change_ll_addr) zassert_true(memcmp(ll->addr, ll_iface->addr, ll->len) != 0, "Wrong link address 2"); - ll_iface->addr[0] = 0x00; - ll_iface->addr[1] = 0x00; - ll_iface->addr[2] = 0x5E; - ll_iface->addr[3] = 0x00; - ll_iface->addr[4] = 0x53; - ll_iface->addr[5] = sys_rand8_get(); + ll_iface->addr = net_test_data.mac_addr; } ZTEST(net_ipv6, test_dad_timeout) @@ -1222,6 +1485,118 @@ ZTEST(net_ipv6, test_dad_timeout) #endif } + +/* Verify that DAD NS is sent after interface state change, for static address + * (added to the interface in ipv6_setup()). + */ +static void verify_dad_on_static_addr_on_iface_event(void (*action)(void)) +{ + struct test_dad_context ctx = { + .exp_dad_addr = &my_addr + }; + struct test_ns_handler handler = { + .fn = expect_dad_ns, + .user_data = &ctx + }; + + k_sem_init(&ctx.wait_dad, 0, 1); + + ns_handler = &handler; + + action(); + + zassert_ok(k_sem_take(&ctx.wait_dad, K_MSEC(WAIT_TIME)), + "Timeout while waiting for DAD NS"); +} + +ZTEST(net_ipv6, test_dad_on_static_addr_after_iface_up) +{ + verify_dad_on_static_addr_on_iface_event(test_iface_down_up); +} + +ZTEST(net_ipv6, test_dad_on_static_addr_after_iface_up_carrier_delayed) +{ + verify_dad_on_static_addr_on_iface_event(test_iface_down_up_delayed_carrier); +} + +ZTEST(net_ipv6, test_dad_on_static_addr_after_carrier_toggle) +{ + verify_dad_on_static_addr_on_iface_event(test_iface_carrier_off_on); +} + +/* Verify that DAD NS is sent after interface state change, for link-local + * address. + */ +static void verify_dad_on_ll_addr_on_iface_event(void (*action)(void)) +{ + struct in6_addr link_local_addr; + struct test_dad_context ctx = { + .exp_dad_addr = &link_local_addr + }; + struct test_ns_handler handler = { + .fn = expect_dad_ns, + .user_data = &ctx + }; + + net_ipv6_addr_create_iid(&link_local_addr, + net_if_get_link_addr(TEST_NET_IF)); + k_sem_init(&ctx.wait_dad, 0, 1); + + ns_handler = &handler; + + action(); + + zassert_ok(k_sem_take(&ctx.wait_dad, K_MSEC(WAIT_TIME)), + "Timeout while waiting for DAD NS"); +} + +ZTEST(net_ipv6, test_dad_on_ll_addr_after_iface_up) +{ + verify_dad_on_ll_addr_on_iface_event(test_iface_down_up); +} + +ZTEST(net_ipv6, test_dad_on_ll_addr_after_iface_up_carrier_delayed) +{ + verify_dad_on_ll_addr_on_iface_event(test_iface_down_up_delayed_carrier); +} + +ZTEST(net_ipv6, test_dad_on_ll_addr_after_carrier_toggle) +{ + verify_dad_on_ll_addr_on_iface_event(test_iface_carrier_off_on); +} + +/* Verify that in case of DAD conflict, address is not used on the interface. */ +ZTEST(net_ipv6, test_dad_conflict) +{ + struct in6_addr addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0x99, 0x4 } } }; + struct test_dad_context ctx = { + .exp_dad_addr = &addr, + .reply = true + }; + struct test_ns_handler handler = { + .fn = expect_dad_ns, + .user_data = &ctx + }; + struct net_if_addr *ifaddr; + + k_sem_init(&ctx.wait_dad, 0, 1); + + ns_handler = &handler; + + ifaddr = net_if_ipv6_addr_add(TEST_NET_IF, &addr, NET_ADDR_AUTOCONF, 0xffff); + zassert_not_null(ifaddr, "Address cannot be added"); + + zassert_ok(k_sem_take(&ctx.wait_dad, K_MSEC(WAIT_TIME)), + "Timeout while waiting for DAD NS"); + + /* Small delay to let the stack process NA response. */ + k_sleep(K_MSEC(100)); + + ifaddr = net_if_ipv6_addr_lookup_by_iface(TEST_NET_IF, &addr); + zassert_is_null(ifaddr, "Address should not be present on the interface"); +} + #define NET_UDP_HDR(pkt) ((struct net_udp_hdr *)(net_udp_get_hdr(pkt, NULL))) static struct net_pkt *setup_ipv6_udp(struct net_if *iface, @@ -1400,6 +1775,8 @@ static void recv_cb(struct net_context *context, recv_cb_called = true; + net_pkt_unref(pkt); + k_sem_give(&wait_data); } @@ -1629,6 +2006,122 @@ ZTEST(net_ipv6, test_dst_is_other_iface_mcast_recv) net_context_put(ctx); } +/* Verify that after interface state change it's possible to transmit mcast + * packets to theoretically joined groups. + */ +static void verify_iface_mcast_send_on_iface_event(void (*action)(void)) +{ + enum net_verdict verdict; + struct net_context *ctx; + struct in6_addr solicited_node_mcast; + + action(); + + /* All nodes */ + net_ctx_create(&ctx); + net_ctx_bind_mcast(ctx, &all_nodes_mcast); + net_ctx_listen(ctx); + net_ctx_recv(ctx); + + verdict = send_msg(&my_addr, &all_nodes_mcast); + zassert_equal(verdict, NET_OK, + "All nodes multicast packet was dropped (%d)", + verdict); + + net_context_put(ctx); + + /* Solicited node */ + net_ipv6_addr_create_solicited_node(&my_addr, &solicited_node_mcast); + + net_ctx_create(&ctx); + net_ctx_bind_mcast(ctx, &solicited_node_mcast); + net_ctx_listen(ctx); + net_ctx_recv(ctx); + + verdict = send_msg(&my_addr, &solicited_node_mcast); + zassert_equal(verdict, NET_OK, + "Solicited node multicast packet was dropped (%d)", + verdict); + + net_context_put(ctx); +} + +ZTEST(net_ipv6, test_iface_mcast_send_after_iface_up) +{ + verify_iface_mcast_send_on_iface_event(test_iface_down_up); +} + +ZTEST(net_ipv6, test_iface_mcast_send_after_iface_up_carrier_delayed) +{ + verify_iface_mcast_send_on_iface_event(test_iface_down_up_delayed_carrier); +} + +ZTEST(net_ipv6, test_iface_mcast_send_after_carrier_toggle) +{ + verify_iface_mcast_send_on_iface_event(test_iface_carrier_off_on); +} + +/* Verify that after interface state change it's possible to receive mcast + * packets on theoretically joined groups. + */ +static void verify_iface_mcast_recv_on_iface_event(void (*action)(void)) +{ + enum net_verdict verdict; + struct net_context *ctx; + struct in6_addr solicited_node_mcast; + + action(); + + k_sem_reset(&wait_data); + + /* All nodes */ + net_ctx_create(&ctx); + net_ctx_bind_mcast(ctx, &all_nodes_mcast); + net_ctx_listen(ctx); + net_ctx_recv(ctx); + + verdict = recv_msg(&peer_addr, &all_nodes_mcast); + zassert_equal(verdict, NET_OK, + "All nodes multicast packet was dropped (%d)", + verdict); + zassert_ok(k_sem_take(&wait_data, K_MSEC(WAIT_TIME)), + "Timeout while waiting for mcast packet"); + + net_context_put(ctx); + + /* Solicited node */ + net_ipv6_addr_create_solicited_node(&my_addr, &solicited_node_mcast); + + net_ctx_create(&ctx); + net_ctx_bind_mcast(ctx, &solicited_node_mcast); + net_ctx_listen(ctx); + net_ctx_recv(ctx); + + verdict = recv_msg(&peer_addr, &solicited_node_mcast); + zassert_equal(verdict, NET_OK, + "Solicited node multicast packet was dropped (%d)", + verdict); + zassert_ok(k_sem_take(&wait_data, K_MSEC(WAIT_TIME)), + "Timeout while waiting for mcast packet"); + + net_context_put(ctx); +} + +ZTEST(net_ipv6, test_iface_mcast_recv_after_iface_up) +{ + verify_iface_mcast_recv_on_iface_event(test_iface_down_up); +} + +ZTEST(net_ipv6, test_iface_mcast_recv_after_iface_up_carrier_delayed) +{ + verify_iface_mcast_recv_on_iface_event(test_iface_down_up_delayed_carrier); +} + +ZTEST(net_ipv6, test_iface_mcast_recv_after_carrier_toggle) +{ + verify_iface_mcast_recv_on_iface_event(test_iface_carrier_off_on); +} + ZTEST(net_ipv6, test_no_nd_flag) { bool ret; @@ -1682,4 +2175,210 @@ ZTEST(net_ipv6, test_nd_reachability_hint) zassert_equal(net_ipv6_nbr_data(nbr)->state, NET_IPV6_NBR_STATE_REACHABLE); } -ZTEST_SUITE(net_ipv6, NULL, ipv6_setup, NULL, NULL, ipv6_teardown); +static bool is_pe_address_found(struct net_if *iface, struct in6_addr *prefix) +{ + struct net_if_ipv6 *ipv6; + + ipv6 = iface->config.ip.ipv6; + + zassert_not_null(ipv6, "IPv6 configuration is wrong for iface %p", + iface); + + ARRAY_FOR_EACH(ipv6->unicast, i) { + if (!ipv6->unicast[i].is_used || + ipv6->unicast[i].address.family != AF_INET6 || + !ipv6->unicast[i].is_temporary) { + continue; + } + + if (net_ipv6_is_prefix( + (uint8_t *)&ipv6->unicast[i].address.in6_addr, + (uint8_t *)prefix, 64)) { + return true; + } + } + + return false; +} + +static void get_pe_addresses(struct net_if *iface, + struct in6_addr **public_addr, + struct in6_addr **temp_addr) +{ + struct in6_addr prefix = { { { 0x3f, 0xfe, 0x05, 0x07, 0, 0, 0, 1, + 0, 0, 0, 0, 0, 0, 0, 0 } } }; + struct net_if_ipv6 *ipv6; + + ipv6 = iface->config.ip.ipv6; + + zassert_not_null(ipv6, "IPv6 configuration is wrong for iface %p", + iface); + + ARRAY_FOR_EACH(ipv6->unicast, i) { + if (!ipv6->unicast[i].is_used || + ipv6->unicast[i].address.family != AF_INET6) { + continue; + } + + if (net_ipv6_is_prefix( + (uint8_t *)&ipv6->unicast[i].address.in6_addr, + (uint8_t *)&prefix, 64)) { + if (ipv6->unicast[i].is_temporary) { + *temp_addr = + &ipv6->unicast[i].address.in6_addr; + } else { + *public_addr = + &ipv6->unicast[i].address.in6_addr; + } + } + } +} + +/* The privacy extension tests need to be run after the RA tests so name + * the tests like this. + */ +ZTEST(net_ipv6, test_z_privacy_extension_01) +{ + struct in6_addr prefix = { { { 0x3f, 0xfe, 0x05, 0x07, 0, 0, 0, 1, + 0, 0, 0, 0, 0, 0, 0, 0 } } }; + struct net_if *iface = net_if_get_default(); + bool found; + + if (!IS_ENABLED(CONFIG_NET_IPV6_PE)) { + return; + } + + zassert_true(iface->pe_enabled, + "Privacy extension not enabled for iface %d", + net_if_get_by_iface(iface)); + + if (IS_ENABLED(CONFIG_NET_IPV6_PE_PREFER_PUBLIC_ADDRESSES)) { + zassert_true(iface->pe_prefer_public, + "Prefer public flag not set correctly for iface %d", + net_if_get_by_iface(iface)); + } + + /* We received RA message earlier, make sure that temporary address + * is created because of that message. + */ + + found = is_pe_address_found(iface, &prefix); + zassert_true(found, "Temporary address not found for iface %d", + net_if_get_by_iface(iface)); +} + +ZTEST(net_ipv6, test_z_privacy_extension_02_filters) +{ + struct in6_addr prefix1 = { { { 0x3f, 0xfe, 0x05, 0x07, 0, 0, 0, 1, + 0, 0, 0, 0, 0, 0, 0, 0 } } }; + struct in6_addr prefix2 = { { { 0x3f, 0xfe, 0x04, 0x07, 0, 0, 0, 1, + 0, 0, 0, 0, 0, 0, 0, 0 } } }; + struct in6_addr prefix3 = { { { 0x3f, 0xfe, 0x03, 0x07, 0, 0, 0, 1, + 0, 0, 0, 0, 0, 0, 0, 0 } } }; + struct net_if *iface = net_if_get_default(); + bool found; + int ret; + + if (!IS_ENABLED(CONFIG_NET_IPV6_PE) || NET_IPV6_PE_FILTER_PREFIX_COUNT == 0) { + return; + } + + /* First add denylist filters */ + ret = net_ipv6_pe_add_filter(&prefix1, true); + zassert_equal(ret, 0, "Filter cannot be added (%d)", ret); + + ret = net_ipv6_pe_add_filter(&prefix2, true); + zassert_equal(ret, 0, "Filter cannot be added (%d)", ret); + + ret = net_ipv6_pe_add_filter(&prefix3, true); + zassert_true(ret < 0, "Filter could be added"); + + /* Then delete them */ + ret = net_ipv6_pe_del_filter(&prefix1); + zassert_equal(ret, 0, "Filter cannot be deleted (%d)", ret); + + ret = net_ipv6_pe_del_filter(&prefix2); + zassert_equal(ret, 0, "Filter cannot be deleted (%d)", ret); + + ret = net_ipv6_pe_del_filter(&prefix2); + zassert_true(ret < 0, "Filter found (%d)", ret); + + /* Then add allowlist filter */ + ret = net_ipv6_pe_add_filter(&prefix1, false); + zassert_equal(ret, 0, "Filter cannot be added (%d)", ret); + + /* Send RS again as we have now PE allowlist filter in place */ + rs_message(); + + /* IP stack needs to process the packet */ + k_sleep(K_MSEC(150)); + + found = is_pe_address_found(iface, &prefix1); + zassert_true(found, "Temporary address not found for iface %p", iface); + + /* Then try with denylisted filter */ + ret = net_ipv6_pe_del_filter(&prefix1); + zassert_equal(ret, 0, "Filter cannot be deleted (%d)", ret); + + ret = net_ipv6_pe_add_filter(&prefix1, true); + zassert_equal(ret, 0, "Filter cannot be added (%d)", ret); + + k_sleep(K_MSEC(10)); + + /* Send RS again as we have now PE denylist filter in place */ + rs_message(); + + k_sleep(K_MSEC(150)); + + found = is_pe_address_found(iface, &prefix1); + zassert_false(found, "Temporary address found for iface %p", iface); + + ret = net_ipv6_pe_del_filter(&prefix1); + zassert_equal(ret, 0, "Filter cannot be deleted (%d)", ret); + + /* Add the temp address back for the next tests */ + ret = net_ipv6_pe_add_filter(&prefix1, false); + zassert_equal(ret, 0, "Filter cannot be added (%d)", ret); + + k_sleep(K_MSEC(50)); + + /* Send RS again as we have now PE allowlist filter in place */ + rs_message(); + + k_sleep(K_MSEC(150)); + + found = is_pe_address_found(iface, &prefix1); + zassert_true(found, "Temporary address not found for iface %p", iface); +} + +ZTEST(net_ipv6, test_z_privacy_extension_03_get_addr) +{ + struct in6_addr dst_addr = { { { 0x3f, 0xfe, 0x05, 0x07, 0, 0, 0, 1, + 0, 0, 2, 3, 4, 5, 6, 7 } } }; + struct net_if *iface = net_if_get_default(); + struct in6_addr *public_addr = NULL; + struct in6_addr *temp_addr = NULL; + const struct in6_addr *src_addr; + + if (!IS_ENABLED(CONFIG_NET_IPV6_PE)) { + return; + } + + get_pe_addresses(iface, &public_addr, &temp_addr); + + zassert_not_null(public_addr, "No public address found"); + zassert_not_null(temp_addr, "No temporary address found"); + + src_addr = net_if_ipv6_select_src_addr(iface, &dst_addr); + zassert_not_null(src_addr, "No suitable source address found"); + + if (iface->pe_prefer_public) { + zassert_true(net_ipv6_addr_cmp(src_addr, public_addr), + "Non public address selected"); + } else { + zassert_true(net_ipv6_addr_cmp(src_addr, temp_addr), + "Non temporary address selected"); + } +} + +ZTEST_SUITE(net_ipv6, NULL, ipv6_setup, ipv6_before, NULL, ipv6_teardown); diff --git a/tests/net/ipv6/testcase.yaml b/tests/net/ipv6/testcase.yaml index 1fbe64f067a..efc60810da2 100644 --- a/tests/net/ipv6/testcase.yaml +++ b/tests/net/ipv6/testcase.yaml @@ -2,13 +2,33 @@ common: tags: - net - ipv6 + - ipv6_pe depends_on: netif + platform_exclude: + - native_posix/native/64 + - native_posix tests: net.ipv6: extra_configs: - CONFIG_NET_BUF_FIXED_DATA_SIZE=y + - CONFIG_NET_IPV6_PE=n net.ipv6.variable_buf_size: extra_configs: - CONFIG_NET_BUF_VARIABLE_DATA_SIZE=y - CONFIG_NET_PKT_BUF_RX_DATA_POOL_SIZE=4096 - CONFIG_NET_PKT_BUF_TX_DATA_POOL_SIZE=4096 + - CONFIG_NET_IPV6_PE=n + net.ipv6.privacy_extension.prefer_public: + extra_configs: + - CONFIG_NET_IPV6_PE=y + - CONFIG_NET_IPV6_PE_PREFER_PUBLIC_ADDRESSES=y + - CONFIG_NET_IPV6_PE_FILTER_PREFIX_COUNT=2 + - CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=9 + - CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=7 + net.ipv6.privacy_extension.prefer_temporary: + extra_configs: + - CONFIG_NET_IPV6_PE=y + - CONFIG_NET_IPV6_PE_PREFER_PUBLIC_ADDRESSES=n + - CONFIG_NET_IPV6_PE_FILTER_PREFIX_COUNT=2 + - CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=9 + - CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=7 diff --git a/tests/net/lib/coap_server/common/prj.conf b/tests/net/lib/coap_server/common/prj.conf index 07cf69355fc..8daa9205bf4 100644 --- a/tests/net/lib/coap_server/common/prj.conf +++ b/tests/net/lib/coap_server/common/prj.conf @@ -4,6 +4,7 @@ CONFIG_NETWORKING=y CONFIG_NET_TEST=y CONFIG_ENTROPY_GENERATOR=y CONFIG_TEST_RANDOM_GENERATOR=y +CONFIG_NET_LOOPBACK=y CONFIG_COAP=y CONFIG_COAP_SERVER=y diff --git a/tests/net/lib/coap_server/common/sections-ram.ld b/tests/net/lib/coap_server/common/sections-ram.ld index d435ffbddd4..2cb27dc13a3 100644 --- a/tests/net/lib/coap_server/common/sections-ram.ld +++ b/tests/net/lib/coap_server/common/sections-ram.ld @@ -2,6 +2,6 @@ #include -ITERABLE_SECTION_RAM(coap_resource_service_A, 4) -ITERABLE_SECTION_RAM(coap_resource_service_B, 4) -ITERABLE_SECTION_RAM(coap_resource_service_C, 4) +ITERABLE_SECTION_RAM(coap_resource_service_A, Z_LINK_ITERABLE_SUBALIGN) +ITERABLE_SECTION_RAM(coap_resource_service_B, Z_LINK_ITERABLE_SUBALIGN) +ITERABLE_SECTION_RAM(coap_resource_service_C, Z_LINK_ITERABLE_SUBALIGN) diff --git a/tests/net/lib/dns_addremove/prj.conf b/tests/net/lib/dns_addremove/prj.conf index db691377acd..c28f0a14eac 100644 --- a/tests/net/lib/dns_addremove/prj.conf +++ b/tests/net/lib/dns_addremove/prj.conf @@ -17,3 +17,4 @@ CONFIG_NET_ARP=n CONFIG_PRINTK=y CONFIG_ZTEST=y CONFIG_MAIN_STACK_SIZE=2048 +CONFIG_NET_SOCKETS_POLL_MAX=5 diff --git a/tests/net/lib/dns_addremove/testcase.yaml b/tests/net/lib/dns_addremove/testcase.yaml index 5551a41cfba..21b33cba4ca 100644 --- a/tests/net/lib/dns_addremove/testcase.yaml +++ b/tests/net/lib/dns_addremove/testcase.yaml @@ -5,6 +5,9 @@ common: depends_on: netif min_ram: 16 timeout: 600 + platform_exclude: + - native_posix + - native_posix/native/64 tests: net.dns.addremove: min_ram: 21 diff --git a/tests/net/lib/dns_cache/testcase.yaml b/tests/net/lib/dns_cache/testcase.yaml index a14a8f6fe7d..b86087552b5 100644 --- a/tests/net/lib/dns_cache/testcase.yaml +++ b/tests/net/lib/dns_cache/testcase.yaml @@ -6,6 +6,9 @@ common: depends_on: netif integration_platforms: - native_sim + platform_exclude: + - native_posix + - native_posix/native/64 tests: net.dns.cache: build_only: false diff --git a/tests/net/lib/dns_packet/testcase.yaml b/tests/net/lib/dns_packet/testcase.yaml index a69ee4ccb73..d1129ca8b42 100644 --- a/tests/net/lib/dns_packet/testcase.yaml +++ b/tests/net/lib/dns_packet/testcase.yaml @@ -1,5 +1,8 @@ tests: net.dns: + platform_exclude: + - native_posix + - native_posix/native/64 min_ram: 16 tags: - dns diff --git a/tests/net/lib/dns_resolve/prj.conf b/tests/net/lib/dns_resolve/prj.conf index c43911ac3cd..4bc1b8706ce 100644 --- a/tests/net/lib/dns_resolve/prj.conf +++ b/tests/net/lib/dns_resolve/prj.conf @@ -29,3 +29,5 @@ CONFIG_PRINTK=y CONFIG_ZTEST=y CONFIG_MAIN_STACK_SIZE=1344 +CONFIG_NET_SOCKETS_POLL_MAX=9 +CONFIG_POSIX_MAX_FDS=5 diff --git a/tests/net/lib/dns_resolve/src/main.c b/tests/net/lib/dns_resolve/src/main.c index cc56a7821a2..3d3bdcf9cf5 100644 --- a/tests/net/lib/dns_resolve/src/main.c +++ b/tests/net/lib/dns_resolve/src/main.c @@ -348,7 +348,7 @@ ZTEST(dns_resolve, test_dns_query_server_count) continue; } - if (!ctx->servers[i].net_ctx) { + if (ctx->servers[i].sock < 0) { continue; } @@ -369,7 +369,7 @@ ZTEST(dns_resolve, test_dns_query_ipv4_server_count) continue; } - if (!ctx->servers[i].net_ctx) { + if (ctx->servers[i].sock < 0) { continue; } @@ -399,7 +399,7 @@ ZTEST(dns_resolve, test_dns_query_ipv6_server_count) continue; } - if (!ctx->servers[i].net_ctx) { + if (ctx->servers[i].sock < 0) { continue; } diff --git a/tests/net/lib/dns_resolve/testcase.yaml b/tests/net/lib/dns_resolve/testcase.yaml index 5b7b40cc277..b0734b4d175 100644 --- a/tests/net/lib/dns_resolve/testcase.yaml +++ b/tests/net/lib/dns_resolve/testcase.yaml @@ -5,6 +5,9 @@ common: depends_on: netif timeout: 600 min_ram: 21 + platform_exclude: + - native_posix + - native_posix/native/64 tests: net.dns.resolve: extra_configs: diff --git a/tests/net/lib/dns_sd/src/main.c b/tests/net/lib/dns_sd/src/main.c index 31b7a6699a1..e70482c027c 100644 --- a/tests/net/lib/dns_sd/src/main.c +++ b/tests/net/lib/dns_sd/src/main.c @@ -12,6 +12,7 @@ #include #include #include +#include #include "dns_pack.h" #include "dns_sd.h" @@ -51,7 +52,7 @@ extern int add_srv_record(const struct dns_sd_rec *inst, uint32_t ttl, uint16_t *host_offset); extern size_t service_proto_size(const struct dns_sd_rec *ref); extern bool rec_is_valid(const struct dns_sd_rec *ref); -extern int setup_dst_addr(struct net_context *ctx, sa_family_t family, +extern int setup_dst_addr(int sock, sa_family_t family, struct sockaddr *dst, socklen_t *dst_len); @@ -666,56 +667,69 @@ ZTEST(dns_sd, test_dns_sd_rec_match) /** Test @ref setup_dst_addr */ ZTEST(dns_sd, test_setup_dst_addr) { - int ret; struct net_if *iface; struct sockaddr dst; socklen_t dst_len; + socklen_t optlen; + int ttl; iface = net_if_get_first_by_type(&NET_L2_GET_NAME(DUMMY)); zassert_not_null(iface, "Interface not available"); /* IPv4 case */ - struct net_context *ctx_v4; + int v4; struct in_addr addr_v4_expect = { { { 224, 0, 0, 251 } } }; memset(&dst, 0, sizeof(struct sockaddr)); - ret = net_context_get(AF_INET, SOCK_DGRAM, IPPROTO_UDP, &ctx_v4); - zassert_equal(ret, 0, "Create IPv4 UDP context failed"); + v4 = zsock_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + zassert_true(v4 >= 0, "Create IPv4 UDP context failed (%d)", -errno); - zassert_equal(0, setup_dst_addr(ctx_v4, AF_INET, &dst, &dst_len), ""); - zassert_equal(255, ctx_v4->ipv4_mcast_ttl, ""); + zassert_equal(0, setup_dst_addr(v4, AF_INET, &dst, &dst_len), ""); + + optlen = sizeof(int); + (void)zsock_getsockopt(v4, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, &optlen); + + zassert_equal(255, ttl, "TTL invalid (%d vs %d)", 255, ttl); zassert_true(net_ipv4_addr_cmp(&addr_v4_expect, &net_sin(&dst)->sin_addr), ""); zassert_equal(8, dst_len, ""); + (void)zsock_close(v4); + #if defined(CONFIG_NET_IPV6) /* IPv6 case */ - struct net_context *ctx_v6; + int v6; struct in6_addr addr_v6_expect = { { { 0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xfb } } }; memset(&dst, 0, sizeof(struct sockaddr)); - ret = net_context_get(AF_INET6, SOCK_DGRAM, IPPROTO_UDP, &ctx_v6); - zassert_equal(ret, 0, "Create IPv6 UDP context failed"); + v6 = zsock_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + zassert_true(v6 >= 0, "Create IPv6 UDP context failed (%d)", -errno); - zassert_equal(0, setup_dst_addr(ctx_v6, AF_INET6, &dst, &dst_len), ""); - zassert_equal(255, ctx_v6->ipv6_mcast_hop_limit, ""); + zassert_equal(0, setup_dst_addr(v6, AF_INET6, &dst, &dst_len), ""); + + optlen = sizeof(int); + (void)zsock_getsockopt(v6, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl, &optlen); + + zassert_equal(255, ttl, "Hoplimit invalid (%d vs %d)", 255, ttl); zassert_true(net_ipv6_addr_cmp(&addr_v6_expect, &net_sin6(&dst)->sin6_addr), ""); zassert_equal(24, dst_len, ""); + + (void)zsock_close(v6); #endif /* Unknown family case */ - struct net_context *ctx_xx; + int xx; - ret = net_context_get(AF_INET, SOCK_DGRAM, IPPROTO_UDP, &ctx_xx); - zassert_equal(ret, 0, "Create IPV4 udp context failed"); + xx = zsock_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + zassert_true(xx >= 0, "Create IPV4 udp socket failed"); zassert_equal(-EPFNOSUPPORT, - setup_dst_addr(ctx_xx, AF_PACKET, &dst, &dst_len), ""); + setup_dst_addr(xx, AF_PACKET, &dst, &dst_len), ""); } /** test for @ref dns_sd_is_service_type_enumeration */ diff --git a/tests/net/lib/dns_sd/testcase.yaml b/tests/net/lib/dns_sd/testcase.yaml index 22a6d332558..bfdc751ed7c 100644 --- a/tests/net/lib/dns_sd/testcase.yaml +++ b/tests/net/lib/dns_sd/testcase.yaml @@ -3,6 +3,9 @@ common: - dns - net depends_on: netif + platform_exclude: + - native_posix + - native_posix/native/64 tests: net.dns.sd: min_ram: 21 diff --git a/tests/net/lib/http_server/common/CMakeLists.txt b/tests/net/lib/http_server/common/CMakeLists.txt index 1a775236a5d..add7abe2de3 100644 --- a/tests/net/lib/http_server/common/CMakeLists.txt +++ b/tests/net/lib/http_server/common/CMakeLists.txt @@ -8,5 +8,5 @@ FILE(GLOB app_sources src/*.c) target_sources(app PRIVATE ${app_sources}) zephyr_linker_sources(SECTIONS sections-rom.ld) -zephyr_iterable_section(NAME http_resource_desc_service_A KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) -zephyr_iterable_section(NAME http_resource_desc_service_B KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) +zephyr_iterable_section(NAME http_resource_desc_service_A KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) +zephyr_iterable_section(NAME http_resource_desc_service_B KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) diff --git a/tests/net/lib/http_server/common/prj.conf b/tests/net/lib/http_server/common/prj.conf index 7fa5d3d6dd0..626a8050482 100644 --- a/tests/net/lib/http_server/common/prj.conf +++ b/tests/net/lib/http_server/common/prj.conf @@ -7,3 +7,8 @@ CONFIG_TEST_RANDOM_GENERATOR=y CONFIG_ZTEST_STACK_SIZE=1024 CONFIG_HTTP_SERVER=y +CONFIG_EVENTFD=y +CONFIG_POSIX_API=y + +# Networking config +CONFIG_NET_SOCKETS=y diff --git a/tests/net/lib/http_server/common/sections-rom.ld b/tests/net/lib/http_server/common/sections-rom.ld index 437e4bcb65b..e8411ede55c 100644 --- a/tests/net/lib/http_server/common/sections-rom.ld +++ b/tests/net/lib/http_server/common/sections-rom.ld @@ -1,4 +1,4 @@ #include -ITERABLE_SECTION_ROM(http_resource_desc_service_A, 4) -ITERABLE_SECTION_ROM(http_resource_desc_service_B, 4) +ITERABLE_SECTION_ROM(http_resource_desc_service_A, Z_LINK_ITERABLE_SUBALIGN) +ITERABLE_SECTION_ROM(http_resource_desc_service_B, Z_LINK_ITERABLE_SUBALIGN) diff --git a/tests/net/lib/http_server/common/testcase.yaml b/tests/net/lib/http_server/common/testcase.yaml index b86f2dc0c95..8b89a10da97 100644 --- a/tests/net/lib/http_server/common/testcase.yaml +++ b/tests/net/lib/http_server/common/testcase.yaml @@ -1,11 +1,13 @@ common: - min_ram: 16 + min_ram: 40 tags: - net - http - server integration_platforms: - native_sim - + platform_exclude: + - native_posix + - native_posix/native/64 tests: net.http.server.common: {} diff --git a/tests/net/lib/http_server/crime/CMakeLists.txt b/tests/net/lib/http_server/crime/CMakeLists.txt new file mode 100644 index 00000000000..d991ae1d3f6 --- /dev/null +++ b/tests/net/lib/http_server/crime/CMakeLists.txt @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(crime) + +set(BASE_PATH "../../../../../subsys/net/lib/http/") +include_directories(${BASE_PATH}/headers) + +FILE(GLOB app_sources src/main.c) +target_sources(app PRIVATE ${app_sources}) + +set(gen_dir ${ZEPHYR_BINARY_DIR}/include/generated/) + +set(source_file_index src/index.html) +generate_inc_file_for_target(app ${source_file_index} ${gen_dir}/index.html.inc) +generate_inc_file_for_target(app ${source_file_index} ${gen_dir}/index.html.gz.inc --gzip) + +set(source_file_not_found src/not_found_page.html) +generate_inc_file_for_target(app ${source_file_not_found} ${gen_dir}/not_found_page.html.inc) +generate_inc_file_for_target(app ${source_file_not_found} ${gen_dir}/not_found_page.html.gz.inc --gzip) + +zephyr_linker_sources(SECTIONS sections-rom.ld) +zephyr_iterable_section(NAME http_resource_desc_test_http_service KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) diff --git a/tests/net/lib/http_server/crime/prj.conf b/tests/net/lib/http_server/crime/prj.conf new file mode 100644 index 00000000000..0596a54e47c --- /dev/null +++ b/tests/net/lib/http_server/crime/prj.conf @@ -0,0 +1,54 @@ +CONFIG_ZTEST=y +CONFIG_NET_TEST=y + +# Eventfd +CONFIG_EVENTFD=y +CONFIG_POSIX_API=y + +CONFIG_ENTROPY_GENERATOR=y +CONFIG_TEST_RANDOM_GENERATOR=y +CONFIG_ZTEST_STACK_SIZE=1024 + +CONFIG_POSIX_MAX_FDS=10 +CONFIG_REQUIRES_FULL_LIBC=y +CONFIG_EVENTFD_MAX=10 +CONFIG_NET_MAX_CONTEXTS=10 +CONFIG_NET_MAX_CONN=10 + +# Networking config +CONFIG_NETWORKING=y +CONFIG_NET_IPV4=y +CONFIG_NET_IPV6=y +CONFIG_NET_TCP=y +CONFIG_NET_SOCKETS=y +CONFIG_NET_LOOPBACK=y +CONFIG_NET_LOOPBACK_MTU=1280 +CONFIG_NET_DRIVERS=y +CONFIG_NET_SOCKETS_POLL_MAX=8 +CONFIG_NET_BUF_RX_COUNT=32 +CONFIG_NET_BUF_TX_COUNT=32 +CONFIG_NET_PKT_RX_COUNT=16 +CONFIG_NET_PKT_TX_COUNT=16 + +# Reduce the retry count, so the close always finishes within a second +CONFIG_NET_TCP_RETRY_COUNT=3 +CONFIG_NET_TCP_INIT_RETRANSMISSION_TIMEOUT=120 + +# JSON +CONFIG_JSON_LIBRARY=y + +# HTTP parser +CONFIG_HTTP_PARSER_URL=y +CONFIG_HTTP_PARSER=y +CONFIG_HTTP_SERVER=y + +CONFIG_HTTP_SERVER_MAX_CLIENTS=5 +CONFIG_HTTP_SERVER_MAX_STREAMS=5 + +# Network address config +CONFIG_NET_CONFIG_SETTINGS=n + +CONFIG_MAIN_STACK_SIZE=2048 + +# Network debug config +CONFIG_NET_LOG=y diff --git a/tests/net/lib/http_server/crime/sections-rom.ld b/tests/net/lib/http_server/crime/sections-rom.ld new file mode 100644 index 00000000000..512251641b2 --- /dev/null +++ b/tests/net/lib/http_server/crime/sections-rom.ld @@ -0,0 +1,3 @@ +#include + +ITERABLE_SECTION_ROM(http_resource_desc_test_http_service, 4) diff --git a/tests/net/lib/http_server/crime/src/index.html b/tests/net/lib/http_server/crime/src/index.html new file mode 100644 index 00000000000..7f82a1e3975 --- /dev/null +++ b/tests/net/lib/http_server/crime/src/index.html @@ -0,0 +1,10 @@ + + + + My Simple Server + + +

Welcome to my simple server!

+

This is a simple HTML file.

+ + diff --git a/tests/net/lib/http_server/crime/src/main.c b/tests/net/lib/http_server/crime/src/main.c new file mode 100644 index 00000000000..992d64eff56 --- /dev/null +++ b/tests/net/lib/http_server/crime/src/main.c @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2023, Emna Rekik + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "server_internal.h" + +#include + +#include +#include +#include + +#define BUFFER_SIZE 256 +#define MY_IPV4_ADDR "127.0.0.1" +#define SERVER_PORT 8080 +#define TIMEOUT 1000 + +static const unsigned char index_html_gz[] = { +#include "index.html.gz.inc" +}; + +static const unsigned char compressed_inc_file[] = { + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0xff, 0x35, 0x8e, 0xc1, 0x0a, 0xc2, 0x30, + 0x0c, 0x86, 0xef, 0x7d, 0x8a, 0xec, 0x05, 0x2c, + 0xbb, 0x87, 0x5c, 0x54, 0xf0, 0xe0, 0x50, 0x58, + 0x41, 0x3c, 0x4e, 0x17, 0x69, 0x21, 0xa5, 0x65, + 0x2d, 0x42, 0xdf, 0xde, 0xba, 0x6e, 0x21, 0x10, + 0xf8, 0xf9, 0xbe, 0x9f, 0x60, 0x77, 0xba, 0x1d, + 0xcd, 0xf3, 0x7e, 0x06, 0x9b, 0xbd, 0x90, 0xc2, + 0xfd, 0xf0, 0x34, 0x93, 0x82, 0x3a, 0x98, 0x5d, + 0x16, 0xa6, 0xa1, 0xc0, 0xe8, 0x7c, 0x14, 0x86, + 0x91, 0x97, 0x2f, 0x2f, 0xa8, 0x5b, 0xae, 0x50, + 0x37, 0x16, 0x5f, 0x61, 0x2e, 0x9b, 0x62, 0x7b, + 0x7a, 0xb0, 0xbc, 0x83, 0x67, 0xc8, 0x01, 0x7c, + 0x81, 0xd4, 0xd4, 0xb4, 0xaa, 0x5d, 0x55, 0xfa, + 0x8d, 0x8c, 0x64, 0xac, 0x4b, 0x50, 0x77, 0xda, + 0xa1, 0x8b, 0x19, 0xae, 0xf0, 0x71, 0xc2, 0x07, + 0xd4, 0xf1, 0xdf, 0xdf, 0x8a, 0xab, 0xb4, 0xbe, + 0xf6, 0x03, 0xea, 0x2d, 0x11, 0x5c, 0xb2, 0x00, + 0x00, 0x00, +}; + +static uint16_t test_http_service_port = SERVER_PORT; +HTTP_SERVICE_DEFINE(test_http_service, MY_IPV4_ADDR, + &test_http_service_port, 1, + 10, NULL); + +struct http_resource_detail_static index_html_gz_resource_detail = { + .common = { + .type = HTTP_RESOURCE_TYPE_STATIC, + .bitmask_of_supported_http_methods = BIT(HTTP_GET), + }, + .static_data = index_html_gz, + .static_data_len = sizeof(index_html_gz), +}; + +HTTP_RESOURCE_DEFINE(index_html_gz_resource, test_http_service, "/", + &index_html_gz_resource_detail); + +static void test_crime(void) +{ + int ret, recv_len; + int client_fd; + int proto = IPPROTO_TCP; + char *ptr; + const char *data; + size_t len; + struct sockaddr_in sa; + static unsigned char buf[512]; + + zassert_ok(http_server_start(), "Failed to start the server"); + + ret = zsock_socket(AF_INET, SOCK_STREAM, proto); + zassert_not_equal(ret, -1, "failed to create client socket (%d)", errno); + client_fd = ret; + + sa.sin_family = AF_INET; + sa.sin_port = htons(SERVER_PORT); + + ret = zsock_inet_pton(AF_INET, MY_IPV4_ADDR, &sa.sin_addr.s_addr); + zassert_not_equal(-1, ret, "inet_pton() failed (%d)", errno); + zassert_not_equal(0, ret, "%s is not a valid IPv4 address", MY_IPV4_ADDR); + zassert_equal(1, ret, "inet_pton() failed to convert %s", MY_IPV4_ADDR); + + memset(buf, '\0', sizeof(buf)); + ptr = (char *)zsock_inet_ntop(AF_INET, &sa.sin_addr, buf, sizeof(buf)); + zassert_not_equal(ptr, NULL, "inet_ntop() failed (%d)", errno); + + ret = zsock_connect(client_fd, (struct sockaddr *)&sa, sizeof(sa)); + zassert_not_equal(ret, -1, "failed to connect (%s/%d)", strerror(errno), errno); + + char *http1_request = "GET / HTTP/1.1\r\n" + "Host: 127.0.0.1:8080\r\n" + "Accept: */*\r\n" + "Accept-Encoding: deflate, gzip, br\r\n" + "\r\n"; + + ret = zsock_send(client_fd, http1_request, strlen(http1_request), 0); + zassert_not_equal(ret, -1, "send() failed (%d)", errno); + + memset(buf, 0, sizeof(buf)); + recv_len = zsock_recv(client_fd, buf, sizeof(buf), 0); + zassert_not_equal(recv_len, -1, "recv() failed (%d)", errno); + + len = sizeof(index_html_gz); + + while (recv_len < len) { + ret = zsock_recv(client_fd, buf + recv_len, sizeof(buf) - recv_len, 0); + zassert_not_equal(ret, -1, "recv() failed (%d)", errno); + + recv_len += ret; + } + + data = strstr(buf, "\r\n\r\n"); + zassert_not_null(data, "Header not found"); + + data += 4; + + zassert_equal(len, sizeof(compressed_inc_file), "Invalid compressed file size"); + + ret = memcmp(data, compressed_inc_file, len); + zassert_equal(ret, 0, + "inc_file and compressed_inc_file contents are not identical (%d)", ret); + + ret = zsock_close(client_fd); + zassert_not_equal(-1, ret, "close() failed on the client fd (%d)", errno); + + zassert_ok(http_server_stop(), "Failed to stop the server"); +} + +ZTEST(framework_tests_crime, test_gen_gz_inc_file) +{ + test_crime(); +} + +ZTEST_SUITE(framework_tests_crime, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/net/lib/http_server/crime/src/not_found_page.html b/tests/net/lib/http_server/crime/src/not_found_page.html new file mode 100644 index 00000000000..c4bf66f08ee --- /dev/null +++ b/tests/net/lib/http_server/crime/src/not_found_page.html @@ -0,0 +1,10 @@ + + + + 404 Not Found + + +

404 Not Found

+

The requested resource was not found.

+ + diff --git a/tests/net/lib/http_server/crime/testcase.yaml b/tests/net/lib/http_server/crime/testcase.yaml new file mode 100644 index 00000000000..615b4264685 --- /dev/null +++ b/tests/net/lib/http_server/crime/testcase.yaml @@ -0,0 +1,16 @@ +common: + harness: net + min_ram: 60 + tags: + - http + - net + - server + - socket + integration_platforms: + - native_sim + - qemu_x86 + platform_exclude: + - native_posix + - native_posix/native/64 +tests: + net.http.server.crime: {} diff --git a/tests/net/lib/http_server/prototype/CMakeLists.txt b/tests/net/lib/http_server/prototype/CMakeLists.txt new file mode 100644 index 00000000000..8ba8aa71fc5 --- /dev/null +++ b/tests/net/lib/http_server/prototype/CMakeLists.txt @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(prototype) + +set(BASE_PATH "../../../../../subsys/net/lib/http/") +include_directories(${BASE_PATH}/headers) + +FILE(GLOB app_sources src/main.c) +target_sources(app PRIVATE ${app_sources}) + +set(gen_dir ${ZEPHYR_BINARY_DIR}/include/generated/) + +target_link_libraries(app PRIVATE zephyr_interface zephyr) + +zephyr_linker_sources(SECTIONS sections-rom.ld) +zephyr_iterable_section(NAME http_resource_desc_test_http_service KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) diff --git a/tests/net/lib/http_server/prototype/prj.conf b/tests/net/lib/http_server/prototype/prj.conf new file mode 100644 index 00000000000..20570610ef7 --- /dev/null +++ b/tests/net/lib/http_server/prototype/prj.conf @@ -0,0 +1,53 @@ +CONFIG_ZTEST=y +CONFIG_NET_TEST=y + +# Eventfd +CONFIG_EVENTFD=y +CONFIG_POSIX_API=y + +CONFIG_ENTROPY_GENERATOR=y +CONFIG_TEST_RANDOM_GENERATOR=y +CONFIG_POSIX_MAX_FDS=10 +CONFIG_REQUIRES_FULL_LIBC=y +CONFIG_EVENTFD_MAX=10 +CONFIG_NET_MAX_CONTEXTS=10 +CONFIG_NET_MAX_CONN=10 + +# Networking config +CONFIG_NETWORKING=y +CONFIG_NET_IPV4=y +CONFIG_NET_IPV6=y +CONFIG_NET_TCP=y +CONFIG_NET_SOCKETS=y +CONFIG_NET_LOOPBACK=y +CONFIG_NET_LOOPBACK_MTU=1280 +CONFIG_NET_DRIVERS=y +CONFIG_NET_SOCKETS_POLL_MAX=8 +CONFIG_NET_BUF_RX_COUNT=32 +CONFIG_NET_BUF_TX_COUNT=32 +CONFIG_NET_PKT_RX_COUNT=16 +CONFIG_NET_PKT_TX_COUNT=16 + +# Reduce the retry count, so the close always finishes within a second +CONFIG_NET_TCP_RETRY_COUNT=3 +CONFIG_NET_TCP_INIT_RETRANSMISSION_TIMEOUT=120 + +# JSON +CONFIG_JSON_LIBRARY=y + +# HTTP parser +CONFIG_HTTP_PARSER_URL=y +CONFIG_HTTP_PARSER=y +CONFIG_HTTP_SERVER=y + +CONFIG_HTTP_SERVER_MAX_CLIENTS=5 +CONFIG_HTTP_SERVER_MAX_STREAMS=5 + +# Network address config +CONFIG_NET_CONFIG_SETTINGS=n + +CONFIG_MAIN_STACK_SIZE=2048 +CONFIG_ZTEST_STACK_SIZE=18192 + +# Network debug config +CONFIG_NET_LOG=y diff --git a/tests/net/lib/http_server/prototype/sections-rom.ld b/tests/net/lib/http_server/prototype/sections-rom.ld new file mode 100644 index 00000000000..512251641b2 --- /dev/null +++ b/tests/net/lib/http_server/prototype/sections-rom.ld @@ -0,0 +1,3 @@ +#include + +ITERABLE_SECTION_ROM(http_resource_desc_test_http_service, 4) diff --git a/tests/net/lib/http_server/prototype/src/main.c b/tests/net/lib/http_server/prototype/src/main.c new file mode 100644 index 00000000000..99db7f81f7c --- /dev/null +++ b/tests/net/lib/http_server/prototype/src/main.c @@ -0,0 +1,402 @@ +/* + * Copyright (c) 2023, Emna Rekik + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "server_internal.h" + +#include + +#include +#include +#include +#include + +#define SUPPORT_BACKWARD_COMPATIBILITY 1 +#define SUPPORT_HTTP_SERVER_UPGRADE 2 +#define BUFFER_SIZE 256 +#define MY_IPV4_ADDR "127.0.0.1" +#define SERVER_PORT 8080 +#define TIMEOUT 1000 + + +/* Magic, SETTINGS[0], HEADERS[1]: GET /, HEADERS[3]: GET /index.html, SETTINGS[0], GOAWAY[0]*/ +static const unsigned char frame[] = { + /* Magic */ + 0x50, 0x52, 0x49, 0x20, 0x2a, 0x20, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x32, + 0x2e, 0x30, 0x0d, 0x0a, 0x0d, 0x0a, 0x53, 0x4d, 0x0d, 0x0a, 0x0d, 0x0a, + /* SETTINGS[0] */ + 0x00, 0x00, 0x0c, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x00, 0x64, 0x00, 0x04, 0x00, 0x00, 0xff, 0xff, + /* HEADERS[1]: GET / */ + 0x00, 0x00, 0x21, 0x01, 0x05, 0x00, 0x00, 0x00, 0x01, + 0x82, 0x84, 0x86, 0x41, 0x8a, 0x0b, 0xe2, 0x5c, 0x0b, 0x89, 0x70, 0xdc, + 0x78, 0x0f, 0x03, 0x53, 0x03, 0x2a, 0x2f, 0x2a, 0x90, 0x7a, 0x8a, 0xaa, + 0x69, 0xd2, 0x9a, 0xc4, 0xc0, 0x57, 0x68, 0x0b, 0x83, + /* HEADERS[3]: GET /index.html */ + 0x00, 0x00, 0x21, 0x01, 0x05, 0x00, 0x00, 0x00, 0x03, + 0x82, 0x85, 0x86, 0x41, 0x8a, 0x0b, 0xe2, 0x5c, 0x0b, 0x89, 0x70, 0xdc, + 0x78, 0x0f, 0x03, 0x53, 0x03, 0x2a, 0x2f, 0x2a, 0x90, 0x7a, 0x8a, 0xaa, + 0x69, 0xd2, 0x9a, 0xc4, 0xc0, 0x57, 0x68, 0x0b, 0x83, + /* SETTINGS[0] */ + 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, + /* GOAWAY[0] */ + 0x00, 0x00, 0x08, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static uint16_t test_http_service_port = SERVER_PORT; +HTTP_SERVICE_DEFINE(test_http_service, MY_IPV4_ADDR, + &test_http_service_port, 1, 10, NULL); + +static const char index_html_gz[] = "Hello, World!"; +struct http_resource_detail_static index_html_gz_resource_detail = { + .common = { + .type = HTTP_RESOURCE_TYPE_STATIC, + .bitmask_of_supported_http_methods = BIT(HTTP_GET), + }, + .static_data = index_html_gz, + .static_data_len = sizeof(index_html_gz), +}; + +HTTP_RESOURCE_DEFINE(index_html_gz_resource, test_http_service, "/", + &index_html_gz_resource_detail); + +static void test_streams(void) +{ + int ret; + int client_fd; + int proto = IPPROTO_TCP; + char *ptr; + struct sockaddr_in sa; + static unsigned char buf[512]; + unsigned int length; + uint8_t type; + size_t offset; + uint32_t stream_id; + + zassert_ok(http_server_start(), "Failed to start the server"); + + ret = zsock_socket(AF_INET, SOCK_STREAM, proto); + zassert_not_equal(ret, -1, "failed to create client socket (%d)", errno); + client_fd = ret; + + sa.sin_family = AF_INET; + sa.sin_port = htons(SERVER_PORT); + + ret = zsock_inet_pton(AF_INET, MY_IPV4_ADDR, &sa.sin_addr.s_addr); + zassert_not_equal(-1, ret, "inet_pton() failed (%d)", errno); + zassert_not_equal(0, ret, "%s is not a valid IPv4 address", MY_IPV4_ADDR); + zassert_equal(1, ret, "inet_pton() failed to convert %s", MY_IPV4_ADDR); + + memset(buf, '\0', sizeof(buf)); + ptr = (char *)zsock_inet_ntop(AF_INET, &sa.sin_addr, buf, sizeof(buf)); + zassert_not_equal(ptr, NULL, "inet_ntop() failed (%d)", errno); + + ret = zsock_connect(client_fd, (struct sockaddr *)&sa, sizeof(sa)); + zassert_not_equal(ret, -1, "failed to connect (%d)", errno); + + ret = zsock_send(client_fd, frame, sizeof(frame), 0); + zassert_not_equal(ret, -1, "send() failed (%d)", errno); + + memset(buf, 0, sizeof(buf)); + offset = 0; + do { + ret = zsock_recv(client_fd, buf + offset, sizeof(buf) - offset, 0); + zassert_not_equal(ret, -1, "recv() failed (%d)", errno); + + offset += ret; + } while (ret > 0); + + /* Settings frame is expected twice (server settings + settings ACK) */ + length = (buf[0] << 16) | (buf[1] << 8) | buf[2]; + length += 9; + type = buf[3]; + stream_id = (buf[5] << 24) | (buf[6] << 16) | (buf[7] << 8) | buf[8]; + stream_id &= 0x7fffffff; + + zassert_true((type == 0x4 && stream_id == 0), + "Expected a SETTINGS frame with stream ID 0"); + zassert_true(offset > length, "Parsing error, buffer exceeded"); + + offset -= length; + memmove(buf, buf + length, offset); + + length = (buf[0] << 16) | (buf[1] << 8) | buf[2]; + length += 9; + type = buf[3]; + stream_id = (buf[5] << 24) | (buf[6] << 16) | (buf[7] << 8) | buf[8]; + stream_id &= 0x7fffffff; + + zassert_true((type == 0x4 && stream_id == 0), + "Expected a SETTINGS frame with stream ID 0"); + zassert_true(offset > length, "Parsing error, buffer exceeded"); + + offset -= length; + memmove(buf, buf + length, offset); + + length = (buf[0] << 16) | (buf[1] << 8) | buf[2]; + length += 9; + type = buf[3]; + stream_id = (buf[5] << 24) | (buf[6] << 16) | (buf[7] << 8) | buf[8]; + stream_id &= 0x7fffffff; + + zassert_true((type == 0x1 && stream_id == 1), + "Expected a HEADERS frame with stream ID 1, got %d", stream_id); + zassert_true(offset > length, "Parsing error, buffer exceeded"); + + offset -= length; + memmove(buf, buf + length, offset); + + length = (buf[0] << 16) | (buf[1] << 8) | buf[2]; + length += 9; + type = buf[3]; + stream_id = (buf[5] << 24) | (buf[6] << 16) | (buf[7] << 8) | buf[8]; + stream_id &= 0x7fffffff; + buf[9] = 0; + + zassert_true((type == 0x0 && stream_id == 1), + "Expected a DATA frame with stream ID 1, got %d", stream_id); + zassert_true(offset > length, "Parsing error, buffer exceeded"); + + offset -= length; + memmove(buf, buf + length, offset); + + length = (buf[0] << 16) | (buf[1] << 8) | buf[2]; + length += 9; + type = buf[3]; + stream_id = (buf[5] << 24) | (buf[6] << 16) | (buf[7] << 8) | buf[8]; + stream_id &= 0x7fffffff; + + zassert_true((type == 0x1 && stream_id == 3), + "Expected a HEADERS frame with stream ID 3"); + zassert_true(offset >= length, "Parsing error, buffer exceeded"); + + offset -= length; + memmove(buf, buf + length, offset); + + length = (buf[0] << 16) | (buf[1] << 8) | buf[2]; + length += 9; + type = buf[3]; + stream_id = (buf[5] << 24) | (buf[6] << 16) | (buf[7] << 8) | buf[8]; + stream_id &= 0x7fffffff; + + zassert_true((type == 0x0 && stream_id == 3), + "Expected a DATA frame with stream ID 3"); + + ret = zsock_close(client_fd); + zassert_not_equal(-1, ret, "close() failed on the client fd (%d)", errno); + + zassert_ok(http_server_stop(), "Failed to stop the server"); +} + +ZTEST(server_function_tests, test_http_concurrent_streams) +{ + test_streams(); +} + +static void test_common(int test_support) +{ + int ret; + int client_fd; + int proto = IPPROTO_TCP; + char *ptr; + struct sockaddr_in sa = { 0 }; + static unsigned char buf[512]; + + zassert_ok(http_server_start(), "Failed to start the server"); + + ret = zsock_socket(AF_INET, SOCK_STREAM, proto); + zassert_not_equal(ret, -1, "failed to create client socket (%d)", errno); + client_fd = ret; + + sa.sin_family = AF_INET; + sa.sin_port = htons(SERVER_PORT); + + ret = zsock_inet_pton(AF_INET, MY_IPV4_ADDR, &sa.sin_addr.s_addr); + zassert_not_equal(-1, ret, "inet_pton() failed (%d)", errno); + zassert_not_equal(0, ret, "%s is not a valid IPv4 address", MY_IPV4_ADDR); + zassert_equal(1, ret, "inet_pton() failed to convert %s", MY_IPV4_ADDR); + + memset(buf, '\0', sizeof(buf)); + ptr = (char *)zsock_inet_ntop(AF_INET, &sa.sin_addr, buf, sizeof(buf)); + zassert_not_equal(ptr, NULL, "inet_ntop() failed (%d)", errno); + + ret = zsock_connect(client_fd, (struct sockaddr *)&sa, sizeof(sa)); + zassert_not_equal(ret, -1, "failed to connect (%s/%d)", strerror(errno), errno); + + if (test_support == SUPPORT_BACKWARD_COMPATIBILITY) { + + char *http1_request = "GET / HTTP/1.1\r\n" + "Host: 127.0.0.1:8080\r\n" + "User-Agent: curl/7.68.0\r\n" + "Accept: */*\r\n" + "Accept-Encoding: deflate, gzip, br\r\n" + "\r\n"; + + ret = zsock_send(client_fd, http1_request, strlen(http1_request), 0); + zassert_not_equal(ret, -1, "send() failed (%d)", errno); + + char expected_response[] = "HTTP/1.1 200 OK\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 14\r\n" + "\r\n"; + + memset(buf, 0, sizeof(buf)); + ret = zsock_recv(client_fd, buf, sizeof(buf), 0); + zassert_not_equal(ret, -1, "recv() failed (%d)", errno); + + zassert_equal(strncmp(buf, expected_response, + strlen(expected_response)), 0, + "Received data doesn't match expected response"); + + } else if (test_support == SUPPORT_HTTP_SERVER_UPGRADE) { + + ret = zsock_send(client_fd, frame, sizeof(frame), 0); + zassert_not_equal(ret, -1, "send() failed (%d)", errno); + + memset(buf, 0, sizeof(buf)); + ret = zsock_recv(client_fd, buf, sizeof(buf), 0); + zassert_not_equal(ret, -1, "recv() failed (%d)", errno); + + uint8_t type = buf[3]; + + zassert_true(type == 0x4, "Expected a SETTINGS frame"); + } + + ret = zsock_close(client_fd); + zassert_not_equal(-1, ret, "close() failed on the client fd (%d)", errno); + + zassert_ok(http_server_stop(), "Failed to stop the server"); +} + +ZTEST(server_function_tests, test_http_upgrade) +{ + test_common(SUPPORT_HTTP_SERVER_UPGRADE); +} + +ZTEST(server_function_tests, test_backward_compatibility) +{ + test_common(SUPPORT_BACKWARD_COMPATIBILITY); +} + +ZTEST(server_function_tests, test_http_server_start_stop) +{ + struct sockaddr_in sa = { 0 }; + int client_fd; + int ret; + + sa.sin_family = AF_INET; + sa.sin_port = htons(SERVER_PORT); + + ret = zsock_inet_pton(AF_INET, MY_IPV4_ADDR, &sa.sin_addr.s_addr); + zassert_not_equal(-1, ret, "inet_pton() failed (%d)", errno); + zassert_not_equal(0, ret, "%s is not a valid IPv4 address", MY_IPV4_ADDR); + zassert_equal(1, ret, "inet_pton() failed to convert %s", MY_IPV4_ADDR); + + zassert_ok(http_server_start(), "Failed to start the server"); + zassert_not_ok(http_server_start(), "Server start should report na error."); + + zassert_ok(http_server_stop(), "Failed to stop the server"); + zassert_not_ok(http_server_stop(), "Server stop should report na error."); + + zassert_ok(http_server_start(), "Failed to start the server"); + + /* Server should be listening now. */ + ret = zsock_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + zassert_not_equal(ret, -1, "failed to create client socket (%d)", errno); + client_fd = ret; + + ret = zsock_connect(client_fd, (struct sockaddr *)&sa, sizeof(sa)); + zassert_not_equal(ret, -1, "failed to connect to the server (%d)", errno); + + ret = zsock_close(client_fd); + zassert_not_equal(-1, ret, "close() failed on the client fd (%d)", errno); + + zassert_ok(http_server_stop(), "Failed to stop the server"); +} + +ZTEST(server_function_tests, test_get_frame_type_name) +{ + zassert_equal(strcmp(get_frame_type_name(HTTP_SERVER_DATA_FRAME), "DATA"), 0, + "Unexpected frame type"); + zassert_equal(strcmp(get_frame_type_name(HTTP_SERVER_HEADERS_FRAME), "HEADERS"), 0, + "Unexpected frame type"); + zassert_equal(strcmp(get_frame_type_name(HTTP_SERVER_PRIORITY_FRAME), "PRIORITY"), 0, + "Unexpected frame type"); + zassert_equal(strcmp(get_frame_type_name(HTTP_SERVER_RST_STREAM_FRAME), "RST_STREAM"), 0, + "Unexpected frame type"); + zassert_equal(strcmp(get_frame_type_name(HTTP_SERVER_SETTINGS_FRAME), "SETTINGS"), 0, + "Unexpected frame type"); + zassert_equal(strcmp(get_frame_type_name(HTTP_SERVER_PUSH_PROMISE_FRAME), "PUSH_PROMISE"), + 0, "Unexpected frame type"); + zassert_equal(strcmp(get_frame_type_name(HTTP_SERVER_PING_FRAME), "PING"), 0, + "Unexpected frame type"); + zassert_equal(strcmp(get_frame_type_name(HTTP_SERVER_GOAWAY_FRAME), "GOAWAY"), 0, + "Unexpected frame type"); + zassert_equal(strcmp(get_frame_type_name(HTTP_SERVER_WINDOW_UPDATE_FRAME), "WINDOW_UPDATE"), + 0, "Unexpected frame type"); + zassert_equal(strcmp(get_frame_type_name(HTTP_SERVER_CONTINUATION_FRAME), "CONTINUATION"), + 0, "Unexpected frame type"); +} + +ZTEST(server_function_tests, test_parse_http_frames) +{ + static struct http_client_ctx ctx_client1; + static struct http_client_ctx ctx_client2; + struct http_frame *frame; + + unsigned char buffer1[] = { + 0x00, 0x00, 0x0c, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x64, 0x00, + 0x04, 0x00, 0x00, 0xff, 0xff, 0x00 + }; + unsigned char buffer2[] = { + 0x00, 0x00, 0x21, 0x01, 0x05, 0x00, 0x00, 0x00, + 0x01, 0x82, 0x84, 0x86, 0x41, 0x8a, 0x0b, 0xe2, + 0x5c, 0x0b, 0x89, 0x70, 0xdc, 0x78, 0x0f, 0x03, + 0x53, 0x03, 0x2a, 0x2f, 0x2a, 0x90, 0x7a, 0x8a, + 0xaa, 0x69, 0xd2, 0x9a, 0xc4, 0xc0, 0x57, 0x68, + 0x0b, 0x83 + }; + + memcpy(ctx_client1.buffer, buffer1, sizeof(buffer1)); + memcpy(ctx_client2.buffer, buffer2, sizeof(buffer2)); + + ctx_client1.cursor = ctx_client1.buffer; + ctx_client1.data_len = ARRAY_SIZE(buffer1); + + ctx_client2.cursor = ctx_client2.buffer; + ctx_client2.data_len = ARRAY_SIZE(buffer2); + + /* Test: Buffer with the first frame */ + int parser1 = parse_http_frame_header(&ctx_client1); + + zassert_equal(parser1, 1, "Failed to parse the first frame"); + + frame = &ctx_client1.current_frame; + + /* Validate frame details for the 1st frame */ + zassert_equal(frame->length, 0x0C, "Expected length for the 1st frame doesn't match"); + zassert_equal(frame->type, 0x04, "Expected type for the 1st frame doesn't match"); + zassert_equal(frame->flags, 0x00, "Expected flags for the 1st frame doesn't match"); + zassert_equal(frame->stream_identifier, 0x00, + "Expected stream_identifier for the 1st frame doesn't match"); + + /* Test: Buffer with the second frame */ + int parser2 = parse_http_frame_header(&ctx_client2); + + zassert_equal(parser2, 1, "Failed to parse the second frame"); + + frame = &ctx_client2.current_frame; + + /* Validate frame details for the 2nd frame */ + zassert_equal(frame->length, 0x21, "Expected length for the 2nd frame doesn't match"); + zassert_equal(frame->type, 0x01, "Expected type for the 2nd frame doesn't match"); + zassert_equal(frame->flags, 0x05, "Expected flags for the 2nd frame doesn't match"); + zassert_equal(frame->stream_identifier, 0x01, + "Expected stream_identifier for the 2nd frame doesn't match"); +} + +ZTEST_SUITE(server_function_tests, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/net/lib/http_server/prototype/testcase.yaml b/tests/net/lib/http_server/prototype/testcase.yaml new file mode 100644 index 00000000000..80d6c7e2651 --- /dev/null +++ b/tests/net/lib/http_server/prototype/testcase.yaml @@ -0,0 +1,16 @@ +common: + harness: net + min_ram: 80 + tags: + - http + - net + - server + - socket + integration_platforms: + - native_sim + - qemu_x86 + platform_exclude: + - native_posix + - native_posix/native/64 +tests: + net.http.server.prototype: {} diff --git a/tests/net/lib/http_server/tls/CMakeLists.txt b/tests/net/lib/http_server/tls/CMakeLists.txt new file mode 100644 index 00000000000..35f1805f63e --- /dev/null +++ b/tests/net/lib/http_server/tls/CMakeLists.txt @@ -0,0 +1,54 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(tls) + +set(BASE_PATH "../../../../../subsys/net/lib/http/") +include_directories(${BASE_PATH}/headers) + +set(gen_dir ${ZEPHYR_BINARY_DIR}/include/generated/) + +if (${CONFIG_TLS_CREDENTIALS}) + generate_inc_file_for_target( + app + ${ZEPHYR_BASE}/samples/net/sockets/http_server/src/ca.der + ${gen_dir}/ca.inc + ) + + generate_inc_file_for_target( + app + ${ZEPHYR_BASE}/samples/net/sockets/http_server/src/server.der + ${gen_dir}/server.inc + ) + + generate_inc_file_for_target( + app + ${ZEPHYR_BASE}/samples/net/sockets/http_server/src/server_privkey.der + ${gen_dir}/server_privkey.inc + ) + + # we reuse the same certificate / private key for client + # since it seems to be the only one that is signed by a ca + generate_inc_file_for_target( + app + ${ZEPHYR_BASE}/samples/net/sockets/http_server/src/server.der + ${gen_dir}/client.inc + ) + + generate_inc_file_for_target( + app + ${ZEPHYR_BASE}/samples/net/sockets/http_server/src/server_privkey.der + ${gen_dir}/client_privkey.inc + ) +endif() + +set(source_file_index src/index.html) +generate_inc_file_for_target(app ${source_file_index} ${gen_dir}/index.html.inc) +generate_inc_file_for_target(app ${source_file_index} ${gen_dir}/index.html.gz.inc --gzip) + +FILE(GLOB app_sources src/main.c) +target_sources(app PRIVATE ${app_sources}) + +zephyr_linker_sources(SECTIONS sections-rom.ld) +zephyr_iterable_section(NAME http_resource_desc_test_http_service KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) diff --git a/tests/net/lib/http_server/tls/prj.conf b/tests/net/lib/http_server/tls/prj.conf new file mode 100644 index 00000000000..997a3b64264 --- /dev/null +++ b/tests/net/lib/http_server/tls/prj.conf @@ -0,0 +1,61 @@ +# General config +CONFIG_ZTEST=y +CONFIG_NET_TEST=y + +CONFIG_ENTROPY_GENERATOR=y +CONFIG_TEST_RANDOM_GENERATOR=y +CONFIG_FDTABLE=y +CONFIG_EVENTFD=y +CONFIG_POSIX_API=y + +# Networking config +CONFIG_NETWORKING=y +CONFIG_NET_LOOPBACK=y +CONFIG_NET_LOOPBACK_MTU=1280 +CONFIG_NET_DRIVERS=y +CONFIG_NET_IPV4=y +CONFIG_NET_IPV6=y +CONFIG_NET_TCP=y +CONFIG_NET_SOCKETS=y + +# Logging / Debugging options +CONFIG_NET_LOG=y + +# TLS Options +CONFIG_TLS_CREDENTIALS=y +CONFIG_NET_SOCKETS_SOCKOPT_TLS=y +CONFIG_TLS_MAX_CREDENTIALS_NUMBER=5 +CONFIG_MBEDTLS_ENABLE_HEAP=y +CONFIG_MBEDTLS_HEAP_SIZE=60000 +CONFIG_MBEDTLS=y +CONFIG_MBEDTLS_BUILTIN=y +CONFIG_MBEDTLS_SSL_MAX_CONTENT_LEN=2048 +CONFIG_NET_SOCKETS_TLS_MAX_CONTEXTS=6 + +# Network buffers / packets / sizes +CONFIG_NET_BUF_TX_COUNT=128 +CONFIG_NET_BUF_RX_COUNT=128 +CONFIG_NET_PKT_TX_COUNT=16 +CONFIG_NET_PKT_RX_COUNT=16 +CONFIG_POSIX_MAX_FDS=32 +CONFIG_NET_SOCKETS_POLL_MAX=32 +CONFIG_POSIX_MAX_FDS=32 +CONFIG_REQUIRES_FULL_LIBC=y +CONFIG_EVENTFD_MAX=10 +CONFIG_NET_MAX_CONTEXTS=10 +CONFIG_NET_MAX_CONN=10 + +# Stack sizes +CONFIG_MAIN_STACK_SIZE=2048 +CONFIG_ZTEST_STACK_SIZE=4096 + +# JSON +CONFIG_JSON_LIBRARY=y + +# HTTP parser +CONFIG_HTTP_PARSER_URL=y +CONFIG_HTTP_PARSER=y +CONFIG_HTTP_SERVER=y + +# Network address config +CONFIG_NET_CONFIG_SETTINGS=n diff --git a/tests/net/lib/http_server/tls/sections-rom.ld b/tests/net/lib/http_server/tls/sections-rom.ld new file mode 100644 index 00000000000..512251641b2 --- /dev/null +++ b/tests/net/lib/http_server/tls/sections-rom.ld @@ -0,0 +1,3 @@ +#include + +ITERABLE_SECTION_ROM(http_resource_desc_test_http_service, 4) diff --git a/tests/net/lib/http_server/tls/src/index.html b/tests/net/lib/http_server/tls/src/index.html new file mode 100644 index 00000000000..7f82a1e3975 --- /dev/null +++ b/tests/net/lib/http_server/tls/src/index.html @@ -0,0 +1,10 @@ + + + + My Simple Server + + +

Welcome to my simple server!

+

This is a simple HTML file.

+ + diff --git a/tests/net/lib/http_server/tls/src/main.c b/tests/net/lib/http_server/tls/src/main.c new file mode 100644 index 00000000000..34c5c8fe7f0 --- /dev/null +++ b/tests/net/lib/http_server/tls/src/main.c @@ -0,0 +1,265 @@ +/* + * Copyright (c) 2023, Emna Rekik + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "server_internal.h" +#include +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(net_test, CONFIG_NET_SOCKETS_LOG_LEVEL); + +/** @brief Stack size for the server thread */ +#define STACK_SIZE 8192 + +#define MY_IPV4_ADDR "127.0.0.1" + +/** @brief arbitrary timeout value in ms */ +#define TIMEOUT 1000 + +#define BUFFER_SIZE 256 +#define SERVER_PORT 8000 + +enum tls_tag { + /** The Certificate Authority public key */ + CA_CERTIFICATE_TAG, + /** Used for both the public and private server keys */ + SERVER_CERTIFICATE_TAG, + /** Used for both the public and private client keys */ + CLIENT_CERTIFICATE_TAG, +}; + +static const sec_tag_t server_tag_list_verify[] = { + CA_CERTIFICATE_TAG, + SERVER_CERTIFICATE_TAG, +}; + +static uint16_t test_http_service_port = SERVER_PORT; +HTTPS_SERVICE_DEFINE(test_http_service, MY_IPV4_ADDR, &test_http_service_port, + 1, 10, NULL, server_tag_list_verify, + sizeof(server_tag_list_verify)); + +static const unsigned char ca[] = { +#include "ca.inc" +}; + +/** + * @brief The Server Certificate + * + * This is the public key of the server. + */ +static const unsigned char server[] = { +#include "server.inc" +}; + +/** + * @brief The Server Private Key + * + * This is the private key of the server. + */ +static const unsigned char server_privkey[] = { +#include "server_privkey.inc" +}; + +/** + * @brief The Client Certificate + * + * This is the public key of the client. + */ +static const unsigned char client[] = { +#include "client.inc" +}; + +/** + * @brief The Client Private Key + * + * This is the private key of the client. + */ +static const unsigned char client_privkey[] = { +#include "client_privkey.inc" +}; + +static const unsigned char index_html_gz[] = { +#include "index.html.gz.inc" +}; + +static const unsigned char compressed_inc_file[] = { + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0xff, 0x35, 0x8e, 0xc1, 0x0a, 0xc2, 0x30, + 0x0c, 0x86, 0xef, 0x7d, 0x8a, 0xec, 0x05, 0x2c, + 0xbb, 0x87, 0x5c, 0x54, 0xf0, 0xe0, 0x50, 0x58, + 0x41, 0x3c, 0x4e, 0x17, 0x69, 0x21, 0xa5, 0x65, + 0x2d, 0x42, 0xdf, 0xde, 0xba, 0x6e, 0x21, 0x10, + 0xf8, 0xf9, 0xbe, 0x9f, 0x60, 0x77, 0xba, 0x1d, + 0xcd, 0xf3, 0x7e, 0x06, 0x9b, 0xbd, 0x90, 0xc2, + 0xfd, 0xf0, 0x34, 0x93, 0x82, 0x3a, 0x98, 0x5d, + 0x16, 0xa6, 0xa1, 0xc0, 0xe8, 0x7c, 0x14, 0x86, + 0x91, 0x97, 0x2f, 0x2f, 0xa8, 0x5b, 0xae, 0x50, + 0x37, 0x16, 0x5f, 0x61, 0x2e, 0x9b, 0x62, 0x7b, + 0x7a, 0xb0, 0xbc, 0x83, 0x67, 0xc8, 0x01, 0x7c, + 0x81, 0xd4, 0xd4, 0xb4, 0xaa, 0x5d, 0x55, 0xfa, + 0x8d, 0x8c, 0x64, 0xac, 0x4b, 0x50, 0x77, 0xda, + 0xa1, 0x8b, 0x19, 0xae, 0xf0, 0x71, 0xc2, 0x07, + 0xd4, 0xf1, 0xdf, 0xdf, 0x8a, 0xab, 0xb4, 0xbe, + 0xf6, 0x03, 0xea, 0x2d, 0x11, 0x5c, 0xb2, 0x00, + 0x00, 0x00, +}; + +struct http_resource_detail_static index_html_gz_resource_detail = { + .common = { + .type = HTTP_RESOURCE_TYPE_STATIC, + .bitmask_of_supported_http_methods = BIT(HTTP_GET), + }, + .static_data = index_html_gz, + .static_data_len = sizeof(index_html_gz), +}; + +HTTP_RESOURCE_DEFINE(index_html_gz_resource, test_http_service, "/", + &index_html_gz_resource_detail); + +static void test_tls(void) +{ + int ret, recv_len; + int client_fd; + int proto = IPPROTO_TCP; + size_t len; + char *ptr; + const char *data; + struct sockaddr_in sa; + static unsigned char buf[512]; + char http1_request[] = + "GET / HTTP/1.1\r\n" + "Host: 127.0.0.1:8080\r\n" + "Accept: */*\r\n" + "Accept-Encoding: deflate, gzip, br\r\n" + "\r\n"; + + /* set the common protocol for both client and server */ + if (IS_ENABLED(CONFIG_NET_SOCKETS_SOCKOPT_TLS)) { + proto = IPPROTO_TLS_1_2; + } + + zassert_ok(http_server_start(), "Failed to start the server"); + + ret = zsock_socket(AF_INET, SOCK_STREAM, proto); + zassert_not_equal(ret, -1, "failed to create client socket (%d)", errno); + client_fd = ret; + + if (IS_ENABLED(CONFIG_TLS_CREDENTIALS) && + IS_ENABLED(CONFIG_NET_SOCKETS_SOCKOPT_TLS)) { + static const sec_tag_t sec_tag_list_verify_none[] = { + CA_CERTIFICATE_TAG, + }; + const sec_tag_t *sec_tag_list; + size_t sec_tag_list_size; + + sec_tag_list_size = sizeof(sec_tag_list); + sec_tag_list = sec_tag_list_verify_none; + + ret = zsock_setsockopt(client_fd, SOL_TLS, TLS_SEC_TAG_LIST, + sec_tag_list, sec_tag_list_size); + zassert_not_equal(ret, -1, "failed to set TLS_SEC_TAG_LIST (%d)", errno); + + ret = zsock_setsockopt(client_fd, SOL_TLS, TLS_HOSTNAME, + "localhost", sizeof("localhost")); + zassert_not_equal(ret, -1, "failed to set TLS_HOSTNAME (%d)", errno); + } + + sa.sin_family = AF_INET; + sa.sin_port = htons(SERVER_PORT); + + ret = zsock_inet_pton(AF_INET, MY_IPV4_ADDR, &sa.sin_addr.s_addr); + zassert_not_equal(-1, ret, "inet_pton() failed (%d)", errno); + zassert_not_equal(ret, 0, "%s is not a valid IPv4 address", MY_IPV4_ADDR); + zassert_equal(ret, 1, "inet_pton() failed to convert %s", MY_IPV4_ADDR); + + memset(buf, '\0', sizeof(buf)); + ptr = (char *)zsock_inet_ntop(AF_INET, &sa.sin_addr, buf, sizeof(buf)); + zassert_not_equal(ptr, NULL, "inet_ntop() failed (%d)", errno); + + ret = zsock_connect(client_fd, (struct sockaddr *)&sa, sizeof(sa)); + zassert_not_equal(ret, -1, "failed to connect (%d)", errno); + + ret = zsock_send(client_fd, http1_request, sizeof(http1_request) - 1, 0); + zassert_not_equal(ret, -1, "send() failed (%d)", errno); + zassert_equal(ret, sizeof(http1_request) - 1, "expected: %zu actual: %d", + sizeof(http1_request) - 1, ret); + + memset(buf, 0, sizeof(buf)); + recv_len = zsock_recv(client_fd, buf, sizeof(buf), 0); + zassert_not_equal(recv_len, -1, "recv() failed (%d)", errno); + + len = sizeof(index_html_gz); + + while (recv_len < len) { + ret = zsock_recv(client_fd, buf + recv_len, sizeof(buf) - recv_len, 0); + zassert_not_equal(ret, -1, "recv() failed (%d)", errno); + + recv_len += ret; + } + + data = strstr(buf, "\r\n\r\n"); + zassert_not_null(data, "Header not found"); + + data += 4; + + zassert_equal(len, sizeof(compressed_inc_file), "Invalid compressed file size"); + + ret = memcmp(data, compressed_inc_file, len); + zassert_equal(ret, 0, + "inc_file and compressed_inc_file contents are not identical (%d)", ret); + + ret = zsock_close(client_fd); + zassert_not_equal(ret, -1, "close() failed on the client fd (%d)", errno); + + zassert_ok(http_server_stop(), "Failed to stop the server"); +} + +ZTEST(framework_tests_tls, test_tls) +{ + test_tls(); +} + +static void *setup(void) +{ + int ret; + + if (IS_ENABLED(CONFIG_TLS_CREDENTIALS)) { + NET_DBG("Loading credentials"); + ret = tls_credential_add(CA_CERTIFICATE_TAG, + TLS_CREDENTIAL_CA_CERTIFICATE, + ca, sizeof(ca)); + zassert_equal(ret, 0, "failed to add CA Certificate (%d)", ret); + + ret = tls_credential_add(SERVER_CERTIFICATE_TAG, + TLS_CREDENTIAL_SERVER_CERTIFICATE, + server, sizeof(server)); + zassert_equal(ret, 0, "failed to add Server Certificate (%d)", ret); + + ret = tls_credential_add(SERVER_CERTIFICATE_TAG, + TLS_CREDENTIAL_PRIVATE_KEY, + server_privkey, sizeof(server_privkey)); + zassert_equal(ret, 0, "failed to add Server Private Key (%d)", ret); + + ret = tls_credential_add(CLIENT_CERTIFICATE_TAG, + TLS_CREDENTIAL_SERVER_CERTIFICATE, + client, sizeof(client)); + zassert_equal(ret, 0, "failed to add Client Certificate (%d)", ret); + + ret = tls_credential_add(CLIENT_CERTIFICATE_TAG, + TLS_CREDENTIAL_PRIVATE_KEY, + client_privkey, sizeof(client_privkey)); + zassert_equal(ret, 0, "failed to add Client Private Key (%d)", ret); + } + + return NULL; +} + +ZTEST_SUITE(framework_tests_tls, NULL, setup, NULL, NULL, NULL); diff --git a/tests/net/lib/http_server/tls/testcase.yaml b/tests/net/lib/http_server/tls/testcase.yaml new file mode 100644 index 00000000000..13f6ded54d1 --- /dev/null +++ b/tests/net/lib/http_server/tls/testcase.yaml @@ -0,0 +1,19 @@ +common: + harness: net + min_ram: 192 + tags: + - http + - net + - server + - socket + integration_platforms: + - native_sim + - qemu_x86 + platform_exclude: + - native_posix + - native_posix/native/64 + platform_allow: + - native_sim + - qemu_x86 +tests: + net.http.server.tls: {} diff --git a/tests/net/lib/lwm2m/block_transfer/src/main.c b/tests/net/lib/lwm2m/block_transfer/src/main.c index 3ec4eb3bed6..1323b5ad10e 100644 --- a/tests/net/lib/lwm2m/block_transfer/src/main.c +++ b/tests/net/lib/lwm2m/block_transfer/src/main.c @@ -11,7 +11,8 @@ /* Declaration of 'private' function */ int prepare_msg_for_send(struct lwm2m_message *msg); -int build_msg_block_for_send(struct lwm2m_message *msg, uint16_t block_num); +int build_msg_block_for_send(struct lwm2m_message *msg, uint16_t block_num, + enum coap_block_size block_size); int request_output_block_ctx(struct coap_block_context **ctx); void release_output_block_ctx(struct coap_block_context ** const ctx); @@ -270,7 +271,7 @@ ZTEST_F(net_block_transfer, test_build_blocks_for_send_exactly_2_blocks) "Last byte in payload wrong"); /* block 1 */ - ret = build_msg_block_for_send(msg, 1); + ret = build_msg_block_for_send(msg, 1, COAP_BLOCK_64); zassert_equal(ret, 0, "Could not create second block"); ret = coap_get_option_int(&msg->cpkt, COAP_OPTION_BLOCK1); @@ -285,7 +286,7 @@ ZTEST_F(net_block_transfer, test_build_blocks_for_send_exactly_2_blocks) "Last byte in payload wrong"); /* block 2 doesn't exist */ - ret = build_msg_block_for_send(msg, 2); + ret = build_msg_block_for_send(msg, 2, COAP_BLOCK_64); zassert_equal(ret, -EINVAL, "Could not create second block"); } @@ -346,7 +347,7 @@ ZTEST_F(net_block_transfer, test_build_blocks_for_send_more_than_2_blocks) "Last byte in payload wrong"); /* block 1 */ - ret = build_msg_block_for_send(msg, 1); + ret = build_msg_block_for_send(msg, 1, COAP_BLOCK_64); zassert_equal(ret, 0, "Could not create second block"); ret = coap_get_option_int(&msg->cpkt, COAP_OPTION_BLOCK1); @@ -361,7 +362,7 @@ ZTEST_F(net_block_transfer, test_build_blocks_for_send_more_than_2_blocks) "Last byte in payload wrong"); /* block 2 */ - ret = build_msg_block_for_send(msg, 2); + ret = build_msg_block_for_send(msg, 2, COAP_BLOCK_64); zassert_equal(ret, 0, "Could not create second block"); ret = coap_get_option_int(&msg->cpkt, COAP_OPTION_BLOCK1); @@ -374,7 +375,7 @@ ZTEST_F(net_block_transfer, test_build_blocks_for_send_more_than_2_blocks) zassert_equal(0x80, payload[0], "First (and only) byte in payload wrong"); /* block 3 doesn't exist */ - ret = build_msg_block_for_send(msg, 3); + ret = build_msg_block_for_send(msg, 3, COAP_BLOCK_64); zassert_equal(ret, -EINVAL, "Could not create second block"); } diff --git a/tests/net/lib/lwm2m/interop/prj.conf b/tests/net/lib/lwm2m/interop/prj.conf index 6115e6f40e3..e5de79a39d3 100644 --- a/tests/net/lib/lwm2m/interop/prj.conf +++ b/tests/net/lib/lwm2m/interop/prj.conf @@ -21,12 +21,16 @@ CONFIG_LWM2M_SHELL=y CONFIG_LWM2M_TICKLESS=y CONFIG_NET_SOCKETPAIR=y -#Enable Portfolio object +#Enable test objects CONFIG_LWM2M_PORTFOLIO_OBJ_SUPPORT=y +CONFIG_LWM2M_BINARYAPPDATA_OBJ_SUPPORT=y +CONFIG_LWM2M_FIRMWARE_UPDATE_OBJ_SUPPORT=y +CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_SUPPORT=y #LwM2M v1.1 configure CONFIG_LWM2M_VERSION_1_1=y CONFIG_LWM2M_DTLS_SUPPORT=y +CONFIG_LWM2M_DTLS_CID=y CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP=y #Enable SenML JSON content format @@ -36,7 +40,7 @@ CONFIG_LWM2M_RW_SENML_JSON_SUPPORT=y #Enable SenML CBOR content format CONFIG_LWM2M_RW_SENML_CBOR_SUPPORT=y -CONFIG_LWM2M_RW_SENML_CBOR_RECORDS=40 +CONFIG_LWM2M_RW_SENML_CBOR_RECORDS=60 CONFIG_ZCBOR_CANONICAL=y #Enable legacy content formats @@ -57,6 +61,7 @@ CONFIG_LWM2M_QUEUE_MODE_ENABLED=y CONFIG_LWM2M_QUEUE_MODE_UPTIME=20 CONFIG_LWM2M_UPDATE_PERIOD=30 CONFIG_LWM2M_RD_CLIENT_STOP_POLLING_AT_IDLE=y +CONFIG_LWM2M_SECONDS_TO_UPDATE_EARLY=1 # LwM2M configuration as OMA-ETS-LightweightM2M_INT-V1_1-20190912-D Configuration 3 CONFIG_LWM2M_ENGINE_DEFAULT_LIFETIME=30 @@ -65,6 +70,7 @@ CONFIG_LWM2M_SERVER_DEFAULT_PMAX=10 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 @@ -90,11 +96,11 @@ CONFIG_MBEDTLS_SSL_DTLS_CONNECTION_ID=y # MTU - IPv6 header - UDP header - DTLS header - CoAP header room # 1280 - 40 - 8 - 21 - 48 CONFIG_LWM2M_COAP_MAX_MSG_SIZE=1163 -CONFIG_LWM2M_COAP_BLOCK_SIZE=1024 +CONFIG_LWM2M_COAP_BLOCK_SIZE=512 CONFIG_LWM2M_COAP_BLOCK_TRANSFER=y -CONFIG_LWM2M_COAP_ENCODE_BUFFER_SIZE=4096 -CONFIG_LWM2M_NUM_OUTPUT_BLOCK_CONTEXT=1 -CONFIG_LWM2M_NUM_BLOCK1_CONTEXT=1 +CONFIG_LWM2M_COAP_ENCODE_BUFFER_SIZE=8192 +CONFIG_LWM2M_NUM_OUTPUT_BLOCK_CONTEXT=2 +CONFIG_LWM2M_NUM_BLOCK1_CONTEXT=2 CONFIG_SYS_HASH_FUNC32=y CONFIG_LWM2M_ENGINE_VALIDATION_BUFFER_SIZE=0 CONFIG_LWM2M_ENGINE_MAX_PENDING=2 diff --git a/tests/net/lib/lwm2m/interop/pytest/leshan.py b/tests/net/lib/lwm2m/interop/pytest/leshan.py index 181f15ebf61..198c3fc2880 100644 --- a/tests/net/lib/lwm2m/interop/pytest/leshan.py +++ b/tests/net/lib/lwm2m/interop/pytest/leshan.py @@ -156,6 +156,8 @@ def _type_to_string(cls, value): return 'integer' if isinstance(value, datetime): return 'time' + if isinstance(value, bytes): + return 'opaque' return 'string' @classmethod @@ -163,6 +165,8 @@ def _convert_type(cls, value): """Wrapper for special types that are not understood by Json""" if isinstance(value, datetime): return int(value.timestamp()) + elif isinstance(value, bytes): + return binascii.b2a_hex(value).decode() else: return value diff --git a/tests/net/lib/lwm2m/interop/pytest/test_blockwise.py b/tests/net/lib/lwm2m/interop/pytest/test_blockwise.py new file mode 100644 index 00000000000..27bece69f1e --- /dev/null +++ b/tests/net/lib/lwm2m/interop/pytest/test_blockwise.py @@ -0,0 +1,133 @@ +""" +Tests for Block-Wise transfers in LwM2M +####################################### + +Copyright (c) 2024 Nordic Semiconductor ASA + +SPDX-License-Identifier: Apache-2.0 + + +""" + +import time +import logging +import zlib +import re +import random +import string +import binascii +from leshan import Leshan + +from twister_harness import Shell +from twister_harness import DeviceAdapter + +logger = logging.getLogger(__name__) + +def test_blockwise_1(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): + """Blockwise test 1: Block-Wise PUT using OPAQUE content format""" + + fw = b'1234567890' * 500 + fmt = leshan.format + to = leshan.timeout + leshan.format = 'OPAQUE' + leshan.timeout = 600 + leshan.write(endpoint, '5/0/0', fw) + # Our Firmware object prints out the CRC of the received firmware + # when Update is executed + leshan.execute(endpoint, '5/0/2') + lines = dut.readlines_until(regex='app_fw_update: UPDATE', timeout=5.0) + assert len(lines) > 0 + line = lines[-1] + crc = int(re.search('CRC ([0-9]+)', line).group(1)) + # Verify that CRC matches + assert crc == zlib.crc32(fw) + leshan.format = fmt + leshan.timeout = to + +def test_blockwise_2(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): + """Blockwise test 2: Block-Wise PUT with retry""" + + fw = b'1234567890' * 500 + fmt = leshan.format + to = leshan.timeout + leshan.format = 'OPAQUE' + # Set timeout to 1 second to force Leshan to stop sending + leshan.timeout = 1 + try: + leshan.write(endpoint, '5/0/0', fw) + except Exception as e: + logger.debug(f'Caught exception: {e}') + shell.exec_command('lwm2m update') + time.sleep(1) + # Now send the firmware again using longer timeout + leshan.timeout = 600 + leshan.write(endpoint, '5/0/0', fw) + # Our Firmware object prints out the CRC of the received firmware + # when Update is executed + leshan.execute(endpoint, '5/0/2') + lines = dut.readlines_until(regex='app_fw_update: UPDATE', timeout=5.0) + assert len(lines) > 0 + line = lines[-1] + crc = int(re.search('CRC ([0-9]+)', line).group(1)) + # Verify that CRC matches + assert crc == zlib.crc32(fw) + leshan.format = fmt + leshan.timeout = to + + +def test_blockwise_3(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): + """Blockwise test 3: Block-Wise Get using TLV and SenML-CBOR content formats""" + + shell.exec_command('lwm2m create /19/0') + + # Generate 4 kB of binary app-data + # and write it into BinaryAppData object + data = ''.join(random.choice(string.ascii_letters) for i in range(4096)).encode() + fmt = leshan.format + to = leshan.timeout + leshan.format = 'OPAQUE' + leshan.timeout = 600 + leshan.write(endpoint, '19/0/0/0', data) + + # Verify data is correctly transferred + lines = shell.get_filtered_output(shell.exec_command('lwm2m read /19/0/0/0 -crc32')) + crc = int(lines[0]) + assert crc == zlib.crc32(data) + + # Try reading the data using different content formats + for fmt in ['TLV', 'SENML_CBOR']: + leshan.format = fmt + data = leshan.read(endpoint, '19/0/0') + data = binascii.a2b_hex(data[0][0]) + assert crc == zlib.crc32(data) + + leshan.format = fmt + leshan.timeout = to + shell.exec_command('lwm2m delete /19/0') + +def test_blockwise_4(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): + """Blockwise test 4: Block-Wise SEND using SenML-CBOR content format""" + + shell.exec_command('lwm2m create /19/0') + # Generate 4 kB of binary app-data + data = ''.join(random.choice(string.ascii_letters) for i in range(4096)).encode() + fmt = leshan.format + to = leshan.timeout + leshan.format = 'OPAQUE' + leshan.timeout = 600 + leshan.write(endpoint, '19/0/0/0', data) + leshan.format = 'SENML_CBOR' + + # Execute SEND and verify that correct data is received + with leshan.get_event_stream(endpoint) as events: + shell.exec_command('lwm2m send /19/0') + dut.readlines_until(regex=r'.*SEND status: 0', timeout=5.0) + send = events.next_event('SEND') + assert send is not None + content = binascii.a2b_hex(send[19][0][0][0]) + assert zlib.crc32(content) == zlib.crc32(data) + + leshan.format = fmt + leshan.timeout = to + + shell.exec_command('lwm2m delete /19/0') diff --git a/tests/net/lib/lwm2m/interop/src/firmware_update.c b/tests/net/lib/lwm2m/interop/src/firmware_update.c new file mode 100644 index 00000000000..7ed44093dbd --- /dev/null +++ b/tests/net/lib/lwm2m/interop/src/firmware_update.c @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define LOG_MODULE_NAME app_fw_update +#define LOG_LEVEL LOG_LEVEL_DBG +#include +LOG_MODULE_REGISTER(LOG_MODULE_NAME); + +#include +#include +#include "lwm2m_engine.h" + +static uint8_t firmware_buf[64]; +static uint32_t crc; + +/* Array with supported PULL firmware update protocols */ +static uint8_t supported_protocol[1]; + +static int firmware_update_cb(uint16_t obj_inst_id, + uint8_t *args, uint16_t args_len) +{ + LOG_INF("UPDATE, (CRC %u)", crc); + + lwm2m_set_u8(&LWM2M_OBJ(5, 0, 3), STATE_IDLE); + lwm2m_set_u8(&LWM2M_OBJ(5, 0, 5), RESULT_SUCCESS); + return 0; +} + +static void *firmware_get_buf(uint16_t obj_inst_id, uint16_t res_id, + uint16_t res_inst_id, size_t *data_len) +{ + *data_len = sizeof(firmware_buf); + return firmware_buf; +} + +static int firmware_block_received_cb(uint16_t obj_inst_id, uint16_t res_id, + uint16_t res_inst_id, uint8_t *data, + uint16_t data_len, bool last_block, + size_t total_size, size_t offset) +{ + if (offset == 0) { + crc = crc32_ieee(data, data_len); + } else { + crc = crc32_ieee_update(crc, data, data_len); + } + LOG_INF("FIRMWARE: BLOCK RECEIVED: offset:%zd len:%u last_block:%d crc: %u", + offset, data_len, last_block, crc); + + /* Add extra delay so short block-wise may timeout */ + k_sleep(K_MSEC(100)); + return 0; +} + +static int firmware_cancel_cb(const uint16_t obj_inst_id) +{ + LOG_INF("FIRMWARE: Update canceled"); + return 0; +} + +static int init_firmware_update(void) +{ + /* setup data buffer for block-wise transfer */ + lwm2m_register_pre_write_callback(&LWM2M_OBJ(5, 0, 0), firmware_get_buf); + lwm2m_firmware_set_write_cb(firmware_block_received_cb); + + /* register cancel callback */ + lwm2m_firmware_set_cancel_cb(firmware_cancel_cb); + lwm2m_firmware_set_update_cb(firmware_update_cb); + + lwm2m_create_res_inst(&LWM2M_OBJ(5, 0, 8, 0)); + lwm2m_set_res_buf(&LWM2M_OBJ(5, 0, 8, 0), &supported_protocol[0], + sizeof(supported_protocol[0]), + sizeof(supported_protocol[0]), 0); + + return 0; +} +LWM2M_APP_INIT(init_firmware_update); diff --git a/tests/net/lib/lwm2m/interop/src/lwm2m-client.c b/tests/net/lib/lwm2m/interop/src/lwm2m-client.c index cb4ab22acd2..bc668c15c3c 100644 --- a/tests/net/lib/lwm2m/interop/src/lwm2m-client.c +++ b/tests/net/lib/lwm2m/interop/src/lwm2m-client.c @@ -88,6 +88,18 @@ int set_socketoptions(struct lwm2m_ctx *ctx) return lwm2m_set_default_sockopt(ctx); } +static int create_appdata(uint16_t obj_inst_id) +{ + /* Create BinaryAppData object */ + static uint8_t data[4096]; + static char description[16]; + + lwm2m_set_res_buf(&LWM2M_OBJ(19, 0, 0, 0), data, sizeof(data), 0, 0); + lwm2m_set_res_buf(&LWM2M_OBJ(19, 0, 3), description, sizeof(description), 0, 0); + + return 0; +} + static int lwm2m_setup(void) { /* setup DEVICE object */ @@ -118,6 +130,8 @@ static int lwm2m_setup(void) lwm2m_create_res_inst(&LWM2M_OBJ(3, 0, 8, 1)); lwm2m_set_res_buf(&LWM2M_OBJ(3, 0, 8, 1), &usb_ma, sizeof(usb_ma), sizeof(usb_ma), 0); + lwm2m_register_create_callback(19, create_appdata); + return 0; } diff --git a/tests/net/lib/lwm2m/lwm2m_registry/src/lwm2m_registry.c b/tests/net/lib/lwm2m/lwm2m_registry/src/lwm2m_registry.c index 68056c5389b..b6178abb17f 100644 --- a/tests/net/lib/lwm2m/lwm2m_registry/src/lwm2m_registry.c +++ b/tests/net/lib/lwm2m/lwm2m_registry/src/lwm2m_registry.c @@ -23,10 +23,10 @@ static void *pre_write_cb(uint16_t obj_inst_id, return pre_write_cb_buf; } -static int post_write_cb(uint16_t obj_inst_id, - uint16_t res_id, uint16_t res_inst_id, - uint8_t *data, uint16_t data_len, - bool last_block, size_t total_size) +static int post_write_cb(uint16_t obj_inst_id, uint16_t res_id, + uint16_t res_inst_id, uint8_t *data, + uint16_t data_len, bool last_block, + size_t total_size, size_t offset) { callback_checker |= 0x02; return 0; @@ -41,10 +41,9 @@ static void *read_cb(uint16_t obj_inst_id, return 0; } -static int validate_cb(uint16_t obj_inst_id, - uint16_t res_id, uint16_t res_inst_id, - uint8_t *data, uint16_t data_len, - bool last_block, size_t total_size) +static int validate_cb(uint16_t obj_inst_id, uint16_t res_id, + uint16_t res_inst_id, uint8_t *data, uint16_t data_len, + bool last_block, size_t total_size, size_t offset) { callback_checker |= 0x08; return 0; @@ -599,11 +598,17 @@ ZTEST(lwm2m_registry, test_null_strings) ZTEST(lwm2m_registry, test_obj_version) { - +#if defined(CONFIG_LWM2M_ENGINE_ALWAYS_REPORT_OBJ_VERSION) + zassert_true(lwm2m_engine_shall_report_obj_version(lwm2m_engine_get_obj(&LWM2M_OBJ(0)))); + zassert_true( + lwm2m_engine_shall_report_obj_version(lwm2m_engine_get_obj(&LWM2M_OBJ(32768)))); + zassert_true(lwm2m_engine_shall_report_obj_version(lwm2m_engine_get_obj(&LWM2M_OBJ(3303)))); +#else zassert_false(lwm2m_engine_shall_report_obj_version(lwm2m_engine_get_obj(&LWM2M_OBJ(0)))); zassert_false( lwm2m_engine_shall_report_obj_version(lwm2m_engine_get_obj(&LWM2M_OBJ(32768)))); zassert_true(lwm2m_engine_shall_report_obj_version(lwm2m_engine_get_obj(&LWM2M_OBJ(3303)))); +#endif } ZTEST(lwm2m_registry, test_resource_cache) diff --git a/tests/net/lib/lwm2m/lwm2m_registry/testcase.yaml b/tests/net/lib/lwm2m/lwm2m_registry/testcase.yaml index a994dd72ad8..a318fe6e0d9 100644 --- a/tests/net/lib/lwm2m/lwm2m_registry/testcase.yaml +++ b/tests/net/lib/lwm2m/lwm2m_registry/testcase.yaml @@ -7,3 +7,13 @@ tests: - net integration_platforms: - native_sim + net.lwm2m.lwm2m_registry.always_report_obj_version: + platform_key: + - simulation + tags: + - lwm2m + - net + integration_platforms: + - native_sim + extra_configs: + - CONFIG_LWM2M_ENGINE_ALWAYS_REPORT_OBJ_VERSION=y diff --git a/tests/net/lib/mdns_responder/prj.conf b/tests/net/lib/mdns_responder/prj.conf index f7c6945827c..6d4db394c8d 100644 --- a/tests/net/lib/mdns_responder/prj.conf +++ b/tests/net/lib/mdns_responder/prj.conf @@ -5,6 +5,7 @@ CONFIG_NET_DRIVERS=y CONFIG_NET_LOOPBACK=y CONFIG_NET_IPV4=y CONFIG_NET_IPV6=y +CONFIG_NET_SOCKETS_POLL_MAX=7 # Network driver config CONFIG_TEST_RANDOM_GENERATOR=y @@ -28,3 +29,4 @@ CONFIG_NET_UDP=y CONFIG_NET_UDP_CHECKSUM=n CONFIG_NET_PKT_RX_COUNT=16 CONFIG_NET_PKT_TX_COUNT=16 +CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=4 diff --git a/tests/net/lib/mdns_responder/testcase.yaml b/tests/net/lib/mdns_responder/testcase.yaml index ae9f6d9dbf2..aabe426bdd0 100644 --- a/tests/net/lib/mdns_responder/testcase.yaml +++ b/tests/net/lib/mdns_responder/testcase.yaml @@ -3,6 +3,9 @@ common: - dns - net depends_on: netif + platform_exclude: + - native_posix/native/64 + - native_posix tests: net.mdns: min_ram: 21 diff --git a/tests/net/lib/tls_credentials/testcase.yaml b/tests/net/lib/tls_credentials/testcase.yaml index 042a59405a8..77e3ac8f283 100644 --- a/tests/net/lib/tls_credentials/testcase.yaml +++ b/tests/net/lib/tls_credentials/testcase.yaml @@ -10,5 +10,5 @@ tests: tags: - net - tls - - trusted - depends_on: netif + - tfm + - trusted-firmware-m diff --git a/tests/net/mld/prj.conf b/tests/net/mld/prj.conf index 06e5cd0d23c..8030ffb7910 100644 --- a/tests/net/mld/prj.conf +++ b/tests/net/mld/prj.conf @@ -20,6 +20,8 @@ CONFIG_NET_BUF_RX_COUNT=20 CONFIG_NET_BUF_TX_COUNT=20 CONFIG_NET_MGMT=y CONFIG_NET_MGMT_EVENT=y +CONFIG_NET_MGMT_EVENT_INFO=y CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=4 -CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=5 +CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=8 CONFIG_NET_SOCKETS=y +CONFIG_NET_IF_MAX_IPV6_COUNT=2 diff --git a/tests/net/mld/src/main.c b/tests/net/mld/src/main.c index 9ca53f6bf31..e1bcce056cf 100644 --- a/tests/net/mld/src/main.c +++ b/tests/net/mld/src/main.c @@ -32,8 +32,10 @@ LOG_MODULE_REGISTER(net_test, CONFIG_NET_IPV6_LOG_LEVEL); #include "icmpv6.h" #include "ipv6.h" +#include "route.h" #define THREAD_SLEEP 50 /* ms */ +#define MLD_REPORT_ADDR_COUNT 8 #define NET_LOG_ENABLED 1 #include "net_private.h" @@ -44,6 +46,25 @@ LOG_MODULE_REGISTER(net_test, CONFIG_NET_IPV6_LOG_LEVEL); #define DBG(fmt, ...) #endif +struct mld_report_mcast_record { + uint8_t record_type; + uint8_t aux_data_len; + uint16_t num_of_sources; + struct in6_addr mcast_addr; +} __packed; + +struct mld_report_info { + uint16_t records_count; + struct mld_report_mcast_record records[MLD_REPORT_ADDR_COUNT]; +}; + +typedef void (*mld_report_callback)(struct net_pkt *pkt, void *user_data); + +struct mld_report_handler { + mld_report_callback fn; + void *user_data; +}; + static struct in6_addr my_addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1 } } }; static struct in6_addr peer_addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, @@ -51,6 +72,7 @@ static struct in6_addr peer_addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, static struct in6_addr mcast_addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1 } } }; +static struct in6_addr *exp_mcast_group; static struct net_if *net_iface; static bool is_group_joined; static bool is_group_left; @@ -59,7 +81,12 @@ static bool is_leave_msg_ok; static bool is_query_received; static bool is_report_sent; static bool ignore_already; + +static struct mld_report_handler *report_handler; + K_SEM_DEFINE(wait_data, 0, UINT_MAX); +K_SEM_DEFINE(wait_joined, 0, UINT_MAX); +K_SEM_DEFINE(wait_left, 0, UINT_MAX); #define WAIT_TIME 500 #define WAIT_TIME_LONG MSEC_PER_SEC @@ -130,19 +157,47 @@ static int tester_send(const struct device *dev, struct net_pkt *pkt) is_leave_msg_ok = true; is_report_sent = true; + if (report_handler) { + report_handler->fn(pkt, report_handler->user_data); + } + k_sem_give(&wait_data); } return 0; } +static int tester_null_send(const struct device *dev, struct net_pkt *pkt) +{ + ARG_UNUSED(dev); + ARG_UNUSED(pkt); + + return 0; +} + struct net_test_mld net_test_data; +struct net_test_mld net_test_null_data; static struct dummy_api net_test_if_api = { .iface_api.init = net_test_iface_init, .send = tester_send, }; +static void init_null_iface(struct net_if *iface) +{ + struct net_test_mld *context = iface->if_dev->dev->data; + + memset(&context->mac_addr, 0, sizeof(context->mac_addr)); + + net_if_set_link_addr(iface, context->mac_addr, sizeof(struct net_eth_addr), + NET_LINK_ETHERNET); +} + +static struct dummy_api net_test_null_if_api = { + .iface_api.init = init_null_iface, + .send = tester_null_send, +}; + #define _ETH_L2_LAYER DUMMY_L2 #define _ETH_L2_CTX_TYPE NET_L2_GET_CTX_TYPE(DUMMY_L2) @@ -152,6 +207,35 @@ NET_DEVICE_INIT(net_test_mld, "net_test_mld", &net_test_if_api, _ETH_L2_LAYER, _ETH_L2_CTX_TYPE, 127); +/* Interface without a device or API, only for usage of `struct net_if` */ +NET_DEVICE_INIT(net_test_null_iface, "net_test_null_iface", net_test_dev_init, NULL, + &net_test_null_data, NULL, 99, &net_test_null_if_api, _ETH_L2_LAYER, + _ETH_L2_CTX_TYPE, 127); + +static void test_iface_down_up(void) +{ + zassert_ok(net_if_down(net_iface), "Failed to bring iface down"); + k_msleep(10); + zassert_ok(net_if_up(net_iface), "Failed to bring iface up"); +} + +static void test_iface_down_up_delayed_carrier(void) +{ + zassert_ok(net_if_down(net_iface), "Failed to bring iface down"); + k_msleep(10); + net_if_carrier_off(net_iface); + zassert_ok(net_if_up(net_iface), "Failed to bring iface up"); + k_msleep(10); + net_if_carrier_on(net_iface); +} + +static void test_iface_carrier_off_on(void) +{ + net_if_carrier_off(net_iface); + k_msleep(10); + net_if_carrier_on(net_iface); +} + static void group_joined(struct net_mgmt_event_callback *cb, uint32_t nm_event, struct net_if *iface) { @@ -160,9 +244,12 @@ static void group_joined(struct net_mgmt_event_callback *cb, return; } - is_group_joined = true; + if (exp_mcast_group == NULL || + net_ipv6_addr_cmp(exp_mcast_group, cb->info)) { + is_group_joined = true; - k_sem_give(&wait_data); + k_sem_give(&wait_joined); + } } static void group_left(struct net_mgmt_event_callback *cb, @@ -173,9 +260,12 @@ static void group_left(struct net_mgmt_event_callback *cb, return; } - is_group_left = true; + if (exp_mcast_group == NULL || + net_ipv6_addr_cmp(exp_mcast_group, cb->info)) { + is_group_left = true; - k_sem_give(&wait_data); + k_sem_give(&wait_left); + } } static struct mgmt_events { @@ -219,6 +309,14 @@ static void *test_mld_setup(void) return NULL; } +static void test_mld_before(void *fixture) +{ + ARG_UNUSED(fixture); + + report_handler = NULL; + exp_mcast_group = NULL; +} + static void test_join_group(void) { int ret; @@ -260,7 +358,7 @@ static void test_catch_join_group(void) test_join_group(); - if (k_sem_take(&wait_data, K_MSEC(WAIT_TIME))) { + if (k_sem_take(&wait_joined, K_MSEC(WAIT_TIME))) { zassert_true(0, "Timeout while waiting join event"); } @@ -277,7 +375,7 @@ static void test_catch_leave_group(void) test_leave_group(); - if (k_sem_take(&wait_data, K_MSEC(WAIT_TIME))) { + if (k_sem_take(&wait_left, K_MSEC(WAIT_TIME))) { zassert_true(0, "Timeout while waiting leave event"); } @@ -296,7 +394,7 @@ static void test_verify_join_group(void) test_join_group(); - if (k_sem_take(&wait_data, K_MSEC(WAIT_TIME))) { + if (k_sem_take(&wait_joined, K_MSEC(WAIT_TIME))) { zassert_true(0, "Timeout while waiting join event"); } @@ -313,7 +411,7 @@ static void test_verify_leave_group(void) test_leave_group(); - if (k_sem_take(&wait_data, K_MSEC(WAIT_TIME))) { + if (k_sem_take(&wait_left, K_MSEC(WAIT_TIME))) { zassert_true(0, "Timeout while waiting leave event"); } @@ -539,6 +637,82 @@ ZTEST(net_mld_test_suite, test_allnodes) "allnodes multicast address"); } +static void expect_exclude_mcast_report(struct net_pkt *pkt, void *user_data) +{ + struct mld_report_mcast_record record; + uint16_t records_count; + uint16_t res_bytes; + bool *report_sent = user_data; + + zassert_not_null(exp_mcast_group, "Expected mcast group not sent"); + + net_pkt_set_overwrite(pkt, true); + net_pkt_skip(pkt, sizeof(struct net_icmp_hdr)); + + zassert_ok(net_pkt_read_be16(pkt, &res_bytes), "Failed to read reserved bytes"); + zassert_equal(0, res_bytes, "Reserved bytes must be zeroed"); + + zassert_ok(net_pkt_read_be16(pkt, &records_count), "Failed to read addr count"); + zexpect_equal(records_count, 1, "Incorrect record count "); + + net_pkt_read(pkt, &record, sizeof(struct mld_report_mcast_record)); + + if (record.record_type == NET_IPV6_MLDv2_CHANGE_TO_EXCLUDE_MODE && + net_ipv6_addr_cmp_raw((const uint8_t *)exp_mcast_group, + (const uint8_t *)&record.mcast_addr)) { + *report_sent = true; + } +} + +static void verify_allnodes_on_iface_event(void (*action)(void)) +{ + struct net_if *iface = NULL; + struct net_if_mcast_addr *ifmaddr; + struct in6_addr addr; + bool exclude_report_sent = false; + struct mld_report_handler handler = { + .fn = expect_exclude_mcast_report, + .user_data = &exclude_report_sent + }; + + net_ipv6_addr_create_ll_allnodes_mcast(&addr); + k_sem_reset(&wait_joined); + + is_group_joined = false; + exp_mcast_group = &addr; + report_handler = &handler; + + action(); + + zassert_ok(k_sem_take(&wait_joined, K_MSEC(WAIT_TIME)), + "Timeout while waiting for an event"); + + ifmaddr = net_if_ipv6_maddr_lookup(&addr, &iface); + zassert_not_null(ifmaddr, "Interface does not contain " + "allnodes multicast address"); + + zassert_true(is_group_joined, "Did not join mcast group"); + zassert_true(exclude_report_sent, "Did not send report"); +} + +/* Verify that mcast all nodes is present after interface admin state toggle */ +ZTEST(net_mld_test_suite, test_allnodes_after_iface_up) +{ + verify_allnodes_on_iface_event(test_iface_down_up); +} + +/* Verify that mcast all nodes is present after delayed carrier on */ +ZTEST(net_mld_test_suite, test_allnodes_after_iface_up_carrier_delayed) +{ + verify_allnodes_on_iface_event(test_iface_down_up_delayed_carrier); +} + +/* Verify that mcast all nodes is present after carrier toggle */ +ZTEST(net_mld_test_suite, test_allnodes_after_carrier_toggle) +{ + verify_allnodes_on_iface_event(test_iface_carrier_off_on); +} + ZTEST(net_mld_test_suite, test_solicit_node) { struct net_if *iface = NULL; @@ -553,6 +727,55 @@ ZTEST(net_mld_test_suite, test_solicit_node) "solicit node multicast address"); } +static void verify_solicit_node_on_iface_event(void (*action)(void)) +{ + struct net_if *iface = NULL; + struct net_if_mcast_addr *ifmaddr; + struct in6_addr addr; + bool exclude_report_sent = false; + struct mld_report_handler handler = { + .fn = expect_exclude_mcast_report, + .user_data = &exclude_report_sent + }; + + net_ipv6_addr_create_solicited_node(&my_addr, &addr); + k_sem_reset(&wait_joined); + + is_group_joined = false; + exp_mcast_group = &addr; + report_handler = &handler; + + action(); + + zassert_ok(k_sem_take(&wait_joined, K_MSEC(WAIT_TIME)), + "Timeout while waiting for an event"); + + ifmaddr = net_if_ipv6_maddr_lookup(&addr, &iface); + zassert_not_null(ifmaddr, "Interface does not contain " + "solicit node multicast address"); + + zassert_true(is_group_joined, "Did not join mcast group"); + zassert_true(exclude_report_sent, "Did not send report"); +} + +/* Verify that mcast solicited node is present after interface admin state toggle */ +ZTEST(net_mld_test_suite, test_solicit_node_after_iface_up) +{ + verify_solicit_node_on_iface_event(test_iface_down_up); +} + +/* Verify that mcast solicited node is present after delayed carrier on */ +ZTEST(net_mld_test_suite, test_solicit_node_after_iface_up_carrier_delayed) +{ + verify_solicit_node_on_iface_event(test_iface_down_up_delayed_carrier); +} + +/* Verify that mcast solicited node is present after delayed carrier toggle */ +ZTEST(net_mld_test_suite, test_solicit_node_after_carrier_toggle) +{ + verify_solicit_node_on_iface_event(test_iface_carrier_off_on); +} + ZTEST(net_mld_test_suite, test_join_leave) { test_join_group(); @@ -604,6 +827,197 @@ ZTEST(net_mld_test_suite, test_no_mld_flag) net_if_flag_clear(net_iface, NET_IF_IPV6_NO_MLD); } +static void handle_mld_report(struct net_pkt *pkt, void *user_data) +{ + struct mld_report_info *info = (struct mld_report_info *)user_data; + uint16_t res_bytes; + + net_pkt_set_overwrite(pkt, true); + net_pkt_skip(pkt, sizeof(struct net_icmp_hdr)); + + zassert_ok(net_pkt_read_be16(pkt, &res_bytes), "Failed to read reserved bytes"); + zassert_equal(0, res_bytes, "Reserved bytes must be zeroed"); + + zassert_ok(net_pkt_read_be16(pkt, &info->records_count), "Failed to read addr count"); + zexpect_between_inclusive(info->records_count, 0, MLD_REPORT_ADDR_COUNT, + "Cannot decode all addresses"); + + for (size_t i = 0; i < info->records_count; ++i) { + net_pkt_read(pkt, &info->records[i], sizeof(struct mld_report_mcast_record)); + } +} + +static size_t get_mcast_addr_count(struct net_if *iface) +{ + size_t ret = 0; + + ARRAY_FOR_EACH_PTR(iface->config.ip.ipv6->mcast, mcast_addr) { + if (mcast_addr->is_used) { + ret++; + } + } + + return ret; +} + +static void add_mcast_route_and_verify(struct net_if *iface, struct in6_addr *addr, + struct mld_report_info *info) +{ + k_sem_reset(&wait_data); + + zassert_not_null(net_route_mcast_add(iface, addr, 128), "Failed to add multicast route"); + + k_msleep(THREAD_SLEEP); + + zassert_ok(k_sem_take(&wait_data, K_MSEC(WAIT_TIME)), "Timeout while waiting for a report"); + + zassert_equal(info->records_count, 1, "Invalid number of reported addresses"); + zassert_equal(info->records[0].record_type, NET_IPV6_MLDv2_CHANGE_TO_EXCLUDE_MODE, + "Invalid MLDv2 record type"); + zassert_mem_equal(&info->records[0].mcast_addr, addr, + sizeof(struct in6_addr), "Invalid reported address"); +} + +static void del_mcast_route_and_verify(struct net_if *iface, struct in6_addr *addr, + struct mld_report_info *info) +{ + struct net_route_entry_mcast *entry; + + k_sem_reset(&wait_data); + + entry = net_route_mcast_lookup(addr); + + zassert_not_null(entry, "Could not find the multicast route entry"); + zassert_true(net_route_mcast_del(entry), "Failed to delete a route"); + + k_msleep(THREAD_SLEEP); + + zassert_ok(k_sem_take(&wait_data, K_MSEC(WAIT_TIME)), "Timeout while waiting for a report"); + + zassert_equal(info->records_count, 1, "Invalid number of reported addresses"); + zassert_equal(info->records[0].record_type, NET_IPV6_MLDv2_CHANGE_TO_INCLUDE_MODE, + "Invalid MLDv2 record type"); + zassert_mem_equal(&info->records[0].mcast_addr, addr, + sizeof(struct in6_addr), "Invalid reported address"); +} + +static void verify_mcast_routes_in_mld(struct mld_report_info *info) +{ + struct net_if *dummy_iface = net_if_get_by_index(net_if_get_by_name("dummy0")); + struct net_if *null_iface = net_if_get_by_index(net_if_get_by_name("dummy1")); + struct in6_addr site_local_mcast_addr_abcd; + struct in6_addr site_local_mcast_addr_beef; + struct in6_addr site_local_mcast_addr_cafe; + + zassert_not_null(dummy_iface, "Invalid dummy iface"); + zassert_not_null(null_iface, "Invalid null iface"); + + net_if_flag_set(null_iface, NET_IF_FORWARD_MULTICASTS); + + net_ipv6_addr_create(&site_local_mcast_addr_abcd, 0xff05, 0, 0, 0, 0, 0, 0, 0xabcd); + net_ipv6_addr_create(&site_local_mcast_addr_beef, 0xff05, 0, 0, 0, 0, 0, 0, 0xbeef); + net_ipv6_addr_create(&site_local_mcast_addr_cafe, 0xff05, 0, 0, 0, 0, 0, 0, 0xcafe); + + /* Next steps: verify that adding a multicast routes to a complete IPv6 address emits + * MLDv2 reports with a single entries. + */ + add_mcast_route_and_verify(null_iface, &site_local_mcast_addr_abcd, info); + add_mcast_route_and_verify(null_iface, &site_local_mcast_addr_beef, info); + + /* Next steps: verify that report is not sent to an iface if it has already joined + * the group. + */ + zassert_ok(net_ipv6_mld_join(dummy_iface, &site_local_mcast_addr_cafe), + "Failed to join a group"); + + k_msleep(THREAD_SLEEP); + + k_sem_reset(&wait_data); + + zassert_not_null(net_route_mcast_add(null_iface, &site_local_mcast_addr_cafe, 128), + "Failed to add multicast route"); + + k_msleep(THREAD_SLEEP); + + zassert_equal(-EAGAIN, k_sem_take(&wait_data, K_MSEC(WAIT_TIME)), "Expected a timeout"); + + k_sem_reset(&wait_data); + + /* Verify that multicast routes can be found in MLDv2 report and that there are + * no duplicates. + */ + send_query(dummy_iface); + + k_msleep(THREAD_SLEEP); + + zassert_ok(k_sem_take(&wait_data, K_MSEC(WAIT_TIME)), "Expected a report"); + + /* Expect 2 additional addresses as 3rd is a duplicate of iface's multicast address */ + zassert_equal(info->records_count, get_mcast_addr_count(dummy_iface) + 2, + "Different number of reported addresses"); + + /* Next steps: Remove routes and expect MLDv2 reports as these addresses are not + * used by the interface. + */ + del_mcast_route_and_verify(dummy_iface, &site_local_mcast_addr_abcd, info); + del_mcast_route_and_verify(dummy_iface, &site_local_mcast_addr_beef, info); + + /* Next steps: Remove the last route and verify that report is NOT sent as this address + * is joined by the interface itself. + */ + k_sem_reset(&wait_data); + + zassert_true(net_route_mcast_del(net_route_mcast_lookup(&site_local_mcast_addr_cafe)), + "Failed to cleanup route to ff05::cafe"); + + k_msleep(THREAD_SLEEP); + + zassert_equal(-EAGAIN, k_sem_take(&wait_data, K_MSEC(WAIT_TIME)), "Expected a timeout"); + + /* Finalize cleanup */ + net_ipv6_mld_leave(dummy_iface, &site_local_mcast_addr_cafe); +} + +ZTEST(net_mld_test_suite, test_mcast_routes_in_mld) +{ + struct mld_report_info info; + struct mld_report_handler handler = { .fn = handle_mld_report, .user_data = &info}; + struct net_if *iface = net_if_get_first_by_type(&NET_L2_GET_NAME(DUMMY)); + char str[INET6_ADDRSTRLEN], *addr_str; + + memset(&info, 0, sizeof(info)); + + join_mldv2_capable_routers_group(); + + /* Enable report handler */ + report_handler = &handler; + + k_msleep(THREAD_SLEEP); + + k_sem_reset(&wait_data); + + send_query(iface); + + k_msleep(THREAD_SLEEP); + + zassert_ok(k_sem_take(&wait_data, K_MSEC(WAIT_TIME)), "Timeout while waiting for a report"); + + for (int i = 0; i < info.records_count; ++i) { + addr_str = zsock_inet_ntop(AF_INET6, &info.records[i].mcast_addr, str, sizeof(str)); + } + + /* 1. Expect that report contains all iface's multicast addressses and no route */ + zassert_equal(info.records_count, get_mcast_addr_count(iface), + "Different number of reported addresses"); + + /* 2. If CONFIG_NET_MCAST_ROUTE_MLD_REPORTS is enabled check that funtionality works */ + if (IS_ENABLED(CONFIG_NET_MCAST_ROUTE_MLD_REPORTS)) { + verify_mcast_routes_in_mld(&info); + } + + leave_mldv2_capable_routers_group(); +} + static void socket_group_with_index(const struct in6_addr *local_addr, bool do_join) { struct ipv6_mreq mreq = { 0 }; @@ -688,4 +1102,4 @@ ZTEST_USER(net_mld_test_suite, test_socket_catch_join_with_index) socket_leave_group_with_index(&my_addr); } -ZTEST_SUITE(net_mld_test_suite, NULL, test_mld_setup, NULL, NULL, NULL); +ZTEST_SUITE(net_mld_test_suite, NULL, test_mld_setup, test_mld_before, NULL, NULL); diff --git a/tests/net/mld/testcase.yaml b/tests/net/mld/testcase.yaml index 5367b669183..8bd91eeff3c 100644 --- a/tests/net/mld/testcase.yaml +++ b/tests/net/mld/testcase.yaml @@ -10,3 +10,8 @@ tests: net.mld.preempt: extra_configs: - CONFIG_NET_TC_THREAD_PREEMPTIVE=y + net.mld.mcast_routes: + extra_configs: + - CONFIG_NET_ROUTE_MCAST=y + - CONFIG_NET_MAX_MCAST_ROUTES=5 + - CONFIG_NET_MCAST_ROUTE_MLD_REPORTS=y diff --git a/tests/net/net_pkt/src/main.c b/tests/net/net_pkt/src/main.c index 73e20fba51a..7dd3f8fd716 100644 --- a/tests/net/net_pkt/src/main.c +++ b/tests/net/net_pkt/src/main.c @@ -1265,7 +1265,7 @@ ZTEST(net_pkt_test_suite, test_net_pkt_shallow_clone_append_buf_0) ZTEST(net_pkt_test_suite, test_net_pkt_shallow_clone_append_buf_1) { - test_net_pkt_shallow_clone_append_buf(2); + test_net_pkt_shallow_clone_append_buf(1); } ZTEST(net_pkt_test_suite, test_net_pkt_shallow_clone_append_buf_2) diff --git a/tests/net/ptp/clock/boards/frdm_k64f.overlay b/tests/net/ptp/clock/boards/frdm_k64f.overlay index baccbf8f044..147c7dd5bf7 100644 --- a/tests/net/ptp/clock/boards/frdm_k64f.overlay +++ b/tests/net/ptp/clock/boards/frdm_k64f.overlay @@ -4,9 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -&enet { - - ptp { - status = "ok"; - }; +&enet_ptp_clock { + status = "okay"; }; diff --git a/tests/net/route_mcast/prj.conf b/tests/net/route_mcast/prj.conf index c655d805cdb..406da69f4dd 100644 --- a/tests/net/route_mcast/prj.conf +++ b/tests/net/route_mcast/prj.conf @@ -23,3 +23,4 @@ CONFIG_NET_IPV6_MAX_NEIGHBORS=8 CONFIG_ZTEST=y CONFIG_NET_MAX_MCAST_ROUTES=10 CONFIG_NET_ROUTE_MCAST=y +CONFIG_NET_MCAST_ROUTE_MAX_IFACES=3 diff --git a/tests/net/route_mcast/src/main.c b/tests/net/route_mcast/src/main.c index 7b6eaab4f5f..3947b9e274c 100644 --- a/tests/net/route_mcast/src/main.c +++ b/tests/net/route_mcast/src/main.c @@ -648,6 +648,99 @@ static void test_route_mcast_scenario3(void) zassert_equal(forwarding_counter, 0, "wrong count forwarded packets"); } +void test_route_mcast_multiple_route_ifaces(void) +{ + /* + * Scenario: + * 1. Verify that multicast packet sent to site-local scoped address + * to the iface_3 is forwarded only to iface_2 as configured in + * test_route_mcast_route_add() test case. + * 2. Verify that interface without NET_IF_FORWARD_MULTICASTS flag + * enabled cannot be added to multicast routing entry. + * 3. Add iface_1 to multicast routing entry for site-local scope. + * 4. Verify that packet sent to the same scope as before is now + * forwarded also to iface_1. + * 5. Remove iface_1 from the multicast routing entry. + * 6. Verify that packet sent to the same scope is before is now + * NOT forwarded to iface_1 as it was removed from the list. + */ + struct net_route_entry_mcast *route; + bool res; + + reset_counters(); + memcpy(&active_scenario.src, &iface_3_addr, sizeof(struct in6_addr)); + active_scenario.src.s6_addr[15] = 0x02; + + memcpy(&active_scenario.mcast, &mcast_prefix_site_local, sizeof(struct in6_addr)); + active_scenario.mcast.s6_addr[15] = 0x01; + + struct net_pkt *pkt = setup_ipv6_udp(iface_3, &active_scenario.src, &active_scenario.mcast, + 20015, 20001); + + active_scenario.is_active = true; + if (net_recv_data(iface_3, pkt) < 0) { + net_pkt_unref(pkt); + zassert_true(0, "failed to receive initial packet!"); + } + k_sleep(WAIT_TIME); + net_pkt_unref(pkt); + active_scenario.is_active = false; + + zassert_true(iface_2_forwarded, "iface_2 did not forward"); + zassert_false(iface_1_forwarded, "iface_1 forwarded"); + zassert_false(iface_3_forwarded, "iface_3 forwarded"); + zassert_equal(forwarding_counter, 1, "unexpected forwarded packet count"); + + reset_counters(); + + route = net_route_mcast_lookup(&mcast_prefix_site_local); + zassert_not_null(route, "failed to find the route entry"); + + /* Add iface_1 to the entry */ + res = net_route_mcast_iface_add(route, iface_1); + zassert_true(res, "failed to add iface_1 to the entry"); + + struct net_pkt *pkt2 = setup_ipv6_udp(iface_3, &active_scenario.src, + &active_scenario.mcast, 215, 201); + + active_scenario.is_active = true; + if (net_recv_data(iface_3, pkt2) < 0) { + net_pkt_unref(pkt2); + zassert_true(0, "failed to receive initial packet!"); + } + k_sleep(WAIT_TIME); + net_pkt_unref(pkt2); + active_scenario.is_active = false; + + zassert_true(iface_2_forwarded, "iface_2 did not forward"); + zassert_true(iface_1_forwarded, "iface_1 did not forward"); + zassert_false(iface_3_forwarded, "iface_3 forwarded"); + zassert_equal(forwarding_counter, 2, "unexpected forwarded packet count"); + + reset_counters(); + + /* Remove iface_1 from the entry */ + res = net_route_mcast_iface_del(route, iface_1); + zassert_true(res, "failed to remove iface_1 from the entry"); + + struct net_pkt *pkt3 = setup_ipv6_udp(iface_3, &active_scenario.src, + &active_scenario.mcast, 215, 201); + + active_scenario.is_active = true; + if (net_recv_data(iface_3, pkt3) < 0) { + net_pkt_unref(pkt3); + zassert_true(0, "failed to receive initial packet!"); + } + k_sleep(WAIT_TIME); + net_pkt_unref(pkt3); + active_scenario.is_active = false; + + zassert_true(iface_2_forwarded, "iface_2 did not forward"); + zassert_false(iface_1_forwarded, "iface_1 forwarded"); + zassert_false(iface_3_forwarded, "iface_3 forwarded"); + zassert_equal(forwarding_counter, 1, "unexpected forwarded packet count"); +} + /*test case main entry*/ ZTEST(route_mcast_test_suite, test_route_mcast) { @@ -657,6 +750,7 @@ ZTEST(route_mcast_test_suite, test_route_mcast) test_route_mcast_scenario1(); test_route_mcast_scenario2(); test_route_mcast_scenario3(); + test_route_mcast_multiple_route_ifaces(); test_route_mcast_lookup(); test_route_mcast_route_del(); } diff --git a/tests/net/socket/getaddrinfo/prj.conf b/tests/net/socket/getaddrinfo/prj.conf index 7b98922798d..986f2515034 100644 --- a/tests/net/socket/getaddrinfo/prj.conf +++ b/tests/net/socket/getaddrinfo/prj.conf @@ -23,6 +23,7 @@ CONFIG_DNS_SERVER1="[::1]:15353" CONFIG_DNS_SERVER2="127.0.0.1:15353" CONFIG_MAIN_STACK_SIZE=2048 +CONFIG_ZTEST_STACK_SIZE=2048 CONFIG_ZTEST=y # User mode requirements diff --git a/tests/net/socket/getaddrinfo/testcase.yaml b/tests/net/socket/getaddrinfo/testcase.yaml index 3d7bb633703..14822401179 100644 --- a/tests/net/socket/getaddrinfo/testcase.yaml +++ b/tests/net/socket/getaddrinfo/testcase.yaml @@ -6,6 +6,9 @@ common: - socket - getaddrinfo - userspace + platform_exclude: + - native_posix + - native_posix/native/64 tests: net.socket.get_addr_info: min_ram: 21 diff --git a/tests/net/socket/getnameinfo/testcase.yaml b/tests/net/socket/getnameinfo/testcase.yaml index 9edc6b2502e..2e60ca44fe0 100644 --- a/tests/net/socket/getnameinfo/testcase.yaml +++ b/tests/net/socket/getnameinfo/testcase.yaml @@ -1,6 +1,9 @@ common: depends_on: netif filter: CONFIG_FULL_LIBC_SUPPORTED + platform_exclude: + - native_posix + - native_posix/native/64 tests: net.socket.get_name_info: min_ram: 21 diff --git a/tests/net/socket/poll/src/main.c b/tests/net/socket/poll/src/main.c index 7b5eac449d5..a155461514f 100644 --- a/tests/net/socket/poll/src/main.c +++ b/tests/net/socket/poll/src/main.c @@ -85,7 +85,6 @@ ZTEST(net_socket_poll, test_poll) tstamp); zassert_equal(res, 0, ""); - /* Send pkt for s_sock and poll with timeout of 10 */ len = zsock_send(c_sock, BUF_AND_SIZE(TEST_STR_SMALL), 0); zassert_equal(len, STRLEN(TEST_STR_SMALL), "invalid send len"); @@ -151,9 +150,6 @@ ZTEST(net_socket_poll, test_poll) zassert_equal(res, 1, ""); zassert_equal(pollout[0].revents, ZSOCK_POLLOUT, ""); - /* Let the network stack run */ - k_msleep(10); - res = zsock_close(c_sock_tcp); zassert_equal(res, 0, "close failed"); diff --git a/tests/net/socket/poll/testcase.yaml b/tests/net/socket/poll/testcase.yaml index 56ac475d13e..9d08909605e 100644 --- a/tests/net/socket/poll/testcase.yaml +++ b/tests/net/socket/poll/testcase.yaml @@ -3,7 +3,10 @@ common: # FIXME: This test fails very frequently on mps2/an385 due to the system # timer stability issues, so keep it disabled until the root cause # is fixed (GitHub issue zephyrproject-rtos/zephyr#48608). - platform_exclude: mps2/an385 + platform_exclude: + - mps2/an385 + - native_posix/native/64 + - native_posix tests: net.socket.poll: min_ram: 21 diff --git a/tests/net/socket/reuseaddr_reuseport/src/main.c b/tests/net/socket/reuseaddr_reuseport/src/main.c index c5e6cb4633f..5e0b95aa827 100644 --- a/tests/net/socket/reuseaddr_reuseport/src/main.c +++ b/tests/net/socket/reuseaddr_reuseport/src/main.c @@ -14,6 +14,7 @@ LOG_MODULE_REGISTER(net_test, CONFIG_NET_SOCKETS_LOG_LEVEL); #include #include +#include #include "../../socket_helpers.h" @@ -36,13 +37,15 @@ static void test_add_local_ip_address(sa_family_t family, const char *ip) { if (family == AF_INET) { struct sockaddr_in addr; + struct net_if_addr *ifaddr; zsock_inet_pton(AF_INET, ip, &addr.sin_addr); - zassert_not_null(net_if_ipv4_addr_add(net_if_get_default(), - &addr.sin_addr, - NET_ADDR_MANUAL, - 0), + ifaddr = net_if_ipv4_addr_add(net_if_get_default(), + &addr.sin_addr, + NET_ADDR_MANUAL, + 0); + zassert_not_null(ifaddr, "Cannot add IPv4 address %s", ip); } else if (family == AF_INET6) { struct sockaddr_in6 addr; @@ -102,16 +105,18 @@ static inline void prepare_sock_udp(sa_family_t family, const char *ip, uint16_t static void test_getsocketopt_reuseaddr(int sock, void *optval, socklen_t *optlen) { - zassert_equal(zsock_getsockopt(sock, SOL_SOCKET, SO_REUSEADDR, optval, optlen), - 0, - "getsocketopt() failed with error %d", errno); + int ret; + + ret = zsock_getsockopt(sock, SOL_SOCKET, SO_REUSEADDR, optval, optlen); + zassert_equal(ret, 0, "getsocketopt() failed with error %d", errno); } static void test_setsocketopt_reuseaddr(int sock, void *optval, socklen_t optlen) { - zassert_equal(zsock_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, optval, optlen), - 0, - "setsocketopt() failed with error %d", errno); + int ret; + + ret = zsock_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, optval, optlen); + zassert_equal(ret, 0, "setsocketopt() failed with error %d", errno); } static void test_enable_reuseaddr(int sock) @@ -123,16 +128,18 @@ static void test_enable_reuseaddr(int sock) static void test_getsocketopt_reuseport(int sock, void *optval, socklen_t *optlen) { - zassert_equal(zsock_getsockopt(sock, SOL_SOCKET, SO_REUSEPORT, optval, optlen), - 0, - "getsocketopt() failed with error %d", errno); + int ret; + + ret = zsock_getsockopt(sock, SOL_SOCKET, SO_REUSEPORT, optval, optlen); + zassert_equal(ret, 0, "getsocketopt() failed with error %d", errno); } static void test_setsocketopt_reuseport(int sock, void *optval, socklen_t optlen) { - zassert_equal(zsock_setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, optval, optlen), - 0, - "setsocketopt() failed with error %d", errno); + int ret; + + ret = zsock_setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, optval, optlen); + zassert_equal(ret, 0, "setsocketopt() failed with error %d", errno); } static void test_enable_reuseport(int sock) @@ -144,16 +151,18 @@ static void test_enable_reuseport(int sock) static void test_bind_success(int sock, const struct sockaddr *addr, socklen_t addrlen) { - zassert_equal(zsock_bind(sock, addr, addrlen), - 0, - "bind() failed with error %d", errno); + int ret; + + ret = zsock_bind(sock, addr, addrlen); + zassert_equal(ret, 0, "bind() failed with error %d", errno); } static void test_bind_fail(int sock, const struct sockaddr *addr, socklen_t addrlen) { - zassert_equal(zsock_bind(sock, addr, addrlen), - -1, - "bind() succeeded incorrectly"); + int ret; + + ret = zsock_bind(sock, addr, addrlen); + zassert_equal(ret, -1, "bind() succeeded incorrectly"); zassert_equal(errno, EADDRINUSE, "bind() returned unexpected errno (%d)", errno); } @@ -167,9 +176,10 @@ static void test_listen(int sock) static void test_connect_success(int sock, const struct sockaddr *addr, socklen_t addrlen) { - zassert_equal(zsock_connect(sock, addr, addrlen), - 0, - "connect() failed with error %d", errno); + int ret; + + ret = zsock_connect(sock, addr, addrlen); + zassert_equal(ret, 0, "connect() failed with error %d", errno); if (IS_ENABLED(CONFIG_NET_TC_THREAD_PREEMPTIVE)) { /* Let the connection proceed */ @@ -179,9 +189,10 @@ static void test_connect_success(int sock, const struct sockaddr *addr, socklen_ static void test_connect_fail(int sock, const struct sockaddr *addr, socklen_t addrlen) { - zassert_equal(zsock_connect(sock, addr, addrlen), - -1, - "connect() succeeded incorrectly"); + int ret; + + ret = zsock_connect(sock, addr, addrlen); + zassert_equal(ret, -1, "connect() succeeded incorrectly"); zassert_equal(errno, EADDRINUSE, "connect() returned unexpected errno (%d)", errno); } @@ -198,41 +209,46 @@ static int test_accept(int sock, struct sockaddr *addr, socklen_t *addrlen) static void test_sendto(int sock, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen) { - zassert_equal(zsock_sendto(sock, buf, len, flags, dest_addr, addrlen), - len, - "sendto failed with error %d", errno); + int ret; + + ret = zsock_sendto(sock, buf, len, flags, dest_addr, addrlen); + zassert_equal(ret, len, "sendto failed with error %d", errno); } static void test_recvfrom_success(int sock, void *buf, size_t max_len, int flags, struct sockaddr *src_addr, socklen_t *addrlen) { - zassert_equal(zsock_recvfrom(sock, buf, max_len, flags, src_addr, addrlen), - max_len, - "recvfrom failed with error %d", errno); + int ret; + + ret = zsock_recvfrom(sock, buf, max_len, flags, src_addr, addrlen); + zassert_equal(ret, max_len, "recvfrom failed with error %d", errno); } static void test_recvfrom_fail(int sock, void *buf, size_t max_len, int flags, struct sockaddr *src_addr, socklen_t *addrlen) { - zassert_equal(zsock_recvfrom(sock, buf, max_len, flags, src_addr, addrlen), - -1, - "recvfrom succeeded incorrectly"); + int ret; + + ret = zsock_recvfrom(sock, buf, max_len, flags, src_addr, addrlen); + zassert_equal(ret, -1, "recvfrom succeeded incorrectly"); zassert_equal(errno, EAGAIN, "recvfrom() returned unexpected errno (%d)", errno); } static void test_recv_success(int sock, void *buf, size_t max_len, int flags) { - zassert_equal(zsock_recv(sock, buf, max_len, flags), - max_len, - "recv failed with error %d", errno); + int ret; + + ret = zsock_recv(sock, buf, max_len, flags); + zassert_equal(ret, max_len, "recv failed with error %d", errno); } static void test_recv_fail(int sock, void *buf, size_t max_len, int flags) { - zassert_equal(zsock_recv(sock, buf, max_len, flags), - -1, - "recvfrom succeeded incorrectly"); + int ret; + + ret = zsock_recv(sock, buf, max_len, flags); + zassert_equal(ret, -1, "recvfrom succeeded incorrectly"); zassert_equal(errno, EAGAIN, "recv() returned unexpected errno (%d)", errno); } diff --git a/tests/net/socket/socketpair/prj.conf b/tests/net/socket/socketpair/prj.conf index 177d9c991c4..fd15cb5309d 100644 --- a/tests/net/socket/socketpair/prj.conf +++ b/tests/net/socket/socketpair/prj.conf @@ -7,6 +7,7 @@ CONFIG_NET_IPV4=y CONFIG_NET_SOCKETS=y CONFIG_NET_SOCKETPAIR=y CONFIG_NET_SOCKETPAIR_BUFFER_SIZE=64 +CONFIG_POSIX_MAX_FDS=10 # Network driver config CONFIG_TEST_RANDOM_GENERATOR=y diff --git a/tests/net/socket/socketpair/src/_main.c b/tests/net/socket/socketpair/src/_main.c index ff8027b0982..118d8be1209 100644 --- a/tests/net/socket/socketpair/src/_main.c +++ b/tests/net/socket/socketpair/src/_main.c @@ -4,8 +4,12 @@ * SPDX-License-Identifier: Apache-2.0 */ +#define _main_defined 1 + #include "_main.h" +LOG_MODULE_REGISTER(net_test, CONFIG_NET_SOCKETS_LOG_LEVEL); + #include #include #include diff --git a/tests/net/socket/socketpair/src/_main.h b/tests/net/socket/socketpair/src/_main.h index f6df1a267f9..d1dbe939b15 100644 --- a/tests/net/socket/socketpair/src/_main.h +++ b/tests/net/socket/socketpair/src/_main.h @@ -16,7 +16,9 @@ #include #include +#if !defined(_main_defined) LOG_MODULE_DECLARE(net_test, CONFIG_NET_SOCKETS_LOG_LEVEL); +#endif struct net_socketpair_fixture { int sv[2]; diff --git a/tests/net/socket/socketpair/testcase.yaml b/tests/net/socket/socketpair/testcase.yaml index bb906c29d0c..133f2801b95 100644 --- a/tests/net/socket/socketpair/testcase.yaml +++ b/tests/net/socket/socketpair/testcase.yaml @@ -5,19 +5,22 @@ common: - userspace depends_on: netif min_ram: 21 + platform_exclude: + - native_posix/native/64 + - native_posix + # See #61246 for info about these next two excludes + - vmu_rt1170/mimxrt1176/cm7 + - mimxrt1160_evk/mimxrt1166/cm7 tests: - net.socket.socketpair: - platform_exclude: vmu_rt1170/mimxrt1176/cm7 mimxrt1160_evk/mimxrt1166/cm7 # See #61246 + net.socket.socketpair: {} net.socket.socketpair.newlib: filter: CONFIG_FULL_LIBC_SUPPORTED extra_configs: - CONFIG_REQUIRES_FULL_LIBC=y - platform_exclude: vmu_rt1170/mimxrt1176/cm7 mimxrt1160_evk/mimxrt1166/cm7 # See #61246 net.socket.socketpair.picolibc: filter: CONFIG_PICOLIBC_SUPPORTED extra_configs: - CONFIG_PICOLIBC=y - platform_exclude: vmu_rt1170/mimxrt1176/cm7 mimxrt1160_evk/mimxrt1166/cm7 # See #61246 net.socket.socketpair.high_mem: min_ram: 64 extra_configs: @@ -25,4 +28,3 @@ tests: # fail due to insufficient memory. So, use high buffer sizes. - CONFIG_NET_SOCKETPAIR_BUFFER_SIZE=4096 - CONFIG_HEAP_MEM_POOL_SIZE=32768 - platform_exclude: vmu_rt1170/mimxrt1176/cm7 mimxrt1160_evk/mimxrt1166/cm7 # See #61246 diff --git a/tests/net/socket/tcp/src/main.c b/tests/net/socket/tcp/src/main.c index a4295b74f1d..5ac3599ca1b 100644 --- a/tests/net/socket/tcp/src/main.c +++ b/tests/net/socket/tcp/src/main.c @@ -9,6 +9,7 @@ LOG_MODULE_REGISTER(net_test, CONFIG_NET_SOCKETS_LOG_LEVEL); #include #include +#include #include #include diff --git a/tests/net/socket/tls/prj.conf b/tests/net/socket/tls/prj.conf index 1b0c9485aee..94fb56a7142 100644 --- a/tests/net/socket/tls/prj.conf +++ b/tests/net/socket/tls/prj.conf @@ -47,3 +47,4 @@ CONFIG_ZTEST_STACK_SIZE=3072 CONFIG_MBEDTLS_ENABLE_HEAP=y CONFIG_MBEDTLS_HEAP_SIZE=18000 CONFIG_MBEDTLS_KEY_EXCHANGE_PSK_ENABLED=y +CONFIG_MBEDTLS_MAC_ALL_ENABLED=y diff --git a/tests/net/socket/tls/src/main.c b/tests/net/socket/tls/src/main.c index 59bad541f1c..f532060f8f5 100644 --- a/tests/net/socket/tls/src/main.c +++ b/tests/net/socket/tls/src/main.c @@ -842,6 +842,7 @@ ZTEST(net_socket_tls, test_close_while_accept) zassert_equal(errno, EINTR, "Unexpected errno value: %d", errno); test_work_wait(&close_work_data.work); + k_sleep(TCP_TEARDOWN_TIMEOUT); } ZTEST(net_socket_tls, test_close_while_recv) @@ -1057,6 +1058,7 @@ ZTEST(net_socket_tls, test_accept_non_block) zassert_equal(errno, EAGAIN, "Unexpected errno value: %d", errno); test_sockets_close(); + k_sleep(TCP_TEARDOWN_TIMEOUT); } ZTEST(net_socket_tls, test_accept_invalid_handshake_data) @@ -1081,6 +1083,7 @@ ZTEST(net_socket_tls, test_accept_invalid_handshake_data) zassert_equal(errno, ECONNABORTED, "Unexpected errno value: %d", errno); test_sockets_close(); + k_sleep(TCP_TEARDOWN_TIMEOUT); } ZTEST(net_socket_tls, test_recv_non_block) diff --git a/tests/net/socket/udp/src/main.c b/tests/net/socket/udp/src/main.c index 3046630906d..3d27e4121a5 100644 --- a/tests/net/socket/udp/src/main.c +++ b/tests/net/socket/udp/src/main.c @@ -343,7 +343,7 @@ ZTEST(net_socket_udp, test_07_so_priority) sizeof(optval)); zassert_equal(rv, 0, "setsockopt failed (%d)", errno); - optval = 8; + optval = 6; rv = zsock_setsockopt(sock2, SOL_SOCKET, SO_PRIORITY, &optval, sizeof(optval)); zassert_equal(rv, 0, "setsockopt failed"); @@ -945,6 +945,8 @@ static ZTEST_BMEM bool test_failed; static struct in6_addr my_addr1 = { { { 0x20, 0x01, 0x0d, 0xb8, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1 } } }; static struct in_addr my_addr2 = { { { 192, 0, 2, 2 } } }; +static struct in6_addr my_addr3 = { { { 0x20, 0x01, 0x0d, 0xb8, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0x3 } } }; static uint8_t server_lladdr[] = { 0x01, 0x02, 0x03, 0xff, 0xfe, 0x04, 0x05, 0x06 }; static struct net_linkaddr server_link_addr = { @@ -2408,6 +2410,124 @@ ZTEST_USER(net_socket_udp, test_35_recvmsg_msg_controllen_update) zassert_equal(rv, 0, "close failed"); } +ZTEST(net_socket_udp, test_36_v6_address_removal) +{ + int ret; + bool status; + int client_sock; + struct sockaddr_in6 client_addr; + struct net_if_addr *ifaddr; + struct net_if *iface; + + if (!IS_ENABLED(CONFIG_NET_IPV6_PE)) { + return; + } + + ifaddr = net_if_ipv6_addr_lookup(&my_addr1, &iface); + zassert_equal(ifaddr->atomic_ref, 1, "Ref count is wrong (%ld vs %ld)", + ifaddr->atomic_ref, 1); + + prepare_sock_udp_v6(MY_IPV6_ADDR_ETH, CLIENT_PORT, &client_sock, &client_addr); + + ret = zsock_bind(client_sock, + (struct sockaddr *)&client_addr, + sizeof(client_addr)); + zassert_equal(ret, 0, "client bind failed"); + + status = net_if_ipv6_addr_rm(eth_iface, &my_addr1); + zassert_false(status, "Address could be removed"); + + ifaddr = net_if_ipv6_addr_lookup(&my_addr1, &iface); + zassert_not_null(ifaddr, "Address %s not found", + net_sprint_ipv6_addr(&my_addr1)); + + ret = zsock_close(client_sock); + zassert_equal(ret, 0, "close failed"); + + ifaddr = net_if_ipv6_addr_lookup(&my_addr1, &iface); + zassert_equal(iface, eth_iface, "Invalid interface %p vs %p", + iface, eth_iface); + zassert_is_null(ifaddr, "Address %s found", + net_sprint_ipv6_addr(&my_addr1)); +} + +static void check_ipv6_address_preferences(struct net_if *iface, + uint16_t preference, + const struct in6_addr *addr, + const struct in6_addr *dest) +{ + const struct in6_addr *selected; + size_t optlen; + int optval; + int sock; + int ret; + + sock = zsock_socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); + zassert_true(sock >= 0, "Cannot create socket (%d)", -errno); + + optval = preference; + ret = zsock_setsockopt(sock, IPPROTO_IPV6, IPV6_ADDR_PREFERENCES, + &optval, sizeof(optval)); + zassert_equal(ret, 0, "setsockopt failed (%d)", errno); + + optval = 0; optlen = 0U; + ret = zsock_getsockopt(sock, IPPROTO_IPV6, IPV6_ADDR_PREFERENCES, + &optval, &optlen); + zassert_equal(ret, 0, "setsockopt failed (%d)", errno); + zassert_equal(optlen, sizeof(optval), "invalid optlen %d vs %d", + optlen, sizeof(optval)); + zassert_equal(optval, preference, + "getsockopt address preferences"); + + selected = net_if_ipv6_select_src_addr_hint(iface, + dest, + preference); + ret = net_ipv6_addr_cmp(addr, selected); + zassert_true(ret, "Wrong address %s selected, expected %s", + net_sprint_ipv6_addr(selected), + net_sprint_ipv6_addr(addr)); + + ret = zsock_close(sock); + zassert_equal(sock, 0, "Cannot close socket (%d)", -errno); +} + +ZTEST(net_socket_udp, test_37_ipv6_src_addr_select) +{ + struct net_if_addr *ifaddr; + const struct in6_addr dest = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0x2 } } }; + + net_if_foreach(iface_cb, ð_iface); + zassert_not_null(eth_iface, "No ethernet interface found"); + + ifaddr = net_if_ipv6_addr_add(eth_iface, &my_addr1, + NET_ADDR_AUTOCONF, 0); + if (!ifaddr) { + DBG("Cannot add IPv6 address %s\n", + net_sprint_ipv6_addr(&my_addr1)); + zassert_not_null(ifaddr, "addr1"); + } + + ifaddr->is_temporary = false; + + ifaddr = net_if_ipv6_addr_add(eth_iface, &my_addr3, + NET_ADDR_AUTOCONF, 0); + if (!ifaddr) { + DBG("Cannot add IPv6 address %s\n", + net_sprint_ipv6_addr(&my_addr3)); + zassert_not_null(ifaddr, "addr1"); + } + + ifaddr->is_temporary = true; + + net_if_up(eth_iface); + + check_ipv6_address_preferences(NULL, IPV6_PREFER_SRC_PUBLIC, + &my_addr1, &dest); + check_ipv6_address_preferences(NULL, IPV6_PREFER_SRC_TMP, + &my_addr3, &dest); +} + static void after(void *arg) { ARG_UNUSED(arg); diff --git a/tests/net/tcp/src/main.c b/tests/net/tcp/src/main.c index 547fd4fc133..adea34c0f3b 100644 --- a/tests/net/tcp/src/main.c +++ b/tests/net/tcp/src/main.c @@ -94,7 +94,6 @@ static struct sockaddr_in6 peer_addr_v6_s = { }; static struct net_if *net_iface; -static uint8_t test_case_no; static uint32_t seq; static uint32_t device_initial_seq; static uint32_t ack; @@ -115,6 +114,27 @@ enum test_state { T_RST, }; +static enum test_case_no { + TEST_CLIENT_IPV4 = 1, + TEST_CLIENT_IPV6 = 2, + TEST_SERVER_IPV4 = 3, + TEST_SERVER_WITH_OPTIONS_IPV4 = 4, + TEST_SERVER_IPV6 = 5, + TEST_CLIENT_SYN_RESEND = 6, + TEST_CLIENT_FIN_WAIT_2_IPV4 = 7, + TEST_CLIENT_CLOSING_IPV6 = 8, + TEST_SERVER_RECV_OUT_OF_ORDER_DATA = 9, + TEST_CLIENT_FIN_WAIT_1_RETRANSMIT_IPV4 = 10, + TEST_CLIENT_DATA_DURING_FIN_1_IPV4 = 11, + TEST_CLIENT_SYN_RST_ACK = 12, + TEST_SERVER_RST_ON_CLOSED_PORT = 13, + TEST_SERVER_RST_ON_LISTENING_PORT_NO_ACTIVE_CONNECTION = 14, + TEST_CLIENT_RST_ON_UNEXPECTED_ACK_ON_SYN = 15, + TEST_CLIENT_CLOSING_FAILURE_IPV6 = 16, + TEST_CLIENT_FIN_WAIT_2_IPV4_FAILURE = 17, + TEST_CLIENT_FIN_ACK_WITH_DATA = 18, +} test_case_no; + static enum test_state t_state; static struct k_work_delayable test_server; @@ -136,6 +156,7 @@ static void handle_server_recv_out_of_order(struct net_pkt *pkt); static void handle_server_rst_on_closed_port(sa_family_t af, struct tcphdr *th); static void handle_server_rst_on_listening_port(sa_family_t af, struct tcphdr *th); static void handle_syn_invalid_ack(sa_family_t af, struct tcphdr *th); +static void handle_client_fin_ack_with_data_test(sa_family_t af, struct tcphdr *th); static void verify_flags(struct tcphdr *th, uint8_t flags, const char *fun, int line) @@ -246,7 +267,7 @@ static struct net_pkt *tester_prepare_tcp_pkt(sa_family_t af, uint8_t opts_len = 0; int ret = -EINVAL; - if ((test_case_no == 4U) && (flags & SYN)) { + if ((test_case_no == TEST_SERVER_WITH_OPTIONS_IPV4) && (flags & SYN)) { opts_len = sizeof(tcp_options); } @@ -282,7 +303,7 @@ static struct net_pkt *tester_prepare_tcp_pkt(sa_family_t af, th->th_sport = src_port; th->th_dport = dst_port; - if ((test_case_no == 4U) && (flags & SYN)) { + if ((test_case_no == TEST_SERVER_WITH_OPTIONS_IPV4) && (flags & SYN)) { th->th_off = 10U; } else { th->th_off = 5U; @@ -301,7 +322,7 @@ static struct net_pkt *tester_prepare_tcp_pkt(sa_family_t af, goto fail; } - if ((test_case_no == 4U) && (flags & SYN)) { + if ((test_case_no == TEST_SERVER_WITH_OPTIONS_IPV4) && (flags & SYN)) { /* Add TCP Options */ ret = net_pkt_write(pkt, tcp_options, opts_len); if (ret < 0) { @@ -440,51 +461,54 @@ static int tester_send(const struct device *dev, struct net_pkt *pkt) } switch (test_case_no) { - case 1: - case 2: + case TEST_CLIENT_IPV4: + case TEST_CLIENT_IPV6: handle_client_test(net_pkt_family(pkt), &th); break; - case 3: - case 4: - case 5: + case TEST_SERVER_IPV4: + case TEST_SERVER_WITH_OPTIONS_IPV4: + case TEST_SERVER_IPV6: handle_server_test(net_pkt_family(pkt), &th); break; - case 6: + case TEST_CLIENT_SYN_RESEND: handle_syn_resend(); break; - case 7: + case TEST_CLIENT_FIN_WAIT_2_IPV4: handle_client_fin_wait_2_test(net_pkt_family(pkt), &th); break; - case 8: + case TEST_CLIENT_CLOSING_IPV6: handle_client_closing_test(net_pkt_family(pkt), &th); break; - case 9: + case TEST_SERVER_RECV_OUT_OF_ORDER_DATA: handle_server_recv_out_of_order(pkt); break; - case 10: + case TEST_CLIENT_FIN_WAIT_1_RETRANSMIT_IPV4: handle_data_fin1_test(net_pkt_family(pkt), &th); break; - case 11: + case TEST_CLIENT_DATA_DURING_FIN_1_IPV4: handle_data_during_fin1_test(net_pkt_family(pkt), &th); break; - case 12: + case TEST_CLIENT_SYN_RST_ACK: handle_syn_rst_ack(net_pkt_family(pkt), &th); break; - case 13: + case TEST_SERVER_RST_ON_CLOSED_PORT: handle_server_rst_on_closed_port(net_pkt_family(pkt), &th); break; - case 14: + case TEST_SERVER_RST_ON_LISTENING_PORT_NO_ACTIVE_CONNECTION: handle_server_rst_on_listening_port(net_pkt_family(pkt), &th); break; - case 15: + case TEST_CLIENT_RST_ON_UNEXPECTED_ACK_ON_SYN: handle_syn_invalid_ack(net_pkt_family(pkt), &th); break; - case 16: + case TEST_CLIENT_CLOSING_FAILURE_IPV6: handle_client_closing_failure_test(net_pkt_family(pkt), &th); break; - case 17: + case TEST_CLIENT_FIN_WAIT_2_IPV4_FAILURE: handle_client_fin_wait_2_failure_test(net_pkt_family(pkt), &th); break; + case TEST_CLIENT_FIN_ACK_WITH_DATA: + handle_client_fin_ack_with_data_test(net_pkt_family(pkt), &th); + break; default: zassert_true(false, "Undefined test case"); @@ -595,7 +619,7 @@ ZTEST(net_tcp, test_client_ipv4) int ret; t_state = T_SYN; - test_case_no = 1; + test_case_no = TEST_CLIENT_IPV4; seq = ack = 0; ret = net_context_get(AF_INET, SOCK_STREAM, IPPROTO_TCP, &ctx); @@ -657,7 +681,7 @@ ZTEST(net_tcp, test_client_ipv6) int ret; t_state = T_SYN; - test_case_no = 2; + test_case_no = TEST_CLIENT_IPV6; seq = ack = 0; ret = net_context_get(AF_INET6, SOCK_STREAM, IPPROTO_TCP, &ctx); @@ -759,10 +783,12 @@ static void handle_server_test(sa_family_t af, struct tcphdr *th) static void test_server_timeout(struct k_work *work) { - if (test_case_no == 3 || test_case_no == 4 || test_case_no == 13 || - test_case_no == 14) { + if (test_case_no == TEST_SERVER_IPV4 || + test_case_no == TEST_SERVER_WITH_OPTIONS_IPV4 || + test_case_no == TEST_SERVER_RST_ON_CLOSED_PORT || + test_case_no == TEST_SERVER_RST_ON_LISTENING_PORT_NO_ACTIVE_CONNECTION) { handle_server_test(AF_INET, NULL); - } else if (test_case_no == 5) { + } else if (test_case_no == TEST_SERVER_IPV6) { handle_server_test(AF_INET6, NULL); } else { zassert_true(false, "Invalid test case"); @@ -824,7 +850,7 @@ ZTEST(net_tcp, test_server_ipv4) int ret; t_state = T_SYN; - test_case_no = 3; + test_case_no = TEST_SERVER_IPV4; seq = ack = 0; ret = net_context_get(AF_INET, SOCK_STREAM, IPPROTO_TCP, &ctx); @@ -893,7 +919,7 @@ ZTEST(net_tcp, test_server_with_options_ipv4) int ret; t_state = T_SYN; - test_case_no = 4; + test_case_no = TEST_SERVER_WITH_OPTIONS_IPV4; seq = ack = 0; ret = net_context_get(AF_INET, SOCK_STREAM, IPPROTO_TCP, &ctx); @@ -962,7 +988,7 @@ ZTEST(net_tcp, test_server_ipv6) int ret; t_state = T_SYN; - test_case_no = 5; + test_case_no = TEST_SERVER_IPV6; seq = ack = 0; ret = net_context_get(AF_INET6, SOCK_STREAM, IPPROTO_TCP, &ctx); @@ -1037,7 +1063,7 @@ ZTEST(net_tcp, test_client_syn_resend) int ret; t_state = T_SYN; - test_case_no = 6; + test_case_no = TEST_CLIENT_SYN_RESEND; seq = ack = 0; ret = net_context_get(AF_INET, SOCK_STREAM, IPPROTO_TCP, &ctx); @@ -1099,7 +1125,7 @@ ZTEST(net_tcp, test_client_syn_rst_ack) int ret; t_state = T_SYN; - test_case_no = 12; + test_case_no = TEST_CLIENT_SYN_RST_ACK; seq = ack = 0; ret = net_context_get(AF_INET, SOCK_STREAM, IPPROTO_TCP, &ctx); @@ -1203,7 +1229,7 @@ ZTEST(net_tcp, test_client_fin_wait_2_ipv4) int ret; t_state = T_SYN; - test_case_no = 7; + test_case_no = TEST_CLIENT_FIN_WAIT_2_IPV4; seq = ack = 0; ret = net_context_get(AF_INET, SOCK_STREAM, IPPROTO_TCP, &ctx); @@ -1344,7 +1370,7 @@ ZTEST(net_tcp, test_client_fin_wait_2_ipv4_failure) int ret; t_state = T_SYN; - test_case_no = 17; + test_case_no = TEST_CLIENT_FIN_WAIT_2_IPV4_FAILURE; seq = ack = 0; closed = false; @@ -1497,7 +1523,7 @@ ZTEST(net_tcp, test_client_fin_wait_1_retransmit_ipv4) int ret; t_state = T_SYN; - test_case_no = 10; + test_case_no = TEST_CLIENT_FIN_WAIT_1_RETRANSMIT_IPV4; seq = ack = 0; ret = net_context_get(AF_INET, SOCK_STREAM, IPPROTO_TCP, &ctx); @@ -1615,7 +1641,7 @@ ZTEST(net_tcp, test_client_data_during_fin_1_ipv4) int ret; t_state = T_SYN; - test_case_no = 11; + test_case_no = TEST_CLIENT_DATA_DURING_FIN_1_IPV4; seq = ack = 0; ret = net_context_get(AF_INET, SOCK_STREAM, IPPROTO_TCP, &ctx); @@ -1728,7 +1754,7 @@ ZTEST(net_tcp, test_client_closing_ipv6) int ret; t_state = T_SYN; - test_case_no = 8; + test_case_no = TEST_CLIENT_CLOSING_IPV6; seq = ack = 0; ret = net_context_get(AF_INET6, SOCK_STREAM, IPPROTO_TCP, &ctx); @@ -1854,7 +1880,7 @@ ZTEST(net_tcp, test_client_closing_failure_ipv6) int ret; t_state = T_SYN; - test_case_no = 16; + test_case_no = TEST_CLIENT_CLOSING_FAILURE_IPV6; seq = ack = 0; ret = net_context_get(AF_INET6, SOCK_STREAM, IPPROTO_TCP, &ctx); @@ -1899,7 +1925,7 @@ static struct net_context *create_server_socket(uint32_t my_seq, int ret; t_state = T_SYN; - test_case_no = 5; + test_case_no = TEST_SERVER_IPV6; seq = my_seq; ack = my_ack; @@ -2137,7 +2163,7 @@ static void test_server_recv_out_of_order_data(void) /* This will force the packet to be routed to our checker func * handle_server_recv_out_of_order() */ - test_case_no = 9; + test_case_no = TEST_SERVER_RECV_OUT_OF_ORDER_DATA; /* Run over the checklist to complete the test */ checklist_based_out_of_order_test(out_of_order_check_list, @@ -2218,7 +2244,7 @@ static void handle_server_rst_on_closed_port(sa_family_t af, struct tcphdr *th) ZTEST(net_tcp, test_server_rst_on_closed_port) { t_state = T_SYN; - test_case_no = 13; + test_case_no = TEST_SERVER_RST_ON_CLOSED_PORT; seq = ack = 0; k_sem_reset(&test_sem); @@ -2264,7 +2290,7 @@ ZTEST(net_tcp, test_server_rst_on_listening_port_no_active_connection) int ret; t_state = T_DATA; - test_case_no = 14; + test_case_no = TEST_SERVER_RST_ON_LISTENING_PORT_NO_ACTIVE_CONNECTION; seq = ack = 200; k_sem_reset(&test_sem); @@ -2383,7 +2409,7 @@ ZTEST(net_tcp, test_client_rst_on_unexpected_ack_on_syn) int ret; t_state = T_SYN; - test_case_no = 15; + test_case_no = TEST_CLIENT_RST_ON_UNEXPECTED_ACK_ON_SYN; seq = ack = 0; ret = net_context_get(AF_INET, SOCK_STREAM, IPPROTO_TCP, &ctx); @@ -2408,4 +2434,191 @@ ZTEST(net_tcp, test_client_rst_on_unexpected_ack_on_syn) test_sem_take(K_MSEC(100), __LINE__); } +#define TEST_FIN_DATA "test_data" + +static enum fin_data_variant { + FIN_DATA_FIN, + FIN_DATA_FIN_ACK, + FIN_DATA_FIN_ACK_PSH, +} test_fin_data_variant; + +static struct k_work_delayable test_fin_data_work; + +/* In this test we check that FIN packet containing data is handled correctly + * by the TCP stack. + */ +static void handle_client_fin_ack_with_data_test(sa_family_t af, struct tcphdr *th) +{ + static uint16_t peer_port; + struct net_pkt *reply; + uint8_t flags = 0; + + switch (t_state) { + case T_SYN: + test_verify_flags(th, SYN); + device_initial_seq = ntohl(th->th_seq); + seq = 0U; + ack = ntohl(th->th_seq) + 1U; + peer_port = th->th_sport; + reply = prepare_syn_ack_packet(af, htons(MY_PORT), peer_port); + seq++; + t_state = T_SYN_ACK; + break; + case T_SYN_ACK: + test_verify_flags(th, ACK); + t_state = T_DATA; + + /* FIN packet with DATA needs to be rescheduled for later - if + * we send it here, the net_context_recv() won't have a chance + * to execute, hence no callback will be registered and data + * will be dropped. + */ + k_work_reschedule(&test_fin_data_work, K_MSEC(1)); + return; + case T_DATA: + switch (test_fin_data_variant) { + case FIN_DATA_FIN: + flags = FIN; + t_state = T_FIN; + break; + case FIN_DATA_FIN_ACK: + flags = FIN | ACK; + t_state = T_FIN_ACK; + break; + case FIN_DATA_FIN_ACK_PSH: + flags = FIN | ACK | PSH; + t_state = T_FIN_ACK; + break; + } + + reply = tester_prepare_tcp_pkt(af, htons(MY_PORT), peer_port, + flags, TEST_FIN_DATA, + strlen(TEST_FIN_DATA)); + seq += strlen(TEST_FIN_DATA) + 1; + + break; + case T_FIN: + test_verify_flags(th, ACK); + zassert_equal(get_rel_seq(th), 1, "Unexpected SEQ number in T_FIN, got %d", + get_rel_seq(th)); + zassert_equal(ntohl(th->th_ack), seq, "Unexpected ACK in T_FIN, got %d", + ntohl(th->th_ack)); + + t_state = T_CLOSING; + return; + case T_FIN_ACK: + test_verify_flags(th, FIN | ACK); + zassert_equal(get_rel_seq(th), 1, "Unexpected SEQ number in T_FIN_ACK, got %d", + get_rel_seq(th)); + zassert_equal(ntohl(th->th_ack), seq, "Unexpected ACK in T_FIN_ACK, got %d", + ntohl(th->th_ack)); + + ack++; + reply = prepare_ack_packet(af, htons(MY_PORT), peer_port); + t_state = T_SYN; + break; + + case T_CLOSING: + test_verify_flags(th, FIN); + zassert_equal(get_rel_seq(th), 1, "Unexpected SEQ number in T_CLOSING, got %d", + get_rel_seq(th)); + + ack++; + reply = prepare_ack_packet(af, htons(MY_PORT), peer_port); + t_state = T_SYN; + break; + + default: + zassert_true(false, "%s unexpected state", __func__); + return; + } + + zassert_ok(net_recv_data(net_iface, reply), "%s failed", __func__); +} + + +static void test_fin_data_handler(struct k_work *work) +{ + ARG_UNUSED(work); + + handle_client_fin_ack_with_data_test(AF_INET, NULL); +} + +static void test_fin_ack_data_recv_cb(struct net_context *context, + struct net_pkt *pkt, + union net_ip_header *ip_hdr, + union net_proto_header *proto_hdr, + int status, + void *user_data) +{ + if (status) { + zassert_true(false, "failed to recv the data"); + } + + if (pkt) { + uint8_t buf[sizeof(TEST_FIN_DATA)] = { 0 }; + int data_len = net_pkt_remaining_data(pkt); + + zassert_equal(data_len, strlen(TEST_FIN_DATA), + "Invalid packet length, %d", data_len); + zassert_ok(net_pkt_read(pkt, buf, data_len)); + zassert_mem_equal(buf, TEST_FIN_DATA, data_len); + + net_pkt_unref(pkt); + } + + test_sem_give(); +} + +/* Test case scenario IPv4 + * expect SYN, + * send SYN ACK, + * expect ACK, + * send FIN/FIN,ACK/FIN,ACK,PSH with Data, + * expect FIN/FIN,ACK/ACK, + * send ACK + * any failures cause test case to fail. + */ +ZTEST(net_tcp, test_client_fin_ack_with_data) +{ + struct net_context *ctx; + + test_case_no = TEST_CLIENT_FIN_ACK_WITH_DATA; + + k_work_init_delayable(&test_fin_data_work, test_fin_data_handler); + + for (enum fin_data_variant variant = FIN_DATA_FIN; + variant <= FIN_DATA_FIN_ACK_PSH; variant++) { + test_fin_data_variant = variant; + t_state = T_SYN; + seq = ack = 0; + + zassert_ok(net_context_get(AF_INET, SOCK_STREAM, IPPROTO_TCP, &ctx), + "Failed to get net_context"); + + net_context_ref(ctx); + + zassert_ok(net_context_connect(ctx, (struct sockaddr *)&peer_addr_s, + sizeof(struct sockaddr_in), NULL, + K_MSEC(1000), NULL), + "Failed to connect to peer"); + zassert_ok(net_context_recv(ctx, test_fin_ack_data_recv_cb, + K_NO_WAIT, NULL), + "Failed to recv data from peer"); + + /* Take sem twice, one for data packet, second for conn close + * (NULL net_pkt). + */ + test_sem_take(K_MSEC(100), __LINE__); + test_sem_take(K_MSEC(100), __LINE__); + + net_context_put(ctx); + + /* Connection is in TIME_WAIT state, context will be released + * after K_MSEC(CONFIG_NET_TCP_TIME_WAIT_DELAY), so wait for it. + */ + k_sleep(K_MSEC(CONFIG_NET_TCP_TIME_WAIT_DELAY)); + } +} + ZTEST_SUITE(net_tcp, NULL, presetup, NULL, NULL, NULL); diff --git a/tests/posix/common/src/stropts.c b/tests/posix/common/src/stropts.c index a1c550062d6..9dcf899ca94 100644 --- a/tests/posix/common/src/stropts.c +++ b/tests/posix/common/src/stropts.c @@ -59,4 +59,13 @@ ZTEST(stropts, test_getpmsg) zassert_equal(errno, ENOSYS, "Expected errno ENOSYS, got %d", errno); } +ZTEST(stropts, test_isastream) +{ + int fd = -1; + int ret = isastream(fd); + + zassert_equal(ret, -1, "Expected return value -1, got %d", ret); + zassert_equal(errno, ENOSYS, "Expected errno ENOSYS, got %d", errno); +} + ZTEST_SUITE(stropts, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/posix/env/testcase.yaml b/tests/posix/env/testcase.yaml index 305fdfff5f8..4648743bbaf 100644 --- a/tests/posix/env/testcase.yaml +++ b/tests/posix/env/testcase.yaml @@ -1,7 +1,5 @@ common: filter: not CONFIG_NATIVE_LIBC - arch_exclude: - - posix integration_platforms: - qemu_riscv64 tags: posix diff --git a/tests/posix/eventfd/src/ioctl.c b/tests/posix/eventfd/src/ioctl.c new file mode 100644 index 00000000000..28c2ce59e4a --- /dev/null +++ b/tests/posix/eventfd/src/ioctl.c @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2024 Celina Sophie Kalus + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "_main.h" +#include + +#define EFD_IN_USE_INTERNAL 0x1 + +ZTEST_F(eventfd, test_set_flags) +{ + eventfd_t val; + int ret; + int flags; + short event; + + /* Get current flags; Expect blocking, non-semaphore. */ + flags = ioctl(fixture->fd, F_GETFL, 0); + zassert_equal(flags, 0, "flags == %d", flags); + + event = POLLIN; + ret = is_blocked(fixture->fd, &event); + zassert_equal(ret, 1, "eventfd read not blocked"); + + /* Try writing and reading. Should not fail. */ + ret = eventfd_write(fixture->fd, 3); + zassert_ok(ret); + + ret = eventfd_read(fixture->fd, &val); + zassert_ok(ret); + zassert_equal(val, 3, "val == %d", val); + + + /* Set nonblocking without reopening. */ + ret = ioctl(fixture->fd, F_SETFL, O_NONBLOCK); + zassert_ok(ret); + + flags = ioctl(fixture->fd, F_GETFL, 0); + zassert_equal(flags, O_NONBLOCK, "flags == %d", flags); + + event = POLLOUT; + ret = is_blocked(fixture->fd, &event); + zassert_equal(ret, 0, "eventfd write blocked"); + + + /* Try writing and reading again. */ + ret = eventfd_write(fixture->fd, 19); + zassert_ok(ret); + + ret = eventfd_read(fixture->fd, &val); + zassert_ok(ret); + zassert_equal(val, 19, "val == %d", val); + + + /* Set back to blocking. */ + ret = ioctl(fixture->fd, F_SETFL, 0); + zassert_ok(ret); + + flags = ioctl(fixture->fd, F_GETFL, 0); + zassert_equal(flags, 0, "flags == %d", flags); + + event = POLLIN; + ret = is_blocked(fixture->fd, &event); + zassert_equal(ret, 1, "eventfd read not blocked"); + + + /* Try writing and reading again. */ + ret = eventfd_write(fixture->fd, 10); + zassert_ok(ret); + + ret = eventfd_read(fixture->fd, &val); + zassert_ok(ret); + zassert_equal(val, 10, "val == %d", val); + + + /* Test setting internal in-use-flag. Should fail. */ + ret = ioctl(fixture->fd, F_SETFL, EFD_IN_USE_INTERNAL); + zassert_not_ok(ret); + + + /* File descriptor should still be valid and working. */ + ret = eventfd_write(fixture->fd, 97); + zassert_ok(ret); + + ret = eventfd_read(fixture->fd, &val); + zassert_ok(ret); + zassert_equal(val, 97, "val == %d", val); +} diff --git a/tests/posix/fs/src/test_fs_file.c b/tests/posix/fs/src/test_fs_file.c index 6a843368955..cb015a41ddf 100644 --- a/tests/posix/fs/src/test_fs_file.c +++ b/tests/posix/fs/src/test_fs_file.c @@ -141,6 +141,43 @@ static int test_file_close(void) return res; } +static int test_file_fsync(void) +{ + int res = 0; + + if (file < 0) + return res; + + res = fsync(file); + if (res < 0) { + TC_ERROR("Failed to sync file: %d, errno = %d\n", res, errno); + res = TC_FAIL; + } + + close(file); + file = -1; + return res; +} + +static int test_file_truncate(void) +{ + int res = 0; + size_t truncate_size = sizeof(test_str) - 4; + + if (file < 0) + return res; + + res = ftruncate(file, truncate_size); + if (res) { + TC_PRINT("Error truncating file [%d]\n", res); + res = TC_FAIL; + } + + close(file); + file = -1; + return res; +} + static int test_file_delete(void) { int res; @@ -201,6 +238,32 @@ ZTEST(posix_fs_file_test, test_fs_read) zassert_true(test_file_read() == TC_PASS); } +/** + * @brief Test for POSIX fsync API + * + * @details Test sync the file through POSIX fsync API. + */ +ZTEST(posix_fs_file_test, test_fs_sync) +{ + /* FIXME: restructure tests as per #46897 */ + zassert_true(test_file_open() == TC_PASS); + zassert_true(test_file_write() == TC_PASS); + zassert_true(test_file_fsync() == TC_PASS); +} + +/** + * @brief Test for POSIX ftruncate API + * + * @details Test truncate the file through POSIX ftruncate API. + */ +ZTEST(posix_fs_file_test, test_fs_truncate) +{ + /* FIXME: restructure tests as per #46897 */ + zassert_true(test_file_open() == TC_PASS); + zassert_true(test_file_write() == TC_PASS); + zassert_true(test_file_truncate() == TC_PASS); +} + /** * @brief Test for POSIX close API * diff --git a/tests/posix/getentropy/CMakeLists.txt b/tests/posix/getentropy/CMakeLists.txt new file mode 100644 index 00000000000..27970bfe2a6 --- /dev/null +++ b/tests/posix/getentropy/CMakeLists.txt @@ -0,0 +1,10 @@ +# Copyright (c) 2024 Google LLC +# +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(getentropy) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/tests/posix/getentropy/prj.conf b/tests/posix/getentropy/prj.conf new file mode 100644 index 00000000000..58160099e32 --- /dev/null +++ b/tests/posix/getentropy/prj.conf @@ -0,0 +1,4 @@ +CONFIG_ENTROPY_GENERATOR=y +CONFIG_GETENTROPY=y +CONFIG_POSIX_API=y +CONFIG_ZTEST=y diff --git a/tests/posix/getentropy/src/main.c b/tests/posix/getentropy/src/main.c new file mode 100644 index 00000000000..a276c4b9663 --- /dev/null +++ b/tests/posix/getentropy/src/main.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2024 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include + +ZTEST(getentropy_test_suite, test_getentropy_too_large) +{ + uint8_t buf[256 + 1] = { 0 }; + int ret; + + ret = getentropy(buf, sizeof(buf)); + zassert_equal(ret, -1); + zassert_equal(errno, EIO); +} + +ZTEST(getentropy_test_suite, test_getentropy_null_buffer) +{ + int ret; + + ret = getentropy(NULL, 0); + zassert_equal(ret, -1); + zassert_equal(errno, EFAULT); +} + +ZTEST(getentropy_test_suite, test_getentropy_max_size) +{ + uint8_t buf[256] = { 0 }; + int ret; + + ret = getentropy(buf, sizeof(buf)); + zassert_equal(ret, 0); +} + +ZTEST(getentropy_test_suite, test_getentropy) +{ + uint8_t zero[16] = { 0 }; + uint8_t buf1[16]; + uint8_t buf2[16]; + int ret; + + ret = getentropy(buf1, sizeof(buf1)); + zassert_equal(ret, 0); + + ret = getentropy(buf2, sizeof(buf2)); + zassert_equal(ret, 0); + + zassert_true(memcmp(buf1, zero, sizeof(zero)) != 0); + zassert_true(memcmp(buf2, zero, sizeof(zero)) != 0); + zassert_true(memcmp(buf1, buf2, sizeof(buf1)) != 0); +} + +ZTEST_SUITE(getentropy_test_suite, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/posix/getentropy/testcase.yaml b/tests/posix/getentropy/testcase.yaml new file mode 100644 index 00000000000..b8b4fc41d8b --- /dev/null +++ b/tests/posix/getentropy/testcase.yaml @@ -0,0 +1,20 @@ +common: + filter: dt_chosen_enabled("zephyr,entropy") and CONFIG_ENTROPY_HAS_DRIVER and + not CONFIG_NATIVE_LIBC + integration_platforms: + - native_sim + tags: + - posix + - getentropy +tests: + portability.posix.getentropy: {} + portability.posix.getentropy.newlib: + filter: CONFIG_NEWLIB_LIBC_SUPPORTED + extra_configs: + - CONFIG_NEWLIB_LIBC=y + - CONFIG_NEWLIB_LIBC_MIN_REQUIRED_HEAP_SIZE=4096 + portability.posix.getentropy.picolibc: + tags: picolibc + filter: CONFIG_PICOLIBC_SUPPORTED + extra_configs: + - CONFIG_PICOLIBC=y diff --git a/tests/posix/headers/CMakeLists.txt b/tests/posix/headers/CMakeLists.txt index 16616d5885f..f34002d6cec 100644 --- a/tests/posix/headers/CMakeLists.txt +++ b/tests/posix/headers/CMakeLists.txt @@ -6,3 +6,4 @@ project(posix_headers) FILE(GLOB app_sources src/*.c) target_sources(app PRIVATE ${app_sources}) +target_compile_options(app PRIVATE -U_POSIX_C_SOURCE -D_POSIX_C_SOURCE=200809L) diff --git a/tests/posix/headers/src/aio_h.c b/tests/posix/headers/src/aio_h.c new file mode 100644 index 00000000000..5888b83925d --- /dev/null +++ b/tests/posix/headers/src/aio_h.c @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2024 Tenstorrent AI ULC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "_common.h" + +#ifdef CONFIG_POSIX_API +#include +#else +#include +#endif + +ZTEST(posix_headers, test_aio_h) +{ + zassert_not_equal(offsetof(struct aiocb, aio_fildes), -1); + zassert_not_equal(offsetof(struct aiocb, aio_offset), -1); + zassert_not_equal(offsetof(struct aiocb, aio_buf), -1); + zassert_not_equal(offsetof(struct aiocb, aio_nbytes), -1); + zassert_not_equal(offsetof(struct aiocb, aio_reqprio), -1); + zassert_not_equal(offsetof(struct aiocb, aio_sigevent), -1); + zassert_not_equal(offsetof(struct aiocb, aio_lio_opcode), -1); + + if (IS_ENABLED(CONFIG_POSIX_API)) { + zassert_not_null(aio_cancel); + zassert_not_null(aio_error); + zassert_not_null(aio_fsync); + zassert_not_null(aio_read); + zassert_not_null(aio_return); + zassert_not_null(aio_suspend); + zassert_not_null(aio_write); + zassert_not_null(lio_listio); + } +} diff --git a/tests/posix/headers/src/stropts_h.c b/tests/posix/headers/src/stropts_h.c index 2cc5c7a859e..fe928e04c2c 100644 --- a/tests/posix/headers/src/stropts_h.c +++ b/tests/posix/headers/src/stropts_h.c @@ -23,6 +23,7 @@ ZTEST(posix_headers, test_stropts_h) zassert_not_null((void *)fattach, "fattach is null"); zassert_not_null((void *)getmsg, "getmsg is null"); zassert_not_null((void *)getpmsg, "getpmsg is null"); + zassert_not_null((void *)isastream, "isastream is null"); zassert_true(sizeof(((struct strbuf *)0)->maxlen) > 0, "maxlen size is 0"); zassert_true(sizeof(((struct strbuf *)0)->len) > 0, "len size is 0"); diff --git a/tests/subsys/bindesc/definition/testcase.yaml b/tests/subsys/bindesc/definition/testcase.yaml index 6e1884ee0b0..1d51ee82fcc 100644 --- a/tests/subsys/bindesc/definition/testcase.yaml +++ b/tests/subsys/bindesc/definition/testcase.yaml @@ -22,14 +22,23 @@ tests: - qemu_riscv32e - qemu_riscv64 bindesc.define.c99: - extra_args: CSTD="c99" + extra_configs: + - CONFIG_STD_C99=y bindesc.define.c11: - extra_args: CSTD="c11" + extra_configs: + - CONFIG_STD_C11=y bindesc.define.c17: - extra_args: CSTD="c17" + extra_configs: + - CONFIG_STD_C17=y bindesc.define.gnu99: - extra_args: CSTD="gnu99" + extra_configs: + - CONFIG_STD_C99=y + - CONFIG_GNU_C_EXTENSIONS=y bindesc.define.gnu11: - extra_args: CSTD="gnu11" + extra_configs: + - CONFIG_STD_C11=y + - CONFIG_GNU_C_EXTENSIONS=y bindesc.define.gnu17: - extra_args: CSTD="gnu17" + extra_configs: + - CONFIG_STD_C17=y + - CONFIG_GNU_C_EXTENSIONS=y diff --git a/tests/subsys/debug/coredump_backends/boards/esp32s3_devkitm.overlay b/tests/subsys/debug/coredump_backends/boards/esp32s3_devkitm_procpu.overlay similarity index 100% rename from tests/subsys/debug/coredump_backends/boards/esp32s3_devkitm.overlay rename to tests/subsys/debug/coredump_backends/boards/esp32s3_devkitm_procpu.overlay diff --git a/tests/subsys/debug/coredump_backends/boards/esp32s3_luatos_core.overlay b/tests/subsys/debug/coredump_backends/boards/esp32s3_luatos_core_procpu.overlay similarity index 100% rename from tests/subsys/debug/coredump_backends/boards/esp32s3_luatos_core.overlay rename to tests/subsys/debug/coredump_backends/boards/esp32s3_luatos_core_procpu.overlay diff --git a/tests/subsys/debug/coredump_backends/boards/esp32s3_luatos_core_esp32s3_procpu_usb.overlay b/tests/subsys/debug/coredump_backends/boards/esp32s3_luatos_core_procpu_usb.overlay similarity index 100% rename from tests/subsys/debug/coredump_backends/boards/esp32s3_luatos_core_esp32s3_procpu_usb.overlay rename to tests/subsys/debug/coredump_backends/boards/esp32s3_luatos_core_procpu_usb.overlay diff --git a/tests/subsys/debug/coredump_backends/boards/yd_esp32.overlay b/tests/subsys/debug/coredump_backends/boards/yd_esp32_procpu.overlay similarity index 100% rename from tests/subsys/debug/coredump_backends/boards/yd_esp32.overlay rename to tests/subsys/debug/coredump_backends/boards/yd_esp32_procpu.overlay diff --git a/tests/subsys/debug/mipi_stp_decoder/CMakeLists.txt b/tests/subsys/debug/mipi_stp_decoder/CMakeLists.txt new file mode 100644 index 00000000000..4b55d300ab9 --- /dev/null +++ b/tests/subsys/debug/mipi_stp_decoder/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(mipi_stp_decoder) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/tests/subsys/debug/mipi_stp_decoder/README b/tests/subsys/debug/mipi_stp_decoder/README new file mode 100644 index 00000000000..c4e9984fc58 --- /dev/null +++ b/tests/subsys/debug/mipi_stp_decoder/README @@ -0,0 +1 @@ +Test for MIPI STPv2 data stream decoder. diff --git a/tests/subsys/debug/mipi_stp_decoder/prj.conf b/tests/subsys/debug/mipi_stp_decoder/prj.conf new file mode 100644 index 00000000000..10d6c08c2c2 --- /dev/null +++ b/tests/subsys/debug/mipi_stp_decoder/prj.conf @@ -0,0 +1,2 @@ +CONFIG_ZTEST=y +CONFIG_MIPI_STP_DECODER=y diff --git a/tests/subsys/debug/mipi_stp_decoder/src/main.c b/tests/subsys/debug/mipi_stp_decoder/src/main.c new file mode 100644 index 00000000000..ecf519de4aa --- /dev/null +++ b/tests/subsys/debug/mipi_stp_decoder/src/main.c @@ -0,0 +1,325 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA. + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include + +static int cnt; +static enum mipi_stp_decoder_ctrl_type exp_type[10]; +static union mipi_stp_decoder_data exp_data[10]; +static size_t exp_data_len[10]; +static uint64_t exp_ts[10]; +static bool exp_marked[10]; +static int d_cnt; + +static void cb(enum mipi_stp_decoder_ctrl_type type, union mipi_stp_decoder_data data, uint64_t *ts, + bool marked) +{ + zassert_equal(exp_type[d_cnt], type, "Expected: %d got:%d", exp_type[d_cnt], type); + + if (exp_ts[d_cnt] == UINT64_MAX) { + zassert_equal(ts, NULL, NULL); + } else { + zassert_true(ts != NULL, NULL); + zassert_equal(exp_ts[d_cnt], *ts, "exp:%llx got:%llx", exp_ts[d_cnt], *ts); + } + + zassert_equal(exp_marked[d_cnt], marked, NULL); + zassert_equal( + memcmp((uint8_t *)&exp_data[d_cnt], (uint8_t *)&data.data, exp_data_len[d_cnt]), 0, + NULL); + d_cnt++; +} + +static const struct mipi_stp_decoder_config config = { + .cb = cb, +}; + +#define ADD_ITEM(_cnt, _type, _ts, _marked, _data) \ + do { \ + exp_type[_cnt] = _type; \ + exp_ts[_cnt] = (uint64_t)_ts; \ + exp_marked[_cnt] = _marked; \ + exp_data[_cnt].data = _data; \ + exp_data_len[_cnt++] = sizeof(_data); \ + } while (0) + +ZTEST(mipi_stp_decoder_test, test_chunk_null) +{ + uint8_t data[] = {0x00, 0x00}; + + ADD_ITEM(cnt, STP_DECODER_NULL, UINT64_MAX, false, (uint8_t)0); + ADD_ITEM(cnt, STP_DECODER_NULL, UINT64_MAX, false, (uint8_t)0); + ADD_ITEM(cnt, STP_DECODER_NULL, UINT64_MAX, false, (uint8_t)0); + ADD_ITEM(cnt, STP_DECODER_NULL, UINT64_MAX, false, (uint8_t)0); + + mipi_stp_decoder_decode(data, sizeof(data)); + zassert_equal(cnt, d_cnt, NULL); +} + +ZTEST(mipi_stp_decoder_test, test_chunk_master) +{ + /* 0x1(m8) 0xab 0x0 (null) 0xf1(m16) 0x3412 */ + uint8_t data[] = {0xa1, 0x0b, 0x1f, 0x34, 0x12}; + + ADD_ITEM(cnt, STP_DECODER_MASTER, UINT64_MAX, false, (uint8_t)0xab); + ADD_ITEM(cnt, STP_DECODER_NULL, UINT64_MAX, false, (uint8_t)0); + ADD_ITEM(cnt, STP_DECODER_MASTER, UINT64_MAX, false, (uint16_t)0x4321); + + mipi_stp_decoder_decode(data, sizeof(data)); + zassert_equal(cnt, d_cnt, NULL); +} + +ZTEST(mipi_stp_decoder_test, test_chunk_channel) +{ + /* 0(null) 1(m8) ab 3(c8) ab f3(c16) 4664 3(c8) bb 1(m8) 0b 3(c8) aa*/ + uint8_t data[] = {0x10, 0xba, 0xa3, 0xfb, 0x63, 0x44, 0x36, 0xbb, 0x01, 0x3b, 0xaa}; + + ADD_ITEM(cnt, STP_DECODER_NULL, UINT64_MAX, false, (uint8_t)0); + ADD_ITEM(cnt, STP_DECODER_MASTER, UINT64_MAX, false, (uint8_t)0xab); + ADD_ITEM(cnt, STP_DECODER_CHANNEL, UINT64_MAX, false, (uint8_t)0xab); + ADD_ITEM(cnt, STP_DECODER_CHANNEL, UINT64_MAX, false, (uint16_t)0x6446); + /* MSB byte is taken from previous C16 */ + ADD_ITEM(cnt, STP_DECODER_CHANNEL, UINT64_MAX, false, (uint16_t)0x64bb); + ADD_ITEM(cnt, STP_DECODER_MASTER, UINT64_MAX, false, (uint8_t)0x0b); + /* M8 resets current channel */ + ADD_ITEM(cnt, STP_DECODER_CHANNEL, UINT64_MAX, false, (uint8_t)0xaa); + + mipi_stp_decoder_decode(data, sizeof(data)); + zassert_equal(d_cnt, cnt, "got:%d exp:%d", d_cnt, cnt); +} + +ZTEST(mipi_stp_decoder_test, test_chunk_data) +{ + /* 4(d8) ab 5(d16) 0x3456 6(d32) 0x11223344 7(d64) 0x1020304050607080 */ + /* f8(dm8) ab f9(dm16) 0x3456 fa(dm32) 0x11223344 fb(dm64) 0x1020304050607080 */ + uint8_t data[] = {0xa4, 0x5b, 0x43, 0x65, 0x16, 0x21, 0x32, 0x43, 0x74, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + + 0x8f, 0xba, 0x9f, 0x43, 0x65, 0xaf, 0x11, 0x22, 0x33, 0x44, + 0xbf, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; + + ADD_ITEM(cnt, STP_DATA8, UINT64_MAX, false, (uint8_t)0xab); + ADD_ITEM(cnt, STP_DATA16, UINT64_MAX, false, (uint16_t)0x3456); + ADD_ITEM(cnt, STP_DATA32, UINT64_MAX, false, (uint32_t)0x11223344); + ADD_ITEM(cnt, STP_DATA64, UINT64_MAX, false, (uint32_t)0x1020304050607080); + ADD_ITEM(cnt, STP_DATA8, UINT64_MAX, true, (uint8_t)0xab); + ADD_ITEM(cnt, STP_DATA16, UINT64_MAX, true, (uint16_t)0x3456); + ADD_ITEM(cnt, STP_DATA32, UINT64_MAX, true, (uint32_t)0x11223344); + ADD_ITEM(cnt, STP_DATA64, UINT64_MAX, true, (uint32_t)0x1020304050607080); + + mipi_stp_decoder_decode(data, sizeof(data)); + zassert_equal(d_cnt, cnt, "got:%d exp:%d", d_cnt, cnt); +} + +ZTEST(mipi_stp_decoder_test, test_chunk_data_ts) +{ + uint8_t data[] = { + /*d8ts + 13b TS */ 0x4f, + 0xba, + 0x1d, + 0x21, + 0x32, + 0x43, + 0x54, + 0x65, + 0x76, + 0x07, + /*d16ts + 3b TS */ 0x5f, + 0xba, + 0xdc, + 0x13, + 0x22, + /*d32ts + 3b TS */ 0x6f, + 0x11, + 0x22, + 0xba, + 0xdc, + 0x13, + 0x22, + /*d64ts + 3b TS */ 0x7f, + 0x11, + 0x22, + 0xba, + 0xdc, + 0x11, + 0x22, + 0x33, + 0x44, + 0x13, + 0x22, + /*d8mts + 14b TS */ 0xa8, + 0xeb, + 0x11, + 0x22, + 0x33, + 0x44, + 0x55, + 0x66, + 0x77, + 0x88, + /*d16mts + 2b TS */ 0xa9, + 0xcb, + 0x2d, + 0x31, + /*d32mts + 2b TS */ 0xaa, + 0xcb, + 0x1d, + 0x21, + 0x22, + 0x31, + /*d64mts + 2b TS */ 0xab, + 0xcb, + 0x1d, + 0x21, + 0x12, + 0x11, + 0x11, + 0x11, + 0x21, + 0x31, + }; + + ADD_ITEM(cnt, STP_DATA8, 0x11223344556677, false, (uint8_t)0xab); + ADD_ITEM(cnt, STP_DECODER_NULL, UINT64_MAX, false, (uint8_t)0); + ADD_ITEM(cnt, STP_DATA16, 0x11223344556122, false, (uint16_t)0xabcd); + ADD_ITEM(cnt, STP_DATA32, 0x11223344556122, false, (uint32_t)0x1122abcd); + ADD_ITEM(cnt, STP_DATA64, 0x11223344556122, false, (uint64_t)0x1122abcd11223344); + ADD_ITEM(cnt, STP_DATA8, 0x1122334455667788, true, (uint8_t)0xab); + ADD_ITEM(cnt, STP_DATA16, 0x1122334455667713, true, (uint16_t)0xabcd); + ADD_ITEM(cnt, STP_DATA32, 0x1122334455667713, true, (uint32_t)0xabcd1122); + ADD_ITEM(cnt, STP_DATA64, 0x1122334455667713, true, (uint64_t)0xabcd112211111111); + + mipi_stp_decoder_decode(data, sizeof(data)); + zassert_equal(d_cnt, cnt, "got:%d exp:%d", d_cnt, cnt); +} + +ZTEST(mipi_stp_decoder_test, test_multi_chunk_data_ts) +{ + /*d8ts + 13b TS */ + uint8_t data[] = {0x4f, 0xba, 0x1d, 0x21, 0x32}; + uint8_t data2[] = { + 0x43, 0x54, 0x65, 0x76, 0x07, + }; + + ADD_ITEM(cnt, STP_DATA8, 0x11223344556677, false, (uint8_t)0xab); + ADD_ITEM(cnt, STP_DECODER_NULL, UINT64_MAX, false, (uint8_t)0); + + /* First part without any packet decoded. */ + mipi_stp_decoder_decode(data, sizeof(data)); + zassert_equal(d_cnt, 0, "got:%d exp:%d", d_cnt, 0); + + mipi_stp_decoder_decode(data2, sizeof(data2)); + zassert_equal(d_cnt, cnt, "got:%d exp:%d", d_cnt, cnt); +} + +ZTEST(mipi_stp_decoder_test, test_chunk_errors) +{ + uint8_t data[] = {/*merr 0x12 gerr 0x12 null */ 0x12, 0xf2, 0x12, 0x02}; + + ADD_ITEM(cnt, STP_DECODER_MERROR, UINT64_MAX, false, (uint8_t)0x12); + ADD_ITEM(cnt, STP_DECODER_GERROR, UINT64_MAX, false, (uint8_t)0x12); + ADD_ITEM(cnt, STP_DECODER_NULL, UINT64_MAX, false, (uint8_t)0); + + mipi_stp_decoder_decode(data, sizeof(data)); + zassert_equal(d_cnt, cnt, "got:%d exp:%d", d_cnt, cnt); +} + +ZTEST(mipi_stp_decoder_test, test_chunk_freq) +{ + uint8_t data[] = {/* freq 0x11223344 null */ 0x0f, + 0x18, + 0x21, + 0x32, + 0x43, + 0x04, + /* freq_ts 0x11223344 + 2b TS */ 0x0f, + 0x19, + 0x21, + 0x32, + 0x43, + 0x24, + 0x12}; + + ADD_ITEM(cnt, STP_DECODER_FREQ, UINT64_MAX, false, (uint32_t)0x11223344); + ADD_ITEM(cnt, STP_DECODER_NULL, UINT64_MAX, false, (uint8_t)0); + ADD_ITEM(cnt, STP_DECODER_FREQ, 0x21ULL, false, (uint32_t)0x11223344); + + mipi_stp_decoder_decode(data, sizeof(data)); + zassert_equal(d_cnt, cnt, "got:%d exp:%d", d_cnt, cnt); +} + +ZTEST(mipi_stp_decoder_test, test_chunk_async) +{ + uint8_t data[] = {/* null async null*/ + 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}; + + ADD_ITEM(cnt, STP_DECODER_NULL, UINT64_MAX, false, (uint8_t)0); + ADD_ITEM(cnt, STP_DECODER_ASYNC, UINT64_MAX, false, (uint8_t)0); + ADD_ITEM(cnt, STP_DECODER_NULL, UINT64_MAX, false, (uint8_t)0); + + mipi_stp_decoder_decode(data, sizeof(data)); + zassert_equal(d_cnt, cnt, "got:%d exp:%d", d_cnt, cnt); +} + +ZTEST(mipi_stp_decoder_test, test_multi_chunk_async) +{ + /* null async null split into 2 buffers */ + uint8_t data[] = { + 0xf0, + 0xff, + 0xff, + }; + uint8_t data2[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}; + + ADD_ITEM(cnt, STP_DECODER_NULL, UINT64_MAX, false, (uint8_t)0); + ADD_ITEM(cnt, STP_DECODER_ASYNC, UINT64_MAX, false, (uint8_t)0); + ADD_ITEM(cnt, STP_DECODER_NULL, UINT64_MAX, false, (uint8_t)0); + + /* First part only null packet is decoded */ + mipi_stp_decoder_decode(data, sizeof(data)); + zassert_equal(d_cnt, 1, "got:%d exp:%d", d_cnt, 1); + + mipi_stp_decoder_decode(data2, sizeof(data2)); + zassert_equal(d_cnt, cnt, "got:%d exp:%d", d_cnt, cnt); +} + +ZTEST(mipi_stp_decoder_test, test_chunk_freq2) +{ + /* null async null split into 2 buffers */ + uint8_t data[] = {0xf0, 0x80, 0x00, 0xc4, 0xb4, 0x04}; + + ADD_ITEM(cnt, STP_DECODER_NULL, UINT64_MAX, false, (uint8_t)0); + ADD_ITEM(cnt, STP_DECODER_FREQ, UINT64_MAX, false, (uint64_t)5000000); + + mipi_stp_decoder_decode(data, sizeof(data)); + zassert_equal(d_cnt, cnt, "got:%d exp:%d", d_cnt, cnt); +} + +ZTEST(mipi_stp_decoder_test, test_sync_loss) +{ + /* null async null split into 2 buffers */ + uint8_t data[] = {0xf0, 0x80, 0x00, 0xc4, 0xff, 0xff, 0xff, 0xff, 0xf5, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x60, 0x11, 0x11, 0x11, 0x11}; + + ADD_ITEM(cnt, STP_DECODER_NULL, UINT64_MAX, false, (uint8_t)0); + ADD_ITEM(cnt, STP_DECODER_ASYNC, UINT64_MAX, false, (uint8_t)0); + ADD_ITEM(cnt, STP_DATA32, UINT64_MAX, false, (uint32_t)0x11111111); + + mipi_stp_decoder_decode(data, 4); + mipi_stp_decoder_sync_loss(); + mipi_stp_decoder_decode(&data[4], sizeof(data) - 4); + + zassert_equal(d_cnt, cnt, "got:%d exp:%d", d_cnt, cnt); +} + +static void before(void *data) +{ + cnt = 0; + d_cnt = 0; + mipi_stp_decoder_init(&config); +} + +ZTEST_SUITE(mipi_stp_decoder_test, NULL, NULL, before, NULL, NULL); diff --git a/tests/subsys/debug/mipi_stp_decoder/testcase.yaml b/tests/subsys/debug/mipi_stp_decoder/testcase.yaml new file mode 100644 index 00000000000..85d342cd60c --- /dev/null +++ b/tests/subsys/debug/mipi_stp_decoder/testcase.yaml @@ -0,0 +1,6 @@ +tests: + debug.mipi_stp_decoder: + filter: not CONFIG_BIG_ENDIAN + tags: stp_decoder + integration_platforms: + - native_posix diff --git a/tests/subsys/dfu/mcuboot_multi/native_sim_native_64.overlay b/tests/subsys/dfu/mcuboot_multi/native_sim_native_64.overlay new file mode 100644 index 00000000000..91647f82e20 --- /dev/null +++ b/tests/subsys/dfu/mcuboot_multi/native_sim_native_64.overlay @@ -0,0 +1,6 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "native_sim.overlay" diff --git a/tests/subsys/fs/ext2/boards/native_sim_native_64.overlay b/tests/subsys/fs/ext2/boards/native_sim_native_64.overlay new file mode 100644 index 00000000000..e4994493dd6 --- /dev/null +++ b/tests/subsys/fs/ext2/boards/native_sim_native_64.overlay @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "native_sim.overlay" diff --git a/tests/subsys/fs/ext2/src/testfs_ext_specific.c b/tests/subsys/fs/ext2/src/testfs_ext_specific.c index 63367d7272e..47863a987a6 100644 --- a/tests/subsys/fs/ext2/src/testfs_ext_specific.c +++ b/tests/subsys/fs/ext2/src/testfs_ext_specific.c @@ -39,41 +39,17 @@ uint32_t calculate_blocks(uint32_t freeb, uint32_t B) /* TODO: revisit this and extend when 3rd level blocks will be possible */ } -void writing_test(struct ext2_cfg *config) +static void write_to_file(const char *file_path, uint32_t bytes_to_write) { int64_t ret = 0; struct fs_file_t file; - struct fs_statvfs sbuf; struct fs_dirent entry; - struct fs_mount_t *mp = &testfs_mnt; - static const char *file_path = "/sml/file"; - - ret = fs_mkfs(FS_EXT2, (uintptr_t)mp->storage_dev, config, 0); - zassert_equal(ret, 0, "Failed to mkfs with 2K blocks"); - - mp->flags = FS_MOUNT_FLAG_NO_FORMAT; - ret = fs_mount(mp); - zassert_equal(ret, 0, "Mount failed (ret=%d)", ret); fs_file_t_init(&file); ret = fs_open(&file, file_path, FS_O_RDWR | FS_O_CREATE); zassert_equal(ret, 0, "File open failed (ret=%d)", ret); - ret = fs_statvfs(mp->mnt_point, &sbuf); - zassert_equal(ret, 0, "Expected success (ret=%d)", ret); - - - /* Calculate how many numbers will be written (use all available memory) */ - uint32_t freeb = sbuf.f_bfree; - uint32_t bsize = sbuf.f_bsize; - uint32_t available_blocks = calculate_blocks(freeb, bsize / sizeof(uint32_t)); - - uint32_t bytes_to_write = bsize * available_blocks; - - TC_PRINT("Available blocks: %d\nBlock size: %d\nBytes_to_write: %d\n", - available_blocks, bsize, bytes_to_write); - - ret = testfs_write_incrementing(&file, 0, available_blocks * bsize); + ret = testfs_write_incrementing(&file, 0, bytes_to_write); zassert_equal(ret, bytes_to_write, "Different number of bytes written %ld (expected %ld)", ret, bytes_to_write); @@ -93,40 +69,121 @@ void writing_test(struct ext2_cfg *config) zassert_equal(ret, 0, "File open failed (ret=%d)", ret); - ret = testfs_verify_incrementing(&file, 0, available_blocks * bsize); + ret = testfs_verify_incrementing(&file, 0, bytes_to_write); zassert_equal(ret, bytes_to_write, "Different number of bytes read %ld (expected %ld)", ret, bytes_to_write); ret = fs_close(&file); zassert_equal(ret, 0, "File close failed (ret=%d)", ret); +} + +static void truncate_file(const char *file_path, uint32_t new_size) +{ + int64_t ret = 0; + struct fs_file_t file; + struct fs_dirent entry; + + fs_file_t_init(&file); + + TC_PRINT("Truncating to %d\n", new_size); + + ret = fs_open(&file, file_path, FS_O_RDWR); + zassert_equal(ret, 0, "File open failed (ret=%d)", ret); + + ret = fs_truncate(&file, new_size); + zassert_equal(ret, 0, "File truncate failed (ret=%d)", ret); + + ret = fs_stat(file_path, &entry); + zassert_equal(ret, 0, "File stat failed (ret=%d)", ret); + zassert_equal(entry.size, new_size, + "Wrong file size %d (expected %d)", entry.size, new_size); + + ret = fs_seek(&file, 0, FS_SEEK_SET); + zassert_equal(ret, 0, "File seek failed (ret=%d)", ret); + + ret = testfs_verify_incrementing(&file, 0, new_size); + zassert_equal(ret, new_size, "Different number of bytes read %ld (expected %ld)", + ret, new_size); + + ret = fs_close(&file); + zassert_equal(ret, 0, "File close failed (ret=%d)", ret); +} + +void writing_test(struct ext2_cfg *config) +{ + int64_t ret = 0; + struct fs_statvfs sbuf; + struct fs_mount_t *mp = &testfs_mnt; + static const char *file_path = "/sml/file"; + + ret = fs_mkfs(FS_EXT2, (uintptr_t)mp->storage_dev, config, 0); + zassert_equal(ret, 0, "Failed to mkfs with 2K blocks"); + + mp->flags = FS_MOUNT_FLAG_NO_FORMAT; + ret = fs_mount(mp); + zassert_equal(ret, 0, "Mount failed (ret=%d)", ret); + + ret = fs_statvfs(mp->mnt_point, &sbuf); + zassert_equal(ret, 0, "Expected success (ret=%d)", ret); + + /* Calculate how many numbers will be written (use all available memory) */ + uint32_t freeb = sbuf.f_bfree; + uint32_t bsize = sbuf.f_bsize; + uint32_t available_blocks = calculate_blocks(freeb, bsize / sizeof(uint32_t)); + + uint32_t bytes_to_write = bsize * available_blocks; + + TC_PRINT("Available blocks: %d\nBlock size: %d\nBytes_to_write: %d\n", + available_blocks, bsize, bytes_to_write); + + write_to_file(file_path, bytes_to_write); uint32_t new_size = bytes_to_write; while (new_size > 1) { new_size = new_size / 8 * 3; + truncate_file(file_path, new_size); + } + + ret = fs_unmount(mp); + zassert_equal(ret, 0, "Unmount failed (ret=%d)", ret); +} - TC_PRINT("Truncating to %d\n", new_size); +ZTEST(ext2tests, test_indirect_block_removal) +{ + int64_t ret = 0; + struct fs_statvfs sbuf; + struct fs_mount_t *mp = &testfs_mnt; + static const char *file_path = "/sml/file"; + + ret = fs_mkfs(FS_EXT2, (uintptr_t)mp->storage_dev, NULL, 0); + zassert_equal(ret, 0, "Failed to mkfs with 2K blocks"); + + mp->flags = FS_MOUNT_FLAG_NO_FORMAT; + ret = fs_mount(mp); + zassert_equal(ret, 0, "Mount failed (ret=%d)", ret); + + ret = fs_statvfs(mp->mnt_point, &sbuf); + zassert_equal(ret, 0, "Expected success (ret=%d)", ret); + + uint32_t bsize = sbuf.f_bsize; - ret = fs_open(&file, file_path, FS_O_RDWR); - zassert_equal(ret, 0, "File open failed (ret=%d)", ret); + uint32_t bytes_to_write = bsize * 13; - ret = fs_truncate(&file, new_size); - zassert_equal(ret, 0, "File truncate failed (ret=%d)", ret); + TC_PRINT("Block size: %d\nBytes_to_write: %d\n", bsize, bytes_to_write); - ret = fs_stat(file_path, &entry); - zassert_equal(ret, 0, "File stat failed (ret=%d)", ret); - zassert_equal(entry.size, new_size, - "Wrong file size %d (expected %d)", entry.size, new_size); + write_to_file(file_path, bytes_to_write); - ret = fs_seek(&file, 0, FS_SEEK_SET); - zassert_equal(ret, 0, "File seek failed (ret=%d)", ret); + /* First truncate will remove all blocks under first indirect block. + * Second truncate will remove rest of blocks; + * it will check if first indirect block was removed properly. + */ + uint32_t sizes[] = {12 * bsize, 0}; - ret = testfs_verify_incrementing(&file, 0, new_size); - zassert_equal(ret, new_size, "Different number of bytes read %ld (expected %ld)", - ret, new_size); + for (int i = 0; i < ARRAY_SIZE(sizes); i++) { + uint32_t new_size = sizes[i]; - ret = fs_close(&file); - zassert_equal(ret, 0, "File close failed (ret=%d)", ret); + truncate_file(file_path, new_size); } ret = fs_unmount(mp); diff --git a/tests/subsys/fs/littlefs/boards/native_sim_native_64.overlay b/tests/subsys/fs/littlefs/boards/native_sim_native_64.overlay new file mode 100644 index 00000000000..e4994493dd6 --- /dev/null +++ b/tests/subsys/fs/littlefs/boards/native_sim_native_64.overlay @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "native_sim.overlay" diff --git a/tests/subsys/input/longpress/boards/native_sim_native_64.overlay b/tests/subsys/input/longpress/boards/native_sim_native_64.overlay new file mode 100644 index 00000000000..091e5d6abd6 --- /dev/null +++ b/tests/subsys/input/longpress/boards/native_sim_native_64.overlay @@ -0,0 +1,6 @@ +/* + * Copyright 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "native_sim.overlay" diff --git a/tests/subsys/llext/simple/CMakeLists.txt b/tests/subsys/llext/simple/CMakeLists.txt index 2bea2e9b7bf..2a677470f66 100644 --- a/tests/subsys/llext/simple/CMakeLists.txt +++ b/tests/subsys/llext/simple/CMakeLists.txt @@ -15,34 +15,42 @@ target_include_directories(app PRIVATE ${ZEPHYR_BASE}/arch/${ARCH}/include ) -if(NOT LOADER_BUILD_ONLY) - set(ext_names hello_world logging relative_jump object syscalls threads_kernel_objects) +set(ext_names hello_world logging relative_jump object syscalls threads_kernel_objects) - if(CONFIG_ARM) - if(NOT CONFIG_CPU_CORTEX_M0 AND NOT CONFIG_CPU_CORTEX_M0PLUS AND NOT CONFIG_CPU_CORTEX_M1) - list(APPEND ext_names movwmovt) - endif() +if(CONFIG_ARM) + if(NOT CONFIG_CPU_CORTEX_M0 AND NOT CONFIG_CPU_CORTEX_M0PLUS AND NOT CONFIG_CPU_CORTEX_M1) + list(APPEND ext_names movwmovt) endif() +endif() + +# generate extension targets foreach extension given by 'ext_names' +foreach(ext_name ${ext_names}) + set(ext_src ${PROJECT_SOURCE_DIR}/src/${ext_name}_ext.c) + set(ext_bin ${ZEPHYR_BINARY_DIR}/${ext_name}.llext) + set(ext_inc ${ZEPHYR_BINARY_DIR}/include/generated/${ext_name}.inc) + add_llext_target(${ext_name}_ext + OUTPUT ${ext_bin} + SOURCES ${ext_src} + ) + generate_inc_file_for_target(app ${ext_bin} ${ext_inc}) +endforeach() - # generate extension targets foreach extension given by 'ext_names' - foreach(ext_name ${ext_names}) - set(ext_src ${PROJECT_SOURCE_DIR}/src/${ext_name}_ext.c) - set(ext_bin ${ZEPHYR_BINARY_DIR}/${ext_name}.llext) - set(ext_inc ${ZEPHYR_BINARY_DIR}/include/generated/${ext_name}.inc) - add_llext_target(${ext_name}_ext - OUTPUT ${ext_bin} - SOURCES ${ext_src} - ) - generate_inc_file_for_target(app ${ext_bin} ${ext_inc}) - endforeach() - - # Add a dummy custom processing command to test add_llext_command - get_target_property(proc_in_file hello_world_ext lib_output) - get_target_property(proc_out_file hello_world_ext pkg_input) - add_llext_command( - TARGET hello_world_ext - POST_BUILD - COMMAND echo "dummy patching ${proc_in_file} to create ${proc_out_file}" - COMMAND ${CMAKE_COMMAND} -E copy ${proc_in_file} ${proc_out_file} +if(NOT CONFIG_LLEXT_TYPE_ELF_OBJECT) + add_llext_target(multi_file_ext + OUTPUT ${ZEPHYR_BINARY_DIR}/multi_file.llext + SOURCES ${PROJECT_SOURCE_DIR}/src/multi_file_ext1.c ${PROJECT_SOURCE_DIR}/src/multi_file_ext2.c + ) + generate_inc_file_for_target(app ${ZEPHYR_BINARY_DIR}/multi_file.llext + ${ZEPHYR_BINARY_DIR}/include/generated/multi_file.inc ) endif() + +# Add a dummy custom processing command to test add_llext_command +get_target_property(proc_in_file hello_world_ext lib_output) +get_target_property(proc_out_file hello_world_ext pkg_input) +add_llext_command( + TARGET hello_world_ext + POST_BUILD + COMMAND echo "dummy patching ${proc_in_file} to create ${proc_out_file}" + COMMAND ${CMAKE_COMMAND} -E copy ${proc_in_file} ${proc_out_file} +) diff --git a/tests/subsys/llext/simple/src/multi_file_ext1.c b/tests/subsys/llext/simple/src/multi_file_ext1.c new file mode 100644 index 00000000000..018c11af6fa --- /dev/null +++ b/tests/subsys/llext/simple/src/multi_file_ext1.c @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2024 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * This code demonstrates multi-file object and function linking support. + */ + +#include +#include +#include + +/* Test non-static global object relocation */ +int number = 0x42; +extern int ext_number; +int ext_sum_fn(int arg); + +void test_entry(void) +{ + printk("initial: local %d plus external %d equals %d\n", + number, ext_number, ext_sum_fn(ext_number)); + number ^= ext_number; + ext_number ^= number; + number ^= ext_number; + printk("updated: local %d plus external %d equals %d\n", + number, ext_number, ext_sum_fn(ext_number)); +} +LL_EXTENSION_SYMBOL(test_entry); diff --git a/tests/subsys/llext/simple/src/multi_file_ext2.c b/tests/subsys/llext/simple/src/multi_file_ext2.c new file mode 100644 index 00000000000..e9ed12997bc --- /dev/null +++ b/tests/subsys/llext/simple/src/multi_file_ext2.c @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2024 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* File 2 of the multi-file linking test */ + +extern int number; +int ext_number = 0x18; + +int ext_sum_fn(int arg) +{ + return arg + number; +} diff --git a/tests/subsys/llext/simple/src/test_llext_simple.c b/tests/subsys/llext/simple/src/test_llext_simple.c index 90fadb68f12..f5e608d8912 100644 --- a/tests/subsys/llext/simple/src/test_llext_simple.c +++ b/tests/subsys/llext/simple/src/test_llext_simple.c @@ -180,7 +180,6 @@ void load_call_unload(struct llext_test *test_case) llext_unload(&ext); } -#ifndef LOADER_BUILD_ONLY /* * Attempt to load, list, list symbols, call a fn, and unload each * extension in the test table. This excercises loading, calling into, and @@ -219,6 +218,7 @@ static LLEXT_CONST uint8_t object_ext[] __aligned(4) = { }; LLEXT_LOAD_UNLOAD(object, true, NULL) +#ifndef CONFIG_LLEXT_TYPE_ELF_RELOCATABLE static LLEXT_CONST uint8_t syscalls_ext[] __aligned(4) = { #include "syscalls.inc" }; @@ -228,7 +228,14 @@ static LLEXT_CONST uint8_t threads_kernel_objects_ext[] __aligned(4) = { #include "threads_kernel_objects.inc" }; LLEXT_LOAD_UNLOAD(threads_kernel_objects, true, threads_objects_perm_setup) -#endif /* ! LOADER_BUILD_ONLY */ +#endif + +#ifndef CONFIG_LLEXT_TYPE_ELF_OBJECT +static LLEXT_CONST uint8_t multi_file_ext[] __aligned(4) = { + #include "multi_file.inc" +}; +LLEXT_LOAD_UNLOAD(multi_file, true, NULL) +#endif /* diff --git a/tests/subsys/llext/simple/testcase.yaml b/tests/subsys/llext/simple/testcase.yaml index 2a90bd1fadb..9f9f70a944c 100644 --- a/tests/subsys/llext/simple/testcase.yaml +++ b/tests/subsys/llext/simple/testcase.yaml @@ -8,22 +8,14 @@ common: - qemu_cortex_r5 # unsupported relocations tests: - # add_llext_target() supports a fairly limited number of - # CONFIG_urations. For instance, invoking add_llext_target() - # currently blocks us from compiling subsys/llext/*.c in 64bits mode; - # CMake aborts before even invoking the compiler. - # # While there is in practice no value in compiling subsys/llext/*.c # without actually running it to load some extension, let's keep it in - # good shape and ready to be used when add_llext_target() - # limitations get lifted in the future. + # good shape and ready to be used by additional architectures in the + # future. llext.simple.loader_build: build_only: true # How to override the above and allow ANY arch? arch_allow: arm arm64 x86 x86_64 xtensa posix - extra_args: - - LOADER_BUILD_ONLY=1 - - EXTRA_CFLAGS=-DLOADER_BUILD_ONLY=1 llext.simple.readonly: arch_exclude: xtensa # for now @@ -55,6 +47,16 @@ tests: - CONFIG_MODULES=y - CONFIG_LLEXT_STORAGE_WRITABLE=y - CONFIG_LLEXT_TEST_HELLO=m + llext.simple.modules_enabled_writable_relocatable: + arch_exclude: arm arm64 + filter: not CONFIG_MPU and not CONFIG_MMU + integration_platforms: + - qemu_xtensa + extra_configs: + - CONFIG_MODULES=y + - CONFIG_LLEXT_STORAGE_WRITABLE=y + - CONFIG_LLEXT_TYPE_ELF_RELOCATABLE=y + - CONFIG_LLEXT_TEST_HELLO=m llext.simple.modules_enabled_readonly: filter: not CONFIG_MPU and not CONFIG_MMU arch_exclude: xtensa # for now diff --git a/tests/subsys/logging/log_api/src/mock_backend.c b/tests/subsys/logging/log_api/src/mock_backend.c index e9cd66978ac..ab4d901c369 100644 --- a/tests/subsys/logging/log_api/src/mock_backend.c +++ b/tests/subsys/logging/log_api/src/mock_backend.c @@ -140,7 +140,7 @@ static void process(const struct log_backend *const backend, } zassert_equal(msg->log.hdr.timestamp, exp->timestamp, -#if CONFIG_LOG_TIMESTAMP_64BIT +#ifdef CONFIG_LOG_TIMESTAMP_64BIT "Got: %llu, expected: %llu", #else "Got: %u, expected: %u", diff --git a/tests/subsys/logging/log_backend_fs/boards/native_sim_native_64.conf b/tests/subsys/logging/log_backend_fs/boards/native_sim_native_64.conf new file mode 100644 index 00000000000..92c00c89a36 --- /dev/null +++ b/tests/subsys/logging/log_backend_fs/boards/native_sim_native_64.conf @@ -0,0 +1 @@ +CONFIG_LOG_MODE_DEFERRED=y diff --git a/tests/subsys/logging/log_backend_fs/boards/native_sim_native_64.overlay b/tests/subsys/logging/log_backend_fs/boards/native_sim_native_64.overlay new file mode 100644 index 00000000000..91647f82e20 --- /dev/null +++ b/tests/subsys/logging/log_backend_fs/boards/native_sim_native_64.overlay @@ -0,0 +1,6 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "native_sim.overlay" diff --git a/tests/subsys/logging/log_core_additional/log_thread.conf b/tests/subsys/logging/log_core_additional/log_thread.conf new file mode 100644 index 00000000000..6940a607ee5 --- /dev/null +++ b/tests/subsys/logging/log_core_additional/log_thread.conf @@ -0,0 +1,18 @@ +CONFIG_MAIN_THREAD_PRIORITY=5 +CONFIG_ZTEST=y +CONFIG_TEST_LOGGING_DEFAULTS=n +CONFIG_LOG=y +CONFIG_LOG_OUTPUT=y +CONFIG_LOG_PRINTK=n +CONFIG_LOG_SPEED=y +CONFIG_LOG_BUFFER_SIZE=1024 +CONFIG_CBPRINTF_FP_SUPPORT=y +CONFIG_CBPRINTF_LIBC_SUBSTS=y +CONFIG_ZTEST_STACK_SIZE=4096 +CONFIG_LOG_MODE_DEFERRED=y +CONFIG_LOG_PROCESS_THREAD_SLEEP_MS=200 +CONFIG_MAIN_STACK_SIZE=4096 + +CONFIG_MPSC_CLEAR_ALLOCATED=y +CONFIG_LOG_BACKEND_UART=y +CONFIG_THREAD_MONITOR=y diff --git a/tests/subsys/logging/log_core_additional/src/log_test.c b/tests/subsys/logging/log_core_additional/src/log_test.c index 2542a4887dc..1af13cb5622 100644 --- a/tests/subsys/logging/log_core_additional/src/log_test.c +++ b/tests/subsys/logging/log_core_additional/src/log_test.c @@ -409,8 +409,6 @@ ZTEST(test_log_core_additional, test_multiple_backends) #ifdef CONFIG_LOG_PROCESS_THREAD ZTEST(test_log_core_additional, test_log_thread) { - uint32_t slabs_free, used, max; - TC_PRINT("Logging buffer is configured to %d bytes\n", CONFIG_LOG_BUFFER_SIZE); @@ -420,25 +418,19 @@ ZTEST(test_log_core_additional, test_log_thread) log_setup(false); - slabs_free = log_msg_mem_get_free(); - used = log_msg_mem_get_used(); - max = log_msg_mem_get_max_used(); - zassert_equal(used, 0); + zassert_false(log_data_pending()); LOG_INF("log info to log thread"); LOG_WRN("log warning to log thread"); LOG_ERR("log error to log thread"); - zassert_equal(log_msg_mem_get_used(), 3); - zassert_equal(log_msg_mem_get_free(), slabs_free - 3); - zassert_equal(log_msg_mem_get_max_used(), max); + zassert_true(log_data_pending()); - TC_PRINT("after log, free: %d, used: %d, max: %d\n", slabs_free, used, max); /* wait 2 seconds for logging thread to handle this log message*/ k_sleep(K_MSEC(2000)); zassert_equal(3, backend1_cb.counter, "Unexpected amount of messages received by the backend."); - zassert_equal(log_msg_mem_get_used(), 0); + zassert_false(log_data_pending()); } #else ZTEST(test_log_core_additional, test_log_thread) @@ -447,6 +439,41 @@ ZTEST(test_log_core_additional, test_log_thread) } #endif +/** + * @brief Process all logging activities using a dedicated thread (trigger immediate processing) + * + * @addtogroup logging + */ + +#ifdef CONFIG_LOG_PROCESS_THREAD +ZTEST(test_log_core_additional, test_log_thread_trigger) +{ + log_setup(false); + + zassert_false(log_data_pending()); + + LOG_INF("log info to log thread"); + LOG_WRN("log warning to log thread"); + LOG_ERR("log error to log thread"); + + zassert_true(log_data_pending()); + + /* Trigger log thread to process messages as soon as possible. */ + log_thread_trigger(); + + /* wait 1ms to give logging thread chance to handle these log messages. */ + k_sleep(K_MSEC(1)); + zassert_equal(3, backend1_cb.counter, + "Unexpected amount of messages received by the backend."); + zassert_false(log_data_pending()); +} +#else +ZTEST(test_log_core_additional, test_log_thread_trigger) +{ + ztest_test_skip(); +} +#endif + static void call_log_generic(const char *fmt, ...) { va_list ap; @@ -491,7 +518,9 @@ ZTEST(test_log_core_additional, test_log_msg_create) Z_LOG_MSG_CREATE(!IS_ENABLED(CONFIG_USERSPACE), mode, Z_LOG_LOCAL_DOMAIN_ID, NULL, - LOG_LEVEL_INTERNAL_RAW_STRING, NULL, 0, TEST_MESSAGE); + LOG_LEVEL_INF, NULL, 0, TEST_MESSAGE); + + backend1_cb.total_logs = 3; while (log_test_process()) { } diff --git a/tests/subsys/logging/log_core_additional/testcase.yaml b/tests/subsys/logging/log_core_additional/testcase.yaml index 53c2d34f5e0..3fc9db4902a 100644 --- a/tests/subsys/logging/log_core_additional/testcase.yaml +++ b/tests/subsys/logging/log_core_additional/testcase.yaml @@ -9,18 +9,8 @@ tests: extra_args: CONF_FILE=log_sync.conf integration_platforms: - native_sim - logging.log_user: + logging.thread: tags: logging - filter: CONFIG_USERSPACE - extra_args: - - CONF_FILE=log_user.conf - - USERSPACE_TEST=1 - # FIXME: log_user test fails when compiled with the GCC 12 from Zephyr SDK. - # (see the GitHub issue zephyrproject-rtos/zephyr#49213) - # Make sure to un-comment `integration_platforms` when the above - # issue is fixed. It has been temporarily disabled because - # `integration_platforms` and `toolchain_exclude` cannot be used - # together. - toolchain_exclude: zephyr - # integration_platforms: - # - qemu_x86 + extra_args: CONF_FILE=log_thread.conf + integration_platforms: + - native_sim diff --git a/tests/subsys/lorawan/channels_mask/CMakeLists.txt b/tests/subsys/lorawan/channels_mask/CMakeLists.txt new file mode 100644 index 00000000000..22b6b5b4d8e --- /dev/null +++ b/tests/subsys/lorawan/channels_mask/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(lorawan_channels_mask_test) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/tests/subsys/lorawan/channels_mask/prj.conf b/tests/subsys/lorawan/channels_mask/prj.conf new file mode 100644 index 00000000000..8b45467c410 --- /dev/null +++ b/tests/subsys/lorawan/channels_mask/prj.conf @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: Apache-2.0 +CONFIG_ZTEST=y +CONFIG_ASSERT=y +CONFIG_SPI=y +CONFIG_GPIO=y +CONFIG_LORA=y +CONFIG_LORAWAN=y +CONFIG_LORAMAC_REGION_AS923=y +CONFIG_LORAMAC_REGION_AU915=y +CONFIG_MAIN_STACK_SIZE=2048 +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048 diff --git a/tests/subsys/lorawan/channels_mask/src/main.c b/tests/subsys/lorawan/channels_mask/src/main.c new file mode 100644 index 00000000000..cd72b800dad --- /dev/null +++ b/tests/subsys/lorawan/channels_mask/src/main.c @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2024 Jeferson Fernando + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +/** + * @brief Test channels mask with size 1 + * + * This test will request the channels mask changes, passing valid + * and invalid arguments and checking when it's successful or returns error + * + */ +ZTEST(channels_mask, test_mask_size_1) +{ + int err = 0; + uint16_t channels_mask[LORAWAN_CHANNELS_MASK_SIZE_AS923] = {0xffff}; + + /* Test the function when a region with mask size 1 is being used */ + err = lorawan_set_region(LORAWAN_REGION_AS923); + zassert_equal(err, 0, "Could not set region"); + + err = lorawan_start(); + zassert_equal(err, 0, "Could not start stack"); + + /* Configure channels mask with expected parameters */ + err = lorawan_set_channels_mask(channels_mask, LORAWAN_CHANNELS_MASK_SIZE_AS923); + zassert_equal(err, 0, "Denied right channels mask configuration"); + + /* Configure channels mask with unexpected channels mask size */ + err = lorawan_set_channels_mask(channels_mask, LORAWAN_CHANNELS_MASK_SIZE_AU915); + zassert_equal(err, -EINVAL, "Accepted an unexpected mask size for the selected region"); + + /* Configure channels mask with pointer to NULL */ + err = lorawan_set_channels_mask(NULL, LORAWAN_CHANNELS_MASK_SIZE_AS923); + zassert_equal(err, -EINVAL, "Accepted a pointer to NULL"); +} + +/** + * @brief Test channels mask with size 6 + * + * This test will request the channels mask changes, passing valid + * and invalid arguments and checking when it's successful or returns error + * + */ +ZTEST(channels_mask, test_mask_size_6) +{ + int err = 0; + uint16_t channels_mask[LORAWAN_CHANNELS_MASK_SIZE_AU915] = {0}; + + /* Test the function when a region with mask size 6 is being used */ + err = lorawan_set_region(LORAWAN_REGION_AU915); + zassert_equal(err, 0, "Could not set region"); + + err = lorawan_start(); + zassert_equal(err, 0, "Could not start stack"); + + /* Configure channels mask with expected parameters */ + err = lorawan_set_channels_mask(channels_mask, LORAWAN_CHANNELS_MASK_SIZE_AU915); + zassert_equal(err, 0, "Denied right channels mask configuration"); + + /* Configure channels mask with unexpected channels mask size */ + err = lorawan_set_channels_mask(channels_mask, LORAWAN_CHANNELS_MASK_SIZE_AS923); + zassert_equal(err, -EINVAL, "Accepted an unexpected mask size for the selected region"); + + /* Configure channels mask with pointer to NULL */ + err = lorawan_set_channels_mask(NULL, LORAWAN_CHANNELS_MASK_SIZE_AU915); + zassert_equal(err, -EINVAL, "Accepted a pointer to NULL"); +} + +ZTEST_SUITE(channels_mask, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/subsys/lorawan/channels_mask/testcase.yaml b/tests/subsys/lorawan/channels_mask/testcase.yaml new file mode 100644 index 00000000000..7290e16c92b --- /dev/null +++ b/tests/subsys/lorawan/channels_mask/testcase.yaml @@ -0,0 +1,6 @@ +tests: + lorawan.channels_mask.set_channels_mask: + tags: lorawan + depends_on: lora + integration_platforms: + - b_l072z_lrwan1 diff --git a/tests/subsys/lorawan/clock_sync/src/main.c b/tests/subsys/lorawan/clock_sync/src/main.c index f1557c9fcba..3534a0dec6b 100644 --- a/tests/subsys/lorawan/clock_sync/src/main.c +++ b/tests/subsys/lorawan/clock_sync/src/main.c @@ -81,7 +81,7 @@ ZTEST(clock_sync, test_app_time) device_time = sys_get_le32(req.data + 1); token_req = req.data[5] & 0xF; - zassert_within((int)device_time, (int)(k_uptime_get() / 1000), 1); + zassert_within((int)device_time, k_uptime_seconds(), 1); /* apply a time correction of 1000 seconds */ sys_put_le32(1000, ans_data + 1); @@ -90,7 +90,7 @@ ZTEST(clock_sync, test_app_time) lorawan_emul_send_downlink(CLOCK_SYNC_PORT, false, 0, 0, sizeof(ans_data), ans_data); lorawan_clock_sync_get(&gps_time); - zassert_within(gps_time, (k_uptime_get() / 1000) + 1000, 1); + zassert_within(gps_time, k_uptime_seconds() + 1000, 1); } ZTEST(clock_sync, test_device_app_time_periodicity) diff --git a/tests/subsys/lorawan/frag_decoder/CMakeLists.txt b/tests/subsys/lorawan/frag_decoder/CMakeLists.txt new file mode 100644 index 00000000000..664fc0371ad --- /dev/null +++ b/tests/subsys/lorawan/frag_decoder/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(lorawan_frag_decoder_test) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/tests/subsys/lorawan/frag_decoder/boards/native_sim.conf b/tests/subsys/lorawan/frag_decoder/boards/native_sim.conf new file mode 100644 index 00000000000..ef6a0585184 --- /dev/null +++ b/tests/subsys/lorawan/frag_decoder/boards/native_sim.conf @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: Apache-2.0 + +# Turn off log messages for failed communication with non-existing LoRa PHY +CONFIG_LORA_LOG_LEVEL_OFF=y diff --git a/tests/subsys/lorawan/frag_decoder/boards/native_sim.overlay b/tests/subsys/lorawan/frag_decoder/boards/native_sim.overlay new file mode 100644 index 00000000000..5101a21d8c3 --- /dev/null +++ b/tests/subsys/lorawan/frag_decoder/boards/native_sim.overlay @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2024 A Labs GmbH + * + * SPDX-License-Identifier: Apache-2.0 + * + * This overlay defines a fake LoRa PHY node which is required to build the driver. + */ + +#include + +/ { + chosen { + zephyr,code-partition = &slot0_partition; + }; + + aliases { + lora0 = &lora; + }; + + test { + #address-cells = <1>; + #size-cells = <1>; + + test_spi: spi@33334444 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "vnd,spi"; + reg = <0x33334444 0x1000>; + status = "okay"; + clock-frequency = <2000000>; + + cs-gpios = <&gpio0 1 GPIO_ACTIVE_LOW>; + + lora: lora@0 { + compatible = "semtech,sx1262"; + status = "okay"; + reg = <0>; + reset-gpios = <&gpio0 2 GPIO_ACTIVE_LOW>; + busy-gpios = <&gpio0 3 GPIO_ACTIVE_HIGH>; + tx-enable-gpios = <&gpio0 4 GPIO_ACTIVE_LOW>; + rx-enable-gpios = <&gpio0 5 GPIO_ACTIVE_LOW>; + dio1-gpios = <&gpio0 5 GPIO_ACTIVE_HIGH>; + dio2-tx-enable; + dio3-tcxo-voltage = ; + tcxo-power-startup-delay-ms = <5>; + spi-max-frequency = <1000000>; + }; + }; + }; +}; diff --git a/tests/subsys/lorawan/frag_decoder/prj.conf b/tests/subsys/lorawan/frag_decoder/prj.conf new file mode 100644 index 00000000000..50141338caf --- /dev/null +++ b/tests/subsys/lorawan/frag_decoder/prj.conf @@ -0,0 +1,33 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_ZTEST=y + +# General Zephyr settings +CONFIG_MAIN_STACK_SIZE=2048 +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048 +CONFIG_THREAD_NAME=y +CONFIG_LOG=y + +# LoRa PHY and required peripherals +CONFIG_LORA=y +CONFIG_SPI=y +CONFIG_GPIO=y + +# Random number generator required for several LoRaWAN services +CONFIG_ENTROPY_GENERATOR=y + +# LoRaWAN application layer +CONFIG_LORAWAN=y +CONFIG_LORAWAN_EMUL=y +CONFIG_LORAMAC_REGION_EU868=y + +# LoRaWAN services required for this test +CONFIG_LORAWAN_SERVICES=y +CONFIG_LORAWAN_FRAG_TRANSPORT=y + +# Flash driver to store firmware image +CONFIG_FLASH=y +CONFIG_FLASH_MAP=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_STREAM_FLASH=y +CONFIG_IMG_MANAGER=y diff --git a/tests/subsys/lorawan/frag_decoder/src/frag_encoder.c b/tests/subsys/lorawan/frag_decoder/src/frag_encoder.c new file mode 100644 index 00000000000..a782647c22b --- /dev/null +++ b/tests/subsys/lorawan/frag_decoder/src/frag_encoder.c @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2024 A Labs GmbH + * Copyright (c) 2024 tado GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * Implementation of the fragment encoding algorithm described in the LoRaWAN TS004-1.0.0. + * https://lora-alliance.org/wp-content/uploads/2020/11/fragmented_data_block_transport_v1.0.0.pdf + * + * Note: This algorithm is not compatible with TS004-2.0.0, which has some subtle differences + * in the parity matrix generation. + * + * Variable naming according to LoRaWAN specification: + * + * M: Number of uncoded fragments (original data) + * N: Number of coded fragments (including the original data at the beginning) + * CR: Coding ratio M/N + */ + +#include "frag_encoder.h" + +#include +#include + +LOG_MODULE_REGISTER(lorawan_frag_enc, CONFIG_LORAWAN_SERVICES_LOG_LEVEL); + +/** + * Generate a 23bit Pseudorandom Binary Sequence (PRBS) + * + * @param seed Seed input value + * + * @returns Pseudorandom output value + */ +static int32_t prbs23(int32_t seed) +{ + int32_t b0 = seed & 1; + int32_t b1 = (seed & 32) / 32; + + return (seed / 2) + ((b0 ^ b1) << 22); +} + +/** + * Generate vector for coded fragment n of the MxN parity matrix + * + * @param m Total number of uncoded fragments (M) + * @param n Coded fragment number (starting at 1 and not 0) + * @param vec Output vector (buffer size must be greater than m) + */ +void lorawan_fec_parity_matrix_vector(int m, int n, uint8_t *vec) +{ + int mm, x, r; + + memset(vec, 0, m); + + /* + * Powers of 2 must be treated differently to make sure matrix content is close + * to random. Powers of 2 tend to generate patterns. + */ + if (is_power_of_two(m)) { + mm = m + 1; + } else { + mm = m; + } + + x = 1 + (1001 * n); + + for (int nb_coeff = 0; nb_coeff < (m / 2); nb_coeff++) { + r = (1 << 16); + while (r >= m) { + x = prbs23(x); + r = x % mm; + } + vec[r] = 1; + } +} + +int lorawan_frag_encoder(const uint8_t *uncoded, size_t uncoded_len, uint8_t *coded, + size_t coded_size, size_t frag_size, unsigned int redundant_frags) +{ + int uncoded_frags = DIV_ROUND_UP(uncoded_len, frag_size); + int coded_frags = uncoded_frags + redundant_frags; + uint8_t parity_vec[frag_size]; + + memset(parity_vec, 0, sizeof(parity_vec)); + + if (coded_size < coded_frags * frag_size) { + LOG_ERR("output buffer not large enough"); + return -EINVAL; + } + + /* copy uncoded frags to the beginning of coded fragments and pad with zeros */ + memcpy(coded, uncoded, uncoded_len); + memset(coded + uncoded_len, 0, uncoded_frags * frag_size - uncoded_len); + + /* generate remaining coded (redundant) frags */ + for (int i = 1; i <= redundant_frags; i++) { + lorawan_fec_parity_matrix_vector(uncoded_frags, i, parity_vec); + + uint8_t *out = coded + (uncoded_frags + i - 1) * frag_size; + + for (int j = 0; j < uncoded_frags; j++) { + if (parity_vec[j] == 1) { + for (int m = 0; m < frag_size; m++) { + out[m] ^= coded[j * frag_size + m]; + } + } + } + } + + return 0; +} diff --git a/tests/subsys/lorawan/frag_decoder/src/frag_encoder.h b/tests/subsys/lorawan/frag_decoder/src/frag_encoder.h new file mode 100644 index 00000000000..62c660aa27d --- /dev/null +++ b/tests/subsys/lorawan/frag_decoder/src/frag_encoder.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2024 A Labs GmbH + * Copyright (c) 2024 tado GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef TEST_SUBSYS_LORAWAN_FRAG_DECODER_SRC_FRAG_ENCODER_H_ +#define TEST_SUBSYS_LORAWAN_FRAG_DECODER_SRC_FRAG_ENCODER_H_ + +#include +#include + +/** + * Generate coded binary data according to LoRaWAN TS004-1.0.0 + * + * @param uncoded Pointer to uncoded data buffer (e.g. firmware binary) + * @param uncoded_len Length of uncoded data in bytes + * @param coded Pointer to buffer for resulting coded data + * @param coded_size Size of the buffer for coded data + * @param frag_size Fragment size to be used + * @param redundant_frags Absolute number of redundant fragments to be generated + * + * @returns 0 for success or negative error code otherwise. + */ +int lorawan_frag_encoder(const uint8_t *uncoded, size_t uncoded_len, uint8_t *coded, + size_t coded_size, size_t frag_size, unsigned int redundant_frags); + +#endif /* TEST_SUBSYS_LORAWAN_FRAG_DECODER_SRC_FRAG_ENCODER_H_ */ diff --git a/tests/subsys/lorawan/frag_decoder/src/main.c b/tests/subsys/lorawan/frag_decoder/src/main.c new file mode 100644 index 00000000000..20714c8a4b1 --- /dev/null +++ b/tests/subsys/lorawan/frag_decoder/src/main.c @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2024 A Labs GmbH + * Copyright (c) 2024 tado GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "frag_encoder.h" + +#define FRAG_SIZE CONFIG_LORAWAN_FRAG_TRANSPORT_MAX_FRAG_SIZE +#define FIRMWARE_SIZE (FRAG_SIZE * 100 + 1) /* not divisible by frag size to test padding */ +#define UNCODED_FRAGS (DIV_ROUND_UP(FIRMWARE_SIZE, FRAG_SIZE)) +#define REDUNDANT_FRAGS \ + (DIV_ROUND_UP(UNCODED_FRAGS * CONFIG_LORAWAN_FRAG_TRANSPORT_MAX_REDUNDANCY, 100)) +#define PADDING (UNCODED_FRAGS * FRAG_SIZE - FIRMWARE_SIZE) + +#define CMD_FRAG_SESSION_SETUP (0x02) +#define CMD_DATA_FRAGMENT (0x08) +#define FRAG_TRANSPORT_PORT (201) +#define FRAG_SESSION_INDEX (1) + +#define TARGET_IMAGE_AREA FIXED_PARTITION_ID(slot1_partition) + +/* below array would normally hold the actual firmware binary */ +static uint8_t fw_uncoded[FIRMWARE_SIZE]; + +/* enough space for redundancy of up to 100% */ +static uint8_t fw_coded[(UNCODED_FRAGS + REDUNDANT_FRAGS) * FRAG_SIZE]; + +static const struct flash_area *fa; + +static struct k_sem fuota_finished_sem; + +static void fuota_finished(void) +{ + k_sem_give(&fuota_finished_sem); +} + +ZTEST(frag_decoder, test_frag_transport) +{ + uint8_t buf[256]; /* maximum size of one LoRaWAN message */ + uint8_t frag_session_setup_req[] = { + CMD_FRAG_SESSION_SETUP, + 0x1f, + UNCODED_FRAGS & 0xFF, + (UNCODED_FRAGS >> 8) & 0xFF, + FRAG_SIZE, + 0x01, + PADDING, + 0x00, + 0x00, + 0x00, + 0x00, + }; + int ret; + + k_sem_reset(&fuota_finished_sem); + + lorawan_emul_send_downlink(FRAG_TRANSPORT_PORT, false, 0, 0, sizeof(frag_session_setup_req), + frag_session_setup_req); + + for (int i = 0; i < sizeof(fw_coded) / FRAG_SIZE; i++) { + if (i % 10 == 9) { + /* loose every 10th packet */ + continue; + } + buf[0] = CMD_DATA_FRAGMENT; + buf[1] = (i + 1) & 0xFF; + buf[2] = (FRAG_SESSION_INDEX << 6) | ((i + 1) >> 8); + memcpy(buf + 3, fw_coded + i * FRAG_SIZE, FRAG_SIZE); + lorawan_emul_send_downlink(FRAG_TRANSPORT_PORT, false, 0, 0, FRAG_SIZE + 3, buf); + } + + for (int i = 0; i < UNCODED_FRAGS; i++) { + size_t num_bytes = (i == UNCODED_FRAGS - 1) ? (FRAG_SIZE - PADDING) : FRAG_SIZE; + + flash_area_read(fa, i * FRAG_SIZE, buf, num_bytes); + zassert_mem_equal(buf, fw_coded + i * FRAG_SIZE, num_bytes, "fragment %d invalid", + i + 1); + } + + ret = k_sem_take(&fuota_finished_sem, K_MSEC(100)); + zassert_equal(ret, 0, "FUOTA finish timed out"); +} + +static void *frag_decoder_setup(void) +{ + const struct device *lora_dev = DEVICE_DT_GET(DT_ALIAS(lora0)); + struct lorawan_join_config join_cfg = {0}; + int ret; + + /* populate firmware image with random data */ + sys_rand_get(fw_uncoded, sizeof(fw_uncoded)); + + /* create coded data (including redundant fragments) from firmware image */ + ret = lorawan_frag_encoder(fw_uncoded, sizeof(fw_uncoded), fw_coded, sizeof(fw_coded), + FRAG_SIZE, REDUNDANT_FRAGS); + zassert_equal(ret, 0, "creating coded data failed: %d", ret); + + k_sem_init(&fuota_finished_sem, 0, 1); + + ret = flash_area_open(TARGET_IMAGE_AREA, &fa); + zassert_equal(ret, 0, "opening flash area failed: %d", ret); + + zassert_true(device_is_ready(lora_dev), "LoRa device not ready"); + + ret = lorawan_start(); + zassert_equal(ret, 0, "lorawan_start failed: %d", ret); + + ret = lorawan_join(&join_cfg); + zassert_equal(ret, 0, "lorawan_join failed: %d", ret); + + lorawan_frag_transport_run(fuota_finished); + + return NULL; +} + +ZTEST_SUITE(frag_decoder, NULL, frag_decoder_setup, NULL, NULL, NULL); diff --git a/tests/subsys/lorawan/frag_decoder/testcase.yaml b/tests/subsys/lorawan/frag_decoder/testcase.yaml new file mode 100644 index 00000000000..fe68bfe2957 --- /dev/null +++ b/tests/subsys/lorawan/frag_decoder/testcase.yaml @@ -0,0 +1,7 @@ +common: + tags: + - lorawan +tests: + lorawan.frag_decoder: + platform_allow: + - native_sim diff --git a/tests/subsys/mgmt/mcumgr/all_options/prj.conf b/tests/subsys/mgmt/mcumgr/all_options/prj.conf index 42ce2e03c86..ed584f34762 100644 --- a/tests/subsys/mgmt/mcumgr/all_options/prj.conf +++ b/tests/subsys/mgmt/mcumgr/all_options/prj.conf @@ -4,8 +4,8 @@ # SPDX-License-Identifier: Apache-2.0 # CONFIG_ZTEST=y -CONFIG_TINYCRYPT=y -CONFIG_TINYCRYPT_SHA256=y +CONFIG_MBEDTLS=y +CONFIG_MBEDTLS_MAC_SHA256_ENABLED=y CONFIG_FILE_SYSTEM=y CONFIG_BASE64=y CONFIG_NET_BUF=y diff --git a/tests/subsys/mgmt/mcumgr/fs_mgmt_hash_supported/configuration/all.conf b/tests/subsys/mgmt/mcumgr/fs_mgmt_hash_supported/configuration/all.conf index 546b7f6128e..53b017ba80a 100644 --- a/tests/subsys/mgmt/mcumgr/fs_mgmt_hash_supported/configuration/all.conf +++ b/tests/subsys/mgmt/mcumgr/fs_mgmt_hash_supported/configuration/all.conf @@ -3,7 +3,7 @@ # # SPDX-License-Identifier: Apache-2.0 # -CONFIG_TINYCRYPT=y -CONFIG_TINYCRYPT_SHA256=y CONFIG_MCUMGR_GRP_FS_CHECKSUM_IEEE_CRC32=y CONFIG_MCUMGR_GRP_FS_HASH_SHA256=y +CONFIG_MBEDTLS=y +CONFIG_MBEDTLS_MAC_SHA256_ENABLED=y diff --git a/tests/subsys/mgmt/mcumgr/fs_mgmt_hash_supported/configuration/sha256.conf b/tests/subsys/mgmt/mcumgr/fs_mgmt_hash_supported/configuration/sha256.conf index d8f44a443a1..bf9bb9763c2 100644 --- a/tests/subsys/mgmt/mcumgr/fs_mgmt_hash_supported/configuration/sha256.conf +++ b/tests/subsys/mgmt/mcumgr/fs_mgmt_hash_supported/configuration/sha256.conf @@ -3,6 +3,7 @@ # # SPDX-License-Identifier: Apache-2.0 # -CONFIG_TINYCRYPT=y -CONFIG_TINYCRYPT_SHA256=y +CONFIG_MCUMGR_GRP_FS_CHECKSUM_IEEE_CRC32=n CONFIG_MCUMGR_GRP_FS_HASH_SHA256=y +CONFIG_MBEDTLS=y +CONFIG_MBEDTLS_MAC_SHA256_ENABLED=y diff --git a/tests/subsys/mgmt/mcumgr/fs_mgmt_hash_supported/testcase.yaml b/tests/subsys/mgmt/mcumgr/fs_mgmt_hash_supported/testcase.yaml index 4f07ecf0211..fd0da3fd047 100644 --- a/tests/subsys/mgmt/mcumgr/fs_mgmt_hash_supported/testcase.yaml +++ b/tests/subsys/mgmt/mcumgr/fs_mgmt_hash_supported/testcase.yaml @@ -20,6 +20,9 @@ tests: - lpcxpresso51u68 - nucleo_h745zi_q/stm32h745xx/m4 - stm32h747i_disco/stm32h747xx/m4 + - lpcxpresso55s69/lpc55s69/cpu1 + - mpfs_icicle + - apollo4p_evb mgmt.mcumgr.fs.mgmt.hash.supported.sha256: extra_args: > OVERLAY_CONFIG="configuration/sha256.conf" @@ -29,6 +32,9 @@ tests: - lpcxpresso51u68 - nucleo_h745zi_q/stm32h745xx/m4 - stm32h747i_disco/stm32h747xx/m4 + - lpcxpresso55s69/lpc55s69/cpu1 + - mpfs_icicle + - apollo4p_evb mgmt.mcumgr.fs.mgmt.hash.supported.all: extra_args: > OVERLAY_CONFIG="configuration/all.conf" @@ -38,3 +44,6 @@ tests: - lpcxpresso51u68 - nucleo_h745zi_q/stm32h745xx/m4 - stm32h747i_disco/stm32h747xx/m4 + - lpcxpresso55s69/lpc55s69/cpu1 + - mpfs_icicle + - apollo4p_evb diff --git a/tests/subsys/modem/modem_chat/src/main.c b/tests/subsys/modem/modem_chat/src/main.c index f9a37ecc6cc..e589c34bb92 100644 --- a/tests/subsys/modem/modem_chat/src/main.c +++ b/tests/subsys/modem/modem_chat/src/main.c @@ -193,6 +193,19 @@ MODEM_CHAT_SCRIPT_CMDS_DEFINE( MODEM_CHAT_SCRIPT_DEFINE(script_partial, script_partial_cmds, abort_matches, on_script_result, 4); +/*************************************************************************************************/ +/* Script containing timeout script chat command */ +/*************************************************************************************************/ +MODEM_CHAT_SCRIPT_CMDS_DEFINE( + script_timeout_cmd_cmds, + MODEM_CHAT_SCRIPT_CMD_RESP("AT", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP_NONE("", 4000), + MODEM_CHAT_SCRIPT_CMD_RESP("AT", ok_match), +); + +MODEM_CHAT_SCRIPT_DEFINE(script_timeout_cmd, script_timeout_cmd_cmds, abort_matches, + on_script_result, 10); + /*************************************************************************************************/ /* Small echo script and mock transactions */ /*************************************************************************************************/ @@ -610,6 +623,59 @@ ZTEST(modem_chat, test_script_run_dynamic_script_sync) zassert_ok(modem_chat_run_script(&cmd, &stack_script), "Failed to run script"); } +ZTEST(modem_chat, test_script_chat_timeout_cmd) +{ + int ret; + bool called; + + zassert_ok(modem_chat_run_script_async(&cmd, &script_timeout_cmd), + "Failed to start script"); + k_msleep(100); + + /* + * Script sends "AT\r\n"; + */ + ret = modem_backend_mock_get(&mock, buffer, ARRAY_SIZE(buffer)); + zassert_equal(ret, sizeof("AT\r\n") - 1); + zassert_true(memcmp(buffer, "AT\r\n", sizeof("AT\r\n") - 1) == 0, + "Request not sent as expected"); + + /* + * Modem responds OK + */ + modem_backend_mock_put(&mock, ok_response, sizeof(ok_response) - 1); + + /* + * Script waits 4 seconds + */ + k_msleep(3000); + zassert_equal(modem_backend_mock_get(&mock, buffer, ARRAY_SIZE(buffer)), 0); + k_msleep(2000); + + /* + * Script sends "AT\r\n"; + */ + ret = modem_backend_mock_get(&mock, buffer, ARRAY_SIZE(buffer)); + zassert_equal(ret, sizeof("AT\r\n") - 1); + zassert_true(memcmp(buffer, "AT\r\n", sizeof("AT\r\n") - 1) == 0, + "Request not sent as expected"); + + /* + * Modem responds OK + */ + modem_backend_mock_put(&mock, ok_response, sizeof(ok_response) - 1); + k_msleep(100); + + called = atomic_test_bit(&callback_called, MODEM_CHAT_UTEST_ON_SCRIPT_CALLBACK_BIT); + zassert_true(called == true, "Script callback should have been called"); + zassert_equal(script_result, MODEM_CHAT_SCRIPT_RESULT_SUCCESS, + "Script should have stopped with success"); + + /* Assert no data was sent except the request */ + zassert_equal(modem_backend_mock_get(&mock, buffer, ARRAY_SIZE(buffer)), 0, + "Script sent too many requests"); +} + /*************************************************************************************************/ /* Test suite */ /*************************************************************************************************/ diff --git a/tests/subsys/openthread/prj.conf b/tests/subsys/openthread/prj.conf index cee7218f847..f3884110630 100644 --- a/tests/subsys/openthread/prj.conf +++ b/tests/subsys/openthread/prj.conf @@ -2,6 +2,7 @@ CONFIG_SHELL=y CONFIG_ZTEST=y CONFIG_IEEE802154=y CONFIG_NETWORKING=y +CONFIG_NET_TEST=y # Network buffers CONFIG_NET_PKT_RX_COUNT=5 diff --git a/tests/subsys/openthread/testcase.yaml b/tests/subsys/openthread/testcase.yaml index c019aa9a8c5..163024d86b7 100644 --- a/tests/subsys/openthread/testcase.yaml +++ b/tests/subsys/openthread/testcase.yaml @@ -1,9 +1,10 @@ common: platform_allow: - - native_posix - - native_posix/native/64 - native_sim - native_sim/native/64 + platform_exclude: + - native_posix/native/64 + - native_posix integration_platforms: - native_sim tags: diff --git a/tests/subsys/pm/device_runtime_api/src/main.c b/tests/subsys/pm/device_runtime_api/src/main.c index 74f46eaf755..ba4482ac8f3 100644 --- a/tests/subsys/pm/device_runtime_api/src/main.c +++ b/tests/subsys/pm/device_runtime_api/src/main.c @@ -94,6 +94,7 @@ ZTEST(device_runtime_api, test_api) /* device is initially suspended */ (void)pm_device_state_get(test_dev, &state); zassert_equal(state, PM_DEVICE_STATE_SUSPENDED); + zassert_equal(pm_device_runtime_usage(test_dev), 0); /*** get + put ***/ @@ -107,6 +108,7 @@ ZTEST(device_runtime_api, test_api) /* usage: 1, +1, resume: no */ ret = pm_device_runtime_get(test_dev); zassert_equal(ret, 0); + zassert_equal(pm_device_runtime_usage(test_dev), 2); /* usage: 2, -1, suspend: no */ ret = pm_device_runtime_put(test_dev); @@ -118,6 +120,7 @@ ZTEST(device_runtime_api, test_api) /* usage: 1, -1, suspend: yes */ ret = pm_device_runtime_put(test_dev); zassert_equal(ret, 0); + zassert_equal(pm_device_runtime_usage(test_dev), 0); (void)pm_device_state_get(test_dev, &state); zassert_equal(state, PM_DEVICE_STATE_SUSPENDED); @@ -125,12 +128,14 @@ ZTEST(device_runtime_api, test_api) /* usage: 0, -1, suspend: no (unbalanced call) */ ret = pm_device_runtime_put(test_dev); zassert_equal(ret, -EALREADY); + zassert_equal(pm_device_runtime_usage(test_dev), 0); /*** get + asynchronous put until suspended ***/ /* usage: 0, +1, resume: yes */ ret = pm_device_runtime_get(test_dev); zassert_equal(ret, 0); + zassert_equal(pm_device_runtime_usage(test_dev), 1); (void)pm_device_state_get(test_dev, &state); zassert_equal(state, PM_DEVICE_STATE_ACTIVE); @@ -140,11 +145,13 @@ ZTEST(device_runtime_api, test_api) /* usage: 1, -1, suspend: yes (queued) */ ret = pm_device_runtime_put_async(test_dev, K_NO_WAIT); zassert_equal(ret, 0); + zassert_equal(pm_device_runtime_usage(test_dev), 0); if (IS_ENABLED(CONFIG_TEST_PM_DEVICE_ISR_SAFE)) { /* In sync mode async put is equivalent as normal put. */ (void)pm_device_state_get(test_dev, &state); zassert_equal(state, PM_DEVICE_STATE_SUSPENDED); + zassert_equal(pm_device_runtime_usage(test_dev), 0); } else { (void)pm_device_state_get(test_dev, &state); zassert_equal(state, PM_DEVICE_STATE_SUSPENDING); @@ -156,6 +163,7 @@ ZTEST(device_runtime_api, test_api) /* usage: 0, -1, suspend: no (unbalanced call) */ ret = pm_device_runtime_put_async(test_dev, K_NO_WAIT); zassert_equal(ret, -EALREADY); + zassert_equal(pm_device_runtime_usage(test_dev), 0); /* unblock test driver and let it finish */ test_driver_pm_done(test_dev); @@ -250,6 +258,7 @@ ZTEST(device_runtime_api, test_api) /* Put operation should fail due the state be locked. */ ret = pm_device_runtime_disable(test_dev); zassert_equal(ret, 0); + zassert_equal(pm_device_runtime_usage(test_dev), -ENOTSUP); } DEVICE_DEFINE(pm_unsupported_device, "PM Unsupported", NULL, NULL, NULL, NULL, diff --git a/tests/subsys/pm/device_runtime_api/testcase.yaml b/tests/subsys/pm/device_runtime_api/testcase.yaml index d86f1ba95d8..80ce7bd9beb 100644 --- a/tests/subsys/pm/device_runtime_api/testcase.yaml +++ b/tests/subsys/pm/device_runtime_api/testcase.yaml @@ -1,11 +1,12 @@ +common: + tags: pm + tests: pm.device_runtime.api: - tags: pm - integration_platforms: - - native_sim + platform_allow: + - native_sim pm.device_runtime.isr_safe.api: - tags: pm - integration_platforms: - - native_sim + platform_allow: + - native_sim extra_configs: - - CONFIG_TEST_PM_DEVICE_ISR_SAFE=y + - CONFIG_TEST_PM_DEVICE_ISR_SAFE=y diff --git a/tests/subsys/pm/power_mgmt/boards/native_sim.overlay b/tests/subsys/pm/power_mgmt/boards/native_sim.overlay index 8cd648a06e3..a66ce9d0025 100644 --- a/tests/subsys/pm/power_mgmt/boards/native_sim.overlay +++ b/tests/subsys/pm/power_mgmt/boards/native_sim.overlay @@ -20,4 +20,8 @@ device_d: device_d { compatible = "test-device-pm"; }; + + device_e: device_e { + compatible = "test-device-pm"; + }; }; diff --git a/tests/subsys/pm/power_mgmt/src/main.c b/tests/subsys/pm/power_mgmt/src/main.c index 73e64020ec8..10746b49021 100644 --- a/tests/subsys/pm/power_mgmt/src/main.c +++ b/tests/subsys/pm/power_mgmt/src/main.c @@ -26,7 +26,6 @@ static bool leave_idle; static bool idle_entered; static bool testing_device_runtime; static bool testing_device_order; -static bool testing_device_lock; static bool testing_force_state; enum pm_state forced_state; @@ -38,6 +37,19 @@ static const struct device *const device_a = static const struct device *const device_c = DEVICE_DT_GET(DT_INST(2, test_device_pm)); +/* + * This device does not support PM. It is used to check + * the behavior of the PM subsystem when a device does not + * support PM. + */ +static const struct device *const device_e = + DEVICE_DT_GET(DT_INST(4, test_device_pm)); + +DEVICE_DT_DEFINE(DT_INST(4, test_device_pm), NULL, + NULL, NULL, NULL, + PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, + NULL); + /* * According with the initialization level, devices A, B and C are * initialized in the following order A -> B -> C. @@ -170,18 +182,6 @@ void pm_state_set(enum pm_state state, uint8_t substate_id) return; } - if (testing_device_lock) { - pm_device_state_get(device_a, &device_power_state); - - /* - * If the device has its state locked the device has - * to be ACTIVE - */ - zassert_true(device_power_state == PM_DEVICE_STATE_ACTIVE, - NULL); - return; - } - if (testing_force_state) { /* if forced to given power state was called */ set_pm = true; @@ -456,6 +456,35 @@ ZTEST(power_management_1cpu, test_force_state) k_sleep(K_SECONDS(1U)); } +ZTEST(power_management_1cpu, test_device_without_pm) +{ + pm_device_busy_set(device_e); + + /* Since this device does not support PM, it should not be set busy */ + zassert_false(pm_device_is_busy(device_e)); + + /* No device should be busy */ + zassert_false(pm_device_is_any_busy()); + + /* Lets ensure that nothing happens */ + pm_device_busy_clear(device_e); + + /* Check the status. Since PM is enabled but this device does not support it. + * It should return -ENOSYS + */ + zassert_equal(pm_device_state_get(device_e, NULL), -ENOSYS); + + /* Try to forcefully change the state should also return an error */ + zassert_equal(pm_device_action_run(device_e, PM_DEVICE_ACTION_SUSPEND), -ENOSYS); + + /* Confirming the device is powered */ + zassert_true(pm_device_is_powered(device_e)); + + /* Test wakeup functionality */ + zassert_false(pm_device_wakeup_enable(device_e, true)); + zassert_false(pm_device_wakeup_is_enabled(device_e)); +} + void power_management_1cpu_teardown(void *data) { pm_notifier_unregister(¬ifier); diff --git a/tests/subsys/pm/power_mgmt_soc/testcase.yaml b/tests/subsys/pm/power_mgmt_soc/testcase.yaml index 021a3416b9b..203e44fbef1 100644 --- a/tests/subsys/pm/power_mgmt_soc/testcase.yaml +++ b/tests/subsys/pm/power_mgmt_soc/testcase.yaml @@ -10,6 +10,7 @@ tests: - nucleo_l476rg - twr_ke18f - mimxrt595_evk/mimxrt595s/cm33 + - rd_rw612_bga tags: pm integration_platforms: - mec15xxevb_assy6853 diff --git a/tests/subsys/sd/mmc/boards/rcar_h3ulcb_r8a77951_a57.overlay b/tests/subsys/sd/mmc/boards/rcar_h3ulcb_r8a77951_a57.overlay new file mode 100644 index 00000000000..9442e02b45f --- /dev/null +++ b/tests/subsys/sd/mmc/boards/rcar_h3ulcb_r8a77951_a57.overlay @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +&emmc2 { + disk { + status = "okay"; + }; + status = "okay"; +}; diff --git a/tests/subsys/sd/sdmmc/src/main.c b/tests/subsys/sd/sdmmc/src/main.c index 84c07bb3998..1bae0941041 100644 --- a/tests/subsys/sd/sdmmc/src/main.c +++ b/tests/subsys/sd/sdmmc/src/main.c @@ -200,23 +200,41 @@ ZTEST(sd_stack, test_card_config) zassert_equal(card.status, CARD_INITIALIZED, "Card status is not OK"); switch (card.card_speed) { case SD_TIMING_SDR12: - TC_PRINT("Card timing: SDR12\n"); + if (card.flags & SD_1800MV_FLAG) { + TC_PRINT("Card timing: SDR12\n"); + } else { + /* Card uses non UHS mode timing */ + TC_PRINT("Card timing: Legacy\n"); + } break; case SD_TIMING_SDR25: - TC_PRINT("Card timing: SDR25\n"); + if (card.flags & SD_1800MV_FLAG) { + TC_PRINT("Card timing: SDR25\n"); + } else { + /* Card uses non UHS mode timing */ + TC_PRINT("Card timing: High Speed\n"); + } break; case SD_TIMING_SDR50: TC_PRINT("Card timing: SDR50\n"); + zassert_true(card.flags & SD_1800MV_FLAG, + "Card must support UHS mode for this timing"); break; case SD_TIMING_SDR104: TC_PRINT("Card timing: SDR104\n"); + zassert_true(card.flags & SD_1800MV_FLAG, + "Card must support UHS mode for this timing"); break; case SD_TIMING_DDR50: TC_PRINT("Card timing: DDR50\n"); + zassert_true(card.flags & SD_1800MV_FLAG, + "Card must support UHS mode for this timing"); break; default: zassert_unreachable("Card timing is not known value"); } + zassert_not_equal(card.bus_io.clock, 0, "Bus should have nonzero clock"); + TC_PRINT("Bus Frequency: %d Hz\n", card.bus_io.clock); switch (card.type) { case CARD_SDIO: TC_PRINT("Card type: SDIO\n"); diff --git a/tests/subsys/settings/fcb/boards/native_sim_native_64.overlay b/tests/subsys/settings/fcb/boards/native_sim_native_64.overlay new file mode 100644 index 00000000000..e4994493dd6 --- /dev/null +++ b/tests/subsys/settings/fcb/boards/native_sim_native_64.overlay @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "native_sim.overlay" diff --git a/tests/subsys/shell/shell_custom_header/CMakeLists.txt b/tests/subsys/shell/shell_custom_header/CMakeLists.txt new file mode 100644 index 00000000000..1993b96acef --- /dev/null +++ b/tests/subsys/shell/shell_custom_header/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(shell_custom_header) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) + +zephyr_include_directories(src) diff --git a/tests/subsys/shell/shell_custom_header/prj.conf b/tests/subsys/shell/shell_custom_header/prj.conf new file mode 100644 index 00000000000..602d869aa1c --- /dev/null +++ b/tests/subsys/shell/shell_custom_header/prj.conf @@ -0,0 +1,11 @@ +CONFIG_SHELL=y +CONFIG_SHELL_BACKEND_SERIAL=n +CONFIG_SHELL_BACKEND_DUMMY=y +CONFIG_SHELL_CMDS_SELECT=y +CONFIG_SHELL_CMD_BUFF_SIZE=90 +CONFIG_SHELL_PRINTF_BUFF_SIZE=15 +CONFIG_SHELL_METAKEYS=n +CONFIG_SHELL_CUSTOM_HEADER=y +CONFIG_LOG=n +CONFIG_ZTEST=y +CONFIG_TEST_LOGGING_DEFAULTS=n diff --git a/tests/subsys/shell/shell_custom_header/src/main.c b/tests/subsys/shell/shell_custom_header/src/main.c new file mode 100644 index 00000000000..81fd71dd06b --- /dev/null +++ b/tests/subsys/shell/shell_custom_header/src/main.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2024 Google, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** @file + * @brief Custom header shell test suite + * + */ + +#include +#include + +#include +#include + +static void *shell_setup(void) +{ + const struct shell *sh = shell_backend_dummy_get_ptr(); + + /* Wait for the initialization of the shell dummy backend. */ + WAIT_FOR(shell_ready(sh), 20000, k_msleep(1)); + zassert_true(shell_ready(sh), "timed out waiting for dummy shell backend"); + + return NULL; +} + +ZTEST_SUITE(sh, NULL, shell_setup, NULL, NULL, NULL); + +ZTEST(sh, test_shell_fprintf) +{ + static const char expect[] = "[CUSTOM_PREFIX]testing 1 2 3"; + const struct shell *sh; + const char *buf; + size_t size; + + sh = shell_backend_dummy_get_ptr(); + zassert_not_null(sh, "Failed to get shell"); + + /* Clear the output buffer */ + shell_backend_dummy_clear_output(sh); + + shell_fprintf(sh, SHELL_VT100_COLOR_DEFAULT, "testing %d %s %c", + 1, "2", '3'); + buf = shell_backend_dummy_get_output(sh, &size); + zassert_true(size >= sizeof(expect), "Expected size > %u, got %d", + sizeof(expect), size); + + /* + * There are prompts and various ANSI characters in the output, so just + * check that the string is in there somewhere. + */ + zassert_true(strstr(buf, expect), + "Expected string to contain '%s', got '%s'", expect, buf); +} diff --git a/tests/subsys/shell/shell_custom_header/src/zephyr_custom_shell.h b/tests/subsys/shell/shell_custom_header/src/zephyr_custom_shell.h new file mode 100644 index 00000000000..a2eedd2a0a0 --- /dev/null +++ b/tests/subsys/shell/shell_custom_header/src/zephyr_custom_shell.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2024 Google, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __ZEPHYR_CUSTOM_SHELL_H +#define __ZEPHYR_CUSTOM_SHELL_H + +#define CUSTOM_SHELL_PREFIX "[CUSTOM_PREFIX]" + +#undef shell_fprintf + +#define shell_fprintf(sh, color, fmt, ...) \ + shell_fprintf_impl(sh, color, CUSTOM_SHELL_PREFIX fmt, ##__VA_ARGS__) + +#endif /* __ZEPHYR_CUSTOM_SHELL_H */ diff --git a/tests/subsys/shell/shell_custom_header/testcase.yaml b/tests/subsys/shell/shell_custom_header/testcase.yaml new file mode 100644 index 00000000000..5e85e3aabd8 --- /dev/null +++ b/tests/subsys/shell/shell_custom_header/testcase.yaml @@ -0,0 +1,9 @@ +common: + integration_platforms: + - native_sim + +tests: + shell.shell_custom_header: + tags: + - shell_custom_header + - shell diff --git a/tests/subsys/shell/shell_device/CMakeLists.txt b/tests/subsys/shell/shell_device/CMakeLists.txt new file mode 100644 index 00000000000..fdea9ba07be --- /dev/null +++ b/tests/subsys/shell/shell_device/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(shell_device) + +target_sources(app PRIVATE src/main.c) diff --git a/tests/subsys/shell/shell_device/prj.conf b/tests/subsys/shell/shell_device/prj.conf new file mode 100644 index 00000000000..a50c21f56fb --- /dev/null +++ b/tests/subsys/shell/shell_device/prj.conf @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SHELL=y +CONFIG_SHELL_BACKEND_SERIAL=n +CONFIG_SHELL_BACKEND_DUMMY=y diff --git a/tests/subsys/shell/shell_device/src/main.c b/tests/subsys/shell/shell_device/src/main.c new file mode 100644 index 00000000000..d18c2c8098d --- /dev/null +++ b/tests/subsys/shell/shell_device/src/main.c @@ -0,0 +1,83 @@ +/* + * Copyright 2024 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_PM_DEVICE +static int dummy_device_pm_action(const struct device *dev, + enum pm_device_action action) +{ + return 0; +} + +PM_DEVICE_DEFINE(dummy_pm_driver_1, dummy_device_pm_action); +PM_DEVICE_DEFINE(dummy_pm_driver_2, dummy_device_pm_action); +PM_DEVICE_DEFINE(dummy_pm_driver_3, dummy_device_pm_action); +PM_DEVICE_DEFINE(dummy_pm_driver_4, dummy_device_pm_action); +#endif + +DEVICE_DEFINE(device_0, "device@0", NULL, NULL, + NULL, NULL, + POST_KERNEL, 0, NULL); + +DEVICE_DEFINE(device_1, "device@1", NULL, PM_DEVICE_GET(dummy_pm_driver_1), + NULL, NULL, + POST_KERNEL, 1, NULL); + +DEVICE_DEFINE(device_2, "device@2", NULL, PM_DEVICE_GET(dummy_pm_driver_2), + NULL, NULL, + POST_KERNEL, 2, NULL); + +DEVICE_DEFINE(device_3, "device@3", NULL, PM_DEVICE_GET(dummy_pm_driver_3), + NULL, NULL, + POST_KERNEL, 3, NULL); + +DEVICE_DEFINE(device_4, "device@4", NULL, PM_DEVICE_GET(dummy_pm_driver_4), + NULL, NULL, + POST_KERNEL, 4, NULL); + +#ifdef CONFIG_PM_DEVICE +static const struct device *d2 = &DEVICE_NAME_GET(device_2); +#endif +static const struct device *d3 = &DEVICE_NAME_GET(device_3); +static const struct device *d4 = &DEVICE_NAME_GET(device_4); + +int main(void) +{ + const struct shell *sh = shell_backend_dummy_get_ptr(); + const char *buf; + int err; + size_t size; + + /* Let the shell backend initialize. */ + k_usleep(10); + +#ifdef CONFIG_PM_DEVICE + pm_device_action_run(d2, PM_DEVICE_ACTION_SUSPEND); +#endif + + pm_device_runtime_enable(d3); + pm_device_runtime_enable(d4); + pm_device_runtime_get(d4); + + shell_backend_dummy_clear_output(sh); + + err = shell_execute_cmd(sh, "device list"); + if (err) { + printf("Failed to execute the shell command: %d.\n", + err); + } + + buf = shell_backend_dummy_get_output(sh, &size); + printf("%s\n", buf); + + return 0; +} diff --git a/tests/subsys/shell/shell_device/testcase.yaml b/tests/subsys/shell/shell_device/testcase.yaml new file mode 100644 index 00000000000..ccc36cf2ba7 --- /dev/null +++ b/tests/subsys/shell/shell_device/testcase.yaml @@ -0,0 +1,45 @@ +# SPDX-License-Identifier: Apache-2.0 + +common: + tags: shell + platform_allow: + - native_sim + integration_platforms: + - native_sim + +tests: + shell.device: + harness: console + harness_config: + type: multi_line + regex: + - "device@0 \\(READY\\)" + - "device@1 \\(READY\\)" + - "device@2 \\(READY\\)" + - "device@3 \\(READY\\)" + - "device@4 \\(READY\\)" + shell.device_pm_device: + extra_configs: + - CONFIG_PM_DEVICE=y + harness: console + harness_config: + type: multi_line + regex: + - "device@0 \\(READY\\)" + - "device@1 \\(active\\)" + - "device@2 \\(suspended\\)" + - "device@3 \\(active\\)" + - "device@4 \\(active\\)" + shell.device_pm_device_runtime: + extra_configs: + - CONFIG_PM_DEVICE=y + - CONFIG_PM_DEVICE_RUNTIME=y + harness: console + harness_config: + type: multi_line + regex: + - "device@0 \\(READY\\)" + - "device@1 \\(active\\)" + - "device@2 \\(suspended\\)" + - "device@3 \\(suspended, usage=0\\)" + - "device@4 \\(active, usage=1\\)" diff --git a/tests/subsys/shell/shell_device_filter/CMakeLists.txt b/tests/subsys/shell/shell_device_filter/CMakeLists.txt new file mode 100644 index 00000000000..008d1d8c7bc --- /dev/null +++ b/tests/subsys/shell/shell_device_filter/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(shell_device_filter) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/tests/subsys/shell/shell_device_filter/prj.conf b/tests/subsys/shell/shell_device_filter/prj.conf new file mode 100644 index 00000000000..48b8525a12e --- /dev/null +++ b/tests/subsys/shell/shell_device_filter/prj.conf @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_ZTEST=y +CONFIG_SHELL=y +CONFIG_SHELL_BACKEND_SERIAL=n +CONFIG_SHELL_BACKEND_DUMMY=n +CONFIG_PM=y diff --git a/tests/subsys/shell/shell_device_filter/src/main.c b/tests/subsys/shell/shell_device_filter/src/main.c new file mode 100644 index 00000000000..3073232fcf8 --- /dev/null +++ b/tests/subsys/shell/shell_device_filter/src/main.c @@ -0,0 +1,59 @@ +/* + * Copyright 2024 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +DEVICE_DEFINE(device_0, "device@0", NULL, NULL, + NULL, NULL, + POST_KERNEL, 0, NULL); + +DEVICE_DEFINE(device_1, "device@1", NULL, NULL, + NULL, NULL, + POST_KERNEL, 1, NULL); + +DEVICE_DEFINE(device_2, "xx_device@2", NULL, NULL, + NULL, NULL, + POST_KERNEL, 2, NULL); + +static const struct device *d0 = &DEVICE_NAME_GET(device_0); +static const struct device *d1 = &DEVICE_NAME_GET(device_1); +static const struct device *d2 = &DEVICE_NAME_GET(device_2); + +ZTEST(shell_device_filter, test_unfiltered) +{ + zassert_equal_ptr(d0, shell_device_filter(0, NULL)); + zassert_equal_ptr(d1, shell_device_filter(1, NULL)); + zassert_equal_ptr(d2, shell_device_filter(2, NULL)); + zassert_equal_ptr(NULL, shell_device_filter(3, NULL)); + + zassert_equal_ptr(d0, shell_device_lookup(0, NULL)); + zassert_equal_ptr(d1, shell_device_lookup(1, NULL)); + zassert_equal_ptr(d2, shell_device_lookup(2, NULL)); + zassert_equal_ptr(NULL, shell_device_lookup(3, NULL)); +} + +ZTEST(shell_device_filter, test_prefix) +{ + zassert_equal_ptr(d2, shell_device_lookup(0, "xx_")); + zassert_equal_ptr(NULL, shell_device_lookup(1, "xx_")); +} + +static bool pm_device_test_filter(const struct device *dev) +{ + return strstr(dev->name, "@1") != NULL; +} + +ZTEST(shell_device_filter, test_filter) +{ + zassert_equal_ptr(d1, shell_device_filter(0, pm_device_test_filter)); + zassert_equal_ptr(NULL, shell_device_filter(1, pm_device_test_filter)); +} + +ZTEST_SUITE(shell_device_filter, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/subsys/shell/shell_device_filter/testcase.yaml b/tests/subsys/shell/shell_device_filter/testcase.yaml new file mode 100644 index 00000000000..fba42351ce4 --- /dev/null +++ b/tests/subsys/shell/shell_device_filter/testcase.yaml @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: Apache-2.0 + +tests: + shell.device_filter: + platform_allow: + - native_sim + tags: + - shell + integration_platforms: + - native_sim diff --git a/tests/subsys/usb/bos/src/test_bos.c b/tests/subsys/usb/bos/src/test_bos.c index 1bd4d9f46cb..e9452d86fc3 100644 --- a/tests/subsys/usb/bos/src/test_bos.c +++ b/tests/subsys/usb/bos/src/test_bos.c @@ -4,6 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include + #include #include diff --git a/tests/subsys/usb/desc_sections/src/desc_sections.c b/tests/subsys/usb/desc_sections/src/desc_sections.c index 5100f1b90ae..0277462b68d 100644 --- a/tests/subsys/usb/desc_sections/src/desc_sections.c +++ b/tests/subsys/usb/desc_sections/src/desc_sections.c @@ -203,6 +203,7 @@ ZTEST(desc_sections, test_desc_sections) { struct usb_desc_header *head; + usb_set_config(usb_get_device_descriptor()); TC_PRINT("__usb_descriptor_start %p\n", __usb_descriptor_start); TC_PRINT("__usb_descriptor_end %p\n", __usb_descriptor_end); TC_PRINT("USB Descriptor table span %d\n", diff --git a/tests/subsys/usb/device_next/build_all.conf b/tests/subsys/usb/device_next/build_all.conf new file mode 100644 index 00000000000..1b49631bbb6 --- /dev/null +++ b/tests/subsys/usb/device_next/build_all.conf @@ -0,0 +1,31 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_LOG=y +CONFIG_ZTEST=y + +CONFIG_SHELL=y +CONFIG_USBD_SHELL=y + +CONFIG_NETWORKING=y +CONFIG_NET_L2_ETHERNET=y + +CONFIG_BT=y +CONFIG_BT_HCI_RAW=y + +CONFIG_USB_DEVICE_STACK_NEXT=y +CONFIG_USBD_LOOPBACK_CLASS=y + +CONFIG_SERIAL=y +CONFIG_UART_INTERRUPT_DRIVEN=y +CONFIG_UART_LINE_CTRL=y +CONFIG_USBD_CDC_ACM_CLASS=y + +CONFIG_USBD_MSC_CLASS=y + +CONFIG_USBD_AUDIO2_CLASS=y + +CONFIG_USBD_BT_HCI=y + +CONFIG_UHC_DRIVER=y +CONFIG_USB_HOST_STACK=y diff --git a/tests/subsys/usb/device_next/build_all.overlay b/tests/subsys/usb/device_next/build_all.overlay new file mode 100644 index 00000000000..2cd037e82b3 --- /dev/null +++ b/tests/subsys/usb/device_next/build_all.overlay @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/delete-node/ &zephyr_udc0; + +#include + +/ { + uac2_headphones: usb_audio2 { + compatible = "zephyr,uac2"; + status = "okay"; + audio-function = ; + + uac_aclk: aclk { + compatible = "zephyr,uac2-clock-source"; + clock-type = "internal-programmable"; + frequency-control = "host-programmable"; + sampling-frequencies = <48000>; + }; + + out_terminal: out_terminal { + compatible = "zephyr,uac2-input-terminal"; + clock-source = <&uac_aclk>; + terminal-type = ; + front-left; + front-right; + }; + + headphones_output: headphones { + compatible = "zephyr,uac2-output-terminal"; + data-source = <&out_terminal>; + clock-source = <&uac_aclk>; + terminal-type = ; + }; + + as_iso_out: out_interface { + compatible = "zephyr,uac2-audio-streaming"; + linked-terminal = <&out_terminal>; + subslot-size = <2>; + bit-resolution = <16>; + }; + }; + + ramdisk0 { + compatible = "zephyr,ram-disk"; + disk-name = "RAM"; + sector-size = <512>; + sector-count = <192>; + }; + + cdc_ecm_eth0: cdc_ecm_eth0 { + compatible = "zephyr,cdc-ecm-ethernet"; + remote-mac-address = "00005E005301"; + }; + + zephyr_uhc0: uhc_vrt0 { + compatible = "zephyr,uhc-virtual"; + + zephyr_udc0: udc_vrt0 { + compatible = "zephyr,udc-virtual"; + num-bidir-endpoints = <16>; + maximum-speed = "high-speed"; + }; + }; + +}; + +&zephyr_udc0 { + cdc_acm_uart0 { + compatible = "zephyr,cdc-acm-uart"; + }; +}; diff --git a/tests/subsys/usb/device_next/src/main.c b/tests/subsys/usb/device_next/src/main.c index 50c20c2fbf3..5d6a9da7039 100644 --- a/tests/subsys/usb/device_next/src/main.c +++ b/tests/subsys/usb/device_next/src/main.c @@ -17,10 +17,15 @@ LOG_MODULE_REGISTER(usb_test, LOG_LEVEL_INF); #define TEST_DEFAULT_INTERFACE 0 #define TEST_DEFAULT_ALTERNATE 1 -USBD_CONFIGURATION_DEFINE(test_config, +USBD_CONFIGURATION_DEFINE(test_fs_config, USB_SCD_SELF_POWERED | USB_SCD_REMOTE_WAKEUP, 200); +USBD_CONFIGURATION_DEFINE(test_hs_config, + USB_SCD_SELF_POWERED | USB_SCD_REMOTE_WAKEUP, + 200); + + USBD_DESC_LANG_DEFINE(test_lang); USBD_DESC_STRING_DEFINE(test_mfg, "ZEPHYR", 1); USBD_DESC_STRING_DEFINE(test_product, "Zephyr USB Test", 2); @@ -120,10 +125,20 @@ static void *usb_test_enable(void) err = usbd_add_descriptor(&test_usbd, &test_sn); zassert_equal(err, 0, "Failed to initialize descriptor (%d)", err); - err = usbd_add_configuration(&test_usbd, &test_config); + if (usbd_caps_speed(&test_usbd) == USBD_SPEED_HS) { + err = usbd_add_configuration(&test_usbd, USBD_SPEED_HS, &test_hs_config); + zassert_equal(err, 0, "Failed to add configuration (%d)"); + } + + err = usbd_add_configuration(&test_usbd, USBD_SPEED_FS, &test_fs_config); zassert_equal(err, 0, "Failed to add configuration (%d)"); - err = usbd_register_class(&test_usbd, "loopback_0", 1); + if (usbd_caps_speed(&test_usbd) == USBD_SPEED_HS) { + err = usbd_register_class(&test_usbd, "loopback_0", USBD_SPEED_HS, 1); + zassert_equal(err, 0, "Failed to register loopback_0 class (%d)"); + } + + err = usbd_register_class(&test_usbd, "loopback_0", USBD_SPEED_FS, 1); zassert_equal(err, 0, "Failed to register loopback_0 class (%d)"); err = usbd_init(&test_usbd); diff --git a/tests/subsys/usb/device_next/testcase.yaml b/tests/subsys/usb/device_next/testcase.yaml index 5a826887b88..ebc5a3273e5 100644 --- a/tests/subsys/usb/device_next/testcase.yaml +++ b/tests/subsys/usb/device_next/testcase.yaml @@ -1,9 +1,16 @@ +common: + depends_on: usb_device + platform_allow: + - native_sim + - qemu_cortex_m3 + integration_platforms: + - native_sim tests: usb.device_next: - depends_on: usb_device tags: usb - platform_allow: - - native_sim - - qemu_cortex_m3 - integration_platforms: - - native_sim + usb.device_next.build_all: + tags: usb + extra_args: + - CONF_FILE="build_all.conf" + - EXTRA_DTC_OVERLAY_FILE="build_all.overlay" + build_only: true diff --git a/tests/subsys/usb/uac2/src/uac2_desc.c b/tests/subsys/usb/uac2/src/uac2_desc.c index 9e22bc079ce..30d064cb5c2 100644 --- a/tests/subsys/usb/uac2/src/uac2_desc.c +++ b/tests/subsys/usb/uac2/src/uac2_desc.c @@ -9,7 +9,7 @@ #include -static const uint8_t reference_ac_descriptors[] = { +static const uint8_t reference_ac_interface_descriptor[] = { /* 4.7.2 Class-Specific AC Interface Descriptor */ 0x09, /* bLength = 9 */ 0x24, /* bDescriptorType = CS_INTERFACE */ @@ -18,6 +18,9 @@ static const uint8_t reference_ac_descriptors[] = { 0x04, /* bCategory = HEADSET */ 0x4b, 0x00, /* wTotalLength = 0x4b = 75 */ 0x00, /* bmControls = Latency Control not present */ +}; + +static const uint8_t reference_ac_clock_source_descriptor[] = { /* 4.7.2.1 Clock Source Descriptor */ 0x08, /* bLength = 8 */ 0x24, /* bDescriptorType = CS_INTERFACE */ @@ -27,6 +30,9 @@ static const uint8_t reference_ac_descriptors[] = { 0x03, /* bmControls = frequency host programmable */ 0x00, /* bAssocTerminal = 0 (not associated) */ 0x00, /* iClockSource = 0 (no string descriptor) */ +}; + +static const uint8_t reference_ac_hp_input_terminal_descriptor[] = { /* 4.7.2.4 Input Terminal Descriptor */ 0x11, /* bLength = 17 */ 0x24, /* bDescriptorType = CS_INTERFACE */ @@ -40,6 +46,9 @@ static const uint8_t reference_ac_descriptors[] = { 0x00, /* iChannelNames = 0 (all pre-defined) */ 0x00, 0x00, /* bmControls = none present */ 0x00, /* iTerminal = 0 (no string descriptor) */ +}; + +static const uint8_t reference_ac_hp_output_terminal_descriptor[] = { /* 4.7.2.5 Output Terminal Descriptor */ 0x0c, /* bLength = 12 */ 0x24, /* bDescriptorType = CS_INTERFACE */ @@ -51,6 +60,9 @@ static const uint8_t reference_ac_descriptors[] = { 0x01, /* bCSourceID = 1 (main clock) */ 0x00, 0x00, /* bmControls = none present */ 0x00, /* iTerminal = 0 (no string descriptor) */ +}; + +static const uint8_t reference_ac_mic_input_terminal_descriptor[] = { /* 4.7.2.4 Input Terminal Descriptor */ 0x11, /* bLength = 17 */ 0x24, /* bDescriptorType = CS_INTERFACE */ @@ -64,6 +76,9 @@ static const uint8_t reference_ac_descriptors[] = { 0x00, /* iChannelNames = 0 (all pre-defined) */ 0x00, 0x00, /* bmControls = none present */ 0x00, /* iTerminal = 0 (no string descriptor) */ +}; + +static const uint8_t reference_ac_mic_output_terminal_descriptor[] = { /* 4.7.2.5 Output Terminal Descriptor */ 0x0c, /* bLength = 12 */ 0x24, /* bDescriptorType = CS_INTERFACE */ @@ -78,7 +93,7 @@ static const uint8_t reference_ac_descriptors[] = { }; /* USB IN = Audio device streaming output */ -static const uint8_t reference_as_in_descriptors[] = { +static const uint8_t reference_as_in_cs_general_descriptor[] = { /* 4.9.2 Class-Specific AS Interface Descriptor */ 0x10, /* bLength = 16 */ 0x24, /* bDescriptorType = CS_INTERFACE */ @@ -90,6 +105,9 @@ static const uint8_t reference_as_in_descriptors[] = { 0x01, /* bNrChannels = 1 */ 0x01, 0x00, 0x00, 0x00, /* bmChannelConfig = Front Left */ 0x00, /* iChannelNames = 0 (all pre-defined) */ +}; + +static const uint8_t reference_as_in_cs_format_descriptor[] = { /* Universal Serial Bus Device Class Definition for Audio Data Formats * Release 2.0, May 31, 2006. 2.3.1.6 Type I Format Type Descriptor */ @@ -102,7 +120,7 @@ static const uint8_t reference_as_in_descriptors[] = { }; /* USB OUT = Audio device streaming input */ -static const uint8_t reference_as_out_descriptors[] = { +static const uint8_t reference_as_out_cs_general_descriptor[] = { /* 4.9.2 Class-Specific AS Interface Descriptor */ 0x10, /* bLength = 16 */ 0x24, /* bDescriptorType = CS_INTERFACE */ @@ -114,6 +132,9 @@ static const uint8_t reference_as_out_descriptors[] = { 0x02, /* bNrChannels = 2 */ 0x03, 0x00, 0x00, 0x00, /* bmChannelConfig = Front Left, Front Right */ 0x00, /* iChannelNames = 0 (all pre-defined) */ +}; + +static const uint8_t reference_as_out_cs_format_descriptor[] = { /* Universal Serial Bus Device Class Definition for Audio Data Formats * Release 2.0, May 31, 2006. 2.3.1.6 Type I Format Type Descriptor */ @@ -139,49 +160,22 @@ static const uint8_t reference_as_ep_descriptor[] = { DT_FOREACH_CHILD(DT_NODELABEL(uac2_headset), VALIDATE_NODE) -static const uint8_t generated_ac_descriptors[] = { - AC_INTERFACE_HEADER_DESCRIPTOR(DT_NODELABEL(uac2_headset)) - ENTITY_HEADERS(DT_NODELABEL(uac2_headset)) -}; - -static const uint8_t generated_as_in_descriptors[] = { - AUDIO_STREAMING_INTERFACE_DESCRIPTORS(DT_NODELABEL(as_iso_in)) -}; +UAC2_DESCRIPTOR_ARRAYS(DT_NODELABEL(uac2_headset)) -static const uint8_t generated_as_out_descriptors[] = { - AUDIO_STREAMING_INTERFACE_DESCRIPTORS(DT_NODELABEL(as_iso_out)) +const static struct usb_desc_header *generated_uac2_descriptor_set[] = { + UAC2_DESCRIPTOR_PTRS(DT_NODELABEL(uac2_headset)) }; -static const uint8_t generated_uac2_descriptors[] = { - UAC2_DESCRIPTORS(DT_NODELABEL(uac2_headset)) -}; - -ZTEST(uac2_desc, test_audiocontrol_descriptors) -{ - zassert_mem_equal(reference_ac_descriptors, generated_ac_descriptors, - ARRAY_SIZE(reference_ac_descriptors)); -} - -ZTEST(uac2_desc, test_audiostreaming_descriptors) -{ - zassert_mem_equal(reference_as_in_descriptors, - generated_as_in_descriptors, - ARRAY_SIZE(reference_as_in_descriptors)); - - zassert_mem_equal(reference_as_out_descriptors, - generated_as_out_descriptors, - ARRAY_SIZE(reference_as_out_descriptors)); -} - ZTEST(uac2_desc, test_uac2_descriptors) { - const uint8_t *ptr = generated_uac2_descriptors; + const struct usb_desc_header **ptr = generated_uac2_descriptor_set; + const struct usb_association_descriptor *iad; const struct usb_if_descriptor *iface; const struct usb_ep_descriptor *ep; /* Headset has 3 interfaces: 1 AudioControl and 2 AudioStreaming */ - iad = (const struct usb_association_descriptor *)ptr; + iad = (const struct usb_association_descriptor *)*ptr; zassert_equal(iad->bLength, sizeof(struct usb_association_descriptor)); zassert_equal(iad->bDescriptorType, USB_DESC_INTERFACE_ASSOC); zassert_equal(iad->bFirstInterface, FIRST_INTERFACE_NUMBER); @@ -190,10 +184,10 @@ ZTEST(uac2_desc, test_uac2_descriptors) zassert_equal(iad->bFunctionSubClass, FUNCTION_SUBCLASS_UNDEFINED); zassert_equal(iad->bFunctionProtocol, AF_VERSION_02_00); zassert_equal(iad->iFunction, 0); - ptr += sizeof(struct usb_association_descriptor); + ptr++; /* AudioControl interface goes first */ - iface = (const struct usb_if_descriptor *)ptr; + iface = (const struct usb_if_descriptor *)*ptr; zassert_equal(iface->bLength, sizeof(struct usb_if_descriptor)); zassert_equal(iface->bDescriptorType, USB_DESC_INTERFACE); zassert_equal(iface->bInterfaceNumber, FIRST_INTERFACE_NUMBER); @@ -203,15 +197,30 @@ ZTEST(uac2_desc, test_uac2_descriptors) zassert_equal(iface->bInterfaceSubClass, AUDIOCONTROL); zassert_equal(iface->bInterfaceProtocol, IP_VERSION_02_00); zassert_equal(iface->iInterface, 0); - ptr += sizeof(struct usb_if_descriptor); + ptr++; /* AudioControl class-specific descriptors */ - zassert_mem_equal(reference_ac_descriptors, ptr, - ARRAY_SIZE(reference_ac_descriptors)); - ptr += ARRAY_SIZE(reference_ac_descriptors); + zassert_mem_equal(reference_ac_interface_descriptor, *ptr, + ARRAY_SIZE(reference_ac_interface_descriptor)); + ptr++; + zassert_mem_equal(reference_ac_clock_source_descriptor, *ptr, + ARRAY_SIZE(reference_ac_clock_source_descriptor)); + ptr++; + zassert_mem_equal(reference_ac_hp_input_terminal_descriptor, *ptr, + ARRAY_SIZE(reference_ac_hp_input_terminal_descriptor)); + ptr++; + zassert_mem_equal(reference_ac_hp_output_terminal_descriptor, *ptr, + ARRAY_SIZE(reference_ac_hp_output_terminal_descriptor)); + ptr++; + zassert_mem_equal(reference_ac_mic_input_terminal_descriptor, *ptr, + ARRAY_SIZE(reference_ac_mic_input_terminal_descriptor)); + ptr++; + zassert_mem_equal(reference_ac_mic_output_terminal_descriptor, *ptr, + ARRAY_SIZE(reference_ac_mic_output_terminal_descriptor)); + ptr++; /* AudioStreaming OUT interface Alt 0 without endpoints */ - iface = (const struct usb_if_descriptor *)ptr; + iface = (const struct usb_if_descriptor *)*ptr; zassert_equal(iface->bLength, sizeof(struct usb_if_descriptor)); zassert_equal(iface->bDescriptorType, USB_DESC_INTERFACE); zassert_equal(iface->bInterfaceNumber, FIRST_INTERFACE_NUMBER + 1); @@ -221,10 +230,10 @@ ZTEST(uac2_desc, test_uac2_descriptors) zassert_equal(iface->bInterfaceSubClass, AUDIOSTREAMING); zassert_equal(iface->bInterfaceProtocol, IP_VERSION_02_00); zassert_equal(iface->iInterface, 0); - ptr += sizeof(struct usb_if_descriptor); + ptr++; /* AudioStreaming OUT interface Alt 1 with endpoint */ - iface = (const struct usb_if_descriptor *)ptr; + iface = (const struct usb_if_descriptor *)*ptr; zassert_equal(iface->bLength, sizeof(struct usb_if_descriptor)); zassert_equal(iface->bDescriptorType, USB_DESC_INTERFACE); zassert_equal(iface->bInterfaceNumber, FIRST_INTERFACE_NUMBER + 1); @@ -234,34 +243,37 @@ ZTEST(uac2_desc, test_uac2_descriptors) zassert_equal(iface->bInterfaceSubClass, AUDIOSTREAMING); zassert_equal(iface->bInterfaceProtocol, IP_VERSION_02_00); zassert_equal(iface->iInterface, 0); - ptr += sizeof(struct usb_if_descriptor); + ptr++; /* AudioStreaming OUT class-specific descriptors */ - zassert_mem_equal(reference_as_out_descriptors, ptr, - ARRAY_SIZE(reference_as_out_descriptors)); - ptr += ARRAY_SIZE(reference_as_out_descriptors); + zassert_mem_equal(reference_as_out_cs_general_descriptor, *ptr, + ARRAY_SIZE(reference_as_out_cs_general_descriptor)); + ptr++; + zassert_mem_equal(reference_as_out_cs_format_descriptor, *ptr, + ARRAY_SIZE(reference_as_out_cs_format_descriptor)); + ptr++; /* Isochronous OUT endpoint descriptor */ - ep = (const struct usb_ep_descriptor *)ptr; + ep = (const struct usb_ep_descriptor *)*ptr; zassert_equal(ep->bLength, sizeof(struct usb_ep_descriptor)); zassert_equal(ep->bDescriptorType, USB_DESC_ENDPOINT); zassert_equal(ep->bEndpointAddress, FIRST_OUT_EP_ADDR); - zassert_equal(&ep->bEndpointAddress - generated_uac2_descriptors, - UAC2_DESCRIPTOR_AS_DATA_EP_OFFSET(DT_NODELABEL(as_iso_out))); + zassert_equal(ptr - generated_uac2_descriptor_set, + UAC2_DESCRIPTOR_AS_DATA_EP_INDEX(DT_NODELABEL(as_iso_out))); zassert_equal(ep->Attributes.transfer, USB_EP_TYPE_ISO); zassert_equal(ep->Attributes.synch, 1 /* Asynchronous */); zassert_equal(ep->Attributes.usage, 0 /* Data Endpoint */); zassert_equal(sys_le16_to_cpu(ep->wMaxPacketSize), 196); zassert_equal(ep->bInterval, 1); - ptr += sizeof(struct usb_ep_descriptor); + ptr++; /* AudioStreaming OUT endpoint descriptor */ - zassert_mem_equal(reference_as_ep_descriptor, ptr, + zassert_mem_equal(reference_as_ep_descriptor, *ptr, ARRAY_SIZE(reference_as_ep_descriptor)); - ptr += ARRAY_SIZE(reference_as_ep_descriptor); + ptr++; /* AudioStreaming IN interface Alt 0 without endpoints */ - iface = (const struct usb_if_descriptor *)ptr; + iface = (const struct usb_if_descriptor *)*ptr; zassert_equal(iface->bLength, sizeof(struct usb_if_descriptor)); zassert_equal(iface->bDescriptorType, USB_DESC_INTERFACE); zassert_equal(iface->bInterfaceNumber, FIRST_INTERFACE_NUMBER + 2); @@ -271,10 +283,10 @@ ZTEST(uac2_desc, test_uac2_descriptors) zassert_equal(iface->bInterfaceSubClass, AUDIOSTREAMING); zassert_equal(iface->bInterfaceProtocol, IP_VERSION_02_00); zassert_equal(iface->iInterface, 0); - ptr += sizeof(struct usb_if_descriptor); + ptr++; /* AudioStreaming IN interface Alt 1 with endpoint */ - iface = (const struct usb_if_descriptor *)ptr; + iface = (const struct usb_if_descriptor *)*ptr; zassert_equal(iface->bLength, sizeof(struct usb_if_descriptor)); zassert_equal(iface->bDescriptorType, USB_DESC_INTERFACE); zassert_equal(iface->bInterfaceNumber, FIRST_INTERFACE_NUMBER + 2); @@ -284,35 +296,37 @@ ZTEST(uac2_desc, test_uac2_descriptors) zassert_equal(iface->bInterfaceSubClass, AUDIOSTREAMING); zassert_equal(iface->bInterfaceProtocol, IP_VERSION_02_00); zassert_equal(iface->iInterface, 0); - ptr += sizeof(struct usb_if_descriptor); + ptr++; /* AudioStreaming IN class-specific descriptors */ - zassert_mem_equal(reference_as_in_descriptors, ptr, - ARRAY_SIZE(reference_as_in_descriptors)); - ptr += ARRAY_SIZE(reference_as_in_descriptors); + zassert_mem_equal(reference_as_in_cs_general_descriptor, *ptr, + ARRAY_SIZE(reference_as_in_cs_general_descriptor)); + ptr++; + zassert_mem_equal(reference_as_in_cs_format_descriptor, *ptr, + ARRAY_SIZE(reference_as_in_cs_format_descriptor)); + ptr++; /* Isochronous IN endpoint descriptor */ - ep = (const struct usb_ep_descriptor *)ptr; + ep = (const struct usb_ep_descriptor *)*ptr; zassert_equal(ep->bLength, sizeof(struct usb_ep_descriptor)); zassert_equal(ep->bDescriptorType, USB_DESC_ENDPOINT); zassert_equal(ep->bEndpointAddress, FIRST_IN_EP_ADDR); - zassert_equal(&ep->bEndpointAddress - generated_uac2_descriptors, - UAC2_DESCRIPTOR_AS_DATA_EP_OFFSET(DT_NODELABEL(as_iso_in))); + zassert_equal(ptr - generated_uac2_descriptor_set, + UAC2_DESCRIPTOR_AS_DATA_EP_INDEX(DT_NODELABEL(as_iso_in))); zassert_equal(ep->Attributes.transfer, USB_EP_TYPE_ISO); zassert_equal(ep->Attributes.synch, 1 /* Asynchronous */); zassert_equal(ep->Attributes.usage, 2 /* Implicit Feedback Data */); zassert_equal(sys_le16_to_cpu(ep->wMaxPacketSize), 98); zassert_equal(ep->bInterval, 1); - ptr += sizeof(struct usb_ep_descriptor); + ptr++; /* AudioStreaming IN endpoint descriptor */ - zassert_mem_equal(reference_as_ep_descriptor, ptr, + zassert_mem_equal(reference_as_ep_descriptor, *ptr, ARRAY_SIZE(reference_as_ep_descriptor)); - ptr += ARRAY_SIZE(reference_as_ep_descriptor); + ptr++; - /* Confirm there are is no trailing data */ - zassert_equal(ptr - generated_uac2_descriptors, - ARRAY_SIZE(generated_uac2_descriptors)); + /* Confirm there is no trailing data */ + zassert_equal(*ptr, NULL); } ZTEST_SUITE(uac2_desc, NULL, NULL, NULL, NULL, NULL); diff --git a/west.yml b/west.yml index a81bbc3e666..c6ff13bd6bf 100644 --- a/west.yml +++ b/west.yml @@ -56,7 +56,7 @@ manifest: remote: babblesim repo-path: ext_2G4_phy_v1 path: tools/bsim/components/ext_2G4_phy_v1 - revision: 1ab9a884621d9ca719ef23536ca47d10494220c6 + revision: d8302b8d51409b9e717a1a0ba6b443d3b5552a6c groups: - babblesim - name: babblesim_ext_2G4_channel_NtNcable @@ -142,7 +142,7 @@ manifest: groups: - hal - name: hal_ambiq - revision: ff4ca358d730536addf336c40c3faa4ebf1df00a + revision: 94dd874cd726ba8185a301e78337c5c39685123f path: modules/hal/ambiq groups: - hal @@ -152,7 +152,7 @@ manifest: groups: - hal - name: hal_espressif - revision: dddb7cf318d931c25623c34ecde20f3150d7f987 + revision: c49581173bab8625d1f08d5c41d5a186afc240b3 path: modules/hal/espressif west-commands: west/west-commands.yml groups: @@ -178,22 +178,22 @@ manifest: groups: - hal - name: hal_microchip - revision: 68575aa28cd33c68b3b8d66f510d15746c57fdb5 + revision: 1279561ea9b71c5f572d3d52708b7b445a383662 path: modules/hal/microchip groups: - hal - name: hal_nordic - revision: bdef8b66d5f59d95c09889918a04ddaecce322c8 + revision: a3aacc7e43dec644a9ddfee4aa578a4f8ff54610 path: modules/hal/nordic groups: - hal - name: hal_nuvoton - revision: 34efb92e37bd07043a2cab7fff847d8443d930f9 + revision: ab342e6915bf7bff2203a20985754f6dbdb5343d path: modules/hal/nuvoton groups: - hal - name: hal_nxp - revision: 4ab0e7bc9c44840cbb22a6dd74c214713f239182 + revision: 57d844b03ea545aa702ae99d9777481709ba8aa4 path: modules/hal/nxp groups: - hal @@ -203,14 +203,14 @@ manifest: groups: - hal - name: hal_quicklogic - revision: b3a66fe6d04d87fd1533a5c8de51d0599fcd08d0 + revision: bad894440fe72c814864798c8e3a76d13edffb6c path: modules/hal/quicklogic repo-path: hal_quicklogic groups: - hal - name: hal_renesas path: modules/hal/renesas - revision: 991e060b6825f0f6830f4dbccbed8252598f2a6d + revision: b4fe8925d95bddc27e6d1666890f560d30cf9166 groups: - hal - name: hal_rpi_pico @@ -219,7 +219,7 @@ manifest: groups: - hal - name: hal_silabs - revision: 442d0fb1d02cc4b2bb159fbff378029998b89049 + revision: 0c39ee28be31c59a98ed490c3811f68caa1fcbd3 path: modules/hal/silabs groups: - hal @@ -229,7 +229,7 @@ manifest: groups: - hal - name: hal_stm32 - revision: 60c9634f61c697e1c310ec648d33529712806069 + revision: ed93098718d5c727d2fac5ef27023a2a14763e32 path: modules/hal/stm32 groups: - hal @@ -256,7 +256,7 @@ manifest: - name: hostap repo-path: hostap path: modules/lib/hostap - revision: 81bdd8343347a2e36c67253a8aeb22ea7cb41132 + revision: 83574f533fb5c6808af0d9872741d72d48be2f98 - name: libmetal revision: 243eed541b9c211a2ce8841c788e62ddce84425e path: modules/hal/libmetal @@ -271,31 +271,31 @@ manifest: - fs revision: 408c16a909dd6cf128874a76f21c793798c9e423 - name: loramac-node - revision: 1bf2120cffcedae174ae35d695a28a46caefcb23 + revision: fb00b383072518c918e2258b0916c996f2d4eebe path: modules/lib/loramac-node - name: lvgl revision: 2b498e6f36d6b82ae1da12c8b7742e318624ecf5 path: modules/lib/gui/lvgl - name: mbedtls - revision: 6ec4abdcda78dfc47315af568f93e5ad4398dea0 + revision: 3217c450180fd5e817601c6f479116de69e57461 path: modules/crypto/mbedtls groups: - crypto - name: mcuboot - revision: 24ac8cc2be9384288829aac7477f522a7a71f3d4 + revision: 018dc01d484358d81f889c36471d9ce5590965b6 path: bootloader/mcuboot - name: mipi-sys-t path: modules/debug/mipi-sys-t groups: - debug - revision: a819419603a2dfcb47f7f39092e1bc112e45d1ef + revision: 71ace1f5caa03e56c8740a09863e685efb4b2360 - name: net-tools - revision: cd2eb1858a1570b49241e18fc1e1cd849a450af2 + revision: 7c7a856814d7f27509c8511fef14cec21f7d0c30 path: tools/net-tools groups: - tools - name: nrf_hw_models - revision: df94612a846b8b1da166d3e4e4273df54de02340 + revision: 36b12714a5ed32450d907c89bb118f6280da3483 path: modules/bsim_hw_models/nrf_hw_models - name: open-amp revision: da78aea63159771956fe0c9263f2e6985b66e9d5 @@ -312,7 +312,7 @@ manifest: path: modules/lib/picolibc revision: 764ef4e401a8f4c6a86ab723533841f072885a5b - name: segger - revision: 9d0191285956cef43daf411edc2f1a7788346def + revision: b011c45b585e097d95d9cf93edf4f2e01588d3cd path: modules/debug/segger groups: - debug @@ -322,7 +322,7 @@ manifest: groups: - crypto - name: trusted-firmware-m - revision: 0b898c9b72171b0a260c0bb64a92ea4713f9e931 + revision: 785d87492490069b62170159fcf21c385f90f4eb path: modules/tee/tf-m/trusted-firmware-m groups: - tee